From 4bf5f598fbe2372605306372b1f52d6c0d099327 Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 2 Jun 2019 16:59:32 +0200 Subject: [PATCH 001/175] begining functional split 6 --- executables/dl_fs6.c | 229 ++++++++++++++++++++++++ executables/split_headers.h | 13 ++ openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- targets/ARCH/COMMON/common_lib.c | 2 +- targets/ARCH/COMMON/common_lib.h | 46 ++++- targets/ARCH/rfsimulator/simulator.c | 204 ++++++++++++--------- targets/RT/USER/lte-ru.c | 38 ++-- 8 files changed, 436 insertions(+), 100 deletions(-) create mode 100644 executables/dl_fs6.c create mode 100644 executables/split_headers.h diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c new file mode 100644 index 0000000000..4eae805eb7 --- /dev/null +++ b/executables/dl_fs6.c @@ -0,0 +1,229 @@ +#define MTU 65536 +#define UDP_TIMEOUT 100000L // in nano second + +receiveSubFrame(int sock) { + //read all subframe data from the control unit + char * buf[MTU]; + int ret=recv(sock, buf, sizeof(buf), 0); + if ( ret==-1) { + if ( errno == EWOULDBLOCK || errno== EINTR ) { + finishSubframeRecv(); + } else { + LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); + return; + } + } else { + } + +} + +void pdsch_procedures(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, + int harq_pid, + LTE_eNB_DLSCH_t *dlsch, + LTE_eNB_DLSCH_t *dlsch1, + LTE_eNB_UE_stats *ue_stats, + int ra_flag) { + + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // 36-212 + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF + + // Replace dlsch_encoding + // data is in + // dlsch->harq_processes[harq_pid]->e + feedDlschBuffers(eNB, + dlsch_harq->pdu, + dlsch_harq->pdsch_start, + dlsch, + frame, + subframe, + &eNB->dlsch_rate_matching_stats, + &eNB->dlsch_turbo_encoding_stats, + &eNB->dlsch_turbo_encoding_waiting_stats, + &eNB->dlsch_turbo_encoding_main_stats, + &eNB->dlsch_turbo_encoding_wakeup_stats0, + &eNB->dlsch_turbo_encoding_wakeup_stats1, + &eNB->dlsch_interleaving_stats); + + // 36-211 + dlsch_scrambling(fp, + 0, + dlsch, + harq_pid, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + dlsch_harq->Qm, + dlsch_harq->Nl, + dlsch_harq->pdsch_start, + frame,subframe, + 0), + 0, + frame, + subframe<<1); + dlsch_modulation(eNB, + eNB->common_vars.txdataF, + AMP, + frame, + subframe, + dlsch_harq->pdsch_start, + dlsch, + dlsch->ue_type==0 ? dlsch1 : (LTE_eNB_DLSCH_t *)NULL); + } + + dlsch->active = 0; + dlsch_harq->round++; +} + +phy_procedures_eNB_TX_fs6() { + + receiveSubFrame(); + + // We got + // subframe number + // + + for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { + memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti], + 0, + fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); + } + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + if (is_pmch_subframe(frame,subframe,fp)) { + pmch_procedures(eNB,proc); + } else { + // this is not a pmch subframe, so generate PSS/SSS/PBCH + common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx); + } + } + + if (ul_subframe < 10)if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + for (i=0; i= MAKE_VERSION(14, 0, 0)) + + if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; + else +#endif + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + + if (eNB->ulsch[i]) { + ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + ulsch_harq->previous_first_rb = ulsch_harq->first_rb; + ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + } + } + } + + num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; + num_dci = eNB->pdcch_vars[subframe&1].num_dci; + if (num_dci > 0) + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + generate_dci_top(num_pdcch_symbols, + num_dci, + &eNB->pdcch_vars[subframe&1].dci_alloc[0], + 0, + AMP, + fp, + eNB->common_vars.txdataF, + subframe); + num_mdci = eNB->mpdcch_vars[subframe &1].num_dci; + + if (num_mdci > 0) { + generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF); + } + } + + // Now scan UE specific DLSCH + LTE_eNB_DLSCH_t *dlsch0,*dlsch1; + + for (UE_id=0; UE_iddlsch[(uint8_t)UE_id][0]; + dlsch1 = eNB->dlsch[(uint8_t)UE_id][1]; + + if ((dlsch0)&&(dlsch0->rnti>0)&& + (dlsch0->active == 1) + ) { + // get harq_pid + harq_pid = dlsch0->harq_ids[frame%2][subframe]; + AssertFatal(harq_pid>=0,"harq_pid is negative\n"); + + if (harq_pid>=8) { + if (dlsch0->ue_type==0) + LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x \n", + harq_pid,UE_id,frame,subframe,dlsch0->rnti); + } else { + // generate pdsch + pdsch_procedures_fs6(eNB, + proc, + harq_pid, + dlsch0, + dlsch1, + &eNB->UE_stats[(uint32_t)UE_id], + 0); + } + } else if ((dlsch0)&&(dlsch0->rnti>0)&& + (dlsch0->active == 0) + ) { + // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) + dlsch0->subframe_tx[subframe]=0; + } + } + generate_phich_top(eNB, + proc, + AMP); + +} + +DL_thread_fs6() { + receiveSubFrame(); + phy_procedures_eNB_TX_fs6(); + ru->feptx_prec(ru); + ru->feptx_ofdm(ru); + ru->fh_south_out(ru); +} + +int createListner (port) { + int sock; + AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); + struct sockaddr_in addr = { +sin_family: + AF_INET, +sin_port: +htons(port), +sin_addr: + { s_addr: INADDR_ANY } + }; + AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); + struct timeval tv={0,UDP_TIMEOUT}; + AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); +} + + +DL_thread_frequency() { + frequency_t header; + + full_read(&header, diff --git a/executables/split_headers.h b/executables/split_headers.h new file mode 100644 index 0000000000..7a580affd4 --- /dev/null +++ b/executables/split_headers.h @@ -0,0 +1,13 @@ +#ifndef __SPLIT_HEADERS_H +#define __SPLIT_HEADERS_H + +struct frequency_s { + int frame; + int subframe; + int timestamp; + int sampleSize; + int nbAnt + int nbSamples; +} frequency_t; + +#endif diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 3b3b9336d4..9a209f06a5 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -431,7 +431,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; - else + else #endif harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 588a96ca6d..d05ffbd8fa 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -1354,7 +1354,7 @@ int main(int argc, char **argv) { printStatIndent2(&eNB->ulsch_deinterleaving_stats,"sub-block interleaving" ); printStatIndent2(&eNB->ulsch_demultiplexing_stats,"sub-block demultiplexing" ); printStatIndent2(&eNB->ulsch_rate_unmatching_stats,"sub-block rate-matching" ); - printf("|__ turbo_decoder(%d bits), avg iterations: %.1f %.2f us (%d cycles, %d trials)\n", + printf(" |__ turbo_decoder(%d bits), avg iterations: %.1f %.2f us (%d cycles, %d trials)\n", eNB->ulsch[0]->harq_processes[harq_pid]->Cminus ? eNB->ulsch[0]->harq_processes[harq_pid]->Kminus : eNB->ulsch[0]->harq_processes[harq_pid]->Kplus, diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index 3f81816aa1..23c979a6e1 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -105,7 +105,7 @@ int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_param if ( IS_SOFTMODEM_BASICSIM ) { libname=OAI_BASICSIM_LIBNAME; shlib_fdesc[0].fname="device_init"; - } else if ( IS_SOFTMODEM_RFSIM ) { + } else if ( IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) { libname=OAI_RFSIM_LIBNAME; shlib_fdesc[0].fname="device_init"; } else if (flag == RAU_LOCAL_RADIO_HEAD) { diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 0af6fa9c5e..03fe4fb789 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -102,6 +102,10 @@ typedef enum { IRIS_DEV, /*!\brief device is NONE*/ NONE_DEV, + /*!\brief device is ADRV9371_ZC706 */ + ADRV9371_ZC706_DEV, + /*!\brief device is UEDv2 */ + UEDv2_DEV, MAX_RF_DEV_TYPE } dev_type_t; @@ -214,6 +218,14 @@ typedef struct { int iq_rxrescale; //! Configuration file for LMS7002M char *configFilename; + //! remote IP/MAC addr for Ethernet interface + char *remote_addr; + //! remote port number for Ethernet interface + unsigned int remote_port; + //! local IP/MAC addr for Ethernet interface (eNB/BBU, UE) + char *my_addr; + //! local port number for Ethernet interface (eNB/BBU, UE) + unsigned int my_port; #if defined(USRP_REC_PLAY) unsigned short sf_mode; // 1=record, 2=replay char sf_filename[1024]; // subframes file path @@ -223,6 +235,13 @@ typedef struct { unsigned int sf_write_delay; // write delay in replay mode unsigned int eth_mtu; // ethernet MTU #endif + + //! number of samples per tti + unsigned int samples_per_tti; + //! the sample rate for receive. + double rx_sample_rate; + //! the sample rate for transmit. + double tx_sample_rate; } openair0_config_t; /*! \brief RF mapping */ @@ -384,6 +403,31 @@ struct openair0_device_t { typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg); /* type of transport init function, implemented in shared lib */ typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params); +#define UE_MAGICDL_FDD 0xA5A5A5A5A5A5A5A5 // UE DL FDD record +#define UE_MAGICUL_FDD 0x5A5A5A5A5A5A5A5A // UE UL FDD record +#define UE_MAGICDL_TDD 0xA6A6A6A6A6A6A6A6 // UE DL TDD record +#define UE_MAGICUL_TDD 0x6A6A6A6A6A6A6A6A // UE UL TDD record + +#define ENB_MAGICDL_FDD 0xB5B5B5B5B5B5B5B5 // eNB DL FDD record +#define ENB_MAGICUL_FDD 0x5B5B5B5B5B5B5B5B // eNB UL FDD record +#define ENB_MAGICDL_TDD 0xB6B6B6B6B6B6B6B6 // eNB DL TDD record +#define ENB_MAGICUL_TDD 0x6B6B6B6B6B6B6B6B // eNB UL TDD record + +#define OPTION_LZ4 0x00000001 // LZ4 compression (option_value is set to compressed size) + +#define sample_t uint32_t // 2*16 bits complex number + +typedef struct { + uint64_t magic; // Magic value (see defines above) + uint32_t size; // Number of samples per antenna to follow this header + uint32_t nbAnt; // Total number of antennas following this header + // Samples per antenna follow this header, + // i.e. nbAnt = 2 => this header+samples_antenna_0+samples_antenna_1 + // data following this header in bytes is nbAnt*size*sizeof(sample_t) + uint64_t timestamp; // Timestamp value of first sample + uint32_t option_value; // Option value + uint32_t option_flag; // Option flag +} samplesBlockHeader_t; #ifdef __cplusplus extern "C" @@ -408,7 +452,7 @@ openair0_timestamp get_usrp_time(openair0_device *device); * \returns 0 in success */ int openair0_set_rx_frequencies(openair0_device *device, openair0_config_t *openair0_cfg); - +#define gettid() syscall(__NR_gettid) /*@}*/ #ifdef __cplusplus diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index a17327b03e..21d3d5dc7e 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -24,28 +24,23 @@ #define PORT 4043 //TCP port for this simulator #define CirSize 3072000 // 100ms is enough +#define MaxBlock 30000 #define sample_t uint32_t // 2*16 bits complex number #define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t)) #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b))) -#define MAGICeNB 0xA5A5A5A5A5A5A5A5 -#define MAGICUE 0x5A5A5A5A5A5A5A5A -typedef struct { - uint64_t magic; - uint32_t size; - uint32_t nbAnt; - uint64_t timestamp; -} transferHeader; +#define sample_t uint32_t // 2*16 bits complex number typedef struct buffer_s { int conn_sock; - bool alreadyRead; + bool readEnabled; uint64_t lastReceivedTS; + uint64_t lastWroteTS; bool headerMode; - transferHeader th; + samplesBlockHeader_t th; char *transferPtr; uint64_t remainToTransfer; - char *circularBufEnd; + int nbAnt; sample_t *circularBuf; } buffer_t; @@ -55,19 +50,22 @@ typedef struct { uint64_t typeStamp; uint64_t initialAhead; char *ip; + int saveIQfile; buffer_t buf[FD_SETSIZE]; } rfsimulator_state_t; void allocCirBuf(rfsimulator_state_t *bridge, int sock) { buffer_t *ptr=&bridge->buf[sock]; AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, ""); - ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; ptr->headerMode=true; ptr->transferPtr=(char *)&ptr->th; - ptr->remainToTransfer=sizeof(transferHeader); + ptr->remainToTransfer=sizeof(samplesBlockHeader_t); int sendbuff=1000*1000*10; AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, ""); + AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sendbuff, sizeof(sendbuff)) == 0, ""); + int tcp_maxseg = 1400; + AssertFatal ( setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,sizeof(tcp_maxseg)) == 0, ""); struct epoll_event ev= {0}; ev.events = EPOLLIN | EPOLLRDHUP; ev.data.fd = sock; @@ -87,7 +85,7 @@ void socketError(rfsimulator_state_t *bridge, int sock) { LOG_W(HW,"Lost socket \n"); removeCirBuf(bridge, sock); - if (bridge->typeStamp==MAGICUE) + if (bridge->typeStamp==UE_MAGICDL_FDD) exit(1); } } @@ -120,6 +118,11 @@ void setblocking(int sock, enum blocking_t active) { static bool flushInput(rfsimulator_state_t *t); void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) { + if (t->saveIQfile != -1) { + if (write(t->saveIQfile, _buf, count) != count ) + LOG_E(HW,"write in save iq file failed (%s)\n",strerror(errno)); + } + char *buf = _buf; int l; setblocking(fd, notBlocking); @@ -145,7 +148,7 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) { int server_start(openair0_device *device) { rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv; - t->typeStamp=MAGICeNB; + t->typeStamp=ENB_MAGICDL_FDD; AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); int enable = 1; AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, ""); @@ -168,7 +171,7 @@ sin_addr: int start_ue(openair0_device *device) { rfsimulator_state_t *t = device->priv; - t->typeStamp=MAGICUE; + t->typeStamp=UE_MAGICDL_FDD; int sock; AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); struct sockaddr_in addr = { @@ -196,43 +199,104 @@ sin_addr: setblocking(sock, notBlocking); allocCirBuf(t, sock); - t->buf[sock].alreadyRead=true; // UE will start blocking on read + t->buf[sock].readEnabled=true; // UE will start blocking on read return 0; } +uint64_t lwrote; int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { rfsimulator_state_t *t = device->priv; + // We do small blocks because the UE and the eNB are not aligned + // So large blocks can lead to deadlock (each side waits a incoming block completed) + int curBeg=0; - for (int i=0; ibuf[i]; + do { + int sizeToSend=min(nsamps-curBeg,MaxBlock); - if (ptr->conn_sock >= 0 ) { - transferHeader header= {t->typeStamp, nsamps, nbAnt, timestamp}; - fullwrite(ptr->conn_sock,&header, sizeof(header), t); - sample_t tmpSamples[nsamps][nbAnt]; + for (int i=0; ibuf[i]; - for(int a=0; aconn_sock >= 0 ) { + samplesBlockHeader_t header= {t->typeStamp, sizeToSend, nbAnt, timestamp+curBeg}; + fullwrite(ptr->conn_sock,&header, sizeof(header), t); + sample_t tmpSamples[sizeToSend][nbAnt]; - for(int s=0; sconn_sock >= 0 ) { + fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(sizeToSend,nbAnt), t); + ptr->lastWroteTS=timestamp+curBeg+sizeToSend; + } } - - if (ptr->conn_sock >= 0 ) - fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); } - } - LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", - nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) ); + LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", + sizeToSend, timestamp+curBeg, timestamp+curBeg+sizeToSend, + signal_energy(samplesVoid[0]+curBeg, sizeToSend) ); + curBeg+=sizeToSend; + } while ( curBeg < nsamps ) ; + return nsamps; } +static void oneTransferDone(rfsimulator_state_t *t, buffer_t *b) { + // check the header and start block transfer + if ( b->headerMode==true) { + AssertFatal( (t->typeStamp == UE_MAGICDL_FDD && b->th.magic==ENB_MAGICDL_FDD) || + (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol"); + b->headerMode=false; + + if ( b->lastReceivedTS != b->th.timestamp && b->readEnabled && b->lastReceivedTS ) { + int nbAnt= b->th.nbAnt; + + for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) + for (int a=0; a < nbAnt; a++) + b->circularBuf[(index*nbAnt+a)%CirSize]=0; + + LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); + } + + if ( b->readEnabled && b->lastReceivedTS && b->lastWroteTS) + AssertFatal( fabs((double)b->lastReceivedTS - (double)b->lastWroteTS) < (double)CirSize, + "Difference between Rx/Tx timestamps impossible, Rx: %lu, T:%lu\n", + b->lastReceivedTS, b->lastWroteTS); + else + printf("diff: %f\n", abs((double)b->lastReceivedTS - (double)b->lastWroteTS)/1000.0); + + + b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; + b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); + } else { + LOG_I(HW,"Completed block reception: %ld\n", b->lastReceivedTS); + // in NB case, the UE started to write, since this event, we will wait it's data + // This is needed because the UE doesn't write in initial sync mode + // in UE case, the UE is already in this state (at connection time) + b->readEnabled=true; + b->lastReceivedTS=b->th.timestamp+b->th.size; + + // First block in UE, resync with the eNB current TS + if ( t->nextTimestamp == 0 ) { + t->nextTimestamp=b->lastReceivedTS-b->th.size; + LOG_I(HW,"Ue synchro on NB timestamp: %lu\n", t->nextTimestamp); + } + + b->headerMode=true; + b->transferPtr=(char *)&b->th; + b->remainToTransfer=sizeof(samplesBlockHeader_t); + b->th.magic=-1; + } +} + static bool flushInput(rfsimulator_state_t *t) { // Process all incoming events on sockets // store the data in lists struct epoll_event events[FD_SETSIZE]= {0}; - int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 200); + int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 2); if ( nfds==-1 ) { if ( errno==EINTR || errno==EAGAIN ) @@ -264,13 +328,14 @@ static bool flushInput(rfsimulator_state_t *t) { } int blockSz; + char * circularBufEnd=((char *)b->circularBuf)+sampleToByte(CirSize,1); if ( b->headerMode) blockSz=b->remainToTransfer; else - blockSz= b->transferPtr+b->remainToTransfer < b->circularBufEnd ? + blockSz= b->transferPtr+b->remainToTransfer < circularBufEnd ? b->remainToTransfer : - b->circularBufEnd - 1 - b->transferPtr ; + circularBufEnd - 1 - b->transferPtr ; int sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT); @@ -285,46 +350,11 @@ static bool flushInput(rfsimulator_state_t *t) { AssertFatal((b->remainToTransfer-=sz) >= 0, ""); b->transferPtr+=sz; - if (b->transferPtr==b->circularBufEnd - 1) + if (b->transferPtr==circularBufEnd - 1) b->transferPtr=(char *)b->circularBuf; - // check the header and start block transfer - if ( b->headerMode==true && b->remainToTransfer==0) { - AssertFatal( (t->typeStamp == MAGICUE && b->th.magic==MAGICeNB) || - (t->typeStamp == MAGICeNB && b->th.magic==MAGICUE), "Socket Error in protocol"); - b->headerMode=false; - b->alreadyRead=true; - - if ( b->lastReceivedTS != b->th.timestamp) { - int nbAnt= b->th.nbAnt; - - for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) - for (int a=0; a < nbAnt; a++) - b->circularBuf[(index*nbAnt+a)%CirSize]=0; - - LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); - } - - b->lastReceivedTS=b->th.timestamp; - b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; - b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); - } - - if ( b->headerMode==false ) { - b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); - - if ( b->remainToTransfer==0) { - LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS); - - // First block in UE, resync with the eNB current TS - if ( t->nextTimestamp == 0 ) - t->nextTimestamp=b->lastReceivedTS-b->th.size; - - b->headerMode=true; - b->transferPtr=(char *)&b->th; - b->remainToTransfer=sizeof(transferHeader); - b->th.magic=-1; - } + if ( b->remainToTransfer==0) { + oneTransferDone(t,b); } } } @@ -367,7 +397,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for ( int sock=0; sockbuf[sock].circularBuf && - t->buf[sock].alreadyRead && //>= t->initialAhead && + t->buf[sock].readEnabled && (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) { have_to_wait=true; break; @@ -390,7 +420,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for (int sock=0; sockbuf[sock]; - if ( ptr->circularBuf && ptr->alreadyRead ) { + if ( ptr->circularBuf && ptr->readEnabled ) { for (int a=0; aip=getenv("RFSIMULATOR")) == NULL ) { @@ -447,10 +477,22 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { } rfsimulator->typeStamp = strncasecmp(rfsimulator->ip,"enb",3) == 0 ? - MAGICeNB: - MAGICUE; - LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == MAGICeNB ? "eNB" : "UE"); - device->trx_start_func = rfsimulator->typeStamp == MAGICeNB ? + ENB_MAGICDL_FDD: + UE_MAGICDL_FDD; + LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "eNB" : "UE"); + char *saveF; + + if ((saveF=getenv("saveIQfile")) != NULL) { + rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666); + + if ( rfsimulator->saveIQfile != -1 ) + LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF); + else + LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno)); + } else + rfsimulator->saveIQfile = -1; + + device->trx_start_func = rfsimulator->typeStamp == ENB_MAGICDL_FDD ? server_start : start_ue; device->trx_get_stats_func = rfsimulator_get_stats; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 93a2440b94..9d2fd5d084 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -148,7 +148,7 @@ int attach_rru(RU_t *ru) { RRU_CONFIG_msg_t rru_config_msg; int received_capabilities=0; wait_eNBs(); - + LOG_ENTER(PHY); // Wait for capabilities while (received_capabilities==0) { memset((void *)&rru_config_msg,0,sizeof(rru_config_msg)); @@ -208,7 +208,7 @@ int connect_rau(RU_t *ru) { RRU_capabilities_t *cap; int i; int len; - + LOG_ENTER(PHY); // wait for RAU_tick while (tick_received == 0) { msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; @@ -299,7 +299,7 @@ int connect_rau(RU_t *ru) { // southbound IF5 fronthaul for 16-bit OAI format static inline void fh_if5_south_out(RU_t *ru) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); - + LOG_ENTER(PHY); send_IF5(ru, ru->proc.timestamp_tx, ru->proc.subframe_tx, &ru->seqno, IF5_RRH_GW_DL); } @@ -315,7 +315,7 @@ static inline void fh_if4p5_south_out(RU_t *ru) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx); - + LOG_ENTER(PHY); if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT); } @@ -327,6 +327,7 @@ static inline void fh_if4p5_south_out(RU_t *ru) { void fh_if5_south_in(RU_t *ru,int *frame, int *subframe) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; RU_proc_t *proc = &ru->proc; + LOG_ENTER(PHY); recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; @@ -358,14 +359,14 @@ void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) { uint16_t packet_type; uint32_t symbol_number=0; uint32_t symbol_mask_full; - + LOG_ENTER(PHY); if ((fp->frame_type == TDD) && (subframe_select(fp,*subframe)==SF_S)) symbol_mask_full = (1<ul_symbols_in_S_subframe)-1; else symbol_mask_full = (1<symbols_per_tti)-1; AssertFatal(proc->symbol_mask[*subframe]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*subframe,proc->symbol_mask[*subframe]); - + LOG_D(PHY,"start rcv IF4p5 \n"); do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! recv_IF4p5(ru, &f, &sf, &packet_type, &symbol_number); @@ -382,6 +383,7 @@ void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) { LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*subframe,proc->symbol_mask[*subframe]); } while(proc->symbol_mask[*subframe] != symbol_mask_full); + LOG_D(PHY,"Done rcv IF4p5 \n"); //caculate timestamp_rx, timestamp_tx based on frame and subframe proc->subframe_rx = sf; @@ -482,6 +484,7 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) { symbol_mask = (1<symbols_per_tti)-1; prach_rx = 0; + LOG_D(PHY,"start rcv IF4p5 \n"); do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number); @@ -578,6 +581,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { uint16_t packet_type; uint32_t symbol_number,symbol_mask,symbol_mask_full; int subframe_tx,frame_tx; + LOG_ENTER(PHY); LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); symbol_number = 0; symbol_mask = 0; @@ -643,7 +647,7 @@ void fh_if4p5_north_out(RU_t *ru) { RU_proc_t *proc=&ru->proc; LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; const int subframe = proc->subframe_rx; - + LOG_ENTER(PHY); if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx ); if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) { @@ -712,6 +716,8 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { unsigned int rxs; int i; openair0_timestamp ts=0,old_ts=0; + LOG_ENTER(PHY); + LOG_D(PHY,"%s:%d start rx_rf \n", __FILE__,__LINE__); for (i=0; inb_rx; i++) rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; @@ -820,6 +826,7 @@ void tx_rf(RU_t *ru) { lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); int sf_extension = 0; + LOG_D(PHY,"start tx_rf \n"); if ((SF_type == SF_DL) || (SF_type == SF_S)) { @@ -935,6 +942,7 @@ static void *ru_thread_asynch_rxtx( void *param ) { printf( "devices ok (ru_thread_asynch_rx)\n"); while (!oai_exit) { + LOG_ENTER(PHY); if (oai_exit) break; if (subframe==9) { @@ -968,7 +976,7 @@ void wakeup_slaves(RU_proc_t *proc) { struct timespec wait; wait.tv_sec=0; wait.tv_nsec=5000000L; - + LOG_ENTER(PHY); for (i=0; inum_slaves; i++) { RU_proc_t *slave_proc = proc->slave_proc[i]; @@ -1029,7 +1037,7 @@ static void *ru_thread_prach( void *param ) { if (oai_exit) break; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); - + LOG_ENTER(PHY); if (ru->eNB_list[0]) { prach_procedures( ru->eNB_list[0] @@ -1075,7 +1083,7 @@ static void *ru_thread_prach_br( void *param ) { if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break; if (oai_exit) break; - + LOG_ENTER(PHY); rx_prach(NULL, ru, NULL, @@ -1098,7 +1106,7 @@ int wakeup_synch(RU_t *ru) { struct timespec wait; wait.tv_sec=0; wait.tv_nsec=5000000L; - + LOG_ENTER(PHY); // wake up synch thread // lock the synch mutex and make sure the thread is ready if (pthread_mutex_timedlock(&ru->proc.mutex_synch,&wait) != 0) { @@ -1135,7 +1143,7 @@ void do_ru_synch(RU_t *ru) { double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0]; double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0]; - + LOG_ENTER(PHY); for (i=0; i<4; i++) { ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i]; ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1; @@ -1198,7 +1206,7 @@ void wakeup_L1s(RU_t *ru) { int i; PHY_VARS_eNB **eNB_list = ru->eNB_list; LOG_D(PHY,"wakeup_L1s (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); - + LOG_ENTER(PHY); if (ru->num_eNB==1 && ru->eNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { // call eNB function directly char string[20]; @@ -1496,7 +1504,7 @@ static void *ru_thread_tx( void *param ) { wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx"); if (oai_exit) break; - + LOG_ENTER(PHY); // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) ru->feptx_prec(ru); @@ -1644,7 +1652,7 @@ static void *ru_thread( void *param ) { // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,sched_getcpu()); - + LOG_ENTER(PHY); // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. // They are set on the first rx/tx in the underly FH routines. if (subframe==9) { From 17d5bcd396bcd41a81a1a2f7929119b95ad4da2f Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 18 Jun 2019 08:57:08 +0200 Subject: [PATCH 002/175] dev continue --- common/utils/system.c | 104 ++++++++++--- common/utils/system.h | 25 ++++ executables/dl_fs6.c | 33 +---- executables/split_headers.h | 21 ++- executables/transport_split.c | 65 +++++++++ openair1/SIMULATION/TOOLS/random_channel.c | 4 + targets/RT/USER/lte-softmodem.c | 161 ++++----------------- 7 files changed, 225 insertions(+), 188 deletions(-) create mode 100644 executables/transport_split.c diff --git a/common/utils/system.c b/common/utils/system.c index dcec681e2d..31c1035129 100644 --- a/common/utils/system.c +++ b/common/utils/system.c @@ -28,13 +28,23 @@ * separate process solves this problem. */ +#define _GNU_SOURCE #include "system.h" #include #include #include #include #include - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define MAX_COMMAND 4096 static int command_pipe_read; @@ -50,37 +60,37 @@ static int module_initialized = 0; /* util functions */ /********************************************************************/ -static void lock_system(void) -{ +static void lock_system(void) { if (pthread_mutex_lock(&lock) != 0) { printf("pthread_mutex_lock fails\n"); abort(); } } -static void unlock_system(void) -{ +static void unlock_system(void) { if (pthread_mutex_unlock(&lock) != 0) { printf("pthread_mutex_unlock fails\n"); abort(); } } -static void write_pipe(int p, char *b, int size) -{ +static void write_pipe(int p, char *b, int size) { while (size) { int ret = write(p, b, size); + if (ret <= 0) exit(0); + b += ret; size -= ret; } } -static void read_pipe(int p, char *b, int size) -{ +static void read_pipe(int p, char *b, int size) { while (size) { int ret = read(p, b, size); + if (ret <= 0) exit(0); + b += ret; size -= ret; } @@ -95,14 +105,13 @@ static void read_pipe(int p, char *b, int size) * when the main process exits, because then a "read" on the pipe * will return 0, in which case "read_pipe" exits. */ -static void background_system_process(void) -{ +static void background_system_process(void) { int len; int ret; char command[MAX_COMMAND+1]; while (1) { - read_pipe(command_pipe_read, (char*)&len, sizeof(int)); + read_pipe(command_pipe_read, (char *)&len, sizeof(int)); read_pipe(command_pipe_read, command, len); ret = system(command); write_pipe(result_pipe_write, (char *)&ret, sizeof(int)); @@ -114,8 +123,7 @@ static void background_system_process(void) /* return -1 on error, 0 on success */ /********************************************************************/ -int background_system(char *command) -{ +int background_system(char *command) { int res; int len; @@ -125,18 +133,22 @@ int background_system(char *command) } len = strlen(command)+1; + if (len > MAX_COMMAND) { printf("FATAL: command too long. Increase MAX_COMMAND (%d).\n", MAX_COMMAND); printf("command was: '%s'\n", command); abort(); } + /* only one command can run at a time, so let's lock/unlock */ lock_system(); - write_pipe(command_pipe_write, (char*)&len, sizeof(int)); + write_pipe(command_pipe_write, (char *)&len, sizeof(int)); write_pipe(command_pipe_write, command, len); - read_pipe(result_pipe_read, (char*)&res, sizeof(int)); + read_pipe(result_pipe_read, (char *)&res, sizeof(int)); unlock_system(); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) return -1; + return 0; } @@ -146,17 +158,16 @@ int background_system(char *command) /* to be called very early by the main processing */ /********************************************************************/ -void start_background_system(void) -{ +void start_background_system(void) { int p[2]; pid_t son; - module_initialized = 1; if (pipe(p) == -1) { perror("pipe"); exit(1); } + command_pipe_read = p[0]; command_pipe_write = p[1]; @@ -164,10 +175,11 @@ void start_background_system(void) perror("pipe"); exit(1); } + result_pipe_read = p[0]; result_pipe_write = p[1]; - son = fork(); + if (son == -1) { perror("fork"); exit(1); @@ -181,6 +193,56 @@ void start_background_system(void) close(result_pipe_read); close(command_pipe_write); - background_system_process(); } + + +void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority){ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + struct sched_param sparam={0}; + sparam.sched_priority = priority; + pthread_attr_setschedparam(&attr, &sparam); + + pthread_create(t, &attr, func, param); + + pthread_setname_np(*t, name); + if (affinity != -1 ) { + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(affinity, &cpuset); + AssertFatal( pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset) == 0, "Error setting processor affinity"); + } + + pthread_attr_destroy(&attr); +} + +// Block CPU C-states deep sleep +void configure_linux(void) { + int ret; + static int latency_target_fd=-1; + uint32_t latency_target_value=10; // in microseconds + if (latency_target_fd == -1) { + if ( (latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR)) != -1 ) { + ret = write(latency_target_fd, &latency_target_value, sizeof(latency_target_value)); + if (ret == 0) { + printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno)); + close(latency_target_fd); + latency_target_fd=-1; + return; + } + } + } + if (latency_target_fd != -1) + LOG_I(HW,"# /dev/cpu_dma_latency set to %dus\n", latency_target_value); + else + LOG_E(HW,"Can't set /dev/cpu_dma_latency to %dus\n", latency_target_value); + + // Set CPU frequency to it's maximum + if ( 0 != system("for d in /sys/devices/system/cpu/cpu[0-9]*; do cat $d/cpufreq/cpuinfo_max_freq > $d/cpufreq/scaling_min_freq; done")) + LOG_W(HW,"Can't set cpu frequency\n"); + +} diff --git a/common/utils/system.h b/common/utils/system.h index 658c17adc1..a89a6c5b17 100644 --- a/common/utils/system.h +++ b/common/utils/system.h @@ -21,6 +21,12 @@ #ifndef _SYSTEM_H_OAI_ #define _SYSTEM_H_OAI_ +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + /**************************************************** * send a command to the background process @@ -36,4 +42,23 @@ int background_system(char *command); void start_background_system(void); +void set_latency_target(void); +void configure_linux(void); + +void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority); +#define OAI_PRIORITY_RT_LOW sched_get_priority_min(SCHED_FIFO) +#define OAI_PRIORITY_RT sched_get_priority_max(SCHED_FIFO)-10 +#define OAI_PRIORITY_RT_MAX sched_get_priority_max(SCHED_FIFO) + +void thread_top_init(char *thread_name, + int affinity, + uint64_t runtime, + uint64_t deadline, + uint64_t period); + +#ifdef __cplusplus +} +#endif + + #endif /* _SYSTEM_H_OAI_ */ diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 4eae805eb7..079f368f1d 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -1,21 +1,5 @@ -#define MTU 65536 -#define UDP_TIMEOUT 100000L // in nano second +#include -receiveSubFrame(int sock) { - //read all subframe data from the control unit - char * buf[MTU]; - int ret=recv(sock, buf, sizeof(buf), 0); - if ( ret==-1) { - if ( errno == EWOULDBLOCK || errno== EINTR ) { - finishSubframeRecv(); - } else { - LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); - return; - } - } else { - } - -} void pdsch_procedures(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, @@ -206,21 +190,6 @@ DL_thread_fs6() { ru->fh_south_out(ru); } -int createListner (port) { - int sock; - AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); - struct sockaddr_in addr = { -sin_family: - AF_INET, -sin_port: -htons(port), -sin_addr: - { s_addr: INADDR_ANY } - }; - AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); - struct timeval tv={0,UDP_TIMEOUT}; - AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); -} DL_thread_frequency() { diff --git a/executables/split_headers.h b/executables/split_headers.h index 7a580affd4..1fe4088971 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -1,13 +1,28 @@ #ifndef __SPLIT_HEADERS_H #define __SPLIT_HEADERS_H -struct frequency_s { +#define MTU 65536 +#define UDP_TIMEOUT 100000L // in nano second +#define MAX_BLOCKS 16 +#define blockAlign 32 //bytes + +typedef struct commonUDP_s { + uint64_t timestamp; // id of the group (subframe for LTE) + uint16_t nbBlocks; // total number of blocks for this timestamp + uint16_t blockID; // id: 0..nbBocks-1 + uint16_t contentType; // defines the content format + uint16_t contentBytes; // will be sent in a UDP packet, so must be < 2^16 bytes +} commonUDP_t; + +typedef struct frequency_s { int frame; int subframe; - int timestamp; int sampleSize; int nbAnt int nbSamples; } frequency_t; - + +int createListner (port); +int receiveSubFrame(int sock, uint64_t expectedTS, void* bufferZone, int bufferSize); +int sendSubFrame(int sock, void* bufferZone, int nbBlocks);} #endif diff --git a/executables/transport_split.c b/executables/transport_split.c new file mode 100644 index 0000000000..a1e0738458 --- /dev/null +++ b/executables/transport_split.c @@ -0,0 +1,65 @@ +#include + +int createListner (port) { + int sock; + AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); + struct sockaddr_in addr = { +sin_family: + AF_INET, +sin_port: +htons(port), +sin_addr: + { s_addr: INADDR_ANY } + }; + int enable=1; + AssertFatal(setsockopt(eth->sockfdc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); + AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); + struct timeval tv={0,UDP_TIMEOUT}; + AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); + // Make a send/recv buffer larger than a a couple of subframe + // so the kernel will store for us in and out paquets + int buff=1000*1000*10; + AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, ""); + AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, ""); +} + +// sock: udp socket +// expectedTS: the expected timestamp, 0 if unknown +// bufferZone: a reception area of bufferSize +int receiveSubFrame(int sock, uint64_t expectedTS, void* bufferZone, int bufferSize) { + int rcved=0; + do { + //read all subframe data from the control unit + int ret=recv(sock, bufferZone, bufferSize, 0); + if ( ret==-1) { + if ( errno == EWOULDBLOCK || errno== EINTR ) { + return rcved; // Timeout, subframe incomplete + } else { + LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); + return -1; + } + } else { + commonUDP_t * tmp=(commonUDP_t *)bufferZone; + if ( expectedTS && tmp->timestamp != expectedTS) { + LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n"); + } else { + rcved++; + bufferZone+=ret; + } + } + } while ( !recved || recved < tmp->nbBlocks); + return recv; +} + +int sendSubFrame(int sock, void* bufferZone, int nbBlocks) { + do { + int sz=alignedSize(bufferZone); + int ret=send(sock, bufferZone, sz, 0); + if ( ret != sz ) + LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d)\n", + sz, ret, errno); + bufferZone+=sz; + nbBlocks--; + } while (nbBlocks); + return 0; +} diff --git a/openair1/SIMULATION/TOOLS/random_channel.c b/openair1/SIMULATION/TOOLS/random_channel.c index 8341c574da..f056d51b5d 100644 --- a/openair1/SIMULATION/TOOLS/random_channel.c +++ b/openair1/SIMULATION/TOOLS/random_channel.c @@ -1204,6 +1204,10 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx, return(chan_desc); } +void free_channel_desc_scm(channel_desc_t * ch) { + // Must be made cleanly, a lot of leaks... + free(ch); +} int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 0dfbcff954..50e866358b 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -108,10 +108,6 @@ pthread_mutex_t sync_mutex; int sync_var=-1; //!< protected by mutex \ref sync_mutex. int config_sync_var=-1; -uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] -uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] - - volatile int oai_exit = 0; uint32_t downlink_frequency[MAX_NUM_CCs][4]; @@ -149,21 +145,13 @@ uint8_t nb_antenna_rx = 1; char ref[128] = "internal"; char channels[128] = "0"; -int rx_input_level_dBm; - - -int otg_enabled; - - +int rx_input_level_dBm; +int otg_enabled; uint8_t exit_missed_slots=1; uint64_t num_missed_slots=0; // counter for the number of missed slots - -extern void reset_opp_meas(void); -extern void print_opp_meas(void); - - extern void init_eNB_afterRU(void); +extern void phy_free_RU(RU_t *); int transmission_mode=1; int emulate_rf = 0; @@ -172,73 +160,11 @@ int numerology = 0; THREAD_STRUCT thread_struct; /* struct for ethernet specific parameters given in eNB conf file */ eth_params_t *eth_params; - double cpuf; - - /* forward declarations */ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); -/*---------------------BMC: timespec helpers -----------------------------*/ - -struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; -struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - -struct timespec clock_difftime(struct timespec start, struct timespec end) { - struct timespec temp; - - if ((end.tv_nsec-start.tv_nsec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_nsec = end.tv_nsec-start.tv_nsec; - } - - return temp; -} - -void print_difftimes(void) { -#ifdef DEBUG - printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -#else - LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -#endif -} - -void update_difftimes(struct timespec start, struct timespec end) { - struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - int changed = 0; - diff_time = clock_difftime(start, end); - - if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { - min_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - - if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { - max_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - -#if 1 - - if (changed) print_difftimes(); - -#endif -} - -/*------------------------------------------------------------------------*/ - -unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { - return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); -} -unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { - return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); -} - - void signal_handler(int sig) { void *array[10]; size_t size; @@ -256,7 +182,6 @@ void signal_handler(int sig) { } } - void exit_function(const char *file, const char *function, const int line, const char *s) { int ru_id; @@ -285,8 +210,6 @@ void exit_function(const char *file, const char *function, const int line, const exit(1); } - - static void get_options(void) { CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); get_common_options(); @@ -297,11 +220,11 @@ static void get_options(void) { /* Read RC configuration file */ RCConfig(); NB_eNB_INST = RC.nb_inst; - printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU); + LOG_I(ENB_APP,"Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU); if (!IS_SOFTMODEM_NONBIOT) { load_NB_IoT(); - printf(" nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n", + LOG_I(ENB_APP," nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n", RC.nb_nb_iot_rrc_inst, RC.nb_nb_iot_L1_inst, RC.nb_nb_iot_macrlc_inst); } else { printf("All Nb-IoT instances disabled\n"); @@ -310,10 +233,6 @@ static void get_options(void) { } } - - - - void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { int CC_id; @@ -528,75 +447,58 @@ int main( int argc, char **argv ) { int CC_id = 0; int ru_id; - if ( load_configmodule(argc,argv,0) == NULL) { - exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); - } - + AssertFatal(load_configmodule(argc,argv,0) != NULL, + "[SOFTMODEM] Error, configuration module init failed\n"); mode = normal_txrx; - set_latency_target(); + logInit(); - printf("Reading in command-line options\n"); get_options (); + AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n"); + + configure_linux(); + // to make a graceful exit when ctrl-c is pressed + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGABRT, signal_handler); + cpuf=get_cpu_freq_GHz(); + + #ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + LOG_I(HW, "OAI Version: %s\n", PACKAGE_VERSION); if (is_nos1exec(argv[0]) ) set_softmodem_optmask(SOFTMODEM_NOS1_BIT); EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1; - if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { - fprintf(stderr,"Getting configuration failed\n"); - exit(-1); - } - #if T_TRACER T_Config_Init(); #endif //randominit (0); set_taus_seed (0); - printf("configuring for RAU/RRU\n"); - if (opp_enabled ==1) { + if (opp_enabled ==1) reset_opp_meas(); - } - cpuf=get_cpu_freq_GHz(); - printf("ITTI init, useMME: %i\n",EPC_MODE_ENABLED); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); - - // initialize mscgen log after ITTI - if (get_softmodem_params()->start_msc) { - load_module_shlib("msc",NULL,0,&msc_interface); - } - - MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); + // allows to forward in wireshark L2 protocol for decoding init_opt(); - // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGABRT, signal_handler); - check_clock(); -#ifndef PACKAGE_VERSION -# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" -#endif - LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); - printf("Runtime table\n"); - fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); /* Read configuration */ if (RC.nb_inst > 0) { read_config_and_init(); /* Start the agent. If it is turned off in the configuration, it won't start */ RCconfig_flexran(); - - for (i = 0; i < RC.nb_inst; i++) { + + for (i = 0; i < RC.nb_inst; i++) flexran_agent_start(i); - } - + /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks * for monolithic/F1 modes */ init_pdcp(); - + if (create_tasks(1) < 0) { printf("cannot create ITTI tasks\n"); exit(-1); @@ -685,15 +587,11 @@ int main( int argc, char **argv ) { } printf("wait RUs\n"); - // CI -- Flushing the std outputs for the previous marker to show on the eNB / RRU log file - fflush(stdout); - fflush(stderr); // end of CI modifications wait_RUs(); LOG_I(ENB_APP,"RC.nb_RU:%d\n", RC.nb_RU); // once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration) - printf("ALL RUs ready - init eNBs\n"); - + if (NFAPI_MODE!=NFAPI_MODE_PNF && NFAPI_MODE!=NFAPI_MODE_VNF) { LOG_I(ENB_APP,"Not NFAPI mode - call init_eNB_afterRU()\n"); init_eNB_afterRU(); @@ -738,7 +636,6 @@ int main( int argc, char **argv ) { * threads have been stopped (they partially use the same memory) */ for (int inst = 0; inst < NB_eNB_INST; inst++) { for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) { - free_transport(RC.eNB[inst][cc_id]); phy_free_lte_eNB(RC.eNB[inst][cc_id]); } } From 0ba0422df7229bdd1a7e0dc769aca5e5c638192e Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 24 Jun 2019 22:04:14 +0200 Subject: [PATCH 003/175] add simple main --- cmake_targets/CMakeLists.txt | 34 + executables/dl_fs6.c | 130 ++- executables/simple_main.c | 1121 ++++++++++++++++++++++++++ executables/transport_split.c | 53 +- targets/ARCH/rfsimulator/simulator.c | 3 - targets/RT/USER/lte-enb.c | 2 +- targets/RT/USER/lte-ru.c | 126 +-- targets/RT/USER/lte-softmodem.c | 17 +- 8 files changed, 1280 insertions(+), 206 deletions(-) create mode 100644 executables/simple_main.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 50acfc4ce6..f2a5163219 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2115,6 +2115,40 @@ target_link_libraries (lte-softmodem NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) + +add_executable(simple-softmodem + ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c + ${OPENAIR_DIR}/executables/simple_main.c + ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c + ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c + ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c + ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR2_DIR}/RRC/NAS/nas_config.c + ${OPENAIR2_DIR}/RRC/NAS/rb_config.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/socket.c + ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c + ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c + ${GTPU_need_ITTI} + ${XFORMSINTERFACE_SOURCE} + ${T_SOURCE} + ${CONFIG_SOURCES} + ${SHLIB_LOADER_SOURCES} + ) +add_dependencies(simple-softmodem rrc_flag s1ap_flag x2_flag) + +target_link_libraries (simple-softmodem + -Wl,--start-group + RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 + ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} LFDS7 + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB + -Wl,--end-group z dl) +target_link_libraries (simple-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) + add_executable(cu_test ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_handler.c diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 079f368f1d..c583a4bc45 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -8,7 +8,6 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, LTE_eNB_DLSCH_t *dlsch1, LTE_eNB_UE_stats *ue_stats, int ra_flag) { - int frame=proc->frame_tx; int subframe=proc->subframe_tx; LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; @@ -16,24 +15,22 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, // 36-212 if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF - // Replace dlsch_encoding - // data is in + // data is in // dlsch->harq_processes[harq_pid]->e feedDlschBuffers(eNB, - dlsch_harq->pdu, - dlsch_harq->pdsch_start, - dlsch, - frame, - subframe, - &eNB->dlsch_rate_matching_stats, - &eNB->dlsch_turbo_encoding_stats, - &eNB->dlsch_turbo_encoding_waiting_stats, - &eNB->dlsch_turbo_encoding_main_stats, - &eNB->dlsch_turbo_encoding_wakeup_stats0, - &eNB->dlsch_turbo_encoding_wakeup_stats1, - &eNB->dlsch_interleaving_stats); - + dlsch_harq->pdu, + dlsch_harq->pdsch_start, + dlsch, + frame, + subframe, + &eNB->dlsch_rate_matching_stats, + &eNB->dlsch_turbo_encoding_stats, + &eNB->dlsch_turbo_encoding_waiting_stats, + &eNB->dlsch_turbo_encoding_main_stats, + &eNB->dlsch_turbo_encoding_wakeup_stats0, + &eNB->dlsch_turbo_encoding_wakeup_stats1, + &eNB->dlsch_interleaving_stats); // 36-211 dlsch_scrambling(fp, 0, @@ -65,7 +62,6 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, } phy_procedures_eNB_TX_fs6() { - receiveSubFrame(); // We got @@ -74,10 +70,10 @@ phy_procedures_eNB_TX_fs6() { for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti], - 0, - fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); + 0, + fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); } - + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { if (is_pmch_subframe(frame,subframe,fp)) { pmch_procedures(eNB,proc); @@ -88,59 +84,60 @@ phy_procedures_eNB_TX_fs6() { } if (ul_subframe < 10)if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here - for (i=0; i= MAKE_VERSION(14, 0, 0)) - if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; - else + if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; + else #endif - harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); - if (eNB->ulsch[i]) { - ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; - /* Store first_rb and n_DMRS for correct PHICH generation below. - * For PHICH generation we need "old" values of last scheduling - * for this HARQ process. 'generate_eNB_dlsch_params' below will - * overwrite first_rb and n_DMRS and 'generate_phich_top', done - * after 'generate_eNB_dlsch_params', would use the "new" values - * instead of the "old" ones. - * - * This has been tested for FDD only, may be wrong for TDD. - * - * TODO: maybe we should restructure the code to be sure it - * is done correctly. The main concern is if the code - * changes and first_rb and n_DMRS are modified before - * we reach here, then the PHICH processing will be wrong, - * using wrong first_rb and n_DMRS values to compute - * ngroup_PHICH and nseq_PHICH. - * - * TODO: check if that works with TDD. - */ - ulsch_harq->previous_first_rb = ulsch_harq->first_rb; - ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + if (eNB->ulsch[i]) { + ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + ulsch_harq->previous_first_rb = ulsch_harq->first_rb; + ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + } } } - } num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; num_dci = eNB->pdcch_vars[subframe&1].num_dci; + if (num_dci > 0) if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { generate_dci_top(num_pdcch_symbols, - num_dci, - &eNB->pdcch_vars[subframe&1].dci_alloc[0], - 0, - AMP, - fp, - eNB->common_vars.txdataF, - subframe); + num_dci, + &eNB->pdcch_vars[subframe&1].dci_alloc[0], + 0, + AMP, + fp, + eNB->common_vars.txdataF, + subframe); num_mdci = eNB->mpdcch_vars[subframe &1].num_dci; - + if (num_mdci > 0) { - generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF); + generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF); } } - + // Now scan UE specific DLSCH LTE_eNB_DLSCH_t *dlsch0,*dlsch1; @@ -158,16 +155,16 @@ phy_procedures_eNB_TX_fs6() { if (harq_pid>=8) { if (dlsch0->ue_type==0) LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x \n", - harq_pid,UE_id,frame,subframe,dlsch0->rnti); + harq_pid,UE_id,frame,subframe,dlsch0->rnti); } else { // generate pdsch pdsch_procedures_fs6(eNB, - proc, - harq_pid, - dlsch0, - dlsch1, - &eNB->UE_stats[(uint32_t)UE_id], - 0); + proc, + harq_pid, + dlsch0, + dlsch1, + &eNB->UE_stats[(uint32_t)UE_id], + 0); } } else if ((dlsch0)&&(dlsch0->rnti>0)&& (dlsch0->active == 0) @@ -176,10 +173,10 @@ phy_procedures_eNB_TX_fs6() { dlsch0->subframe_tx[subframe]=0; } } + generate_phich_top(eNB, proc, AMP); - } DL_thread_fs6() { @@ -194,5 +191,4 @@ DL_thread_fs6() { DL_thread_frequency() { frequency_t header; - - full_read(&header, + full_read(&header, \ No newline at end of file diff --git a/executables/simple_main.c b/executables/simple_main.c new file mode 100644 index 0000000000..04ab39e7a7 --- /dev/null +++ b/executables/simple_main.c @@ -0,0 +1,1121 @@ +/* + * Author: Laurent Thomas + * Copyright: Open Cells Project company + */ + +#include +static int DEFBANDS[] = {7}; +static int DEFENBS[] = {0}; +#include +#include +#include +#include +#include +#include +#include +#include +extern uint16_t sf_ahead; +extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); +extern void fep_full(RU_t *ru); +extern void feptx_ofdm(RU_t *ru); +extern void feptx_prec(RU_t *ru); +extern void phy_init_RU(RU_t *); + +static void *ru_thread( void *param ); +void kill_RU_proc(RU_t *ru) { +} +void kill_eNB_proc(int inst) { +} +void free_transport(PHY_VARS_eNB *eNB) { +} +void reset_opp_meas(void) { +} + +void init_eNB_proc(int inst) { + /*int i=0;*/ + int CC_id; + PHY_VARS_eNB *eNB; + L1_proc_t *proc; + L1_rxtx_proc_t *L1_proc, *L1_proc_tx; + + for (CC_id=0; CC_idproc; + L1_proc = &proc->L1_proc; + L1_proc_tx = &proc->L1_proc_tx; + L1_proc->instance_cnt = -1; + L1_proc_tx->instance_cnt = -1; + L1_proc->instance_cnt_RUs = 0; + L1_proc_tx->instance_cnt_RUs = 0; + proc->instance_cnt_prach = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->instance_cnt_synch = -1; + proc->CC_id = CC_id; + proc->first_rx =1; + proc->first_tx =1; + proc->RU_mask_tx = (1<num_RU)-1; + proc->RU_mask =0; + proc->RU_mask_prach =0; + pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); + pthread_mutex_init( &L1_proc->mutex, NULL); + pthread_mutex_init( &L1_proc_tx->mutex, NULL); + pthread_cond_init( &L1_proc->cond, NULL); + pthread_cond_init( &L1_proc_tx->cond, NULL); + pthread_mutex_init( &L1_proc->mutex_RUs, NULL); + pthread_mutex_init( &L1_proc_tx->mutex_RUs, NULL); + pthread_cond_init( &L1_proc->cond_RUs, NULL); + pthread_cond_init( &L1_proc_tx->cond_RUs, NULL); + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_RU,NULL); + pthread_mutex_init( &proc->mutex_RU_tx,NULL); + pthread_mutex_init( &proc->mutex_RU_PRACH,NULL); + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + pthread_attr_init( &proc->attr_prach); + pthread_attr_init( &proc->attr_asynch_rxtx); + pthread_attr_init( &L1_proc->attr); + pthread_attr_init( &L1_proc_tx->attr); + proc->instance_cnt_prach_br = -1; + proc->RU_mask_prach_br=0; + pthread_mutex_init( &proc->mutex_prach_br, NULL); + pthread_mutex_init( &proc->mutex_RU_PRACH_br,NULL); + pthread_cond_init( &proc->cond_prach_br, NULL); + pthread_attr_init( &proc->attr_prach_br); + } + + //for multiple CCs: setup master and slaves + /* + for (CC_id=0; CC_idnode_timing == synch_to_ext_device) { //master + eNB->proc.num_slaves = MAX_NUM_CCs-1; + eNB->proc.slave_proc = (L1_proc_t**)malloc(eNB->proc.num_slaves*sizeof(L1_proc_t*)); + + for (i=0; i< eNB->proc.num_slaves; i++) { + if (i < CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc); + if (i >= CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc); + } + } + } + */ +} + +void init_RU_proc(RU_t *ru) { + int i=0; + RU_proc_t *proc; + pthread_attr_t *attr_FH=NULL; + //pthread_attr_t *attr_fep=NULL; + proc = &ru->proc; + memset((void *)proc,0,sizeof(RU_proc_t)); + proc->ru = ru; + proc->instance_cnt_prach = -1; + proc->instance_cnt_synch = -1; + proc->instance_cnt_FH = -1; + proc->instance_cnt_FH1 = -1; + proc->instance_cnt_emulateRF = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->instance_cnt_eNBs = -1; + proc->first_rx = 1; + proc->first_tx = 1; + proc->frame_offset = 0; + proc->num_slaves = 0; + proc->frame_tx_unwrap = 0; + + for (i=0; i<10; i++) proc->symbol_mask[i]=0; + + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_synch,NULL); + pthread_mutex_init( &proc->mutex_FH,NULL); + pthread_mutex_init( &proc->mutex_FH1,NULL); + pthread_mutex_init( &proc->mutex_emulateRF,NULL); + pthread_mutex_init( &proc->mutex_eNBs, NULL); + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_FH, NULL); + pthread_cond_init( &proc->cond_FH1, NULL); + pthread_cond_init( &proc->cond_emulateRF, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + pthread_cond_init( &proc->cond_synch,NULL); + pthread_cond_init( &proc->cond_eNBs, NULL); + pthread_attr_init( &proc->attr_FH); + pthread_attr_init( &proc->attr_FH1); + pthread_attr_init( &proc->attr_emulateRF); + pthread_attr_init( &proc->attr_prach); + pthread_attr_init( &proc->attr_synch); + pthread_attr_init( &proc->attr_asynch_rxtx); + pthread_attr_init( &proc->attr_fep); + proc->instance_cnt_prach_br = -1; + pthread_mutex_init( &proc->mutex_prach_br, NULL); + pthread_cond_init( &proc->cond_prach_br, NULL); + attr_FH = &proc->attr_FH; + pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void *)ru ); +} + +void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + prach_procedures(eNB + ,0 + ); + } +} + +void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); + // set timing for prach thread + proc->frame_prach_br = frame; + proc->subframe_prach_br = subframe; + prach_procedures(eNB,1); + } +} + +static inline int wakeup_prach_ru(RU_t *ru) { + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + if (pthread_mutex_timedlock(&ru->proc.mutex_prach,&wait) !=0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread (IC %d)\n", ru->proc.instance_cnt_prach); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + + if (ru->proc.instance_cnt_prach==-1) { + ++ru->proc.instance_cnt_prach; + ru->proc.frame_prach = ru->proc.frame_rx; + ru->proc.subframe_prach = ru->proc.subframe_rx; + + // DJP - think prach_procedures() is looking at eNB frame_prach + if (ru->eNB_list[0]) { + ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; + ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; + } + + LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + // the thread can now be woken up + AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); + } else LOG_W(PHY,"RU prach thread busy, skipping\n"); + + pthread_mutex_unlock( &ru->proc.mutex_prach ); + return(0); +} + +static inline int wakeup_prach_ru_br(RU_t *ru) { + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + if (pthread_mutex_timedlock(&ru->proc.mutex_prach_br,&wait) !=0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread BR (IC %d)\n", ru->proc.instance_cnt_prach_br); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + + if (ru->proc.instance_cnt_prach_br==-1) { + ++ru->proc.instance_cnt_prach_br; + ru->proc.frame_prach_br = ru->proc.frame_rx; + ru->proc.subframe_prach_br = ru->proc.subframe_rx; + LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + // the thread can now be woken up + AssertFatal(pthread_cond_signal(&ru->proc.cond_prach_br) == 0, "ERROR pthread_cond_signal for RU prach thread BR\n"); + } else LOG_W(PHY,"RU prach thread busy, skipping\n"); + + pthread_mutex_unlock( &ru->proc.mutex_prach_br ); + return(0); +} + +static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { + //L1_rxtx_proc_t *L1_proc_tx = &eNB->proc.L1_proc_tx; + // ******************************************************************* + AssertFatal( eNB !=NULL, ""); + + if (NFAPI_MODE==NFAPI_MODE_PNF) { + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + uint16_t frame = proc->frame_rx; + uint16_t subframe = proc->subframe_rx; + //add_subframe(&frame, &subframe, 4); + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe); + oai_subframe_ind(frame, subframe); + } + + AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); + wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); + wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); + release_UE_in_freeList(eNB->Mod_id); + + // UE-specific RX processing for subframe n + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + phy_procedures_eNB_uespec_RX(eNB, proc); + } + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.frame = proc->frame_rx; + eNB->UL_INFO.subframe = proc->subframe_rx; + eNB->UL_INFO.module_id = eNB->Mod_id; + eNB->UL_INFO.CC_id = eNB->CC_id; + eNB->if_inst->UL_indication(&eNB->UL_INFO); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + phy_procedures_eNB_TX(eNB, proc, 1); + return(0); +} + +void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { + L1_proc_t *proc = &eNB->proc; + L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *ru_proc=&ru->proc; + proc->frame_rx = frame_rx; + proc->subframe_rx = subframe_rx; + + if (!oai_exit) { + T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->subframe_rx = ru_proc->subframe_rx; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; + + if (rxtx(eNB,L1_proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); + + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; + } +} +void init_transport(PHY_VARS_eNB *eNB) { + int i; + int j; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + LOG_I(PHY, "Initialise transport\n"); + + for (i=0; idlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp); + + if (!eNB->dlsch[i][j]) { + LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i); + exit(-1); + } else { + eNB->dlsch[i][j]->rnti=0; + LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,eNB->dlsch[i][j], eNB->dlsch[i][j]->rnti); + } + } + + LOG_D(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i); + eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0); + + if (!eNB->ulsch[1+i]) { + LOG_E(PHY,"Can't get eNB ulsch structures\n"); + exit(-1); + } + + // this is the transmission mode for the signalling channels + // this will be overwritten with the real transmission mode by the RRC once the UE is connected + eNB->transmission_mode[i] = fp->nb_antenna_ports_eNB==1 ? 1 : 2; + } + + // ULSCH for RA + eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0); + + if (!eNB->ulsch[0]) { + LOG_E(PHY,"Can't get eNB ulsch structures\n"); + exit(-1); + } + + eNB->dlsch_SI = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); + LOG_D(PHY,"eNB %d.%d : SI %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_SI); + eNB->dlsch_ra = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); + LOG_D(PHY,"eNB %d.%d : RA %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_ra); + eNB->dlsch_MCH = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); + LOG_D(PHY,"eNB %d.%d : MCH %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_MCH); + eNB->rx_total_gain_dB=130; + + for(i=0; imu_mimo_mode[i].dl_pow_off = 2; + + eNB->check_for_total_transmissions = 0; + eNB->check_for_MUMIMO_transmissions = 0; + eNB->FULL_MUMIMO_transmissions = 0; + eNB->check_for_SUMIMO_transmissions = 0; + fp->pucch_config_common.deltaPUCCH_Shift = 1; +} + +void init_eNB_afterRU(void) { + int inst,CC_id,ru_id,i,aa; + PHY_VARS_eNB *eNB; + + for (inst=0; instframe_parms.nb_antennas_rx = 0; + eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *)); + + for (int ce_level=0; ce_level<4; ce_level++) { + LOG_I(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); + eNB->prach_vars_br.rxsigF[ce_level] = (int16_t **)malloc16(64*sizeof(int16_t *)); + } + + for (ru_id=0,aa=0; ru_idnum_RU; ru_id++) { + eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx; + AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL, + "RU %d : common.rxdataF is NULL\n", + eNB->RU_list[ru_id]->idx); + AssertFatal(eNB->RU_list[ru_id]->prach_rxsigF!=NULL, + "RU %d : prach_rxsigF is NULL\n", + eNB->RU_list[ru_id]->idx); + + for (i=0; iRU_list[ru_id]->nb_rx; aa++,i++) { + LOG_I(PHY,"Attaching RU %d antenna %d to eNB antenna %d\n",eNB->RU_list[ru_id]->idx,i,aa); + eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[ru_id]->prach_rxsigF[i]; + + for (int ce_level=0; ce_level<4; ce_level++) + eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[ru_id]->prach_rxsigF_br[ce_level][i]; + + eNB->common_vars.rxdataF[aa] = eNB->RU_list[ru_id]->common.rxdataF[i]; + } + } + + /* TODO: review this code, there is something wrong. + * In monolithic mode, we come here with nb_antennas_rx == 0 + * (not tested in other modes). + */ + if (eNB->frame_parms.nb_antennas_rx < 1) { + LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx); + eNB->frame_parms.nb_antennas_rx = 1; + } else { + //LOG_I(PHY," Delete code\n"); + } + + if (eNB->frame_parms.nb_antennas_tx < 1) { + LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx); + eNB->frame_parms.nb_antennas_tx = 1; + } else { + //LOG_I(PHY," Delete code\n"); + } + + AssertFatal(eNB->frame_parms.nb_antennas_rx >0, + "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); + LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); + init_transport(eNB); + //init_precoding_weights(RC.eNB[inst][CC_id]); + } + + init_eNB_proc(inst); + } +} + +void init_eNB(int single_thread_flag,int wait_for_sync) { + int CC_id; + int inst; + PHY_VARS_eNB *eNB; + + if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB ** *) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **)); + + for (inst=0; instabstraction_flag = 0; + eNB->single_thread_flag = single_thread_flag; + AssertFatal((eNB->if_inst = IF_Module_init(inst))!=NULL,"Cannot register interface"); + eNB->if_inst->schedule_response = schedule_response; + eNB->if_inst->PHY_config_req = phy_config_request; + memset((void *)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO)); + memset((void *)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO)); + LOG_I(PHY,"Setting indication lists\n"); + eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = eNB->rx_pdu_list; + eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list; + eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list; + eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list; + eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list; + eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; + eNB->prach_energy_counter = 0; + } + } +} + +void stop_eNB(int nb_inst) { + for (int inst=0; instproc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *rxp[ru->nb_rx]; + unsigned int rxs; + int i; + openair0_timestamp ts=0,old_ts=0; + + for (i=0; inb_rx; i++) + rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; + + old_ts = proc->timestamp_rx; + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &ts, + rxp, + fp->samples_per_tti, + ru->nb_rx); + proc->timestamp_rx = ts-ru->ts_offset; + + // AssertFatal(rxs == fp->samples_per_tti, + // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); + if(rxs != fp->samples_per_tti) { + LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); + } + + if (proc->first_rx == 1) { + ru->ts_offset = proc->timestamp_rx; + proc->timestamp_rx = 0; + } else { + if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { + //LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_tti,ru->ts_offset); + ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); + proc->timestamp_rx = ts-ru->ts_offset; + } + } + + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; + proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; + // synchronize first reception to frame 0 subframe 0 + proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); + proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + + if (proc->first_rx == 0) { + if (proc->subframe_rx != *subframe) { + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe); + exit_fun("Exiting"); + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + } + + //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe); + + if (rxs != fp->samples_per_tti) { +#if defined(USRP_REC_PLAY) + exit_fun("Exiting IQ record/playback"); +#else + //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples"); +#endif + } +} + + +void tx_rf(RU_t *ru) { + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *txp[ru->nb_tx]; + int i; + lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); + lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); + int sf_extension = 0; + + if ((SF_type == SF_DL) || + (SF_type == SF_S)) { + int siglen=fp->samples_per_tti,flags=1; + + if (SF_type == SF_S) { + /* end_of_burst_delay is used to stop TX only "after a while". + * If we stop right after effective signal, with USRP B210 and + * B200mini, we observe a high EVM on the S subframe (on the + * PSS). + * A value of 400 (for 30.72MHz) solves this issue. This is + * the default. + */ + siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + + (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples) + + ru->end_of_burst_delay; + flags=3; // end of burst + } + + if (fp->frame_type == TDD && + SF_type == SF_DL && + prevSF_type == SF_UL) { + flags = 2; // start of burst + sf_extension = ru->sf_extension; + } + +#if defined(__x86_64) || defined(__i386__) +#ifdef __AVX2__ + sf_extension = (sf_extension)&0xfffffff8; +#else + sf_extension = (sf_extension)&0xfffffffc; +#endif +#elif defined(__arm__) + sf_extension = (sf_extension)&0xfffffffc; +#endif + + for (i=0; inb_tx; i++) + txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; + + /* add fail safe for late command end */ + // prepare tx buffer pointers + ru->rfdevice.trx_write_func(&ru->rfdevice, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + } +} +// this is for RU with local RF unit +void fill_rf_config(RU_t *ru, char *rf_config_file) { + int i; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + openair0_config_t *cfg = &ru->openair0_cfg; + //printf("////////////////numerology in config = %d\n",numerology); + int numerology = get_softmodem_params()->numerology; + + if(fp->N_RB_DL == 100) { + if(numerology == 0) { + if (fp->threequarter_fs) { + cfg->sample_rate=23.04e6; + cfg->samples_per_frame = 230400; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } else { + cfg->sample_rate=30.72e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + } else if(numerology == 1) { + cfg->sample_rate=61.44e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 20e6; + cfg->rx_bw = 20e6; + } else if(numerology == 2) { + cfg->sample_rate=122.88e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; + } else { + printf("Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology); + cfg->sample_rate=30.72e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + } else if(fp->N_RB_DL == 50) { + cfg->sample_rate=15.36e6; + cfg->samples_per_frame = 153600; + cfg->tx_bw = 5e6; + cfg->rx_bw = 5e6; + } else if (fp->N_RB_DL == 25) { + cfg->sample_rate=7.68e6; + cfg->samples_per_frame = 76800; + cfg->tx_bw = 2.5e6; + cfg->rx_bw = 2.5e6; + } else if (fp->N_RB_DL == 6) { + cfg->sample_rate=1.92e6; + cfg->samples_per_frame = 19200; + cfg->tx_bw = 1.5e6; + cfg->rx_bw = 1.5e6; + } else AssertFatal(1==0,"Unknown N_RB_DL %d\n",fp->N_RB_DL); + + if (fp->frame_type==TDD) + cfg->duplex_mode = duplex_mode_TDD; + else //FDD + cfg->duplex_mode = duplex_mode_FDD; + + cfg->Mod_id = 0; + cfg->num_rb_dl=fp->N_RB_DL; + cfg->tx_num_channels=ru->nb_tx; + cfg->rx_num_channels=ru->nb_rx; + cfg->clock_source=get_softmodem_params()->clock_source; + + for (i=0; inb_tx; i++) { + cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; + cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; + cfg->tx_gain[i] = (double)ru->att_tx; + cfg->rx_gain[i] = ru->max_rxgain-(double)ru->att_rx; + cfg->configFilename = rf_config_file; + printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n", + i, cfg->tx_gain[i], + cfg->rx_gain[i], + cfg->tx_freq[i], + cfg->rx_freq[i]); + } +} + +/* this function maps the RU tx and rx buffers to the available rf chains. + Each rf chain is is addressed by the card number and the chain on the card. The + rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple + antennas are mapped to successive RF chains on the same card. */ +int setup_RU_buffers(RU_t *ru) { + int i,j; + int card,ant; + //uint16_t N_TA_offset = 0; + LTE_DL_FRAME_PARMS *frame_parms; + + if (ru) { + frame_parms = &ru->frame_parms; + printf("setup_RU_buffers: frame_parms = %p\n",frame_parms); + } else { + printf("RU not initialized (NULL pointer)\n"); + return(-1); + } + + if (frame_parms->frame_type == TDD) { + if (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624; + else if (frame_parms->N_RB_DL == 50) ru->N_TA_offset = 624/2; + else if (frame_parms->N_RB_DL == 25) ru->N_TA_offset = 624/4; + + if(IS_SOFTMODEM_BASICSIM) + /* this is required for the basic simulator in TDD mode + * TODO: find a proper cleaner solution + */ + ru->N_TA_offset = 0; + + if (frame_parms->N_RB_DL == 100) /* no scaling to do */; + else if (frame_parms->N_RB_DL == 50) { + ru->sf_extension /= 2; + ru->end_of_burst_delay /= 2; + } else if (frame_parms->N_RB_DL == 25) { + ru->sf_extension /= 4; + ru->end_of_burst_delay /= 4; + } else { + printf("not handled, todo\n"); + exit(1); + } + } else { + ru->N_TA_offset = 0; + ru->sf_extension = 0; + ru->end_of_burst_delay = 0; + } + + if (ru->openair0_cfg.mmapped_dma == 1) { + // replace RX signal buffers with mmaped HW versions + for (i=0; inb_rx; i++) { + card = i/4; + ant = i%4; + printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + free(ru->common.rxdata[i]); + ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant]; + printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]); + + for (j=0; j<16; j++) { + printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]); + ru->common.rxdata[i][j] = 16-j; + } + } + + for (i=0; inb_tx; i++) { + card = i/4; + ant = i%4; + printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + free(ru->common.txdata[i]); + ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant]; + printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]); + + for (j=0; j<16; j++) { + printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]); + ru->common.txdata[i][j] = 16-j; + } + } + } else { // not memory-mapped DMA + //nothing to do, everything already allocated in lte_init + } + + return(0); +} +static void *ru_thread( void *param ) { + static int ru_thread_status; + RU_t *ru = (RU_t *)param; + RU_proc_t *proc = &ru->proc; + int subframe =9; + int frame =1023; + // set default return value + ru_thread_status = 0; + + if (ru->if_south == LOCAL_RF) { // configure RF parameters only + fill_rf_config(ru,ru->rf_config_file); + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); + openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + } + + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + } + + LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); + pthread_mutex_lock(&RC.ru_mutex); + RC.ru_mask &= ~(1<idx); + pthread_cond_signal(&RC.ru_cond); + pthread_mutex_unlock(&RC.ru_mutex); + pthread_mutex_lock(&proc->mutex_FH1); + proc->instance_cnt_FH1 = 0; + pthread_mutex_unlock(&proc->mutex_FH1); + pthread_cond_signal(&proc->cond_FH1); + wait_sync("ru_thread"); + + // Start RF device if any + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + LOG_E(HW,"Could not start the RF device\n"); + else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); + } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + + // if an asnych_rxtx thread exists + // wakeup the thread because the devices are ready at this point + + if ((ru->fh_south_asynch_in)||(ru->fh_north_asynch_in)) { + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->instance_cnt_asynch_rxtx=0; + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + pthread_cond_signal(&proc->cond_asynch_rxtx); + } else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx); + + // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices + while (!oai_exit) { + // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. + // They are set on the first rx/tx in the underly FH routines. + if (subframe==9) { + subframe=0; + frame++; + frame&=1023; + } else { + subframe++; + } + + // synchronization on input FH interface, acquire signals/data and block + AssertFatal(ru->fh_south_in, "No fronthaul interface at south port"); + ru->fh_south_in(ru,&frame,&subframe); + + // adjust for timing offset between RU + if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023; + + // do RX front-end processing (frequency-shift, dft) if needed + if (ru->feprx) ru->feprx(ru); + + // At this point, all information for subframe has been received on FH interface + // If this proc is to provide synchronization, do so + // Fixme: not used + // wakeup_slaves(proc); + for (int i=0; inum_eNB; i++) { + char string[20]; + sprintf(string,"Incoming RU %d",ru->idx); + ru->eNB_top(ru->eNB_list[i],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru); + } + + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } + + printf( "Exiting ru_thread \n"); + + if (ru->stop_rf != NULL) { + if (ru->stop_rf(ru) != 0) + LOG_E(HW,"Could not stop the RF device\n"); + else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); + } + + ru_thread_status = 0; + return &ru_thread_status; +} +int start_if(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB) { + return(ru->ifdevice.trx_start_func(&ru->ifdevice)); +} + +int start_rf(RU_t *ru) { + return(ru->rfdevice.trx_start_func(&ru->rfdevice)); +} + +int stop_rf(RU_t *ru) { + ru->rfdevice.trx_end_func(&ru->rfdevice); + return 0; +} +void init_precoding_weights(PHY_VARS_eNB *eNB) { + int layer,ru_id,aa,re,ue,tb; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + RU_t *ru; + LTE_eNB_DLSCH_t *dlsch; + + // init precoding weigths + for (ue=0; uedlsch[ue][tb]; + + for (layer=0; layer<4; layer++) { + int nb_tx=0; + + for (ru_id=0; ru_idnb_tx; + } + + dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *)); + + for (aa=0; aaue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); + + for (re=0; reofdm_symbol_size; re++) { + dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + } + } +} + +void set_function_spec_param(RU_t *ru) { + + switch (ru->if_south) { + case LOCAL_RF: { // this is an RU with integrated RF (RRU, eNB) + ru->do_prach = 0; // no prach processing in RU + ru->feprx = fep_full; + ru->feptx_ofdm = feptx_ofdm; + ru->feptx_prec = feptx_prec; // this is fep with idft and precoding + ru->fh_north_in = NULL; // no incoming fronthaul from north + ru->fh_north_out = NULL; // no outgoing fronthaul to north + ru->start_if = NULL; // no if interface + ru->rfdevice.host_type = RAU_HOST; + } + + ru->fh_south_in = rx_rf; // local synchronous RF RX + ru->fh_south_out = tx_rf; // local synchronous RF TX + ru->start_rf = start_rf; // need to start the local RF interface + ru->stop_rf = stop_rf; + ru->eNB_top=eNB_top; + printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); + /* + if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise + fill_rf_config(ru,rf_config_file); + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); + } + + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + }*/ + break; + + default: + LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + break; + } // switch on interface type +} + +//extern void RCconfig_RU(void); + +void init_RU(char *rf_config_file) { + int ru_id; + RU_t *ru; + PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; + int i; + int CC_id; + // create status mask + RC.ru_mask = 0; + pthread_mutex_init(&RC.ru_mutex,NULL); + pthread_cond_init(&RC.ru_cond,NULL); + // read in configuration file) + printf("configuring RU from file\n"); + RCconfig_RU(); + LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs()); + + if (RC.nb_CC != 0) + for (i=0; inum_RU=0; + + LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); + + for (ru_id=0; ru_idrf_config_file = rf_config_file; + ru->idx = ru_id; + ru->ts_offset = 0; + // use eNB_list[0] as a reference for RU frame parameters + // NOTE: multiple CC_id are not handled here yet! + + if (ru->num_eNB > 0) { + LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + + if (ru->eNB_list[0] == 0) { + LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__); + ru->eNB_list[0] = RC.eNB[0][0]; + ru->num_eNB=1; + // + // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU + // + } else { + LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); + } + } + + eNB0 = ru->eNB_list[0]; + LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); + LOG_D(PHY, "eNB0:%p\n", eNB0); + + if (eNB0) { + if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) + AssertFatal(eNB0!=NULL,"eNB0 is null!\n"); + + if (eNB0) { + LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); + memcpy((void *)&ru->frame_parms,(void *)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); + // attach all RU to all eNBs in its list/ + LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU); + + for (i=0; inum_eNB; i++) { + eNB0 = ru->eNB_list[i]; + eNB0->RU_list[eNB0->num_RU++] = ru; + } + } + } + + LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); + set_function_spec_param(ru); + LOG_I(PHY,"Starting ru_thread %d\n",ru_id); + init_RU_proc(ru); + } // for ru_id + + // sleep(1); + LOG_D(HW,"[lte-softmodem.c] RU threads created\n"); +} + +void stop_RU(int nb_ru) { + for (int inst = 0; inst < nb_ru; inst++) { + LOG_I(PHY, "Stopping RU %d processing threads\n", inst); + kill_RU_proc(RC.ru[inst]); + } +} +/* --------------------------------------------------------*/ +/* from here function to use configuration module */ +void RCconfig_RU(void) { + int j = 0; + int i = 0; + paramdef_t RUParams[] = RUPARAMS_DESC; + paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; + config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); + + if ( RUParamList.numelt > 0) { + RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); + RC.ru_mask=(1<idx = j; + printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); + RC.ru[j]->if_timing = synch_to_ext_device; + + if (RC.nb_L1_inst >0) + RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; + else + RC.ru[j]->num_eNB = 0; + + for (i=0; inum_eNB; i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0]; + + if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) { + RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr)); + } + + if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) { + if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) { + RC.ru[j]->openair0_cfg.clock_source = internal; + LOG_D(PHY, "RU clock source set as internal\n"); + } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) { + RC.ru[j]->openair0_cfg.clock_source = external; + LOG_D(PHY, "RU clock source set as external\n"); + } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) { + RC.ru[j]->openair0_cfg.clock_source = gpsdo; + LOG_D(PHY, "RU clock source set as gpsdo\n"); + } else { + LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); + } + } + + if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { + if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = eNodeB_3GPP; + printf("Setting function for RU %d to eNodeB_3GPP\n",j); + } else { + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + } + + RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; + RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); + RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; + /* sf_extension is in unit of samples for 30.72MHz here, has to be scaled later */ + RC.ru[j]->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr); + RC.ru[j]->end_of_burst_delay = *(RUParamList.paramarray[j][RU_END_OF_BURST_DELAY_IDX].uptr); + + for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; + } //strcmp(local_rf, "yes") == 0 + else { + printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + } /* strcmp(local_rf, "yes") != 0 */ + + RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); + RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); + RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); + RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); + }// j=0..num_rus + } else { + RC.nb_RU = 0; + } // setting != NULL + + return; +} diff --git a/executables/transport_split.c b/executables/transport_split.c index a1e0738458..fe9e1a419c 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -3,63 +3,70 @@ int createListner (port) { int sock; AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); - struct sockaddr_in addr = { + struct sockaddr_in addr = { sin_family: AF_INET, sin_port: -htons(port), + htons(port), sin_addr: { s_addr: INADDR_ANY } - }; - int enable=1; - AssertFatal(setsockopt(eth->sockfdc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); - AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); - struct timeval tv={0,UDP_TIMEOUT}; - AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); - // Make a send/recv buffer larger than a a couple of subframe - // so the kernel will store for us in and out paquets - int buff=1000*1000*10; - AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, ""); - AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, ""); + }; + int enable=1; + AssertFatal(setsockopt(eth->sockfdc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); + AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); + struct timeval tv= {0,UDP_TIMEOUT}; + AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); + // Make a send/recv buffer larger than a a couple of subframe + // so the kernel will store for us in and out paquets + int buff=1000*1000*10; + AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, ""); + AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, ""); } // sock: udp socket // expectedTS: the expected timestamp, 0 if unknown // bufferZone: a reception area of bufferSize -int receiveSubFrame(int sock, uint64_t expectedTS, void* bufferZone, int bufferSize) { +int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int bufferSize) { int rcved=0; + do { //read all subframe data from the control unit int ret=recv(sock, bufferZone, bufferSize, 0); + if ( ret==-1) { if ( errno == EWOULDBLOCK || errno== EINTR ) { - return rcved; // Timeout, subframe incomplete + return rcved; // Timeout, subframe incomplete } else { - LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); - return -1; + LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); + return -1; } } else { - commonUDP_t * tmp=(commonUDP_t *)bufferZone; + commonUDP_t *tmp=(commonUDP_t *)bufferZone; + if ( expectedTS && tmp->timestamp != expectedTS) { - LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n"); + LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n"); } else { - rcved++; - bufferZone+=ret; + rcved++; + bufferZone+=ret; } } } while ( !recved || recved < tmp->nbBlocks); + return recv; } -int sendSubFrame(int sock, void* bufferZone, int nbBlocks) { +int sendSubFrame(int sock, void *bufferZone, int nbBlocks) { do { int sz=alignedSize(bufferZone); int ret=send(sock, bufferZone, sz, 0); + if ( ret != sz ) LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d)\n", - sz, ret, errno); + sz, ret, errno); + bufferZone+=sz; nbBlocks--; } while (nbBlocks); + return 0; } diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index e81e958184..1bb424d115 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -135,9 +135,6 @@ void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_si } out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0)); - printf("in: %d, out %d= %f*%f + %f*%f\n", - input_sig[((TS+i)*nbTx)%CirSize].r, out_ptr->r , rx_tmp.x, - pathLossLinear, noise_per_sample,gaussdouble(0.0,1.0)); out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0)); out_ptr++; } diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 8ae3d8956c..b9c6b19f11 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -1146,7 +1146,7 @@ void init_eNB_afterRU(void) { for (CC_id=0; CC_idmutex_FH,&wait) != 0) { - LOG_E( PHY, "ERROR pthread_mutex_lock for RU %d slave %d (IC %d)\n",proc->ru->idx,slave_proc->ru->idx,slave_proc->instance_cnt_FH); - exit_fun( "error locking mutex_rxtx" ); - break; - } + AssertFatal(pthread_mutex_timedlock(&slave_proc->mutex_FH,&wait) == 0, + "ERROR pthread_mutex_lock for RU %d slave %d (IC %d)\n", + proc->ru->idx,slave_proc->ru->idx,slave_proc->instance_cnt_FH); int cnt_slave = ++slave_proc->instance_cnt_FH; slave_proc->frame_rx = proc->frame_rx; @@ -1628,7 +1626,6 @@ static void *ru_thread( void *param ) { pthread_cond_signal(&proc->cond_FH1); wait_sync("ru_thread"); - if(!(get_softmodem_params()->emulate_rf)) { // Start RF device if any if (ru->start_rf) { if (ru->start_rf(ru) != 0) @@ -1648,12 +1645,9 @@ static void *ru_thread( void *param ) { // if this is a slave RRU, try to synchronize on the DL frequency if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru); - } // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,sched_getcpu()); - LOG_ENTER(PHY); // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. // They are set on the first rx/tx in the underly FH routines. if (subframe==9) { @@ -1665,37 +1659,9 @@ static void *ru_thread( void *param ) { } // synchronization on input FH interface, acquire signals/data and block - if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe); - else AssertFatal(1==0, "No fronthaul interface at south port"); + AssertFatal(ru->fh_south_in, "No fronthaul interface at south port"); + ru->fh_south_in(ru,&frame,&subframe); -#ifdef PHY_TX_THREAD - - if(first_phy_tx == 0) { - phy_tx_end = 0; - phy_tx_txdataF_end = 0; - - if(pthread_mutex_lock(&ru->proc.mutex_phy_tx) != 0) { - LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for phy tx thread (IC %d)\n", ru->proc.instance_cnt_phy_tx); - exit_fun( "error locking mutex_rxtx" ); - } - - if (ru->proc.instance_cnt_phy_tx==-1) { - ++ru->proc.instance_cnt_phy_tx; - // the thread can now be woken up - AssertFatal(pthread_cond_signal(&ru->proc.cond_phy_tx) == 0, "ERROR pthread_cond_signal for phy_tx thread\n"); - } else { - LOG_E(PHY,"phy tx thread busy, skipping\n"); - ++ru->proc.instance_cnt_phy_tx; - } - - pthread_mutex_unlock( &ru->proc.mutex_phy_tx ); - } else { - phy_tx_end = 1; - phy_tx_txdataF_end = 1; - } - - first_phy_tx = 0; -#endif LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n", ru->do_prach, is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx), @@ -1720,72 +1686,26 @@ static void *ru_thread( void *param ) { // At this point, all information for subframe has been received on FH interface // If this proc is to provide synchronization, do so - wakeup_slaves(proc); -#if defined(PRE_SCD_THREAD) - new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use; - dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use; - memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); - memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); - - if (pthread_mutex_lock(&ru->proc.mutex_pre_scd)!= 0) { - LOG_E( PHY, "[eNB] error locking proc mutex for eNB pre scd\n"); - exit_fun("error locking mutex_time"); + // Fixme: not used + // wakeup_slaves(proc); + for (int i=0; inum_eNB; i++) { + char string[20]; + sprintf(string,"Incoming RU %d",ru->idx); + ru->eNB_top(ru->eNB_list[i],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru); } - - ru->proc.instance_pre_scd++; - - if (ru->proc.instance_pre_scd == 0) { - if (pthread_cond_signal(&ru->proc.cond_pre_scd) != 0) { - LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB pre scd\n" ); - exit_fun( "ERROR pthread_cond_signal cond_pre_scd" ); - } - } else { - LOG_E( PHY, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n", - frame,subframe,ru->proc.instance_pre_scd ); - } - - if (pthread_mutex_unlock(&ru->proc.mutex_pre_scd)!= 0) { - LOG_E( PHY, "[eNB] error unlocking mutex_pre_scd mutex for eNB pre scd\n"); - exit_fun("error unlocking mutex_pre_scd"); - } - -#endif - - // wakeup all eNB processes waiting for this RU - if (ru->num_eNB>0) wakeup_L1s(ru); - -#ifndef PHY_TX_THREAD - - if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0) { - // do TX front-end processing if needed (precoding and/or IDFTs) - if (ru->feptx_prec) ru->feptx_prec(ru); - - // do OFDM if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); - - if(!(get_softmodem_params()->emulate_rf)) { - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); - - if (ru->fh_north_out) ru->fh_north_out(ru); - } - - proc->emulate_rf_busy = 0; - } - -#else - struct timespec time_req, time_rem; - time_req.tv_sec = 0; - time_req.tv_nsec = 10000; - - while((!oai_exit)&&(phy_tx_end == 0)) { - nanosleep(&time_req,&time_rem); - continue; - } - -#endif + + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } - + printf( "Exiting ru_thread \n"); if (!(get_softmodem_params()->emulate_rf)) { diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 50e866358b..f8a42de069 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -505,9 +505,7 @@ int main( int argc, char **argv ) { } for (int enb_id = 0; enb_id < RC.nb_inst; enb_id++) { - MessageDef *msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ); - RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; - itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + openair_rrc_eNB_configuration(enb_id, &RC.rrc[enb_id]->configuration); } } else { printf("RC.nb_inst = 0, Initializing L1\n"); @@ -530,12 +528,9 @@ int main( int argc, char **argv ) { // init UE_PF_PO and mutex lock pthread_mutex_init(&ue_pf_po_mutex, NULL); memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*MAX_MOBILES_PER_ENB*MAX_NUM_CCs); - mlockall(MCL_CURRENT | MCL_FUTURE); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); - - rt_sleep_ns(10*100000000ULL); if (NFAPI_MODE!=NFAPI_MONOLITHIC) { @@ -563,9 +558,10 @@ int main( int argc, char **argv ) { // for (CC_id=0;CC_idinit_SI()->rrc_mac_config_req_eNB ()->phy_config_request () sets the wait_eNBs() tested flag + // wait_eNBs(); + // printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator. // but RU thread deals with pre_scd and this is necessary in VNF and simulator. @@ -588,6 +584,9 @@ int main( int argc, char **argv ) { printf("wait RUs\n"); // end of CI modifications + // fixme: very weird usage of bitmask + // lack of mutex in: ru_thread_prach(),... + // wait_RUs() is wrong and over complex! wait_RUs(); LOG_I(ENB_APP,"RC.nb_RU:%d\n", RC.nb_RU); // once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration) From 217491cbbfe2a1f18a67c67a386300a63949395c Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 1 Jul 2019 15:46:38 +0200 Subject: [PATCH 004/175] progress in main cleanup coding --- cmake_targets/CMakeLists.txt | 10 +- executables/{simple_main.c => main-ocp.c} | 528 +++++++++++----------- executables/split_headers.h | 5 +- targets/ARCH/rfsimulator/simulator.c | 64 ++- targets/RT/USER/lte-softmodem.c | 158 +++++-- 5 files changed, 443 insertions(+), 322 deletions(-) rename executables/{simple_main.c => main-ocp.c} (95%) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index c9741ce488..10f263100b 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2090,9 +2090,9 @@ target_link_libraries (lte-softmodem -Wl,--end-group z dl) -add_executable(simple-softmodem +add_executable(ocp-softmodem ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_DIR}/executables/simple_main.c + ${OPENAIR_DIR}/executables/main-ocp.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c @@ -2113,15 +2113,15 @@ add_executable(simple-softmodem ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} ) -add_dependencies(simple-softmodem rrc_flag s1ap_flag x2_flag) +add_dependencies(ocp-softmodem rrc_flag s1ap_flag x2_flag) -target_link_libraries (simple-softmodem +target_link_libraries (ocp-softmodem -Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} LFDS7 NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) -target_link_libraries (simple-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) +target_link_libraries (ocp-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) add_executable(cu_test ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c diff --git a/executables/simple_main.c b/executables/main-ocp.c similarity index 95% rename from executables/simple_main.c rename to executables/main-ocp.c index 7a15f6df3c..b3472f17cb 100644 --- a/executables/simple_main.c +++ b/executables/main-ocp.c @@ -50,9 +50,6 @@ void init_eNB_proc(int inst) { proc->CC_id = CC_id; proc->first_rx =1; proc->first_tx =1; - proc->RU_mask_tx = (1<num_RU)-1; - proc->RU_mask =0; - proc->RU_mask_prach =0; pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); pthread_mutex_init( &L1_proc->mutex, NULL); pthread_cond_init( &L1_proc->cond, NULL); @@ -94,102 +91,12 @@ void init_RU_proc(RU_t *ru) { for (i=0; i<10; i++) proc->symbol_mask[i]=0; pthread_mutex_init( &proc->mutex_synch,NULL); - pthread_cond_init( &proc->cond_synch,NULL); pthread_cond_init( &proc->cond_eNBs, NULL); - pthread_t t; threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); } -void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - // set timing for prach thread - proc->frame_prach = frame; - proc->subframe_prach = subframe; - prach_procedures(eNB,0); - } -} - -void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); - // set timing for prach thread - proc->frame_prach_br = frame; - proc->subframe_prach_br = subframe; - prach_procedures(eNB,1); - } -} - -static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { - - AssertFatal( eNB !=NULL, ""); - - if (NFAPI_MODE==NFAPI_MODE_PNF) { - // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick - //add_subframe(&frame, &subframe, 4); - //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); - oai_subframe_ind(proc->frame_rx, proc->subframe_rx); - } - - AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && - eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); - - wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); - wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); - release_UE_in_freeList(eNB->Mod_id); - - // UE-specific RX processing for subframe n - if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX(eNB, proc); - } - - pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.frame = proc->frame_rx; - eNB->UL_INFO.subframe = proc->subframe_rx; - eNB->UL_INFO.module_id = eNB->Mod_id; - eNB->UL_INFO.CC_id = eNB->CC_id; - eNB->if_inst->UL_indication(&eNB->UL_INFO); - pthread_mutex_unlock(&eNB->UL_INFO_mutex); - phy_procedures_eNB_TX(eNB, proc, 1); - - return(0); -} - -void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { - L1_proc_t *proc = &eNB->proc; - L1_rxtx_proc_t *L1_proc = &proc->L1_proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - RU_proc_t *ru_proc=&ru->proc; - proc->frame_rx = frame_rx; - proc->subframe_rx = subframe_rx; - - if (!oai_exit) { - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); - L1_proc->frame_rx = ru_proc->frame_rx; - L1_proc->subframe_rx = ru_proc->subframe_rx; - L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? - (L1_proc->frame_rx+1)&1023 : - L1_proc->frame_rx; - L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; - - if (rxtx(eNB,L1_proc,string) < 0) - LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; - } -} - void init_transport(PHY_VARS_eNB *eNB) { int i; int j; @@ -354,129 +261,6 @@ void stop_eNB(int nb_inst) { kill_eNB_proc(inst); } } - -void rx_rf(RU_t *ru,int *frame,int *subframe) { - RU_proc_t *proc = &ru->proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - void *rxp[ru->nb_rx]; - unsigned int rxs; - int i; - openair0_timestamp ts=0,old_ts=0; - - for (i=0; inb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; - - old_ts = proc->timestamp_rx; - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, - &ts, - rxp, - fp->samples_per_tti, - ru->nb_rx); - proc->timestamp_rx = ts-ru->ts_offset; - - // AssertFatal(rxs == fp->samples_per_tti, - // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); - if(rxs != fp->samples_per_tti) { - LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); - } - - if (proc->first_rx == 1) { - ru->ts_offset = proc->timestamp_rx; - proc->timestamp_rx = 0; - } else { - if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { - ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); - proc->timestamp_rx = ts-ru->ts_offset; - } - } - - proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; - proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; - // synchronize first reception to frame 0 subframe 0 - proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); - proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; - proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; - - if (proc->first_rx == 0) { - AssertFatal( proc->subframe_rx == *subframe && proc->frame_rx == *frame , - "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d) (proc->frame_rx %d frame %d)\n", - (long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe, proc->frame_rx,*frame); - } else { - proc->first_rx = 0; - *frame = proc->frame_rx; - *subframe = proc->subframe_rx; - } - - if (rxs != fp->samples_per_tti) { -#if defined(USRP_REC_PLAY) - exit_fun("Exiting IQ record/playback"); -#else - //exit_fun( "problem receiving samples" ); - LOG_E(PHY, "problem receiving samples"); -#endif - } -} - -void tx_rf(RU_t *ru) { - RU_proc_t *proc = &ru->proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - void *txp[ru->nb_tx]; - int i; - lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); - lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); - int sf_extension = 0; - - if ((SF_type == SF_DL) || - (SF_type == SF_S)) { - int siglen=fp->samples_per_tti,flags=1; - - if (SF_type == SF_S) { - /* end_of_burst_delay is used to stop TX only "after a while". - * If we stop right after effective signal, with USRP B210 and - * B200mini, we observe a high EVM on the S subframe (on the - * PSS). - * A value of 400 (for 30.72MHz) solves this issue. This is - * the default. - */ - siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) - + (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples) - + ru->end_of_burst_delay; - flags=3; // end of burst - } - - if (fp->frame_type == TDD && - SF_type == SF_DL && - prevSF_type == SF_UL) { - flags = 2; // start of burst - sf_extension = ru->sf_extension; - } - -#if defined(__x86_64) || defined(__i386__) -#ifdef __AVX2__ - sf_extension = (sf_extension)&0xfffffff8; -#else - sf_extension = (sf_extension)&0xfffffffc; -#endif -#elif defined(__arm__) - sf_extension = (sf_extension)&0xfffffffc; -#endif - - for (i=0; inb_tx; i++) - txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; - - /* add fail safe for late command end */ - // prepare tx buffer pointers - ru->rfdevice.trx_write_func(&ru->rfdevice, - proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, - txp, - siglen+sf_extension, - ru->nb_tx, - flags); - LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, - (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); - } -} - // this is for RU with local RF unit void fill_rf_config(RU_t *ru, char *rf_config_file) { int i; @@ -642,6 +426,247 @@ int setup_RU_buffers(RU_t *ru) { return(0); } + +void init_precoding_weights(PHY_VARS_eNB *eNB) { + int layer,ru_id,aa,re,ue,tb; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + RU_t *ru; + LTE_eNB_DLSCH_t *dlsch; + + // init precoding weigths + for (ue=0; uedlsch[ue][tb]; + + for (layer=0; layer<4; layer++) { + int nb_tx=0; + + for (ru_id=0; ru_idnb_tx; + } + + dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *)); + + for (aa=0; aaue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); + + for (re=0; reofdm_symbol_size; re++) { + dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + } + } +} + +void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + prach_procedures(eNB,0); + } +} + +void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); + // set timing for prach thread + proc->frame_prach_br = frame; + proc->subframe_prach_br = subframe; + prach_procedures(eNB,1); + } +} + +static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { + AssertFatal( eNB !=NULL, ""); + + if (NFAPI_MODE==NFAPI_MODE_PNF) { + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + //add_subframe(&frame, &subframe, 4); + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + oai_subframe_ind(proc->frame_rx, proc->subframe_rx); + } + + AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && + eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); + wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); + wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); + release_UE_in_freeList(eNB->Mod_id); + + // UE-specific RX processing for subframe n + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + phy_procedures_eNB_uespec_RX(eNB, proc); + } + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.frame = proc->frame_rx; + eNB->UL_INFO.subframe = proc->subframe_rx; + eNB->UL_INFO.module_id = eNB->Mod_id; + eNB->UL_INFO.CC_id = eNB->CC_id; + eNB->if_inst->UL_indication(&eNB->UL_INFO); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + phy_procedures_eNB_TX(eNB, proc, 1); + return(0); +} + +void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { + L1_proc_t *proc = &eNB->proc; + L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *ru_proc=&ru->proc; + proc->frame_rx = frame_rx; + proc->subframe_rx = subframe_rx; + + if (!oai_exit) { + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->subframe_rx = ru_proc->subframe_rx; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? + (L1_proc->frame_rx+1)&1023 : + L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; + + if (rxtx(eNB,L1_proc,string) < 0) + LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); + + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; + } +} + +void rx_rf(RU_t *ru,int *frame,int *subframe) { + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *rxp[ru->nb_rx]; + unsigned int rxs; + int i; + openair0_timestamp ts=0,old_ts=0; + + for (i=0; inb_rx; i++) + rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; + + old_ts = proc->timestamp_rx; + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &ts, + rxp, + fp->samples_per_tti, + ru->nb_rx); + proc->timestamp_rx = ts-ru->ts_offset; + + // AssertFatal(rxs == fp->samples_per_tti, + // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); + if(rxs != fp->samples_per_tti) { + LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); + } + + if (proc->first_rx == 1) { + ru->ts_offset = proc->timestamp_rx; + proc->timestamp_rx = 0; + } else { + if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { + ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); + proc->timestamp_rx = ts-ru->ts_offset; + } + } + + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; + proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; + // synchronize first reception to frame 0 subframe 0 + proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); + proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + + if (proc->first_rx == 0) { + AssertFatal( proc->subframe_rx == *subframe && proc->frame_rx == *frame, + "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d) (proc->frame_rx %d frame %d)\n", + (long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe, proc->frame_rx,*frame); + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + } + + if (rxs != fp->samples_per_tti) { +#if defined(USRP_REC_PLAY) + exit_fun("Exiting IQ record/playback"); +#else + //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples"); +#endif + } +} + +void tx_rf(RU_t *ru) { + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *txp[ru->nb_tx]; + int i; + lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); + lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); + int sf_extension = 0; + + if ((SF_type == SF_DL) || + (SF_type == SF_S)) { + int siglen=fp->samples_per_tti,flags=1; + + if (SF_type == SF_S) { + /* end_of_burst_delay is used to stop TX only "after a while". + * If we stop right after effective signal, with USRP B210 and + * B200mini, we observe a high EVM on the S subframe (on the + * PSS). + * A value of 400 (for 30.72MHz) solves this issue. This is + * the default. + */ + siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + + (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples) + + ru->end_of_burst_delay; + flags=3; // end of burst + } + + if (fp->frame_type == TDD && + SF_type == SF_DL && + prevSF_type == SF_UL) { + flags = 2; // start of burst + sf_extension = ru->sf_extension; + } + +#if defined(__x86_64) || defined(__i386__) +#ifdef __AVX2__ + sf_extension = (sf_extension)&0xfffffff8; +#else + sf_extension = (sf_extension)&0xfffffffc; +#endif +#elif defined(__arm__) + sf_extension = (sf_extension)&0xfffffffc; +#endif + + for (i=0; inb_tx; i++) + txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; + + /* add fail safe for late command end */ + // prepare tx buffer pointers + ru->rfdevice.trx_write_func(&ru->rfdevice, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + } +} + static void *ru_thread( void *param ) { static int ru_thread_status; RU_t *ru = (RU_t *)param; @@ -664,10 +689,6 @@ static void *ru_thread( void *param ) { } LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); - pthread_mutex_lock(&RC.ru_mutex); - RC.ru_mask &= ~(1<idx); - pthread_cond_signal(&RC.ru_cond); - pthread_mutex_unlock(&RC.ru_mutex); wait_sync("ru_thread"); // Start RF device if any @@ -745,41 +766,7 @@ int stop_rf(RU_t *ru) { return 0; } -void init_precoding_weights(PHY_VARS_eNB *eNB) { - int layer,ru_id,aa,re,ue,tb; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - RU_t *ru; - LTE_eNB_DLSCH_t *dlsch; - - // init precoding weigths - for (ue=0; uedlsch[ue][tb]; - - for (layer=0; layer<4; layer++) { - int nb_tx=0; - - for (ru_id=0; ru_idnb_tx; - } - - dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *)); - - for (aa=0; aaue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); - - for (re=0; reofdm_symbol_size; re++) { - dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; - } - } - } - } - } -} - void set_function_spec_param(RU_t *ru) { - switch (ru->if_south) { case LOCAL_RF: { // this is an RU with integrated RF (RRU, eNB) ru->do_prach = 0; // no prach processing in RU @@ -819,21 +806,20 @@ void set_function_spec_param(RU_t *ru) { //extern void RCconfig_RU(void); -void init_RU(char *rf_config_file) { +void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t time_source,int send_dmrssync) { int ru_id; RU_t *ru; PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; int i; int CC_id; // create status mask - RC.ru_mask = 0; pthread_mutex_init(&RC.ru_mutex,NULL); pthread_cond_init(&RC.ru_cond,NULL); // read in configuration file) printf("configuring RU from file\n"); RCconfig_RU(); LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n", - RC.nb_L1_inst,RC.nb_RU,get_nprocs()); + RC.nb_L1_inst,RC.nb_RU,get_nprocs()); if (RC.nb_CC != 0) for (i=0; irf_config_file = rf_config_file; ru->idx = ru_id; ru->ts_offset = 0; + + if (ru->is_slave == 1) { + ru->in_synch = 0; + ru->generate_dmrs_sync = 0; + } else { + ru->in_synch = 1; + ru->generate_dmrs_sync=send_dmrssync; + } + + ru->cmd = EMPTY; + ru->south_out_cnt= 0; // use eNB_list[0] as a reference for RU frame parameters // NOTE: multiple CC_id are not handled here yet! + ru->openair0_cfg.clock_source = clock_source; + ru->openair0_cfg.time_source = time_source; + + // ru->generate_dmrs_sync = (ru->is_slave == 0) ? 1 : 0; + if (ru->generate_dmrs_sync == 1) { + generate_ul_ref_sigs(); + ru->dmrssync = (int16_t *)malloc16_clear(ru->frame_parms.ofdm_symbol_size*2*sizeof(int16_t)); + } + + ru->wakeup_L1_sleeptime = 2000; + ru->wakeup_L1_sleep_cnt_max = 3; if (ru->num_eNB > 0) { LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", - __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); if (ru->eNB_list[0] == 0) { LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", - __FUNCTION__); + __FUNCTION__); ru->eNB_list[0] = RC.eNB[0][0]; ru->num_eNB=1; // @@ -916,8 +924,6 @@ void RCconfig_RU(void) { if ( RUParamList.numelt > 0) { RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); - RC.ru_mask=(1<circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, ""); ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; - ptr->alreadyRead=false; ptr->lastReceivedTS=0; + ptr->lastWroteTS=0; ptr->headerMode=true; ptr->transferPtr=(char *)&ptr->th; ptr->remainToTransfer=sizeof(samplesBlockHeader_t); @@ -319,21 +319,22 @@ sin_addr: setblocking(sock, notBlocking); allocCirBuf(t, sock); - t->buf[sock].alreadyRead=true; // UE will start blocking on read return 0; } -uint64_t lastW=-1; int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { rfsimulator_state_t *t = device->priv; LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); - for (int i=0; ibuf[i]; - if (ptr->conn_sock >= 0 ) { + for (int i=0; ibuf[i]; + + if (b->conn_sock >= 0 ) { + if ( abs((double)b->lastWroteTS-timestamp) > (double)CirSize) + LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS); samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp}; - fullwrite(ptr->conn_sock,&header, sizeof(header), t); + fullwrite(b->conn_sock,&header, sizeof(header), t); sample_t tmpSamples[nsamps][nbAnt]; for(int a=0; aconn_sock >= 0 ) - fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); + if (b->conn_sock >= 0 ) { + fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); + b->lastWroteTS=timestamp+nsamps; + } } } - lastW=timestamp; LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) ); // Let's verify we don't have incoming data // This is mandatory when the opposite side don't transmit - // This is mandatory when the opposite side don't transmit flushInput(t, 0); pthread_mutex_unlock(&Sockmutex); return nsamps; @@ -425,7 +426,6 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { AssertFatal( (t->typeStamp == UE_MAGICDL_FDD && b->th.magic==ENB_MAGICDL_FDD) || (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol"); b->headerMode=false; - b->alreadyRead=true; if ( b->lastReceivedTS != b->th.timestamp) { int nbAnt= b->th.nbAnt; @@ -441,8 +441,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { } b->lastReceivedTS=b->th.timestamp; - AssertFatal(lastW == -1 || ( abs((double)lastW-b->lastReceivedTS) < (double)CirSize), - "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", lastW, b->lastReceivedTS); + AssertFatal(b->lastWroteTS == 0 || ( abs((double)b->lastWroteTS-b->lastReceivedTS) < (double)CirSize), + "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS); b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); } @@ -498,15 +498,33 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo return nsamps; } } else { + bool have_to_wait; do { have_to_wait=false; for ( int sock=0; sockbuf[sock].circularBuf && t->buf[sock].alreadyRead ) - if ( t->buf[sock].lastReceivedTS == 0 || - (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) { + buffer_t *b=&t->buf[sock]; + if ( b->circularBuf) { + LOG_D(HW,"sock: %d, lastWroteTS: %lu, lastRecvTS: %lu, TS must be avail: %lu\n", + sock, b->lastWroteTS, + b->lastReceivedTS, + t->nextTimestamp+nsamps); + if ( b->lastReceivedTS > b->lastWroteTS ) { + // The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance + // This occurs for example when UE is in sync mode: it doesn't transmit + // with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power + struct complex16 v={0}; + void *samplesVoid[b->th.nbAnt]; + for ( int i=0; i th.nbAnt; i++) + samplesVoid[i]=(void*)&v; + rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0); + } + } + + if ( b->circularBuf ) + if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) { have_to_wait=true; break; } @@ -529,7 +547,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for (int sock=0; sockbuf[sock]; - if ( ptr->circularBuf && ptr->alreadyRead ) { + if ( ptr->circularBuf ) { bool reGenerateChannel=false; //fixme: when do we regenerate diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index dcd7966874..37e94de2b6 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -80,7 +80,7 @@ unsigned short config_frames[4] = {2,9,11,13}; //#include "PHY/TOOLS/time_meas.h" #ifndef OPENAIR2 -#include "UTIL/OTG/otg_vars.h" + #include "UTIL/OTG/otg_vars.h" #endif @@ -91,6 +91,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "system.h" + #include "lte-softmodem.h" #include "NB_IoT_interface.h" @@ -107,6 +108,10 @@ pthread_mutex_t sync_mutex; int sync_var=-1; //!< protected by mutex \ref sync_mutex. int config_sync_var=-1; +uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] +uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] + + volatile int oai_exit = 0; uint32_t downlink_frequency[MAX_NUM_CCs][4]; @@ -145,10 +150,18 @@ char ref[128] = "internal"; char channels[128] = "0"; int rx_input_level_dBm; + int otg_enabled; + + uint8_t exit_missed_slots=1; uint64_t num_missed_slots=0; // counter for the number of missed slots + +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + + extern void init_eNB_afterRU(void); extern void phy_free_RU(RU_t *); @@ -159,11 +172,73 @@ int numerology = 0; THREAD_STRUCT thread_struct; /* struct for ethernet specific parameters given in eNB conf file */ eth_params_t *eth_params; + double cpuf; +/* forward declarations */ + /* forward declarations */ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + +#if 1 + + if (changed) print_difftimes(); + +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + + void signal_handler(int sig) { void *array[10]; size_t size; @@ -181,6 +256,7 @@ void signal_handler(int sig) { } } + void exit_function(const char *file, const char *function, const int line, const char *s) { int ru_id; @@ -209,6 +285,7 @@ void exit_function(const char *file, const char *function, const int line, const exit(1); } + static void get_options(void) { CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); get_common_options(); @@ -232,6 +309,10 @@ static void get_options(void) { } } + + + + void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { int CC_id; @@ -446,11 +527,14 @@ int main( int argc, char **argv ) { int CC_id = 0; int ru_id; - AssertFatal(load_configmodule(argc,argv,0) != NULL, - "[SOFTMODEM] Error, configuration module init failed\n"); + if ( load_configmodule(argc,argv,0) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + mode = normal_txrx; logInit(); + printf("Reading in command-line options\n"); get_options (); AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n"); @@ -472,14 +556,21 @@ int main( int argc, char **argv ) { EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1; + if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { + fprintf(stderr,"Getting configuration failed\n"); + exit(-1); + } + #if T_TRACER T_Config_Init(); #endif //randominit (0); set_taus_seed (0); + printf("configuring for RAU/RRU\n"); - if (opp_enabled ==1) + if (opp_enabled ==1) { reset_opp_meas(); + } itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); // allows to forward in wireshark L2 protocol for decoding @@ -491,8 +582,9 @@ int main( int argc, char **argv ) { /* Start the agent. If it is turned off in the configuration, it won't start */ RCconfig_flexran(); - for (i = 0; i < RC.nb_inst; i++) + for (i = 0; i < RC.nb_inst; i++) { flexran_agent_start(i); + } /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks * for monolithic/F1 modes */ @@ -521,7 +613,7 @@ int main( int argc, char **argv ) { ctxt.subframe = 0; pdcp_run(&ctxt); } - + /* start threads if only L1 or not a CU */ if (RC.nb_inst == 0 || !NODE_IS_CU(RC.rrc[0]->node_type)) { // init UE_PF_PO and mutex lock @@ -531,53 +623,56 @@ int main( int argc, char **argv ) { pthread_mutex_init(&sync_mutex, NULL); rt_sleep_ns(10*100000000ULL); - + if (NFAPI_MODE!=NFAPI_MONOLITHIC) { LOG_I(ENB_APP,"NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); } - + if (NFAPI_MODE==NFAPI_MODE_VNF) {// VNF #if defined(PRE_SCD_THREAD) init_ru_vnf(); // ru pointer is necessary for pre_scd. #endif wait_nfapi_init("main?"); } - + LOG_I(ENB_APP,"START MAIN THREADS\n"); // start the main threads number_of_cards = 1; printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst); - + if (RC.nb_L1_inst > 0) { printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", get_softmodem_params()->single_thread_flag,get_softmodem_params()->wait_for_sync); init_eNB(get_softmodem_params()->single_thread_flag,get_softmodem_params()->wait_for_sync); // for (inst=0;inst0 && NFAPI_MODE!=NFAPI_MODE_VNF) { - printf("Initializing RU threads\n"); + + // no need to wait: openair_rrc_eNB_configuration() is called earlier from this thread + // openair_rrc_eNB_configuration()->init_SI()->rrc_mac_config_req_eNB ()->phy_config_request () sets the wait_eNBs() tested flag + // wait_eNBs(); + // printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); + + // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator. + // but RU thread deals with pre_scd and this is necessary in VNF and simulator. + // some initialization is necessary and init_ru_vnf do this. + if (RC.nb_RU >0 && NFAPI_MODE!=NFAPI_MODE_VNF) { + printf("Initializing RU threads\n"); init_RU(get_softmodem_params()->rf_config_file,get_softmodem_params()->clock_source,get_softmodem_params()->timing_source,get_softmodem_params()->send_dmrs_sync); - - for (ru_id=0; ru_idrf_map.card=0; - RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset); + + for (ru_id=0; ru_idrf_map.card=0; + RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset); + } } - + config_sync_var=0; - + if (NFAPI_MODE==NFAPI_MODE_PNF) { // PNF wait_nfapi_init("main?"); } - + printf("wait RUs\n"); // end of CI modifications // fixme: very weird usage of bitmask @@ -604,6 +699,7 @@ int main( int argc, char **argv ) { pthread_mutex_unlock(&sync_mutex); config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS); } + // wait for end of program LOG_UI(ENB_APP,"TYPE TO TERMINATE\n"); // CI -- Flushing the std outputs for the previous marker to show on the eNB / DU / CU log file @@ -648,17 +744,17 @@ int main( int argc, char **argv ) { for(ru_id=0; ru_idrfdevice.trx_end_func) { - RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); - RC.ru[ru_id]->rfdevice.trx_end_func = NULL; + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + RC.ru[ru_id]->rfdevice.trx_end_func = NULL; } if (RC.ru[ru_id]->ifdevice.trx_end_func) { - RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); - RC.ru[ru_id]->ifdevice.trx_end_func = NULL; + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + RC.ru[ru_id]->ifdevice.trx_end_func = NULL; } } } - + terminate_opt(); logClean(); printf("Bye.\n"); From 92442cece206ea48645c4aa3534076e041a92206 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 1 Jul 2019 16:43:47 +0200 Subject: [PATCH 005/175] progress in main cleanup coding --- executables/main-ocp.c | 60 +++++++++---------------------- targets/RT/USER/lte-softmodem.c | 63 ++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 72 deletions(-) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index b3472f17cb..cbd18c6541 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -15,6 +15,7 @@ static int DEFENBS[] = {0}; #include #include #include +#include extern uint16_t sf_ahead; extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); extern void fep_full(RU_t *ru); @@ -89,10 +90,6 @@ void init_RU_proc(RU_t *ru) { proc->frame_tx_unwrap = 0; for (i=0; i<10; i++) proc->symbol_mask[i]=0; - - pthread_mutex_init( &proc->mutex_synch,NULL); - pthread_cond_init( &proc->cond_synch,NULL); - pthread_cond_init( &proc->cond_eNBs, NULL); pthread_t t; threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); } @@ -166,6 +163,7 @@ void init_eNB_afterRU(void) { eNB = RC.eNB[inst][CC_id]; phy_init_lte_eNB(eNB,0,0); eNB->frame_parms.nb_antennas_rx = 0; + eNB->frame_parms.nb_antennas_tx = 0; eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *)); for (int ce_level=0; ce_level<4; ce_level++) { @@ -175,6 +173,7 @@ void init_eNB_afterRU(void) { for (ru_id=0,aa=0; ru_idnum_RU; ru_id++) { eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx; + eNB->frame_parms.nb_antennas_tx += eNB->RU_list[ru_id]->nb_tx; AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL, "RU %d : common.rxdataF is NULL\n", eNB->RU_list[ru_id]->idx); @@ -197,22 +196,9 @@ void init_eNB_afterRU(void) { * In monolithic mode, we come here with nb_antennas_rx == 0 * (not tested in other modes). */ - if (eNB->frame_parms.nb_antennas_rx < 1) { - LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx); - eNB->frame_parms.nb_antennas_rx = 1; - } else { - //LOG_I(PHY," Delete code\n"); - } + AssertFatal( eNB->frame_parms.nb_antennas_rx > 0 && eNB->frame_parms.nb_antennas_rx < 4, ""); + AssertFatal( eNB->frame_parms.nb_antennas_tx > 0 && eNB->frame_parms.nb_antennas_rx < 4, ""); - if (eNB->frame_parms.nb_antennas_tx < 1) { - LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx); - eNB->frame_parms.nb_antennas_tx = 1; - } else { - //LOG_I(PHY," Delete code\n"); - } - - AssertFatal(eNB->frame_parms.nb_antennas_rx >0, - "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); init_transport(eNB); //init_precoding_weights(RC.eNB[inst][CC_id]); @@ -261,6 +247,7 @@ void stop_eNB(int nb_inst) { kill_eNB_proc(inst); } } + // this is for RU with local RF unit void fill_rf_config(RU_t *ru, char *rf_config_file) { int i; @@ -768,7 +755,7 @@ int stop_rf(RU_t *ru) { void set_function_spec_param(RU_t *ru) { switch (ru->if_south) { - case LOCAL_RF: { // this is an RU with integrated RF (RRU, eNB) + case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) ru->do_prach = 0; // no prach processing in RU ru->feprx = fep_full; ru->feptx_ofdm = feptx_ofdm; @@ -776,31 +763,16 @@ void set_function_spec_param(RU_t *ru) { ru->fh_north_in = NULL; // no incoming fronthaul from north ru->start_if = NULL; // no if interface ru->rfdevice.host_type = RAU_HOST; - } - - ru->fh_south_in = rx_rf; // local synchronous RF RX - ru->fh_south_out = tx_rf; // local synchronous RF TX - ru->start_rf = start_rf; // need to start the local RF interface - ru->stop_rf = stop_rf; - ru->eNB_top=eNB_top; - printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); - /* - if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise - fill_rf_config(ru,rf_config_file); - init_frame_parms(&ru->frame_parms,1); - phy_init_RU(ru); - } - - ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); - if (setup_RU_buffers(ru)!=0) { - printf("Exiting, cannot initialize RU Buffers\n"); - exit(-1); - }*/ - break; - - default: - LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + ru->fh_south_in = rx_rf; // local synchronous RF RX + ru->fh_south_out = tx_rf; // local synchronous RF TX + ru->start_rf = start_rf; // need to start the local RF interface + ru->stop_rf = stop_rf; + ru->eNB_top=eNB_top; break; + + default: + LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + break; } // switch on interface type } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 37e94de2b6..de211376b2 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -91,7 +91,6 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "system.h" - #include "lte-softmodem.h" #include "NB_IoT_interface.h" @@ -163,7 +162,6 @@ extern void print_opp_meas(void); extern void init_eNB_afterRU(void); -extern void phy_free_RU(RU_t *); int transmission_mode=1; int emulate_rf = 0; @@ -296,11 +294,11 @@ static void get_options(void) { /* Read RC configuration file */ RCConfig(); NB_eNB_INST = RC.nb_inst; - LOG_I(ENB_APP,"Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU); + printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU); if (!IS_SOFTMODEM_NONBIOT) { load_NB_IoT(); - LOG_I(ENB_APP," nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n", + printf(" nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n", RC.nb_nb_iot_rrc_inst, RC.nb_nb_iot_L1_inst, RC.nb_nb_iot_macrlc_inst); } else { printf("All Nb-IoT instances disabled\n"); @@ -532,25 +530,11 @@ int main( int argc, char **argv ) { } mode = normal_txrx; - + set_latency_target(); logInit(); printf("Reading in command-line options\n"); get_options (); - AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n"); - configure_linux(); - // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGABRT, signal_handler); - cpuf=get_cpu_freq_GHz(); - - #ifndef PACKAGE_VERSION -# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" -#endif - LOG_I(HW, "OAI Version: %s\n", PACKAGE_VERSION); - if (is_nos1exec(argv[0]) ) set_softmodem_optmask(SOFTMODEM_NOS1_BIT); @@ -572,10 +556,30 @@ int main( int argc, char **argv ) { reset_opp_meas(); } + cpuf=get_cpu_freq_GHz(); + printf("ITTI init, useMME: %i\n",EPC_MODE_ENABLED); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); // allows to forward in wireshark L2 protocol for decoding + // initialize mscgen log after ITTI + if (get_softmodem_params()->start_msc) { + load_module_shlib("msc",NULL,0,&msc_interface); + } + + MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); init_opt(); + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGABRT, signal_handler); + check_clock(); +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); + printf("Runtime table\n"); + fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); + /* Read configuration */ if (RC.nb_inst > 0) { read_config_and_init(); @@ -596,7 +600,9 @@ int main( int argc, char **argv ) { } for (int enb_id = 0; enb_id < RC.nb_inst; enb_id++) { - openair_rrc_eNB_configuration(enb_id, &RC.rrc[enb_id]->configuration); + MessageDef *msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; + itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); } } else { printf("RC.nb_inst = 0, Initializing L1\n"); @@ -619,6 +625,7 @@ int main( int argc, char **argv ) { // init UE_PF_PO and mutex lock pthread_mutex_init(&ue_pf_po_mutex, NULL); memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*MAX_MOBILES_PER_ENB*MAX_NUM_CCs); + mlockall(MCL_CURRENT | MCL_FUTURE); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); @@ -648,11 +655,11 @@ int main( int argc, char **argv ) { // for (inst=0;instinit_SI()->rrc_mac_config_req_eNB ()->phy_config_request () sets the wait_eNBs() tested flag - // wait_eNBs(); - // printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); + printf("wait_eNBs()\n"); + wait_eNBs(); + printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator. // but RU thread deals with pre_scd and this is necessary in VNF and simulator. @@ -664,7 +671,6 @@ int main( int argc, char **argv ) { for (ru_id=0; ru_idrf_map.card=0; RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset); - } } config_sync_var=0; @@ -675,12 +681,13 @@ int main( int argc, char **argv ) { printf("wait RUs\n"); // end of CI modifications - // fixme: very weird usage of bitmask - // lack of mutex in: ru_thread_prach(),... + fflush(stdout); + fflush(stderr); // wait_RUs() is wrong and over complex! wait_RUs(); LOG_I(ENB_APP,"RC.nb_RU:%d\n", RC.nb_RU); // once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration) + printf("ALL RUs ready - init eNBs\n"); if (NFAPI_MODE!=NFAPI_MODE_PNF && NFAPI_MODE!=NFAPI_MODE_VNF) { LOG_I(ENB_APP,"Not NFAPI mode - call init_eNB_afterRU()\n"); @@ -700,7 +707,6 @@ int main( int argc, char **argv ) { config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS); } - // wait for end of program LOG_UI(ENB_APP,"TYPE TO TERMINATE\n"); // CI -- Flushing the std outputs for the previous marker to show on the eNB / DU / CU log file fflush(stdout); @@ -726,6 +732,7 @@ int main( int argc, char **argv ) { * threads have been stopped (they partially use the same memory) */ for (int inst = 0; inst < NB_eNB_INST; inst++) { for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) { + free_transport(RC.eNB[inst][cc_id]); phy_free_lte_eNB(RC.eNB[inst][cc_id]); } } From db85b231221eadee1d616e937c681e993e43610a Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 5 Jul 2019 16:27:28 +0200 Subject: [PATCH 006/175] continue ocp-main.c --- executables/main-ocp.c | 427 +++++++++++++++++++++++------------------ 1 file changed, 241 insertions(+), 186 deletions(-) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index cbd18c6541..93bf7d3daf 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -3,6 +3,15 @@ * Copyright: Open Cells Project company */ +/* + * This file replaces + * targets/RT/USER/lte-ru.c + * targets/RT/USER/lte-enb.c + * openair1/SCHED/prach_procedures.c + * The merger of OpenAir central code to this branch + * should check if these 3 files are modified and analyze if code code has to be copied in here + */ + #include #include static int DEFBANDS[] = {7}; @@ -16,6 +25,8 @@ static int DEFENBS[] = {0}; #include #include #include +#include + extern uint16_t sf_ahead; extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); extern void fep_full(RU_t *ru); @@ -90,6 +101,7 @@ void init_RU_proc(RU_t *ru) { proc->frame_tx_unwrap = 0; for (i=0; i<10; i++) proc->symbol_mask[i]=0; + pthread_t t; threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); } @@ -198,7 +210,6 @@ void init_eNB_afterRU(void) { */ AssertFatal( eNB->frame_parms.nb_antennas_rx > 0 && eNB->frame_parms.nb_antennas_rx < 4, ""); AssertFatal( eNB->frame_parms.nb_antennas_tx > 0 && eNB->frame_parms.nb_antennas_rx < 4, ""); - LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); init_transport(eNB); //init_precoding_weights(RC.eNB[inst][CC_id]); @@ -280,7 +291,7 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { cfg->tx_bw = 40e6; cfg->rx_bw = 40e6; } else { - printf("Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology); + LOG_E(PHY,"Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology); cfg->sample_rate=30.72e6; cfg->samples_per_frame = 307200; cfg->tx_bw = 10e6; @@ -320,11 +331,11 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { cfg->tx_gain[i] = (double)ru->att_tx; cfg->rx_gain[i] = ru->max_rxgain-(double)ru->att_rx; cfg->configFilename = rf_config_file; - printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n", - i, cfg->tx_gain[i], - cfg->rx_gain[i], - cfg->tx_freq[i], - cfg->rx_freq[i]); + LOG_I(PHY,"channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n", + i, cfg->tx_gain[i], + cfg->rx_gain[i], + cfg->tx_freq[i], + cfg->rx_freq[i]); } } @@ -333,42 +344,25 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple antennas are mapped to successive RF chains on the same card. */ int setup_RU_buffers(RU_t *ru) { - int i,j; - int card,ant; //uint16_t N_TA_offset = 0; LTE_DL_FRAME_PARMS *frame_parms; - - if (ru) { - frame_parms = &ru->frame_parms; - printf("setup_RU_buffers: frame_parms = %p\n",frame_parms); - } else { - printf("RU not initialized (NULL pointer)\n"); - return(-1); - } + AssertFatal(ru, "ru is NULL"); + frame_parms = &ru->frame_parms; + LOG_I(PHY,"setup_RU_buffers: frame_parms = %p\n",frame_parms); if (frame_parms->frame_type == TDD) { - if (frame_parms->N_RB_DL == 100) + if (frame_parms->N_RB_DL == 100) { ru->N_TA_offset = 624; - else if (frame_parms->N_RB_DL == 50) + } else if (frame_parms->N_RB_DL == 50) { ru->N_TA_offset = 624/2; - else if (frame_parms->N_RB_DL == 25) - ru->N_TA_offset = 624/4; - - if(IS_SOFTMODEM_BASICSIM) - /* this is required for the basic simulator in TDD mode - * TODO: find a proper cleaner solution - */ - ru->N_TA_offset = 0; - - if (frame_parms->N_RB_DL == 100) /* no scaling to do */; - else if (frame_parms->N_RB_DL == 50) { ru->sf_extension /= 2; ru->end_of_burst_delay /= 2; } else if (frame_parms->N_RB_DL == 25) { + ru->N_TA_offset = 624/4; ru->sf_extension /= 4; ru->end_of_burst_delay /= 4; } else { - printf("not handled, todo\n"); + LOG_E(PHY,"not handled, todo\n"); exit(1); } } else { @@ -377,39 +371,6 @@ int setup_RU_buffers(RU_t *ru) { ru->end_of_burst_delay = 0; } - if (ru->openair0_cfg.mmapped_dma == 1) { - // replace RX signal buffers with mmaped HW versions - for (i=0; inb_rx; i++) { - card = i/4; - ant = i%4; - printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); - free(ru->common.rxdata[i]); - ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant]; - printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]); - - for (j=0; j<16; j++) { - printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]); - ru->common.rxdata[i][j] = 16-j; - } - } - - for (i=0; inb_tx; i++) { - card = i/4; - ant = i%4; - printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); - free(ru->common.txdata[i]); - ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant]; - printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]); - - for (j=0; j<16; j++) { - printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]); - ru->common.txdata[i][j] = 16-j; - } - } - } else { // not memory-mapped DMA - //nothing to do, everything already allocated in lte_init - } - return(0); } @@ -447,30 +408,134 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) { } } -void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; +void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subframe) { + uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4],avg_preamble_energy[4]; - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - // set timing for prach thread - proc->frame_prach = frame; - proc->subframe_prach = subframe; - prach_procedures(eNB,0); + if (br_flag==0) { + eNB->proc.frame_prach = frame; + eNB->proc.subframe_prach = subframe; + } else { + eNB->proc.frame_prach_br = frame; + eNB->proc.subframe_prach_br = subframe; } -} -void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + RU_t *ru; + int aa=0; + int ru_aa; + for (int i=0; inum_RU; i++) { + ru=eNB->RU_list[i]; + + for (ru_aa=0,aa=0; ru_aanb_rx; ru_aa++,aa++) { + eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[ru_aa]; + int ce_level; + + if (br_flag==1) + for (ce_level=0; ce_level<4; ce_level++) + eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa]; + } + } + + // run PRACH detection for CE-level 0 only for now when br_flag is set + rx_prach(eNB, + eNB->RU_list[0], + &max_preamble[0], + &max_preamble_energy[0], + &max_preamble_delay[0], + &avg_preamble_energy[0], + frame, + 0 + ,br_flag + ); + + if (br_flag==1) { + int prach_mask; + prach_mask = is_prach_subframe (&eNB->frame_parms, eNB->proc.frame_prach_br, eNB->proc.subframe_prach_br); + eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; + int ind = 0; + int ce_level = 0; + /* Save for later, it doesn't work + for (int ind=0,ce_level=0;ce_level<4;ce_level++) { + + if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&& + (prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions + (eNB->prach_vars_br.repetition_number[ce_level]== + eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) { + + */ + + if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) { + if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) { + eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++; + eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; // + eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; + // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 + eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + subframe + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40)); + eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is + eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1 + ce_level; // CE Level + LOG_I (PHY, "Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + ind, + ce_level, + prach_mask, + eNB->preamble_list_br[ind].preamble_rel8.timing_advance, + eNB->preamble_list_br[ind].preamble_rel8.preamble, eNB->preamble_list_br[ind].preamble_rel8.rnti, eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type); + } + } + + /* + ind++; + } + } */// ce_level + } else if ((eNB->prach_energy_counter == 100) && + (max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) { + LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", + eNB->Mod_id, + eNB->CC_id, + frame, + subframe, + max_preamble[0], + max_preamble_energy[0]/10, + max_preamble_energy[0]%10, + max_preamble_delay[0]); + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1; + eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; + eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; + eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; + eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe; + eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; + eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; + eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; + eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here + eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; + eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is + + if (NFAPI_MODE==NFAPI_MODE_PNF) { // If NFAPI PNF then we need to send the message to the VNF + LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), + eNB->preamble_list[0].preamble_rel8.timing_advance, + eNB->preamble_list[0].preamble_rel8.preamble, + eNB->preamble_list[0].preamble_rel8.rnti, + eNB->preamble_list[0].preamble_rel13.rach_resource_type); + oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind); + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0; + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + } // max_preamble_energy > prach_I0 + 100 + else { + eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((avg_preamble_energy[0]*124)>>10); + + if (eNB->prach_energy_counter < 100) + eNB->prach_energy_counter++; + } +} // else br_flag + +void prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); - // set timing for prach thread - proc->frame_prach_br = frame; - proc->subframe_prach_br = subframe; - prach_procedures(eNB,1); + if (is_prach_subframe(&eNB->frame_parms, frame,subframe)>0) { + prach_procedures_ocp(eNB, 0, frame, subframe); + prach_procedures_ocp(eNB, 1, frame, subframe); } } @@ -486,8 +551,7 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); - wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); - wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); + prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); release_UE_in_freeList(eNB->Mod_id); // UE-specific RX processing for subframe n @@ -670,11 +734,7 @@ static void *ru_thread( void *param ) { openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); } - if (setup_RU_buffers(ru)!=0) { - printf("Exiting, cannot initialize RU Buffers\n"); - exit(-1); - } - + AssertFatal(setup_RU_buffers(ru)==0, "Exiting, cannot initialize RU Buffers\n"); LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); wait_sync("ru_thread"); @@ -732,7 +792,7 @@ static void *ru_thread( void *param ) { ru->fh_south_out(ru); } - printf( "Exiting ru_thread \n"); + LOG_W(PHY,"Exiting ru_thread \n"); if (ru->stop_rf != NULL) { if (ru->stop_rf(ru) != 0) @@ -769,10 +829,10 @@ void set_function_spec_param(RU_t *ru) { ru->stop_rf = stop_rf; ru->eNB_top=eNB_top; break; - - default: - LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); - break; + + default: + LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + break; } // switch on interface type } @@ -788,7 +848,7 @@ void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t ti pthread_mutex_init(&RC.ru_mutex,NULL); pthread_cond_init(&RC.ru_cond,NULL); // read in configuration file) - printf("configuring RU from file\n"); + LOG_I(PHY,"configuring RU from file\n"); RCconfig_RU(); LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n", RC.nb_L1_inst,RC.nb_RU,get_nprocs()); @@ -852,23 +912,17 @@ void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t ti LOG_D(PHY, "eNB0:%p\n", eNB0); if (eNB0) { - if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) - AssertFatal(eNB0!=NULL,"eNB0 is null!\n"); + LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); + memcpy((void *)&ru->frame_parms,(void *)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); - if (eNB0) { - LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); - memcpy((void *)&ru->frame_parms,(void *)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); - // attach all RU to all eNBs in its list/ - LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU); - - for (i=0; inum_eNB; i++) { - eNB0 = ru->eNB_list[i]; - eNB0->RU_list[eNB0->num_RU++] = ru; - } + for (i=0; inum_eNB; i++) { + eNB0 = ru->eNB_list[i]; + eNB0->RU_list[eNB0->num_RU++] = ru; } } - LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); + LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n", + ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); set_function_spec_param(ru); LOG_I(PHY,"Starting ru_thread %d\n",ru_id); init_RU_proc(ru); @@ -894,85 +948,86 @@ void RCconfig_RU(void) { paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); - if ( RUParamList.numelt > 0) { - RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); - - for (j = 0; j < RC.nb_RU; j++) { - RC.ru[j] = (RU_t *)malloc(sizeof(RU_t)); - memset((void *)RC.ru[j],0,sizeof(RU_t)); - RC.ru[j]->idx = j; - printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); - RC.ru[j]->if_timing = synch_to_ext_device; - - if (RC.nb_L1_inst >0) - RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; - else - RC.ru[j]->num_eNB = 0; - - for (i=0; inum_eNB; i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0]; - - if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) { - RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr)); - } - - if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) { - if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) { - RC.ru[j]->openair0_cfg.clock_source = internal; - LOG_D(PHY, "RU clock source set as internal\n"); - } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) { - RC.ru[j]->openair0_cfg.clock_source = external; - LOG_D(PHY, "RU clock source set as external\n"); - } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) { - RC.ru[j]->openair0_cfg.clock_source = gpsdo; - LOG_D(PHY, "RU clock source set as gpsdo\n"); - } else { - LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); - } - } - - if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { - if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = eNodeB_3GPP; - printf("Setting function for RU %d to eNodeB_3GPP\n",j); - } else { - RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); - RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); - RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); - RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); - RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); - } - - RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; - RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); - RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; - /* sf_extension is in unit of samples for 30.72MHz here, has to be scaled later */ - RC.ru[j]->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr); - RC.ru[j]->end_of_burst_delay = *(RUParamList.paramarray[j][RU_END_OF_BURST_DELAY_IDX].uptr); - - for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; - } //strcmp(local_rf, "yes") == 0 - else { - printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); - RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); - RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); - RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); - RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); - RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); - } /* strcmp(local_rf, "yes") != 0 */ - - RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); - RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); - RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); - RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); - }// j=0..num_rus - } else { + if ( RUParamList.numelt == 0 ) { RC.nb_RU = 0; + return; } // setting != NULL + RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); + + for (j = 0; j < RC.nb_RU; j++) { + RC.ru[j] = (RU_t *)calloc(sizeof(RU_t), 1); + RC.ru[j]->idx = j; + LOG_I(PHY,"Creating RC.ru[%d]:%p\n", j, RC.ru[j]); + RC.ru[j]->if_timing = synch_to_ext_device; + paramdef_t *vals=RUParamList.paramarray[j]; + + if (RC.nb_L1_inst >0) + RC.ru[j]->num_eNB = vals[RU_ENB_LIST_IDX].numelt; + else + RC.ru[j]->num_eNB = 0; + + for (i=0; inum_eNB; i++) + RC.ru[j]->eNB_list[i] = RC.eNB[vals[RU_ENB_LIST_IDX].iptr[i]][0]; + + if (config_isparamset(vals, RU_SDR_ADDRS)) { + RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(vals[RU_SDR_ADDRS].strptr)); + } + + if (config_isparamset(vals, RU_SDR_CLK_SRC)) { + char *paramVal=*(vals[RU_SDR_CLK_SRC].strptr); + LOG_D(PHY, "RU clock source set as %s\n", paramVal); + + if (strcmp(paramVal, "internal") == 0) { + RC.ru[j]->openair0_cfg.clock_source = internal; + } else if (strcmp(paramVal, "external") == 0) { + RC.ru[j]->openair0_cfg.clock_source = external; + } else if (strcmp(paramVal, "gpsdo") == 0) { + RC.ru[j]->openair0_cfg.clock_source = gpsdo; + } else { + LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", paramVal); + } + } + + if (strcmp(*(vals[RU_LOCAL_RF_IDX].strptr), "yes") == 0) { + if ( !(config_isparamset(vals,RU_LOCAL_IF_NAME_IDX)) ) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = eNodeB_3GPP; + LOG_I(PHY, "Setting function for RU %d to eNodeB_3GPP\n",j); + } else { + RC.ru[j]->eth_params.local_if_name = strdup(*(vals[RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(vals[RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(vals[RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(vals[RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(vals[RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(vals[RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(vals[RU_REMOTE_PORTD_IDX].uptr); + } + + RC.ru[j]->max_pdschReferenceSignalPower = *(vals[RU_MAX_RS_EPRE_IDX].uptr);; + RC.ru[j]->max_rxgain = *(vals[RU_MAX_RXGAIN_IDX].uptr); + RC.ru[j]->num_bands = vals[RU_BAND_LIST_IDX].numelt; + /* sf_extension is in unit of samples for 30.72MHz here, has to be scaled later */ + RC.ru[j]->sf_extension = *(vals[RU_SF_EXTENSION_IDX].uptr); + RC.ru[j]->end_of_burst_delay = *(vals[RU_END_OF_BURST_DELAY_IDX].uptr); + + for (i=0; inum_bands; i++) RC.ru[j]->band[i] = vals[RU_BAND_LIST_IDX].iptr[i]; + } else { + LOG_I(PHY,"RU %d: Transport %s\n",j,*(vals[RU_TRANSPORT_PREFERENCE_IDX].strptr)); + RC.ru[j]->eth_params.local_if_name = strdup(*(vals[RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(vals[RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(vals[RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(vals[RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(vals[RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(vals[RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(vals[RU_REMOTE_PORTD_IDX].uptr); + } /* strcmp(local_rf, "yes") != 0 */ + + RC.ru[j]->nb_tx = *(vals[RU_NB_TX_IDX].uptr); + RC.ru[j]->nb_rx = *(vals[RU_NB_RX_IDX].uptr); + RC.ru[j]->att_tx = *(vals[RU_ATT_TX_IDX].uptr); + RC.ru[j]->att_rx = *(vals[RU_ATT_RX_IDX].uptr); + }// j=0..num_rus + return; } From 6b662a3ed9a2742871c5418332b65a3123565673 Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 12 Jul 2019 17:25:52 +0200 Subject: [PATCH 007/175] compiles --- cmake_targets/CMakeLists.txt | 2 + executables/dl_fs6.c | 157 +++++++++++++++++++++++++++++++--- executables/main-ocp.c | 32 ++++--- executables/split_headers.h | 21 ++++- executables/transport_split.c | 19 ++-- 5 files changed, 195 insertions(+), 36 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 552c5179b4..177de04a2d 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2094,6 +2094,8 @@ target_link_libraries (lte-softmodem add_executable(ocp-softmodem ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_DIR}/executables/main-ocp.c + ${OPENAIR_DIR}/executables/dl_fs6.c + ${OPENAIR_DIR}/executables/transport_split.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index c583a4bc45..5ad6ddfd3b 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -1,5 +1,11 @@ -#include +#include +#include +#include +#include +#define FS6_BUF_SIZE 100*1000 +static int sockFS6; +#if 0 void pdsch_procedures(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, @@ -61,14 +67,15 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, dlsch_harq->round++; } -phy_procedures_eNB_TX_fs6() { - receiveSubFrame(); +phy_procedures_eNB_TX_fs6(int sockFS6, uint64_t TS) { + uint8_t bufferZone[FS6_BUF_SIZE]; + receiveSubFrame(sockFS6, TS, bufferZone, sizeof(bufferZone) ); // We got // subframe number // - for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { + for (int aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti], 0, fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); @@ -178,17 +185,141 @@ phy_procedures_eNB_TX_fs6() { proc, AMP); } +#endif -DL_thread_fs6() { - receiveSubFrame(); - phy_procedures_eNB_TX_fs6(); - ru->feptx_prec(ru); - ru->feptx_ofdm(ru); - ru->fh_south_out(ru); +void prach_eNB_extract(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { } +void prach_eNB_process(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { +} +void phy_procedures_eNB_uespec_RX_extract(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { +} -DL_thread_frequency() { - frequency_t header; - full_read(&header, \ No newline at end of file +void phy_procedures_eNB_uespec_RX_process(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { +} + +void phy_procedures_eNB_TX_fs6() { +} + +void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { + RU_proc_t *ru_proc=&ru->proc; + + for (int i=0; inum_eNB; i++) { + uint8_t bufferZone[FS6_BUF_SIZE]; + receiveSubFrame(sockFS6, TS, bufferZone, sizeof(bufferZone) ); + } + + phy_procedures_eNB_TX_fs6(); + /* Fixme: datamodel issue: a ru is supposed to be connected to several eNB + L1_rxtx_proc_t * L1_proc = &proc->L1_proc; + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; + */ + feptx_prec(ru); + feptx_ofdm(ru); + tx_rf(ru); +} + +void UL_du_fs6(RU_t *ru, int frame, int subframe) { + RU_proc_t *ru_proc=&ru->proc; + int tmpf=frame, tmpsf=subframe; + rx_rf(ru,&tmpf,&tmpsf); + AssertFatal(tmpf==frame && tmpsf==subframe, "lost synchronization\n"); + ru_proc->frame_tx = (ru_proc->frame_tx+ru_proc->frame_offset)&1023; + // Fixme: datamodel issue + PHY_VARS_eNB *eNB = RC.eNB[0][0]; + L1_proc_t *proc = &eNB->proc; + L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + proc->frame_rx = frame; + proc->subframe_rx = subframe; + + if (NFAPI_MODE==NFAPI_MODE_PNF) { + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + //add_subframe(&frame, &subframe, 4); + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + oai_subframe_ind(proc->frame_rx, proc->subframe_rx); + } + + uint8_t bufferZone[FS6_BUF_SIZE]; + prach_eNB_extract(eNB,NULL,proc->frame_rx,proc->subframe_rx); + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + phy_procedures_eNB_uespec_RX_extract(eNB, &proc->L1_proc); + } + + for (int i=0; inum_eNB; i++) { + sendSubFrame(sockFS6,bufferZone, sizeof(bufferZone) ); + } +} + +void DL_cu_fs6(RU_t *ru,int frame, int subframe) { + // Fixme: datamodel issue + PHY_VARS_eNB *eNB = RC.eNB[0][0]; + L1_proc_t *proc = &eNB->proc; + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.frame = proc->frame_rx; + eNB->UL_INFO.subframe = proc->subframe_rx; + eNB->UL_INFO.module_id = eNB->Mod_id; + eNB->UL_INFO.CC_id = eNB->CC_id; + eNB->if_inst->UL_indication(&eNB->UL_INFO); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + uint8_t bufferZone[FS6_BUF_SIZE]; + phy_procedures_eNB_TX(eNB, &proc->L1_proc, 1); + sendSubFrame(sockFS6, bufferZone, sizeof(bufferZone) ); +} + +void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { + uint8_t bufferZone[FS6_BUF_SIZE]; + receiveSubFrame(sockFS6, TS, bufferZone, sizeof(bufferZone) ); + // Fixme: datamodel issue + PHY_VARS_eNB *eNB = RC.eNB[0][0]; + L1_proc_t *proc = &eNB->proc; + prach_eNB_process(eNB,NULL,proc->frame_rx,proc->subframe_rx); + release_UE_in_freeList(eNB->Mod_id); + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + phy_procedures_eNB_uespec_RX_process(eNB, &proc->L1_proc); + } +} + +void *cu_fs6(void *arg) { + RU_t *ru = (RU_t *)arg; + RU_proc_t *proc = &ru->proc; + int64_t AbsoluteSubframe=-1; + init_frame_parms(&ru->frame_parms,1); + wait_sync("ru_thread"); + + while(1) { + AbsoluteSubframe++; + int subframe=AbsoluteSubframe%10; + int frame=(AbsoluteSubframe/10)%1024; + UL_cu_fs6(ru, frame,subframe, AbsoluteSubframe); + DL_cu_fs6(ru, frame,subframe); + } + + return NULL; +} + +void *du_fs6(void *arg) { + RU_t *ru = (RU_t *)arg; + RU_proc_t *proc = &ru->proc; + int64_t AbsoluteSubframe=-1; + fill_rf_config(ru,ru->rf_config_file); + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); + openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + wait_sync("ru_thread"); + + while(1) { + AbsoluteSubframe++; + int subframe=AbsoluteSubframe%10; + int frame=(AbsoluteSubframe/10)%1024; + UL_du_fs6(ru, frame,subframe); + DL_du_fs6(ru, frame,subframe, AbsoluteSubframe); + } + + return NULL; +} diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 93bf7d3daf..db64e47732 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -26,6 +26,7 @@ static int DEFENBS[] = {0}; #include #include #include +#include extern uint16_t sf_ahead; extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); @@ -103,7 +104,17 @@ void init_RU_proc(RU_t *ru) { for (i=0; i<10; i++) proc->symbol_mask[i]=0; pthread_t t; - threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); + char *fs6=getenv("fs6"); + + if (fs6) { + if ( strncasecmp(fs6,"cu", 2) ) + threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); + else if ( strncasecmp(fs6,"du", 2) ) + threadCreate(&t, du_fs6, (void *)ru, "MainDu", -1, OAI_PRIORITY_RT_MAX); + else + AssertFatal(false, "environement variable fs6 is not cu or du"); + } else + threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); } void init_transport(PHY_VARS_eNB *eNB) { @@ -719,13 +730,10 @@ void tx_rf(RU_t *ru) { } static void *ru_thread( void *param ) { - static int ru_thread_status; RU_t *ru = (RU_t *)param; RU_proc_t *proc = &ru->proc; int subframe =9; int frame =1023; - // set default return value - ru_thread_status = 0; if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); @@ -800,8 +808,7 @@ static void *ru_thread( void *param ) { else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); } - ru_thread_status = 0; - return &ru_thread_status; + return NULL; } int start_rf(RU_t *ru) { @@ -816,18 +823,15 @@ int stop_rf(RU_t *ru) { void set_function_spec_param(RU_t *ru) { switch (ru->if_south) { case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) - ru->do_prach = 0; // no prach processing in RU ru->feprx = fep_full; ru->feptx_ofdm = feptx_ofdm; ru->feptx_prec = feptx_prec; // this is fep with idft and precoding - ru->fh_north_in = NULL; // no incoming fronthaul from north - ru->start_if = NULL; // no if interface ru->rfdevice.host_type = RAU_HOST; - ru->fh_south_in = rx_rf; // local synchronous RF RX - ru->fh_south_out = tx_rf; // local synchronous RF TX - ru->start_rf = start_rf; // need to start the local RF interface - ru->stop_rf = stop_rf; - ru->eNB_top=eNB_top; + ru->fh_south_in = rx_rf; // local synchronous RF RX + ru->fh_south_out = tx_rf; // local synchronous RF TX + ru->start_rf = start_rf; // need to start the local RF interface + ru->stop_rf = stop_rf; + ru->eNB_top = eNB_top; break; default: diff --git a/executables/split_headers.h b/executables/split_headers.h index 3d59f3c199..68bb3925d7 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -1,6 +1,8 @@ #ifndef __SPLIT_HEADERS_H #define __SPLIT_HEADERS_H +#include +#include #define MTU 65536 #define UDP_TIMEOUT 100000L // in nano second #define MAX_BLOCKS 16 @@ -18,12 +20,27 @@ typedef struct frequency_s { int frame; int subframe; int sampleSize; - int nbAnt + int nbAnt; int nbSamples; } frequency_t; -int createListner (port); +int createListner (int port); int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int bufferSize); int sendSubFrame(int sock, void *bufferZone, int nbBlocks); +inline size_t alignedSize(void *ptr) { + commonUDP_t *header=(commonUDP_t *) ptr; + return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign; } + +void *cu_fs6(void *arg); +void *du_fs6(void *arg); +void fill_rf_config(RU_t *ru, char *rf_config_file); +void rx_rf(RU_t *ru,int *frame,int *subframe); +void tx_rf(RU_t *ru); + +// mistakes in main OAI +void phy_init_RU(RU_t *); +void feptx_prec(RU_t *); +void feptx_ofdm(RU_t *); +void oai_subframe_ind(uint16_t sfn, uint16_t sf); #endif diff --git a/executables/transport_split.c b/executables/transport_split.c index fe9e1a419c..c3819d665e 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -1,6 +1,10 @@ -#include +#include +#include /* See NOTES */ +#include +#include +#include -int createListner (port) { +int createListner (int port) { int sock; AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); struct sockaddr_in addr = { @@ -12,8 +16,8 @@ sin_addr: { s_addr: INADDR_ANY } }; int enable=1; - AssertFatal(setsockopt(eth->sockfdc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); - AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,""); + AssertFatal(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); + AssertFatal(bind(sock, (const struct sockaddr *) &addr, sizeof(addr))==0,""); struct timeval tv= {0,UDP_TIMEOUT}; AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); // Make a send/recv buffer larger than a a couple of subframe @@ -28,6 +32,7 @@ sin_addr: // bufferZone: a reception area of bufferSize int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int bufferSize) { int rcved=0; + commonUDP_t *tmp=NULL; do { //read all subframe data from the control unit @@ -41,7 +46,7 @@ int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int buffer return -1; } } else { - commonUDP_t *tmp=(commonUDP_t *)bufferZone; + tmp=(commonUDP_t *)bufferZone; if ( expectedTS && tmp->timestamp != expectedTS) { LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n"); @@ -50,9 +55,9 @@ int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int buffer bufferZone+=ret; } } - } while ( !recved || recved < tmp->nbBlocks); + } while ( !rcved || rcved < tmp->nbBlocks); - return recv; + return rcved; } int sendSubFrame(int sock, void *bufferZone, int nbBlocks) { From 50aa4dcc584649e93db1fe825814e9619dcb742a Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sat, 13 Jul 2019 22:06:34 +0200 Subject: [PATCH 008/175] test commit - just whitespace --- executables/transport_split.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executables/transport_split.c b/executables/transport_split.c index c3819d665e..8f0ac5108c 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -55,7 +55,7 @@ int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int buffer bufferZone+=ret; } } - } while ( !rcved || rcved < tmp->nbBlocks); + } while ( !rcved || rcved < tmp->nbBlocks ); return rcved; } From b8005ed09a07fc5142668a0ec19a5c80232810ee Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 15 Jul 2019 20:09:56 +0200 Subject: [PATCH 009/175] more code --- executables/dl_fs6.c | 77 ++++++++++++++++++++---------- executables/main-ocp.c | 4 +- executables/split_headers.h | 18 +++++-- executables/transport_split.c | 88 ++++++++++++++++++++++++++--------- 4 files changed, 136 insertions(+), 51 deletions(-) diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 5ad6ddfd3b..2dcdca2365 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -4,7 +4,7 @@ #include #define FS6_BUF_SIZE 100*1000 -static int sockFS6; +static UDPsock_t sockFS6; #if 0 void pdsch_procedures(PHY_VARS_eNB *eNB, @@ -66,14 +66,26 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, dlsch->active = 0; dlsch_harq->round++; } +#endif -phy_procedures_eNB_TX_fs6(int sockFS6, uint64_t TS) { - uint8_t bufferZone[FS6_BUF_SIZE]; - receiveSubFrame(sockFS6, TS, bufferZone, sizeof(bufferZone) ); - +void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { // We got // subframe number // + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + uint32_t i,aa; + uint8_t harq_pid; + int16_t UE_id=0; + uint8_t num_pdcch_symbols=0; + uint8_t num_dci=0; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + uint8_t num_mdci = 0; +#endif + uint8_t ul_subframe; + uint32_t ul_frame; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + LTE_UL_eNB_HARQ_t *ulsch_harq; for (int aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti], @@ -165,13 +177,15 @@ phy_procedures_eNB_TX_fs6(int sockFS6, uint64_t TS) { harq_pid,UE_id,frame,subframe,dlsch0->rnti); } else { // generate pdsch - pdsch_procedures_fs6(eNB, - proc, - harq_pid, - dlsch0, - dlsch1, - &eNB->UE_stats[(uint32_t)UE_id], - 0); + /* + pdsch_procedures_fs6(eNB, + proc, + harq_pid, + dlsch0, + dlsch1, + &eNB->UE_stats[(uint32_t)UE_id], + 0); + */ } } else if ((dlsch0)&&(dlsch0->rnti>0)&& (dlsch0->active == 0) @@ -185,21 +199,32 @@ phy_procedures_eNB_TX_fs6(int sockFS6, uint64_t TS) { proc, AMP); } -#endif -void prach_eNB_extract(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { +void prach_eNB_extract(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe, uint8_t *buf, int bufSize) { + commonUDP_t *header=(commonUDP_t *) buf; + header->contentBytes=1000; + header->nbBlocks=1; + return; } void prach_eNB_process(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { } -void phy_procedures_eNB_uespec_RX_extract(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { +void phy_procedures_eNB_uespec_RX_extract(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc, uint8_t *buf, int bufSize) { + commonUDP_t *header=(commonUDP_t *) buf; + header->contentBytes=1000; + header->nbBlocks=1; + return; } void phy_procedures_eNB_uespec_RX_process(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { } -void phy_procedures_eNB_TX_fs6() { +void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { + commonUDP_t *header=(commonUDP_t *) buf; + header->contentBytes=1000; + header->nbBlocks=1; + return; } void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { @@ -207,10 +232,10 @@ void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { for (int i=0; inum_eNB; i++) { uint8_t bufferZone[FS6_BUF_SIZE]; - receiveSubFrame(sockFS6, TS, bufferZone, sizeof(bufferZone) ); + receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + phy_procedures_eNB_TX_process( bufferZone, sizeof(bufferZone), ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); } - phy_procedures_eNB_TX_fs6(); /* Fixme: datamodel issue: a ru is supposed to be connected to several eNB L1_rxtx_proc_t * L1_proc = &proc->L1_proc; ru_proc->timestamp_tx = L1_proc->timestamp_tx; @@ -244,14 +269,14 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } uint8_t bufferZone[FS6_BUF_SIZE]; - prach_eNB_extract(eNB,NULL,proc->frame_rx,proc->subframe_rx); + prach_eNB_extract(eNB,NULL,proc->frame_rx,proc->subframe_rx, bufferZone, FS6_BUF_SIZE); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_extract(eNB, &proc->L1_proc); + phy_procedures_eNB_uespec_RX_extract(eNB, &proc->L1_proc, bufferZone, FS6_BUF_SIZE); } for (int i=0; inum_eNB; i++) { - sendSubFrame(sockFS6,bufferZone, sizeof(bufferZone) ); + sendSubFrame(&sockFS6,bufferZone); } } @@ -267,13 +292,13 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { eNB->if_inst->UL_indication(&eNB->UL_INFO); pthread_mutex_unlock(&eNB->UL_INFO_mutex); uint8_t bufferZone[FS6_BUF_SIZE]; - phy_procedures_eNB_TX(eNB, &proc->L1_proc, 1); - sendSubFrame(sockFS6, bufferZone, sizeof(bufferZone) ); + phy_procedures_eNB_TX_extract(eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); + sendSubFrame(&sockFS6, bufferZone ); } void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { uint8_t bufferZone[FS6_BUF_SIZE]; - receiveSubFrame(sockFS6, TS, bufferZone, sizeof(bufferZone) ); + receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; @@ -289,8 +314,11 @@ void *cu_fs6(void *arg) { RU_t *ru = (RU_t *)arg; RU_proc_t *proc = &ru->proc; int64_t AbsoluteSubframe=-1; + fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); wait_sync("ru_thread"); + AssertFatal(createUDPsock(NULL, "8888", "127.0.0.1", "7777", &sockFS6), ""); while(1) { AbsoluteSubframe++; @@ -312,6 +340,7 @@ void *du_fs6(void *arg) { phy_init_RU(ru); openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); wait_sync("ru_thread"); + AssertFatal(createUDPsock(NULL, "7777", "127.0.0.1", "8888", &sockFS6),""); while(1) { AbsoluteSubframe++; diff --git a/executables/main-ocp.c b/executables/main-ocp.c index db64e47732..13464ed166 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -107,9 +107,9 @@ void init_RU_proc(RU_t *ru) { char *fs6=getenv("fs6"); if (fs6) { - if ( strncasecmp(fs6,"cu", 2) ) + if ( strncasecmp(fs6,"cu", 2) == 0 ) threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); - else if ( strncasecmp(fs6,"du", 2) ) + else if ( strncasecmp(fs6,"du", 2) == 0 ) threadCreate(&t, du_fs6, (void *)ru, "MainDu", -1, OAI_PRIORITY_RT_MAX); else AssertFatal(false, "environement variable fs6 is not cu or du"); diff --git a/executables/split_headers.h b/executables/split_headers.h index 68bb3925d7..064615284f 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -2,12 +2,22 @@ #define __SPLIT_HEADERS_H #include +#include #include #define MTU 65536 #define UDP_TIMEOUT 100000L // in nano second #define MAX_BLOCKS 16 #define blockAlign 32 //bytes +typedef struct { + char *sourceIP; + char *sourcePort; + char *destIP; + char *destPort; + struct addrinfo *destAddr; + int sockHandler; +} UDPsock_t; + typedef struct commonUDP_s { uint64_t timestamp; // id of the group (subframe for LTE) uint16_t nbBlocks; // total number of blocks for this timestamp @@ -24,9 +34,9 @@ typedef struct frequency_s { int nbSamples; } frequency_t; -int createListner (int port); -int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int bufferSize); -int sendSubFrame(int sock, void *bufferZone, int nbBlocks); +bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); +int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize); +int sendSubFrame(UDPsock_t *sock, void *bufferZone); inline size_t alignedSize(void *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign; @@ -37,6 +47,8 @@ void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); void rx_rf(RU_t *ru,int *frame,int *subframe); void tx_rf(RU_t *ru); +void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe); +void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); // mistakes in main OAI void phy_init_RU(RU_t *); diff --git a/executables/transport_split.c b/executables/transport_split.c index 8f0ac5108c..00de32a156 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -3,40 +3,79 @@ #include #include #include +#include + +bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result) { + struct addrinfo hints= {0}, *servinfo, *p; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + int status; + + if ((status = getaddrinfo(sourceIP, sourcePort, &hints, &servinfo)) != 0) { + LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status)); + return false; + } + + // loop through all the results and bind to the first we can + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((result->sockHandler = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + LOG_W(GTPU,"socket: %s\n", strerror(errno)); + continue; + } + + if (bind(result->sockHandler, p->ai_addr, p->ai_addrlen) == -1) { + close(result->sockHandler); + LOG_W(GTPU,"bind: %s\n", strerror(errno)); + continue; + } + + break; // if we get here, we must have connected successfully + } + + if (p == NULL) { + // looped off the end of the list with no successful bind + LOG_E(GTPU,"failed to bind socket: %s %s \n",sourceIP,sourcePort); + return false; + } + + freeaddrinfo(servinfo); // all done with this structure + + if ((status = getaddrinfo(destIP, destPort, &hints, &servinfo)) != 0) { + LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status)); + return false; + } + + if (servinfo) { + result->destAddr=servinfo; + } else { + LOG_E(PHY,"No valid UDP addr: %s:%s\n",destIP, destPort); + return false; + } -int createListner (int port) { - int sock; - AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, ""); - struct sockaddr_in addr = { -sin_family: - AF_INET, -sin_port: - htons(port), -sin_addr: - { s_addr: INADDR_ANY } - }; int enable=1; - AssertFatal(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); - AssertFatal(bind(sock, (const struct sockaddr *) &addr, sizeof(addr))==0,""); + AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); struct timeval tv= {0,UDP_TIMEOUT}; - AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); + AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); // Make a send/recv buffer larger than a a couple of subframe // so the kernel will store for us in and out paquets int buff=1000*1000*10; - AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, ""); - AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, ""); + AssertFatal ( setsockopt(result->sockHandler, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, ""); + AssertFatal ( setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, ""); + return true; } // sock: udp socket // expectedTS: the expected timestamp, 0 if unknown // bufferZone: a reception area of bufferSize -int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int bufferSize) { +int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize) { int rcved=0; commonUDP_t *tmp=NULL; do { //read all subframe data from the control unit - int ret=recv(sock, bufferZone, bufferSize, 0); + int ret=recv(sock->sockHandler, bufferZone, bufferSize, 0); if ( ret==-1) { if ( errno == EWOULDBLOCK || errno== EINTR ) { @@ -60,14 +99,19 @@ int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone, int buffer return rcved; } -int sendSubFrame(int sock, void *bufferZone, int nbBlocks) { +int sendSubFrame(UDPsock_t *sock, void *bufferZone) { + commonUDP_t *header=(commonUDP_t *)bufferZone ; + int nbBlocks=header->nbBlocks; + do { int sz=alignedSize(bufferZone); - int ret=send(sock, bufferZone, sz, 0); + // Let's use the first address returned by getaddrinfo() + int ret=sendto(sock->sockHandler, bufferZone, sz, 0, + sock->destAddr->ai_addr, sock->destAddr->ai_addrlen); if ( ret != sz ) - LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d)\n", - sz, ret, errno); + LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d, %s)\n", + sz, ret, errno, strerror(errno)); bufferZone+=sz; nbBlocks--; From 8f3a5d455c921b41089c0969cbb6a0b06a6e11e0 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 16 Jul 2019 20:50:31 +0200 Subject: [PATCH 010/175] continue coding DL --- executables/dl_fs6.c | 355 +++++++++++++++++++++++++++---------------- 1 file changed, 224 insertions(+), 131 deletions(-) diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 2dcdca2365..6b80369895 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -5,6 +5,7 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; + #if 0 void pdsch_procedures(PHY_VARS_eNB *eNB, @@ -68,137 +69,6 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, } #endif -void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { - // We got - // subframe number - // - int frame=proc->frame_tx; - int subframe=proc->subframe_tx; - uint32_t i,aa; - uint8_t harq_pid; - int16_t UE_id=0; - uint8_t num_pdcch_symbols=0; - uint8_t num_dci=0; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - uint8_t num_mdci = 0; -#endif - uint8_t ul_subframe; - uint32_t ul_frame; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - LTE_UL_eNB_HARQ_t *ulsch_harq; - - for (int aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { - memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti], - 0, - fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); - } - - if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - if (is_pmch_subframe(frame,subframe,fp)) { - pmch_procedures(eNB,proc); - } else { - // this is not a pmch subframe, so generate PSS/SSS/PBCH - common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx); - } - } - - if (ul_subframe < 10)if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here - for (i=0; i= MAKE_VERSION(14, 0, 0)) - - if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; - else -#endif - harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); - - if (eNB->ulsch[i]) { - ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; - /* Store first_rb and n_DMRS for correct PHICH generation below. - * For PHICH generation we need "old" values of last scheduling - * for this HARQ process. 'generate_eNB_dlsch_params' below will - * overwrite first_rb and n_DMRS and 'generate_phich_top', done - * after 'generate_eNB_dlsch_params', would use the "new" values - * instead of the "old" ones. - * - * This has been tested for FDD only, may be wrong for TDD. - * - * TODO: maybe we should restructure the code to be sure it - * is done correctly. The main concern is if the code - * changes and first_rb and n_DMRS are modified before - * we reach here, then the PHICH processing will be wrong, - * using wrong first_rb and n_DMRS values to compute - * ngroup_PHICH and nseq_PHICH. - * - * TODO: check if that works with TDD. - */ - ulsch_harq->previous_first_rb = ulsch_harq->first_rb; - ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; - } - } - } - - num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; - num_dci = eNB->pdcch_vars[subframe&1].num_dci; - - if (num_dci > 0) - if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - generate_dci_top(num_pdcch_symbols, - num_dci, - &eNB->pdcch_vars[subframe&1].dci_alloc[0], - 0, - AMP, - fp, - eNB->common_vars.txdataF, - subframe); - num_mdci = eNB->mpdcch_vars[subframe &1].num_dci; - - if (num_mdci > 0) { - generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF); - } - } - - // Now scan UE specific DLSCH - LTE_eNB_DLSCH_t *dlsch0,*dlsch1; - - for (UE_id=0; UE_iddlsch[(uint8_t)UE_id][0]; - dlsch1 = eNB->dlsch[(uint8_t)UE_id][1]; - - if ((dlsch0)&&(dlsch0->rnti>0)&& - (dlsch0->active == 1) - ) { - // get harq_pid - harq_pid = dlsch0->harq_ids[frame%2][subframe]; - AssertFatal(harq_pid>=0,"harq_pid is negative\n"); - - if (harq_pid>=8) { - if (dlsch0->ue_type==0) - LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x \n", - harq_pid,UE_id,frame,subframe,dlsch0->rnti); - } else { - // generate pdsch - /* - pdsch_procedures_fs6(eNB, - proc, - harq_pid, - dlsch0, - dlsch1, - &eNB->UE_stats[(uint32_t)UE_id], - 0); - */ - } - } else if ((dlsch0)&&(dlsch0->rnti>0)&& - (dlsch0->active == 0) - ) { - // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) - dlsch0->subframe_tx[subframe]=0; - } - } - - generate_phich_top(eNB, - proc, - AMP); -} void prach_eNB_extract(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe, uint8_t *buf, int bufSize) { commonUDP_t *header=(commonUDP_t *) buf; @@ -220,7 +90,230 @@ void phy_procedures_eNB_uespec_RX_extract(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_pro void phy_procedures_eNB_uespec_RX_process(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { } +typedef struct { + int frame; + int subframe; + int num_pdcch_symbols; + int num_dci; + int amp; + bool UE_active[NUMBER_OF_UE_MAX]; + LTE_eNB_PHICH phich_vars; +} fs6_dl_t; + +void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { + // TBD: read frame&subframe from received data + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + uint32_t i,aa; + uint8_t harq_pid; + uint8_t num_pdcch_symbols=0; + uint8_t num_dci=0; + uint8_t num_mdci = 0; + uint8_t ul_subframe; + uint32_t ul_frame; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + LTE_UL_eNB_HARQ_t *ulsch_harq; + + if (do_meas==1) { + start_meas(&eNB->phy_proc_tx); + start_meas(&eNB->dlsch_common_and_dci); + } + + // clear the transmit data array for the current subframe + for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { + memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti)], + 0, fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); + } + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + if (is_pmch_subframe(frame,subframe,fp)) { + pmch_procedures(eNB,proc); + } else { + // this is not a pmch subframe, so generate PSS/SSS/PBCH + common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx); + } + } + + // clear existing ulsch dci allocations before applying info from MAC (this is table + ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); + ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); + + // clear previous allocation information for all UEs + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]) + eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + } + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + generate_dci_top(header->num_pdcch_symbols, + header->num_dci, + &eNB->pdcch_vars[subframe&1].dci_alloc[0], + 0, + headerAMP, + fp, + eNB->common_vars.txdataF, + header->subframe); + num_mdci = eNB->mpdcch_vars[subframe &1].num_dci; + + if (num_mdci > 0) { + LOG_D (PHY, "[eNB %" PRIu8 "] Frame %d, subframe %d: Calling generate_mdci_top (mpdcch) (num_dci %" PRIu8 ")\n", eNB->Mod_id, frame, subframe, num_mdci); + generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF); + } + } + + for (int UE_id=0; UE_iddlsch[UE_id][0]; + dlsch1 = eNB->dlsch[UE_id][1]; + pdsch_procedures(eNB, + proc, + harq_pid, + dlsch0, + dlsch1); + } + } + + eNB->phich_vars[subframe&1]=header.phich_vars; + generate_phich_top(eNB, + proc, + AMP); +} + void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + uint32_t i,aa; + uint8_t harq_pid; + uint8_t num_pdcch_symbols=0; + uint8_t num_dci=0; + uint8_t num_mdci = 0; + uint8_t ul_subframe; + uint32_t ul_frame; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + LTE_UL_eNB_HARQ_t *ulsch_harq; + + if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) + return; + + header.frame=frame; + header.subframe=subframe; + // clear existing ulsch dci allocations before applying info from MAC (this is table + ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); + ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); + + // clear previous allocation information for all UEs + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]) + eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + } + + /* TODO: check the following test - in the meantime it is put back as it was before */ + //if ((ul_subframe < 10)&& + // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here + if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + for (i=0; iulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; + else + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + + if (eNB->ulsch[i]) { + ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + ulsch_harq->previous_first_rb = ulsch_harq->first_rb; + ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + } + } + } + + num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; + num_dci = eNB->pdcch_vars[subframe&1].num_dci; + LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + header.num_pdcch_symbols=num_pdcch_symbols; + header.num_dci=num_dci; + header.amp=AMP; + } + + if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci); + + if (do_meas==1) start_meas(&eNB->dlsch_ue_specific); + + // Now scan UE specific DLSCH + LTE_eNB_DLSCH_t *dlsch0,*dlsch1; + + for (int UE_id=0; UE_iddlsch[UE_id][0]; + dlsch1 = eNB->dlsch[UE_id][1]; + + if ((dlsch0)&&(dlsch0->rnti>0)&& +#ifdef PHY_TX_THREAD + (dlsch0->active[subframe] == 1) +#else + (dlsch0->active == 1) +#endif + ) { + // get harq_pid + harq_pid = dlsch0->harq_ids[frame%2][subframe]; + AssertFatal(harq_pid>=0,"harq_pid is negative\n"); + + if (harq_pid>=8) { + if (dlsch0->ue_type==0) + LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x [ %1d.%1d.%1d.%1d.%1d.%1d.%1d.%1d\n", harq_pid,UE_id,frame,subframe,dlsch0->rnti, + dlsch0->harq_ids[frame%2][0], + dlsch0->harq_ids[frame%2][1], + dlsch0->harq_ids[frame%2][2], + dlsch0->harq_ids[frame%2][3], + dlsch0->harq_ids[frame%2][4], + dlsch0->harq_ids[frame%2][5], + dlsch0->harq_ids[frame%2][6], + dlsch0->harq_ids[frame%2][7]); + } else { + header.UE_active[UE_id]=true; + + if (dlsch_procedures(eNB, + proc, + harq_pid, + dlsch0, + &eNB->UE_stats[(uint32_t)UE_id])) { + append(UEdata); + } + } + } else if ((dlsch0)&&(dlsch0->rnti>0)&& +#ifdef PHY_TX_THREAD + (dlsch0->active[subframe] == 0) +#else + (dlsch0->active == 0) +#endif + ) { + // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) + dlsch0->subframe_tx[subframe]=0; + } + } + + header.phich_vars=eNB->phich_vars[subframe&1]; + + if (do_meas==1) stop_meas(&eNB->dlsch_ue_specific); + + if (do_meas==1) stop_meas(&eNB->phy_proc_tx); + commonUDP_t *header=(commonUDP_t *) buf; header->contentBytes=1000; header->nbBlocks=1; From c48609f9af649f0255b324b44f6ed51a86de5a0d Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 18 Jul 2019 15:10:20 +0200 Subject: [PATCH 011/175] merge develop (split pdsch/dlsch) --- executables/dl_fs6.c | 64 +++++++++++++++++++++---------------- executables/split_headers.h | 5 +++ 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 6b80369895..5cdb6a0444 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -6,6 +6,23 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; +typedef struct { + int frame; + int subframe; +} fs6_ul_t; + + +typedef struct { + int frame; + int subframe; + int num_pdcch_symbols; + int num_dci; + int amp; + bool UE_active[NUMBER_OF_UE_MAX]; + LTE_eNB_PHICH phich_vars; +} fs6_dl_t; + + #if 0 void pdsch_procedures(PHY_VARS_eNB *eNB, @@ -90,17 +107,11 @@ void phy_procedures_eNB_uespec_RX_extract(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_pro void phy_procedures_eNB_uespec_RX_process(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { } -typedef struct { - int frame; - int subframe; - int num_pdcch_symbols; - int num_dci; - int amp; - bool UE_active[NUMBER_OF_UE_MAX]; - LTE_eNB_PHICH phich_vars; -} fs6_dl_t; - void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { + commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; + UDPheader->contentBytes=1000; + UDPheader->nbBlocks=1; + fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); // TBD: read frame&subframe from received data int frame=proc->frame_tx; int subframe=proc->subframe_tx; @@ -113,6 +124,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN uint32_t ul_frame; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_UL_eNB_HARQ_t *ulsch_harq; + if (do_meas==1) { start_meas(&eNB->phy_proc_tx); @@ -149,7 +161,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN header->num_dci, &eNB->pdcch_vars[subframe&1].dci_alloc[0], 0, - headerAMP, + header->amp, fp, eNB->common_vars.txdataF, header->subframe); @@ -162,9 +174,9 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN } for (int UE_id=0; UE_iddlsch[UE_id][0]; - dlsch1 = eNB->dlsch[UE_id][1]; + if (header->UE_active[UE_id]) { // if we generate dlsch, we must generate pdsch + LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; + LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1]; pdsch_procedures(eNB, proc, harq_pid, @@ -173,13 +185,14 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN } } - eNB->phich_vars[subframe&1]=header.phich_vars; + eNB->phich_vars[subframe&1]=header->phich_vars; generate_phich_top(eNB, proc, AMP); } -void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { +void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { + fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); int frame=proc->frame_tx; int subframe=proc->subframe_tx; uint32_t i,aa; @@ -195,8 +208,8 @@ void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) return; - header.frame=frame; - header.subframe=subframe; + header->frame=frame; + header->subframe=subframe; // clear existing ulsch dci allocations before applying info from MAC (this is table ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); @@ -247,9 +260,9 @@ void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - header.num_pdcch_symbols=num_pdcch_symbols; - header.num_dci=num_dci; - header.amp=AMP; + header->num_pdcch_symbols=num_pdcch_symbols; + header->num_dci=num_dci; + header->amp=AMP; } if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci); @@ -286,7 +299,7 @@ void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int dlsch0->harq_ids[frame%2][6], dlsch0->harq_ids[frame%2][7]); } else { - header.UE_active[UE_id]=true; + header->UE_active[UE_id]=true; if (dlsch_procedures(eNB, proc, @@ -308,15 +321,12 @@ void phy_procedures_eNB_TX_extract(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int } } - header.phich_vars=eNB->phich_vars[subframe&1]; + header->phich_vars=eNB->phich_vars[subframe&1]; if (do_meas==1) stop_meas(&eNB->dlsch_ue_specific); if (do_meas==1) stop_meas(&eNB->phy_proc_tx); - commonUDP_t *header=(commonUDP_t *) buf; - header->contentBytes=1000; - header->nbBlocks=1; return; } @@ -385,7 +395,7 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { eNB->if_inst->UL_indication(&eNB->UL_INFO); pthread_mutex_unlock(&eNB->UL_INFO_mutex); uint8_t bufferZone[FS6_BUF_SIZE]; - phy_procedures_eNB_TX_extract(eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); + phy_procedures_eNB_TX_extract(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); sendSubFrame(&sockFS6, bufferZone ); } diff --git a/executables/split_headers.h b/executables/split_headers.h index 064615284f..6480680693 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -37,11 +37,16 @@ typedef struct frequency_s { bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize); int sendSubFrame(UDPsock_t *sock, void *bufferZone); + inline size_t alignedSize(void *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign; } +inline void * commonUDPdata(void* ptr) { + return (void*) (((commonUDP_t*)ptr)+1); +} + void *cu_fs6(void *arg); void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); From 94831547c779c4fa2e541b5b7b9a78e780778ec1 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 23 Jul 2019 18:24:27 +0200 Subject: [PATCH 012/175] add prach --- executables/dl_fs6.c | 424 +++++++++++++++++++++++----------- executables/split_headers.h | 46 +++- executables/transport_split.c | 15 +- 3 files changed, 344 insertions(+), 141 deletions(-) diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 5cdb6a0444..7dacf08b51 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -1,4 +1,17 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -6,125 +19,214 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; -typedef struct { - int frame; - int subframe; -} fs6_ul_t; +void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { + commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; + fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); + if (is_prach_subframe(&eNB->frame_parms, frame,subframe)<=0) + return; -typedef struct { - int frame; - int subframe; - int num_pdcch_symbols; - int num_dci; - int amp; - bool UE_active[NUMBER_OF_UE_MAX]; - LTE_eNB_PHICH phich_vars; -} fs6_dl_t; + eNB->proc.frame_prach = frame; + eNB->proc.subframe_prach = subframe; + eNB->proc.frame_prach_br = frame; + eNB->proc.subframe_prach_br = subframe; + RU_t *ru; + int aa=0; + int ru_aa; + for (int i=0; inum_RU; i++) { + ru=eNB->RU_list[i]; -#if 0 + for (ru_aa=0,aa=0; ru_aanb_rx; ru_aa++,aa++) { + eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[ru_aa]; + int ce_level; -void pdsch_procedures(PHY_VARS_eNB *eNB, - L1_rxtx_proc_t *proc, - int harq_pid, - LTE_eNB_DLSCH_t *dlsch, - LTE_eNB_DLSCH_t *dlsch1, - LTE_eNB_UE_stats *ue_stats, - int ra_flag) { - int frame=proc->frame_tx; - int subframe=proc->subframe_tx; - LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - - // 36-212 - if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF - // Replace dlsch_encoding - // data is in - // dlsch->harq_processes[harq_pid]->e - feedDlschBuffers(eNB, - dlsch_harq->pdu, - dlsch_harq->pdsch_start, - dlsch, - frame, - subframe, - &eNB->dlsch_rate_matching_stats, - &eNB->dlsch_turbo_encoding_stats, - &eNB->dlsch_turbo_encoding_waiting_stats, - &eNB->dlsch_turbo_encoding_main_stats, - &eNB->dlsch_turbo_encoding_wakeup_stats0, - &eNB->dlsch_turbo_encoding_wakeup_stats1, - &eNB->dlsch_interleaving_stats); - // 36-211 - dlsch_scrambling(fp, - 0, - dlsch, - harq_pid, - get_G(fp, - dlsch_harq->nb_rb, - dlsch_harq->rb_alloc, - dlsch_harq->Qm, - dlsch_harq->Nl, - dlsch_harq->pdsch_start, - frame,subframe, - 0), - 0, - frame, - subframe<<1); - dlsch_modulation(eNB, - eNB->common_vars.txdataF, - AMP, - frame, - subframe, - dlsch_harq->pdsch_start, - dlsch, - dlsch->ue_type==0 ? dlsch1 : (LTE_eNB_DLSCH_t *)NULL); + for (ce_level=0; ce_level<4; ce_level++) + eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa]; + } } - dlsch->active = 0; - dlsch_harq->round++; -} -#endif - - -void prach_eNB_extract(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe, uint8_t *buf, int bufSize) { - commonUDP_t *header=(commonUDP_t *) buf; - header->contentBytes=1000; - header->nbBlocks=1; + /* Fixme: the orgin code calls the two funtiosn, so one overwrite the second? + rx_prach(eNB, + eNB->RU_list[0], + header->max_preamble, + header->max_preamble_energy, + header->max_preamble_delay, + header->avg_preamble_energy, + frame, + 0, + false + ); + */ + // run PRACH detection for CE-level 0 only for now when br_flag is set + rx_prach(eNB, + eNB->RU_list[0], + header->max_preamble, + header->max_preamble_energy, + header->max_preamble_delay, + header->avg_preamble_energy, + frame, + 0, + true + ); return; } -void prach_eNB_process(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { +void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; + fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); + uint16_t *max_preamble=header->max_preamble; + uint16_t *max_preamble_energy=header->max_preamble_energy; + uint16_t *max_preamble_delay=header->max_preamble_delay; + uint16_t *avg_preamble_energy=header->avg_preamble_energy; + // Fixme: not clear why we call twice with "br" and without + int br_flag=1; + + if (br_flag==1) { + int prach_mask; + prach_mask = is_prach_subframe (&eNB->frame_parms, eNB->proc.frame_prach_br, eNB->proc.subframe_prach_br); + eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; + int ind = 0; + int ce_level = 0; + /* Save for later, it doesn't work + for (int ind=0,ce_level=0;ce_level<4;ce_level++) { + + if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&& + (prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions + (eNB->prach_vars_br.repetition_number[ce_level]== + eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) { + + */ + + if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) { + if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) { + eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++; + eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; // + eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; + // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 + eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + subframe + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40)); + eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is + eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1 + ce_level; // CE Level + LOG_I (PHY, "Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + ind, + ce_level, + prach_mask, + eNB->preamble_list_br[ind].preamble_rel8.timing_advance, + eNB->preamble_list_br[ind].preamble_rel8.preamble, eNB->preamble_list_br[ind].preamble_rel8.rnti, eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type); + } + } + + /* + ind++; + } + } */// ce_level + } else if ((eNB->prach_energy_counter == 100) && + (max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) { + LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", + eNB->Mod_id, + eNB->CC_id, + frame, + subframe, + max_preamble[0], + max_preamble_energy[0]/10, + max_preamble_energy[0]%10, + max_preamble_delay[0]); + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1; + eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; + eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; + eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; + eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe; + eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; + eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; + eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; + eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here + eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; + eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is + + if (NFAPI_MODE==NFAPI_MODE_PNF) { // If NFAPI PNF then we need to send the message to the VNF + LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), + eNB->preamble_list[0].preamble_rel8.timing_advance, + eNB->preamble_list[0].preamble_rel8.preamble, + eNB->preamble_list[0].preamble_rel8.rnti, + eNB->preamble_list[0].preamble_rel13.rach_resource_type); + oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind); + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0; + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + } // max_preamble_energy > prach_I0 + 100 + else { + eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((avg_preamble_energy[0]*124)>>10); + + if (eNB->prach_energy_counter < 100) + eNB->prach_energy_counter++; + } } + +void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { + //RX processing for ue-specific resources (i + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + /* TODO: use correct rxdata */ + T (T_ENB_PHY_INPUT_SIGNAL, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (0), + T_BUFFER (&eNB->RU_list[0]->common.rxdata[0][subframe * eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti * 4)); + + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return; + + T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 1 ); + LOG_D (PHY, "[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n", eNB->Mod_id, frame, subframe); + eNB->rb_mask_ul[0] = 0; + eNB->rb_mask_ul[1] = 0; + eNB->rb_mask_ul[2] = 0; + eNB->rb_mask_ul[3] = 0; + // Fix me here, these should be locked + eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0; + eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs = 0; + // Call SRS first since all others depend on presence of SRS or lack thereof + srs_procedures (eNB, proc); + eNB->first_run_I0_measurements = 0; + uci_procedures (eNB, proc); + lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements); + int min_I0=1000,max_I0=0; + + if ((frame==0) && (subframe==4)) { + for (int i=0; iframe_parms.N_RB_UL; i++) { + if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2; + + if (eNB->measurements.n0_subband_power_tot_dB[i]measurements.n0_subband_power_tot_dB[i]; + + if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) + max_I0 = eNB->measurements.n0_subband_power_tot_dB[i]; + } + + LOG_I (PHY, "max_I0 %d, min_I0 %d\n", max_I0, min_I0); + } -void phy_procedures_eNB_uespec_RX_extract(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc, uint8_t *buf, int bufSize) { commonUDP_t *header=(commonUDP_t *) buf; header->contentBytes=1000; header->nbBlocks=1; return; } -void phy_procedures_eNB_uespec_RX_process(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { +void phy_procedures_eNB_uespec_RX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { } -void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { +void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; - UDPheader->contentBytes=1000; - UDPheader->nbBlocks=1; fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); // TBD: read frame&subframe from received data - int frame=proc->frame_tx; - int subframe=proc->subframe_tx; - uint32_t i,aa; - uint8_t harq_pid; - uint8_t num_pdcch_symbols=0; - uint8_t num_dci=0; - uint8_t num_mdci = 0; - uint8_t ul_subframe; - uint32_t ul_frame; + int frame=proc->frame_tx=header->frame; + int subframe=proc->subframe_tx=header->subframe; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_UL_eNB_HARQ_t *ulsch_harq; - + eNB->pdcch_vars[subframe&1].num_pdcch_symbols=header->num_pdcch_symbols; + eNB->pdcch_vars[subframe&1].num_dci=header->num_dci; + uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = header->num_mdci; if (do_meas==1) { start_meas(&eNB->phy_proc_tx); @@ -132,7 +234,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN } // clear the transmit data array for the current subframe - for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { + for (int aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) { memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti)], 0, fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t)); } @@ -142,21 +244,20 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN pmch_procedures(eNB,proc); } else { // this is not a pmch subframe, so generate PSS/SSS/PBCH - common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx); + common_signal_procedures(eNB,frame, subframe); } } - // clear existing ulsch dci allocations before applying info from MAC (this is table - ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); - ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); - // clear previous allocation information for all UEs - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { if (eNB->dlsch[i][0]) eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { + for (int i=0; i< header->num_dci; i++) + eNB->pdcch_vars[subframe&1].dci_alloc[i]=header->dci_alloc[i]; + generate_dci_top(header->num_pdcch_symbols, header->num_dci, &eNB->pdcch_vars[subframe&1].dci_alloc[0], @@ -165,7 +266,6 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN fp, eNB->common_vars.txdataF, header->subframe); - num_mdci = eNB->mpdcch_vars[subframe &1].num_dci; if (num_mdci > 0) { LOG_D (PHY, "[eNB %" PRIu8 "] Frame %d, subframe %d: Calling generate_mdci_top (mpdcch) (num_dci %" PRIu8 ")\n", eNB->Mod_id, frame, subframe, num_mdci); @@ -177,6 +277,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN if (header->UE_active[UE_id]) { // if we generate dlsch, we must generate pdsch LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1]; + int harq_pid=dlsch0->harq_ids[frame%2][subframe]=header->UE_active[UE_id]; pdsch_procedures(eNB, proc, harq_pid, @@ -191,15 +292,32 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eN AMP); } -void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { +void appendFs6DLUE(uint8_t *bufferZone, uint8_t *UEdata, int UEdataLen) { + commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; + // move to the end + uint8_t *firstFreeByte=bufferZone; + int curBlock=0; + + for (int i=0; i < FirstUDPheader->nbBlocks; i++) { + AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,""); + firstFreeByte+=alignedSize(firstFreeByte); + curBlock++; + } + + AssertFatal(firstFreeByte+UEdataLen+sizeof(fs6_dl_t) <= bufferZone+FS6_BUF_SIZE, ""); + commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; + FirstUDPheader->nbBlocks++; + newUDPheader->blockID=curBlock; + newUDPheader->contentBytes=sizeof(fs6_dl_t)+UEdataLen; + // We skip the fs6 DL header, that is populated by caller + // This header will be duplicated during sending + memcpy(commonUDPdata(firstFreeByte+sizeof(fs6_dl_t)), UEdata, UEdataLen); +} + +void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); int frame=proc->frame_tx; int subframe=proc->subframe_tx; - uint32_t i,aa; - uint8_t harq_pid; - uint8_t num_pdcch_symbols=0; - uint8_t num_dci=0; - uint8_t num_mdci = 0; uint8_t ul_subframe; uint32_t ul_frame; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; @@ -215,7 +333,7 @@ void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxt ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); // clear previous allocation information for all UEs - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { if (eNB->dlsch[i][0]) eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } @@ -224,8 +342,11 @@ void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxt //if ((ul_subframe < 10)&& // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here - for (i=0; iulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; + for (int i=0; iulsch[i] && eNB->ulsch[i]->ue_type >0) + harq_pid = 0; else harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); @@ -255,13 +376,15 @@ void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxt } } - num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; - num_dci = eNB->pdcch_vars[subframe&1].num_dci; + uint8_t num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; + uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci; + uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { header->num_pdcch_symbols=num_pdcch_symbols; header->num_dci=num_dci; + header->num_mdci=num_mdci; header->amp=AMP; } @@ -270,11 +393,11 @@ void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxt if (do_meas==1) start_meas(&eNB->dlsch_ue_specific); // Now scan UE specific DLSCH - LTE_eNB_DLSCH_t *dlsch0,*dlsch1; + LTE_eNB_DLSCH_t *dlsch0; for (int UE_id=0; UE_iddlsch[UE_id][0]; - dlsch1 = eNB->dlsch[UE_id][1]; + header->UE_active[UE_id]=-1; if ((dlsch0)&&(dlsch0->rnti>0)&& #ifdef PHY_TX_THREAD @@ -284,7 +407,7 @@ void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxt #endif ) { // get harq_pid - harq_pid = dlsch0->harq_ids[frame%2][subframe]; + int harq_pid = dlsch0->harq_ids[frame%2][subframe]; AssertFatal(harq_pid>=0,"harq_pid is negative\n"); if (harq_pid>=8) { @@ -299,14 +422,37 @@ void phy_procedures_eNB_TX_extract(uint8_t bufferZone, PHY_VARS_eNB *eNB, L1_rxt dlsch0->harq_ids[frame%2][6], dlsch0->harq_ids[frame%2][7]); } else { - header->UE_active[UE_id]=true; + header->UE_active[UE_id]=harq_pid; if (dlsch_procedures(eNB, proc, harq_pid, dlsch0, &eNB->UE_stats[(uint32_t)UE_id])) { - append(UEdata); + // data in: dlsch0 harq_processes[harq_pid]->e + /* length + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + dlsch_harq->Qm, + dlsch_harq->Nl, + dlsch_harq->pdsch_start, + frame,subframe, + 0) + need harq_pid + */ + LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[harq_pid]; + appendFs6DLUE(bufferZone, + dlsch0->harq_processes[harq_pid]->e, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + dlsch_harq->Qm, + dlsch_harq->Nl, + dlsch_harq->pdsch_start, + frame,subframe, + 0) + ); } } } else if ((dlsch0)&&(dlsch0->rnti>0)&& @@ -334,9 +480,13 @@ void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { RU_proc_t *ru_proc=&ru->proc; for (int i=0; inum_eNB; i++) { - uint8_t bufferZone[FS6_BUF_SIZE]; - receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); - phy_procedures_eNB_TX_process( bufferZone, sizeof(bufferZone), ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); + initBufferZone(bufferZone); + int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + + if (nb_blocks>0) + phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); + else + LOG_E(PHY,"DL not received for subframe: %d\n", subframe); } /* Fixme: datamodel issue: a ru is supposed to be connected to several eNB @@ -371,15 +521,15 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { oai_subframe_ind(proc->frame_rx, proc->subframe_rx); } - uint8_t bufferZone[FS6_BUF_SIZE]; - prach_eNB_extract(eNB,NULL,proc->frame_rx,proc->subframe_rx, bufferZone, FS6_BUF_SIZE); + initBufferZone(bufferZone); + prach_eNB_extract(bufferZone, FS6_BUF_SIZE, eNB, proc->frame_rx,proc->subframe_rx ); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_extract(eNB, &proc->L1_proc, bufferZone, FS6_BUF_SIZE); + phy_procedures_eNB_uespec_RX_extract(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc ); } for (int i=0; inum_eNB; i++) { - sendSubFrame(&sockFS6,bufferZone); + sendSubFrame(&sockFS6,bufferZone, sizeof(fs6_ul_t)); } } @@ -394,28 +544,36 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { eNB->UL_INFO.CC_id = eNB->CC_id; eNB->if_inst->UL_indication(&eNB->UL_INFO); pthread_mutex_unlock(&eNB->UL_INFO_mutex); - uint8_t bufferZone[FS6_BUF_SIZE]; + initBufferZone(bufferZone); phy_procedures_eNB_TX_extract(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); - sendSubFrame(&sockFS6, bufferZone ); + commonUDP_t *firstHeader=(commonUDP_t *) bufferZone; + + if (firstHeader->nbBlocks==0) { + firstHeader->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE) + firstHeader->blockID=0; + firstHeader->contentBytes=sizeof(fs6_dl_t); + } + + sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t) ); } void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { - uint8_t bufferZone[FS6_BUF_SIZE]; - receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + initBufferZone(bufferZone); + int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; - prach_eNB_process(eNB,NULL,proc->frame_rx,proc->subframe_rx); + prach_eNB_process(bufferZone, sizeof(bufferZone), eNB,NULL,proc->frame_rx,proc->subframe_rx); release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_process(eNB, &proc->L1_proc); + phy_procedures_eNB_uespec_RX_process(bufferZone, sizeof(bufferZone), eNB, &proc->L1_proc); } } void *cu_fs6(void *arg) { RU_t *ru = (RU_t *)arg; - RU_proc_t *proc = &ru->proc; + //RU_proc_t *proc = &ru->proc; int64_t AbsoluteSubframe=-1; fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); @@ -436,7 +594,7 @@ void *cu_fs6(void *arg) { void *du_fs6(void *arg) { RU_t *ru = (RU_t *)arg; - RU_proc_t *proc = &ru->proc; + //RU_proc_t *proc = &ru->proc; int64_t AbsoluteSubframe=-1; fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); diff --git a/executables/split_headers.h b/executables/split_headers.h index 6480680693..f4bc2ba3db 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -34,17 +34,44 @@ typedef struct frequency_s { int nbSamples; } frequency_t; +typedef struct { + int frame; + int subframe; + uint16_t max_preamble[4]; + uint16_t max_preamble_energy[4]; + uint16_t max_preamble_delay[4]; + uint16_t avg_preamble_energy[4]; +} fs6_ul_t; + + +typedef struct { + int frame; + int subframe; + int num_pdcch_symbols; + int num_dci; + DCI_ALLOC_t dci_alloc[32]; + int num_mdci; + int amp; + bool UE_active[NUMBER_OF_UE_MAX]; + LTE_eNB_PHICH phich_vars; +} fs6_dl_t; + bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize); -int sendSubFrame(UDPsock_t *sock, void *bufferZone); +int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize); -inline size_t alignedSize(void *ptr) { +#define initBufferZone(xBuf) \ + uint8_t xBuf[FS6_BUF_SIZE];\ + ((commonUDP_t *)xBuf)->nbBlocks=0; + + +inline size_t alignedSize(uint8_t *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign; } -inline void * commonUDPdata(void* ptr) { - return (void*) (((commonUDP_t*)ptr)+1); +inline void *commonUDPdata(uint8_t *ptr) { + return (void *) (((commonUDP_t *)ptr)+1); } void *cu_fs6(void *arg); @@ -54,7 +81,16 @@ void rx_rf(RU_t *ru,int *frame,int *subframe); void tx_rf(RU_t *ru); void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe); void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); - +bool dlsch_procedures(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, + int harq_pid, + LTE_eNB_DLSCH_t *dlsch, + LTE_eNB_UE_stats *ue_stats) ; +void pdsch_procedures(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, + int harq_pid, + LTE_eNB_DLSCH_t *dlsch, + LTE_eNB_DLSCH_t *dlsch1); // mistakes in main OAI void phy_init_RU(RU_t *); void feptx_prec(RU_t *); diff --git a/executables/transport_split.c b/executables/transport_split.c index 00de32a156..8a43a63833 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -99,11 +99,20 @@ int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int return rcved; } -int sendSubFrame(UDPsock_t *sock, void *bufferZone) { - commonUDP_t *header=(commonUDP_t *)bufferZone ; - int nbBlocks=header->nbBlocks; +int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize) { + commonUDP_t *UDPheader=(commonUDP_t *)bufferZone ; + int nbBlocks=UDPheader->nbBlocks; + int blockId=0; do { + if (blockId > 0 ) { + commonUDP_t *currentHeader=(commonUDP_t *)bufferZone; + *currentHeader=*UDPheader; + currentHeader->blockID=blockId; + memcpy(commonUDPdata((void *)currentHeader), commonUDPdata(bufferZone), secondHeaderSize); + blockId++; + } + int sz=alignedSize(bufferZone); // Let's use the first address returned by getaddrinfo() int ret=sendto(sock->sockHandler, bufferZone, sz, 0, From a9122624a178e13105362d86cdc766616b333fbf Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 26 Jul 2019 11:24:51 +0200 Subject: [PATCH 013/175] progress fs6 uplink --- executables/dl_fs6.c | 313 +++++++++++++++++++++++++++++++----- executables/split_headers.h | 12 +- 2 files changed, 282 insertions(+), 43 deletions(-) diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 7dacf08b51..3e72eb8c37 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -14,13 +14,14 @@ #include #include #include +#include #include #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { - commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; + //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); if (is_prach_subframe(&eNB->frame_parms, frame,subframe)<=0) @@ -47,7 +48,7 @@ void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int } /* Fixme: the orgin code calls the two funtiosn, so one overwrite the second? - rx_prach(eNB, + rx_prach(eNB, eNB->RU_list[0], header->max_preamble, header->max_preamble_energy, @@ -73,7 +74,7 @@ void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int } void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; + //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); uint16_t *max_preamble=header->max_preamble; uint16_t *max_preamble_energy=header->max_preamble_energy; @@ -119,7 +120,7 @@ void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t /* ind++; } - } */// ce_level + } */// ce_level } else if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) { LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", @@ -165,7 +166,72 @@ void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t } } -void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc) { +void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { + uint32_t harq_pid; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); + + for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { + LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i]; + + if (ulsch->ue_type > 0) harq_pid = 0; + else harq_pid=harq_pid0; + + LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; + + if (ulsch->rnti>0) + LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n", + i, harq_pid, frame,subframe,i,ulsch->rnti, + ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); + + if ((ulsch) && + (ulsch->rnti>0) && + (ulsch_harq->status == ACTIVE) && + (ulsch_harq->frame == frame) && + (ulsch_harq->subframe == subframe) && + (ulsch_harq->handled == 0)) { + // UE has ULSCH scheduling + for (int rb=0; + rb<=ulsch_harq->nb_rb; + rb++) { + int rb2 = rb+ulsch_harq->first_rb; + eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); + } + + LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", + eNB->Mod_id, frame, subframe, i); + uint8_t nPRS= fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1]; + ulsch->cyclicShift = (ulsch_harq->n_DMRS2 + + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + + nPRS)%12; + AssertFatal(ulsch_harq->TBS>0,"illegal TBS %d\n",ulsch_harq->TBS); + LOG_D(PHY, + "[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, ), O_ACK %d, beta_cqi %d \n", + eNB->Mod_id,harq_pid,frame,subframe, + ulsch_harq->dci_alloc, + ulsch_harq->rar_alloc, + ulsch_harq->round, + ulsch_harq->first_rb, + ulsch_harq->nb_rb, + ulsch_harq->Qm, + ulsch_harq->TBS, + ulsch_harq->rvidx, + ulsch->cyclicShift, + ulsch_harq->n_DMRS2, + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift, + ulsch_harq->O_ACK, + ulsch->beta_offset_cqi_times8); + start_meas(&eNB->ulsch_demodulation_stats); + rx_ulsch(eNB,proc, i); + stop_meas(&eNB->ulsch_demodulation_stats); + // TBD: add datablock for transmission + } + } +} + +void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { //RX processing for ue-specific resources (i LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; const int subframe = proc->subframe_rx; @@ -176,8 +242,6 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eN if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return; - T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 1 ); LOG_D (PHY, "[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n", eNB->Mod_id, frame, subframe); eNB->rb_mask_ul[0] = 0; eNB->rb_mask_ul[1] = 0; @@ -190,6 +254,11 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eN srs_procedures (eNB, proc); eNB->first_run_I0_measurements = 0; uci_procedures (eNB, proc); + + if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // If PNF or monolithic + pusch_procedures_extract(buf, bufSize, eNB,proc); + } + lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements); int min_I0=1000,max_I0=0; @@ -213,17 +282,172 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eN return; } +void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { + //LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + uint32_t harq_pid; + uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); + + for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { + LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i]; + + if (ulsch->ue_type > 0) harq_pid = 0; + else harq_pid=harq_pid0; + + LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; + + if (ulsch->rnti>0) LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n", + i, harq_pid, frame,subframe,i,ulsch->rnti, + ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); + + if ((ulsch) && + (ulsch->rnti>0) && + (ulsch_harq->status == ACTIVE) && + (ulsch_harq->frame == frame) && + (ulsch_harq->subframe == subframe) && + (ulsch_harq->handled == 0)) { + // UE has ULSCH scheduling + for (int rb=0; + rb<=ulsch_harq->nb_rb; + rb++) { + int rb2 = rb+ulsch_harq->first_rb; + eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); + } + + start_meas(&eNB->ulsch_decoding_stats); + int ret = ulsch_decoding(eNB,proc, + i, + 0, // control_only_flag + ulsch_harq->V_UL_DAI, + ulsch_harq->nb_rb>20 ? 1 : 0); + stop_meas(&eNB->ulsch_decoding_stats); + LOG_D(PHY, + "[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n", + eNB->Mod_id,harq_pid, + frame,subframe, + ulsch->rnti, + dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), + dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), + 30,//eNB->measurements.n0_power_dB[0], + 30,//eNB->measurements.n0_power_dB[1], + ulsch_harq->o_ACK[0], + ulsch_harq->o_ACK[1], + ret, + ulsch_harq->cqi_crc_status, + ulsch_harq->O_ACK, + eNB->ulsch_decoding_stats.p_time, eNB->ulsch_decoding_stats.max); + //compute the expected ULSCH RX power (for the stats) + ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered + + if (RC.mac != NULL) { /* ulsim does not use RC.mac context. */ + if (ulsch_harq->cqi_crc_status == 1) { +#ifdef DEBUG_PHY_PROC + //if (((frame%10) == 0) || (frame < 50)) + print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL); +#endif + fill_ulsch_cqi_indication(eNB,frame,subframe,ulsch_harq,ulsch->rnti); + RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << subframe)); + } else { + if(RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag & (1 << subframe) ) { + RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << subframe)); + RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_timer=30; + LOG_D(PHY,"Frame %d,Subframe %d, We're supposed to get a cqi here. Set cqi_req_timer to 30.\n",frame,subframe); + } + } + } + + if (ret == (1+MAX_TURBO_ITERATIONS)) { + T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), + T_INT(harq_pid)); + fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC + fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", + eNB->Mod_id,harq_pid, + frame,subframe, i, + ulsch_harq->round, + ulsch->Mlimit, + ulsch_harq->o_ACK[0], + ulsch_harq->o_ACK[1]); + + if (ulsch_harq->round >= 3) { + ulsch_harq->status = SCH_IDLE; + ulsch_harq->handled = 0; + ulsch->harq_mask &= ~(1 << harq_pid); + ulsch_harq->round = 0; + } + + MSC_LOG_RX_DISCARDED_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u ULSCH received rnti %x harq id %u round %d", + frame,subframe, + ulsch->rnti,harq_pid, + ulsch_harq->round-1 + ); + /* Mark the HARQ process to release it later if max transmission reached + * (see below). + * MAC does not send the max transmission count, we have to deal with it + * locally in PHY. + */ + ulsch_harq->handled = 1; + } // ulsch in error + else { + fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC + fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + ulsch_harq->status = SCH_IDLE; + ulsch->harq_mask &= ~(1 << harq_pid); + T (T_ENB_PHY_ULSCH_UE_ACK, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (ulsch->rnti), T_INT (harq_pid)); + MSC_LOG_RX_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u ULSCH received rnti %x harq id %u", + frame,subframe, + ulsch->rnti,harq_pid + ); + } // ulsch not in error + + if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling); + + LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", + eNB->Mod_id,frame,subframe, + harq_pid, + i, + ret, + ulsch_harq->cqi_crc_status, + ulsch_harq->o_ACK[0], + ulsch_harq->o_ACK[1], + eNB->UE_stats[i].ulsch_errors[harq_pid], + eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]); + } // if ((ulsch) && + // (ulsch->rnti>0) && + // (ulsch_harq->status == ACTIVE)) + else if ((ulsch) && + (ulsch->rnti>0) && + (ulsch_harq->status == ACTIVE) && + (ulsch_harq->frame == frame) && + (ulsch_harq->subframe == subframe) && + (ulsch_harq->handled == 1)) { + // this harq process is stale, kill it, this 1024 frames later (10s), consider reducing that + ulsch_harq->status = SCH_IDLE; + ulsch_harq->handled = 0; + ulsch->harq_mask &= ~(1 << harq_pid); + LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask); + } + } // for (i=0; iframe_tx=header->frame; int subframe=proc->subframe_tx=header->subframe; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - LTE_UL_eNB_HARQ_t *ulsch_harq; + //LTE_UL_eNB_HARQ_t *ulsch_harq; eNB->pdcch_vars[subframe&1].num_pdcch_symbols=header->num_pdcch_symbols; eNB->pdcch_vars[subframe&1].num_dci=header->num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = header->num_mdci; @@ -274,10 +498,10 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e } for (int UE_id=0; UE_idUE_active[UE_id]) { // if we generate dlsch, we must generate pdsch + if (header->UE_dl_active[UE_id]) { // if we generate dlsch, we must generate pdsch LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1]; - int harq_pid=dlsch0->harq_ids[frame%2][subframe]=header->UE_active[UE_id]; + int harq_pid=dlsch0->harq_ids[frame%2][subframe]=header->UE_dl_active[UE_id]; pdsch_procedures(eNB, proc, harq_pid, @@ -318,10 +542,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); int frame=proc->frame_tx; int subframe=proc->subframe_tx; - uint8_t ul_subframe; - uint32_t ul_frame; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - LTE_UL_eNB_HARQ_t *ulsch_harq; if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) return; @@ -329,8 +550,8 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx header->frame=frame; header->subframe=subframe; // clear existing ulsch dci allocations before applying info from MAC (this is table - ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); - ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); + header->ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); + header->ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); // clear previous allocation information for all UEs for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { @@ -341,17 +562,17 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx /* TODO: check the following test - in the meantime it is put back as it was before */ //if ((ul_subframe < 10)&& // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here - if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + if (header->ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here for (int i=0; iulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0; else - harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + header->UE_ul_active[i] = harq_pid = subframe2harq_pid(fp,header->ul_frame,header->ul_subframe); if (eNB->ulsch[i]) { - ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; + //LTE_UL_eNB_HARQ_t *ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; /* Store first_rb and n_DMRS for correct PHICH generation below. * For PHICH generation we need "old" values of last scheduling * for this HARQ process. 'generate_eNB_dlsch_params' below will @@ -370,9 +591,15 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx * * TODO: check if that works with TDD. */ - ulsch_harq->previous_first_rb = ulsch_harq->first_rb; - ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; - } + /* seems useless: unused variables + header->previous_first_rb= + ulsch_harq->previous_first_rb = ulsch_harq->first_rb; + header->previous_n_DMRS = + ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + */ + header->UE_ul_active[i] = harq_pid; + } else + header->UE_ul_active[i] = -1; } } @@ -397,7 +624,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx for (int UE_id=0; UE_iddlsch[UE_id][0]; - header->UE_active[UE_id]=-1; + header->UE_dl_active[UE_id]=-1; if ((dlsch0)&&(dlsch0->rnti>0)&& #ifdef PHY_TX_THREAD @@ -422,7 +649,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx dlsch0->harq_ids[frame%2][6], dlsch0->harq_ids[frame%2][7]); } else { - header->UE_active[UE_id]=harq_pid; + header->UE_dl_active[UE_id]=harq_pid; if (dlsch_procedures(eNB, proc, @@ -431,15 +658,15 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx &eNB->UE_stats[(uint32_t)UE_id])) { // data in: dlsch0 harq_processes[harq_pid]->e /* length - get_G(fp, - dlsch_harq->nb_rb, - dlsch_harq->rb_alloc, - dlsch_harq->Qm, - dlsch_harq->Nl, - dlsch_harq->pdsch_start, - frame,subframe, - 0) - need harq_pid + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + dlsch_harq->Qm, + dlsch_harq->Nl, + dlsch_harq->pdsch_start, + frame,subframe, + 0) + need harq_pid */ LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[harq_pid]; appendFs6DLUE(bufferZone, @@ -477,8 +704,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx } void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { - RU_proc_t *ru_proc=&ru->proc; - + //RU_proc_t *ru_proc=&ru->proc; for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); @@ -490,10 +716,10 @@ void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { } /* Fixme: datamodel issue: a ru is supposed to be connected to several eNB - L1_rxtx_proc_t * L1_proc = &proc->L1_proc; - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; + L1_rxtx_proc_t * L1_proc = &proc->L1_proc; + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; */ feptx_prec(ru); feptx_ofdm(ru); @@ -509,8 +735,8 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; - L1_rxtx_proc_t *L1_proc = &proc->L1_proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + //L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + //LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; proc->frame_rx = frame; proc->subframe_rx = subframe; @@ -559,7 +785,12 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { initBufferZone(bufferZone); + commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + + if (nb_blocks != UDPheader->nbBlocks ) + LOG_W(PHY, "received %d blocks for %d expected\n", nb_blocks, UDPheader->nbBlocks); + // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; diff --git a/executables/split_headers.h b/executables/split_headers.h index f4bc2ba3db..4cb2f4a5c4 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -43,16 +43,20 @@ typedef struct { uint16_t avg_preamble_energy[4]; } fs6_ul_t; - typedef struct { int frame; int subframe; + int ul_frame; + int ul_subframe; int num_pdcch_symbols; int num_dci; DCI_ALLOC_t dci_alloc[32]; int num_mdci; int amp; - bool UE_active[NUMBER_OF_UE_MAX]; + int8_t UE_dl_active[NUMBER_OF_UE_MAX]; // the HARQ id for this UE (-1: disabled) + int8_t UE_ul_active[NUMBER_OF_UE_MAX]; + int8_t UE_ul_first_rb[NUMBER_OF_UE_MAX]; // + int8_t UE_ul_last_rb[NUMBER_OF_UE_MAX]; // LTE_eNB_PHICH phich_vars; } fs6_dl_t; @@ -91,6 +95,10 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, int harq_pid, LTE_eNB_DLSCH_t *dlsch, LTE_eNB_DLSCH_t *dlsch1); +void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); +void uci_procedures(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc); + // mistakes in main OAI void phy_init_RU(RU_t *); void feptx_prec(RU_t *); From 9e4f59f8e5c2c1042d668ecc620f26a5d81df3e8 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 29 Jul 2019 08:58:40 +0200 Subject: [PATCH 014/175] add SystemX documentation --- SystemX-tutorial-design.odt | Bin 0 -> 54430 bytes executables/dl_fs6.c | 15 +++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 SystemX-tutorial-design.odt diff --git a/SystemX-tutorial-design.odt b/SystemX-tutorial-design.odt new file mode 100644 index 0000000000000000000000000000000000000000..788f9de955d3891f294a4efd08686925c6834e61 GIT binary patch literal 54430 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 literal 0 HcmV?d00001 diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c index 3e72eb8c37..3b20ac9c7a 100644 --- a/executables/dl_fs6.c +++ b/executables/dl_fs6.c @@ -171,13 +171,14 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; - uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i]; - if (ulsch->ue_type > 0) harq_pid = 0; - else harq_pid=harq_pid0; + if (ulsch->ue_type > 0) + harq_pid = 0; + else + harq_pid= subframe2harq_pid(&eNB->frame_parms,frame,subframe); LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; @@ -297,9 +298,10 @@ void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - if (ulsch->rnti>0) LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n", - i, harq_pid, frame,subframe,i,ulsch->rnti, - ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); + if (ulsch->rnti>0) + LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n", + i, harq_pid, frame,subframe,i,ulsch->rnti, + ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); if ((ulsch) && (ulsch->rnti>0) && @@ -550,6 +552,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx header->frame=frame; header->subframe=subframe; // clear existing ulsch dci allocations before applying info from MAC (this is table + // returns -1 (or 255) if there is no ul (tdd cases) header->ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); header->ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); From 2af75f48f20ccd1c0cababda2e05a8a20bf5fd8d Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 29 Jul 2019 09:12:24 +0200 Subject: [PATCH 015/175] merge develop --- executables/main-ocp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 13464ed166..3fc3b00e89 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -256,8 +256,8 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list; eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list; eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list; - eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list; - eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; + eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_pdu_list = eNB->cqi_pdu_list; + eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; eNB->prach_energy_counter = 0; } } From 75665ad0fc1247b598eb4b6db98b78920baa5cd2 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 1 Aug 2019 10:45:25 +0200 Subject: [PATCH 016/175] Create DL sub header --- SystemX-tutorial-design.odt | Bin 54430 -> 55501 bytes cmake_targets/CMakeLists.txt | 2 +- executables/{dl_fs6.c => main-fs6.c} | 99 +++++++++++++++------ executables/split_headers.h | 8 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 12 +-- openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 6 +- openair1/SCHED/phy_procedures_lte_eNb.c | 6 +- 7 files changed, 90 insertions(+), 43 deletions(-) rename executables/{dl_fs6.c => main-fs6.c} (92%) diff --git a/SystemX-tutorial-design.odt b/SystemX-tutorial-design.odt index 788f9de955d3891f294a4efd08686925c6834e61..42e195ac112b370ff7d48cfbb5e083d9cfaecf6e 100644 GIT binary patch delta 21677 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�e+QF_zHp1N4uo9b0i5eK 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 delta 20589 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

)QR!~2=}W7u<&nt14zsWr3);Rp^>DYefC0$* zaidVpUyerMa)9giJ=CB>Uc@8W-6Udtf9{vbLJG*x$Wtrrdih-S zMVF0+?+eU__^P5liMa|D723)0yL}CY`~s={+x>mMU90arYfYfV+P?Q?lpN=eVFsD+ zw+)25K2Vj?N}yDq(HD*Sd+Y-9fB7VBYuHk``uJd>rz^m!VaLiMfAVd;x^HzSCYqlb zLA;Ly*)3X)D_?H6oCbG4-r?@mT)HlRY@Rjq*K)=u;;}^kMt* z5C?PebD?a_jXeT*tL8r$F*tw2*Bo9XvOx`nHhT(wywg%lyw@UAU)xQlC-YCs?M6q# zC2iTX=%bwz_TFz2blD47ZRCrq+l3}x&u0xidN2xX#z3`bW^+D`DrMUtPiOjzV$j=> z?A%xs)(vrRuX9{;ql2m1ZSfg03@OD)`UZ$=_9n6qY(+wxB3RsXJx@U@{oOpcL0S@J ziiaI?y=xcRH6`x~uec25v#0cSH^_xo>qA{$Z2%wop`NtyR3c#=gma>JE8c-SgJ4Gv zB484|Rpmydfe+i6Vy{I z>JZ5&P%3P+FVjekJPAWw-lSKffus=|q-6(Nmtv^c>DXkJrEglksM8RoE7N8TzFGi( zI9sPad>?_y^@eRKI!UcRP*ySxpyo+WDL?sO=}6kYg->569#v zLCe<};LP$@R_MfNuJ3&QbF>H60vrrBeAcd@MVmv4pV$_tYOv5&CW(YkZ9tq$EPSUi zDU0KQDU<_Sy0!MkGGmR1l+Tq2*ZA`2(m{c&or}H&@ON33mW~KbD;L6d1oio_D#o+~ z@WR?x`Fbdb-BCq_K73^)Lnr0!zZ7`dn>kdFF~t1waDW;@kD!tpRmKadlru~ucwUQ!vI@ zDj-2en|rOi*jP(8y||qy+9odCrk6)C(d2e2Mz75uLUX>e~$wC28mhweQ8ZQUo8TuRrZ9_6Dm_GpBX- z5xfTn^MB3qC^aR_7?OOj2zMJRJ6_zFIY``jqXg;AC1Wd7YyB#{R$gbi--~~n=3%)k zl38#qdGJBr-J~ye&M{7YSJ?^o~ zAKh8`ZLQHQX5!s#ja;WQ8ke@8P|KMg39vL?19n-@3CFI=CnDxE`l%=QlW+XpP^cA~ zRbS9+4g#Go@iUsC<7DfFhQJ6d&f5jiG<7xLADjMqP6mST9Q2p>kHKJ3l;;>fqi>(- z^eaXXXp@lOta%YkKn40|ejMucnCR7W67$ahIn=i?N!Ig|-&-EfY0WROKp1bDulsch[i]; - if (ulsch->ue_type > 0) + if (ulsch->ue_type > NOCE) harq_pid = 0; else harq_pid= subframe2harq_pid(&eNB->frame_parms,frame,subframe); @@ -232,14 +232,12 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN } } -void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { +void phy_procedures_eNB_uespec_RX_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { //RX processing for ue-specific resources (i LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; /* TODO: use correct rxdata */ - T (T_ENB_PHY_INPUT_SIGNAL, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (0), - T_BUFFER (&eNB->RU_list[0]->common.rxdata[0][subframe * eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti * 4)); if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return; @@ -257,7 +255,7 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eN uci_procedures (eNB, proc); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // If PNF or monolithic - pusch_procedures_extract(buf, bufSize, eNB,proc); + pusch_procedures_extract(bufferZone, bufSize, eNB,proc); } lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements); @@ -277,9 +275,6 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *buf, int bufSize, PHY_VARS_eN LOG_I (PHY, "max_I0 %d, min_I0 %d\n", max_I0, min_I0); } - commonUDP_t *header=(commonUDP_t *) buf; - header->contentBytes=1000; - header->nbBlocks=1; return; } @@ -293,7 +288,7 @@ void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i]; - if (ulsch->ue_type > 0) harq_pid = 0; + if (ulsch->ue_type > NOCE) harq_pid = 0; else harq_pid=harq_pid0; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; @@ -454,6 +449,35 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e eNB->pdcch_vars[subframe&1].num_dci=header->num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = header->num_mdci; + // Remove all scheduled DL, we will populate from the CU sending + for (int UE_id=0; UE_iddlsch[UE_id][0]; + + if ( dlsch0 && dlsch0->rnti>0 ) { +#ifdef PHY_TX_THREAD + dlsch0->active[subframe] = 0; +#else + dlsch0->active = 0; +#endif + } + } + + void *bufPtr=bufferZone; + + for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks + fs6_dl_uespec_t *dlPtr=(fs6_dl_uespec_t *)(commonUDPdata(bufPtr)+sizeof(fs6_dl_t)); +#ifdef PHY_TX_THREAD + eNB->dlsch[dlPtr->UE_id][0]->active[subframe] = 1; +#else + eNB->dlsch[dlPtr->UE_id][0]->active = 1; +#endif + eNB->dlsch[dlPtr->UE_id][0]->harq_ids[frame%2][subframe]=dlPtr->harq_pid; + eNB->dlsch[dlPtr->UE_id][0]->rnti=dlPtr->rnti; + memcpy(eNB->dlsch[dlPtr->UE_id][0]->harq_processes[dlPtr->harq_pid]->e, + commonUDPdata(((uint8_t *)dlPtr)+sizeof(fs6_dl_t)), dlPtr->dataLen); + bufPtr+=alignedSize(bufPtr); + } + if (do_meas==1) { start_meas(&eNB->phy_proc_tx); start_meas(&eNB->dlsch_common_and_dci); @@ -476,8 +500,8 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e // clear previous allocation information for all UEs for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (eNB->dlsch[i][0]) - eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + //if (eNB->dlsch[i][0]) + //eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -500,10 +524,17 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e } for (int UE_id=0; UE_idUE_dl_active[UE_id]) { // if we generate dlsch, we must generate pdsch - LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; - LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1]; - int harq_pid=dlsch0->harq_ids[frame%2][subframe]=header->UE_dl_active[UE_id]; + LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; + LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1]; + + if ((dlsch0)&&(dlsch0->rnti>0)&& +#ifdef PHY_TX_THREAD + (dlsch0->active[subframe] == 1) +#else + (dlsch0->active == 1) +#endif + ) { + int harq_pid=dlsch0->harq_ids[frame%2][subframe]; pdsch_procedures(eNB, proc, harq_pid, @@ -518,7 +549,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e AMP); } -void appendFs6DLUE(uint8_t *bufferZone, uint8_t *UEdata, int UEdataLen) { +void appendFs6DLUE(uint8_t *bufferZone, int UE_id, int8_t harq_pid, uint16_t rnti, uint8_t *UEdata, int UEdataLen) { commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; // move to the end uint8_t *firstFreeByte=bufferZone; @@ -534,10 +565,14 @@ void appendFs6DLUE(uint8_t *bufferZone, uint8_t *UEdata, int UEdataLen) { commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; FirstUDPheader->nbBlocks++; newUDPheader->blockID=curBlock; - newUDPheader->contentBytes=sizeof(fs6_dl_t)+UEdataLen; + newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) + UEdataLen; // We skip the fs6 DL header, that is populated by caller // This header will be duplicated during sending - memcpy(commonUDPdata(firstFreeByte+sizeof(fs6_dl_t)), UEdata, UEdataLen); + fs6_dl_uespec_t *tmp=(fs6_dl_uespec_t *) firstFreeByte+sizeof(fs6_dl_t); + tmp->UE_id=UE_id; + tmp->harq_pid=harq_pid; + tmp->rnti=rnti; + memcpy(commonUDPdata(((uint8_t *)tmp)+sizeof(fs6_dl_uespec_t)), UEdata, UEdataLen); } void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { @@ -558,8 +593,8 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx // clear previous allocation information for all UEs for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (eNB->dlsch[i][0]) - eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + //if (eNB->dlsch[i][0]) + //eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } /* TODO: check the following test - in the meantime it is put back as it was before */ @@ -569,7 +604,8 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx for (int i=0; iulsch[i] && eNB->ulsch[i]->ue_type >0) + if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type > NOCE) + // LTE-M case harq_pid = 0; else header->UE_ul_active[i] = harq_pid = subframe2harq_pid(fp,header->ul_frame,header->ul_subframe); @@ -608,7 +644,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx uint8_t num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci; - uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; + uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -626,8 +662,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx LTE_eNB_DLSCH_t *dlsch0; for (int UE_id=0; UE_iddlsch[UE_id][0]; - header->UE_dl_active[UE_id]=-1; + LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; if ((dlsch0)&&(dlsch0->rnti>0)&& #ifdef PHY_TX_THREAD @@ -641,7 +676,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx AssertFatal(harq_pid>=0,"harq_pid is negative\n"); if (harq_pid>=8) { - if (dlsch0->ue_type==0) + if (dlsch0->ue_type == NOCE) LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x [ %1d.%1d.%1d.%1d.%1d.%1d.%1d.%1d\n", harq_pid,UE_id,frame,subframe,dlsch0->rnti, dlsch0->harq_ids[frame%2][0], dlsch0->harq_ids[frame%2][1], @@ -652,8 +687,6 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx dlsch0->harq_ids[frame%2][6], dlsch0->harq_ids[frame%2][7]); } else { - header->UE_dl_active[UE_id]=harq_pid; - if (dlsch_procedures(eNB, proc, harq_pid, @@ -673,6 +706,9 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx */ LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[harq_pid]; appendFs6DLUE(bufferZone, + UE_id, + harq_pid, + dlsch0->rnti, dlsch0->harq_processes[harq_pid]->e, get_G(fp, dlsch_harq->nb_rb, @@ -693,7 +729,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx #endif ) { // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) - dlsch0->subframe_tx[subframe]=0; + //dlsch0->subframe_tx[subframe]=0; } } @@ -791,12 +827,17 @@ void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + if (nb_blocks ==0) { + LOG_W(PHY, "CU lost a subframe\n"); + return; + } + if (nb_blocks != UDPheader->nbBlocks ) LOG_W(PHY, "received %d blocks for %d expected\n", nb_blocks, UDPheader->nbBlocks); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; - L1_proc_t *proc = &eNB->proc; + L1_proc_t *proc = &eNB->proc; prach_eNB_process(bufferZone, sizeof(bufferZone), eNB,NULL,proc->frame_rx,proc->subframe_rx); release_UE_in_freeList(eNB->Mod_id); diff --git a/executables/split_headers.h b/executables/split_headers.h index 4cb2f4a5c4..35e2e78d3a 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -53,13 +53,19 @@ typedef struct { DCI_ALLOC_t dci_alloc[32]; int num_mdci; int amp; - int8_t UE_dl_active[NUMBER_OF_UE_MAX]; // the HARQ id for this UE (-1: disabled) int8_t UE_ul_active[NUMBER_OF_UE_MAX]; int8_t UE_ul_first_rb[NUMBER_OF_UE_MAX]; // int8_t UE_ul_last_rb[NUMBER_OF_UE_MAX]; // LTE_eNB_PHICH phich_vars; } fs6_dl_t; +typedef struct { + int UE_id; + int8_t harq_pid; + uint16_t rnti; + int dataLen; +} fs6_dl_uespec_t; + bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize); int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize); diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 29bbd774a1..476e255fef 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -307,7 +307,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0_harq->codeword = 0; dlsch1_harq = dlsch1->harq_processes[rel8->harq_process]; dlsch1_harq->codeword = 1; - dlsch0->subframe_tx[subframe] = 1; + //dlsch0->subframe_tx[subframe] = 1; LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d dlsch0[rnti:%x harq_mask:%04x] dci_pdu[rnti:%x rnti_type:%d harq_process:%d ndi1:%d] dlsch0_harq[round:%d harq_mask:%x ndi:%d]\n", frame,subframe, @@ -658,7 +658,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0_harq->codeword = 0; // printf("DCI: Setting subframe_tx for subframe %d\n",subframe); - dlsch0->subframe_tx[subframe] = 1; + //dlsch0->subframe_tx[subframe] = 1; conv_rballoc (rel8->resource_allocation_type, rel8->resource_block_coding, fp->N_RB_DL, dlsch0_harq->rb_alloc); @@ -868,7 +868,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0_harq = dlsch0->harq_processes[rel8->harq_process]; dlsch1_harq = dlsch1->harq_processes[rel8->harq_process]; - dlsch0->subframe_tx[subframe] = 1; + //dlsch0->subframe_tx[subframe] = 1; dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process; dlsch1->harq_ids[frame%2][subframe] = rel8->harq_process; @@ -1316,7 +1316,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t } if (dlsch0 != NULL) { - dlsch0->subframe_tx[subframe] = 1; + //dlsch0->subframe_tx[subframe] = 1; dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process; } @@ -1723,7 +1723,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,mDCI_ALLOC_t *dc dlsch0_harq->codeword = 0; // printf("DCI: Setting subframe_tx for subframe %d\n",subframe); - dlsch0->subframe_tx[(subframe + 2) % 10] = 1; + //dlsch0->subframe_tx[(subframe + 2) % 10] = 1; LOG_D(PHY,"PDSCH : resource_block_coding %x\n",rel13->resource_block_coding); conv_eMTC_rballoc (rel13->resource_block_coding, @@ -1746,7 +1746,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,mDCI_ALLOC_t *dc dlsch0_harq->dl_power_off = 1; - dlsch0->subframe_tx[subframe] = 1; + //dlsch0->subframe_tx[subframe] = 1; if (dlsch0->rnti != rel13->rnti) { // if rnti of dlsch is not the same as in the config, this is a new entry dlsch0_harq->round = 0; dlsch0->harq_mask =0; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 9e8685732f..196bfcaafb 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -154,11 +154,11 @@ typedef struct { uint8_t active; #endif /// indicator of UE type (0 = LTE, 1,2 = Cat-M) - int ue_type; + UE_type_t ue_type; /// HARQ process mask, indicates which processes are currently active uint16_t harq_mask; /// Indicator of TX activation per subframe. Used during PUCCH detection for ACK/NAK. - uint8_t subframe_tx[10]; + //uint8_t subframe_tx[10]; /// First CCE of last PDSCH scheduling per subframe. Again used during PUCCH detection for ACK/NAK. uint8_t nCCE[10]; /// Process ID's per subframe. Used to associate received ACKs on PUSCH/PUCCH to DLSCH harq process ids @@ -450,7 +450,7 @@ typedef struct { typedef struct { #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) /// UE type (normal, CEModeA, CEModeB) - uint8_t ue_type; + UE_type_t ue_type; #endif /// HARQ process mask, indicates which processes are currently active uint16_t harq_mask; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c4e162ec66..261e092737 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -410,8 +410,8 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, // clear previous allocation information for all UEs for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (eNB->dlsch[i][0]) - eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + //if (eNB->dlsch[i][0]) + //eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } /* TODO: check the following test - in the meantime it is put back as it was before */ @@ -548,7 +548,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, #endif ) { // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) - dlsch0->subframe_tx[subframe]=0; + //dlsch0->subframe_tx[subframe]=0; } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); From cd920b09eb54a4d6b9fb87541fa069c406631cb8 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 1 Aug 2019 10:18:16 +0000 Subject: [PATCH 017/175] test mail --- executables/main-fs6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 16a0cd305c..f54f0b9136 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -20,6 +20,7 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; + void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); From 5a7cbde584e03113561d4d244cf834615d5c31fc Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 1 Aug 2019 12:23:38 +0200 Subject: [PATCH 018/175] test mail --- executables/main-fs6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index f54f0b9136..16a0cd305c 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -20,7 +20,6 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; - void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); From 02c8b38b18bd568178507912a11e1d24a7340cd5 Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 2 Aug 2019 11:08:09 +0200 Subject: [PATCH 019/175] adding timestamp management --- executables/main-fs6.c | 112 +++++++++++++++++--------------- executables/split_headers.h | 2 + executables/transport_split.c | 5 ++ targets/RT/USER/lte-softmodem.c | 3 +- 4 files changed, 69 insertions(+), 53 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 16a0cd305c..c04290fef9 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -21,7 +21,6 @@ static UDPsock_t sockFS6; void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { - //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); if (is_prach_subframe(&eNB->frame_parms, frame,subframe)<=0) @@ -74,7 +73,6 @@ void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int } void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); uint16_t *max_preamble=header->max_preamble; uint16_t *max_preamble_energy=header->max_preamble_energy; @@ -438,16 +436,14 @@ void phy_procedures_eNB_uespec_RX_process(uint8_t *bufferZone, int nbBlocks, PHY } void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { - //commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; - fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); // TBD: read frame&subframe from received data - int frame=proc->frame_tx=header->frame; - int subframe=proc->subframe_tx=header->subframe; + int frame=proc->frame_tx=hDL(bufferZone)->frame; + int subframe=proc->subframe_tx=hDL(bufferZone)->subframe; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; //LTE_UL_eNB_HARQ_t *ulsch_harq; - eNB->pdcch_vars[subframe&1].num_pdcch_symbols=header->num_pdcch_symbols; - eNB->pdcch_vars[subframe&1].num_dci=header->num_dci; - uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = header->num_mdci; + eNB->pdcch_vars[subframe&1].num_pdcch_symbols=hDL(bufferZone)->num_pdcch_symbols; + eNB->pdcch_vars[subframe&1].num_dci=hDL(bufferZone)->num_dci; + uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = hDL(bufferZone)->num_mdci; // Remove all scheduled DL, we will populate from the CU sending for (int UE_id=0; UE_idcontentBytes >= sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) ) { + fs6_dl_uespec_t *dlPtr=(fs6_dl_uespec_t *)(commonUDPdata(bufPtr)+sizeof(fs6_dl_t)); #ifdef PHY_TX_THREAD - eNB->dlsch[dlPtr->UE_id][0]->active[subframe] = 1; + eNB->dlsch[dlPtr->UE_id][0]->active[subframe] = 1; #else - eNB->dlsch[dlPtr->UE_id][0]->active = 1; + eNB->dlsch[dlPtr->UE_id][0]->active = 1; #endif - eNB->dlsch[dlPtr->UE_id][0]->harq_ids[frame%2][subframe]=dlPtr->harq_pid; - eNB->dlsch[dlPtr->UE_id][0]->rnti=dlPtr->rnti; - memcpy(eNB->dlsch[dlPtr->UE_id][0]->harq_processes[dlPtr->harq_pid]->e, - commonUDPdata(((uint8_t *)dlPtr)+sizeof(fs6_dl_t)), dlPtr->dataLen); + eNB->dlsch[dlPtr->UE_id][0]->harq_ids[frame%2][subframe]=dlPtr->harq_pid; + eNB->dlsch[dlPtr->UE_id][0]->rnti=dlPtr->rnti; + memcpy(eNB->dlsch[dlPtr->UE_id][0]->harq_processes[dlPtr->harq_pid]->e, + commonUDPdata(((uint8_t *)dlPtr)+sizeof(fs6_dl_t)), dlPtr->dataLen); + } + bufPtr+=alignedSize(bufPtr); } @@ -505,17 +504,17 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e } if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - for (int i=0; i< header->num_dci; i++) - eNB->pdcch_vars[subframe&1].dci_alloc[i]=header->dci_alloc[i]; + for (int i=0; i< hDL(bufferZone)->num_dci; i++) + eNB->pdcch_vars[subframe&1].dci_alloc[i]=hDL(bufferZone)->dci_alloc[i]; - generate_dci_top(header->num_pdcch_symbols, - header->num_dci, + generate_dci_top(hDL(bufferZone)->num_pdcch_symbols, + hDL(bufferZone)->num_dci, &eNB->pdcch_vars[subframe&1].dci_alloc[0], 0, - header->amp, + hDL(bufferZone)->amp, fp, eNB->common_vars.txdataF, - header->subframe); + hDL(bufferZone)->subframe); if (num_mdci > 0) { LOG_D (PHY, "[eNB %" PRIu8 "] Frame %d, subframe %d: Calling generate_mdci_top (mpdcch) (num_dci %" PRIu8 ")\n", eNB->Mod_id, frame, subframe, num_mdci); @@ -543,7 +542,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e } } - eNB->phich_vars[subframe&1]=header->phich_vars; + eNB->phich_vars[subframe&1]=hDL(bufferZone)->phich_vars; generate_phich_top(eNB, proc, AMP); @@ -576,7 +575,6 @@ void appendFs6DLUE(uint8_t *bufferZone, int UE_id, int8_t harq_pid, uint16_t rnt } void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { - fs6_dl_t *header=(fs6_dl_t *) commonUDPdata(bufferZone); int frame=proc->frame_tx; int subframe=proc->subframe_tx; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; @@ -584,12 +582,12 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) return; - header->frame=frame; - header->subframe=subframe; + hDL(bufferZone)->frame=frame; + hDL(bufferZone)->subframe=subframe; // clear existing ulsch dci allocations before applying info from MAC (this is table // returns -1 (or 255) if there is no ul (tdd cases) - header->ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); - header->ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); + hDL(bufferZone)->ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); + hDL(bufferZone)->ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); // clear previous allocation information for all UEs for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { @@ -600,7 +598,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx /* TODO: check the following test - in the meantime it is put back as it was before */ //if ((ul_subframe < 10)&& // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here - if (header->ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + if (hDL(bufferZone)->ul_subframe < 10) { // This means that there is a potential UL subframe that will be schedulyed here for (int i=0; iUE_ul_active[i] = harq_pid = subframe2harq_pid(fp,header->ul_frame,header->ul_subframe); + hDL(bufferZone)->UE_ul_active[i] = harq_pid = subframe2harq_pid(fp, hDL(bufferZone)->ul_frame, + hDL(bufferZone)->ul_subframe); if (eNB->ulsch[i]) { //LTE_UL_eNB_HARQ_t *ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; @@ -636,9 +635,9 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx header->previous_n_DMRS = ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; */ - header->UE_ul_active[i] = harq_pid; + hDL(bufferZone)->UE_ul_active[i] = harq_pid; } else - header->UE_ul_active[i] = -1; + hDL(bufferZone)->UE_ul_active[i] = -1; } } @@ -648,10 +647,10 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - header->num_pdcch_symbols=num_pdcch_symbols; - header->num_dci=num_dci; - header->num_mdci=num_mdci; - header->amp=AMP; + hDL(bufferZone)->num_pdcch_symbols=num_pdcch_symbols; + hDL(bufferZone)->num_dci=num_dci; + hDL(bufferZone)->num_mdci=num_mdci; + hDL(bufferZone)->amp=AMP; } if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci); @@ -733,7 +732,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx } } - header->phich_vars=eNB->phich_vars[subframe&1]; + hDL(bufferZone)->phich_vars=eNB->phich_vars[subframe&1]; if (do_meas==1) stop_meas(&eNB->dlsch_ue_specific); @@ -743,10 +742,15 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx } void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { - //RU_proc_t *ru_proc=&ru->proc; + RU_proc_t *ru_proc=&ru->proc; + for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + L1_rxtx_proc_t *L1_proc = &ru->eNB_list[i]->proc.L1_proc_tx; + L1_proc->timestamp_tx=hUDP(bufferZone)->timestamp; + L1_proc->frame_tx=hDL(bufferZone)->frame; + L1_proc->subframe_tx=hDL(bufferZone)->subframe; if (nb_blocks>0) phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); @@ -754,12 +758,11 @@ void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { LOG_E(PHY,"DL not received for subframe: %d\n", subframe); } - /* Fixme: datamodel issue: a ru is supposed to be connected to several eNB - L1_rxtx_proc_t * L1_proc = &proc->L1_proc; - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; - */ + /* OAI data model is wrong: hardcode link ru to enb index 0*/ + L1_rxtx_proc_t *L1_proc = &ru->eNB_list[0]->proc.L1_proc_tx; + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; feptx_prec(ru); feptx_ofdm(ru); tx_rf(ru); @@ -787,6 +790,9 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } initBufferZone(bufferZone); + hDL(bufferZone)->frame=frame; + hDL(bufferZone)->subframe=subframe; + hUDP(bufferZone)->timestamp=ru->proc.timestamp_rx; prach_eNB_extract(bufferZone, FS6_BUF_SIZE, eNB, proc->frame_rx,proc->subframe_rx ); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -811,12 +817,14 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { pthread_mutex_unlock(&eNB->UL_INFO_mutex); initBufferZone(bufferZone); phy_procedures_eNB_TX_extract(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); - commonUDP_t *firstHeader=(commonUDP_t *) bufferZone; + hUDP(bufferZone)->timestamp=proc->L1_proc.timestamp_tx; + hDL(bufferZone)->frame=frame; + hDL(bufferZone)->subframe=subframe; - if (firstHeader->nbBlocks==0) { - firstHeader->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE) - firstHeader->blockID=0; - firstHeader->contentBytes=sizeof(fs6_dl_t); + if (hUDP(bufferZone)->nbBlocks==0) { + hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE) + hUDP(bufferZone)->blockID=0; + hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t); } sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t) ); @@ -824,7 +832,6 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { initBufferZone(bufferZone); - commonUDP_t *UDPheader=(commonUDP_t *) bufferZone; int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); if (nb_blocks ==0) { @@ -832,12 +839,13 @@ void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { return; } - if (nb_blocks != UDPheader->nbBlocks ) - LOG_W(PHY, "received %d blocks for %d expected\n", nb_blocks, UDPheader->nbBlocks); + if (nb_blocks != hUDP(bufferZone)->nbBlocks ) + LOG_W(PHY, "received %d blocks for %d expected\n", nb_blocks, hUDP(bufferZone)->nbBlocks); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; + proc->timestamp_rx=hUDP(bufferZone)->timestamp; prach_eNB_process(bufferZone, sizeof(bufferZone), eNB,NULL,proc->frame_rx,proc->subframe_rx); release_UE_in_freeList(eNB->Mod_id); diff --git a/executables/split_headers.h b/executables/split_headers.h index 35e2e78d3a..0b9104fc20 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -74,6 +74,8 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize); uint8_t xBuf[FS6_BUF_SIZE];\ ((commonUDP_t *)xBuf)->nbBlocks=0; +#define hUDP(xBuf) ((commonUDP_t *)xBuf) +#define hDL(xBuf) (((fs6_dl_t*)((commonUDP_t *)xBuf)+1)) inline size_t alignedSize(uint8_t *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; diff --git a/executables/transport_split.c b/executables/transport_split.c index 8a43a63833..6b13036d11 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -104,6 +104,11 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize) { int nbBlocks=UDPheader->nbBlocks; int blockId=0; + if (nbBlocks <= 0 ) { + LOG_E(PHY,"FS6: can't send blocks: %d\n", nbBlocks); + return 0; + } + do { if (blockId > 0 ) { commonUDP_t *currentHeader=(commonUDP_t *)bufferZone; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index dc429f0288..109c0afdd4 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -593,7 +593,8 @@ int main( int argc, char **argv ) { /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks * for monolithic/F1 modes */ - init_pdcp(); + if ( getenv("fs6") == NULL || strncasecmp( getenv("fs6"), "du", 2) != 0 ) + init_pdcp(); if (create_tasks(1) < 0) { printf("cannot create ITTI tasks\n"); From 9b8e103329c0b86876646ee47953dd25b5db4f6b Mon Sep 17 00:00:00 2001 From: ferrieux Date: Fri, 2 Aug 2019 21:49:09 +0200 Subject: [PATCH 020/175] test mail --- executables/main-fs6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index c04290fef9..e68327084a 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -18,6 +18,7 @@ #include #define FS6_BUF_SIZE 100*1000 + static UDPsock_t sockFS6; void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { From 0d582559053c33f4333e71d6865d1c0ea26ec710 Mon Sep 17 00:00:00 2001 From: laurent Date: Sat, 3 Aug 2019 11:51:11 +0200 Subject: [PATCH 021/175] test --- executables/main-ocp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 3fc3b00e89..3e9e7bdf64 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -14,6 +14,7 @@ #include #include + static int DEFBANDS[] = {7}; static int DEFENBS[] = {0}; #include From ebb52e388bc6f2342f54b4311c83bd8242ef3099 Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sat, 3 Aug 2019 15:50:50 +0200 Subject: [PATCH 022/175] test mail, qui marche \! --- executables/main-fs6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index e68327084a..c04290fef9 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -18,7 +18,6 @@ #include #define FS6_BUF_SIZE 100*1000 - static UDPsock_t sockFS6; void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { From 88d5739040ce656858f710a71e04e0d41d569b58 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 5 Aug 2019 21:19:27 +0200 Subject: [PATCH 023/175] continue timestamp --- SystemX-tutorial-design.md | 264 ++++++++++++++++++++++++ cmake_targets/CMakeLists.txt | 4 +- executables/main-fs6.c | 41 ++-- executables/main-ocp.c | 14 +- executables/split_headers.h | 11 +- executables/transport_split.c | 34 ++- openair1/SCHED/phy_procedures_lte_eNb.c | 4 +- 7 files changed, 325 insertions(+), 47 deletions(-) create mode 100644 SystemX-tutorial-design.md diff --git a/SystemX-tutorial-design.md b/SystemX-tutorial-design.md new file mode 100644 index 0000000000..6371c81050 --- /dev/null +++ b/SystemX-tutorial-design.md @@ -0,0 +1,264 @@ +# OpenAirInterface for SystemX + +#Terminology + +****This document use the 5G terminology**** + +**Central Unit (CU): **It is a logical node that includes the gNB +functions like Transfer of user data, Mobility control, Radio access +network sharing, Positioning, Session Management etc., except those +functions allocated exclusively to the DU. CU controls the operation of +DUs over front-haul (Fs) interface. A central unit (CU) may also be +known as BBU/REC/RCC/C-RAN/V-RAN/VNF + +**Distributed Unit (DU):** This logical node includes a subset of the +gNB functions, depending on the functional split option. Its operation +is controlled by the CU. Distributed Unit (DU) also known with other +names like RRH/RRU/RE/RU/PNF. + +In OpenAir code, the terminology is often RU and BBU. + +#Usage +##EPC and general environment +### OAI EPC + +Use the stable OAI EPC, that can run in one machine (VM or standalone) + +Draft description: + + +##Standalone 4G + +EPC+eNB on one machine, the UE can be commercial or OAI UE. +### USRP B210 + +Main current issue: traffic is good only on coaxial link between UE and +eNB (probably power management issue). + +### Simulated RF + +Running eNB+UE both OAI can be done over a virtual RF link. + +The UE current status is that threads synchronization is implicit in +some cases. As the RF simulator is very quick, a “sleep()” is required +in the UE main loop + +(line 1744, targets/RT/USER/lte-ue.c). + +Running also the UE in the same machine is possible with simulated RF. + +Running in same machine is simpler, offers about infinite speed for +virtual RF samples transmission. + +A specific configuration is required because the EPC Sgi interface has +the same IP tunnel end point as the UE. + +So, we have to create a network namespace for the UE and to route data +in/out of the namespace. +``` bash +ip netns delete aNameSpace 2> /dev/null + +ip link delete v-eth1 2> /dev/null + +ip netns add aNameSpace + +ip link add v-eth1 type veth peer name v-peer1 + +ip link set v-peer1 netns aNameSpace + +ip addr add 10.200.1.1/24 dev v-eth1 + +ip link set v-eth1 up + +iptables -t nat -A POSTROUTING -s 10.200.1.0/255.255.255.0 -o enp0s31f6 +-j MASQUERADE + +iptables -A FORWARD -i enp0s31f6 -o v-eth1 -j ACCEPT + +iptables -A FORWARD -o enp0s31f6 -i v-eth1 -j ACCEPT + +ip netns exec aNameSpace ip link set dev lo up + +ip netns exec aNameSpace ip addr add 10.200.1.2/24 dev v-peer1 + +ip netns exec aNameSpace ip link set v-peer1 up + +ip netns exec aNameSpace bash +``` + +After the last command, the Linux shell is in the new namespace, ready +to run the UE. + +To make user plan traffic, the traffic generator has to run in the same +namespace + +`ip netns exec aNameSpace bash +` + +The traffic genenrator has to specify the interface: + +`route add default oaitun_ue1 +` + +or specify the outgoing route in the traffic generator (like option “-I” +in ping command). + +## Split 6 DL 4G + +The contract describes to reuse the uplink existing if4p5 and to develop +is this work the downlink “functional split 6”. + +The customer required after signature to develop also the uplink +functional split 6. This is accepted, as long as the whole work is +research with no delivery completeness warranty. +### Simulation + +To be able to verify the new features and to help in all future +developments, Open Cells added and improved the Rf board simulator +during this contract. + +We added the channel modeling simulation, that offer to simulate various +3GPP defined channels. +### Main loop + +The main log is in RF simulator is in + + targets/RT/USER/lte-ru.c and targets/RT/USER/lte-enb.c + +As this piece of SW is very complex and doesn’t meet our goals +(functional split 6), a cleaned version replaces these 2 files in +executables/ocp-main.c (openair1/SCHED/prach\_procedures.c is also +replaced by this new file as it only launching the RACH actual work in a +way not compatible with our FS6). + +The main loop cadences the I/Q samples reception, signal processing and +I/Q samples sending. + +The main loop uses extensively function pointers to call the right +processing function depending on the split case. + +This is enough for RF board dialog, but the FS6 is higher in SW layers, +we need to cut higher functions inside downlink and uplink procedures. + +### DownLink + +The main procedure is phy\_procedures\_eNB\_TX + +This is building the common channels (beacon, multi-UE signaling). + +The FS6 split breaks this function into pieces: + +- The multi-UE signals, built by common\_signal\_procedures(), + subframe2harq\_pid(), generate\_dci\_top(), subframe2harq\_pid() + + - These functions will be executed in the DU, nevertheless all + context has to be sent (it is also needed partially for + UL spitting) + - IT should be in the DU also to meet the requirement of pushing + in DU the data encoded with large redundancy (>3 redundancy) +- the per UE data: pdsch\_procedures() that needs further splitting: + + - dlsch\_encoding\_all() that makes the encoding: turbo code + and lte\_rate\_matching\_turbo() that will be in the DU (some + unlikely cases can reach redundancy up to x3, when MCS is very + low (negative SINR cases)). + + - dlsch\_encoding() output needs to be transmitted between the + DU and the CU for functional split 6. + - dlsch\_scrambling() that will go in the DU + - dlsch\_modulation() that will go in the DU + +### Uplink + +The uplink require configuration that is part of the DL transmission. + +It interprets the signalling to extract the RACH and the per UE data +channels. + +Ocp-main.c:rxtx() calls directly the entry procedure +phy\_procedures\_eNB\_uespec\_RX() calls: + +- rx\_ulsch() that demodulate and extract soft bits per UE. + + - This function runs in the DU + - the output data will be processes in the DU, so it needs to be + transmitted to the DU +- ulsch\_decoding() that do lte\_rate\_matching\_turbo\_rx() + sub\_block\_deinterleaving\_turbo() then turbo decode + + - it runs +- fill\_ulsch\_cqi\_indication() + + - TBD: either runs in DU or output needs to be transmitted to DU +- fill\_crc\_indication() , fill\_rx\_indication() results need also + to be transmitted or made in the DU + +### UDP transport layer + +A general UDP transport layer is in executables/transport\_split.c + +Linux offers a UDP socket builtin timeout, that we use. + +In and out buffers are memory zones that contains compacted +(concatenated) UDP chunks. + +For output, sendSubFrame() sends each UDP chunk + +For input, receiveSubFrame() collects all UDP chunks for a group (a +subframe in OAI LTE case). It returns in the following cases: + +- all chunks are received +- a timeout expired +- a chunk from the next subframe already arrived + +### Functional split 6 usage + +The ocp cleaned main hale to be used: run ocp-softmodem instead of +lte-softmodem. + +The functionality and parameters is the same, enhanced with FS6 mode. + +The environment variable “fs6” enables the fs6 mode and decided to be cu +or du from the fs6 variable content. + +Example: + +`fs6=cu ./ocp-softmodem -O … (regular lte-softmodem paramters) +` + +Run the CU init of the split 6 eNB. + +CU and DU IP address and port are configurable in the eNB configuration +file (as X2, GTP, … interfaces). + +##5G and F1 + +Today 5G achievement is limited to physical layer. + +The available modulation is 40MHz, that require one X310 or N300 for the +gNB and a X310 or N300 for the nrUE. + +### Usage with X310 + +Linux configuration: + + +We included most of this configuration included in OAI source code. + +Remain to set the NIC (network interface card) MTU to 9000 (jumbo +frames). + +### Running 5G + +Usage with RFsimulator: + +gNB + +`sudo RFSIMULATOR=server ./nr-softmodem -O +../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf +--parallel-config PARALLEL\_SINGLE\_THREAD` + +nrUE + +`sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C +3510000000 -d` diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 62b592673f..76be8cf250 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -183,8 +183,8 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${CMAKE_CU ######################### # set a flag for changes in the source code # these changes are related to hardcoded path to include .h files -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3 -O2") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -O0") set(GIT_BRANCH "UNKNOWN") diff --git a/executables/main-fs6.c b/executables/main-fs6.c index c04290fef9..4e4d7dd54d 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -653,6 +653,8 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx hDL(bufferZone)->amp=AMP; } + if (num_mdci) abort(); + if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci); if (do_meas==1) start_meas(&eNB->dlsch_ue_specific); @@ -741,21 +743,21 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx return; } -void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) { +void DL_du_fs6(RU_t *ru) { RU_proc_t *ru_proc=&ru->proc; for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); - int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); - L1_rxtx_proc_t *L1_proc = &ru->eNB_list[i]->proc.L1_proc_tx; - L1_proc->timestamp_tx=hUDP(bufferZone)->timestamp; - L1_proc->frame_tx=hDL(bufferZone)->frame; - L1_proc->subframe_tx=hDL(bufferZone)->subframe; + int nb_blocks=receiveSubFrame(&sockFS6, ru_proc->timestamp_tx, bufferZone, sizeof(bufferZone), CTsentCUv0 ); - if (nb_blocks>0) + if (nb_blocks > 0) { + L1_rxtx_proc_t *L1_proc = &ru->eNB_list[i]->proc.L1_proc_tx; + L1_proc->timestamp_tx=hUDP(bufferZone)->timestamp; + L1_proc->frame_tx=hDL(bufferZone)->frame; + L1_proc->subframe_tx=hDL(bufferZone)->subframe; phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); - else - LOG_E(PHY,"DL not received for subframe: %d\n", subframe); + } else + LOG_E(PHY,"DL not received for subframe\n"); } /* OAI data model is wrong: hardcode link ru to enb index 0*/ @@ -799,8 +801,14 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { phy_procedures_eNB_uespec_RX_extract(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc ); } + if (hUDP(bufferZone)->nbBlocks==0) { + hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE) + hUDP(bufferZone)->blockID=0; + hUDP(bufferZone)->contentBytes=sizeof(fs6_ul_t); + } + for (int i=0; inum_eNB; i++) { - sendSubFrame(&sockFS6,bufferZone, sizeof(fs6_ul_t)); + sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_ul_t), CTsentDUv0); } } @@ -827,12 +835,12 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t); } - sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t) ); + sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); } void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { initBufferZone(bufferZone); - int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) ); + int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone), CTsentDUv0 ); if (nb_blocks ==0) { LOG_W(PHY, "CU lost a subframe\n"); @@ -878,7 +886,6 @@ void *cu_fs6(void *arg) { void *du_fs6(void *arg) { RU_t *ru = (RU_t *)arg; //RU_proc_t *proc = &ru->proc; - int64_t AbsoluteSubframe=-1; fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); @@ -887,11 +894,9 @@ void *du_fs6(void *arg) { AssertFatal(createUDPsock(NULL, "7777", "127.0.0.1", "8888", &sockFS6),""); while(1) { - AbsoluteSubframe++; - int subframe=AbsoluteSubframe%10; - int frame=(AbsoluteSubframe/10)%1024; - UL_du_fs6(ru, frame,subframe); - DL_du_fs6(ru, frame,subframe, AbsoluteSubframe); + L1_rxtx_proc_t *proc = &ru->eNB_list[0]->proc; + UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); + DL_du_fs6(ru); } return NULL; diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 3e9e7bdf64..92546eb018 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -582,13 +582,11 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name return(0); } -void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { +void eNB_top(PHY_VARS_eNB *eNB, int dummy1, int dummy2, char *string,RU_t *ru) { L1_proc_t *proc = &eNB->proc; L1_rxtx_proc_t *L1_proc = &proc->L1_proc; LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; RU_proc_t *ru_proc=&ru->proc; - proc->frame_rx = frame_rx; - proc->subframe_rx = subframe_rx; if (!oai_exit) { L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); @@ -650,16 +648,6 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; - if (proc->first_rx == 0) { - AssertFatal( proc->subframe_rx == *subframe && proc->frame_rx == *frame, - "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d) (proc->frame_rx %d frame %d)\n", - (long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe, proc->frame_rx,*frame); - } else { - proc->first_rx = 0; - *frame = proc->frame_rx; - *subframe = proc->subframe_rx; - } - if (rxs != fp->samples_per_tti) { #if defined(USRP_REC_PLAY) exit_fun("Exiting IQ record/playback"); diff --git a/executables/split_headers.h b/executables/split_headers.h index 0b9104fc20..9674541628 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -18,6 +18,9 @@ typedef struct { int sockHandler; } UDPsock_t; +#define CTsentCUv0 0xA500 +#define CTsentDUv0 0x5A00 + typedef struct commonUDP_s { uint64_t timestamp; // id of the group (subframe for LTE) uint16_t nbBlocks; // total number of blocks for this timestamp @@ -67,8 +70,8 @@ typedef struct { } fs6_dl_uespec_t; bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); -int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize); -int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize); +int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize, uint16_t contentType); +int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType); #define initBufferZone(xBuf) \ uint8_t xBuf[FS6_BUF_SIZE];\ @@ -77,12 +80,12 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize); #define hUDP(xBuf) ((commonUDP_t *)xBuf) #define hDL(xBuf) (((fs6_dl_t*)((commonUDP_t *)xBuf)+1)) -inline size_t alignedSize(uint8_t *ptr) { +static inline size_t alignedSize(uint8_t *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign; } -inline void *commonUDPdata(uint8_t *ptr) { +static inline void *commonUDPdata(uint8_t *ptr) { return (void *) (((commonUDP_t *)ptr)+1); } diff --git a/executables/transport_split.c b/executables/transport_split.c index 6b13036d11..490f1259a3 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -56,7 +56,8 @@ bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPo int enable=1; AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); - struct timeval tv= {0,UDP_TIMEOUT}; + //struct timeval tv= {0,UDP_TIMEOUT}; + struct timeval tv= {2,UDP_TIMEOUT}; //debug: wait 2 seconds for human understanding AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); // Make a send/recv buffer larger than a a couple of subframe // so the kernel will store for us in and out paquets @@ -69,9 +70,9 @@ bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPo // sock: udp socket // expectedTS: the expected timestamp, 0 if unknown // bufferZone: a reception area of bufferSize -int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize) { +int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize, uint16_t contentType) { int rcved=0; - commonUDP_t *tmp=NULL; + commonUDP_t *bufOrigin=(commonUDP_t *)bufferZone; do { //read all subframe data from the control unit @@ -85,22 +86,37 @@ int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int return -1; } } else { - tmp=(commonUDP_t *)bufferZone; + if (hUDP(bufferZone)->contentType != contentType) + abort(); - if ( expectedTS && tmp->timestamp != expectedTS) { - LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n"); + if ( hUDP(bufferZone)->timestamp != expectedTS) { + if ( hUDP(bufferZone)->timestamp < expectedTS) { + LOG_W(HW,"Received a paquet from past subframes, dropping it\n"); + } else { + LOG_W(HW,"Received a paquet in future subframes\n"); + + if ( rcved == 0 ) { + LOG_W(HW,"First paquet in the sub-frame, keeping it\n"); + rcved++; + bufferZone+=ret; + expectedTS=hUDP(bufferZone)->timestamp; + } + } } else { rcved++; bufferZone+=ret; } } - } while ( !rcved || rcved < tmp->nbBlocks ); + } while ( !rcved || rcved < hUDP(bufferZone)->nbBlocks ); + LOG_D(HW,"Received: nb_blocks: %d, TS: %lu, frame: %d, subframe: %d\n", + rcved, bufOrigin->timestamp, *(((int *)bufOrigin)+1), *(((int *)bufOrigin)+2)); return rcved; } -int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize) { +int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType) { commonUDP_t *UDPheader=(commonUDP_t *)bufferZone ; + UDPheader->contentType=contentType; int nbBlocks=UDPheader->nbBlocks; int blockId=0; @@ -131,5 +147,7 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize) { nbBlocks--; } while (nbBlocks); + LOG_D(HW,"Sent: TS: %lu, frame: %d, subframe: %d\n", + UDPheader->timestamp, *(((int *)UDPheader)+1), *(((int *)UDPheader)+2)); return 0; } diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 261e092737..17d3001205 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -409,10 +409,10 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); // clear previous allocation information for all UEs - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + //for (i = 0; i < NUMBER_OF_UE_MAX; i++) { //if (eNB->dlsch[i][0]) //eNB->dlsch[i][0]->subframe_tx[subframe] = 0; - } + //} /* TODO: check the following test - in the meantime it is put back as it was before */ //if ((ul_subframe < 10)&& From 32e19dbbb756ea7cbdc0b0e44fb1d65a64301f0b Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 9 Aug 2019 08:10:36 +0200 Subject: [PATCH 024/175] removed all frame/subframe copies distributed update, replace by a single function --- executables/main-fs6.c | 163 +++++++++++++++--------- executables/main-ocp.c | 6 +- executables/split_headers.h | 22 ++-- executables/transport_split.c | 50 +++++--- openair1/PHY/LTE_TRANSPORT/pbch.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- 6 files changed, 150 insertions(+), 95 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 4e4d7dd54d..ace3f7fd1d 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -20,6 +20,48 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; +// Fixme: there are many mistakes in the datamodel and in redondant variables +// TDD is also mode complex +void setAllfromTS(uint64_t TS) { + for (int i=0; i frame_parms; + uint64_t TStx=TS+sf_ahead*fp->samples_per_tti; + RU_proc_t *proc =&RC.ru[i]->proc; + proc->timestamp_rx= TS; + proc->timestamp_tx= TStx; + proc->subframe_rx= (TS / fp->samples_per_tti)%10; + proc->subframe_tx= (TStx / fp->samples_per_tti)%10; + proc->subframe_prach=(TS / fp->samples_per_tti)%10; + proc->subframe_prach_br=(TS / fp->samples_per_tti)%10; + proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; + proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + } + + for (int i=0; i < RC.nb_inst; i++) { + for (int j=0; jframe_parms; + uint64_t TStx=TS+sf_ahead*fp->samples_per_tti; + L1_proc_t *proc =&RC.eNB[i][j]->proc; + L1_rxtx_proc_t *proc1=&RC.eNB[i][j]->proc.L1_proc; + proc->timestamp_rx= TS; + proc->timestamp_tx= TStx; + proc->subframe_rx= (TS / fp->samples_per_tti)%10; + proc->subframe_prach=(TS / fp->samples_per_tti)%10; + proc->subframe_prach_br=(TS / fp->samples_per_tti)%10; + proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; + proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + proc1->timestamp_tx= TStx; + proc1->subframe_rx= (TS / fp->samples_per_tti)%10; + proc1->subframe_tx= (TStx / fp->samples_per_tti)%10; + proc1->frame_rx= (TS / (fp->samples_per_tti*10))&1023; + proc1->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + } + } + + return; +} + + void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); @@ -436,10 +478,9 @@ void phy_procedures_eNB_uespec_RX_process(uint8_t *bufferZone, int nbBlocks, PHY } void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { - // TBD: read frame&subframe from received data - int frame=proc->frame_tx=hDL(bufferZone)->frame; - int subframe=proc->subframe_tx=hDL(bufferZone)->subframe; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int subframe=proc->subframe_tx; + int frame=proc->frame_tx; //LTE_UL_eNB_HARQ_t *ulsch_harq; eNB->pdcch_vars[subframe&1].num_pdcch_symbols=hDL(bufferZone)->num_pdcch_symbols; eNB->pdcch_vars[subframe&1].num_dci=hDL(bufferZone)->num_dci; @@ -462,16 +503,16 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks if ( ((commonUDP_t *)bufPtr)->contentBytes >= sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) ) { - fs6_dl_uespec_t *dlPtr=(fs6_dl_uespec_t *)(commonUDPdata(bufPtr)+sizeof(fs6_dl_t)); + int curUE=hDLUE(bufPtr)->UE_id; #ifdef PHY_TX_THREAD - eNB->dlsch[dlPtr->UE_id][0]->active[subframe] = 1; + eNB->dlsch[curUE][0]->active[subframe] = 1; #else - eNB->dlsch[dlPtr->UE_id][0]->active = 1; + eNB->dlsch[curUE][0]->active = 1; #endif - eNB->dlsch[dlPtr->UE_id][0]->harq_ids[frame%2][subframe]=dlPtr->harq_pid; - eNB->dlsch[dlPtr->UE_id][0]->rnti=dlPtr->rnti; - memcpy(eNB->dlsch[dlPtr->UE_id][0]->harq_processes[dlPtr->harq_pid]->e, - commonUDPdata(((uint8_t *)dlPtr)+sizeof(fs6_dl_t)), dlPtr->dataLen); + eNB->dlsch[curUE][0]->harq_ids[frame%2][subframe]=hDLUE(bufPtr)->harq_pid; + eNB->dlsch[curUE][0]->rnti=hDLUE(bufPtr)->rnti; + memcpy(eNB->dlsch[curUE][0]->harq_processes[hDLUE(bufPtr)->harq_pid]->e, + hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); } bufPtr+=alignedSize(bufPtr); @@ -514,7 +555,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e hDL(bufferZone)->amp, fp, eNB->common_vars.txdataF, - hDL(bufferZone)->subframe); + subframe); if (num_mdci > 0) { LOG_D (PHY, "[eNB %" PRIu8 "] Frame %d, subframe %d: Calling generate_mdci_top (mpdcch) (num_dci %" PRIu8 ")\n", eNB->Mod_id, frame, subframe, num_mdci); @@ -567,11 +608,11 @@ void appendFs6DLUE(uint8_t *bufferZone, int UE_id, int8_t harq_pid, uint16_t rnt newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) + UEdataLen; // We skip the fs6 DL header, that is populated by caller // This header will be duplicated during sending - fs6_dl_uespec_t *tmp=(fs6_dl_uespec_t *) firstFreeByte+sizeof(fs6_dl_t); - tmp->UE_id=UE_id; - tmp->harq_pid=harq_pid; - tmp->rnti=rnti; - memcpy(commonUDPdata(((uint8_t *)tmp)+sizeof(fs6_dl_uespec_t)), UEdata, UEdataLen); + hDLUE(newUDPheader)->UE_id=UE_id; + hDLUE(newUDPheader)->harq_pid=harq_pid; + hDLUE(newUDPheader)->rnti=rnti; + hDLUE(newUDPheader)->dataLen=UEdataLen; + memcpy(hDLUE(newUDPheader)+1, UEdata, UEdataLen); } void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { @@ -579,15 +620,15 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx int subframe=proc->subframe_tx; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) + if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) { + LOG_W(HW,"no sending in eNB_TX\n"); return; + } - hDL(bufferZone)->frame=frame; - hDL(bufferZone)->subframe=subframe; // clear existing ulsch dci allocations before applying info from MAC (this is table // returns -1 (or 255) if there is no ul (tdd cases) - hDL(bufferZone)->ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); - hDL(bufferZone)->ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); + int ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); + int ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); // clear previous allocation information for all UEs for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { @@ -598,7 +639,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx /* TODO: check the following test - in the meantime it is put back as it was before */ //if ((ul_subframe < 10)&& // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here - if (hDL(bufferZone)->ul_subframe < 10) { // This means that there is a potential UL subframe that will be schedulyed here + if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be schedulyed here for (int i=0; iUE_ul_active[i] = harq_pid = subframe2harq_pid(fp, hDL(bufferZone)->ul_frame, - hDL(bufferZone)->ul_subframe); + hDL(bufferZone)->UE_ul_active[i] = harq_pid = subframe2harq_pid(fp, ul_frame, ul_subframe); if (eNB->ulsch[i]) { //LTE_UL_eNB_HARQ_t *ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; @@ -653,8 +693,6 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx hDL(bufferZone)->amp=AMP; } - if (num_mdci) abort(); - if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci); if (do_meas==1) start_meas(&eNB->dlsch_ue_specific); @@ -740,6 +778,9 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx if (do_meas==1) stop_meas(&eNB->phy_proc_tx); + // MBMS is not working in OAI + if (hDL(bufferZone)->num_mdci) abort(); + return; } @@ -748,23 +789,24 @@ void DL_du_fs6(RU_t *ru) { for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); - int nb_blocks=receiveSubFrame(&sockFS6, ru_proc->timestamp_tx, bufferZone, sizeof(bufferZone), CTsentCUv0 ); + int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); if (nb_blocks > 0) { - L1_rxtx_proc_t *L1_proc = &ru->eNB_list[i]->proc.L1_proc_tx; - L1_proc->timestamp_tx=hUDP(bufferZone)->timestamp; - L1_proc->frame_tx=hDL(bufferZone)->frame; - L1_proc->subframe_tx=hDL(bufferZone)->subframe; + L1_proc_t *L1_proc = &ru->eNB_list[i]->proc; + + if ( L1_proc->timestamp_tx != hUDP(bufferZone)->timestamp) { + LOG_E(HW,"Missed a subframe: expecting: %lu, received %lu\n", + L1_proc->timestamp_tx, + hUDP(bufferZone)->timestamp); + } + + setAllfromTS(hUDP(bufferZone)->timestamp - + sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti); phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); } else LOG_E(PHY,"DL not received for subframe\n"); } - /* OAI data model is wrong: hardcode link ru to enb index 0*/ - L1_rxtx_proc_t *L1_proc = &ru->eNB_list[0]->proc.L1_proc_tx; - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; feptx_prec(ru); feptx_ofdm(ru); tx_rf(ru); @@ -776,13 +818,10 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { rx_rf(ru,&tmpf,&tmpsf); AssertFatal(tmpf==frame && tmpsf==subframe, "lost synchronization\n"); ru_proc->frame_tx = (ru_proc->frame_tx+ru_proc->frame_offset)&1023; + setAllfromTS(ru_proc->timestamp_rx); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; - //L1_rxtx_proc_t *L1_proc = &proc->L1_proc; - //LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - proc->frame_rx = frame; - proc->subframe_rx = subframe; if (NFAPI_MODE==NFAPI_MODE_PNF) { // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick @@ -792,8 +831,6 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } initBufferZone(bufferZone); - hDL(bufferZone)->frame=frame; - hDL(bufferZone)->subframe=subframe; hUDP(bufferZone)->timestamp=ru->proc.timestamp_rx; prach_eNB_extract(bufferZone, FS6_BUF_SIZE, eNB, proc->frame_rx,proc->subframe_rx ); @@ -812,7 +849,7 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } } -void DL_cu_fs6(RU_t *ru,int frame, int subframe) { +void DL_cu_fs6(RU_t *ru, uint64_t TS) { // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; @@ -826,8 +863,6 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { initBufferZone(bufferZone); phy_procedures_eNB_TX_extract(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); hUDP(bufferZone)->timestamp=proc->L1_proc.timestamp_tx; - hDL(bufferZone)->frame=frame; - hDL(bufferZone)->subframe=subframe; if (hUDP(bufferZone)->nbBlocks==0) { hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE) @@ -838,9 +873,9 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) { sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); } -void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { +void UL_cu_fs6(RU_t *ru, uint64_t *TS) { initBufferZone(bufferZone); - int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone), CTsentDUv0 ); + int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentDUv0 ); if (nb_blocks ==0) { LOG_W(PHY, "CU lost a subframe\n"); @@ -850,34 +885,34 @@ void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) { if (nb_blocks != hUDP(bufferZone)->nbBlocks ) LOG_W(PHY, "received %d blocks for %d expected\n", nb_blocks, hUDP(bufferZone)->nbBlocks); - // Fixme: datamodel issue + if ( *TS != hUDP(bufferZone)->timestamp ) { + LOG_W(HW, "CU received time: %lu instead of %lu expected\n", hUDP(bufferZone)->timestamp, *TS); + *TS=hUDP(bufferZone)->timestamp; + } + + setAllfromTS(hUDP(bufferZone)->timestamp); PHY_VARS_eNB *eNB = RC.eNB[0][0]; - L1_proc_t *proc = &eNB->proc; - proc->timestamp_rx=hUDP(bufferZone)->timestamp; - prach_eNB_process(bufferZone, sizeof(bufferZone), eNB,NULL,proc->frame_rx,proc->subframe_rx); release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_process(bufferZone, sizeof(bufferZone), eNB, &proc->L1_proc); + phy_procedures_eNB_uespec_RX_process(bufferZone, sizeof(bufferZone), eNB, &eNB->proc.L1_proc); } } void *cu_fs6(void *arg) { RU_t *ru = (RU_t *)arg; //RU_proc_t *proc = &ru->proc; - int64_t AbsoluteSubframe=-1; fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); wait_sync("ru_thread"); - AssertFatal(createUDPsock(NULL, "8888", "127.0.0.1", "7777", &sockFS6), ""); + AssertFatal(createUDPsock(NULL, CU_PORT, CU_IP, DU_PORT, &sockFS6), ""); + uint64_t timeStamp=0; while(1) { - AbsoluteSubframe++; - int subframe=AbsoluteSubframe%10; - int frame=(AbsoluteSubframe/10)%1024; - UL_cu_fs6(ru, frame,subframe, AbsoluteSubframe); - DL_cu_fs6(ru, frame,subframe); + timeStamp+=ru->frame_parms.samples_per_tti; + UL_cu_fs6(ru, &timeStamp); + DL_cu_fs6(ru, timeStamp); } return NULL; @@ -891,10 +926,16 @@ void *du_fs6(void *arg) { phy_init_RU(ru); openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); wait_sync("ru_thread"); - AssertFatal(createUDPsock(NULL, "7777", "127.0.0.1", "8888", &sockFS6),""); + AssertFatal(createUDPsock(NULL, DU_PORT, DU_IP, CU_PORT, &sockFS6),""); + + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + LOG_E(HW,"Could not start the RF device\n"); + else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); + } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); while(1) { - L1_rxtx_proc_t *proc = &ru->eNB_list[0]->proc; + L1_proc_t *proc = &ru->eNB_list[0]->proc; UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); DL_du_fs6(ru); } diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 92546eb018..3f6d057d82 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -632,10 +632,12 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { } if (proc->first_rx == 1) { - ru->ts_offset = proc->timestamp_rx; - proc->timestamp_rx = 0; + //ru->ts_offset = proc->timestamp_rx; + //proc->timestamp_rx = 0; + proc->first_rx = false; } else { if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { + LOG_E(HW,"impossible shift in RFSIM\n"); ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); proc->timestamp_rx = ts-ru->ts_offset; } diff --git a/executables/split_headers.h b/executables/split_headers.h index 9674541628..59909e524e 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -4,11 +4,18 @@ #include #include #include + +#define CU_IP "127.0.0.1" +#define CU_PORT "7878" +#define DU_IP "127.0.0.1" +#define DU_PORT "8787" + #define MTU 65536 #define UDP_TIMEOUT 100000L // in nano second #define MAX_BLOCKS 16 #define blockAlign 32 //bytes + typedef struct { char *sourceIP; char *sourcePort; @@ -38,8 +45,6 @@ typedef struct frequency_s { } frequency_t; typedef struct { - int frame; - int subframe; uint16_t max_preamble[4]; uint16_t max_preamble_energy[4]; uint16_t max_preamble_delay[4]; @@ -47,10 +52,6 @@ typedef struct { } fs6_ul_t; typedef struct { - int frame; - int subframe; - int ul_frame; - int ul_subframe; int num_pdcch_symbols; int num_dci; DCI_ALLOC_t dci_alloc[32]; @@ -70,15 +71,17 @@ typedef struct { } fs6_dl_uespec_t; bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); -int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize, uint16_t contentType); +int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t contentType); int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType); #define initBufferZone(xBuf) \ - uint8_t xBuf[FS6_BUF_SIZE];\ + uint8_t xBuf[FS6_BUF_SIZE]; \ ((commonUDP_t *)xBuf)->nbBlocks=0; #define hUDP(xBuf) ((commonUDP_t *)xBuf) -#define hDL(xBuf) (((fs6_dl_t*)((commonUDP_t *)xBuf)+1)) +#define hDL(xBuf) ((fs6_dl_t*)(((commonUDP_t *)xBuf)+1)) +#define hUL(xBuf) ((fs6_ul_t*)(((commonUDP_t *)xBuf)+1)) +#define hDLUE(xBuf) ((fs6_dl_uespec_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1)) static inline size_t alignedSize(uint8_t *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; @@ -115,4 +118,5 @@ void phy_init_RU(RU_t *); void feptx_prec(RU_t *); void feptx_ofdm(RU_t *); void oai_subframe_ind(uint16_t sfn, uint16_t sf); +extern uint16_t sf_ahead; #endif diff --git a/executables/transport_split.c b/executables/transport_split.c index 490f1259a3..38cd9c3438 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -68,11 +68,20 @@ bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPo } // sock: udp socket -// expectedTS: the expected timestamp, 0 if unknown // bufferZone: a reception area of bufferSize -int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize, uint16_t contentType) { +int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t contentType) { int rcved=0; commonUDP_t *bufOrigin=(commonUDP_t *)bufferZone; + static uint8_t crossData[65536]; + static int crossDataSize=0; + + if (crossDataSize) { + LOG_D(HW,"copy a block received in previous subframe\n"); + memcpy(bufferZone, crossData, crossDataSize); + rcved=1; + bufferZone+=crossDataSize; + crossDataSize=0; + } do { //read all subframe data from the control unit @@ -80,7 +89,8 @@ int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int if ( ret==-1) { if ( errno == EWOULDBLOCK || errno== EINTR ) { - return rcved; // Timeout, subframe incomplete + LOG_I(HW,"Received: Timeout, subframe incomplete\n"); + return rcved; } else { LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno)); return -1; @@ -89,28 +99,26 @@ int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int if (hUDP(bufferZone)->contentType != contentType) abort(); - if ( hUDP(bufferZone)->timestamp != expectedTS) { - if ( hUDP(bufferZone)->timestamp < expectedTS) { - LOG_W(HW,"Received a paquet from past subframes, dropping it\n"); + if (rcved && bufOrigin->timestamp != hUDP(bufferZone)->timestamp ) { + if ( hUDP(bufferZone)->timestamp > bufOrigin->timestamp ) { + LOG_W(HW,"Received data for TS: %lu before end of TS : %lu completion\n", + hUDP(bufferZone)->timestamp, + bufOrigin->timestamp); + memcpy(crossData, bufferZone, ret ); + crossDataSize=ret; + return rcved; } else { - LOG_W(HW,"Received a paquet in future subframes\n"); - - if ( rcved == 0 ) { - LOG_W(HW,"First paquet in the sub-frame, keeping it\n"); - rcved++; - bufferZone+=ret; - expectedTS=hUDP(bufferZone)->timestamp; - } + LOG_W(HW,"Dropping late packet\n"); + continue; } - } else { - rcved++; - bufferZone+=ret; } - } - } while ( !rcved || rcved < hUDP(bufferZone)->nbBlocks ); - LOG_D(HW,"Received: nb_blocks: %d, TS: %lu, frame: %d, subframe: %d\n", - rcved, bufOrigin->timestamp, *(((int *)bufOrigin)+1), *(((int *)bufOrigin)+2)); + rcved++; + bufferZone+=ret; + } + } while ( rcved == 0 || rcved < bufOrigin->nbBlocks ); + + LOG_D(HW,"Received: nb_blocks: %d, TS: %lu\n",rcved, bufOrigin->timestamp); return rcved; } diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index 37997c94b4..d852248b63 100644 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -195,7 +195,7 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, pbch_E = (frame_parms->Ncp==NORMAL) ? 1920 : 1728; //RE/RB * #RB * bits/RB (QPSK) // pbch_E_bytes = pbch_coded_bits>>3; - LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4==0); + LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4); if (frame_mod4==0) { bzero(pbch_a,PBCH_A>>3); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 17d3001205..533254ebc6 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -162,7 +162,7 @@ void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int **txdataF = eNB->common_vars.txdataF; uint8_t *pbch_pdu=&eNB->pbch_pdu[0]; - //LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?"); + LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?"); // generate Cell-Specific Reference Signals for both slots VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1); From 9fb9ac53876758482c69936fd84dfbaea61de5a7 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 12 Aug 2019 21:32:46 +0200 Subject: [PATCH 025/175] UE primary sync ok, DU upper layers disabled, UE DCI decoding nok (partial) --- executables/main-fs6.c | 5 +++++ executables/main-ocp.c | 11 ++++++----- executables/split_headers.h | 1 + executables/transport_split.c | 3 +-- targets/COMMON/create_tasks.c | 5 ++++- targets/RT/USER/lte-softmodem.c | 6 ++++-- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index ace3f7fd1d..cc94ea42fa 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -485,6 +485,8 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e eNB->pdcch_vars[subframe&1].num_pdcch_symbols=hDL(bufferZone)->num_pdcch_symbols; eNB->pdcch_vars[subframe&1].num_dci=hDL(bufferZone)->num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = hDL(bufferZone)->num_mdci; + eNB->pbch_configured=true; + memcpy(eNB->pbch_pdu,hDL(bufferZone)->pbch_pdu, 4); // Remove all scheduled DL, we will populate from the CU sending for (int UE_id=0; UE_idpdcch_vars[subframe&1].num_pdcch_symbols; uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; + memcpy(hDL(bufferZone)->pbch_pdu,eNB->pbch_pdu,4); + LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -691,6 +695,7 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx hDL(bufferZone)->num_dci=num_dci; hDL(bufferZone)->num_mdci=num_mdci; hDL(bufferZone)->amp=AMP; + LOG_D(PHY, "pbch configured: %d\n", eNB->pbch_configured); } if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci); diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 3f6d057d82..432ec6025a 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -109,9 +109,10 @@ void init_RU_proc(RU_t *ru) { if (fs6) { if ( strncasecmp(fs6,"cu", 2) == 0 ) - threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); - else if ( strncasecmp(fs6,"du", 2) == 0 ) - threadCreate(&t, du_fs6, (void *)ru, "MainDu", -1, OAI_PRIORITY_RT_MAX); + threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); + else if ( strncasecmp(fs6,"du", 2) == 0 ) { + threadCreate(&t, du_fs6, (void *)ru, "MainDu", -1, OAI_PRIORITY_RT_MAX); + } else AssertFatal(false, "environement variable fs6 is not cu or du"); } else @@ -638,8 +639,8 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { } else { if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { LOG_E(HW,"impossible shift in RFSIM\n"); - ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); - proc->timestamp_rx = ts-ru->ts_offset; + //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); + //proc->timestamp_rx = ts-ru->ts_offset; } } diff --git a/executables/split_headers.h b/executables/split_headers.h index 59909e524e..42202d546b 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -52,6 +52,7 @@ typedef struct { } fs6_ul_t; typedef struct { + uint8_t pbch_pdu[4]; int num_pdcch_symbols; int num_dci; DCI_ALLOC_t dci_alloc[32]; diff --git a/executables/transport_split.c b/executables/transport_split.c index 38cd9c3438..c9d848ef19 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -155,7 +155,6 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui nbBlocks--; } while (nbBlocks); - LOG_D(HW,"Sent: TS: %lu, frame: %d, subframe: %d\n", - UDPheader->timestamp, *(((int *)UDPheader)+1), *(((int *)UDPheader)+2)); + LOG_D(HW,"Sent: TS: %lu\n", UDPheader->timestamp); return 0; } diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index cfc2bc2215..58be63a848 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -49,6 +49,9 @@ int create_tasks(uint32_t enb_nb) { int rc; if (enb_nb == 0) return 0; + bool fs6Du=false; + if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) + fs6Du=true; LOG_I(ENB_APP, "Creating ENB_APP eNB Task\n"); rc = itti_create_task (TASK_ENB_APP, eNB_app_task, NULL); @@ -64,7 +67,7 @@ int create_tasks(uint32_t enb_nb) { } - if (EPC_MODE_ENABLED && !NODE_IS_DU(type)) { + if (EPC_MODE_ENABLED && !NODE_IS_DU(type) && !fs6Du ) { rc = itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL); AssertFatal(rc >= 0, "Create task for S1AP failed\n"); if (!(get_softmodem_params()->emulate_rf)){ diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 109c0afdd4..85862f9430 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -593,8 +593,10 @@ int main( int argc, char **argv ) { /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks * for monolithic/F1 modes */ - if ( getenv("fs6") == NULL || strncasecmp( getenv("fs6"), "du", 2) != 0 ) - init_pdcp(); + //if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) + //RC.rrc[0]->node_type=ngran_eNB_DU; + + init_pdcp(); if (create_tasks(1) < 0) { printf("cannot create ITTI tasks\n"); From b907922014800ba44ef96efd40bdec13d1575df6 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 13 Aug 2019 21:03:45 +0200 Subject: [PATCH 026/175] SIB ok for UE, UE send RACH --- executables/main-fs6.c | 86 +++++++++++++++++++++++++++++-------- executables/split_headers.h | 9 ++++ 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index cc94ea42fa..6aed32d132 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -506,14 +506,30 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks if ( ((commonUDP_t *)bufPtr)->contentBytes >= sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) ) { int curUE=hDLUE(bufPtr)->UE_id; + LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[curUE][0]; + LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[hDLUE(bufPtr)->harq_pid]; #ifdef PHY_TX_THREAD - eNB->dlsch[curUE][0]->active[subframe] = 1; + dlsch0->active[subframe] = 1; #else - eNB->dlsch[curUE][0]->active = 1; + dlsch0->active = 1; #endif - eNB->dlsch[curUE][0]->harq_ids[frame%2][subframe]=hDLUE(bufPtr)->harq_pid; - eNB->dlsch[curUE][0]->rnti=hDLUE(bufPtr)->rnti; - memcpy(eNB->dlsch[curUE][0]->harq_processes[hDLUE(bufPtr)->harq_pid]->e, + dlsch0->harq_ids[frame%2][subframe]=hDLUE(bufPtr)->harq_pid; + dlsch0->rnti=hDLUE(bufPtr)->rnti; + dlsch0->sqrt_rho_a=hDLUE(bufPtr)->sqrt_rho_a; + dlsch0->sqrt_rho_b=hDLUE(bufPtr)->sqrt_rho_b; + dlsch_harq->nb_rb=hDLUE(bufPtr)->nb_rb; + memcpy(dlsch_harq->rb_alloc, hDLUE(bufPtr)->rb_alloc, sizeof(hDLUE(bufPtr)->rb_alloc)); + dlsch_harq->Qm=hDLUE(bufPtr)->Qm; + dlsch_harq->Nl=hDLUE(bufPtr)->Nl; + dlsch_harq->pdsch_start=hDLUE(bufPtr)->pdsch_start; +#ifdef PHY_TX_THREAD + dlsch_harq->i0=hDLUE(bufPtr)->i0; + dlsch_harq->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; +#else + dlsch0->i0=hDLUE(bufPtr)->i0; + dlsch0->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; +#endif + memcpy(dlsch_harq->e, hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); } @@ -550,6 +566,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e for (int i=0; i< hDL(bufferZone)->num_dci; i++) eNB->pdcch_vars[subframe&1].dci_alloc[i]=hDL(bufferZone)->dci_alloc[i]; + LOG_D (PHY, "Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %" PRIu8 ")\n", frame, subframe, hDL(bufferZone)->num_dci); generate_dci_top(hDL(bufferZone)->num_pdcch_symbols, hDL(bufferZone)->num_dci, &eNB->pdcch_vars[subframe&1].dci_alloc[0], @@ -576,6 +593,14 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e (dlsch0->active == 1) #endif ) { + uint64_t sum=0; + + for ( int i= subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti); + i< (subframe+1) * fp->ofdm_symbol_size * (fp->symbols_per_tti); + i++) + sum+=((int32_t *)(eNB->common_vars.txdataF[0]))[i]; + + LOG_D(PHY,"frame: %d, subframe: %d, sum of dlsch mod v1: %lx\n", frame, subframe, sum); int harq_pid=dlsch0->harq_ids[frame%2][subframe]; pdsch_procedures(eNB, proc, @@ -591,7 +616,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e AMP); } -void appendFs6DLUE(uint8_t *bufferZone, int UE_id, int8_t harq_pid, uint16_t rnti, uint8_t *UEdata, int UEdataLen) { +void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_t harq_pid, LTE_eNB_DLSCH_t *dlsch0, LTE_DL_eNB_HARQ_t *harqData, int frame, int subframe) { commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; // move to the end uint8_t *firstFreeByte=bufferZone; @@ -603,6 +628,14 @@ void appendFs6DLUE(uint8_t *bufferZone, int UE_id, int8_t harq_pid, uint16_t rnt curBlock++; } + int UEdataLen= get_G(fp, + harqData->nb_rb, + harqData->rb_alloc, + harqData->Qm, + harqData->Nl, + harqData->pdsch_start, + frame,subframe, + 0); AssertFatal(firstFreeByte+UEdataLen+sizeof(fs6_dl_t) <= bufferZone+FS6_BUF_SIZE, ""); commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; FirstUDPheader->nbBlocks++; @@ -612,9 +645,26 @@ void appendFs6DLUE(uint8_t *bufferZone, int UE_id, int8_t harq_pid, uint16_t rnt // This header will be duplicated during sending hDLUE(newUDPheader)->UE_id=UE_id; hDLUE(newUDPheader)->harq_pid=harq_pid; - hDLUE(newUDPheader)->rnti=rnti; + hDLUE(newUDPheader)->rnti=dlsch0->rnti; + hDLUE(newUDPheader)->sqrt_rho_a=dlsch0->sqrt_rho_a; + hDLUE(newUDPheader)->sqrt_rho_b=dlsch0->sqrt_rho_b; + hDLUE(newUDPheader)->nb_rb=harqData->nb_rb; + memcpy(hDLUE(newUDPheader)->rb_alloc, harqData->rb_alloc, sizeof(harqData->rb_alloc)); + hDLUE(newUDPheader)->Qm=harqData->Qm; + hDLUE(newUDPheader)->Nl=harqData->Nl; + hDLUE(newUDPheader)->pdsch_start=harqData->pdsch_start; +#ifdef PHY_TX_THREAD + hDLUE(newUDPheader)->i0=harqData->i0; + hDLUE(newUDPheader)->sib1_br_flag=harqData->sib1_br_flag; +#else + hDLUE(newUDPheader)->i0=dlsch0->i0; + hDLUE(newUDPheader)->sib1_br_flag=dlsch0->sib1_br_flag; +#endif hDLUE(newUDPheader)->dataLen=UEdataLen; - memcpy(hDLUE(newUDPheader)+1, UEdata, UEdataLen); + memcpy(hDLUE(newUDPheader)+1, harqData->e, UEdataLen); + + for (int i=0; i < UEdataLen; i++) + LOG_D(PHY,"buffer e:%hhx\n", ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); } void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { @@ -687,7 +737,6 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; memcpy(hDL(bufferZone)->pbch_pdu,eNB->pbch_pdu,4); - LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -695,6 +744,10 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx hDL(bufferZone)->num_dci=num_dci; hDL(bufferZone)->num_mdci=num_mdci; hDL(bufferZone)->amp=AMP; + + for (int i=0; i< hDL(bufferZone)->num_dci; i++) + hDL(bufferZone)->dci_alloc[i]=eNB->pdcch_vars[subframe&1].dci_alloc[i]; + LOG_D(PHY, "pbch configured: %d\n", eNB->pbch_configured); } @@ -750,18 +803,13 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx */ LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[harq_pid]; appendFs6DLUE(bufferZone, + fp, UE_id, harq_pid, - dlsch0->rnti, - dlsch0->harq_processes[harq_pid]->e, - get_G(fp, - dlsch_harq->nb_rb, - dlsch_harq->rb_alloc, - dlsch_harq->Qm, - dlsch_harq->Nl, - dlsch_harq->pdsch_start, - frame,subframe, - 0) + dlsch0, + dlsch_harq, + frame, + subframe ); } } diff --git a/executables/split_headers.h b/executables/split_headers.h index 42202d546b..2e0df34c54 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -68,6 +68,15 @@ typedef struct { int UE_id; int8_t harq_pid; uint16_t rnti; + int16_t sqrt_rho_a; + int16_t sqrt_rho_b; + uint16_t nb_rb; + uint8_t Qm; + int8_t Nl; + uint8_t pdsch_start; + uint8_t sib1_br_flag; + uint16_t i0; + uint32_t rb_alloc[4]; int dataLen; } fs6_dl_uespec_t; From d28419cfca26ca6bd6a493b6359c572a02380702 Mon Sep 17 00:00:00 2001 From: laurent Date: Sat, 24 Aug 2019 16:28:55 +0200 Subject: [PATCH 027/175] usage of setAllfromTS in also monolitic version, RACH detected to the cu, several bugs fixed, still no attach complete --- executables/main-fs6.c | 508 ++++++++++++++------ executables/main-ocp.c | 151 +++--- executables/split_headers.h | 51 +- openair1/PHY/LTE_TRANSPORT/prach.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach_common.c | 1 + openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 6 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 79 +-- openair1/PHY/defs_eNB.h | 1 + openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- 9 files changed, 522 insertions(+), 279 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 6aed32d132..1ebce9ef7d 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -16,62 +16,18 @@ #include #include #include +#include #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; -// Fixme: there are many mistakes in the datamodel and in redondant variables -// TDD is also mode complex -void setAllfromTS(uint64_t TS) { - for (int i=0; i frame_parms; - uint64_t TStx=TS+sf_ahead*fp->samples_per_tti; - RU_proc_t *proc =&RC.ru[i]->proc; - proc->timestamp_rx= TS; - proc->timestamp_tx= TStx; - proc->subframe_rx= (TS / fp->samples_per_tti)%10; - proc->subframe_tx= (TStx / fp->samples_per_tti)%10; - proc->subframe_prach=(TS / fp->samples_per_tti)%10; - proc->subframe_prach_br=(TS / fp->samples_per_tti)%10; - proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; - proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; - } - for (int i=0; i < RC.nb_inst; i++) { - for (int j=0; jframe_parms; - uint64_t TStx=TS+sf_ahead*fp->samples_per_tti; - L1_proc_t *proc =&RC.eNB[i][j]->proc; - L1_rxtx_proc_t *proc1=&RC.eNB[i][j]->proc.L1_proc; - proc->timestamp_rx= TS; - proc->timestamp_tx= TStx; - proc->subframe_rx= (TS / fp->samples_per_tti)%10; - proc->subframe_prach=(TS / fp->samples_per_tti)%10; - proc->subframe_prach_br=(TS / fp->samples_per_tti)%10; - proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; - proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; - proc1->timestamp_tx= TStx; - proc1->subframe_rx= (TS / fp->samples_per_tti)%10; - proc1->subframe_tx= (TStx / fp->samples_per_tti)%10; - proc1->frame_rx= (TS / (fp->samples_per_tti*10))&1023; - proc1->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; - } - } - - return; -} - - -void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int frame,int subframe) { +void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); - if (is_prach_subframe(&eNB->frame_parms, frame,subframe)<=0) + if (is_prach_subframe(&eNB->frame_parms, eNB->proc.frame_prach,eNB->proc.subframe_prach)<=0) return; - eNB->proc.frame_prach = frame; - eNB->proc.subframe_prach = subframe; - eNB->proc.frame_prach_br = frame; - eNB->proc.subframe_prach_br = subframe; RU_t *ru; int aa=0; int ru_aa; @@ -88,19 +44,19 @@ void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int } } - /* Fixme: the orgin code calls the two funtiosn, so one overwrite the second? - rx_prach(eNB, - eNB->RU_list[0], - header->max_preamble, - header->max_preamble_energy, - header->max_preamble_delay, - header->avg_preamble_energy, - frame, - 0, - false - ); - */ + rx_prach(eNB, + eNB->RU_list[0], + header->max_preamble, + header->max_preamble_energy, + header->max_preamble_delay, + header->avg_preamble_energy, + eNB->proc.frame_prach, + 0, + false + ); // run PRACH detection for CE-level 0 only for now when br_flag is set + /* fixme: seems not operational and may overwrite regular LTE prach detection + * OAI code can call is sequence rx_prach(eNB, eNB->RU_list[0], header->max_preamble, @@ -111,17 +67,26 @@ void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, int 0, true ); + */ + LOG_D(PHY,"RACH detection index 0: max preamble: %u, energy: %u, delay: %u, avg energy: %u\n", + header->max_preamble[0], + header->max_preamble_energy[0], + header->max_preamble_delay[0], + header->avg_preamble_energy[0] + ); return; } -void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { +void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); uint16_t *max_preamble=header->max_preamble; uint16_t *max_preamble_energy=header->max_preamble_energy; uint16_t *max_preamble_delay=header->max_preamble_delay; uint16_t *avg_preamble_energy=header->avg_preamble_energy; + int subframe=eNB->proc.subframe_prach; + int frame=eNB->proc.frame_prach; // Fixme: not clear why we call twice with "br" and without - int br_flag=1; + int br_flag=0; if (br_flag==1) { int prach_mask; @@ -206,6 +171,29 @@ void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,RU_t } } +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen) { + uint8_t *bufferZone=eNB->FS6bufferZone; + commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; + // move to the end + uint8_t *firstFreeByte=bufferZone; + int curBlock=0; + + for (int i=0; i < FirstUDPheader->nbBlocks; i++) { + AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,""); + firstFreeByte+=alignedSize(firstFreeByte); + curBlock++; + } + + commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; + FirstUDPheader->nbBlocks++; + newUDPheader->blockID=curBlock; + newUDPheader->contentBytes=sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_t) + dataLen; + hULUE(newUDPheader)->UE_id=UE_id; + hULUE(newUDPheader)->harq_id=harq_pid; + hULUE(newUDPheader)->segment=segmentID; + memcpy(hULUE(newUDPheader)+1, data, dataLen); +} + void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { uint32_t harq_pid; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; @@ -223,9 +211,14 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; if (ulsch->rnti>0) - LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n", + LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d active: %d handled:%d]\n", i, harq_pid, frame,subframe,i,ulsch->rnti, - ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); + ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->status, ulsch_harq->handled); + + if ((ulsch) && + (ulsch->rnti>0) && + (ulsch_harq->status == ACTIVE)) + LOG_E(PHY,"active ulsch harq\n"); if ((ulsch) && (ulsch->rnti>0) && @@ -265,7 +258,8 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN ulsch_harq->O_ACK, ulsch->beta_offset_cqi_times8); start_meas(&eNB->ulsch_demodulation_stats); - rx_ulsch(eNB,proc, i); + eNB->FS6bufferZone=bufferZone; + rx_ulsch(eNB, proc, i); stop_meas(&eNB->ulsch_demodulation_stats); // TBD: add datablock for transmission } @@ -318,13 +312,98 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *bufferZone, int bufSize, PHY_ return; } -void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { +int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { + int harq_pid; + LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; + + if (ulsch->ue_type>0) + harq_pid = 0; + else + harq_pid = subframe2harq_pid(&eNB->frame_parms,eNB->proc.frame_rx,eNB->proc.subframe_rx); + + LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; + decoder_if_t *tc; + int offset, ret; + + if (llr8_flag == 0) + tc = *decoder16; + else + tc = *decoder8; + + for (int r=0; rC; r++) { + // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); + // Get Turbo interleaver parameters + int Kr; + + if (rCminus) + Kr = ulsch_harq->Kminus; + else + Kr = ulsch_harq->Kplus; + + int Kr_bytes = Kr>>3; + int crc_type; + + if (ulsch_harq->C == 1) + crc_type = CRC24_A; + else + crc_type = CRC24_B; + + start_meas(&eNB->ulsch_turbo_decoding_stats); + ret = tc(&ulsch_harq->d[r][96], + NULL, + ulsch_harq->c[r], + NULL, + Kr, + ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, + crc_type, + (r==0) ? ulsch_harq->F : 0, + &eNB->ulsch_tc_init_stats, + &eNB->ulsch_tc_alpha_stats, + &eNB->ulsch_tc_beta_stats, + &eNB->ulsch_tc_gamma_stats, + &eNB->ulsch_tc_ext_stats, + &eNB->ulsch_tc_intl1_stats, + &eNB->ulsch_tc_intl2_stats); + stop_meas(&eNB->ulsch_turbo_decoding_stats); + + // Reassembly of Transport block here + + if (ret != (1+ulsch->max_turbo_iterations)) { + if (rCminus) + Kr = ulsch_harq->Kminus; + else + Kr = ulsch_harq->Kplus; + + Kr_bytes = Kr>>3; + + if (r==0) { + memcpy(ulsch_harq->bb, + &ulsch_harq->c[0][(ulsch_harq->F>>3)], + Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); + offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); + } else { + memcpy(ulsch_harq->bb+offset, + ulsch_harq->c[r], + Kr_bytes - ((ulsch_harq->C>1)?3:0)); + offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); + } + } else { + break; + } + } + + return(ret); +} + +void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { //LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - const int subframe = proc->subframe_rx; - const int frame = proc->frame_rx; + const int subframe = eNB->proc.subframe_rx; + const int frame = eNB->proc.frame_rx; uint32_t harq_pid; uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); + // TBD: read UL data + for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i]; @@ -353,11 +432,16 @@ void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN } start_meas(&eNB->ulsch_decoding_stats); - int ret = ulsch_decoding(eNB,proc, + /* + int ret = ulsch_decoding(eNB,&eNB->proc.L1_proc, i, 0, // control_only_flag ulsch_harq->V_UL_DAI, ulsch_harq->nb_rb>20 ? 1 : 0); + */ + int ret = ulsch_decoding_process(eNB, + i, + ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); LOG_D(PHY, "[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n", @@ -474,7 +558,26 @@ void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN } // for (i=0; icontentBytes >= sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_t) ) { + LTE_eNB_ULSCH_t *ulsch =eNB->ulsch[hULUE(bufPtr)->UE_id]; + LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hULUE(bufPtr)->harq_id]; + memcpy(&ulsch_harq->d[hULUE(bufPtr)->segment][96], + hULUE(bufPtr)+1, + hULUE(bufPtr)->segLen); + bufPtr+=alignedSize(bufPtr); + LOG_W(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); + } + } +} + +void phy_procedures_eNB_uespec_RX_process(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { + // The configuration arrived in Dl, so we can extract the UL data + recvFs6Ul(bufferZone, nbBlocks, eNB); + pusch_procedures_process(bufferZone, nbBlocks, eNB); } void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { @@ -504,36 +607,75 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e void *bufPtr=bufferZone; for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks - if ( ((commonUDP_t *)bufPtr)->contentBytes >= sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) ) { - int curUE=hDLUE(bufPtr)->UE_id; - LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[curUE][0]; - LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[hDLUE(bufPtr)->harq_pid]; -#ifdef PHY_TX_THREAD - dlsch0->active[subframe] = 1; -#else - dlsch0->active = 1; -#endif - dlsch0->harq_ids[frame%2][subframe]=hDLUE(bufPtr)->harq_pid; - dlsch0->rnti=hDLUE(bufPtr)->rnti; - dlsch0->sqrt_rho_a=hDLUE(bufPtr)->sqrt_rho_a; - dlsch0->sqrt_rho_b=hDLUE(bufPtr)->sqrt_rho_b; - dlsch_harq->nb_rb=hDLUE(bufPtr)->nb_rb; - memcpy(dlsch_harq->rb_alloc, hDLUE(bufPtr)->rb_alloc, sizeof(hDLUE(bufPtr)->rb_alloc)); - dlsch_harq->Qm=hDLUE(bufPtr)->Qm; - dlsch_harq->Nl=hDLUE(bufPtr)->Nl; - dlsch_harq->pdsch_start=hDLUE(bufPtr)->pdsch_start; -#ifdef PHY_TX_THREAD - dlsch_harq->i0=hDLUE(bufPtr)->i0; - dlsch_harq->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; -#else - dlsch0->i0=hDLUE(bufPtr)->i0; - dlsch0->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; -#endif - memcpy(dlsch_harq->e, - hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); - } + if ( ((commonUDP_t *)bufPtr)->contentBytes > sizeof(fs6_dl_t) ) { + int type=hDLUE(bufPtr)->type; - bufPtr+=alignedSize(bufPtr); + if ( type == fs6DlConfig) { + int curUE=hDLUE(bufPtr)->UE_id; + LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[curUE][0]; + LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[hDLUE(bufPtr)->harq_pid]; +#ifdef PHY_TX_THREAD + dlsch0->active[subframe] = 1; +#else + dlsch0->active = 1; +#endif + dlsch0->harq_ids[frame%2][subframe]=hDLUE(bufPtr)->harq_pid; + dlsch0->rnti=hDLUE(bufPtr)->rnti; + dlsch0->sqrt_rho_a=hDLUE(bufPtr)->sqrt_rho_a; + dlsch0->sqrt_rho_b=hDLUE(bufPtr)->sqrt_rho_b; + dlsch_harq->nb_rb=hDLUE(bufPtr)->nb_rb; + memcpy(dlsch_harq->rb_alloc, hDLUE(bufPtr)->rb_alloc, sizeof(hDLUE(bufPtr)->rb_alloc)); + dlsch_harq->Qm=hDLUE(bufPtr)->Qm; + dlsch_harq->Nl=hDLUE(bufPtr)->Nl; + dlsch_harq->pdsch_start=hDLUE(bufPtr)->pdsch_start; +#ifdef PHY_TX_THREAD + dlsch_harq->i0=hDLUE(bufPtr)->i0; + dlsch_harq->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; +#else + dlsch0->i0=hDLUE(bufPtr)->i0; + dlsch0->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; +#endif + memcpy(dlsch_harq->e, + hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); + } else if (type == fs6UlConfig) { + int nbUE=(((commonUDP_t *)bufPtr)->contentBytes - sizeof(fs6_dl_t)) / sizeof( fs6_dl_ulsched_t ) ; + + for ( int i=0; i < nbUE; i++ ) { + int curUE=hTxULUE(bufPtr)->UE_id; + LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[curUE]; + LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hTxULUE(bufPtr)->harq_pid]; + ulsch->ue_type=hTxULUE(bufPtr)->ue_type; + ulsch->harq_mask=hTxULUE(bufPtr)->harq_mask; + ulsch->Mlimit=hTxULUE(bufPtr)->Mlimit; + ulsch->max_turbo_iterations=hTxULUE(bufPtr)->max_turbo_iterations; + ulsch->bundling=hTxULUE(bufPtr)->bundling; + ulsch->beta_offset_cqi_times8=hTxULUE(bufPtr)->beta_offset_cqi_times8; + ulsch->beta_offset_ri_times8=hTxULUE(bufPtr)->beta_offset_ri_times8; + ulsch->beta_offset_harqack_times8=hTxULUE(bufPtr)->beta_offset_harqack_times8; + ulsch->Msg3_active=hTxULUE(bufPtr)->Msg3_active; + ulsch->cyclicShift=hTxULUE(bufPtr)->cyclicShift; + ulsch->cooperation_flag=hTxULUE(bufPtr)->cooperation_flag; + ulsch->num_active_cba_groups=hTxULUE(bufPtr)->num_active_cba_groups; + memcpy(ulsch->cba_rnti,hTxULUE(bufPtr)->cba_rnti,sizeof(ulsch->cba_rnti));//NUM_MAX_CBA_GROUP]; + ulsch->rnti=hTxULUE(bufPtr)->rnti; + ulsch_harq->nb_rb=hTxULUE(bufPtr)->nb_rb; + ulsch_harq->handled=0; + ulsch_harq->status = ACTIVE; + ulsch_harq->frame = frame; + ulsch_harq->subframe = subframe; + ulsch_harq->first_rb=hTxULUE(bufPtr)->first_rb; + ulsch_harq->V_UL_DAI=hTxULUE(bufPtr)->V_UL_DAI; + ulsch_harq->Qm=hTxULUE(bufPtr)->Qm; + ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; + ulsch_harq->TBS=hTxULUE(bufPtr)->TBS; + ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch; + LOG_W(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); + } + } else + LOG_E(PHY, "Impossible block in fs6 DL\n"); + + bufPtr+=alignedSize(bufPtr); + } } if (do_meas==1) { @@ -616,6 +758,63 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e AMP); } +#define cpyToDu(a) hTxULUE(newUDPheader)->a=ulsch->a +#define cpyToDuHarq(a) hTxULUE(newUDPheader)->a=ulsch_harq->a + +void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE_eNB_ULSCH_t *ulsch, int frame, int subframe) { + commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; + // move to the end + uint8_t *firstFreeByte=bufferZone; + int curBlock=0; + + for (int i=0; i < FirstUDPheader->nbBlocks; i++) { + AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,""); + firstFreeByte+=alignedSize(firstFreeByte); + curBlock++; + } + + commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; + FirstUDPheader->nbBlocks++; + newUDPheader->blockID=curBlock; + newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_ulsched_t); + // We skip the fs6 DL header, that is populated by caller + // This header will be duplicated during sending + hTxULUE(newUDPheader)->type=fs6UlConfig; + hTxULUE(newUDPheader)->UE_id=curUE; + int harq_pid; + + if (ulsch->ue_type > NOCE) + // LTE-M case + harq_pid = 0; + else + harq_pid = subframe2harq_pid(fp, frame, subframe); + + LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[harq_pid]; + hTxULUE(newUDPheader)->harq_pid=harq_pid; + cpyToDu(ue_type); + cpyToDu(harq_mask); + cpyToDu(Mlimit); + cpyToDu(max_turbo_iterations); + cpyToDu(bundling); + cpyToDu(beta_offset_cqi_times8); + cpyToDu(beta_offset_ri_times8); + cpyToDu(beta_offset_harqack_times8); + cpyToDu(Msg3_active); + cpyToDu(cyclicShift); + cpyToDu(cooperation_flag); + cpyToDu(num_active_cba_groups); + memcpy(hTxULUE(newUDPheader)->cba_rnti,ulsch->cba_rnti,sizeof(ulsch->cba_rnti));//NUM_MAX_CBA_GROUP]; + cpyToDu(rnti); + cpyToDuHarq(nb_rb); + cpyToDuHarq(first_rb); + cpyToDuHarq(V_UL_DAI); + cpyToDuHarq(Qm); + cpyToDuHarq(srs_active); + cpyToDuHarq(TBS); + cpyToDuHarq(Nsymb_pusch); + LOG_W(PHY,"Added request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); +} + void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_t harq_pid, LTE_eNB_DLSCH_t *dlsch0, LTE_DL_eNB_HARQ_t *harqData, int frame, int subframe) { commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; // move to the end @@ -643,6 +842,7 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) + UEdataLen; // We skip the fs6 DL header, that is populated by caller // This header will be duplicated during sending + hDLUE(newUDPheader)->type=fs6DlConfig; hDLUE(newUDPheader)->UE_id=UE_id; hDLUE(newUDPheader)->harq_pid=harq_pid; hDLUE(newUDPheader)->rnti=dlsch0->rnti; @@ -662,9 +862,8 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ #endif hDLUE(newUDPheader)->dataLen=UEdataLen; memcpy(hDLUE(newUDPheader)+1, harqData->e, UEdataLen); - - for (int i=0; i < UEdataLen; i++) - LOG_D(PHY,"buffer e:%hhx\n", ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); + //for (int i=0; i < UEdataLen; i++) + //LOG_D(PHY,"buffer e:%hhx\n", ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); } void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { @@ -677,59 +876,51 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx return; } - // clear existing ulsch dci allocations before applying info from MAC (this is table - // returns -1 (or 255) if there is no ul (tdd cases) - int ul_subframe = pdcch_alloc2ul_subframe (fp, subframe); - int ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); - // clear previous allocation information for all UEs for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { //if (eNB->dlsch[i][0]) //eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } - /* TODO: check the following test - in the meantime it is put back as it was before */ - //if ((ul_subframe < 10)&& - // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here - if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be schedulyed here - for (int i=0; iulsch[i]; - if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type > NOCE) - // LTE-M case - harq_pid = 0; - else - hDL(bufferZone)->UE_ul_active[i] = harq_pid = subframe2harq_pid(fp, ul_frame, ul_subframe); + if (ulsch->ue_type > NOCE) + harq_pid = 0; + else + harq_pid= subframe2harq_pid(&eNB->frame_parms,frame,subframe); - if (eNB->ulsch[i]) { - //LTE_UL_eNB_HARQ_t *ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; - /* Store first_rb and n_DMRS for correct PHICH generation below. - * For PHICH generation we need "old" values of last scheduling - * for this HARQ process. 'generate_eNB_dlsch_params' below will - * overwrite first_rb and n_DMRS and 'generate_phich_top', done - * after 'generate_eNB_dlsch_params', would use the "new" values - * instead of the "old" ones. - * - * This has been tested for FDD only, may be wrong for TDD. - * - * TODO: maybe we should restructure the code to be sure it - * is done correctly. The main concern is if the code - * changes and first_rb and n_DMRS are modified before - * we reach here, then the PHICH processing will be wrong, - * using wrong first_rb and n_DMRS values to compute - * ngroup_PHICH and nseq_PHICH. - * - * TODO: check if that works with TDD. - */ - /* seems useless: unused variables - header->previous_first_rb= - ulsch_harq->previous_first_rb = ulsch_harq->first_rb; - header->previous_n_DMRS = - ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; - */ - hDL(bufferZone)->UE_ul_active[i] = harq_pid; - } else - hDL(bufferZone)->UE_ul_active[i] = -1; + LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; + + if (ulsch->rnti>0) { + LOG_I(PHY,"check in UL scheduled harq %d: rnti %d, tx frame %d/%d, ulsch: %d, %d/%d (handled: %d)\n", + harq_pid, ulsch->rnti, frame, subframe, ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); + + for (int k=0; k<8; k++) + if ( ulsch->harq_processes[k]->status == ACTIVE) + LOG_I(PHY,"check in UL scheduledi (harq_pid %d): rnti %d, tx frame %d/%d, ulsch: %d, %d/%d (handled: %d)\n", k, + ulsch->rnti, frame, subframe, ulsch->harq_processes[k]->status, ulsch->harq_processes[k]->frame, ulsch->harq_processes[k]->subframe, ulsch->harq_processes[k]->handled); + } + + for (int k=0; k<8; k++) { + ulsch_harq = ulsch->harq_processes[k]; + + if (ulsch && + (ulsch->rnti>0) && + (ulsch_harq->status == ACTIVE) && + (ulsch_harq->frame == frame) && + (ulsch_harq->subframe == subframe) && + (ulsch_harq->handled == 0) + ) + appendFs6TxULUE(bufferZone, + fp, + i, + ulsch, + frame, + subframe + ); } } @@ -755,9 +946,6 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx if (do_meas==1) start_meas(&eNB->dlsch_ue_specific); - // Now scan UE specific DLSCH - LTE_eNB_DLSCH_t *dlsch0; - for (int UE_id=0; UE_iddlsch[UE_id][0]; @@ -838,8 +1026,6 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx } void DL_du_fs6(RU_t *ru) { - RU_proc_t *ru_proc=&ru->proc; - for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); @@ -853,8 +1039,7 @@ void DL_du_fs6(RU_t *ru) { hUDP(bufferZone)->timestamp); } - setAllfromTS(hUDP(bufferZone)->timestamp - - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti); + setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti); phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); } else LOG_E(PHY,"DL not received for subframe\n"); @@ -868,13 +1053,15 @@ void DL_du_fs6(RU_t *ru) { void UL_du_fs6(RU_t *ru, int frame, int subframe) { RU_proc_t *ru_proc=&ru->proc; int tmpf=frame, tmpsf=subframe; - rx_rf(ru,&tmpf,&tmpsf); + rx_rf(ru); AssertFatal(tmpf==frame && tmpsf==subframe, "lost synchronization\n"); - ru_proc->frame_tx = (ru_proc->frame_tx+ru_proc->frame_offset)&1023; setAllfromTS(ru_proc->timestamp_rx); + // front end processing: convert from time domain to frequency domain + // fills rxdataF buffer + fep_full(ru); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; - L1_proc_t *proc = &eNB->proc; + L1_proc_t *proc = &eNB->proc; if (NFAPI_MODE==NFAPI_MODE_PNF) { // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick @@ -885,7 +1072,7 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { initBufferZone(bufferZone); hUDP(bufferZone)->timestamp=ru->proc.timestamp_rx; - prach_eNB_extract(bufferZone, FS6_BUF_SIZE, eNB, proc->frame_rx,proc->subframe_rx ); + prach_eNB_extract(bufferZone, FS6_BUF_SIZE, eNB); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { phy_procedures_eNB_uespec_RX_extract(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc ); @@ -902,7 +1089,7 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } } -void DL_cu_fs6(RU_t *ru, uint64_t TS) { +void DL_cu_fs6(RU_t *ru) { // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; L1_proc_t *proc = &eNB->proc; @@ -945,10 +1132,11 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { setAllfromTS(hUDP(bufferZone)->timestamp); PHY_VARS_eNB *eNB = RC.eNB[0][0]; + prach_eNB_process(bufferZone, sizeof(bufferZone), eNB); release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_process(bufferZone, sizeof(bufferZone), eNB, &eNB->proc.L1_proc); + phy_procedures_eNB_uespec_RX_process(bufferZone, nb_blocks, eNB); } } @@ -965,7 +1153,7 @@ void *cu_fs6(void *arg) { while(1) { timeStamp+=ru->frame_parms.samples_per_tti; UL_cu_fs6(ru, &timeStamp); - DL_cu_fs6(ru, timeStamp); + DL_cu_fs6(ru); } return NULL; diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 432ec6025a..b3983463e0 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -46,6 +46,54 @@ void free_transport(PHY_VARS_eNB *eNB) { void reset_opp_meas(void) { } +// Fixme: there are many mistakes in the datamodel and in redondant variables +// TDD is also mode complex +void setAllfromTS(uint64_t TS) { + for (int i=0; i frame_parms; + RU_proc_t *proc =&RC.ru[i]->proc; + uint64_t TStx=TS+(sf_ahead)*fp->samples_per_tti; + uint64_t TSrach=TS;//-fp->samples_per_tti; + proc->timestamp_rx= TS; + proc->timestamp_tx= TStx; + proc->subframe_rx= (TS / fp->samples_per_tti)%10; + proc->subframe_tx= (TStx / fp->samples_per_tti)%10; + proc->subframe_prach=(TSrach / fp->samples_per_tti)%10; + proc->subframe_prach_br=proc->subframe_prach; + proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; + proc->frame_prach= (TSrach / (fp->samples_per_tti*10))&1023; + proc->frame_prach_br=(TSrach / (fp->samples_per_tti*10))&1023; + proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + } + + for (int i=0; i < RC.nb_inst; i++) { + for (int j=0; jframe_parms; + L1_proc_t *proc =&RC.eNB[i][j]->proc; + L1_rxtx_proc_t *proc1=&RC.eNB[i][j]->proc.L1_proc; + uint64_t TStx=TS+(sf_ahead)*fp->samples_per_tti; + uint64_t TSrach=TS;//-fp->samples_per_tti; + proc->timestamp_rx= TS; + proc->timestamp_tx= TStx; + proc->subframe_rx= (TS / fp->samples_per_tti)%10; + proc->subframe_prach=(TSrach / fp->samples_per_tti)%10; + proc->subframe_prach_br=(TSrach / fp->samples_per_tti)%10; + proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; + proc->frame_prach= (TSrach / (fp->samples_per_tti*10))&1023; + proc->frame_prach_br=(TSrach / (fp->samples_per_tti*10))&1023; + proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + proc1->timestamp_tx= TStx; + proc1->subframe_rx= (TS / fp->samples_per_tti)%10; + proc1->subframe_tx= (TStx / fp->samples_per_tti)%10; + proc1->frame_rx= (TS / (fp->samples_per_tti*10))&1023; + proc1->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + } + } + + return; +} + + void init_eNB_proc(int inst) { /*int i=0;*/ int CC_id; @@ -98,7 +146,6 @@ void init_RU_proc(RU_t *ru) { proc->instance_cnt_eNBs = -1; proc->first_rx = 1; proc->first_tx = 1; - proc->frame_offset = 0; proc->num_slaves = 0; proc->frame_tx_unwrap = 0; @@ -112,8 +159,7 @@ void init_RU_proc(RU_t *ru) { threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); else if ( strncasecmp(fs6,"du", 2) == 0 ) { threadCreate(&t, du_fs6, (void *)ru, "MainDu", -1, OAI_PRIORITY_RT_MAX); - } - else + } else AssertFatal(false, "environement variable fs6 is not cu or du"); } else threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); @@ -263,6 +309,8 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { eNB->prach_energy_counter = 0; } } + + SET_LOG_DEBUG(PRACH); } void stop_eNB(int nb_inst) { @@ -421,17 +469,8 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) { } } -void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subframe) { +void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4],avg_preamble_energy[4]; - - if (br_flag==0) { - eNB->proc.frame_prach = frame; - eNB->proc.subframe_prach = subframe; - } else { - eNB->proc.frame_prach_br = frame; - eNB->proc.subframe_prach_br = subframe; - } - RU_t *ru; int aa=0; int ru_aa; @@ -456,10 +495,16 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subfram &max_preamble_energy[0], &max_preamble_delay[0], &avg_preamble_energy[0], - frame, + eNB->proc.frame_prach, 0 ,br_flag ); + LOG_D(PHY,"RACH detection index 0: max preamble: %u, energy: %u, delay: %u, avg energy: %u\n", + max_preamble[0], + max_preamble_energy[0], + max_preamble_delay[0], + avg_preamble_energy[0] + ); if (br_flag==1) { int prach_mask; @@ -483,7 +528,7 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subfram eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; // eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 - eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + subframe + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40)); + eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + eNB->proc.subframe_prach + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40)); eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1 + ce_level; // CE Level LOG_I (PHY, "Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", @@ -504,8 +549,8 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subfram LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, - frame, - subframe, + eNB->proc.frame_prach, + eNB->proc.subframe_prach, max_preamble[0], max_preamble_energy[0]/10, max_preamble_energy[0]%10, @@ -515,11 +560,11 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subfram eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; - eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe; + eNB->UL_INFO.rach_ind.sfn_sf = eNB->proc.frame_prach<<4 | eNB->proc.subframe_prach; eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; - eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here + eNB->preamble_list[0].preamble_rel8.rnti = 1+eNB->proc.subframe_prach; // note: fid is implicitly 0 here eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is @@ -547,8 +592,8 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag, int frame, int subfram void prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { // check if we have to detect PRACH first if (is_prach_subframe(&eNB->frame_parms, frame,subframe)>0) { - prach_procedures_ocp(eNB, 0, frame, subframe); - prach_procedures_ocp(eNB, 1, frame, subframe); + prach_procedures_ocp(eNB, 0); + prach_procedures_ocp(eNB, 1); } } @@ -586,28 +631,14 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name void eNB_top(PHY_VARS_eNB *eNB, int dummy1, int dummy2, char *string,RU_t *ru) { L1_proc_t *proc = &eNB->proc; L1_rxtx_proc_t *L1_proc = &proc->L1_proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - RU_proc_t *ru_proc=&ru->proc; if (!oai_exit) { - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); - L1_proc->frame_rx = ru_proc->frame_rx; - L1_proc->subframe_rx = ru_proc->subframe_rx; - L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? - (L1_proc->frame_rx+1)&1023 : - L1_proc->frame_rx; - L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; - if (rxtx(eNB,L1_proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; } } -void rx_rf(RU_t *ru,int *frame,int *subframe) { +void rx_rf(RU_t *ru) { RU_proc_t *proc = &ru->proc; LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; void *rxp[ru->nb_rx]; @@ -616,7 +647,8 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { openair0_timestamp ts=0,old_ts=0; for (i=0; inb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; + //receive in the next slot + rxp[i] = (void *)&ru->common.rxdata[i][((ru->proc.subframe_rx+1)%10)*fp->samples_per_tti]; old_ts = proc->timestamp_rx; rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, @@ -630,6 +662,12 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); if(rxs != fp->samples_per_tti) { LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); +#if defined(USRP_REC_PLAY) + exit_fun("Exiting IQ record/playback"); +#else + //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples"); +#endif } if (proc->first_rx == 1) { @@ -638,27 +676,13 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { proc->first_rx = false; } else { if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { - LOG_E(HW,"impossible shift in RFSIM\n"); + LOG_E(HW,"impossible shift in RFSIM, rx: %ld, previous rx distance: %ld\n", proc->timestamp_rx, proc->timestamp_rx - old_ts); //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); //proc->timestamp_rx = ts-ru->ts_offset; } } - proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; - proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; - // synchronize first reception to frame 0 subframe 0 - proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); - proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; - proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; - - if (rxs != fp->samples_per_tti) { -#if defined(USRP_REC_PLAY) - exit_fun("Exiting IQ record/playback"); -#else - //exit_fun( "problem receiving samples" ); - LOG_E(PHY, "problem receiving samples"); -#endif - } + setAllfromTS(proc->timestamp_rx); } void tx_rf(RU_t *ru) { @@ -723,9 +747,6 @@ void tx_rf(RU_t *ru) { static void *ru_thread( void *param ) { RU_t *ru = (RU_t *)param; - RU_proc_t *proc = &ru->proc; - int subframe =9; - int frame =1023; if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); @@ -747,23 +768,8 @@ static void *ru_thread( void *param ) { // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { - // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. - // They are set on the first rx/tx in the underly FH routines. - if (subframe==9) { - subframe=0; - frame++; - frame&=1023; - } else { - subframe++; - } - // synchronization on input FH interface, acquire signals/data and block - AssertFatal(ru->fh_south_in, "No fronthaul interface at south port"); - ru->fh_south_in(ru,&frame,&subframe); - - // adjust for timing offset between RU - if (ru->idx!=0) - proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023; + rx_rf(ru); // do RX front-end processing (frequency-shift, dft) if needed if (ru->feprx) @@ -819,7 +825,6 @@ void set_function_spec_param(RU_t *ru) { ru->feptx_ofdm = feptx_ofdm; ru->feptx_prec = feptx_prec; // this is fep with idft and precoding ru->rfdevice.host_type = RAU_HOST; - ru->fh_south_in = rx_rf; // local synchronous RF RX ru->fh_south_out = tx_rf; // local synchronous RF TX ru->start_rf = start_rf; // need to start the local RF interface ru->stop_rf = stop_rf; diff --git a/executables/split_headers.h b/executables/split_headers.h index 2e0df34c54..f3b17e4918 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -58,13 +58,43 @@ typedef struct { DCI_ALLOC_t dci_alloc[32]; int num_mdci; int amp; - int8_t UE_ul_active[NUMBER_OF_UE_MAX]; - int8_t UE_ul_first_rb[NUMBER_OF_UE_MAX]; // - int8_t UE_ul_last_rb[NUMBER_OF_UE_MAX]; // LTE_eNB_PHICH phich_vars; } fs6_dl_t; +enum pckType { + fs6UlConfig=25, + fs6DlConfig=26, +}; + typedef struct { + enum pckType type:8; + uint16_t UE_id; + int8_t harq_pid; + UE_type_t ue_type; + uint16_t harq_mask; + uint16_t nb_rb; + uint8_t Qm; + uint16_t first_rb; + uint8_t V_UL_DAI; + uint8_t srs_active; + uint32_t TBS; + uint8_t Nsymb_pusch; + uint8_t Mlimit; + uint8_t max_turbo_iterations; + uint8_t bundling; + uint16_t beta_offset_cqi_times8; + uint16_t beta_offset_ri_times8; + uint16_t beta_offset_harqack_times8; + uint8_t Msg3_active; + uint16_t rnti; + uint8_t cyclicShift; + uint8_t cooperation_flag; + uint8_t num_active_cba_groups; + uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP]; +} fs6_dl_ulsched_t; + +typedef struct { + enum pckType type:8; int UE_id; int8_t harq_pid; uint16_t rnti; @@ -76,10 +106,17 @@ typedef struct { uint8_t pdsch_start; uint8_t sib1_br_flag; uint16_t i0; - uint32_t rb_alloc[4]; + uint32_t rb_alloc[4];; int dataLen; } fs6_dl_uespec_t; +typedef struct { + short UE_id; + short harq_id; + short segment; + short segLen; +} fs6_ul_uespec_t; + bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t contentType); int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType); @@ -92,6 +129,8 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui #define hDL(xBuf) ((fs6_dl_t*)(((commonUDP_t *)xBuf)+1)) #define hUL(xBuf) ((fs6_ul_t*)(((commonUDP_t *)xBuf)+1)) #define hDLUE(xBuf) ((fs6_dl_uespec_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1)) +#define hTxULUE(xBuf) ((fs6_dl_ulsched_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1)) +#define hULUE(xBuf) ((fs6_ul_uespec_t*) (((fs6_ul_t*)(((commonUDP_t *)xBuf)+1))+1)) static inline size_t alignedSize(uint8_t *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; @@ -102,10 +141,11 @@ static inline void *commonUDPdata(uint8_t *ptr) { return (void *) (((commonUDP_t *)ptr)+1); } +void setAllfromTS(uint64_t TS); void *cu_fs6(void *arg); void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); -void rx_rf(RU_t *ru,int *frame,int *subframe); +void rx_rf(RU_t *ru); void tx_rf(RU_t *ru); void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe); void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); @@ -128,5 +168,6 @@ void phy_init_RU(RU_t *); void feptx_prec(RU_t *); void feptx_ofdm(RU_t *); void oai_subframe_ind(uint16_t sfn, uint16_t sf); +void fep_full(RU_t *ru); extern uint16_t sf_ahead; #endif diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index f49005b5d7..6aca9ba904 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -649,7 +649,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<harq_processes[i]) { - if (ulsch->harq_processes[i]->b) { - free16(ulsch->harq_processes[i]->b,MAX_ULSCH_PAYLOAD_BYTES); - ulsch->harq_processes[i]->b = NULL; + if (ulsch->harq_processes[i]->bb) { + free16(ulsch->harq_processes[i]->bb,MAX_ULSCH_PAYLOAD_BYTES); + ulsch->harq_processes[i]->bb = NULL; } for (r=0; rharq_processes[i]) { memset(ulsch->harq_processes[i],0,sizeof(LTE_UL_eNB_HARQ_t)); - ulsch->harq_processes[i]->b = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); + ulsch->harq_processes[i]->bb = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); - if (ulsch->harq_processes[i]->b) - memset(ulsch->harq_processes[i]->b,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); + if (ulsch->harq_processes[i]->bb) + memset(ulsch->harq_processes[i]->bb,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); else exit_flag=3; @@ -274,7 +274,7 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { Kr_bytes = Kr>>3; memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), + ulsch_harq->RTCC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING @@ -286,11 +286,11 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { ulsch_harq->Nl); #endif - if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], + if (lte_rate_matching_turbo_rx(ulsch_harq->RTCC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], - ulsch_harq->e+r_offset, + ulsch_harq->eE+r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -340,7 +340,7 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { Kr = ulsch_harq->Kplus; Kr_bytes = Kr>>3; - memcpy(ulsch_harq->b+offset, + memcpy(ulsch_harq->bb+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -448,7 +448,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr Kr_bytes = Kr>>3; memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), + ulsch_harq->RTCC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING @@ -461,11 +461,11 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr #endif start_meas(&eNB->ulsch_rate_unmatching_stats); - if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], + if (lte_rate_matching_turbo_rx(ulsch_harq->RTCC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], - ulsch_harq->e+r_offset, + ulsch_harq->eE+r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -521,12 +521,12 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr Kr_bytes = Kr>>3; if (r==0) { - memcpy(ulsch_harq->b, + memcpy(ulsch_harq->bb, &ulsch_harq->c[0][(ulsch_harq->F>>3)], Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); } else { - memcpy(ulsch_harq->b+offset, + memcpy(ulsch_harq->bb+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -553,7 +553,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; int G = ulsch_harq->G; - unsigned int E; + unsigned int EE; decoder_if_t *tc; if (llr8_flag == 0) @@ -571,7 +571,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) Kr_bytes = Kr>>3; memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), + ulsch_harq->RTCC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING @@ -584,11 +584,11 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) #endif start_meas(&eNB->ulsch_rate_unmatching_stats); - if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], + if (lte_rate_matching_turbo_rx(ulsch_harq->RTCC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], - ulsch_harq->e+r_offset, + ulsch_harq->eE+r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -598,13 +598,13 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) ulsch_harq->Qm, 1, r, - &E)==-1) { + &EE)==-1) { LOG_E(PHY,"ulsch_decoding.c: Problem in rate matching\n"); return(-1); } stop_meas(&eNB->ulsch_rate_unmatching_stats); - r_offset += E; + r_offset += EE; start_meas(&eNB->ulsch_deinterleaving_stats); sub_block_deinterleaving_turbo(4+Kr, &ulsch_harq->d[r][96], @@ -616,6 +616,13 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) else crc_type = CRC24_B; + if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + // r is the segment id, + // Kr is the segment length in short + sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)); + return 0; + } + start_meas(&eNB->ulsch_turbo_decoding_stats); ret = tc(&ulsch_harq->d[r][96], NULL, @@ -645,12 +652,12 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) Kr_bytes = Kr>>3; if (r==0) { - memcpy(ulsch_harq->b, + memcpy(ulsch_harq->bb, &ulsch_harq->c[0][(ulsch_harq->F>>3)], Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); } else { - memcpy(ulsch_harq->b+offset, + memcpy(ulsch_harq->bb+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -1190,8 +1197,8 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, j2+=2; } - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; } break; @@ -1203,10 +1210,10 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, j2+=4; } - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; } break; @@ -1218,12 +1225,12 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, j2+=6; } - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->eE[iprime++] = y[j2++]; } break; @@ -1261,7 +1268,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, */ int16_t *yp,*ep; - for (iprime=0,yp=&y[j2],ep=&ulsch_harq->e[0]; + for (iprime=0,yp=&y[j2],ep=&ulsch_harq->eE[0]; iprimerx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation - pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; + pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->bb; // estimate timing advance for MAC sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check From cb41822b426b410753f7148049e6a4d7851fcc47 Mon Sep 17 00:00:00 2001 From: laurent Date: Sat, 24 Aug 2019 18:59:45 +0200 Subject: [PATCH 028/175] ulsch turbo decode success, fails after now --- executables/main-fs6.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 1ebce9ef7d..6cc5f1be65 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -262,6 +262,13 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN rx_ulsch(eNB, proc, i); stop_meas(&eNB->ulsch_demodulation_stats); // TBD: add datablock for transmission + start_meas(&eNB->ulsch_decoding_stats); + ulsch_decoding(eNB,proc, + i, + 0, // control_only_flag + ulsch_harq->V_UL_DAI, + ulsch_harq->nb_rb>20 ? 1 : 0); + stop_meas(&eNB->ulsch_decoding_stats); } } } @@ -323,14 +330,28 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; decoder_if_t *tc; - int offset, ret; + int offset, ret=-1; if (llr8_flag == 0) tc = *decoder16; else tc = *decoder8; - for (int r=0; rC; r++) { + // This is a new packet, so compute quantities regarding segmentation + //Fixme: very dirty: all the variables produced by let_segmentation are only used localy + // Furthermore, variables as 1 letter and global is "time consuming" for everybody !!! + ulsch_harq->B = ulsch_harq->TBS+24; + lte_segmentation(NULL, + NULL, + ulsch_harq->B, + &ulsch_harq->C, + &ulsch_harq->Cplus, + &ulsch_harq->Cminus, + &ulsch_harq->Kplus, + &ulsch_harq->Kminus, + &ulsch_harq->F); + + for (int r=0; rCcC; r++) { // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); // Get Turbo interleaver parameters int Kr; @@ -379,13 +400,13 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { if (r==0) { memcpy(ulsch_harq->bb, &ulsch_harq->c[0][(ulsch_harq->F>>3)], - Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); - offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); + Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->CcC>1)?3:0)); + offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->CcC>1)?3:0); } else { memcpy(ulsch_harq->bb+offset, ulsch_harq->c[r], - Kr_bytes - ((ulsch_harq->C>1)?3:0)); - offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); + Kr_bytes - ((ulsch_harq->CcC>1)?3:0)); + offset += (Kr_bytes- ((ulsch_harq->CcC>1)?3:0)); } } else { break; @@ -666,6 +687,7 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e ulsch_harq->first_rb=hTxULUE(bufPtr)->first_rb; ulsch_harq->V_UL_DAI=hTxULUE(bufPtr)->V_UL_DAI; ulsch_harq->Qm=hTxULUE(bufPtr)->Qm; + ulsch_harq->CcC=hTxULUE(bufPtr)->CcC; ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; ulsch_harq->TBS=hTxULUE(bufPtr)->TBS; ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch; @@ -809,6 +831,7 @@ void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE cpyToDuHarq(first_rb); cpyToDuHarq(V_UL_DAI); cpyToDuHarq(Qm); + cpyToDuHarq(CcC); cpyToDuHarq(srs_active); cpyToDuHarq(TBS); cpyToDuHarq(Nsymb_pusch); @@ -1052,9 +1075,7 @@ void DL_du_fs6(RU_t *ru) { void UL_du_fs6(RU_t *ru, int frame, int subframe) { RU_proc_t *ru_proc=&ru->proc; - int tmpf=frame, tmpsf=subframe; rx_rf(ru); - AssertFatal(tmpf==frame && tmpsf==subframe, "lost synchronization\n"); setAllfromTS(ru_proc->timestamp_rx); // front end processing: convert from time domain to frequency domain // fills rxdataF buffer From 55660e87ca4442dd3ca0873289eef08ee727cc37 Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 25 Aug 2019 20:32:57 +0200 Subject: [PATCH 029/175] RACH working, fails later during MME authentication --- executables/main-fs6.c | 203 +++++++++++++++----- executables/split_headers.h | 32 +++ executables/transport_split.c | 5 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 4 +- openair1/SCHED/fapi_l1.h | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 20 +- 6 files changed, 212 insertions(+), 54 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 6cc5f1be65..07a5fc2805 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -171,6 +171,49 @@ void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { } } +void sendFs6Ulharq(int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { + static int current_fsf=-1; + int fsf=frame*16+subframe; + uint8_t *bufferZone=eNB->FS6bufferZone; + commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; + // move to the end + uint8_t *firstFreeByte=bufferZone; + int curBlock=0; + + if ( current_fsf != fsf ) { + for (int i=0; i < FirstUDPheader->nbBlocks; i++) { + AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,""); + firstFreeByte+=alignedSize(firstFreeByte); + curBlock++; + } + + commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; + FirstUDPheader->nbBlocks++; + newUDPheader->blockID=curBlock; + newUDPheader->contentBytes=sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_uci_t); + hULUEuci(newUDPheader)->type=fs6ULcch; + hULUEuci(newUDPheader)->nb_active_ue=0; + } else + for (int i=0; i < FirstUDPheader->nbBlocks-1; i++) { + AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,""); + firstFreeByte+=alignedSize(firstFreeByte); + curBlock++; + } + + commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; + fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(newUDPheader)+1); + tmp+=hULUEuci(newUDPheader)->nb_active_ue; + tmp->UEid=UEid; + tmp->frame=frame; + tmp->subframe=subframe; + memcpy(tmp->harq_ack, harq_ack, 4); + tmp->tdd_mapping_mode=tdd_mapping_mode; + tmp->tdd_multiplexing_mask=tdd_multiplexing_mask; + tmp->n0_subband_power_dB=eNB->measurements.n0_subband_power_dB[0][0]; + hULUEuci(newUDPheader)->nb_active_ue++; + newUDPheader->contentBytes+=sizeof(fs6_ul_uespec_uci_element_t); +} + void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen) { uint8_t *bufferZone=eNB->FS6bufferZone; commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; @@ -188,10 +231,12 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ FirstUDPheader->nbBlocks++; newUDPheader->blockID=curBlock; newUDPheader->contentBytes=sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_t) + dataLen; + hULUE(newUDPheader)->type=fs6ULsch; hULUE(newUDPheader)->UE_id=UE_id; hULUE(newUDPheader)->harq_id=harq_pid; hULUE(newUDPheader)->segment=segmentID; memcpy(hULUE(newUDPheader)+1, data, dataLen); + hULUE(newUDPheader)->segLen=dataLen; } void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { @@ -351,7 +396,7 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { &ulsch_harq->Kminus, &ulsch_harq->F); - for (int r=0; rCcC; r++) { + for (int r=0; rC; r++) { // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); // Get Turbo interleaver parameters int Kr; @@ -400,13 +445,13 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { if (r==0) { memcpy(ulsch_harq->bb, &ulsch_harq->c[0][(ulsch_harq->F>>3)], - Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->CcC>1)?3:0)); - offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->CcC>1)?3:0); + Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); + offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); } else { memcpy(ulsch_harq->bb+offset, ulsch_harq->c[r], - Kr_bytes - ((ulsch_harq->CcC>1)?3:0)); - offset += (Kr_bytes- ((ulsch_harq->CcC>1)?3:0)); + Kr_bytes - ((ulsch_harq->C>1)?3:0)); + offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); } } else { break; @@ -583,15 +628,32 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { void *bufPtr=bufferZone; for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks - if ( ((commonUDP_t *)bufPtr)->contentBytes >= sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_t) ) { - LTE_eNB_ULSCH_t *ulsch =eNB->ulsch[hULUE(bufPtr)->UE_id]; - LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hULUE(bufPtr)->harq_id]; - memcpy(&ulsch_harq->d[hULUE(bufPtr)->segment][96], - hULUE(bufPtr)+1, - hULUE(bufPtr)->segLen); - bufPtr+=alignedSize(bufPtr); - LOG_W(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); + if ( ((commonUDP_t *)bufPtr)->contentBytes > sizeof(fs6_ul_t) ) { + int type=hULUE(bufPtr)->type; + + if ( type == fs6ULsch) { + LTE_eNB_ULSCH_t *ulsch =eNB->ulsch[hULUE(bufPtr)->UE_id]; + LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hULUE(bufPtr)->harq_id]; + memcpy(&ulsch_harq->d[hULUE(bufPtr)->segment][96], + hULUE(bufPtr)+1, + hULUE(bufPtr)->segLen); + LOG_W(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); + } else if ( type == fs6ULcch ) { + int nb_uci=hULUEuci(bufPtr)->nb_active_ue; + fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); + + for (int i=0; i < nb_uci ; i++) { + eNB->measurements.n0_subband_power_dB[0][0]=tmp->n0_subband_power_dB; + fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid], + tmp->frame, tmp->subframe, tmp->harq_ack, + tmp->tdd_mapping_mode, tmp->tdd_multiplexing_mask); + tmp++; + } + } else + LOG_E(PHY, "FS6 ul packet type impossible\n" ); } + + bufPtr+=alignedSize(bufPtr); } } @@ -601,30 +663,7 @@ void phy_procedures_eNB_uespec_RX_process(uint8_t *bufferZone, int nbBlocks,PHY_ pusch_procedures_process(bufferZone, nbBlocks, eNB); } -void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - int subframe=proc->subframe_tx; - int frame=proc->frame_tx; - //LTE_UL_eNB_HARQ_t *ulsch_harq; - eNB->pdcch_vars[subframe&1].num_pdcch_symbols=hDL(bufferZone)->num_pdcch_symbols; - eNB->pdcch_vars[subframe&1].num_dci=hDL(bufferZone)->num_dci; - uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = hDL(bufferZone)->num_mdci; - eNB->pbch_configured=true; - memcpy(eNB->pbch_pdu,hDL(bufferZone)->pbch_pdu, 4); - - // Remove all scheduled DL, we will populate from the CU sending - for (int UE_id=0; UE_iddlsch[UE_id][0]; - - if ( dlsch0 && dlsch0->rnti>0 ) { -#ifdef PHY_TX_THREAD - dlsch0->active[subframe] = 0; -#else - dlsch0->active = 0; -#endif - } - } - +void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, int subframe) { void *bufPtr=bufferZone; for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks @@ -687,19 +726,50 @@ void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_e ulsch_harq->first_rb=hTxULUE(bufPtr)->first_rb; ulsch_harq->V_UL_DAI=hTxULUE(bufPtr)->V_UL_DAI; ulsch_harq->Qm=hTxULUE(bufPtr)->Qm; - ulsch_harq->CcC=hTxULUE(bufPtr)->CcC; ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; ulsch_harq->TBS=hTxULUE(bufPtr)->TBS; ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch; LOG_W(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); } - } else - LOG_E(PHY, "Impossible block in fs6 DL\n"); + } else if ( type == fs6ULConfigCCH ) { + fs6_dl_uespec_ulcch_element_t *tmp=(fs6_dl_uespec_ulcch_element_t *)(hTxULcch(bufPtr)+1); - bufPtr+=alignedSize(bufPtr); + for (int i=0; i< hTxULcch(bufPtr)->nb_active_ue; i++ ) + memcpy(&eNB->uci_vars[tmp->UE_id], &tmp->cch_vars, sizeof(tmp->cch_vars)); + } else + LOG_E(PHY, "Impossible block in fs6 DL\n"); + } + + bufPtr+=alignedSize(bufPtr); + } +} + +void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int subframe=proc->subframe_tx; + int frame=proc->frame_tx; + //LTE_UL_eNB_HARQ_t *ulsch_harq; + eNB->pdcch_vars[subframe&1].num_pdcch_symbols=hDL(bufferZone)->num_pdcch_symbols; + eNB->pdcch_vars[subframe&1].num_dci=hDL(bufferZone)->num_dci; + uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = hDL(bufferZone)->num_mdci; + eNB->pbch_configured=true; + memcpy(eNB->pbch_pdu,hDL(bufferZone)->pbch_pdu, 4); + + // Remove all scheduled DL, we will populate from the CU sending + for (int UE_id=0; UE_iddlsch[UE_id][0]; + + if ( dlsch0 && dlsch0->rnti>0 ) { +#ifdef PHY_TX_THREAD + dlsch0->active[subframe] = 0; +#else + dlsch0->active = 0; +#endif } } + rcvFs6DL(bufferZone, nbBlocks, eNB, frame, subframe); + if (do_meas==1) { start_meas(&eNB->phy_proc_tx); start_meas(&eNB->dlsch_common_and_dci); @@ -831,13 +901,11 @@ void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE cpyToDuHarq(first_rb); cpyToDuHarq(V_UL_DAI); cpyToDuHarq(Qm); - cpyToDuHarq(CcC); cpyToDuHarq(srs_active); cpyToDuHarq(TBS); cpyToDuHarq(Nsymb_pusch); LOG_W(PHY,"Added request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); } - void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_t harq_pid, LTE_eNB_DLSCH_t *dlsch0, LTE_DL_eNB_HARQ_t *harqData, int frame, int subframe) { commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; // move to the end @@ -889,6 +957,50 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ //LOG_D(PHY,"buffer e:%hhx\n", ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); } +void appendFs6DLUEcch(uint8_t *bufferZone, PHY_VARS_eNB *eNB, int frame, int subframe) { + commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; + // move to the end + uint8_t *firstFreeByte=bufferZone; + int curBlock=0; + + for (int i=0; i < FirstUDPheader->nbBlocks; i++) { + AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,""); + firstFreeByte+=alignedSize(firstFreeByte); + curBlock++; + } + + commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; + bool first_UE=true; + + for (int i = 0; i < NUMBER_OF_UCI_VARS_MAX; i++) { + LTE_eNB_UCI *uci = &(eNB->uci_vars[i]); + + if ((uci->active == 1) && (uci->frame == frame) && (uci->subframe == subframe)) { + LOG_D(PHY,"Frame %d, subframe %d: adding uci procedures (type %d) for %d \n", + frame, + subframe, + uci->type, + i); + + if ( first_UE ) { + FirstUDPheader->nbBlocks++; + newUDPheader->blockID=curBlock; + newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_ulcch_t); + hTxULcch(newUDPheader)->type=fs6ULConfigCCH; + hTxULcch(newUDPheader)->nb_active_ue=0; + first_UE=false; + } + + fs6_dl_uespec_ulcch_element_t *tmp=(fs6_dl_uespec_ulcch_element_t *)(hTxULcch(newUDPheader)+1); + tmp+=hTxULcch(newUDPheader)->nb_active_ue; + tmp->UE_id=i; + memcpy(&tmp->cch_vars,uci, sizeof(tmp->cch_vars)); + hTxULcch(newUDPheader)->nb_active_ue++; + newUDPheader->contentBytes+=sizeof(fs6_dl_uespec_ulcch_element_t); + } + } +} + void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { int frame=proc->frame_tx; int subframe=proc->subframe_tx; @@ -947,6 +1059,11 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx } } + appendFs6DLUEcch(bufferZone, + eNB, + frame, + subframe + ); uint8_t num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; diff --git a/executables/split_headers.h b/executables/split_headers.h index f3b17e4918..0fed9d63c8 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -64,6 +64,9 @@ typedef struct { enum pckType { fs6UlConfig=25, fs6DlConfig=26, + fs6ULConfigCCH=27, + fs6ULsch=28, + fs6ULcch=29, }; typedef struct { @@ -111,12 +114,39 @@ typedef struct { } fs6_dl_uespec_t; typedef struct { + int16_t UE_id; + LTE_eNB_UCI cch_vars; +} fs6_dl_uespec_ulcch_element_t; + +typedef struct { + enum pckType type:8; + int16_t nb_active_ue; +} fs6_dl_uespec_ulcch_t; + +typedef struct { + enum pckType type:8; short UE_id; short harq_id; short segment; short segLen; } fs6_ul_uespec_t; +typedef struct { + int UEid; + int frame; + int subframe; + uint8_t harq_ack[4]; + uint8_t tdd_mapping_mode; + uint16_t tdd_multiplexing_mask; + unsigned short n0_subband_power_dB; +} fs6_ul_uespec_uci_element_t; + +typedef struct { + enum pckType type:8; + int16_t nb_active_ue; +} fs6_ul_uespec_uci_t; + + bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result); int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t contentType); int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType); @@ -130,7 +160,9 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui #define hUL(xBuf) ((fs6_ul_t*)(((commonUDP_t *)xBuf)+1)) #define hDLUE(xBuf) ((fs6_dl_uespec_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1)) #define hTxULUE(xBuf) ((fs6_dl_ulsched_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1)) +#define hTxULcch(xBuf) ((fs6_dl_uespec_ulcch_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1)) #define hULUE(xBuf) ((fs6_ul_uespec_t*) (((fs6_ul_t*)(((commonUDP_t *)xBuf)+1))+1)) +#define hULUEuci(xBuf) ((fs6_ul_uespec_uci_t*) (((fs6_ul_t*)(((commonUDP_t *)xBuf)+1))+1)) static inline size_t alignedSize(uint8_t *ptr) { commonUDP_t *header=(commonUDP_t *) ptr; diff --git a/executables/transport_split.c b/executables/transport_split.c index c9d848ef19..17e40e7e25 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -139,9 +139,9 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui *currentHeader=*UDPheader; currentHeader->blockID=blockId; memcpy(commonUDPdata((void *)currentHeader), commonUDPdata(bufferZone), secondHeaderSize); - blockId++; } + blockId++; int sz=alignedSize(bufferZone); // Let's use the first address returned by getaddrinfo() int ret=sendto(sock->sockHandler, bufferZone, sz, 0, @@ -155,6 +155,7 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui nbBlocks--; } while (nbBlocks); - LOG_D(HW,"Sent: TS: %lu\n", UDPheader->timestamp); + LOG_D(HW,"Sent: TS: %lu, nb blocks %d, size of first block: %lu \n", + UDPheader->timestamp, UDPheader->nbBlocks, alignedSize((void *)UDPheader)); return 0; } diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 1fe65cd75e..59fd9b1378 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -46,6 +46,7 @@ #include "transport_proto.h" extern WORKER_CONF_t get_thread_worker_conf(void); +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen); void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch) { int i,r; @@ -619,7 +620,8 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { // r is the segment id, // Kr is the segment length in short - sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)); +// *3 because LTE redudancy scheme + sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)*3); return 0; } diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index 3bd469b685..77c254b13f 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -37,7 +37,7 @@ #include "SCHED/sched_common.h" #include "nfapi_interface.h" -void fill_uci_harq_indication(PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci,int frame,int subframe,uint8_t *harq_ack,uint8_t tdd_mapping_mode,uint16_t tdd_multiplexing_mask); +void fill_uci_harq_indication(int UEid, PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci,int frame,int subframe,uint8_t *harq_ack,uint8_t tdd_mapping_mode,uint16_t tdd_multiplexing_mask); void fill_ulsch_harq_indication(PHY_VARS_eNB *eNB,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti, int frame,int subframe,int bundling); void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti); void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 52b0c93bcf..4764ede395 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -46,6 +46,7 @@ #include #include "intertask_interface.h" +void sendFs6Ulharq(int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask); nfapi_ue_release_request_body_t release_rntis; @@ -768,7 +769,7 @@ uci_procedures(PHY_VARS_eNB *eNB, frame,subframe, pucch_b0b1[0][0],metric[0]); uci->stat = metric[0]; - fill_uci_harq_indication(eNB,uci,frame,subframe,pucch_b0b1[0],0,0xffff); + fill_uci_harq_indication(i, eNB,uci,frame,subframe,pucch_b0b1[0],0,0xffff); } else { // frame_type == TDD LOG_D(PHY,"Frame %d Subframe %d Demodulating PUCCH (UCI %d) for ACK/NAK (uci->pucch_fmt %d,uci->type %d.uci->frame %d, uci->subframe %d): n1_pucch0 %d SR_payload %d\n", frame,subframe,i, @@ -881,7 +882,7 @@ uci_procedures(PHY_VARS_eNB *eNB, } uci->stat = metric[0]; - fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,2,0xffff); // special_bundling mode + fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,2,0xffff); // special_bundling mode } else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==2)) { // multiplexing + no SR, implement Table 10.1.3-5 (Rel14) for multiplexing with M=2 if (pucch_b0b1[0][0] == 4 || pucch_b0b1[1][0] == 4) { // there isn't a likely transmission @@ -917,7 +918,7 @@ uci_procedures(PHY_VARS_eNB *eNB, } uci->stat = max(metric[0],metric[1]); - fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode + fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } //else if ((uci->tdd_bundling == 0) && (res==2)) else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==3)) { // multiplexing + no SR, implement Table 10.1.3-6 (Rel14) for multiplexing with M=3 if (harq_ack[0] == 4 || @@ -988,7 +989,7 @@ uci_procedures(PHY_VARS_eNB *eNB, } uci->stat = max_metric; - fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode + fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } } //else if ((uci->tdd_bundling == 0) && (res==3)) else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==4)) { // multiplexing + no SR, implement Table 10.1.3-7 (Rel14) for multiplexing with M=4 @@ -1110,14 +1111,14 @@ uci_procedures(PHY_VARS_eNB *eNB, } uci->stat = max_metric; - fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode + fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } // else if ((uci->tdd_bundling == 0) && (res==4)) else { // bundling harq_ack[0] = pucch_b0b1[0][0]; harq_ack[1] = pucch_b0b1[0][1]; uci->stat = metric[0]; LOG_D(PHY,"bundling: (%d,%d), metric %d\n",harq_ack[0],harq_ack[1],uci->stat); - fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,0,0xffff); // special_bundling mode + fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,0,0xffff); // special_bundling mode } #ifdef DEBUG_PHY_PROC @@ -1754,7 +1755,12 @@ void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_har pthread_mutex_unlock(&eNB->UL_INFO_mutex); } -void fill_uci_harq_indication (PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { +void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { + if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + sendFs6Ulharq(UEid, eNB, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask); + return; + } + int UE_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST); //AssertFatal(UE_id>=0,"UE_id doesn't exist rnti:%x\n", uci->rnti); From 1fe5ed6f3a232378a47f00f19eb8226939b55d19 Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 25 Aug 2019 20:45:13 +0200 Subject: [PATCH 030/175] changed terminology from/to split --- executables/main-fs6.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 07a5fc2805..845e5c6f5f 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -22,7 +22,7 @@ static UDPsock_t sockFS6; -void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { +void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); if (is_prach_subframe(&eNB->frame_parms, eNB->proc.frame_prach,eNB->proc.subframe_prach)<=0) @@ -77,7 +77,7 @@ void prach_eNB_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { return; } -void prach_eNB_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { +void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); uint16_t *max_preamble=header->max_preamble; uint16_t *max_preamble_energy=header->max_preamble_energy; @@ -239,7 +239,7 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ hULUE(newUDPheader)->segLen=dataLen; } -void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { +void pusch_procedures_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { uint32_t harq_pid; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; const int subframe = proc->subframe_rx; @@ -260,11 +260,6 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN i, harq_pid, frame,subframe,i,ulsch->rnti, ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->status, ulsch_harq->handled); - if ((ulsch) && - (ulsch->rnti>0) && - (ulsch_harq->status == ACTIVE)) - LOG_E(PHY,"active ulsch harq\n"); - if ((ulsch) && (ulsch->rnti>0) && (ulsch_harq->status == ACTIVE) && @@ -318,7 +313,7 @@ void pusch_procedures_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN } } -void phy_procedures_eNB_uespec_RX_extract(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { +void phy_procedures_eNB_uespec_RX_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { //RX processing for ue-specific resources (i LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; const int subframe = proc->subframe_rx; @@ -341,7 +336,7 @@ void phy_procedures_eNB_uespec_RX_extract(uint8_t *bufferZone, int bufSize, PHY_ uci_procedures (eNB, proc); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // If PNF or monolithic - pusch_procedures_extract(bufferZone, bufSize, eNB,proc); + pusch_procedures_tosplit(bufferZone, bufSize, eNB,proc); } lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements); @@ -461,7 +456,7 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { return(ret); } -void pusch_procedures_process(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { +void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { //LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; const int subframe = eNB->proc.subframe_rx; const int frame = eNB->proc.frame_rx; @@ -657,10 +652,10 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { } } -void phy_procedures_eNB_uespec_RX_process(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { +void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { // The configuration arrived in Dl, so we can extract the UL data recvFs6Ul(bufferZone, nbBlocks, eNB); - pusch_procedures_process(bufferZone, nbBlocks, eNB); + pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB); } void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, int subframe) { @@ -744,7 +739,7 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i } } -void phy_procedures_eNB_TX_process(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { +void phy_procedures_eNB_TX_fromsplit(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int subframe=proc->subframe_tx; int frame=proc->frame_tx; @@ -1001,7 +996,7 @@ void appendFs6DLUEcch(uint8_t *bufferZone, PHY_VARS_eNB *eNB, int frame, int sub } } -void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { +void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) { int frame=proc->frame_tx; int subframe=proc->subframe_tx; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; @@ -1180,7 +1175,7 @@ void DL_du_fs6(RU_t *ru) { } setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti); - phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); + phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); } else LOG_E(PHY,"DL not received for subframe\n"); } @@ -1210,10 +1205,10 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { initBufferZone(bufferZone); hUDP(bufferZone)->timestamp=ru->proc.timestamp_rx; - prach_eNB_extract(bufferZone, FS6_BUF_SIZE, eNB); + prach_eNB_tosplit(bufferZone, FS6_BUF_SIZE, eNB); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_extract(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc ); + phy_procedures_eNB_uespec_RX_tosplit(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc ); } if (hUDP(bufferZone)->nbBlocks==0) { @@ -1239,7 +1234,7 @@ void DL_cu_fs6(RU_t *ru) { eNB->if_inst->UL_indication(&eNB->UL_INFO); pthread_mutex_unlock(&eNB->UL_INFO_mutex); initBufferZone(bufferZone); - phy_procedures_eNB_TX_extract(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); + phy_procedures_eNB_TX_tosplit(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); hUDP(bufferZone)->timestamp=proc->L1_proc.timestamp_tx; if (hUDP(bufferZone)->nbBlocks==0) { @@ -1270,11 +1265,11 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { setAllfromTS(hUDP(bufferZone)->timestamp); PHY_VARS_eNB *eNB = RC.eNB[0][0]; - prach_eNB_process(bufferZone, sizeof(bufferZone), eNB); + prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB); release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_process(bufferZone, nb_blocks, eNB); + phy_procedures_eNB_uespec_RX_fromsplit(bufferZone, nb_blocks, eNB); } } From 43c07e401d3cdeddddb9620bcf1e9db004f9dd6e Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 26 Aug 2019 21:14:25 +0200 Subject: [PATCH 031/175] fix SR report from UE->DU->CU, remain later failure in PUSCH allocation --- executables/main-fs6.c | 41 ++++++++++++++------- executables/split_headers.h | 7 ++++ openair1/PHY/LTE_TRANSPORT/pbch.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach_common.c | 1 - openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 2 +- openair1/PHY/LTE_TRANSPORT/uci_tools.c | 4 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 34 +++++++++++++---- openair1/SCHED/fapi_l1.c | 2 +- openair1/SCHED/fapi_l1.h | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 16 +++++--- targets/ARCH/rfsimulator/simulator.c | 2 +- 11 files changed, 79 insertions(+), 34 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 845e5c6f5f..bb88c1d61e 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -171,7 +171,7 @@ void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { } } -void sendFs6Ulharq(int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) { static int current_fsf=-1; int fsf=frame*16+subframe; uint8_t *bufferZone=eNB->FS6bufferZone; @@ -200,16 +200,22 @@ void sendFs6Ulharq(int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_ curBlock++; } + LOG_D(PHY,"FS6 du, block: %d: adding ul harq/sr: %d, rnti: %d, ueid: %d\n", + curBlock, type, rnti, UEid); commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(newUDPheader)+1); tmp+=hULUEuci(newUDPheader)->nb_active_ue; + tmp->type=type; tmp->UEid=UEid; tmp->frame=frame; tmp->subframe=subframe; - memcpy(tmp->harq_ack, harq_ack, 4); + if (harq_ack != NULL) + memcpy(tmp->harq_ack, harq_ack, 4); tmp->tdd_mapping_mode=tdd_mapping_mode; tmp->tdd_multiplexing_mask=tdd_multiplexing_mask; tmp->n0_subband_power_dB=eNB->measurements.n0_subband_power_dB[0][0]; + tmp->rnti=rnti; + tmp->stat=stat; hULUEuci(newUDPheader)->nb_active_ue++; newUDPheader->contentBytes+=sizeof(fs6_ul_uespec_uci_element_t); } @@ -636,12 +642,19 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); - - for (int i=0; i < nb_uci ; i++) { + for (int j=0; j < nb_uci ; j++) { + LOG_D(PHY,"FS6 cu, block: %d/%d: received ul harq/sr: %d, rnti: %d, ueid: %d\n", + i, j, type, tmp->rnti, tmp->UEid); eNB->measurements.n0_subband_power_dB[0][0]=tmp->n0_subband_power_dB; - fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid], - tmp->frame, tmp->subframe, tmp->harq_ack, - tmp->tdd_mapping_mode, tmp->tdd_multiplexing_mask); + + if ( tmp->type == fs6ULindicationHarq ) + fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid], + tmp->frame, tmp->subframe, tmp->harq_ack, + tmp->tdd_mapping_mode, tmp->tdd_multiplexing_mask); + else if ( tmp->type == fs6ULindicationSr ) + fill_sr_indication(tmp->UEid, eNB,tmp->rnti,tmp->frame,tmp->subframe,tmp->stat); + else + LOG_E(PHY, "Split FS6: impossible UL harq type\n"); tmp++; } } else @@ -655,6 +668,13 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { // The configuration arrived in Dl, so we can extract the UL data recvFs6Ul(bufferZone, nbBlocks, eNB); + + // dirty memory allocation in OAI... + for (int i = 0; i < NUMBER_OF_UCI_VARS_MAX; i++) + if ( eNB->uci_vars[i].frame == eNB->proc.frame_rx && + eNB->uci_vars[i].subframe == eNB->proc.subframe_rx ) + eNB->uci_vars[i].active=0; + pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB); } @@ -1025,13 +1045,8 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; if (ulsch->rnti>0) { - LOG_I(PHY,"check in UL scheduled harq %d: rnti %d, tx frame %d/%d, ulsch: %d, %d/%d (handled: %d)\n", + LOG_D(PHY,"check in UL scheduled harq %d: rnti %d, tx frame %d/%d, ulsch: %d, %d/%d (handled: %d)\n", harq_pid, ulsch->rnti, frame, subframe, ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); - - for (int k=0; k<8; k++) - if ( ulsch->harq_processes[k]->status == ACTIVE) - LOG_I(PHY,"check in UL scheduledi (harq_pid %d): rnti %d, tx frame %d/%d, ulsch: %d, %d/%d (handled: %d)\n", k, - ulsch->rnti, frame, subframe, ulsch->harq_processes[k]->status, ulsch->harq_processes[k]->frame, ulsch->harq_processes[k]->subframe, ulsch->harq_processes[k]->handled); } for (int k=0; k<8; k++) { diff --git a/executables/split_headers.h b/executables/split_headers.h index 0fed9d63c8..576a3854a1 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -67,6 +67,8 @@ enum pckType { fs6ULConfigCCH=27, fs6ULsch=28, fs6ULcch=29, + fs6ULindicationHarq=40, + fs6ULindicationSr=41, }; typedef struct { @@ -132,6 +134,7 @@ typedef struct { } fs6_ul_uespec_t; typedef struct { + enum pckType type:8; int UEid; int frame; int subframe; @@ -139,6 +142,8 @@ typedef struct { uint8_t tdd_mapping_mode; uint16_t tdd_multiplexing_mask; unsigned short n0_subband_power_dB; + uint16_t rnti; + int32_t stat; } fs6_ul_uespec_uci_element_t; typedef struct { @@ -174,6 +179,8 @@ static inline void *commonUDPdata(uint8_t *ptr) { } void setAllfromTS(uint64_t TS); +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat); +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen); void *cu_fs6(void *arg); void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index d852248b63..37997c94b4 100644 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -195,7 +195,7 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, pbch_E = (frame_parms->Ncp==NORMAL) ? 1920 : 1728; //RE/RB * #RB * bits/RB (QPSK) // pbch_E_bytes = pbch_coded_bits>>3; - LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4); + LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4==0); if (frame_mod4==0) { bzero(pbch_a,PBCH_A>>3); diff --git a/openair1/PHY/LTE_TRANSPORT/prach_common.c b/openair1/PHY/LTE_TRANSPORT/prach_common.c index 32c37842b5..5f7a904db1 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach_common.c +++ b/openair1/PHY/LTE_TRANSPORT/prach_common.c @@ -36,7 +36,6 @@ #include "common/utils/LOG/vcd_signal_dumper.h" -#define PRACH_DEBUG uint16_t NCS_unrestricted[16] = {0,13,15,18,22,26,32,38,46,59,76,93,119,167,279,419}; uint16_t NCS_restricted[15] = {15,18,22,26,32,38,46,55,68,82,100,128,158,202,237}; // high-speed case uint16_t NCS_4[7] = {2,4,6,8,10,12,15}; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 4caca45acd..e1c68cc055 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -274,7 +274,7 @@ typedef struct { /// Pointers to transport block segments uint8_t *c[MAX_NUM_ULSCH_SEGMENTS]; /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) - uint32_t RTCC[MAX_NUM_ULSCH_SEGMENTS]; + uint32_t RTC[MAX_NUM_ULSCH_SEGMENTS]; /// Current Number of Symbols uint8_t Nsymb_pusch; /// SRS active flag diff --git a/openair1/PHY/LTE_TRANSPORT/uci_tools.c b/openair1/PHY/LTE_TRANSPORT/uci_tools.c index c301c8510f..08addbb635 100644 --- a/openair1/PHY/LTE_TRANSPORT/uci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/uci_tools.c @@ -49,7 +49,9 @@ int16_t find_uci(uint16_t rnti, int frame, int subframe, PHY_VARS_eNB *eNB,find_ else if ((eNB->uci_vars[i].active == 0) && (first_free_index==-1)) first_free_index=i; } if (type == SEARCH_EXIST) return(-1); - else return(first_free_index); + if (first_free_index==-1) + LOG_E(MAC,"UCI table is full\n"); + return(first_free_index); } diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 59fd9b1378..fbbe9eadbe 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -44,9 +44,10 @@ //#define DEBUG_ULSCH_DECODING #include "targets/RT/USER/rt_wrapper.h" #include "transport_proto.h" +#include extern WORKER_CONF_t get_thread_worker_conf(void); -void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen); + void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch) { int i,r; @@ -275,7 +276,7 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { Kr_bytes = Kr>>3; memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTCC[r] = generate_dummy_w(4+(Kr_bytes*8), + ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING @@ -287,7 +288,7 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { ulsch_harq->Nl); #endif - if (lte_rate_matching_turbo_rx(ulsch_harq->RTCC[r], + if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], @@ -449,7 +450,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr Kr_bytes = Kr>>3; memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTCC[r] = generate_dummy_w(4+(Kr_bytes*8), + ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING @@ -462,7 +463,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr #endif start_meas(&eNB->ulsch_rate_unmatching_stats); - if (lte_rate_matching_turbo_rx(ulsch_harq->RTCC[r], + if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], @@ -572,7 +573,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) Kr_bytes = Kr>>3; memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTCC[r] = generate_dummy_w(4+(Kr_bytes*8), + ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING @@ -585,7 +586,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) #endif start_meas(&eNB->ulsch_rate_unmatching_stats); - if (lte_rate_matching_turbo_rx(ulsch_harq->RTCC[r], + if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], @@ -620,8 +621,24 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { // r is the segment id, // Kr is the segment length in short -// *3 because LTE redudancy scheme + // *3 because LTE redudancy scheme sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)*3); + LOG_D(PHY, "Cu should decode in %d iter\n",tc(&ulsch_harq->d[r][96], + NULL, + ulsch_harq->c[r], + NULL, + Kr, + ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, + crc_type, + (r==0) ? ulsch_harq->F : 0, + &eNB->ulsch_tc_init_stats, + &eNB->ulsch_tc_alpha_stats, + &eNB->ulsch_tc_beta_stats, + &eNB->ulsch_tc_gamma_stats, + &eNB->ulsch_tc_ext_stats, + &eNB->ulsch_tc_intl1_stats, + &eNB->ulsch_tc_intl2_stats)); + return 0; } @@ -642,6 +659,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) &eNB->ulsch_tc_intl1_stats, &eNB->ulsch_tc_intl2_stats); stop_meas(&eNB->ulsch_turbo_decoding_stats); + LOG_D(PHY,"turbo decode in %d iter\n",ret); // Reassembly of Transport block here diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 5f8b4ec3db..41c6554c8f 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -720,7 +720,7 @@ void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE) { AssertFatal(1==0,"NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE not handled yet\n"); } else if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE) { - AssertFatal((UE_id = find_uci(ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti, + AssertFatal((UE_id = find_uci(ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti, proc->frame_tx,proc->subframe_tx,eNB,SEARCH_EXIST_OR_FREE))>=0, "No available UE UCI for rnti %x\n",ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti); handle_uci_sr_pdu(eNB,UE_id,ul_config_pdu,frame,subframe,srs_present); diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index 77c254b13f..0314fcc322 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -40,7 +40,7 @@ void fill_uci_harq_indication(int UEid, PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci,int frame,int subframe,uint8_t *harq_ack,uint8_t tdd_mapping_mode,uint16_t tdd_multiplexing_mask); void fill_ulsch_harq_indication(PHY_VARS_eNB *eNB,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti, int frame,int subframe,int bundling); void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti); -void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat); +void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat); void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe); void fill_crc_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe,uint8_t crc_flag); void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t *proc,nfapi_dl_config_request_pdu_t *dl_config_pdu); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 4764ede395..e139994514 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -46,7 +46,7 @@ #include #include "intertask_interface.h" -void sendFs6Ulharq(int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask); +#include nfapi_ue_release_request_body_t release_rntis; @@ -590,7 +590,11 @@ void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { } } -void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { +void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { + if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, frame, subframe, NULL,0,0, rnti, stat); + return; + } pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_sr_indication_t *sr_ind = &eNB->UL_INFO.sr_ind; nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body; @@ -706,7 +710,7 @@ uci_procedures(PHY_VARS_eNB *eNB, if (uci->type == SR) { if (SR_payload == 1) { - fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR); + fill_sr_indication(i, eNB,uci->rnti,frame,subframe,metric_SR); break; } else { break; @@ -742,7 +746,7 @@ uci_procedures(PHY_VARS_eNB *eNB, /* cancel SR detection if reception on n1_pucch0 is better than on SR PUCCH resource index, otherwise send it up to MAC */ if (uci->type==HARQ_SR && metric[0] > metric_SR) SR_payload = 0; - else if (SR_payload == 1) fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR); + else if (SR_payload == 1) fill_sr_indication(i, eNB,uci->rnti,frame,subframe,metric_SR); if (uci->type==HARQ_SR && metric[0] <= metric_SR) { /* when transmitting ACK/NACK on SR PUCCH resource index, SR payload is always 1 */ @@ -793,7 +797,7 @@ uci_procedures(PHY_VARS_eNB *eNB, ); if (uci->type==HARQ_SR && metric[0] > metric_SR) SR_payload = 0; - else if (SR_payload == 1) fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR); + else if (SR_payload == 1) fill_sr_indication(i, eNB,uci->rnti,frame,subframe,metric_SR); if (uci->type==HARQ_SR && metric[0] <= metric_SR) { SR_payload = 1; @@ -1757,7 +1761,7 @@ void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_har void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { - sendFs6Ulharq(UEid, eNB, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask); + sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0); return; } diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index d308486096..c8469adbb2 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -487,7 +487,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo if ( first_sock == FD_SETSIZE ) { // no connected device (we are eNB, no UE is connected) - if (!flushInput(t, 10)) { + if (!flushInput(t, 100)) { for (int x=0; x < nbAnt; x++) memset(samplesVoid[x],0,sampleToByte(nsamps,1)); From f1b677f849e2e72276ed86f617396620c044df42 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 27 Aug 2019 18:47:12 +0200 Subject: [PATCH 032/175] Remove useless differences with regular OAI, enhance the build to be compatible with regular binaries --- cmake_targets/CMakeLists.txt | 10 +++++++++- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 12 ++++++------ openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 2 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 17 ++++++++++++----- openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c | 5 +++++ openair1/SCHED/phy_procedures_lte_eNb.c | 4 ++++ targets/RT/USER/lte-ru.c | 7 +++---- targets/RT/USER/lte-softmodem.c | 5 +---- 8 files changed, 41 insertions(+), 21 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 76be8cf250..fd3364dec8 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1059,6 +1059,10 @@ set(SCHED_SRC add_library(SCHED_LIB ${SCHED_SRC}) add_dependencies(SCHED_LIB rrc_flag) +add_library(SCHED_LIB_FS6 ${SCHED_SRC}) +target_compile_definitions(SCHED_LIB_FS6 PRIVATE FS6=1) +add_dependencies(SCHED_LIB_FS6 rrc_flag) + set(SCHED_SRC_RU ${OPENAIR1_DIR}/SCHED/ru_procedures.c ${OPENAIR1_DIR}/SCHED/prach_procedures.c @@ -1290,6 +1294,9 @@ endif () add_library(PHY_COMMON ${PHY_SRC_COMMON}) add_dependencies(PHY_COMMON rrc_flag) add_library(PHY ${PHY_SRC}) +add_library(PHY_FS6 ${PHY_SRC}) +target_compile_definitions(PHY_FS6 PRIVATE FS6=1) + add_dependencies(PHY rrc_flag) add_library(PHY_UE ${PHY_SRC_UE}) add_dependencies(PHY_UE rrc_flag) @@ -2116,11 +2123,12 @@ add_executable(ocp-softmodem ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} ) +target_compile_definitions(ocp-softmodem PRIVATE FS6=1) add_dependencies(ocp-softmodem rrc_flag s1ap_flag x2_flag) target_link_libraries (ocp-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 + RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB_FS6 SCHED_RU_LIB PHY_COMMON PHY_FS6 PHY_RU LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} LFDS7 NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 476e255fef..29bbd774a1 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -307,7 +307,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0_harq->codeword = 0; dlsch1_harq = dlsch1->harq_processes[rel8->harq_process]; dlsch1_harq->codeword = 1; - //dlsch0->subframe_tx[subframe] = 1; + dlsch0->subframe_tx[subframe] = 1; LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d dlsch0[rnti:%x harq_mask:%04x] dci_pdu[rnti:%x rnti_type:%d harq_process:%d ndi1:%d] dlsch0_harq[round:%d harq_mask:%x ndi:%d]\n", frame,subframe, @@ -658,7 +658,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0_harq->codeword = 0; // printf("DCI: Setting subframe_tx for subframe %d\n",subframe); - //dlsch0->subframe_tx[subframe] = 1; + dlsch0->subframe_tx[subframe] = 1; conv_rballoc (rel8->resource_allocation_type, rel8->resource_block_coding, fp->N_RB_DL, dlsch0_harq->rb_alloc); @@ -868,7 +868,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0_harq = dlsch0->harq_processes[rel8->harq_process]; dlsch1_harq = dlsch1->harq_processes[rel8->harq_process]; - //dlsch0->subframe_tx[subframe] = 1; + dlsch0->subframe_tx[subframe] = 1; dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process; dlsch1->harq_ids[frame%2][subframe] = rel8->harq_process; @@ -1316,7 +1316,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t } if (dlsch0 != NULL) { - //dlsch0->subframe_tx[subframe] = 1; + dlsch0->subframe_tx[subframe] = 1; dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process; } @@ -1723,7 +1723,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,mDCI_ALLOC_t *dc dlsch0_harq->codeword = 0; // printf("DCI: Setting subframe_tx for subframe %d\n",subframe); - //dlsch0->subframe_tx[(subframe + 2) % 10] = 1; + dlsch0->subframe_tx[(subframe + 2) % 10] = 1; LOG_D(PHY,"PDSCH : resource_block_coding %x\n",rel13->resource_block_coding); conv_eMTC_rballoc (rel13->resource_block_coding, @@ -1746,7 +1746,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,mDCI_ALLOC_t *dc dlsch0_harq->dl_power_off = 1; - //dlsch0->subframe_tx[subframe] = 1; + dlsch0->subframe_tx[subframe] = 1; if (dlsch0->rnti != rel13->rnti) { // if rnti of dlsch is not the same as in the config, this is a new entry dlsch0_harq->round = 0; dlsch0->harq_mask =0; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index e1c68cc055..e76939e8af 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -158,7 +158,7 @@ typedef struct { /// HARQ process mask, indicates which processes are currently active uint16_t harq_mask; /// Indicator of TX activation per subframe. Used during PUCCH detection for ACK/NAK. - //uint8_t subframe_tx[10]; + uint8_t subframe_tx[10]; /// First CCE of last PDSCH scheduling per subframe. Again used during PUCCH detection for ACK/NAK. uint8_t nCCE[10]; /// Process ID's per subframe. Used to associate received ACKs on PUSCH/PUCCH to DLSCH harq process ids diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index fbbe9eadbe..cbf1e887b5 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -617,13 +617,13 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) crc_type = CRC24_A; else crc_type = CRC24_B; - +#ifdef FS6 if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { // r is the segment id, // Kr is the segment length in short // *3 because LTE redudancy scheme sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)*3); - LOG_D(PHY, "Cu should decode in %d iter\n",tc(&ulsch_harq->d[r][96], + int iter=tc(&ulsch_harq->d[r][96], NULL, ulsch_harq->c[r], NULL, @@ -637,11 +637,18 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) &eNB->ulsch_tc_gamma_stats, &eNB->ulsch_tc_ext_stats, &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats)); + &eNB->ulsch_tc_intl2_stats); + LOG_D(PHY, "Cu should decode in %d iter\n",iter); + if ( iter == 5 ) { + for (int i=0; i < Kr; i++ ) + printf("%hx:", ulsch_harq->d[r][96+i]); + printf("\n"); + } return 0; } - + + #endif start_meas(&eNB->ulsch_turbo_decoding_stats); ret = tc(&ulsch_harq->d[r][96], NULL, @@ -788,7 +795,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, Q_m = ulsch_harq->Qm; G = nb_rb * (12 * Q_m) * ulsch_harq->Nsymb_pusch; //#ifdef DEBUG_ULSCH_DECODING - LOG_D(PHY,"[PUSCH %d] Frame %d, Subframe %d: ulsch_decoding (Nid_cell %d, rnti %x, x2 %x): A %d, round %d, RV %d, O_r1 %d, O_RI %d, O_ACK %d, G %d, Q_m %d Nsymb_pusch %d nb_rb %d\n", + LOG_D(PHY,"[PUSCH harq %d] Frame %d, Subframe %d: ulsch_decoding (Nid_cell %d, rnti %x, x2 %x): TBS %d, round %d, RV %d, O_r1 %d, O_RI %d, O_ACK %d, G %d, Q_m %d Nsymb_pusch %d nb_rb %d\n", harq_pid, proc->frame_rx,subframe, frame_parms->Nid_cell,ulsch->rnti,x2, diff --git a/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c index cc1f762e70..53c45b2d2f 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c @@ -353,6 +353,11 @@ uint32_t ulsch_encoding(uint8_t *a, (r==0) ? ulsch->harq_processes[harq_pid]->F : 0 ); stop_meas(te_stats); +/* + for (int i=0; i< Kr ; i++ ) + printf("%hx", ulsch->harq_processes[harq_pid]->d[r][96+i]); + printf ("\n"); +*/ #ifdef DEBUG_ULSCH_CODING if (r==0) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index e139994514..13ec2de771 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -591,10 +591,12 @@ void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { } void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { + #ifdef FS6 if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, frame, subframe, NULL,0,0, rnti, stat); return; } + #endif pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_sr_indication_t *sr_ind = &eNB->UL_INFO.sr_ind; nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body; @@ -1760,10 +1762,12 @@ void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_har } void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { + #ifdef FS6 if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0); return; } + #endif int UE_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 89abd12499..b1894be28f 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1202,7 +1202,8 @@ void wakeup_L1s(RU_t *ru) { ru->proc.emulate_rf_busy = 0; } -inline int wakeup_prach_ru(RU_t *ru) { + +void wakeup_prach_ru(RU_t *ru) { int ret; struct timespec wait; int time_ns = 5000000L; @@ -1234,11 +1235,10 @@ inline int wakeup_prach_ru(RU_t *ru) { } else LOG_W(PHY,"RU prach thread busy, skipping\n"); AssertFatal((ret=pthread_mutex_unlock( &ru->proc.mutex_prach ))==0,"mutex_unlock returns %d\n",ret); - return(0); } #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) -inline int wakeup_prach_ru_br(RU_t *ru) { +void wakeup_prach_ru_br(RU_t *ru) { int ret; struct timespec wait; int time_ns = 5000000L; @@ -1264,7 +1264,6 @@ inline int wakeup_prach_ru_br(RU_t *ru) { } else LOG_W(PHY,"RU prach thread busy, skipping\n"); AssertFatal((ret=pthread_mutex_unlock( &ru->proc.mutex_prach_br ))==0,"mutex_unlock returns %d\n",ret); - return(0); } #endif diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 85862f9430..b1d2bd4e3f 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -593,10 +593,7 @@ int main( int argc, char **argv ) { /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks * for monolithic/F1 modes */ - //if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) - //RC.rrc[0]->node_type=ngran_eNB_DU; - - init_pdcp(); + init_pdcp(); if (create_tasks(1) < 0) { printf("cannot create ITTI tasks\n"); From f112de54b1d7b4a56662a22ae0ae085ab45ee5d3 Mon Sep 17 00:00:00 2001 From: laurent Date: Wed, 28 Aug 2019 09:35:27 +0200 Subject: [PATCH 033/175] fix -O3 issue; add FS6_REMOTE_IP to set distant CU or DU --- cmake_targets/CMakeLists.txt | 2 +- executables/main-fs6.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index fd3364dec8..4897146918 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -184,7 +184,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${CMAKE_CU # set a flag for changes in the source code # these changes are related to hardcoded path to include .h files set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -O0") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -O3") set(GIT_BRANCH "UNKNOWN") diff --git a/executables/main-fs6.c b/executables/main-fs6.c index bb88c1d61e..ff932d71ad 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1280,7 +1280,8 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { setAllfromTS(hUDP(bufferZone)->timestamp); PHY_VARS_eNB *eNB = RC.eNB[0][0]; - prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB); + if (is_prach_subframe(&eNB->frame_parms, eNB->proc.frame_prach,eNB->proc.subframe_prach)>0) + prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB); release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -1295,7 +1296,12 @@ void *cu_fs6(void *arg) { init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); wait_sync("ru_thread"); - AssertFatal(createUDPsock(NULL, CU_PORT, CU_IP, DU_PORT, &sockFS6), ""); + char * remoteIP; + if ( getenv("FS6_REMOTE_IP") ) + remoteIP=getenv("FS6_REMOTE_IP"); + else + remoteIP=DU_IP; + AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, DU_PORT, &sockFS6), ""); uint64_t timeStamp=0; while(1) { @@ -1315,7 +1321,12 @@ void *du_fs6(void *arg) { phy_init_RU(ru); openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); wait_sync("ru_thread"); - AssertFatal(createUDPsock(NULL, DU_PORT, DU_IP, CU_PORT, &sockFS6),""); + char * remoteIP; + if ( getenv("FS6_REMOTE_IP") ) + remoteIP=getenv("FS6_REMOTE_IP"); + else + remoteIP=CU_IP; + AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, CU_PORT, &sockFS6), ""); if (ru->start_rf) { if (ru->start_rf(ru) != 0) From 839a7997d18989428b0117458ecff4f6bd650d6b Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 29 Aug 2019 19:22:46 +0200 Subject: [PATCH 034/175] UE attach complete, added traces ulsch coding, remove temporary renaming --- executables/main-fs6.c | 63 ++++++++++++----- executables/split_headers.h | 5 ++ openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 4 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 73 +++++++++++--------- openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c | 15 ++-- openair1/SCHED/phy_procedures_lte_eNb.c | 12 ++-- openair2/LAYER2/MAC/eNB_scheduler_fairRR.c | 2 +- 7 files changed, 107 insertions(+), 67 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index ff932d71ad..aa1b31d67f 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -171,7 +171,8 @@ void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { } } -void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) { +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, + int32_t stat) { static int current_fsf=-1; int fsf=frame*16+subframe; uint8_t *bufferZone=eNB->FS6bufferZone; @@ -201,7 +202,7 @@ void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, in } LOG_D(PHY,"FS6 du, block: %d: adding ul harq/sr: %d, rnti: %d, ueid: %d\n", - curBlock, type, rnti, UEid); + curBlock, type, rnti, UEid); commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(newUDPheader)+1); tmp+=hULUEuci(newUDPheader)->nb_active_ue; @@ -209,8 +210,10 @@ void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, in tmp->UEid=UEid; tmp->frame=frame; tmp->subframe=subframe; + if (harq_ack != NULL) memcpy(tmp->harq_ack, harq_ack, 4); + tmp->tdd_mapping_mode=tdd_mapping_mode; tmp->tdd_multiplexing_mask=tdd_multiplexing_mask; tmp->n0_subband_power_dB=eNB->measurements.n0_subband_power_dB[0][0]; @@ -240,6 +243,9 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ hULUE(newUDPheader)->type=fs6ULsch; hULUE(newUDPheader)->UE_id=UE_id; hULUE(newUDPheader)->harq_id=harq_pid; + memcpy(hULUE(newUDPheader)->ulsch_power, + eNB->pusch_vars[UE_id]->ulsch_power, + sizeof(int)*2); hULUE(newUDPheader)->segment=segmentID; memcpy(hULUE(newUDPheader)+1, data, dataLen); hULUE(newUDPheader)->segLen=dataLen; @@ -444,12 +450,12 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { Kr_bytes = Kr>>3; if (r==0) { - memcpy(ulsch_harq->bb, + memcpy(ulsch_harq->b, &ulsch_harq->c[0][(ulsch_harq->F>>3)], Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); } else { - memcpy(ulsch_harq->bb+offset, + memcpy(ulsch_harq->b+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -638,23 +644,28 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { memcpy(&ulsch_harq->d[hULUE(bufPtr)->segment][96], hULUE(bufPtr)+1, hULUE(bufPtr)->segLen); + memcpy(eNB->pusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power, + hULUE(bufPtr)->ulsch_power, + sizeof(int)*2); LOG_W(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); + for (int j=0; j < nb_uci ; j++) { - LOG_D(PHY,"FS6 cu, block: %d/%d: received ul harq/sr: %d, rnti: %d, ueid: %d\n", - i, j, type, tmp->rnti, tmp->UEid); + LOG_D(PHY,"FS6 cu, block: %d/%d: received ul harq/sr: %d, rnti: %d, ueid: %d\n", + i, j, type, tmp->rnti, tmp->UEid); eNB->measurements.n0_subband_power_dB[0][0]=tmp->n0_subband_power_dB; - - if ( tmp->type == fs6ULindicationHarq ) - fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid], - tmp->frame, tmp->subframe, tmp->harq_ack, - tmp->tdd_mapping_mode, tmp->tdd_multiplexing_mask); - else if ( tmp->type == fs6ULindicationSr ) - fill_sr_indication(tmp->UEid, eNB,tmp->rnti,tmp->frame,tmp->subframe,tmp->stat); - else - LOG_E(PHY, "Split FS6: impossible UL harq type\n"); + + if ( tmp->type == fs6ULindicationHarq ) + fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid], + tmp->frame, tmp->subframe, tmp->harq_ack, + tmp->tdd_mapping_mode, tmp->tdd_multiplexing_mask); + else if ( tmp->type == fs6ULindicationSr ) + fill_sr_indication(tmp->UEid, eNB,tmp->rnti,tmp->frame,tmp->subframe,tmp->stat); + else + LOG_E(PHY, "Split FS6: impossible UL harq type\n"); + tmp++; } } else @@ -668,11 +679,11 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { // The configuration arrived in Dl, so we can extract the UL data recvFs6Ul(bufferZone, nbBlocks, eNB); - + // dirty memory allocation in OAI... for (int i = 0; i < NUMBER_OF_UCI_VARS_MAX; i++) if ( eNB->uci_vars[i].frame == eNB->proc.frame_rx && - eNB->uci_vars[i].subframe == eNB->proc.subframe_rx ) + eNB->uci_vars[i].subframe == eNB->proc.subframe_rx ) eNB->uci_vars[i].active=0; pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB); @@ -739,6 +750,10 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i ulsch_harq->frame = frame; ulsch_harq->subframe = subframe; ulsch_harq->first_rb=hTxULUE(bufPtr)->first_rb; + ulsch_harq->O_RI=hTxULUE(bufPtr)->O_RI; + ulsch_harq->Or1=hTxULUE(bufPtr)->Or1; + ulsch_harq->Msc_initial=hTxULUE(bufPtr)->Msc_initial; + ulsch_harq->Nsymb_initial=hTxULUE(bufPtr)->Nsymb_initial; ulsch_harq->V_UL_DAI=hTxULUE(bufPtr)->V_UL_DAI; ulsch_harq->Qm=hTxULUE(bufPtr)->Qm; ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; @@ -913,6 +928,10 @@ void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE memcpy(hTxULUE(newUDPheader)->cba_rnti,ulsch->cba_rnti,sizeof(ulsch->cba_rnti));//NUM_MAX_CBA_GROUP]; cpyToDu(rnti); cpyToDuHarq(nb_rb); + cpyToDuHarq(Msc_initial); + cpyToDuHarq(Nsymb_initial); + cpyToDuHarq(O_RI); + cpyToDuHarq(Or1); cpyToDuHarq(first_rb); cpyToDuHarq(V_UL_DAI); cpyToDuHarq(Qm); @@ -1280,8 +1299,10 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { setAllfromTS(hUDP(bufferZone)->timestamp); PHY_VARS_eNB *eNB = RC.eNB[0][0]; + if (is_prach_subframe(&eNB->frame_parms, eNB->proc.frame_prach,eNB->proc.subframe_prach)>0) prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB); + release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { @@ -1296,11 +1317,13 @@ void *cu_fs6(void *arg) { init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); wait_sync("ru_thread"); - char * remoteIP; + char *remoteIP; + if ( getenv("FS6_REMOTE_IP") ) remoteIP=getenv("FS6_REMOTE_IP"); else remoteIP=DU_IP; + AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, DU_PORT, &sockFS6), ""); uint64_t timeStamp=0; @@ -1321,11 +1344,13 @@ void *du_fs6(void *arg) { phy_init_RU(ru); openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); wait_sync("ru_thread"); - char * remoteIP; + char *remoteIP; + if ( getenv("FS6_REMOTE_IP") ) remoteIP=getenv("FS6_REMOTE_IP"); else remoteIP=CU_IP; + AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, CU_PORT, &sockFS6), ""); if (ru->start_rf) { diff --git a/executables/split_headers.h b/executables/split_headers.h index 576a3854a1..737358f51f 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -80,6 +80,10 @@ typedef struct { uint16_t nb_rb; uint8_t Qm; uint16_t first_rb; + uint8_t O_RI; + uint8_t Or1; + uint16_t Msc_initial; + uint8_t Nsymb_initial; uint8_t V_UL_DAI; uint8_t srs_active; uint32_t TBS; @@ -131,6 +135,7 @@ typedef struct { short harq_id; short segment; short segLen; + int ulsch_power[2]; } fs6_ul_uespec_t; typedef struct { diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index e76939e8af..dfa2a2f20b 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -266,11 +266,11 @@ typedef struct { /// coded RI bits int16_t q_RI[MAX_RI_PAYLOAD]; /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) - int16_t eE[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); + int16_t e[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); /// Temporary h sequence to flag PUSCH_x/PUSCH_y symbols which are not scrambled uint8_t h[MAX_NUM_CHANNEL_BITS]; /// Pointer to the payload - uint8_t *bb; + uint8_t *b; /// Pointers to transport block segments uint8_t *c[MAX_NUM_ULSCH_SEGMENTS]; /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index cbf1e887b5..663b32b7fb 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -55,9 +55,9 @@ void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch) { if (ulsch) { for (i=0; i<8; i++) { if (ulsch->harq_processes[i]) { - if (ulsch->harq_processes[i]->bb) { - free16(ulsch->harq_processes[i]->bb,MAX_ULSCH_PAYLOAD_BYTES); - ulsch->harq_processes[i]->bb = NULL; + if (ulsch->harq_processes[i]->b) { + free16(ulsch->harq_processes[i]->b,MAX_ULSCH_PAYLOAD_BYTES); + ulsch->harq_processes[i]->b = NULL; } for (r=0; rharq_processes[i]) { memset(ulsch->harq_processes[i],0,sizeof(LTE_UL_eNB_HARQ_t)); - ulsch->harq_processes[i]->bb = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); + ulsch->harq_processes[i]->b = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); - if (ulsch->harq_processes[i]->bb) - memset(ulsch->harq_processes[i]->bb,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); + if (ulsch->harq_processes[i]->b) + memset(ulsch->harq_processes[i]->b,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); else exit_flag=3; @@ -292,7 +292,7 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], - ulsch_harq->eE+r_offset, + ulsch_harq->e+r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -342,7 +342,7 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { Kr = ulsch_harq->Kplus; Kr_bytes = Kr>>3; - memcpy(ulsch_harq->bb+offset, + memcpy(ulsch_harq->b+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -467,7 +467,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], - ulsch_harq->eE+r_offset, + ulsch_harq->e+r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -523,12 +523,12 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr Kr_bytes = Kr>>3; if (r==0) { - memcpy(ulsch_harq->bb, + memcpy(ulsch_harq->b, &ulsch_harq->c[0][(ulsch_harq->F>>3)], Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); } else { - memcpy(ulsch_harq->bb+offset, + memcpy(ulsch_harq->b+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -555,7 +555,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; int G = ulsch_harq->G; - unsigned int EE; + unsigned int E; decoder_if_t *tc; if (llr8_flag == 0) @@ -580,8 +580,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, nb_rb %d, Nl %d)...\n", r, G, Kr*3, - Q_m, - nb_rb, + ulsch_harq->Qm, ulsch_harq->Nl); #endif start_meas(&eNB->ulsch_rate_unmatching_stats); @@ -590,7 +589,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) G, ulsch_harq->w[r], (uint8_t *) &dummy_w[r][0], - ulsch_harq->eE+r_offset, + ulsch_harq->e+r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -600,13 +599,13 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) ulsch_harq->Qm, 1, r, - &EE)==-1) { + &E)==-1) { LOG_E(PHY,"ulsch_decoding.c: Problem in rate matching\n"); return(-1); } stop_meas(&eNB->ulsch_rate_unmatching_stats); - r_offset += EE; + r_offset += E; start_meas(&eNB->ulsch_deinterleaving_stats); sub_block_deinterleaving_turbo(4+Kr, &ulsch_harq->d[r][96], @@ -623,6 +622,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) // Kr is the segment length in short // *3 because LTE redudancy scheme sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)*3); +/* int iter=tc(&ulsch_harq->d[r][96], NULL, ulsch_harq->c[r], @@ -644,7 +644,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) printf("%hx:", ulsch_harq->d[r][96+i]); printf("\n"); } - +*/ return 0; } @@ -679,12 +679,12 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) Kr_bytes = Kr>>3; if (r==0) { - memcpy(ulsch_harq->bb, + memcpy(ulsch_harq->b, &ulsch_harq->c[0][(ulsch_harq->F>>3)], Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); } else { - memcpy(ulsch_harq->bb+offset, + memcpy(ulsch_harq->b+offset, ulsch_harq->c[r], Kr_bytes - ((ulsch_harq->C>1)?3:0)); offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); @@ -794,6 +794,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, A = ulsch_harq->TBS; Q_m = ulsch_harq->Qm; G = nb_rb * (12 * Q_m) * ulsch_harq->Nsymb_pusch; + LOG_D(PHY, "PUSCH nb_rb %d Q_m %d ulsch_harq->Nsymb_pusch %d\n",nb_rb, Q_m, ulsch_harq->Nsymb_pusch); //#ifdef DEBUG_ULSCH_DECODING LOG_D(PHY,"[PUSCH harq %d] Frame %d, Subframe %d: ulsch_decoding (Nid_cell %d, rnti %x, x2 %x): TBS %d, round %d, RV %d, O_r1 %d, O_RI %d, O_ACK %d, G %d, Q_m %d Nsymb_pusch %d nb_rb %d\n", harq_pid, @@ -848,6 +849,12 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, subframe); // Compute Q_ri Qprime = ulsch_harq->O_RI*ulsch_harq->Msc_initial*ulsch_harq->Nsymb_initial * ulsch->beta_offset_ri_times8; + LOG_D(PHY, "Qprime %d, O_RI %d, Msc %d, Nym %d beta %d\n", + Qprime, + ulsch_harq->O_RI, + ulsch_harq->Msc_initial, + ulsch_harq->Nsymb_initial, + ulsch->beta_offset_ri_times8); if (Qprime > 0 ) { if ((Qprime % (8*sumKr)) > 0) @@ -1224,8 +1231,8 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, j2+=2; } - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; } break; @@ -1237,10 +1244,10 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, j2+=4; } - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; } break; @@ -1252,12 +1259,12 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, j2+=6; } - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; - ulsch_harq->eE[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->e[iprime++] = y[j2++]; } break; @@ -1295,7 +1302,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, */ int16_t *yp,*ep; - for (iprime=0,yp=&y[j2],ep=&ulsch_harq->eE[0]; + for (iprime=0,yp=&y[j2],ep=&ulsch_harq->e[0]; iprimeharq_processes[harq_pid]->F : 0 ); stop_meas(te_stats); -/* - for (int i=0; i< Kr ; i++ ) - printf("%hx", ulsch->harq_processes[harq_pid]->d[r][96+i]); - printf ("\n"); -*/ #ifdef DEBUG_ULSCH_CODING if (r==0) @@ -451,6 +446,13 @@ uint32_t ulsch_encoding(uint8_t *a, Qprime = (ulsch->O + L) * ulsch->harq_processes[harq_pid]->Msc_initial*ulsch->harq_processes[harq_pid]->Nsymb_initial * ulsch->beta_offset_cqi_times8; else Qprime = 0; + LOG_D(PHY,"Qprime %d, O_RI %d + %d, Msc %d, Nym %d beta %d\n", + Qprime, + ulsch->O, L, + ulsch->harq_processes[harq_pid]->Msc_initial, + ulsch->harq_processes[harq_pid]->Nsymb_initial, + ulsch->beta_offset_cqi_times8); + if (Qprime > 0) { if ((Qprime % (8*sumKr)) > 0) @@ -460,7 +462,7 @@ uint32_t ulsch_encoding(uint8_t *a, } G = ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); - + LOG_D(PHY,"G: rb %d * ( 12 * Qm %d ) * nsymb %d, Qprime %d, O_RI %d\n", ulsch->harq_processes[harq_pid]->nb_rb, Q_m, ulsch->Nsymb_pusch, Qprime, ulsch->O_RI); if (Qprime > (G - ulsch->O_RI)) Qprime = G - ulsch->O_RI; @@ -470,6 +472,7 @@ uint32_t ulsch_encoding(uint8_t *a, G = G - Q_RI - Q_CQI; + LOG_D(PHY,"new G: %d, Q_RI %d Q_CQI %d\n", G , Q_RI , Q_CQI); ulsch->harq_processes[harq_pid]->G = G; /* diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 13ec2de771..374cbb251a 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -410,10 +410,10 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe); // clear previous allocation information for all UEs - //for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - //if (eNB->dlsch[i][0]) - //eNB->dlsch[i][0]->subframe_tx[subframe] = 0; - //} + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]) + eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + } /* TODO: check the following test - in the meantime it is put back as it was before */ //if ((ul_subframe < 10)&& @@ -549,7 +549,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, #endif ) { // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) - //dlsch0->subframe_tx[subframe]=0; + dlsch0->subframe_tx[subframe]=0; } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); @@ -1424,7 +1424,7 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) { pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation - pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->bb; + pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; // estimate timing advance for MAC sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c index c071c1f505..cc08f4f611 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c @@ -2836,7 +2836,7 @@ void schedule_ulsch_rnti_fairRR(module_id_t module_idP, } if (tpc!=1) { - LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, snr/target snr %d/%d\n", + LOG_D(MAC,"[eNB %d] ULSCH schedulerRR: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, snr/target snr %d/%d\n", module_idP,frameP,subframeP,harq_pid,tpc, tpc_accumulated,snr,target_snr); } From 733d1292c6b11d4174049078bf04cac4b3c015dd Mon Sep 17 00:00:00 2001 From: laurent Date: Wed, 25 Sep 2019 08:28:02 +0200 Subject: [PATCH 035/175] small fixes --- executables/main-ocp.c | 2 +- openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 4 ++-- openair2/LAYER2/MAC/pre_processor.c | 7 +++++-- targets/RT/USER/lte-ue.c | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index b3983463e0..cfec3b336c 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -676,7 +676,7 @@ void rx_rf(RU_t *ru) { proc->first_rx = false; } else { if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { - LOG_E(HW,"impossible shift in RFSIM, rx: %ld, previous rx distance: %ld\n", proc->timestamp_rx, proc->timestamp_rx - old_ts); + LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", proc->timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti); //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); //proc->timestamp_rx = ts-ru->ts_offset; } diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 61a9d50b53..5feb1389be 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -154,7 +154,7 @@ typedef struct { uint8_t active; #endif /// indicator of UE type (0 = LTE, 1,2 = Cat-M) - UE_type_t ue_type; + int ue_type; /// HARQ process mask, indicates which processes are currently active uint16_t harq_mask; /// Indicator of TX activation per subframe. Used during PUCCH detection for ACK/NAK. @@ -456,7 +456,7 @@ typedef struct { typedef struct { #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) /// UE type (normal, CEModeA, CEModeB) - UE_type_t ue_type; + uint8_t ue_type; #endif /// HARQ process mask, indicates which processes are currently active uint16_t harq_mask; diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 0dc11b0e45..1e6b0148a8 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1799,12 +1799,15 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP, } total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n", + LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d, nb_rb_ul %d, %d ,%d\n", nb_allocated_rbs[CC_id][UE_id], UE_id, rntiTable[UE_id], CC_id, - harq_pid); + harq_pid, + UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid], + UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[slice_idx], + average_rbs_per_user[CC_id]); } } diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 42ec7d216d..6c4087d08f 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1644,6 +1644,7 @@ void *UE_thread(void *arg) { pthread_mutex_unlock(&proc->mutex_rxtx); } + usleep(3000); } LOG_D(PHY,"Process Subframe %d thread Idx %d \n", sub_frame, UE->current_thread_id[sub_frame]); From 2aafa61712af1f9d85645262555d570ddc3e0993 Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 29 Sep 2019 18:00:07 +0200 Subject: [PATCH 036/175] fix multi blocks transport issue in fs6, and simulators related ul issue for rfsim --- executables/main-fs6.c | 21 +++++++++++++--- executables/split_headers.h | 1 + executables/transport_split.c | 15 +++++++---- openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c | 4 +-- openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c | 4 +-- openair1/SCHED_UE/phy_procedures_lte_ue.c | 26 +++++++++++--------- targets/ARCH/rfsimulator/simulator.c | 4 +-- 7 files changed, 50 insertions(+), 25 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index aa1b31d67f..2b724ea163 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -21,6 +21,12 @@ #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; +int sum(uint8_t * b, int s) { + int sum=0; + for (int i=0; i < s; i++) + sum+=b[i]; + return sum; +} void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); @@ -647,7 +653,8 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { memcpy(eNB->pusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power, hULUE(bufPtr)->ulsch_power, sizeof(int)*2); - LOG_W(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); + LOG_I(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", + ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); @@ -715,6 +722,7 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i dlsch_harq->Nl=hDLUE(bufPtr)->Nl; dlsch_harq->pdsch_start=hDLUE(bufPtr)->pdsch_start; #ifdef PHY_TX_THREAD + dlsch_harq->CEmode = hDLUE(bufPtr)->CEmode; dlsch_harq->i0=hDLUE(bufPtr)->i0; dlsch_harq->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; #else @@ -723,6 +731,8 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i #endif memcpy(dlsch_harq->e, hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); + LOG_D(PHY,"received %d bits, in harq id: %di fsf: %d.%d, sum %d\n", + hDLUE(bufPtr)->dataLen, hDLUE(bufPtr)->harq_pid, frame, subframe, sum(dlsch_harq->e, hDLUE(bufPtr)->dataLen)); } else if (type == fs6UlConfig) { int nbUE=(((commonUDP_t *)bufPtr)->contentBytes - sizeof(fs6_dl_t)) / sizeof( fs6_dl_ulsched_t ) ; @@ -759,7 +769,8 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; ulsch_harq->TBS=hTxULUE(bufPtr)->TBS; ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch; - LOG_W(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); + LOG_I(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", + ulsch->rnti, frame, subframe); } } else if ( type == fs6ULConfigCCH ) { fs6_dl_uespec_ulcch_element_t *tmp=(fs6_dl_uespec_ulcch_element_t *)(hTxULcch(bufPtr)+1); @@ -979,6 +990,7 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ hDLUE(newUDPheader)->Nl=harqData->Nl; hDLUE(newUDPheader)->pdsch_start=harqData->pdsch_start; #ifdef PHY_TX_THREAD + hDLUE(newUDPheader)->CEmode=harqData->CEmode; hDLUE(newUDPheader)->i0=harqData->i0; hDLUE(newUDPheader)->sib1_br_flag=harqData->sib1_br_flag; #else @@ -987,8 +999,11 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ #endif hDLUE(newUDPheader)->dataLen=UEdataLen; memcpy(hDLUE(newUDPheader)+1, harqData->e, UEdataLen); + LOG_D(PHY,"sending %d bits, in harq id: %di fsf: %d.%d, sum %d\n", + UEdataLen , harq_pid, frame, subframe, sum(harqData->e, UEdataLen)); + //for (int i=0; i < UEdataLen; i++) - //LOG_D(PHY,"buffer e:%hhx\n", ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); + //LOG_D(PHY,"buffer ei[%d]:%hhx\n", i, ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); } void appendFs6DLUEcch(uint8_t *bufferZone, PHY_VARS_eNB *eNB, int frame, int subframe) { diff --git a/executables/split_headers.h b/executables/split_headers.h index 737358f51f..9b67cadd91 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -109,6 +109,7 @@ typedef struct { uint16_t rnti; int16_t sqrt_rho_a; int16_t sqrt_rho_b; + CEmode_t CEmode:8; uint16_t nb_rb; uint8_t Qm; int8_t Nl; diff --git a/executables/transport_split.c b/executables/transport_split.c index 17e40e7e25..07cb67b31a 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -116,9 +116,11 @@ int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t rcved++; bufferZone+=ret; } + LOG_D(HW,"Received: blocks: %d/%d, size %d, TS: %lu\n", + rcved, bufOrigin->nbBlocks, ret, bufOrigin->timestamp); + } while ( rcved == 0 || rcved < bufOrigin->nbBlocks ); - LOG_D(HW,"Received: nb_blocks: %d, TS: %lu\n",rcved, bufOrigin->timestamp); return rcved; } @@ -136,8 +138,10 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui do { if (blockId > 0 ) { commonUDP_t *currentHeader=(commonUDP_t *)bufferZone; - *currentHeader=*UDPheader; + currentHeader->timestamp=UDPheader->timestamp; + currentHeader->nbBlocks=UDPheader->nbBlocks; currentHeader->blockID=blockId; + currentHeader->contentType=UDPheader->contentType; memcpy(commonUDPdata((void *)currentHeader), commonUDPdata(bufferZone), secondHeaderSize); } @@ -151,11 +155,12 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d, %s)\n", sz, ret, errno, strerror(errno)); + LOG_D(HW,"Sent: TS: %lu, blocks %d/%d, block size : %d \n", + UDPheader->timestamp, UDPheader->nbBlocks-nbBlocks, UDPheader->nbBlocks, sz); + bufferZone+=sz; nbBlocks--; } while (nbBlocks); - LOG_D(HW,"Sent: TS: %lu, nb blocks %d, size of first block: %lu \n", - UDPheader->timestamp, UDPheader->nbBlocks, alignedSize((void *)UDPheader)); - return 0; + return 0; } diff --git a/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c index 968597bfb8..100dd3b2f1 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c @@ -590,10 +590,10 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) { LOG_I(PHY,"[UE%d] Initial sync : Estimated power: %d dB\n",ue->Mod_id,ue->measurements.rx_power_avg_dB[0] ); - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) + if (IS_SOFTMODEM_BASICSIM ) phy_adjust_gain(ue,ue->measurements.rx_power_avg_dB[0],0); } else { - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) + if (IS_SOFTMODEM_BASICSIM ) phy_adjust_gain(ue,dB_fixed(ue->measurements.rssi),0); } diff --git a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c index 8139c496ae..49fa484c26 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c @@ -80,7 +80,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 int i, prach_len; uint16_t first_nonzero_root_idx=0; - if ( !(IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM) ) { + if ( !(IS_SOFTMODEM_BASICSIM ) ) { prach_start = (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset); #ifdef PRACH_DEBUG LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, @@ -473,7 +473,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 AssertFatal(prach_fmt<4, "prach_fmt4 not fully implemented" ); - if (!(IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM) ) { + if (!(IS_SOFTMODEM_BASICSIM ) ) { int j; int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*ue->frame_parms.samples_per_tti; LOG_I( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow ); diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index 5da97b3a1a..cbcd72a9c1 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -166,13 +166,16 @@ unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb int gain_dB; double gain_lin; - if (power_dBm<=power_max_dBm) + if ( (power_dBm<=power_max_dBm) && ! IS_SOFTMODEM_RFSIM) gain_dB = power_dBm - power_max_dBm; else gain_dB = 0; gain_lin = pow(10,.1*gain_dB); AssertFatal((nb_rb >0) && (nb_rb <= N_RB_UL),"Illegal nb_rb/N_RB_UL combination (%d/%d)\n",nb_rb,N_RB_UL); + LOG_D(PHY," tx gain: %d = %d * sqrt ( pow(10, 0.1*max(0,%d-%d)) * %d/%d ) (gain lin=%f (dB=%d))\n", + (int)(AMP*sqrt(gain_lin*N_RB_UL/(double)nb_rb)), + AMP, power_dBm, power_max_dBm, N_RB_UL, nb_rb, gain_lin, gain_dB); return((int)(AMP*sqrt(gain_lin*N_RB_UL/(double)nb_rb))); } @@ -1099,7 +1102,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt nsymb = (frame_parms->Ncp == 0) ? 14 : 12; - if (!(IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM) ) { + if (!IS_SOFTMODEM_BASICSIM) { ulsch_start = (ue->rx_offset+subframe_tx*frame_parms->samples_per_tti- ue->hw_timing_advance- ue->timing_advance- @@ -1130,7 +1133,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt } for (aa=0; aanb_antennas_tx; aa++) { - int *Buff = (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM) ? &ue->common_vars.txdata[aa][ulsch_start] :dummy_tx_buffer; + int *Buff = IS_SOFTMODEM_BASICSIM ? &ue->common_vars.txdata[aa][ulsch_start] :dummy_tx_buffer; if (frame_parms->Ncp == 1) { PHY_ofdm_mod(&ue->common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size], @@ -1151,7 +1154,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt &ue->frame_parms); } - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) { + if (IS_SOFTMODEM_BASICSIM ) { apply_7_5_kHz(ue,&ue->common_vars.txdata[aa][ulsch_start],0); apply_7_5_kHz(ue,&ue->common_vars.txdata[aa][ulsch_start],1); } else { @@ -1159,7 +1162,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt apply_7_5_kHz(ue,dummy_tx_buffer,1); } - if (!(IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM) ) { + if (!(IS_SOFTMODEM_BASICSIM ) ) { overflow = ulsch_start - 9*frame_parms->samples_per_tti; for (k=ulsch_start,l=0; ksamples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,ulsch_start+frame_parms->samples_per_tti); k++,l++) { @@ -1259,7 +1262,7 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->prach_resources[eNB_id]->ra_RNTI); ue->tx_total_RE[subframe_tx] = 96; - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) { + if (IS_SOFTMODEM_BASICSIM ) { ue->prach_vars[eNB_id]->amp = get_tx_amp(ue->tx_power_dBm[subframe_tx], ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, @@ -1630,7 +1633,7 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB ue->tx_total_RE[subframe_tx] = nb_rb*12; - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) { + if (IS_SOFTMODEM_BASICSIM ) { tx_amp = AMP; } else { tx_amp = get_tx_amp(ue->tx_power_dBm[subframe_tx], @@ -1704,7 +1707,7 @@ void ue_srs_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8 Po_SRS = ue->tx_power_max_dBm; } - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) { + if (IS_SOFTMODEM_BASICSIM) { tx_amp = AMP; } else { if (ue->mac_enabled==1) { @@ -1942,7 +1945,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->tx_power_dBm[subframe_tx] = Po_PUCCH; ue->tx_total_RE[subframe_tx] = 12; - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) { + if (IS_SOFTMODEM_BASICSIM ) { tx_amp = AMP; } else { tx_amp = get_tx_amp(Po_PUCCH, @@ -2023,7 +2026,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->tx_power_dBm[subframe_tx] = Po_PUCCH; ue->tx_total_RE[subframe_tx] = 12; - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) { + if (IS_SOFTMODEM_BASICSIM ) { tx_amp = AMP; } else { tx_amp = get_tx_amp(Po_PUCCH, @@ -2269,7 +2272,7 @@ void ue_measurement_procedures( // AGC VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_IN); - if (IS_SOFTMODEM_BASICSIM || IS_SOFTMODEM_RFSIM ) + if (IS_SOFTMODEM_BASICSIM ) phy_adjust_gain (ue,dB_fixed(ue->measurements.rssi),0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT); @@ -3325,6 +3328,7 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, pdsch==PDSCH?1:0, dlsch0->harq_processes[harq_pid]->TBS>256?1:0); + LOG_D(PHY,"dlsch turbo decode in %d iter\n", ret); if (LOG_DEBUGFLAG(UE_TIMING)) { stop_meas(&ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]]); LOG_I(PHY, " --> Unscrambling for CW0 %5.3f\n", diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 76f2f3f0fb..36a90994cb 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -430,8 +430,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { b->circularBuf[(index*nbAnt+a)%CirSize].i=0; } } - - LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); + if ( abs(b->th.timestamp-b->lastReceivedTS) > 50 ) + LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); } b->lastReceivedTS=b->th.timestamp; From 3321a3510100fbf51de5f1ed1887cad478aa799e Mon Sep 17 00:00:00 2001 From: laurent Date: Wed, 2 Oct 2019 16:22:47 +0200 Subject: [PATCH 037/175] add DL packet compression --- executables/main-fs6.c | 68 +++++++++++++++++---- executables/split_headers.h | 8 +-- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 4 +- openair1/SCHED_UE/phy_procedures_lte_ue.c | 1 - openair2/LAYER2/MAC/pre_processor.c | 11 +++- openair2/UTIL/OPT/probe.c | 8 ++- 6 files changed, 76 insertions(+), 24 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 2b724ea163..1b060d3eef 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -17,17 +17,54 @@ #include #include #include +#include #define FS6_BUF_SIZE 100*1000 static UDPsock_t sockFS6; -int sum(uint8_t * b, int s) { +int sum(uint8_t *b, int s) { int sum=0; + for (int i=0; i < s; i++) sum+=b[i]; + return sum; } +#define ceil16_bytes(a) ((((a+15)/16)*16)/8) +static void fs6Dlunpack(void *out, void *in, int szUnpacked) { + static uint64_t *lut=NULL; + + if (!lut) { + lut=(uint64_t *) malloc(sizeof(*lut)*256); + + for (int i=0; i <256; i++) + for (int j=0; j<8; j++) + ((uint8_t *)(lut+i))[7-j]=(i>>j)&1; + } + + int64_t *out_64 = (int64_t *)out; + int sz=ceil16_bytes(szUnpacked); + + for (int i=0; ipusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power, hULUE(bufPtr)->ulsch_power, sizeof(int)*2); - LOG_I(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", + LOG_I(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; @@ -722,16 +759,16 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i dlsch_harq->Nl=hDLUE(bufPtr)->Nl; dlsch_harq->pdsch_start=hDLUE(bufPtr)->pdsch_start; #ifdef PHY_TX_THREAD - dlsch_harq->CEmode = hDLUE(bufPtr)->CEmode; + dlsch_harq->CEmode = hDLUE(bufPtr)->CEmode; dlsch_harq->i0=hDLUE(bufPtr)->i0; dlsch_harq->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; #else dlsch0->i0=hDLUE(bufPtr)->i0; dlsch0->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; #endif - memcpy(dlsch_harq->e, - hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); - LOG_D(PHY,"received %d bits, in harq id: %di fsf: %d.%d, sum %d\n", + fs6Dlunpack(dlsch_harq->e, + hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); + LOG_D(PHY,"received %d bits, in harq id: %di fsf: %d.%d, sum %d\n", hDLUE(bufPtr)->dataLen, hDLUE(bufPtr)->harq_pid, frame, subframe, sum(dlsch_harq->e, hDLUE(bufPtr)->dataLen)); } else if (type == fs6UlConfig) { int nbUE=(((commonUDP_t *)bufPtr)->contentBytes - sizeof(fs6_dl_t)) / sizeof( fs6_dl_ulsched_t ) ; @@ -769,7 +806,7 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; ulsch_harq->TBS=hTxULUE(bufPtr)->TBS; ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch; - LOG_I(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", + LOG_I(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); } } else if ( type == fs6ULConfigCCH ) { @@ -971,11 +1008,11 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ harqData->pdsch_start, frame,subframe, 0); - AssertFatal(firstFreeByte+UEdataLen+sizeof(fs6_dl_t) <= bufferZone+FS6_BUF_SIZE, ""); + AssertFatal(firstFreeByte+ceil16_bytes(UEdataLen)+sizeof(fs6_dl_t) <= bufferZone+FS6_BUF_SIZE, ""); commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte; FirstUDPheader->nbBlocks++; newUDPheader->blockID=curBlock; - newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) + UEdataLen; + newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) + ceil16_bytes(UEdataLen); // We skip the fs6 DL header, that is populated by caller // This header will be duplicated during sending hDLUE(newUDPheader)->type=fs6DlConfig; @@ -998,10 +1035,9 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ hDLUE(newUDPheader)->sib1_br_flag=dlsch0->sib1_br_flag; #endif hDLUE(newUDPheader)->dataLen=UEdataLen; - memcpy(hDLUE(newUDPheader)+1, harqData->e, UEdataLen); + fs6Dlpack(hDLUE(newUDPheader)+1, harqData->e, UEdataLen); LOG_D(PHY,"sending %d bits, in harq id: %di fsf: %d.%d, sum %d\n", - UEdataLen , harq_pid, frame, subframe, sum(harqData->e, UEdataLen)); - + UEdataLen, harq_pid, frame, subframe, sum(harqData->e, UEdataLen)); //for (int i=0; i < UEdataLen; i++) //LOG_D(PHY,"buffer ei[%d]:%hhx\n", i, ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); } @@ -1112,7 +1148,13 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci; uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci; memcpy(hDL(bufferZone)->pbch_pdu,eNB->pbch_pdu,4); - LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); + + if ( num_dci <= 8 ) + LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); + else { + LOG_E(PHY, "Num dci too large for current FS6 implementation, reducing to 8 dci (was %d)\n", num_dci); + num_dci=8; + } if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { hDL(bufferZone)->num_pdcch_symbols=num_pdcch_symbols; diff --git a/executables/split_headers.h b/executables/split_headers.h index 9b67cadd91..12dd08beb4 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -55,7 +55,7 @@ typedef struct { uint8_t pbch_pdu[4]; int num_pdcch_symbols; int num_dci; - DCI_ALLOC_t dci_alloc[32]; + DCI_ALLOC_t dci_alloc[8]; int num_mdci; int amp; LTE_eNB_PHICH phich_vars; @@ -133,9 +133,9 @@ typedef struct { typedef struct { enum pckType type:8; short UE_id; - short harq_id; - short segment; - short segLen; + uint8_t harq_id; + uint8_t segment; + int segLen; int ulsch_power[2]; } fs6_ul_uespec_t; diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index c59e71607e..f51fc3035b 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -666,9 +666,9 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) &eNB->ulsch_tc_intl1_stats, &eNB->ulsch_tc_intl2_stats); LOG_D(PHY, "Cu should decode in %d iter\n",iter); - if ( iter == 5 ) { + if ( 1) { //iter == 5 ) { for (int i=0; i < Kr; i++ ) - printf("%hx:", ulsch_harq->d[r][96+i]); + printf("%hhx:", ulsch_harq->d[r][96+i]); printf("\n"); } */ diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index cbcd72a9c1..9e6644def9 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -3328,7 +3328,6 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, pdsch==PDSCH?1:0, dlsch0->harq_processes[harq_pid]->TBS>256?1:0); - LOG_D(PHY,"dlsch turbo decode in %d iter\n", ret); if (LOG_DEBUGFLAG(UE_TIMING)) { stop_meas(&ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]]); LOG_I(PHY, " --> Unscrambling for CW0 %5.3f\n", diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 1e6b0148a8..991c459c24 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1799,7 +1799,7 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP, } total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d, nb_rb_ul %d, %d ,%d\n", + LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d, nb_rb_ul %d, %d ,%d, slice %d, round ul %d\n", nb_allocated_rbs[CC_id][UE_id], UE_id, rntiTable[UE_id], @@ -1807,7 +1807,9 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP, harq_pid, UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid], UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[slice_idx], - average_rbs_per_user[CC_id]); + average_rbs_per_user[CC_id], + slice_idx, + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid]); } } @@ -1833,6 +1835,10 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP, while (UE_template->pre_allocated_nb_rb_ul[slice_idx] > 0 && nb_allocated_rbs[CC_id][UE_id] < UE_template->pre_allocated_nb_rb_ul[slice_idx] && total_remaining_rbs[CC_id] > 0) { + LOG_D(PHY,"in ulsch alloc: prealloc: %d, nb_allocated %d, total remain%d\n", + UE_template->pre_allocated_nb_rb_ul[slice_idx], + nb_allocated_rbs[CC_id][UE_id], + total_remaining_rbs[CC_id]); nb_allocated_rbs[CC_id][UE_id] = cmin(nb_allocated_rbs[CC_id][UE_id] + 1, UE_template->pre_allocated_nb_rb_ul[slice_idx]); total_remaining_rbs[CC_id]--; total_allocated_rbs[CC_id]++; @@ -1902,6 +1908,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_idx] = nb_rbs_allowed_slice(sli->ul[slice_idx].pct, N_RB_UL); int bytes_to_schedule = UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes; + LOG_D(MAC,"ul bytes to schedule: %d-%d\n",UE_template->estimated_ul_buffer, UE_template->scheduled_ul_bytes); if (bytes_to_schedule < 0) bytes_to_schedule = 0; int bits_to_schedule = bytes_to_schedule * 8; diff --git a/openair2/UTIL/OPT/probe.c b/openair2/UTIL/OPT/probe.c index b032784028..32facd6889 100644 --- a/openair2/UTIL/OPT/probe.c +++ b/openair2/UTIL/OPT/probe.c @@ -396,11 +396,15 @@ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size, MAC_Context_Info_t pdu_context; int radioType=FDD_RADIO; - if (RC.eNB[0][0]!=NULL) + if (RC.eNB && RC.eNB[0][0]!=NULL) radioType=RC.eNB[0][0]->frame_parms.frame_type== FDD ? FDD_RADIO:TDD_RADIO; - if (PHY_vars_UE_g[0][0] != NULL) + else if (PHY_vars_UE_g && PHY_vars_UE_g[0][0] != NULL) radioType=PHY_vars_UE_g[0][0]->frame_parms.frame_type== FDD ? FDD_RADIO:TDD_RADIO; + else { + LOG_E(OPT,"not a eNB neither a UE!!! \n"); + return; + } switch (opt_type) { case OPT_WIRESHARK : From 18fb589b7130ad7afd6b22b6a9add523950b5d43 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 7 Oct 2019 13:21:01 +0200 Subject: [PATCH 038/175] fixes: improves throughput --- executables/main-fs6.c | 187 ++++++++++++++++-- executables/split_headers.h | 44 ++++- openair1/PHY/CODING/lte_segmentation.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 5 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 7 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 6 +- targets/ARCH/rfsimulator/stored_node.c | 36 +++- 8 files changed, 263 insertions(+), 26 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 1b060d3eef..dbfa0a4cbb 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -214,7 +214,8 @@ void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { } } -void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, + uint16_t rnti, int32_t stat) { static int current_fsf=-1; int fsf=frame*16+subframe; @@ -254,6 +255,11 @@ void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, in tmp->frame=frame; tmp->subframe=subframe; + if (uci != NULL) + memcpy(&tmp->uci, uci, sizeof(*uci)); + else + tmp->uci.ue_id=0xFFFF; + if (harq_ack != NULL) memcpy(tmp->harq_ack, harq_ack, 4); @@ -289,7 +295,11 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ memcpy(hULUE(newUDPheader)->ulsch_power, eNB->pusch_vars[UE_id]->ulsch_power, sizeof(int)*2); + hULUE(newUDPheader)->cqi_crc_status=eNB->ulsch[UE_id]->harq_processes[harq_pid]->cqi_crc_status; + hULUE(newUDPheader)->ta=lte_est_timing_advance_pusch(eNB, UE_id); hULUE(newUDPheader)->segment=segmentID; + memcpy(hULUE(newUDPheader)->o, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o, + sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o)); memcpy(hULUE(newUDPheader)+1, data, dataLen); hULUE(newUDPheader)->segLen=dataLen; } @@ -433,7 +443,7 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { tc = *decoder8; // This is a new packet, so compute quantities regarding segmentation - //Fixme: very dirty: all the variables produced by let_segmentation are only used localy + // Fixme: very dirty: all the variables produced by let_segmentation are only used localy // Furthermore, variables as 1 letter and global is "time consuming" for everybody !!! ulsch_harq->B = ulsch_harq->TBS+24; lte_segmentation(NULL, @@ -511,15 +521,99 @@ int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { return(ret); } -void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { +void fill_rx_indication_from_split(uint8_t *bufferZone, PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe, ul_propagation_t *ul_propa) { + nfapi_rx_indication_pdu_t *pdu; + int timing_advance_update; + uint32_t harq_pid; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + + if (eNB->ulsch[UE_id]->ue_type > 0) harq_pid = 0; + else +#endif + { + harq_pid = subframe2harq_pid (&eNB->frame_parms, + frame, subframe); + } + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.rx_ind.sfn_sf = frame<<4| subframe; + eNB->UL_INFO.rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + pdu = &eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list[eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus]; + // pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; + pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; + pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; + pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation + pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; + // estimate timing advance for MAC + timing_advance_update = ul_propa[UE_id].ta; + + // if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);} + // if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);} + switch (eNB->frame_parms.N_RB_DL) { + case 6: /* nothing to do */ + break; + + case 15: + timing_advance_update /= 2; + break; + + case 25: + timing_advance_update /= 4; + break; + + case 50: + timing_advance_update /= 8; + break; + + case 75: + timing_advance_update /= 12; + break; + + case 100: + timing_advance_update /= 16; + break; + + default: + abort (); + } + + // put timing advance command in 0..63 range + timing_advance_update += 31; + + if (timing_advance_update < 0) + timing_advance_update = 0; + + if (timing_advance_update > 63) + timing_advance_update = 63; + + pdu->rx_indication_rel8.timing_advance = timing_advance_update; + // estimate UL_CQI for MAC (from antenna port 0 only) + int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 10 * eNB->measurements.n0_subband_power_dB[0][0]; + + if (SNRtimes10 < -640) + pdu->rx_indication_rel8.ul_cqi = 0; + else if (SNRtimes10 > 635) + pdu->rx_indication_rel8.ul_cqi = 255; + else + pdu->rx_indication_rel8.ul_cqi = (640 + SNRtimes10) / 5; + + LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n", + harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance, + timing_advance_update); + eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++; + eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe; + pthread_mutex_unlock(&eNB->UL_INFO_mutex); +} + +void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, ul_propagation_t *ul_propa) { //LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; const int subframe = eNB->proc.subframe_rx; const int frame = eNB->proc.frame_rx; uint32_t harq_pid; uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); - // TBD: read UL data - for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i]; @@ -598,7 +692,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), T_INT(harq_pid)); fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC - fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + fill_rx_indication_from_split(bufferZone, eNB,i,frame,subframe, ul_propa); // indicate SDU to MAC LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", eNB->Mod_id,harq_pid, frame,subframe, i, @@ -631,7 +725,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * } // ulsch in error else { fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC - fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + fill_rx_indication_from_split(bufferZone, eNB,i,frame,subframe, ul_propa); // indicate SDU to MAC ulsch_harq->status = SCH_IDLE; ulsch->harq_mask &= ~(1 << harq_pid); T (T_ENB_PHY_ULSCH_UE_ACK, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (ulsch->rnti), T_INT (harq_pid)); @@ -674,7 +768,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * } // for (i=0; ipusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power, hULUE(bufPtr)->ulsch_power, sizeof(int)*2); - LOG_I(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d\n", - ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx); + ulsch_harq->cqi_crc_status=hULUE(bufPtr)->cqi_crc_status; + memcpy(ulsch_harq->o,hULUE(bufPtr)->o, sizeof(ulsch_harq->o)); + ul_propa[hULUE(bufPtr)->UE_id].ta=hULUE(bufPtr)->ta; + LOG_I(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d, cqi_crc_status %d \n", + ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx, ulsch_harq->cqi_crc_status); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); @@ -701,6 +798,9 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { i, j, type, tmp->rnti, tmp->UEid); eNB->measurements.n0_subband_power_dB[0][0]=tmp->n0_subband_power_dB; + if (tmp->uci.ue_id != 0xFFFF) + memcpy(&eNB->uci_vars[tmp->UEid],&tmp->uci, sizeof(tmp->uci)); + if ( tmp->type == fs6ULindicationHarq ) fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid], tmp->frame, tmp->subframe, tmp->harq_ack, @@ -722,7 +822,8 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB) { void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { // The configuration arrived in Dl, so we can extract the UL data - recvFs6Ul(bufferZone, nbBlocks, eNB); + ul_propagation_t ul_propa[NUMBER_OF_UE_MAX]; + recvFs6Ul(bufferZone, nbBlocks, eNB, ul_propa); // dirty memory allocation in OAI... for (int i = 0; i < NUMBER_OF_UCI_VARS_MAX; i++) @@ -730,7 +831,7 @@ void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PH eNB->uci_vars[i].subframe == eNB->proc.subframe_rx ) eNB->uci_vars[i].active=0; - pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB); + pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB, ul_propa); } void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, int subframe) { @@ -772,6 +873,7 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i hDLUE(bufPtr)->dataLen, hDLUE(bufPtr)->harq_pid, frame, subframe, sum(dlsch_harq->e, hDLUE(bufPtr)->dataLen)); } else if (type == fs6UlConfig) { int nbUE=(((commonUDP_t *)bufPtr)->contentBytes - sizeof(fs6_dl_t)) / sizeof( fs6_dl_ulsched_t ) ; +#define cpyVal(a) memcpy(&ulsch_harq->a,&hTxULUE(bufPtr)->a, sizeof(ulsch_harq->a)) for ( int i=0; i < nbUE; i++ ) { int curUE=hTxULUE(bufPtr)->UE_id; @@ -806,6 +908,36 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active; ulsch_harq->TBS=hTxULUE(bufPtr)->TBS; ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch; + cpyVal(dci_alloc); + cpyVal(rar_alloc); + cpyVal(status); + cpyVal(Msg3_flag); + cpyVal(phich_active); + cpyVal(phich_ACK); + cpyVal(previous_first_rb); + cpyVal(B); + cpyVal(G); + //cpyVal(o); + cpyVal(uci_format); + cpyVal(Or2); + cpyVal(o_RI); + cpyVal(o_ACK); + cpyVal(O_ACK); + //cpyVal(q); + cpyVal(o_RCC); + cpyVal(q_ACK); + cpyVal(q_RI); + cpyVal(RTC); + cpyVal(ndi); + cpyVal(round); + cpyVal(rvidx); + cpyVal(Nl); + cpyVal(n_DMRS); + cpyVal(previous_n_DMRS); + cpyVal(n_DMRS2); + cpyVal(delta_TF); + cpyVal(repetition_number ); + cpyVal(total_number_of_repetitions); LOG_I(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); } @@ -930,6 +1062,7 @@ void phy_procedures_eNB_TX_fromsplit(uint8_t *bufferZone, int nbBlocks, PHY_VARS #define cpyToDu(a) hTxULUE(newUDPheader)->a=ulsch->a #define cpyToDuHarq(a) hTxULUE(newUDPheader)->a=ulsch_harq->a +#define memcpyToDuHarq(a) memcpy(&hTxULUE(newUDPheader)->a,&ulsch_harq->a, sizeof(ulsch_harq->a)); void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE_eNB_ULSCH_t *ulsch, int frame, int subframe) { commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; @@ -986,6 +1119,36 @@ void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE cpyToDuHarq(srs_active); cpyToDuHarq(TBS); cpyToDuHarq(Nsymb_pusch); + memcpyToDuHarq(dci_alloc); + memcpyToDuHarq(rar_alloc); + memcpyToDuHarq(status); + memcpyToDuHarq(Msg3_flag); + memcpyToDuHarq(phich_active); + memcpyToDuHarq(phich_ACK); + memcpyToDuHarq(previous_first_rb); + memcpyToDuHarq(B); + memcpyToDuHarq(G); + //memcpyToDuHarq(o); + memcpyToDuHarq(uci_format); + memcpyToDuHarq(Or2); + memcpyToDuHarq(o_RI); + memcpyToDuHarq(o_ACK); + memcpyToDuHarq(O_ACK); + //memcpyToDuHarq(q); + memcpyToDuHarq(o_RCC); + memcpyToDuHarq(q_ACK); + memcpyToDuHarq(q_RI); + memcpyToDuHarq(RTC); + memcpyToDuHarq(ndi); + memcpyToDuHarq(round); + memcpyToDuHarq(rvidx); + memcpyToDuHarq(Nl); + memcpyToDuHarq(n_DMRS); + memcpyToDuHarq(previous_n_DMRS); + memcpyToDuHarq(n_DMRS2); + memcpyToDuHarq(delta_TF); + memcpyToDuHarq(repetition_number ); + memcpyToDuHarq(total_number_of_repetitions); LOG_W(PHY,"Added request to perform ulsch for: rnti:%d, fsf: %d/%d\n", ulsch->rnti, frame, subframe); } void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_t harq_pid, LTE_eNB_DLSCH_t *dlsch0, LTE_DL_eNB_HARQ_t *harqData, int frame, int subframe) { diff --git a/executables/split_headers.h b/executables/split_headers.h index 12dd08beb4..87c8176b9a 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -76,6 +76,39 @@ typedef struct { uint16_t UE_id; int8_t harq_pid; UE_type_t ue_type; + + uint8_t dci_alloc; + uint8_t rar_alloc; + SCH_status_t status; + uint8_t Msg3_flag; + uint8_t subframe; + uint32_t frame; + uint8_t handled; + uint8_t phich_active; + uint8_t phich_ACK; + uint16_t previous_first_rb; + uint32_t B; + uint32_t G; + UCI_format_t uci_format; + uint8_t Or2; + uint8_t o_RI[2]; + uint8_t o_ACK[4]; + uint8_t O_ACK; + uint8_t o_RCC; + int16_t q_ACK[MAX_ACK_PAYLOAD]; + int16_t q_RI[MAX_RI_PAYLOAD]; + uint32_t RTC[MAX_NUM_ULSCH_SEGMENTS]; + uint8_t ndi; + uint8_t round; + uint8_t rvidx; + uint8_t Nl; + uint8_t n_DMRS; + uint8_t previous_n_DMRS; + uint8_t n_DMRS2; + int32_t delta_TF; + uint32_t repetition_number ; + uint32_t total_number_of_repetitions; + uint16_t harq_mask; uint16_t nb_rb; uint8_t Qm; @@ -130,6 +163,10 @@ typedef struct { int16_t nb_active_ue; } fs6_dl_uespec_ulcch_t; +typedef struct { + int ta; +} ul_propagation_t; + typedef struct { enum pckType type:8; short UE_id; @@ -137,6 +174,9 @@ typedef struct { uint8_t segment; int segLen; int ulsch_power[2]; + int ta; + uint8_t o[MAX_CQI_BYTES]; + uint8_t cqi_crc_status; } fs6_ul_uespec_t; typedef struct { @@ -144,6 +184,7 @@ typedef struct { int UEid; int frame; int subframe; + LTE_eNB_UCI uci; uint8_t harq_ack[4]; uint8_t tdd_mapping_mode; uint16_t tdd_multiplexing_mask; @@ -185,7 +226,8 @@ static inline void *commonUDPdata(uint8_t *ptr) { } void setAllfromTS(uint64_t TS); -void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat); +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, + uint16_t rnti, int32_t stat); void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen); void *cu_fs6(void *arg); void *du_fs6(void *arg); diff --git a/openair1/PHY/CODING/lte_segmentation.c b/openair1/PHY/CODING/lte_segmentation.c index 5116c765b8..6a38707580 100644 --- a/openair1/PHY/CODING/lte_segmentation.c +++ b/openair1/PHY/CODING/lte_segmentation.c @@ -105,7 +105,7 @@ int lte_segmentation(unsigned char *input_buffer, #endif *Kminus = (*Kplus - 64); } else { - printf("lte_segmentation.c: Illegal codeword size !!!\n"); + LOG_E(PHY,"lte_segmentation.c: Illegal codeword size !!!\n"); return(-1); } diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 0b35e98a0b..a6b546679a 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -593,7 +593,7 @@ void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { #ifdef FS6 if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { - sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, frame, subframe, NULL,0,0, rnti, stat); + sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, NULL, frame, subframe, NULL,0,0, rnti, stat); return; } #endif @@ -609,6 +609,7 @@ void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = rnti; int SNRtimes10 = dB_fixed_times10(stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0]; + LOG_D(PHY,"stat %d subbandpower %d, SNRtimes10 %d\n", stat, eNB->measurements.n0_subband_power_dB[0][0], SNRtimes10); pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0; @@ -1769,7 +1770,7 @@ void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_har void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { #ifdef FS6 if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { - sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0); + sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, uci, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0); return; } #endif diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 134089dbf4..2c317900bf 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -1506,7 +1506,7 @@ schedule_ue_spec(module_id_t module_idP, tpc = 1; //0 } - LOG_D(MAC, "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, snr/target snr %d/%d\n", + LOG_D(MAC, "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, snr/target snr %d/%d (normal case)\n", module_idP, frameP, subframeP, diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 63f838f652..784e413f37 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -4990,7 +4990,12 @@ cqi_indication(module_id_t mod_idP, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); - +/* + int sum=0; + for (int i=0; i length; i++) + sum+=pdu[i]; + LOG_D(MAC, "pdu for channel: %d, checksum: %d\n", ul_cqi_information->channel, sum); +*/ if (ul_cqi_information->channel == 0) { // PUCCH // extract pucch csi information before changing RI information extract_pucch_csi(mod_idP, diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index dc1799ccb6..424e23c6da 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -127,14 +127,16 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) { } else if (UE_NAS_USE_TUN) { ret = write(nas_sock_fd[ctxt_pP->module_id], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); } else if (ENB_NAS_USE_TUN) { - ret = write(nas_sock_fd[0], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite ); + if ((ret = write(nas_sock_fd[0], &(sdu_p->data[sizeof(pdcp_data_ind_header_t)]),sizeToWrite )) != sizeToWrite) { + printf("ret: %d\n",ret); + } } else if (PDCP_USE_NETLINK) { memcpy(NLMSG_DATA(nas_nlh_tx), (uint8_t *) sdu_p->data, sizeToWrite); nas_nlh_tx->nlmsg_len = sizeToWrite; ret = sendmsg(nas_sock_fd[0],&nas_msg_tx,0); } // PDCP_USE_NETLINK - AssertFatal(ret >= 0,"[PDCP_FIFOS] pdcp_fifo_flush_sdus (errno: %d %s)\n", errno, strerror(errno)); + if(ret < 0) LOG_E(PDCP,"[PDCP_FIFOS] pdcp_fifo_flush_sdus (ret (instead of: %d) : %d, errno: %d %s)\n", ret, sizeToWrite, errno, strerror(errno)); list_remove_head (&pdcp_sdu_list); free_mem_block (sdu_p, __func__); pdcp_nb_sdu_sent ++; diff --git a/targets/ARCH/rfsimulator/stored_node.c b/targets/ARCH/rfsimulator/stored_node.c index 8cf3aa3bb2..07d6861d57 100644 --- a/targets/ARCH/rfsimulator/stored_node.c +++ b/targets/ARCH/rfsimulator/stored_node.c @@ -7,6 +7,21 @@ volatile int oai_exit = 0; +int fullread(int fd, void *_buf, int count) +{ + char *buf = _buf; + int ret = 0; + int l; + while (count) { + l = read(fd, buf, count); + if (l <= 0) return -1; + count -= l; + buf += l; + ret += l; + } + return ret; +} + void fullwrite(int fd, void *_buf, int count) { char *buf = _buf; int l; @@ -63,10 +78,10 @@ sin_addr: bool connected=false; while(!connected) { - LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", IP, port); + //LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", IP, port); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { - LOG_I(HW,"rfsimulator: connection established\n"); + //LOG_I(HW,"rfsimulator: connection established\n"); connected=true; } @@ -108,12 +123,13 @@ int main(int argc, char *argv[]) { if (strcmp(argv[2],"server")==0) { serviceSock=server_start(atoi(argv[3])); } else { - client_start(argv[2],atoi(argv[3])); + serviceSock=client_start(argv[2],atoi(argv[3])); } samplesBlockHeader_t header; int bufSize=100000; void *buff=malloc(bufSize); + uint64_t readTS=0; while (1) { //Rewind the file to loop on the samples @@ -125,6 +141,7 @@ int main(int argc, char *argv[]) { AssertFatal(read(fd,&header,sizeof(header)), ""); fullwrite(serviceSock, &header, sizeof(header)); int dataSize=sizeof(int32_t)*header.size*header.nbAnt; + uint64_t wroteTS=header.timestamp; if (dataSize>bufSize) { void * new_buff = realloc(buff, dataSize); @@ -139,9 +156,16 @@ int main(int argc, char *argv[]) { AssertFatal(read(fd,buff,dataSize) == dataSize, ""); fullwrite(serviceSock, buff, dataSize); // Purge incoming samples - setblocking(serviceSock, notBlocking); - - while(recv(serviceSock,buff, bufSize, MSG_DONTWAIT) > 0) { + setblocking(serviceSock, blocking); + while(readTS < wroteTS) { + if ( fullread(serviceSock, &header,sizeof(header)) != sizeof(header) || + fullread(serviceSock, buff, sizeof(int32_t)*header.size*header.nbAnt) != + sizeof(int32_t)*header.size*header.nbAnt + ) { + printf("error: %s\n", strerror(errno)); + exit(1); + } + readTS=header.timestamp; } } From 2fc638464233baf81b811ecbdd434b7ec583cbc2 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 7 Oct 2019 17:56:46 +0200 Subject: [PATCH 039/175] first version with UL and DL traffic good throughput --- executables/main-fs6.c | 18 ++++++++++++------ executables/split_headers.h | 2 ++ openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 2 +- openair2/PHY_INTERFACE/IF_Module.c | 6 +++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index dbfa0a4cbb..edd3f24f05 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -19,7 +19,7 @@ #include #include -#define FS6_BUF_SIZE 100*1000 +#define FS6_BUF_SIZE 1000*1000 static UDPsock_t sockFS6; int sum(uint8_t *b, int s) { @@ -296,6 +296,9 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ eNB->pusch_vars[UE_id]->ulsch_power, sizeof(int)*2); hULUE(newUDPheader)->cqi_crc_status=eNB->ulsch[UE_id]->harq_processes[harq_pid]->cqi_crc_status; + hULUE(newUDPheader)->O_ACK=eNB->ulsch[UE_id]->harq_processes[harq_pid]->O_ACK; + memcpy(hULUE(newUDPheader)->o_ACK, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK, + sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK)); hULUE(newUDPheader)->ta=lte_est_timing_advance_pusch(eNB, UE_id); hULUE(newUDPheader)->segment=segmentID; memcpy(hULUE(newUDPheader)->o, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o, @@ -379,7 +382,7 @@ void pusch_procedures_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eN } void phy_procedures_eNB_uespec_RX_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { - //RX processing for ue-specific resources (i + //RX processing for ue-specific resources LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; @@ -785,10 +788,13 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagat hULUE(bufPtr)->ulsch_power, sizeof(int)*2); ulsch_harq->cqi_crc_status=hULUE(bufPtr)->cqi_crc_status; + //ulsch_harq->O_ACK= hULUE(bufPtr)->O_ACK; + memcpy(ulsch_harq->o_ACK, hULUE(bufPtr)->o_ACK, + sizeof(ulsch_harq->o_ACK)); memcpy(ulsch_harq->o,hULUE(bufPtr)->o, sizeof(ulsch_harq->o)); ul_propa[hULUE(bufPtr)->UE_id].ta=hULUE(bufPtr)->ta; - LOG_I(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d, cqi_crc_status %d \n", - ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx, ulsch_harq->cqi_crc_status); + LOG_D(PHY,"Received ulsch data for: rnti:%d, fsf: %d/%d, cqi_crc_status %d O_ACK: %di, segment: %di, seglen: %d \n", + ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment , hULUE(bufPtr)->segLen); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); @@ -938,8 +944,8 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i cpyVal(delta_TF); cpyVal(repetition_number ); cpyVal(total_number_of_repetitions); - LOG_I(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d\n", - ulsch->rnti, frame, subframe); + LOG_D(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d, O_ACK: %d\n", + ulsch->rnti, frame, subframe, ulsch_harq->O_ACK); } } else if ( type == fs6ULConfigCCH ) { fs6_dl_uespec_ulcch_element_t *tmp=(fs6_dl_uespec_ulcch_element_t *)(hTxULcch(bufPtr)+1); diff --git a/executables/split_headers.h b/executables/split_headers.h index 87c8176b9a..04e70bb469 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -174,6 +174,8 @@ typedef struct { uint8_t segment; int segLen; int ulsch_power[2]; + uint8_t o_ACK[4]; + uint8_t O_ACK; int ta; uint8_t o[MAX_CQI_BYTES]; uint8_t cqi_crc_status; diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index f51fc3035b..c4b8dc7755 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -672,7 +672,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) printf("\n"); } */ - return 0; + continue; } #endif diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index 2cc43189c6..98d099add8 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -388,10 +388,10 @@ static void dump_ul(UL_IND_t *u) { A("XXXX crc_ind %d\n", u->crc_ind.crc_indication_body.number_of_crcs); A("XXXX sr_ind %d\n", u->sr_ind.sr_indication_body.number_of_srs); - A("XXXX cqi_ind %d\n", u->cqi_ind.number_of_cqis); + A("XXXX cqi_ind %d\n", u->cqi_ind.cqi_indication_body.number_of_cqis); - for (i = 0; i < u->cqi_ind.number_of_cqis; i++) { - nfapi_cqi_indication_pdu_t *v = &u->cqi_ind.cqi_pdu_list[i]; + for (i = 0; i < u->cqi_ind.cqi_indication_body.number_of_cqis; i++) { + nfapi_cqi_indication_pdu_t *v = &u->cqi_ind.cqi_indication_body.cqi_pdu_list[i]; A("XXXX cqi ind %d\n", i); A("XXXX cqi ul_cqi %d channel %d\n", v->ul_cqi_information.ul_cqi, v->ul_cqi_information.channel); From 93f6e2446b4a094f2d1f8653e67a61f716008a2a Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 16 Oct 2019 18:01:40 +0200 Subject: [PATCH 040/175] CI: increasing the repeat count since the 1st try will always fail Signed-off-by: Raphael Defosseux --- ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml index 5843539f72..2d34439ef7 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml @@ -25,7 +25,7 @@ test-05-tm1 Test-05MHz-TM1 tasks - 2 + 4 030201 040101 030102 000002 040301 000002 040504 000001 040401 000002 030201 From 2e0890751307ab9353067285d0aa57a20e169148 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 11:14:23 +0200 Subject: [PATCH 041/175] Move split 6 to do rate matching (puncturing) in CU --- enb.fs6.example.conf | 4 +- executables/main-fs6.c | 138 ++++---------------- executables/split_headers.h | 4 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 69 +++------- 4 files changed, 48 insertions(+), 167 deletions(-) diff --git a/enb.fs6.example.conf b/enb.fs6.example.conf index 6102f91756..d5e5609dd0 100644 --- a/enb.fs6.example.conf +++ b/enb.fs6.example.conf @@ -276,9 +276,9 @@ rfsimulator : global_log_verbosity ="medium"; hw_log_level ="info"; hw_log_verbosity ="medium"; - phy_log_level ="info"; + phy_log_level ="debug"; phy_log_verbosity ="medium"; - mac_log_level ="info"; + mac_log_level ="debug"; mac_log_verbosity ="high"; rlc_log_level ="info"; rlc_log_verbosity ="medium"; diff --git a/executables/main-fs6.c b/executables/main-fs6.c index df1c2810cd..8e57e75c6a 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -272,7 +272,8 @@ void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI * newUDPheader->contentBytes+=sizeof(fs6_ul_uespec_uci_element_t); } -void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen) { + +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) { uint8_t *bufferZone=eNB->FS6bufferZone; commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; // move to the end @@ -298,13 +299,15 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ hULUE(newUDPheader)->cqi_crc_status=eNB->ulsch[UE_id]->harq_processes[harq_pid]->cqi_crc_status; hULUE(newUDPheader)->O_ACK=eNB->ulsch[UE_id]->harq_processes[harq_pid]->O_ACK; memcpy(hULUE(newUDPheader)->o_ACK, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK, - sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK)); + sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK)); hULUE(newUDPheader)->ta=lte_est_timing_advance_pusch(eNB, UE_id); hULUE(newUDPheader)->segment=segmentID; memcpy(hULUE(newUDPheader)->o, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o, sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o)); memcpy(hULUE(newUDPheader)+1, data, dataLen); hULUE(newUDPheader)->segLen=dataLen; + hULUE(newUDPheader)->r_offset=r_offset; + hULUE(newUDPheader)->G=eNB->ulsch[UE_id]->harq_processes[harq_pid]->G; } void pusch_procedures_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { @@ -427,102 +430,6 @@ void phy_procedures_eNB_uespec_RX_tosplit(uint8_t *bufferZone, int bufSize, PHY_ return; } -int ulsch_decoding_process(PHY_VARS_eNB *eNB, int UE_id, int llr8_flag) { - int harq_pid; - LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; - - if (ulsch->ue_type>0) - harq_pid = 0; - else - harq_pid = subframe2harq_pid(&eNB->frame_parms,eNB->proc.frame_rx,eNB->proc.subframe_rx); - - LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - decoder_if_t *tc; - int offset, ret=-1; - - if (llr8_flag == 0) - tc = *decoder16; - else - tc = *decoder8; - - // This is a new packet, so compute quantities regarding segmentation - // Fixme: very dirty: all the variables produced by let_segmentation are only used localy - // Furthermore, variables as 1 letter and global is "time consuming" for everybody !!! - ulsch_harq->B = ulsch_harq->TBS+24; - lte_segmentation(NULL, - NULL, - ulsch_harq->B, - &ulsch_harq->C, - &ulsch_harq->Cplus, - &ulsch_harq->Cminus, - &ulsch_harq->Kplus, - &ulsch_harq->Kminus, - &ulsch_harq->F); - - for (int r=0; rC; r++) { - // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); - // Get Turbo interleaver parameters - int Kr; - - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - int Kr_bytes = Kr>>3; - int crc_type; - - if (ulsch_harq->C == 1) - crc_type = CRC24_A; - else - crc_type = CRC24_B; - - start_meas(&eNB->ulsch_turbo_decoding_stats); - ret = tc(&ulsch_harq->d[r][96], - NULL, - ulsch_harq->c[r], - NULL, - Kr, - ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, - crc_type, - (r==0) ? ulsch_harq->F : 0, - &eNB->ulsch_tc_init_stats, - &eNB->ulsch_tc_alpha_stats, - &eNB->ulsch_tc_beta_stats, - &eNB->ulsch_tc_gamma_stats, - &eNB->ulsch_tc_ext_stats, - &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats); - stop_meas(&eNB->ulsch_turbo_decoding_stats); - - // Reassembly of Transport block here - - if (ret != (1+ulsch->max_turbo_iterations)) { - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - - if (r==0) { - memcpy(ulsch_harq->b, - &ulsch_harq->c[0][(ulsch_harq->F>>3)], - Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); - offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); - } else { - memcpy(ulsch_harq->b+offset, - ulsch_harq->c[r], - Kr_bytes - ((ulsch_harq->C>1)?3:0)); - offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); - } - } else { - break; - } - } - - return(ret); -} void fill_rx_indication_from_split(uint8_t *bufferZone, PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe, ul_propagation_t *ul_propa) { nfapi_rx_indication_pdu_t *pdu; @@ -645,16 +552,19 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * } start_meas(&eNB->ulsch_decoding_stats); - /* - int ret = ulsch_decoding(eNB,&eNB->proc.L1_proc, - i, - 0, // control_only_flag - ulsch_harq->V_UL_DAI, - ulsch_harq->nb_rb>20 ? 1 : 0); - */ - int ret = ulsch_decoding_process(eNB, - i, - ulsch_harq->nb_rb>20 ? 1 : 0); + // This is a new packet, so compute quantities regarding segmentation + ulsch_harq->B = ulsch_harq->TBS+24; + lte_segmentation(NULL, + NULL, + ulsch_harq->B, + &ulsch_harq->C, + &ulsch_harq->Cplus, + &ulsch_harq->Cminus, + &ulsch_harq->Kplus, + &ulsch_harq->Kminus, + &ulsch_harq->F); + int ret = ulsch_decoding_data(eNB, i, harq_pid, + ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); LOG_D(PHY, "[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n", @@ -781,20 +691,21 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagat if ( type == fs6ULsch) { LTE_eNB_ULSCH_t *ulsch =eNB->ulsch[hULUE(bufPtr)->UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hULUE(bufPtr)->harq_id]; - memcpy(&ulsch_harq->d[hULUE(bufPtr)->segment][96], + memcpy(ulsch_harq->e+hULUE(bufPtr)->r_offset, hULUE(bufPtr)+1, hULUE(bufPtr)->segLen); memcpy(eNB->pusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power, hULUE(bufPtr)->ulsch_power, sizeof(int)*2); + ulsch_harq->G=hULUE(bufPtr)->G; ulsch_harq->cqi_crc_status=hULUE(bufPtr)->cqi_crc_status; - //ulsch_harq->O_ACK= hULUE(bufPtr)->O_ACK; - memcpy(ulsch_harq->o_ACK, hULUE(bufPtr)->o_ACK, - sizeof(ulsch_harq->o_ACK)); + //ulsch_harq->O_ACK= hULUE(bufPtr)->O_ACK; + memcpy(ulsch_harq->o_ACK, hULUE(bufPtr)->o_ACK, + sizeof(ulsch_harq->o_ACK)); memcpy(ulsch_harq->o,hULUE(bufPtr)->o, sizeof(ulsch_harq->o)); ul_propa[hULUE(bufPtr)->UE_id].ta=hULUE(bufPtr)->ta; LOG_D(PHY,"Received ulsch data for: rnti:%x, fsf: %d/%d, cqi_crc_status %d O_ACK: %di, segment: %di, seglen: %d \n", - ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment , hULUE(bufPtr)->segLen); + ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment, hULUE(bufPtr)->segLen); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); @@ -1157,6 +1068,7 @@ void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE memcpyToDuHarq(total_number_of_repetitions); LOG_D(PHY,"Added request to perform ulsch for: rnti:%x, fsf: %d/%d\n", ulsch->rnti, frame, subframe); } + void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_t harq_pid, LTE_eNB_DLSCH_t *dlsch0, LTE_DL_eNB_HARQ_t *harqData, int frame, int subframe) { commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone; // move to the end diff --git a/executables/split_headers.h b/executables/split_headers.h index 673628b8e0..4a8afc9c85 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -173,6 +173,8 @@ typedef struct { uint8_t harq_id; uint8_t segment; int segLen; + int r_offset; + int G; int ulsch_power[2]; uint8_t o_ACK[4]; uint8_t O_ACK; @@ -230,7 +232,7 @@ static inline void *commonUDPdata(uint8_t *ptr) { void setAllfromTS(uint64_t TS); void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat); -void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen); +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset); void *cu_fs6(void *arg); void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 5d39076d08..f7bea46744 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -279,14 +279,6 @@ int ulsch_decoding_data_2thread0(td_params *tdp) { ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); -#ifdef DEBUG_ULSCH_DECODING - printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, nb_rb %d, Nl %d)...\n", - r, G, - Kr*3, - Q_m, - nb_rb, - ulsch_harq->Nl); -#endif if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, @@ -453,14 +445,6 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); -#ifdef DEBUG_ULSCH_DECODING - printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, nb_rb %d, Nl %d)...\n", - r, G, - Kr*3, - Q_m, - nb_rb, - ulsch_harq->Nl); -#endif start_meas(&eNB->ulsch_rate_unmatching_stats); if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], @@ -583,13 +567,29 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) (uint8_t *)&dummy_w[r][0], (r==0) ? ulsch_harq->F : 0); #ifdef DEBUG_ULSCH_DECODING - printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, nb_rb %d, Nl %d)...\n", + printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, Nl %d, r_offset %d)...\n", r, G, Kr*3, ulsch_harq->Qm, - ulsch_harq->Nl); + ulsch_harq->Nl, r_offset); #endif start_meas(&eNB->ulsch_rate_unmatching_stats); + #ifdef FS6 + if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + int Gp=G/ulsch_harq->Qm; + int GpmodC = Gp%ulsch_harq->C; + + if (r < (ulsch_harq->C-(GpmodC))) + E = ulsch_harq->Qm * (Gp/ulsch_harq->C); + else + E = ulsch_harq->Qm * ((GpmodC==0?0:1) + (Gp/ulsch_harq->C)); + sendFs6Ul(eNB, UE_id, harq_pid, r, ulsch_harq->e+r_offset, E*sizeof(int16_t), r_offset); + + r_offset += E; + continue; + } + + #endif if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, @@ -639,39 +639,6 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) crc_type = CRC24_A; else crc_type = CRC24_B; -#ifdef FS6 - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { - // r is the segment id, - // Kr is the segment length in short - // *3 because LTE redudancy scheme - sendFs6Ul(eNB, UE_id, harq_pid, r, &ulsch_harq->d[r][96], Kr*sizeof(int16_t)*3); -/* - int iter=tc(&ulsch_harq->d[r][96], - NULL, - ulsch_harq->c[r], - NULL, - Kr, - ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, - crc_type, - (r==0) ? ulsch_harq->F : 0, - &eNB->ulsch_tc_init_stats, - &eNB->ulsch_tc_alpha_stats, - &eNB->ulsch_tc_beta_stats, - &eNB->ulsch_tc_gamma_stats, - &eNB->ulsch_tc_ext_stats, - &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats); - LOG_D(PHY, "Cu should decode in %d iter\n",iter); - if ( 1) { //iter == 5 ) { - for (int i=0; i < Kr; i++ ) - printf("%hhx:", ulsch_harq->d[r][96+i]); - printf("\n"); - } -*/ - continue; - } - - #endif start_meas(&eNB->ulsch_turbo_decoding_stats); ret = tc(&ulsch_harq->d[r][96], NULL, From 61041b4275a546cd94fdd33bd98925a22f353e06 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 15:04:20 +0200 Subject: [PATCH 042/175] add du measurements --- enb.fs6.example.conf | 4 ++-- executables/main-fs6.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/enb.fs6.example.conf b/enb.fs6.example.conf index d5e5609dd0..6102f91756 100644 --- a/enb.fs6.example.conf +++ b/enb.fs6.example.conf @@ -276,9 +276,9 @@ rfsimulator : global_log_verbosity ="medium"; hw_log_level ="info"; hw_log_verbosity ="medium"; - phy_log_level ="debug"; + phy_log_level ="info"; phy_log_verbosity ="medium"; - mac_log_level ="debug"; + mac_log_level ="info"; mac_log_verbosity ="high"; rlc_log_level ="info"; rlc_log_verbosity ="medium"; diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 8e57e75c6a..074b4c8770 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1497,10 +1497,18 @@ void *du_fs6(void *arg) { else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + initStaticTime(begingWait); + initRefTimes(waitRxAndProcessingUL); + initRefTimes(makeSendDL); + while(1) { L1_proc_t *proc = &ru->eNB_list[0]->proc; + pickStaticTime(begingWait); UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); + updateTimes(begingWait, &waitRxAndProcessingUL, 1000, "DU Time in wait Rx + Ul processing"); + pickStaticTime(begingWait); DL_du_fs6(ru); + updateTimes(begingWait, &makeSendDL, 1000, "DU Time in build and send Tx"); } return NULL; From 80b89510b7d41673cef6783bca87a358f6399754 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 15:15:19 +0200 Subject: [PATCH 043/175] add cu and full loop measurements --- executables/main-fs6.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 074b4c8770..42b016919c 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1464,11 +1464,22 @@ void *cu_fs6(void *arg) { AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, DU_PORT, &sockFS6), ""); uint64_t timeStamp=0; + initStaticTime(begingWait); + initStaticTime(begingWait2); + initRefTimes(waitDUAndProcessingUL); + initRefTimes(makeSendDL); + initRefTimes(fullLoop); while(1) { timeStamp+=ru->frame_parms.samples_per_tti; + updateTimes(begingWait, &fullLoop, 1000, "CU for full SubFrame (must be less 1ms)"); + pickStaticTime(begingWait); + updateTimes(begingWait, &waitDUAndProcessingUL, 1000, "CU Time in wait Rx + Ul processing"); UL_cu_fs6(ru, &timeStamp); + pickStaticTime(begingWait2); DL_cu_fs6(ru); + updateTimes(begingWait2, &makeSendDL, 1000, "CU Time in DL build+send"); + } return NULL; @@ -1498,17 +1509,20 @@ void *du_fs6(void *arg) { } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); initStaticTime(begingWait); - initRefTimes(waitRxAndProcessingUL); + initStaticTime(begingWait2); + initRefTimes(waitRxAndProcessingUL); initRefTimes(makeSendDL); + initRefTimes(fullLoop); while(1) { L1_proc_t *proc = &ru->eNB_list[0]->proc; + updateTimes(begingWait, &fullLoop, 1000, "DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); updateTimes(begingWait, &waitRxAndProcessingUL, 1000, "DU Time in wait Rx + Ul processing"); - pickStaticTime(begingWait); + pickStaticTime(begingWait2); DL_du_fs6(ru); - updateTimes(begingWait, &makeSendDL, 1000, "DU Time in build and send Tx"); + updateTimes(begingWait2, &makeSendDL, 1000, "DU Time in build and send Tx"); } return NULL; From 282a60fd561e93c96931802a063f3d5b098f1bc1 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 15:29:20 +0200 Subject: [PATCH 044/175] reset measurements after print --- executables/main-fs6.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 42b016919c..fb8fc9ada4 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -31,6 +31,20 @@ int sum(uint8_t *b, int s) { return sum; } +static inline void updateTimesReset(uint64_t start, Meas *M, int period, char *txt) { + if (start!=0) { + uint64_t end=rdtsc(); + long long diff=(end-start)/(cpuf*1000); + M->maxArray[0]=diff; + M->sum+=diff; + M->iterations++; + qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); + printMeas(txt,M,period); + if (M->iterations%period == 0 ) + bzero(M,sizeof(*M)); + } +} + #define ceil16_bytes(a) ((((a+15)/16)*16)/8) static void fs6Dlunpack(void *out, void *in, int szUnpacked) { static uint64_t *lut=NULL; @@ -1472,13 +1486,13 @@ void *cu_fs6(void *arg) { while(1) { timeStamp+=ru->frame_parms.samples_per_tti; - updateTimes(begingWait, &fullLoop, 1000, "CU for full SubFrame (must be less 1ms)"); + updateTimesReset(begingWait, &fullLoop, 1000, "CU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); - updateTimes(begingWait, &waitDUAndProcessingUL, 1000, "CU Time in wait Rx + Ul processing"); + updateTimesReset(begingWait, &waitDUAndProcessingUL, 1000, "CU Time in wait Rx + Ul processing"); UL_cu_fs6(ru, &timeStamp); pickStaticTime(begingWait2); DL_cu_fs6(ru); - updateTimes(begingWait2, &makeSendDL, 1000, "CU Time in DL build+send"); + updateTimesReset(begingWait2, &makeSendDL, 1000, "CU Time in DL build+send"); } @@ -1509,20 +1523,20 @@ void *du_fs6(void *arg) { } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); initStaticTime(begingWait); - initStaticTime(begingWait2); - initRefTimes(waitRxAndProcessingUL); + initStaticTime(begingWait2); + initRefTimes(waitRxAndProcessingUL); initRefTimes(makeSendDL); initRefTimes(fullLoop); while(1) { L1_proc_t *proc = &ru->eNB_list[0]->proc; - updateTimes(begingWait, &fullLoop, 1000, "DU for full SubFrame (must be less 1ms)"); + updateTimesReset(begingWait, &fullLoop, 1000, "DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); - updateTimes(begingWait, &waitRxAndProcessingUL, 1000, "DU Time in wait Rx + Ul processing"); + updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, "DU Time in wait Rx + Ul processing"); pickStaticTime(begingWait2); DL_du_fs6(ru); - updateTimes(begingWait2, &makeSendDL, 1000, "DU Time in build and send Tx"); + updateTimesReset(begingWait2, &makeSendDL, 1000, "DU Time in build and send Tx"); } return NULL; From 63f04fe72c8cb3faa7fcdf142b006830ff9f370a Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 15:52:41 +0200 Subject: [PATCH 045/175] flush traces --- executables/main-fs6.c | 9 +++++++++ executables/main-ocp.c | 1 + 2 files changed, 10 insertions(+) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index fb8fc9ada4..12904d378d 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1373,7 +1373,12 @@ void DL_du_fs6(RU_t *ru) { void UL_du_fs6(RU_t *ru, int frame, int subframe) { RU_proc_t *ru_proc=&ru->proc; + initStaticTime(begingWait); + initRefTimes(fullLoop); + pickStaticTime(begingWait); rx_rf(ru); + updateTimesReset(begingWait, &fullLoop, 1000, "DU wait USRP"); + setAllfromTS(ru_proc->timestamp_rx); // front end processing: convert from time domain to frequency domain // fills rxdataF buffer @@ -1434,7 +1439,11 @@ void DL_cu_fs6(RU_t *ru) { void UL_cu_fs6(RU_t *ru, uint64_t *TS) { initBufferZone(bufferZone); + initStaticTime(begingWait); + initRefTimes(fullLoop); + pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentDUv0 ); + updateTimesReset(begingWait, &fullLoop, 1000, "CU wait DU"); if (nb_blocks ==0) { LOG_W(PHY, "CU lost a subframe\n"); diff --git a/executables/main-ocp.c b/executables/main-ocp.c index cfec3b336c..afcc1a2363 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -746,6 +746,7 @@ void tx_rf(RU_t *ru) { } static void *ru_thread( void *param ) { + setbuf(stdout, NULL); RU_t *ru = (RU_t *)param; if (ru->if_south == LOCAL_RF) { // configure RF parameters only From 24de1caad6ca01d71048bf962a1b38308384a548 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 16:01:30 +0200 Subject: [PATCH 046/175] flush traces --- executables/main-ocp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index afcc1a2363..e1c3c94d4d 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -747,6 +747,7 @@ void tx_rf(RU_t *ru) { static void *ru_thread( void *param ) { setbuf(stdout, NULL); + setbuf(stderr, NULL); RU_t *ru = (RU_t *)param; if (ru->if_south == LOCAL_RF) { // configure RF parameters only From 280e12ba4f425fb0a158821d109d270249955c53 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 16:03:39 +0200 Subject: [PATCH 047/175] flush traces --- executables/main-fs6.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 12904d378d..966a198654 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1472,6 +1472,9 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { } void *cu_fs6(void *arg) { + setbuf(stdout, NULL); + setbuf(stderr, NULL); + RU_t *ru = (RU_t *)arg; //RU_proc_t *proc = &ru->proc; fill_rf_config(ru,ru->rf_config_file); @@ -1509,6 +1512,9 @@ void *cu_fs6(void *arg) { } void *du_fs6(void *arg) { + setbuf(stdout, NULL); + setbuf(stderr, NULL); + RU_t *ru = (RU_t *)arg; //RU_proc_t *proc = &ru->proc; fill_rf_config(ru,ru->rf_config_file); From 03dda0d890f72c6f6792f3ee47aee8a4434421ee Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 16:30:45 +0200 Subject: [PATCH 048/175] flush traces --- executables/main-fs6.c | 58 ++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 966a198654..42cd146ee2 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -31,17 +31,49 @@ int sum(uint8_t *b, int s) { return sum; } -static inline void updateTimesReset(uint64_t start, Meas *M, int period, char *txt) { +static inline int cmpintRev(const void *a, const void *b) { + uint64_t *aa=(uint64_t *)a; + uint64_t *bb=(uint64_t *)b; + return (int)(*bb-*aa); +} + +static inline void printMeas2(char *txt, Meas *M, int period, bool MaxMin) { + if (M->iterations%period == 0 ) { + char txt2[512]; + sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " %s=%" + PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n", + txt, + M->sum/M->iterations, + M->iterations, + MaxMin?"max":"min", + M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5], + M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]); +#if T_TRACER + LOG_W(PHY,"%s",txt2); +#else + printf("%s",txt2); +#endif + } +} + +static inline void updateTimesReset(uint64_t start, Meas *M, int period, bool MaxMin, char *txt) { if (start!=0) { uint64_t end=rdtsc(); long long diff=(end-start)/(cpuf*1000); M->maxArray[0]=diff; M->sum+=diff; M->iterations++; - qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); - printMeas(txt,M,period); - if (M->iterations%period == 0 ) - bzero(M,sizeof(*M)); + if ( MaxMin) + qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); + else + qsort(M->maxArray, 11, sizeof(uint64_t), cmpintRev); + printMeas2(txt,M,period, MaxMin); + if (M->iterations%period == 0 ) { + bzero(M,sizeof(*M)); + if (!MaxMin) + for (int i=0;i<11;i++) + M->maxArray[i]=INT_MAX; + } } } @@ -1377,7 +1409,7 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { initRefTimes(fullLoop); pickStaticTime(begingWait); rx_rf(ru); - updateTimesReset(begingWait, &fullLoop, 1000, "DU wait USRP"); + updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait USRP"); setAllfromTS(ru_proc->timestamp_rx); // front end processing: convert from time domain to frequency domain @@ -1443,7 +1475,7 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { initRefTimes(fullLoop); pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentDUv0 ); - updateTimesReset(begingWait, &fullLoop, 1000, "CU wait DU"); + updateTimesReset(begingWait, &fullLoop, 1000, false, "CU wait DU"); if (nb_blocks ==0) { LOG_W(PHY, "CU lost a subframe\n"); @@ -1498,13 +1530,13 @@ void *cu_fs6(void *arg) { while(1) { timeStamp+=ru->frame_parms.samples_per_tti; - updateTimesReset(begingWait, &fullLoop, 1000, "CU for full SubFrame (must be less 1ms)"); + updateTimesReset(begingWait, &fullLoop, 1000, true, "CU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); - updateTimesReset(begingWait, &waitDUAndProcessingUL, 1000, "CU Time in wait Rx + Ul processing"); + updateTimesReset(begingWait, &waitDUAndProcessingUL, 1000, true,"CU Time in wait Rx + Ul processing"); UL_cu_fs6(ru, &timeStamp); pickStaticTime(begingWait2); DL_cu_fs6(ru); - updateTimesReset(begingWait2, &makeSendDL, 1000, "CU Time in DL build+send"); + updateTimesReset(begingWait2, &makeSendDL, 1000, true,"CU Time in DL build+send"); } @@ -1545,13 +1577,13 @@ void *du_fs6(void *arg) { while(1) { L1_proc_t *proc = &ru->eNB_list[0]->proc; - updateTimesReset(begingWait, &fullLoop, 1000, "DU for full SubFrame (must be less 1ms)"); + updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); - updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, "DU Time in wait Rx + Ul processing"); + updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); pickStaticTime(begingWait2); DL_du_fs6(ru); - updateTimesReset(begingWait2, &makeSendDL, 1000, "DU Time in build and send Tx"); + updateTimesReset(begingWait2, &makeSendDL, 1000, true, "DU Time in build and send Tx"); } return NULL; From ae25c88372d609115afad1c23e573583a814ee1d Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 17 Oct 2019 16:38:08 +0200 Subject: [PATCH 049/175] flush traces --- executables/main-fs6.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 42cd146ee2..60dbf0014a 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1381,8 +1381,12 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx void DL_du_fs6(RU_t *ru) { for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); + initStaticTime(begingWait); + initRefTimes(fullLoop); + pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); - + updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU"); + if (nb_blocks > 0) { L1_proc_t *L1_proc = &ru->eNB_list[i]->proc; From 6b52ac7d584ff0c948e23279eb09207adf090b1f Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 17 Oct 2019 16:51:15 +0200 Subject: [PATCH 050/175] CI: looping on attach/ping/detach sequences Signed-off-by: Raphael Defosseux --- .../enb_usrp210_band7_test_05mhz_tm1.xml | 286 +++++++++++++++++- 1 file changed, 284 insertions(+), 2 deletions(-) diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml index 2d34439ef7..f5e095ba8a 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml @@ -19,7 +19,7 @@ For more information about the OpenAirInterface (OAI) Software Alliance: contact@openairinterface.org - 030102 000002 040301 000002 040504 040605 040606 040645 040646 000001 040401 000002 030201 + 030103 000002 040301 000002 040504 040605 040606 040645 040646 000001 040401 000002 030201 --> test-05-tm1 @@ -28,7 +28,44 @@ 4 030201 040101 - 030102 000002 040301 000002 040504 000001 040401 000002 030201 + 030103 000002 040301 + 000002 040504 000001 + 000002 040505 000001 + 000002 040506 000001 + 000002 040507 000001 + 000002 040508 000001 + 000002 040509 000001 + 000002 040510 000001 + 000002 040511 000001 + 000002 040512 000001 + 000002 040513 000001 + 000002 040514 000001 + 000002 040515 000001 + 000002 040516 000001 + 000002 040517 000001 + 000002 040518 000001 + 000002 040519 000001 + 000002 040520 000001 + 000002 040521 000001 + 000002 040522 000001 + 000002 040523 000001 + 000002 040524 000001 + 000002 040525 000001 + 000002 040526 000001 + 000002 040527 000001 + 000002 040528 000001 + 000002 040529 000001 + 000002 040530 000001 + 000002 040531 000001 + 000002 040532 000001 + 000002 040533 000001 + 000002 040534 000001 + 000002 040535 000001 + 000002 040536 000001 + 000002 040537 000001 + 000002 040538 000001 + 000002 040539 000001 + 040401 000002 030201 @@ -77,6 +114,251 @@ 5 + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -I 192.168.248.159 -c 20 + 5 + + Iperf iperf (5MHz - DL/1Mbps/UDP)(30 sec) From 90b9cbb81df0934129c63c0f2ba54926bf54bfc3 Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 18 Oct 2019 16:35:33 +0200 Subject: [PATCH 051/175] remove global for frame/subframe, noS1 attach+ traffic ok, UE do not compile --- executables/main-fs6.c | 135 +++--- executables/main-ocp.c | 143 ++---- executables/split_headers.h | 12 +- nfapi/oai_integration/nfapi_pnf.c | 11 +- nfapi/oai_integration/nfapi_vnf.c | 9 +- .../PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c | 2 +- .../lte_ul_channel_estimation.c | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 287 ------------ openair1/PHY/LTE_TRANSPORT/if5_tools.c | 7 +- openair1/PHY/LTE_TRANSPORT/if5_tools.h | 3 +- openair1/PHY/LTE_TRANSPORT/prach.c | 52 +-- openair1/PHY/LTE_TRANSPORT/transport_proto.h | 4 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 317 ------------- openair1/PHY/defs_eNB.h | 416 +----------------- openair1/SCHED/fapi_l1.c | 4 +- openair1/SCHED/fapi_l1.h | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 43 -- openair1/SCHED/prach_procedures.c | 14 +- openair1/SCHED/ru_procedures.c | 397 +---------------- openair1/SCHED/sched_common.h | 2 +- openair1/SCHED/sched_eNB.h | 4 +- openair1/SCHED_UE/phy_procedures_lte_ue.c | 2 +- openair2/PHY_INTERFACE/IF_Module.c | 4 +- openair2/PHY_INTERFACE/IF_Module.h | 48 +- 24 files changed, 242 insertions(+), 1678 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 60dbf0014a..b7f4c62293 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -45,7 +45,7 @@ static inline void printMeas2(char *txt, Meas *M, int period, bool MaxMin) { txt, M->sum/M->iterations, M->iterations, - MaxMin?"max":"min", + MaxMin?"max":"min", M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5], M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]); #if T_TRACER @@ -63,16 +63,20 @@ static inline void updateTimesReset(uint64_t start, Meas *M, int period, bool Ma M->maxArray[0]=diff; M->sum+=diff; M->iterations++; + if ( MaxMin) qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); else qsort(M->maxArray, 11, sizeof(uint64_t), cmpintRev); + printMeas2(txt,M,period, MaxMin); + if (M->iterations%period == 0 ) { - bzero(M,sizeof(*M)); - if (!MaxMin) - for (int i=0;i<11;i++) - M->maxArray[i]=INT_MAX; + bzero(M,sizeof(*M)); + + if (!MaxMin) + for (int i=0; i<11; i++) + M->maxArray[i]=INT_MAX; } } } @@ -111,10 +115,10 @@ static void fs6Dlpack(void *out, void *in, int szUnpacked) { } } -void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { +void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); - if (is_prach_subframe(&eNB->frame_parms, eNB->proc.frame_prach,eNB->proc.subframe_prach)<=0) + if (is_prach_subframe(&eNB->frame_parms, proc->frame_prach,proc->subframe_prach)<=0) return; RU_t *ru; @@ -134,12 +138,13 @@ void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { } rx_prach(eNB, + proc, eNB->RU_list[0], header->max_preamble, header->max_preamble_energy, header->max_preamble_delay, header->avg_preamble_energy, - eNB->proc.frame_prach, + proc->frame_prach, 0, false ); @@ -166,20 +171,20 @@ void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { return; } -void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB) { +void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc) { fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone); uint16_t *max_preamble=header->max_preamble; uint16_t *max_preamble_energy=header->max_preamble_energy; uint16_t *max_preamble_delay=header->max_preamble_delay; uint16_t *avg_preamble_energy=header->avg_preamble_energy; - int subframe=eNB->proc.subframe_prach; - int frame=eNB->proc.frame_prach; + int subframe=proc->subframe_prach; + int frame=proc->frame_prach; // Fixme: not clear why we call twice with "br" and without int br_flag=0; if (br_flag==1) { int prach_mask; - prach_mask = is_prach_subframe (&eNB->frame_parms, eNB->proc.frame_prach_br, eNB->proc.subframe_prach_br); + prach_mask = is_prach_subframe (&eNB->frame_parms, proc->frame_prach_br, proc->subframe_prach_br); eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; int ind = 0; int ce_level = 0; @@ -563,10 +568,10 @@ void fill_rx_indication_from_split(uint8_t *bufferZone, PHY_VARS_eNB *eNB,int UE pthread_mutex_unlock(&eNB->UL_INFO_mutex); } -void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, ul_propagation_t *ul_propa) { +void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, ul_propagation_t *ul_propa) { //LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - const int subframe = eNB->proc.subframe_rx; - const int frame = eNB->proc.frame_rx; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; uint32_t harq_pid; uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); @@ -750,8 +755,8 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagat sizeof(ulsch_harq->o_ACK)); memcpy(ulsch_harq->o,hULUE(bufPtr)->o, sizeof(ulsch_harq->o)); ul_propa[hULUE(bufPtr)->UE_id].ta=hULUE(bufPtr)->ta; - LOG_D(PHY,"Received ulsch data for: rnti:%x, fsf: %d/%d, cqi_crc_status %d O_ACK: %di, segment: %di, seglen: %d \n", - ulsch->rnti, eNB->proc.frame_rx, eNB->proc.subframe_rx, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment, hULUE(bufPtr)->segLen); + LOG_D(PHY,"Received ulsch data for: rnti:%x, cqi_crc_status %d O_ACK: %di, segment: %di, seglen: %d \n", + ulsch->rnti, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment, hULUE(bufPtr)->segLen); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1); @@ -783,18 +788,18 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagat } } -void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB) { +void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc) { // The configuration arrived in Dl, so we can extract the UL data ul_propagation_t ul_propa[NUMBER_OF_UE_MAX]; recvFs6Ul(bufferZone, nbBlocks, eNB, ul_propa); // dirty memory allocation in OAI... for (int i = 0; i < NUMBER_OF_UCI_VARS_MAX; i++) - if ( eNB->uci_vars[i].frame == eNB->proc.frame_rx && - eNB->uci_vars[i].subframe == eNB->proc.subframe_rx ) + if ( eNB->uci_vars[i].frame == proc->frame_rx && + eNB->uci_vars[i].subframe == proc->subframe_rx ) eNB->uci_vars[i].active=0; - pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB, ul_propa); + pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB, proc, ul_propa); } void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, int subframe) { @@ -1379,6 +1384,9 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx } void DL_du_fs6(RU_t *ru) { + static uint64_t lastTS; + L1_rxtx_proc_t L1_proc; + for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); initStaticTime(begingWait); @@ -1386,42 +1394,38 @@ void DL_du_fs6(RU_t *ru) { pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU"); - - if (nb_blocks > 0) { - L1_proc_t *L1_proc = &ru->eNB_list[i]->proc; - if ( L1_proc->timestamp_tx != hUDP(bufferZone)->timestamp) { + if (nb_blocks > 0) { + if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti != hUDP(bufferZone)->timestamp) { LOG_E(HW,"Missed a subframe: expecting: %lu, received %lu\n", - L1_proc->timestamp_tx, + lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, hUDP(bufferZone)->timestamp); } - setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti); - phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1); + lastTS=hUDP(bufferZone)->timestamp; + setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1_proc); + phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1_proc, 1); } else LOG_E(PHY,"DL not received for subframe\n"); } - feptx_prec(ru); - feptx_ofdm(ru); - tx_rf(ru); + feptx_prec(ru, &L1_proc); + feptx_ofdm(ru, &L1_proc); + tx_rf(ru, &L1_proc); } -void UL_du_fs6(RU_t *ru, int frame, int subframe) { - RU_proc_t *ru_proc=&ru->proc; +void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc, int frame, int subframe) { initStaticTime(begingWait); initRefTimes(fullLoop); pickStaticTime(begingWait); - rx_rf(ru); + rx_rf(ru, proc); updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait USRP"); - - setAllfromTS(ru_proc->timestamp_rx); + setAllfromTS(proc->timestamp_rx, proc); // front end processing: convert from time domain to frequency domain // fills rxdataF buffer - fep_full(ru); + fep_full(ru, proc); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; - L1_proc_t *proc = &eNB->proc; if (NFAPI_MODE==NFAPI_MODE_PNF) { // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick @@ -1431,11 +1435,11 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } initBufferZone(bufferZone); - hUDP(bufferZone)->timestamp=ru->proc.timestamp_rx; - prach_eNB_tosplit(bufferZone, FS6_BUF_SIZE, eNB); + hUDP(bufferZone)->timestamp=proc->timestamp_rx; + prach_eNB_tosplit(bufferZone, FS6_BUF_SIZE, eNB, proc ); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_tosplit(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc ); + phy_procedures_eNB_uespec_RX_tosplit(bufferZone, FS6_BUF_SIZE, eNB, proc ); } if (hUDP(bufferZone)->nbBlocks==0) { @@ -1449,20 +1453,19 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) { } } -void DL_cu_fs6(RU_t *ru) { +void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; - L1_proc_t *proc = &eNB->proc; pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.frame = proc->frame_rx; eNB->UL_INFO.subframe = proc->subframe_rx; eNB->UL_INFO.module_id = eNB->Mod_id; eNB->UL_INFO.CC_id = eNB->CC_id; - eNB->if_inst->UL_indication(&eNB->UL_INFO); + eNB->if_inst->UL_indication(&eNB->UL_INFO, proc); pthread_mutex_unlock(&eNB->UL_INFO_mutex); initBufferZone(bufferZone); - phy_procedures_eNB_TX_tosplit(bufferZone, eNB, &proc->L1_proc, 1, bufferZone, FS6_BUF_SIZE); - hUDP(bufferZone)->timestamp=proc->L1_proc.timestamp_tx; + phy_procedures_eNB_TX_tosplit(bufferZone, eNB, proc, 1, bufferZone, FS6_BUF_SIZE); + hUDP(bufferZone)->timestamp=proc->timestamp_tx; if (hUDP(bufferZone)->nbBlocks==0) { hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE) @@ -1473,7 +1476,7 @@ void DL_cu_fs6(RU_t *ru) { sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); } -void UL_cu_fs6(RU_t *ru, uint64_t *TS) { +void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS) { initBufferZone(bufferZone); initStaticTime(begingWait); initRefTimes(fullLoop); @@ -1494,23 +1497,22 @@ void UL_cu_fs6(RU_t *ru, uint64_t *TS) { *TS=hUDP(bufferZone)->timestamp; } - setAllfromTS(hUDP(bufferZone)->timestamp); + setAllfromTS(hUDP(bufferZone)->timestamp, proc); PHY_VARS_eNB *eNB = RC.eNB[0][0]; - if (is_prach_subframe(&eNB->frame_parms, eNB->proc.frame_prach,eNB->proc.subframe_prach)>0) - prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB); + if (is_prach_subframe(&eNB->frame_parms, proc->frame_prach,proc->subframe_prach)>0) + prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB, proc); release_UE_in_freeList(eNB->Mod_id); if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { - phy_procedures_eNB_uespec_RX_fromsplit(bufferZone, nb_blocks, eNB); + phy_procedures_eNB_uespec_RX_fromsplit(bufferZone, nb_blocks, eNB, proc); } } void *cu_fs6(void *arg) { - setbuf(stdout, NULL); - setbuf(stderr, NULL); - + setbuf(stdout, NULL); + setbuf(stderr, NULL); RU_t *ru = (RU_t *)arg; //RU_proc_t *proc = &ru->proc; fill_rf_config(ru,ru->rf_config_file); @@ -1530,27 +1532,30 @@ void *cu_fs6(void *arg) { initStaticTime(begingWait2); initRefTimes(waitDUAndProcessingUL); initRefTimes(makeSendDL); - initRefTimes(fullLoop); + initRefTimes(fullLoop); + L1_rxtx_proc_t L1proc; while(1) { timeStamp+=ru->frame_parms.samples_per_tti; updateTimesReset(begingWait, &fullLoop, 1000, true, "CU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); updateTimesReset(begingWait, &waitDUAndProcessingUL, 1000, true,"CU Time in wait Rx + Ul processing"); - UL_cu_fs6(ru, &timeStamp); + UL_cu_fs6(ru, &L1proc, &timeStamp); pickStaticTime(begingWait2); - DL_cu_fs6(ru); + DL_cu_fs6(ru, &L1proc); updateTimesReset(begingWait2, &makeSendDL, 1000, true,"CU Time in DL build+send"); - } return NULL; } -void *du_fs6(void *arg) { - setbuf(stdout, NULL); - setbuf(stderr, NULL); +void *DlDu(void *arg) { + return NULL; +} +void *du_fs6(void *arg) { + setbuf(stdout, NULL); + setbuf(stderr, NULL); RU_t *ru = (RU_t *)arg; //RU_proc_t *proc = &ru->proc; fill_rf_config(ru,ru->rf_config_file); @@ -1573,17 +1578,19 @@ void *du_fs6(void *arg) { else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + //threadCreate(&t, dutxfs6, (void *)ru, "DlDu", -1, OAI_PRIORITY_RT_MAX); initStaticTime(begingWait); initStaticTime(begingWait2); initRefTimes(waitRxAndProcessingUL); initRefTimes(makeSendDL); initRefTimes(fullLoop); - + L1_rxtx_proc_t L1proc; + while(1) { - L1_proc_t *proc = &ru->eNB_list[0]->proc; + L1_rxtx_proc_t *proc = &L1proc; updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); - UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx); + UL_du_fs6(ru, proc, proc->frame_rx,proc->subframe_rx); updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); pickStaticTime(begingWait2); DL_du_fs6(ru); diff --git a/executables/main-ocp.c b/executables/main-ocp.c index e1c3c94d4d..9a4743a295 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -30,11 +30,6 @@ static int DEFENBS[] = {0}; #include extern uint16_t sf_ahead; -extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); -extern void fep_full(RU_t *ru); -extern void feptx_ofdm(RU_t *ru); -extern void feptx_prec(RU_t *ru); -extern void phy_init_RU(RU_t *); static void *ru_thread( void *param ); void kill_RU_proc(RU_t *ru) { @@ -48,29 +43,11 @@ void reset_opp_meas(void) { // Fixme: there are many mistakes in the datamodel and in redondant variables // TDD is also mode complex -void setAllfromTS(uint64_t TS) { - for (int i=0; i frame_parms; - RU_proc_t *proc =&RC.ru[i]->proc; - uint64_t TStx=TS+(sf_ahead)*fp->samples_per_tti; - uint64_t TSrach=TS;//-fp->samples_per_tti; - proc->timestamp_rx= TS; - proc->timestamp_tx= TStx; - proc->subframe_rx= (TS / fp->samples_per_tti)%10; - proc->subframe_tx= (TStx / fp->samples_per_tti)%10; - proc->subframe_prach=(TSrach / fp->samples_per_tti)%10; - proc->subframe_prach_br=proc->subframe_prach; - proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023; - proc->frame_prach= (TSrach / (fp->samples_per_tti*10))&1023; - proc->frame_prach_br=(TSrach / (fp->samples_per_tti*10))&1023; - proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; - } +void setAllfromTS(uint64_t TS, L1_rxtx_proc_t *proc) { for (int i=0; i < RC.nb_inst; i++) { for (int j=0; jframe_parms; - L1_proc_t *proc =&RC.eNB[i][j]->proc; - L1_rxtx_proc_t *proc1=&RC.eNB[i][j]->proc.L1_proc; uint64_t TStx=TS+(sf_ahead)*fp->samples_per_tti; uint64_t TSrach=TS;//-fp->samples_per_tti; proc->timestamp_rx= TS; @@ -82,11 +59,7 @@ void setAllfromTS(uint64_t TS) { proc->frame_prach= (TSrach / (fp->samples_per_tti*10))&1023; proc->frame_prach_br=(TSrach / (fp->samples_per_tti*10))&1023; proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; - proc1->timestamp_tx= TStx; - proc1->subframe_rx= (TS / fp->samples_per_tti)%10; - proc1->subframe_tx= (TStx / fp->samples_per_tti)%10; - proc1->frame_rx= (TS / (fp->samples_per_tti*10))&1023; - proc1->frame_tx= (TStx / (fp->samples_per_tti*10))&1023; + proc->subframe_tx= (TStx / fp->samples_per_tti)%10; } } @@ -98,24 +71,10 @@ void init_eNB_proc(int inst) { /*int i=0;*/ int CC_id; PHY_VARS_eNB *eNB; - L1_proc_t *proc; - L1_rxtx_proc_t *L1_proc; for (CC_id=0; CC_idproc; - L1_proc = &proc->L1_proc; - L1_proc->instance_cnt = -1; - L1_proc->instance_cnt_RUs = 0; - proc->instance_cnt_prach = -1; - proc->instance_cnt_synch = -1; - proc->CC_id = CC_id; - proc->first_rx =1; - proc->first_tx =1; pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); - pthread_mutex_init( &L1_proc->mutex, NULL); - pthread_cond_init( &L1_proc->cond, NULL); - pthread_mutex_init( &proc->mutex_RU,NULL); } //for multiple CCs: setup master and slaves @@ -124,8 +83,8 @@ void init_eNB_proc(int inst) { eNB = PHY_vars_eNB_g[inst][CC_id]; if (eNB->node_timing == synch_to_ext_device) { //master - eNB->proc.num_slaves = MAX_NUM_CCs-1; - eNB->proc.slave_proc = (L1_proc_t**)malloc(eNB->proc.num_slaves*sizeof(L1_proc_t*)); + proc->num_slaves = MAX_NUM_CCs-1; + proc->slave_proc = (L1_proc_t**)malloc(proc->num_slaves*sizeof(L1_proc_t*)); for (i=0; i< eNB->proc.num_slaves; i++) { if (i < CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc); @@ -137,19 +96,6 @@ void init_eNB_proc(int inst) { } void init_RU_proc(RU_t *ru) { - int i=0; - RU_proc_t *proc; - proc = &ru->proc; - memset((void *)proc,0,sizeof(RU_proc_t)); - proc->ru = ru; - proc->instance_cnt_synch = -1; - proc->instance_cnt_eNBs = -1; - proc->first_rx = 1; - proc->first_tx = 1; - proc->num_slaves = 0; - proc->frame_tx_unwrap = 0; - - for (i=0; i<10; i++) proc->symbol_mask[i]=0; pthread_t t; char *fs6=getenv("fs6"); @@ -469,7 +415,7 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) { } } -void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { +void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t * proc, int br_flag) { uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4],avg_preamble_energy[4]; RU_t *ru; int aa=0; @@ -490,12 +436,13 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { // run PRACH detection for CE-level 0 only for now when br_flag is set rx_prach(eNB, + proc, eNB->RU_list[0], &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0], &avg_preamble_energy[0], - eNB->proc.frame_prach, + proc->frame_prach, 0 ,br_flag ); @@ -508,7 +455,7 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { if (br_flag==1) { int prach_mask; - prach_mask = is_prach_subframe (&eNB->frame_parms, eNB->proc.frame_prach_br, eNB->proc.subframe_prach_br); + prach_mask = is_prach_subframe (&eNB->frame_parms, proc->frame_prach_br, proc->subframe_prach_br); eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; int ind = 0; int ce_level = 0; @@ -528,7 +475,7 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; // eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 - eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + eNB->proc.subframe_prach + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40)); + eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + proc->subframe_prach + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40)); eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1 + ce_level; // CE Level LOG_I (PHY, "Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", @@ -549,8 +496,8 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, - eNB->proc.frame_prach, - eNB->proc.subframe_prach, + proc->frame_prach, + proc->subframe_prach, max_preamble[0], max_preamble_energy[0]/10, max_preamble_energy[0]%10, @@ -560,11 +507,11 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; - eNB->UL_INFO.rach_ind.sfn_sf = eNB->proc.frame_prach<<4 | eNB->proc.subframe_prach; + eNB->UL_INFO.rach_ind.sfn_sf = proc->frame_prach<<4 | proc->subframe_prach; eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; - eNB->preamble_list[0].preamble_rel8.rnti = 1+eNB->proc.subframe_prach; // note: fid is implicitly 0 here + eNB->preamble_list[0].preamble_rel8.rnti = 1+proc->subframe_prach; // note: fid is implicitly 0 here eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is @@ -589,11 +536,11 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, int br_flag) { } } // else br_flag -void prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { +void prach_eNB(PHY_VARS_eNB *eNB, L1_rxtx_proc_t * proc, int frame,int subframe) { // check if we have to detect PRACH first if (is_prach_subframe(&eNB->frame_parms, frame,subframe)>0) { - prach_procedures_ocp(eNB, 0); - prach_procedures_ocp(eNB, 1); + prach_procedures_ocp(eNB, proc, 0); + prach_procedures_ocp(eNB, proc, 1); } } @@ -609,7 +556,7 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), ""); - prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); + prach_eNB(eNB,proc,proc->frame_rx,proc->subframe_rx); release_UE_in_freeList(eNB->Mod_id); // UE-specific RX processing for subframe n @@ -622,41 +569,38 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name eNB->UL_INFO.subframe = proc->subframe_rx; eNB->UL_INFO.module_id = eNB->Mod_id; eNB->UL_INFO.CC_id = eNB->CC_id; - eNB->if_inst->UL_indication(&eNB->UL_INFO); + eNB->if_inst->UL_indication(&eNB->UL_INFO, proc); pthread_mutex_unlock(&eNB->UL_INFO_mutex); phy_procedures_eNB_TX(eNB, proc, 1); return(0); } -void eNB_top(PHY_VARS_eNB *eNB, int dummy1, int dummy2, char *string,RU_t *ru) { - L1_proc_t *proc = &eNB->proc; - L1_rxtx_proc_t *L1_proc = &proc->L1_proc; +void eNB_top(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int dummy1, int dummy2, char *string,RU_t *ru) { if (!oai_exit) { - if (rxtx(eNB,L1_proc,string) < 0) + if (rxtx(eNB,proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); } } -void rx_rf(RU_t *ru) { - RU_proc_t *proc = &ru->proc; +void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; void *rxp[ru->nb_rx]; unsigned int rxs; int i; - openair0_timestamp ts=0,old_ts=0; - + openair0_timestamp ts=0, timestamp_rx; + static openair0_timestamp old_ts=0; + for (i=0; inb_rx; i++) //receive in the next slot - rxp[i] = (void *)&ru->common.rxdata[i][((ru->proc.subframe_rx+1)%10)*fp->samples_per_tti]; + rxp[i] = (void *)&ru->common.rxdata[i][((proc->subframe_rx+1)%10)*fp->samples_per_tti]; - old_ts = proc->timestamp_rx; rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, fp->samples_per_tti, ru->nb_rx); - proc->timestamp_rx = ts-ru->ts_offset; + timestamp_rx = ts-ru->ts_offset; // AssertFatal(rxs == fp->samples_per_tti, // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); @@ -670,23 +614,16 @@ void rx_rf(RU_t *ru) { #endif } - if (proc->first_rx == 1) { - //ru->ts_offset = proc->timestamp_rx; - //proc->timestamp_rx = 0; - proc->first_rx = false; - } else { - if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { - LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", proc->timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti); + if (timestamp_rx - old_ts != fp->samples_per_tti) { + LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti); //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); //proc->timestamp_rx = ts-ru->ts_offset; - } } - - setAllfromTS(proc->timestamp_rx); + old_ts=timestamp_rx; + setAllfromTS(timestamp_rx, proc); } -void tx_rf(RU_t *ru) { - RU_proc_t *proc = &ru->proc; +void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; void *txp[ru->nb_tx]; int i; @@ -740,8 +677,8 @@ void tx_rf(RU_t *ru) { siglen+sf_extension, ru->nb_tx, flags); - LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, - (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->subframe_tx); } } @@ -749,6 +686,8 @@ static void *ru_thread( void *param ) { setbuf(stdout, NULL); setbuf(stderr, NULL); RU_t *ru = (RU_t *)param; + L1_rxtx_proc_t L1proc; + L1_rxtx_proc_t * proc=&L1proc; if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); @@ -771,11 +710,11 @@ static void *ru_thread( void *param ) { // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { // synchronization on input FH interface, acquire signals/data and block - rx_rf(ru); + rx_rf(ru, proc); // do RX front-end processing (frequency-shift, dft) if needed if (ru->feprx) - ru->feprx(ru); + ru->feprx(ru, proc); // At this point, all information for subframe has been received on FH interface // If this proc is to provide synchronization, do so @@ -784,20 +723,20 @@ static void *ru_thread( void *param ) { for (int i=0; inum_eNB; i++) { char string[20]; sprintf(string,"Incoming RU %d",ru->idx); - ru->eNB_top(ru->eNB_list[i],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru); + ru->eNB_top(ru->eNB_list[i],proc, proc->frame_rx,proc->subframe_rx,string,ru); } // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) - ru->feptx_prec(ru); + ru->feptx_prec(ru, proc); // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) - ru->feptx_ofdm(ru); + ru->feptx_ofdm(ru, proc); // do outgoing fronthaul (south) if needed if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) - ru->fh_south_out(ru); + ru->fh_south_out(ru, proc); } LOG_W(PHY,"Exiting ru_thread \n"); diff --git a/executables/split_headers.h b/executables/split_headers.h index 4a8afc9c85..1f9443c00c 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -229,15 +229,15 @@ static inline void *commonUDPdata(uint8_t *ptr) { return (void *) (((commonUDP_t *)ptr)+1); } -void setAllfromTS(uint64_t TS); +void setAllfromTS(uint64_t TS, L1_rxtx_proc_t *proc); void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat); void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset); void *cu_fs6(void *arg); void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); -void rx_rf(RU_t *ru); -void tx_rf(RU_t *ru); +void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc); +void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc); void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe); void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); bool dlsch_procedures(PHY_VARS_eNB *eNB, @@ -256,9 +256,9 @@ void uci_procedures(PHY_VARS_eNB *eNB, // mistakes in main OAI void phy_init_RU(RU_t *); -void feptx_prec(RU_t *); -void feptx_ofdm(RU_t *); +void feptx_prec(RU_t *, L1_rxtx_proc_t *proc); +void feptx_ofdm(RU_t *, L1_rxtx_proc_t *proc); void oai_subframe_ind(uint16_t sfn, uint16_t sf); -void fep_full(RU_t *ru); +void fep_full(RU_t *ru, L1_rxtx_proc_t *proc); extern uint16_t sf_ahead; #endif diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index f07fb1ad23..ed3d708992 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -692,13 +692,12 @@ void pnf_phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t *header) { free(header); } -int pnf_phy_hi_dci0_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_hi_dci0_request_t *req) { +int pnf_phy_hi_dci0_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_hi_dci0_request_t *req) { if (req->hi_dci0_request_body.number_of_dci == 0 && req->hi_dci0_request_body.number_of_hi == 0) LOG_D(PHY,"[PNF] HI_DCI0_REQUEST SFN/SF:%05d dci:%d hi:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), req->hi_dci0_request_body.number_of_dci, req->hi_dci0_request_body.number_of_hi); //phy_info* phy = (phy_info*)(pnf_p7->user_data); struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; - L1_rxtx_proc_t *proc = &eNB->proc.L1_proc; for (int i=0; ihi_dci0_request_body.number_of_dci + req->hi_dci0_request_body.number_of_hi; i++) { //LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d]\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); @@ -719,7 +718,7 @@ int pnf_phy_hi_dci0_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_hi_dci0_request_t * return 0; } -int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_dl_config_request_t *req) { +int pnf_phy_dl_config_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_dl_config_request_t *req) { if (RC.ru == 0) { return -1; } @@ -740,7 +739,6 @@ int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_dl_config_request int sfn = NFAPI_SFNSF2SFN(req->sfn_sf); int sf = NFAPI_SFNSF2SF(req->sfn_sf); struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; - L1_rxtx_proc_t *proc = &eNB->proc.L1_proc; nfapi_dl_config_request_pdu_t *dl_config_pdu_list = req->dl_config_request_body.dl_config_pdu_list; LTE_eNB_PDCCH *pdcch_vars = &eNB->pdcch_vars[sf&1]; pdcch_vars->num_pdcch_symbols = req->dl_config_request_body.number_pdcch_ofdm_symbols; @@ -797,7 +795,7 @@ int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_dl_config_request uint8_t *dlsch_sdu = tx_pdus[UE_id][harq_pid]; memcpy(dlsch_sdu, tx_pdu->segments[0].segment_data, tx_pdu->segments[0].segment_length); //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() DLSCH:pdu_index:%d handle_nfapi_dlsch_pdu(eNB, proc_rxtx, dlsch_pdu, transport_blocks:%d sdu:%p) eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols:%d\n", __FUNCTION__, rel8_pdu->pdu_index, rel8_pdu->transport_blocks, dlsch_sdu, eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols); - handle_nfapi_dlsch_pdu( eNB, sfn,sf, &eNB->proc.L1_proc, &dl_config_pdu_list[i], rel8_pdu->transport_blocks-1, dlsch_sdu); + handle_nfapi_dlsch_pdu( eNB, sfn,sf, proc, &dl_config_pdu_list[i], rel8_pdu->transport_blocks-1, dlsch_sdu); } else { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() DLSCH NULL TX PDU SFN/SF:%d PDU_INDEX:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), rel8_pdu->pdu_index); } @@ -837,7 +835,7 @@ int pnf_phy_tx_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_tx_request_t *req) { return 0; } -int pnf_phy_ul_config_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_ul_config_request_t *req) { +int pnf_phy_ul_config_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_ul_config_request_t *req) { if (0)LOG_D(PHY,"[PNF] UL_CONFIG_REQ %s() sfn_sf:%d pdu:%d rach_prach_frequency_resources:%d srs_present:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), @@ -866,7 +864,6 @@ int pnf_phy_ul_config_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_ul_config_request uint16_t curr_sfn = NFAPI_SFNSF2SFN(req->sfn_sf); uint16_t curr_sf = NFAPI_SFNSF2SF(req->sfn_sf); struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; - L1_rxtx_proc_t *proc = &eNB->proc.L1_proc; nfapi_ul_config_request_pdu_t *ul_config_pdu_list = req->ul_config_request_body.ul_config_pdu_list; for (int i=0; iul_config_request_body.number_of_pdus; i++) { diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index 6b68a29658..729ce5e78d 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -321,9 +321,8 @@ int pnf_config_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_pnf_config_ return 0; } -int wake_eNB_rxtx(PHY_VARS_eNB *eNB, uint16_t sfn, uint16_t sf) { - L1_proc_t *proc=&eNB->proc; - L1_rxtx_proc_t *L1_proc= (sf&1)? &proc->L1_proc : &proc->L1_proc_tx; +int wake_eNB_rxtx(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, uint16_t sfn, uint16_t sf) { + L1_rxtx_proc_t *L1_proc= proc; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; //printf("%s(eNB:%p, sfn:%d, sf:%d)\n", __FUNCTION__, eNB, sfn, sf); //int i; @@ -398,7 +397,7 @@ int phy_sync_indication(struct nfapi_vnf_p7_config *config, uint8_t sync) { return(0); } -int phy_subframe_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn_sf) { +int phy_subframe_indication(L1_rxtx_proc_t * proc, struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn_sf) { static uint8_t first_time = 1; if (first_time) { @@ -410,7 +409,7 @@ int phy_subframe_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn = NFAPI_SFNSF2SFN(sfn_sf); uint16_t sf = NFAPI_SFNSF2SF(sfn_sf); //LOG_D(PHY,"[VNF] subframe indication sfn_sf:%d sfn:%d sf:%d\n", sfn_sf, sfn, sf); - wake_eNB_rxtx(RC.eNB[0][0], sfn, sf); + wake_eNB_rxtx(RC.eNB[0][0], proc, sfn, sf); } else { printf("[VNF] %s() RC.eNB:%p\n", __FUNCTION__, RC.eNB); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c index 960ad10667..ee80dff7b9 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c @@ -148,7 +148,7 @@ int lte_est_timing_advance_pusch(PHY_VARS_eNB *eNB,module_id_t UE_id) max_pos = max_pos-frame_parms->ofdm_symbol_size; //#ifdef DEBUG_PHY - LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); + LOG_D(PHY,"max_pos = %d, sync_pos=%d\n",max_pos,sync_pos); //#endif //DEBUG_PHY return max_pos - sync_pos; diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index eaed019a4f..26d800fa5d 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -54,7 +54,7 @@ int32_t lte_ul_channel_estimation(PHY_VARS_eNB *eNB, int32_t **rxdataF_ext = (eNB!=NULL) ? pusch_vars->rxdataF_ext : calibration->rxdataF_ext; - int subframe = (eNB!=NULL) ? proc->subframe_rx : ru->proc.subframe_rx; + int subframe = proc->subframe_rx; uint8_t harq_pid; int16_t delta_phase = 0; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index 327b0cf57c..b494f7bd6c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -328,231 +328,7 @@ int dlsch_encoding_2threads0(te_params *tep) { extern int oai_exit; -void *te_thread(void *param) { - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - thread_top_init("te_thread",1,200000,250000,500000); - pthread_setname_np( pthread_self(),"te processing"); - LOG_I(PHY,"thread te created id=%ld\n", syscall(__NR_gettid)); - te_params *tep = (te_params *)param; - //wait_sync("te_thread"); - - while (!oai_exit) { - if (wait_on_condition(&tep->mutex_te,&tep->cond_te,&tep->instance_cnt_te,"te thread")<0) break; - - if(oai_exit) break; - - dlsch_encoding_2threads0(tep); - - if (release_thread(&tep->mutex_te,&tep->instance_cnt_te,"te thread")<0) break; - - if (pthread_cond_signal(&tep->cond_te) != 0) { - printf("[eNB] ERROR pthread_cond_signal for te thread exit\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return(NULL); - } - - /*if(opp_enabled == 1 && te_wakeup_stats0->p_time>50*3000){ - print_meas_now(te_wakeup_stats0,"coding_wakeup",stderr); - printf("te_thread0 delay for waking up in frame_rx: %d subframe_rx: %d \n",proc->frame_rx,proc->subframe_rx); - }*/ - } - - return(NULL); -} - - - -int dlsch_encoding_2threads(PHY_VARS_eNB *eNB, - unsigned char *a, - uint8_t num_pdcch_symbols, - LTE_eNB_DLSCH_t *dlsch, - int frame, - uint8_t subframe, - time_stats_t *rm_stats, - time_stats_t *te_stats, - time_stats_t *te_wait_stats, - time_stats_t *te_main_stats, - time_stats_t *te_wakeup_stats0, - time_stats_t *te_wakeup_stats1, - time_stats_t *i_stats, - int worker_num) { - //start_meas(&eNB->dlsch_turbo_encoding_preperation_stats); - LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms; - L1_proc_t *proc = &eNB->proc; - unsigned int G; - unsigned int crc=1; - unsigned char harq_pid = dlsch->harq_ids[frame%2][subframe]; - if((harq_pid < 0) || (harq_pid >= dlsch->Mdlharq)) { - LOG_E(PHY,"dlsch_encoding_2threads illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__); - return(-1); - } - - unsigned short nb_rb = dlsch->harq_processes[harq_pid]->nb_rb; - unsigned int A; - unsigned char mod_order; - unsigned int Kr=0,Kr_bytes,r,r_offset=0; - // unsigned short m=dlsch->harq_processes[harq_pid]->mcs; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN); - A = dlsch->harq_processes[harq_pid]->TBS; //6228 - mod_order = dlsch->harq_processes[harq_pid]->Qm; - G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe, - dlsch->harq_processes[harq_pid]->mimo_mode==TM7?7:0); - - if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet - start_meas(&eNB->dlsch_turbo_encoding_preperation_stats); - // Add 24-bit crc (polynomial A) to payload - crc = crc24a(a, - A)>>8; - stop_meas(&eNB->dlsch_turbo_encoding_preperation_stats); - a[A>>3] = ((uint8_t *)&crc)[2]; - a[1+(A>>3)] = ((uint8_t *)&crc)[1]; - a[2+(A>>3)] = ((uint8_t *)&crc)[0]; - dlsch->harq_processes[harq_pid]->B = A+24; - memcpy(dlsch->harq_processes[harq_pid]->b,a,(A/8)+4); - //stop_meas(&eNB->dlsch_turbo_encoding_preperation_stats); - start_meas(&eNB->dlsch_turbo_encoding_segmentation_stats); - - if (lte_segmentation(dlsch->harq_processes[harq_pid]->b, - dlsch->harq_processes[harq_pid]->c, - dlsch->harq_processes[harq_pid]->B, - &dlsch->harq_processes[harq_pid]->C, - &dlsch->harq_processes[harq_pid]->Cplus, - &dlsch->harq_processes[harq_pid]->Cminus, - &dlsch->harq_processes[harq_pid]->Kplus, - &dlsch->harq_processes[harq_pid]->Kminus, - &dlsch->harq_processes[harq_pid]->F)<0) - return(-1); - - stop_meas(&eNB->dlsch_turbo_encoding_segmentation_stats); - start_meas(&eNB->dlsch_turbo_encoding_signal_stats); - - for(int i=0; itep[i].eNB = eNB; - proc->tep[i].dlsch = dlsch; - proc->tep[i].G = G; - proc->tep[i].harq_pid = harq_pid; - proc->tep[i].total_worker = worker_num; - proc->tep[i].current_worker = i; - pthread_mutex_lock( &proc->tep[i].mutex_te ); - - if (proc->tep[i].instance_cnt_te==0) { - printf("[eNB] TE thread busy\n"); - exit_fun("TE thread busy"); - pthread_mutex_unlock( &proc->tep[i].mutex_te ); - return(-1); - } - - ++proc->tep[i].instance_cnt_te; - - // wakeup worker to do segments - if (pthread_cond_signal(&proc->tep[i].cond_te) != 0) { - printf("[eNB] ERROR pthread_cond_signal for te thread %d exit\n",i); - exit_fun( "ERROR pthread_cond_signal" ); - return (-1); - } - - pthread_mutex_unlock( &proc->tep[i].mutex_te ); - } - - stop_meas(&eNB->dlsch_turbo_encoding_signal_stats); - start_meas(te_main_stats); - - for (r=(dlsch->harq_processes[harq_pid]->C/(worker_num+1))*worker_num; rharq_processes[harq_pid]->C; r++) { - if (rharq_processes[harq_pid]->Cminus) - Kr = dlsch->harq_processes[harq_pid]->Kminus; - else - Kr = dlsch->harq_processes[harq_pid]->Kplus; - - Kr_bytes = Kr>>3; - start_meas(te_stats); - encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0 - ); - stop_meas(te_stats); - start_meas(i_stats); - dlsch->harq_processes[harq_pid]->RTC[r] = - sub_block_interleaving_turbo(4+(Kr_bytes*8), - &dlsch->harq_processes[harq_pid]->d[r][96], - dlsch->harq_processes[harq_pid]->w[r]); - stop_meas(i_stats); - } - } else { - for(int i=0; itep[i].eNB = eNB; - proc->tep[i].dlsch = dlsch; - proc->tep[i].G = G; - proc->tep[i].total_worker = worker_num; - proc->tep[i].current_worker = i; - - if (pthread_cond_signal(&proc->tep[i].cond_te) != 0) { - printf("[eNB] ERROR pthread_cond_signal for te thread exit\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return (-1); - } - } - } - - // Fill in the "e"-sequence from 36-212, V8.6 2009-03, p. 16-17 (for each "e") and concatenate the - // outputs for each code segment, see Section 5.1.5 p.20 - for (r=0,r_offset=0; rharq_processes[harq_pid]->C; r++) { - // get information for E for the segments that are handled by the worker thread - if (r<(dlsch->harq_processes[harq_pid]->C/(worker_num+1))*worker_num) { - int Nl=dlsch->harq_processes[harq_pid]->Nl; - int Qm=dlsch->harq_processes[harq_pid]->Qm; - int C = dlsch->harq_processes[harq_pid]->C; - int Gp = G/Nl/Qm; - int GpmodC = Gp%C; - - if (r < (C-(GpmodC))) - r_offset += Nl*Qm * (Gp/C); - else - r_offset += Nl*Qm * ((GpmodC==0?0:1) + (Gp/C)); - } else { - start_meas(rm_stats); - r_offset += lte_rate_matching_turbo(dlsch->harq_processes[harq_pid]->RTC[r], - G, //G - dlsch->harq_processes[harq_pid]->w[r], - dlsch->harq_processes[harq_pid]->e+r_offset, - dlsch->harq_processes[harq_pid]->C, // C - dlsch->Nsoft, // Nsoft, - dlsch->Mdlharq, - dlsch->Kmimo, - dlsch->harq_processes[harq_pid]->rvidx, - dlsch->harq_processes[harq_pid]->Qm, - dlsch->harq_processes[harq_pid]->Nl, - r, - nb_rb); - // m); // r - stop_meas(rm_stats); - } - } - - stop_meas(te_main_stats); - start_meas(te_wait_stats); - - if(worker_num == 1) { - wait_on_busy_condition(&proc->tep[0].mutex_te,&proc->tep[0].cond_te,&proc->tep[0].instance_cnt_te,"te thread 0"); - } else if(worker_num == 2) { - wait_on_busy_condition(&proc->tep[0].mutex_te,&proc->tep[0].cond_te,&proc->tep[0].instance_cnt_te,"te thread 0"); - wait_on_busy_condition(&proc->tep[1].mutex_te,&proc->tep[1].cond_te,&proc->tep[1].instance_cnt_te,"te thread 1"); - } else { - wait_on_busy_condition(&proc->tep[0].mutex_te,&proc->tep[0].cond_te,&proc->tep[0].instance_cnt_te,"te thread 0"); - wait_on_busy_condition(&proc->tep[1].mutex_te,&proc->tep[1].cond_te,&proc->tep[1].instance_cnt_te,"te thread 1"); - wait_on_busy_condition(&proc->tep[2].mutex_te,&proc->tep[2].cond_te,&proc->tep[2].instance_cnt_te,"te thread 2"); - } - - stop_meas(te_wait_stats); - /*if(opp_enabled == 1 && te_wait_stats->p_time>100*3000){ - print_meas_now(te_wait_stats,"coding_wait",stderr); - printf("coding delay in wait on codition in frame_rx: %d \n",proc->frame_rx); - }*/ - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_OUT); - return(0); -} int dlsch_encoding_all(PHY_VARS_eNB *eNB, unsigned char *a, uint8_t num_pdcch_symbols, @@ -589,68 +365,6 @@ int dlsch_encoding_all(PHY_VARS_eNB *eNB, } } - if(get_thread_worker_conf() == WORKER_ENABLE) { - if(C >= 8) { //one main three worker - encoding_return = - dlsch_encoding_2threads(eNB, - a, - num_pdcch_symbols, - dlsch, - frame, - subframe, - rm_stats, - te_stats, - te_wait_stats, - te_main_stats, - te_wakeup_stats0, - te_wakeup_stats1, - i_stats, - 3); - } else if(C >= 6) { //one main two worker - encoding_return = - dlsch_encoding_2threads(eNB, - a, - num_pdcch_symbols, - dlsch, - frame, - subframe, - rm_stats, - te_stats, - te_wait_stats, - te_main_stats, - te_wakeup_stats0, - te_wakeup_stats1, - i_stats, - 2); - } else if(C >= 4) { //one main one worker - encoding_return = - dlsch_encoding_2threads(eNB, - a, - num_pdcch_symbols, - dlsch, - frame, - subframe, - rm_stats, - te_stats, - te_wait_stats, - te_main_stats, - te_wakeup_stats0, - te_wakeup_stats1, - i_stats, - 1); - } else { - encoding_return = - dlsch_encoding(eNB, - a, - num_pdcch_symbols, - dlsch, - frame, - subframe, - rm_stats, - te_stats, - i_stats); - } - } else { encoding_return = dlsch_encoding(eNB, a, @@ -661,7 +375,6 @@ int dlsch_encoding_all(PHY_VARS_eNB *eNB, rm_stats, te_stats, i_stats); - } return encoding_return; } diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index 9e31735f81..5882ab50d3 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -308,7 +308,7 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t } -void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type) { +void recv_IF5(RU_t *ru, L1_rxtx_proc_t *proc, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type) { LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; int32_t *txp[fp->nb_antennas_tx], *rxp[fp->nb_antennas_rx]; @@ -505,7 +505,6 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 rxp[0] = (void*)&ru->common.rxdata[0][subframe*ru->frame_parms.samples_per_tti]; rxp128 = (__m128i *) (rxp[0]); - RU_proc_t *proc = &ru->proc; /* // while(packet_idsamples_per_tti/db_fulllength) { data_block = data_block_head; @@ -569,13 +568,13 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 subframe_skip++; offset_cnt = header->seqno; } else { - if ((offset_cnt != header->seqno) && (start_flag == 0) && (proc->first_rx > 3)){ + if ((offset_cnt != header->seqno) && (start_flag == 0) ){ #ifdef DEBUG_UL_MOBIPASS LOG_D(PHY,"[Mobipass] Reset sequence number, offset_cnt:%d, header->seqno:%d, packet_id:%d\n", offset_cnt, header->seqno, packet_id); #endif reset_flag=1; } - if ((reset_flag == 1) && (proc->first_rx > 3 ) && (start_flag == 0) && (packet_id == 0)) { + if ((reset_flag == 1) && (start_flag == 0) && (packet_id == 0)) { packet_id = 1; reset_flag = 0; } diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.h b/openair1/PHY/LTE_TRANSPORT/if5_tools.h index 0f24f7bece..445accd899 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.h +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.h @@ -61,7 +61,8 @@ typedef struct IF5_mobipass_header IF5_mobipass_header_t; void send_IF5(RU_t *, openair0_timestamp, int, uint8_t*, uint16_t); -void recv_IF5(RU_t *, openair0_timestamp*, int, uint16_t); +void recv_IF5(RU_t *ru, L1_rxtx_proc_t *proc, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type); + void malloc_IF5_buffer(RU_t *ru); diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index 6aca9ba904..94c5ede32f 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -38,12 +38,15 @@ #include "SCHED/sched_eNB.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "prach_extern.h" +#include +#include #if (LTE_RRC_VERSION < MAKE_VERSION(14, 0, 0)) #define rx_prach0 rx_prach #endif void rx_prach0(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, RU_t *ru, uint16_t *max_preamble, uint16_t *max_preamble_energy, @@ -147,13 +150,13 @@ void rx_prach0(PHY_VARS_eNB *eNB, if (br_flag == 1) { prach_ifftp = eNB->prach_vars_br.prach_ifft[ce_level]; - subframe = eNB->proc.subframe_prach_br; + subframe = proc->subframe_prach_br; prachF = eNB->prach_vars_br.prachF; rxsigF = eNB->prach_vars_br.rxsigF[ce_level]; if (LOG_DEBUGFLAG(PRACH)){ - if (((eNB->proc.frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (eNB) : running rx_prach (br_flag %d, ce_level %d) for frame %d subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d, rootSequenceIndex %d, repetition number %d,numRepetitionsPrePreambleAttempt %d\n", - br_flag,ce_level,eNB->proc.frame_prach,subframe, + if (((proc->frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (eNB) : running rx_prach (br_flag %d, ce_level %d) for frame %d subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d, rootSequenceIndex %d, repetition number %d,numRepetitionsPrePreambleAttempt %d\n", + br_flag,ce_level,proc->frame_prach,subframe, fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level], prach_ConfigIndex,rootSequenceIndex, eNB->prach_vars_br.repetition_number[ce_level], @@ -163,34 +166,30 @@ void rx_prach0(PHY_VARS_eNB *eNB, #endif { prach_ifftp = eNB->prach_vars.prach_ifft[0]; - subframe = eNB->proc.subframe_prach; + subframe = proc->subframe_prach; prachF = eNB->prach_vars.prachF; rxsigF = eNB->prach_vars.rxsigF[0]; if (LOG_DEBUGFLAG(PRACH)){ - if (((eNB->proc.frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (eNB) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d , rootSequenceIndex %d\n", subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex,rootSequenceIndex); + if (((proc->frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (eNB) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d , rootSequenceIndex %d\n", subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex,rootSequenceIndex); } } } else { #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) if (br_flag == 1) { - subframe = ru->proc.subframe_prach_br; + subframe = proc->subframe_prach_br; rxsigF = ru->prach_rxsigF_br[ce_level]; if (LOG_DEBUGFLAG(PRACH)) { - if (((ru->proc.frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (RU) : running rx_prach (br_flag %d, ce_level %d) for frame %d subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n", - br_flag,ce_level,ru->proc.frame_prach,subframe,fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],prach_ConfigIndex); + if (((proc->frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (RU) : running rx_prach (br_flag %d, ce_level %d) for frame %d subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n", + br_flag,ce_level,proc->frame_prach,subframe,fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],prach_ConfigIndex); } } else #endif { - subframe = ru->proc.subframe_prach; + subframe = proc->subframe_prach; rxsigF = ru->prach_rxsigF; - if (LOG_DEBUGFLAG(PRACH)) { - if (((ru->proc.frame_prach)&1023) < 20) LOG_I(PHY,"PRACH (RU) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n", - subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex); - } } } @@ -218,8 +217,8 @@ void rx_prach0(PHY_VARS_eNB *eNB, if (prach[0]!= NULL) LOG_M("prach_rx","prach_rx",prach[0],fp->samples_per_tti,1,1); - LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d %s rxdata:%p index:%d\n", - ru->idx,br_flag,ce_level,ru->proc.frame_prach,subframe,fp->samples_per_tti, + LOG_I(PHY,"RU %d, br_flag %d ce_level %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d %s rxdata:%p index:%d\n", + ru->idx,br_flag,ce_level,subframe,fp->samples_per_tti, prach[aa],dbEn0,ru->N_TA_offset,buffer,ru->common.rxdata[aa], (subframe*fp->samples_per_tti)-ru->N_TA_offset); } @@ -424,16 +423,16 @@ void rx_prach0(PHY_VARS_eNB *eNB, if ((eNB==NULL) && ru->function == NGFI_RRU_IF4p5) { /// **** send_IF4 of rxsigF to RAU **** /// #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - if (br_flag == 1) send_IF4p5(ru, ru->proc.frame_prach, ru->proc.subframe_prach, IF4p5_PRACH+1+ce_level); + if (br_flag == 1) send_IF4p5(ru, proc->frame_prach, proc->subframe_prach, IF4p5_PRACH+1+ce_level); else #endif - send_IF4p5(ru, ru->proc.frame_prach, ru->proc.subframe_prach, IF4p5_PRACH); + send_IF4p5(ru, proc->frame_prach, proc->subframe_prach, IF4p5_PRACH); return; } else if (eNB!=NULL) { if ( LOG_DEBUGFLAG(PRACH)) { int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840)); - if ((en > 60)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,eNB->proc.frame_rx,eNB->proc.subframe_rx,en); + if ((en > 60)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,proc->frame_rx,proc->subframe_rx,en); } } @@ -475,7 +474,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, if (LOG_DEBUGFLAG(PRACH)) { int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840)); - if (en>60) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",ru->proc.frame_prach,subframe,preamble_index,br_flag); + if (en>60) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",proc->frame_prach,subframe,preamble_index,br_flag); } if (restricted_set == 0) { @@ -561,7 +560,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840)); if (en>60) LOG_I(PHY,"frame %d, subframe %d : preamble index %d: offset %d, preamble shift %d (br_flag %d, en %d)\n", - ru->proc.frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,en); + proc->frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,en); } log2_ifft_size = 10; @@ -643,7 +642,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, if (LOG_DEBUGFLAG(PRACH)) { int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840)); - if (en>60) LOG_I(PHY,"frame %d, subframe %d: Checking for peak in time-domain (br_flag %d, en %d)\n",ru->proc.frame_prach,subframe,br_flag,en); + if (en>60) LOG_I(PHY,"frame %d, subframe %d: Checking for peak in time-domain (br_flag %d, en %d)\n",proc->frame_prach,subframe,br_flag,en); } preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<60) && (br_flag==1)) LOG_D(PHY,"frame %d, subframe %d : max_preamble_energy %d, max_preamble_delay %d, max_preamble %d (br_flag %d,ce_level %d, levdB %d, lev %d)\n", - ru->proc.frame_prach,subframe, + proc->frame_prach,subframe, *max_preamble_energy,*max_preamble_delay, *max_preamble,br_flag,ce_level,levdB,lev); } @@ -707,6 +706,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) void rx_prach(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, RU_t *ru, uint16_t *max_preamble, uint16_t *max_preamble_energy, @@ -719,21 +719,21 @@ void rx_prach(PHY_VARS_eNB *eNB, int prach_mask=0; if (br_flag == 0) { - rx_prach0(eNB,ru,max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,0,0); + rx_prach0(eNB,proc, ru,max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,0,0); } else { // This is procedure for eMTC, basically handling the repetitions - prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br); + prach_mask = is_prach_subframe(&eNB->frame_parms,proc->frame_prach_br,proc->subframe_prach_br); for (i=0; i<4; i++) { if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]==1) && ((prach_mask&(1<<(i+1))) > 0)) { // check that prach CE level is active now // if first reception in group of repetitions store frame for later (in RA-RNTI for Msg2) - if (eNB->prach_vars_br.repetition_number[i]==0) eNB->prach_vars_br.first_frame[i]=eNB->proc.frame_prach_br; + if (eNB->prach_vars_br.repetition_number[i]==0) eNB->prach_vars_br.first_frame[i]=proc->frame_prach_br; // increment repetition number eNB->prach_vars_br.repetition_number[i]++; // do basic PRACH reception - rx_prach0(eNB,ru,max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,1,i); + rx_prach0(eNB,proc, ru,max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,1,i); // if last repetition, clear counter if (eNB->prach_vars_br.repetition_number[i] == eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[i]) { diff --git a/openair1/PHY/LTE_TRANSPORT/transport_proto.h b/openair1/PHY/LTE_TRANSPORT/transport_proto.h index 90555eb2a8..a795ca79a0 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_proto.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_proto.h @@ -573,7 +573,9 @@ uint32_t rx_pucch(PHY_VARS_eNB *phy_vars_eNB, @returns 0 on success */ -void rx_prach(PHY_VARS_eNB *phy_vars_eNB,RU_t *ru, +void rx_prach(PHY_VARS_eNB *phy_vars_eNB, + L1_rxtx_proc_t *proc, + RU_t *ru, uint16_t *max_preamble, uint16_t *max_preamble_energy, uint16_t *max_preamble_delay, diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index f7bea46744..1f8afe2609 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -211,324 +211,7 @@ uint8_t extract_cqi_crc(uint8_t *cqi,uint8_t CQI_LENGTH) { return(crc); } - - - -int ulsch_decoding_data_2thread0(td_params *tdp) { - PHY_VARS_eNB *eNB = tdp->eNB; - int UE_id = tdp->UE_id; - int harq_pid = tdp->harq_pid; - int llr8_flag = tdp->llr8_flag; - unsigned int r,r_offset=0,Kr,Kr_bytes; - uint8_t crc_type; - int offset = 0; - int ret = 1; - int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; - LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; - LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - int Q_m = ulsch_harq->Qm; - int G = ulsch_harq->G; - uint32_t E=0; - uint32_t Gp,GpmodC,Nl=1; - uint32_t C = ulsch_harq->C; - decoder_if_t *tc; - - if (llr8_flag == 0) - tc = decoder16; - else - tc = decoder8; - - // go through first half of segments to get r_offset - for (r=0; r<(ulsch_harq->C/2); r++) { - // Get Turbo interleaver parameters - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - // This is stolen from rate-matching algorithm to get the value of E - Gp = G/Nl/Q_m; - GpmodC = Gp%C; - - if (r < (C-(GpmodC))) - E = Nl*Q_m * (Gp/C); - else - E = Nl*Q_m * ((GpmodC==0?0:1) + (Gp/C)); - - r_offset += E; - - if (r==0) { - offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); - } else { - offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); - } - } - - // go through second half of segments - for (; r<(ulsch_harq->C); r++) { - // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); - // Get Turbo interleaver parameters - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), - (uint8_t *)&dummy_w[r][0], - (r==0) ? ulsch_harq->F : 0); - - if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], - G, - ulsch_harq->w[r], - (uint8_t *) &dummy_w[r][0], - ulsch_harq->e+r_offset, - ulsch_harq->C, - NSOFT, - 0, //Uplink - 1, - ulsch_harq->rvidx, - (ulsch_harq->round==0)?1:0, // clear - ulsch_harq->Qm, - 1, - r, - &E)==-1) { - LOG_E(PHY,"ulsch_decoding.c: Problem in rate matching\n"); - return(-1); - } - - r_offset += E; - sub_block_deinterleaving_turbo(4+Kr, - &ulsch_harq->d[r][96], - ulsch_harq->w[r]); - - if (ulsch_harq->C == 1) - crc_type = CRC24_A; - else - crc_type = CRC24_B; - - ret = tc(&ulsch_harq->d[r][96], - NULL, - ulsch_harq->c[r], - NULL, - Kr, - ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, - crc_type, - (r==0) ? ulsch_harq->F : 0, - &eNB->ulsch_tc_init_stats, - &eNB->ulsch_tc_alpha_stats, - &eNB->ulsch_tc_beta_stats, - &eNB->ulsch_tc_gamma_stats, - &eNB->ulsch_tc_ext_stats, - &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats); - - // Reassembly of Transport block here - - if (ret != (1+ulsch->max_turbo_iterations)) { - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - memcpy(ulsch_harq->b+offset, - ulsch_harq->c[r], - Kr_bytes - ((ulsch_harq->C>1)?3:0)); - offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); - } else { - break; - } - } - - return(ret); -} - extern int oai_exit; -void *td_thread(void *param) { - PHY_VARS_eNB *eNB = ((td_params *)param)->eNB; - L1_proc_t *proc = &eNB->proc; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - thread_top_init("td_thread",1,200000,250000,500000); - pthread_setname_np( pthread_self(),"td processing"); - LOG_I(PHY,"thread td created id=%ld\n", syscall(__NR_gettid)); - //wait_sync("td_thread"); - - while (!oai_exit) { - if (wait_on_condition(&proc->mutex_td,&proc->cond_td,&proc->instance_cnt_td,"td thread")<0) break; - - if(oai_exit) break; - - ((td_params *)param)->ret = ulsch_decoding_data_2thread0((td_params *)param); - - if (release_thread(&proc->mutex_td,&proc->instance_cnt_td,"td thread")<0) break; - - if (pthread_cond_signal(&proc->cond_td) != 0) { - printf("[eNB] ERROR pthread_cond_signal for td thread exit\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return(NULL); - } - } - - return(NULL); -} - -int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) { - L1_proc_t *proc = &eNB->proc; - unsigned int r,r_offset=0,Kr,Kr_bytes; - uint8_t crc_type; - int offset = 0; - int ret = 1; - int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; - LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; - LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - int G = ulsch_harq->G; - unsigned int E; - int Cby2; - decoder_if_t *tc; - struct timespec wait; - wait.tv_sec=0; - wait.tv_nsec=5000000L; - - if (llr8_flag == 0) - tc = decoder16; - else - tc = decoder8; - - if (ulsch_harq->C>1) { // wakeup worker if more than 1 segment - if (pthread_mutex_timedlock(&proc->mutex_td,&wait) != 0) { - printf("[eNB] ERROR pthread_mutex_lock for TD thread (IC %d)\n", proc->instance_cnt_td); - exit_fun( "error locking mutex_fep" ); - return -1; - } - - if (proc->instance_cnt_td==0) { - printf("[eNB] TD thread busy\n"); - exit_fun("TD thread busy"); - pthread_mutex_unlock( &proc->mutex_td ); - return -1; - } - - ++proc->instance_cnt_td; - proc->tdp.eNB = eNB; - proc->tdp.UE_id = UE_id; - proc->tdp.harq_pid = harq_pid; - proc->tdp.llr8_flag = llr8_flag; - - // wakeup worker to do second half segments - if (pthread_cond_signal(&proc->cond_td) != 0) { - printf("[eNB] ERROR pthread_cond_signal for td thread exit\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return (1+ulsch->max_turbo_iterations); - } - - pthread_mutex_unlock( &proc->mutex_td ); - Cby2 = ulsch_harq->C/2; - } else { - Cby2 = 1; - } - - // go through first half of segments in main thread - for (r=0; rc[r]); - // Get Turbo interleaver parameters - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), - (uint8_t *)&dummy_w[r][0], - (r==0) ? ulsch_harq->F : 0); - start_meas(&eNB->ulsch_rate_unmatching_stats); - - if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], - G, - ulsch_harq->w[r], - (uint8_t *) &dummy_w[r][0], - ulsch_harq->e+r_offset, - ulsch_harq->C, - NSOFT, - 0, //Uplink - 1, - ulsch_harq->rvidx, - (ulsch_harq->round==0)?1:0, // clear - ulsch_harq->Qm, - 1, - r, - &E)==-1) { - LOG_E(PHY,"ulsch_decoding.c: Problem in rate matching\n"); - return(-1); - } - - stop_meas(&eNB->ulsch_rate_unmatching_stats); - r_offset += E; - start_meas(&eNB->ulsch_deinterleaving_stats); - sub_block_deinterleaving_turbo(4+Kr, - &ulsch_harq->d[r][96], - ulsch_harq->w[r]); - stop_meas(&eNB->ulsch_deinterleaving_stats); - - if (ulsch_harq->C == 1) - crc_type = CRC24_A; - else - crc_type = CRC24_B; - - start_meas(&eNB->ulsch_turbo_decoding_stats); - ret = tc(&ulsch_harq->d[r][96], - NULL, - ulsch_harq->c[r], - NULL, - Kr, - ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, - crc_type, - (r==0) ? ulsch_harq->F : 0, - &eNB->ulsch_tc_init_stats, - &eNB->ulsch_tc_alpha_stats, - &eNB->ulsch_tc_beta_stats, - &eNB->ulsch_tc_gamma_stats, - &eNB->ulsch_tc_ext_stats, - &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats); - - // Reassembly of Transport block here - - if (ret != (1+ulsch->max_turbo_iterations)) { - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - - if (r==0) { - memcpy(ulsch_harq->b, - &ulsch_harq->c[0][(ulsch_harq->F>>3)], - Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); - offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); - } else { - memcpy(ulsch_harq->b+offset, - ulsch_harq->c[r], - Kr_bytes - ((ulsch_harq->C>1)?3:0)); - offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); - } - } else { - break; - } - - stop_meas(&eNB->ulsch_turbo_decoding_stats); - //printf("/////////////////////////////////////////**************************loop for %d time in ulsch_decoding main\n",r); - } - - // wait for worker to finish - wait_on_busy_condition(&proc->mutex_td,&proc->cond_td,&proc->instance_cnt_td,"td thread"); - return( (ret>proc->tdp.ret) ? ret : proc->tdp.ret ); -} int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) { unsigned int r,r_offset=0,Kr,Kr_bytes; diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index c6e348cb70..1ae3515cd8 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -71,220 +71,8 @@ #include -#include "openair2/PHY_INTERFACE/IF_Module.h" -typedef struct RU_proc_t_s { - /// Pointer to associated RU descriptor - struct RU_t_s *ru; - /// timestamp received from HW - openair0_timestamp timestamp_rx; - /// timestamp to send to "slave rru" - openair0_timestamp timestamp_tx; - /// subframe to act upon for reception - int subframe_rx; - /// subframe to act upon for transmission - int subframe_tx; - /// subframe to act upon for reception of prach - int subframe_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// subframe to act upon for reception of prach BL/CE UEs - int subframe_prach_br; -#endif - /// frame to act upon for reception - int frame_rx; - /// frame to act upon for transmission - int frame_tx; - /// unwrapped frame count - int frame_tx_unwrap; - /// frame to act upon for reception of prach - int frame_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// frame to act upon for reception of prach - int frame_prach_br; -#endif - /// frame offset for slave RUs (to correct for frame asynchronism at startup) - int frame_offset; - /// \brief Instance count for FH processing thread. - /// \internal This variable is protected by \ref mutex_FH. - int instance_cnt_FH; - int instance_cnt_FH1; - /// \internal This variable is protected by \ref mutex_prach. - int instance_cnt_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// \internal This variable is protected by \ref mutex_prach. - int instance_cnt_prach_br; -#endif - /// \internal This variable is protected by \ref mutex_synch. - int instance_cnt_synch; - /// \internal This variable is protected by \ref mutex_eNBs. - int instance_cnt_eNBs; - /// \brief Instance count for rx processing thread. - /// \internal This variable is protected by \ref mutex_asynch_rxtx. - int instance_cnt_asynch_rxtx; - /// \internal This variable is protected by \ref mutex_fep - int instance_cnt_fep; - /// \internal This variable is protected by \ref mutex_feptx - int instance_cnt_feptx; - - /// \internal This variable is protected by \ref mutex_ru_thread - int instance_cnt_ru; - /// pthread structure for RU FH processing thread - pthread_t pthread_FH; - /// pthread structure for RU control thread - pthread_t pthread_ctrl; - - /// This varible is protected by \ref mutex_emulatedRF - int instance_cnt_emulateRF; - /// pthread structure for RU FH processing thread - - pthread_t pthread_FH1; - - /// pthread structure for RU prach processing thread - pthread_t pthread_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// pthread structure for RU prach processing thread BL/CE UEs - pthread_t pthread_prach_br; -#endif - /// pthread struct for RU synch thread - pthread_t pthread_synch; - /// pthread struct for RU RX FEP worker thread - pthread_t pthread_fep; - /// pthread struct for RU TX FEP worker thread - pthread_t pthread_feptx; - /// pthread struct for emulated RF - pthread_t pthread_emulateRF; - /// pthread structure for asychronous RX/TX processing thread - pthread_t pthread_asynch_rxtx; - /// flag to indicate first RX acquisition - int first_rx; - /// flag to indicate first TX transmission - int first_tx; - /// pthread attributes for RU FH processing thread - pthread_attr_t attr_FH; - - /// pthread attributes for RU control thread - pthread_attr_t attr_ctrl; - - pthread_attr_t attr_FH1; - - /// pthread attributes for RU prach - pthread_attr_t attr_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// pthread attributes for RU prach BL/CE UEs - pthread_attr_t attr_prach_br; -#endif - /// pthread attributes for RU synch thread - pthread_attr_t attr_synch; - /// pthread attributes for asynchronous RX thread - pthread_attr_t attr_asynch_rxtx; - /// pthread attributes for worker fep thread - pthread_attr_t attr_fep; - /// pthread attributes for worker feptx thread - pthread_attr_t attr_feptx; - /// pthread attributes for emulated RF - pthread_attr_t attr_emulateRF; - /// scheduling parameters for RU FH thread - struct sched_param sched_param_FH; - struct sched_param sched_param_FH1; - /// scheduling parameters for RU prach thread - struct sched_param sched_param_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// scheduling parameters for RU prach thread BL/CE UEs - struct sched_param sched_param_prach_br; -#endif - /// scheduling parameters for RU synch thread - struct sched_param sched_param_synch; - /// scheduling parameters for asynch_rxtx thread - struct sched_param sched_param_asynch_rxtx; - /// condition variable for RU FH thread - pthread_cond_t cond_FH; - pthread_cond_t cond_FH1; - /// condition variable for RU prach thread - pthread_cond_t cond_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// condition variable for RU prach thread BL/CE UEs - pthread_cond_t cond_prach_br; -#endif - /// condition variable for RU synch thread - pthread_cond_t cond_synch; - /// condition variable for asynch RX/TX thread - pthread_cond_t cond_asynch_rxtx; - /// condition variable for RU RX FEP thread - pthread_cond_t cond_fep; - /// condition variable for RU TX FEP thread - pthread_cond_t cond_feptx; - /// condition variable for emulated RF - pthread_cond_t cond_emulateRF; - /// condition variable for eNB signal - pthread_cond_t cond_eNBs; - /// condition variable for ru_thread - pthread_cond_t cond_ru_thread; - /// mutex for RU FH - pthread_mutex_t mutex_FH; - pthread_mutex_t mutex_FH1; - /// mutex for RU prach - pthread_mutex_t mutex_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// mutex for RU prach BL/CE UEs - pthread_mutex_t mutex_prach_br; -#endif - /// mutex for RU synch - pthread_mutex_t mutex_synch; - /// mutex for eNB signal - pthread_mutex_t mutex_eNBs; - /// mutex for asynch RX/TX thread - pthread_mutex_t mutex_asynch_rxtx; - /// mutex for fep RX worker thread - pthread_mutex_t mutex_fep; - /// mutex for fep TX worker thread - pthread_mutex_t mutex_feptx; - - /// mutex for ru_thread - pthread_mutex_t mutex_ru; - - /// mutex for emulated RF thread - pthread_mutex_t mutex_emulateRF; - - /// symbol mask for IF4p5 reception per subframe - uint32_t symbol_mask[10]; - /// time measurements for each subframe - struct timespec t[10]; - /// number of slave threads - int num_slaves; - /// array of pointers to slaves - struct RU_proc_t_s **slave_proc; -#ifdef PHY_TX_THREAD - /// pthread structure for PRACH thread - pthread_t pthread_phy_tx; - pthread_mutex_t mutex_phy_tx; - pthread_cond_t cond_phy_tx; - /// \internal This variable is protected by \ref mutex_phy_tx. - int instance_cnt_phy_tx; - /// frame to act upon for transmission - int frame_phy_tx; - /// subframe to act upon for transmission - int subframe_phy_tx; - /// timestamp to send to "slave rru" - openair0_timestamp timestamp_phy_tx; - /// pthread structure for RF TX thread - pthread_t pthread_rf_tx; - pthread_mutex_t mutex_rf_tx; - pthread_cond_t cond_rf_tx; - /// \internal This variable is protected by \ref mutex_rf_tx. - int instance_cnt_rf_tx; -#endif -#if defined(PRE_SCD_THREAD) - pthread_t pthread_pre_scd; - /// condition variable for time processing thread - pthread_cond_t cond_pre_scd; - /// mutex for time thread - pthread_mutex_t mutex_pre_scd; - int instance_pre_scd; -#endif - int emulate_rf_busy; -} RU_proc_t; - typedef enum { LOCAL_RF =0, REMOTE_IF5 =1, @@ -312,6 +100,7 @@ typedef enum { WAIT_RESYNCH = 3 } rru_cmd_t; +#include "openair2/PHY_INTERFACE/IF_Module.h" typedef struct RU_t_s{ /// index of this ru uint32_t idx; @@ -396,7 +185,7 @@ typedef struct RU_t_s{ /// function pointer to synchronous RX fronthaul function (RRU,3GPP_eNB) void (*fh_south_in)(struct RU_t_s *ru,int *frame, int *subframe); /// function pointer to synchronous TX fronthaul function - void (*fh_south_out)(struct RU_t_s *ru); + void (*fh_south_out)(struct RU_t_s *ru, L1_rxtx_proc_t * proc); /// function pointer to synchronous RX fronthaul function (RRU) void (*fh_north_in)(struct RU_t_s *ru,int *frame, int *subframe); /// function pointer to synchronous RX fronthaul function (RRU) @@ -412,11 +201,11 @@ typedef struct RU_t_s{ /// function pointer to initialization function for radio interface int (*start_if)(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB); /// function pointer to RX front-end processing routine (DFTs/prefix removal or NULL) - void (*feprx)(struct RU_t_s *ru); + void (*feprx)(struct RU_t_s *ru, L1_rxtx_proc_t * proc); /// function pointer to TX front-end processing routine (IDFTs and prefix removal or NULL) - void (*feptx_ofdm)(struct RU_t_s *ru); + void (*feptx_ofdm)(struct RU_t_s *ru, L1_rxtx_proc_t * proc); /// function pointer to TX front-end processing routine (PRECODING) - void (*feptx_prec)(struct RU_t_s *ru); + void (*feptx_prec)(struct RU_t_s *ru, L1_rxtx_proc_t * proc); /// function pointer to wakeup routine in lte-enb. int (*wakeup_rxtx)(struct PHY_VARS_eNB_s *eNB, struct RU_t_s *ru); /// function pointer to wakeup routine in lte-enb. @@ -426,7 +215,7 @@ typedef struct RU_t_s{ void (*wakeup_prach_eNB_br)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe); #endif /// function pointer to eNB entry routine - void (*eNB_top)(struct PHY_VARS_eNB_s *eNB, int frame_rx, int subframe_rx, char *string, struct RU_t_s *ru); + void (*eNB_top)(struct PHY_VARS_eNB_s *eNB, L1_rxtx_proc_t * proc, int frame_rx, int subframe_rx, char *string, struct RU_t_s *ru); /// Timing statistics time_stats_t ofdm_demod_stats; /// Timing statistics (TX) @@ -468,7 +257,7 @@ typedef struct RU_t_s{ /// value to be passed using command uint16_t cmdval; /// process scheduling variables - RU_proc_t proc; + //RU_proc_t proc; /// stats thread pthread descriptor pthread_t ru_stats_thread; /// OTA synchronization signal @@ -728,41 +517,6 @@ typedef struct { #include "PHY/TOOLS/tools_defs.h" #include "PHY/LTE_TRANSPORT/transport_eNB.h" -/// Context data structure for RX/TX portion of subframe processing -typedef struct { - /// Component Carrier index - uint8_t CC_id; - /// timestamp transmitted to HW - openair0_timestamp timestamp_tx; - /// subframe to act upon for transmission - int subframe_tx; - /// subframe to act upon for reception - int subframe_rx; - /// frame to act upon for transmission - int frame_tx; - /// frame to act upon for reception - int frame_rx; - /// \brief Instance count for RXn-TXnp4 processing thread. - /// \internal This variable is protected by \ref mutex_rxtx. - int instance_cnt; - /// pthread structure for RXn-TXnp4 processing thread - pthread_t pthread; - /// pthread attributes for RXn-TXnp4 processing thread - pthread_attr_t attr; - /// condition variable for tx processing thread - pthread_cond_t cond; - /// mutex for RXn-TXnp4 processing thread - pthread_mutex_t mutex; - /// scheduling parameters for RXn-TXnp4 thread - struct sched_param sched_param_rxtx; - - /// \internal This variable is protected by \ref mutex_RUs. - int instance_cnt_RUs; - /// condition variable for tx processing thread - pthread_cond_t cond_RUs; - /// mutex for RXn-TXnp4 processing thread - pthread_mutex_t mutex_RUs; -} L1_rxtx_proc_t; typedef struct { struct PHY_VARS_eNB_s *eNB; @@ -793,159 +547,6 @@ typedef struct { pthread_mutex_t mutex_te; } te_params; -/// Context data structure for eNB subframe processing -typedef struct L1_proc_t_s { - /// Component Carrier index - uint8_t CC_id; - /// thread index - int thread_index; - /// timestamp received from HW - openair0_timestamp timestamp_rx; - /// timestamp to send to "slave rru" - openair0_timestamp timestamp_tx; - /// subframe to act upon for reception - int subframe_rx; - /// subframe to act upon for PRACH - int subframe_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// subframe to act upon for reception of prach BL/CE UEs - int subframe_prach_br; -#endif - /// frame to act upon for reception - int frame_rx; - /// frame to act upon for transmission - int frame_tx; - /// frame to act upon for PRACH - int frame_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// frame to act upon for PRACH BL/CE UEs - int frame_prach_br; -#endif - /// \internal This variable is protected by \ref mutex_td. - int instance_cnt_td; - /// \internal This variable is protected by \ref mutex_te. - int instance_cnt_te; - /// \internal This variable is protected by \ref mutex_prach. - int instance_cnt_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// \internal This variable is protected by \ref mutex_prach for BL/CE UEs. - int instance_cnt_prach_br; -#endif - // instance count for over-the-air eNB synchronization - int instance_cnt_synch; - - - /// \internal This variable is protected by \ref mutex_asynch_rxtx. - int instance_cnt_asynch_rxtx; - /// pthread structure for asychronous RX/TX processing thread - pthread_t pthread_asynch_rxtx; - /// flag to indicate first RX acquisition - int first_rx; - /// flag to indicate first TX transmission - int first_tx; - /// pthread attributes for parallel turbo-decoder thread - pthread_attr_t attr_td; - /// pthread attributes for parallel turbo-encoder thread - pthread_attr_t attr_te; - /// pthread attributes for single eNB processing thread - pthread_attr_t attr_single; - /// pthread attributes for prach processing thread - pthread_attr_t attr_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// pthread attributes for prach processing thread BL/CE UEs - pthread_attr_t attr_prach_br; -#endif - /// pthread attributes for asynchronous RX thread - pthread_attr_t attr_asynch_rxtx; - /// scheduling parameters for parallel turbo-decoder thread - struct sched_param sched_param_td; - /// scheduling parameters for parallel turbo-encoder thread - struct sched_param sched_param_te; - /// scheduling parameters for single eNB thread - struct sched_param sched_param_single; - /// scheduling parameters for prach thread - struct sched_param sched_param_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// scheduling parameters for prach thread - struct sched_param sched_param_prach_br; -#endif - /// scheduling parameters for asynch_rxtx thread - struct sched_param sched_param_asynch_rxtx; - /// pthread structure for parallel turbo-decoder thread - pthread_t pthread_td; - /// pthread structure for parallel turbo-encoder thread - pthread_t pthread_te; - /// pthread structure for PRACH thread - pthread_t pthread_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// pthread structure for PRACH thread BL/CE UEs - pthread_t pthread_prach_br; -#endif - /// condition variable for parallel turbo-decoder thread - pthread_cond_t cond_td; - /// condition variable for parallel turbo-encoder thread - pthread_cond_t cond_te; - /// condition variable for PRACH processing thread; - pthread_cond_t cond_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// condition variable for PRACH processing thread BL/CE UEs; - pthread_cond_t cond_prach_br; -#endif - - /// condition variable for asynch RX/TX thread - pthread_cond_t cond_asynch_rxtx; - /// mutex for parallel turbo-decoder thread - pthread_mutex_t mutex_td; - /// mutex for parallel turbo-encoder thread - pthread_mutex_t mutex_te; - /// mutex for PRACH thread - pthread_mutex_t mutex_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// mutex for PRACH thread for BL/CE UEs - pthread_mutex_t mutex_prach_br; -#endif - /// mutex for asynch RX/TX thread - pthread_mutex_t mutex_asynch_rxtx; - /// mutex for RU access to eNB processing (PDSCH/PUSCH) - pthread_mutex_t mutex_RU; - /// mutex for eNB processing to access RU TX (PDSCH/PUSCH) - pthread_mutex_t mutex_RU_tx; - /// mutex for RU access to eNB processing (PRACH) - pthread_mutex_t mutex_RU_PRACH; - /// mutex for RU access to eNB processing (PRACH BR) - pthread_mutex_t mutex_RU_PRACH_br; - /// mask for RUs serving eNB (PDSCH/PUSCH) - int RU_mask[10]; - /// mask for RUs serving eNB (PDSCH/PUSCH) - int RU_mask_tx; - /// time measurements for RU arrivals - struct timespec t[10]; - /// Timing statistics (RU_arrivals) - time_stats_t ru_arrival_time; - /// mask for RUs serving eNB (PRACH) - int RU_mask_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /// mask for RUs serving eNB (PRACH) - int RU_mask_prach_br; -#endif - /// parameters for turbo-decoding worker thread - td_params tdp; - /// parameters for turbo-encoding worker thread - te_params tep[3]; - /// set of scheduling variables RXn-TXnp4 threads - L1_rxtx_proc_t L1_proc,L1_proc_tx; - /// stats thread pthread descriptor - pthread_t process_stats_thread; - /// for waking up tx procedure - RU_proc_t *ru_proc; -} L1_proc_t; - - - - - - - typedef struct { //unsigned int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (linear) //unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (dB) @@ -1007,7 +608,7 @@ typedef struct PHY_VARS_eNB_s { module_id_t Mod_id; uint8_t CC_id; uint8_t configured; - L1_proc_t proc; + //L1_proc_t proc; int single_thread_flag; int abstraction_flag; int num_RU; @@ -1257,5 +858,6 @@ typedef struct PHY_VARS_eNB_s { } PHY_VARS_eNB; + #endif /* __PHY_DEFS_ENB__H__ */ diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 5113502fcc..b52a2eb22c 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -730,9 +730,8 @@ void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, } } -void schedule_response(Sched_Rsp_t *Sched_INFO) { +void schedule_response(Sched_Rsp_t *Sched_INFO, L1_rxtx_proc_t *proc) { PHY_VARS_eNB *eNB; - L1_rxtx_proc_t *proc; // copy data from L2 interface into L1 structures module_id_t Mod_id = Sched_INFO->module_id; uint8_t CC_id = Sched_INFO->CC_id; @@ -752,7 +751,6 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) { AssertFatal(RC.eNB[Mod_id][CC_id]!=NULL,"RC.eNB[%d][%d] is null\n",Mod_id,CC_id); eNB = RC.eNB[Mod_id][CC_id]; fp = &eNB->frame_parms; - proc = &eNB->proc.L1_proc; /* TODO: check that following line is correct - in the meantime it is disabled */ //if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index 0314fcc322..9c5c314334 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -76,4 +76,4 @@ void handle_uci_harq_pdu(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_request_pdu void handle_srs_pdu(PHY_VARS_eNB *eNB,nfapi_ul_config_request_pdu_t *ul_config_pdu,uint16_t frame,uint8_t subframe); -void schedule_response(Sched_Rsp_t *Sched_INFO); +void schedule_response(Sched_Rsp_t *Sched_INFO, L1_rxtx_proc_t *proc); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index a6b546679a..e5c767361d 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1360,51 +1360,8 @@ extern int oai_exit; extern void *td_thread (void *); -void init_td_thread(PHY_VARS_eNB *eNB) { - L1_proc_t *proc = &eNB->proc; - proc->tdp.eNB = eNB; - proc->instance_cnt_td = -1; - pthread_attr_init( &proc->attr_td); - pthread_mutex_init( &proc->mutex_td, NULL); - pthread_cond_init( &proc->cond_td, NULL); - pthread_create(&proc->pthread_td, &proc->attr_td, td_thread, (void *)&proc->tdp); -} -void kill_td_thread(PHY_VARS_eNB *eNB) { - L1_proc_t *proc = &eNB->proc; - proc->instance_cnt_td = 0; - pthread_cond_signal(&proc->cond_td); - pthread_join(proc->pthread_td, NULL); - pthread_mutex_destroy( &proc->mutex_td ); - pthread_cond_destroy( &proc->cond_td ); -} - extern void *te_thread (void *); -void init_te_thread(PHY_VARS_eNB *eNB) { - L1_proc_t *proc = &eNB->proc; - - for(int i=0; i<3 ; i++) { - proc->tep[i].eNB = eNB; - proc->tep[i].instance_cnt_te = -1; - pthread_mutex_init( &proc->tep[i].mutex_te, NULL); - pthread_cond_init( &proc->tep[i].cond_te, NULL); - pthread_attr_init( &proc->tep[i].attr_te); - LOG_I(PHY,"Creating te_thread %d\n",i); - pthread_create(&proc->tep[i].pthread_te, &proc->tep[i].attr_te, te_thread, (void *)&proc->tep[i]); - } -} -void kill_te_thread(PHY_VARS_eNB *eNB) { - L1_proc_t *proc = &eNB->proc; - - for(int i=0; i<3 ; i++) { - proc->tep[i].instance_cnt_te = 0; - pthread_cond_signal(&proc->tep[i].cond_te); - pthread_join(proc->tep[i].pthread_te, NULL); - pthread_mutex_destroy( &proc->tep[i].mutex_te); - pthread_cond_destroy( &proc->tep[i].cond_te); - } -} - void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) { nfapi_rx_indication_pdu_t *pdu; int timing_advance_update; diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index 15d2c4fafc..6223be1a91 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -53,7 +53,8 @@ extern int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); -void prach_procedures(PHY_VARS_eNB *eNB +void prach_procedures(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) , int br_flag @@ -65,8 +66,8 @@ void prach_procedures(PHY_VARS_eNB *eNB #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) if (br_flag==1) { - subframe = eNB->proc.subframe_prach_br; - frame = eNB->proc.frame_prach_br; + subframe = proc->subframe_prach_br; + frame = proc->frame_prach_br; pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles=0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); @@ -76,8 +77,8 @@ void prach_procedures(PHY_VARS_eNB *eNB pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles=0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); - subframe = eNB->proc.subframe_prach; - frame = eNB->proc.frame_prach; + subframe = proc->subframe_prach; + frame = proc->frame_prach; } RU_t *ru; @@ -102,6 +103,7 @@ void prach_procedures(PHY_VARS_eNB *eNB // run PRACH detection for CE-level 0 only for now when br_flag is set rx_prach(eNB, + proc, eNB->RU_list[0], &max_preamble[0], &max_preamble_energy[0], @@ -125,7 +127,7 @@ void prach_procedures(PHY_VARS_eNB *eNB if (br_flag==1) { int prach_mask; - prach_mask = is_prach_subframe (&eNB->frame_parms, eNB->proc.frame_prach_br, eNB->proc.subframe_prach_br); + prach_mask = is_prach_subframe (&eNB->frame_parms, proc->frame_prach_br, proc->subframe_prach_br); eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; int ind = 0; int ce_level = 0; diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index 1f1a36b238..52103ef878 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -69,7 +69,7 @@ extern int oai_exit; -void feptx0(RU_t *ru,int slot) { +void feptx0(RU_t *ru, L1_rxtx_proc_t *proc, int slot) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; //int dummy_tx_b[7680*2] __attribute__((aligned(32))); @@ -77,7 +77,7 @@ void feptx0(RU_t *ru,int slot) { unsigned int aa,slot_offset; int slot_sizeF = (fp->ofdm_symbol_size)* ((fp->Ncp==1) ? 6 : 7); - int subframe = ru->proc.subframe_tx; + int subframe = proc->subframe_tx; //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+slot , 1 ); @@ -169,108 +169,7 @@ void feptx0(RU_t *ru,int slot) { //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+slot , 0); } -static void *feptx_thread(void *param) { - - RU_t *ru = (RU_t *)param; - RU_proc_t *proc = &ru->proc; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - - thread_top_init("feptx_thread",1,85000,120000,500000); - pthread_setname_np( pthread_self(),"feptx processing"); - LOG_I(PHY,"thread feptx created id=%ld\n", syscall(__NR_gettid)); - //CPU_SET(6, &cpuset); - //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - //wait_sync("feptx_thread"); - - - - while (!oai_exit) { - - if (wait_on_condition(&proc->mutex_feptx,&proc->cond_feptx,&proc->instance_cnt_feptx,"feptx thread")<0) break; - if (oai_exit) break; - //stop_meas(&ru->ofdm_mod_wakeup_stats); - feptx0(ru,1); - if (release_thread(&proc->mutex_feptx,&proc->instance_cnt_feptx,"feptx thread")<0) break; - - if (pthread_cond_signal(&proc->cond_feptx) != 0) { - printf("[eNB] ERROR pthread_cond_signal for feptx thread exit\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return NULL; - } - /*if(opp_enabled == 1 && ru->ofdm_mod_wakeup_stats.p_time>30*3000){ - print_meas_now(&ru->ofdm_mod_wakeup_stats,"fep wakeup",stderr); - printf("delay in fep wakeup in frame_tx: %d subframe_rx: %d \n",proc->frame_tx,proc->subframe_tx); - }*/ - } - - - - return(NULL); -} - -void feptx_ofdm_2thread(RU_t *ru) { - - LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; - RU_proc_t *proc = &ru->proc; - struct timespec wait; - int subframe = ru->proc.subframe_tx; - - wait.tv_sec=0; - wait.tv_nsec=5000000L; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+ru->idx , 1 ); - start_meas(&ru->ofdm_mod_stats); - - if (subframe_select(fp,subframe) == SF_UL) return; - - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 ); - - if (subframe_select(fp,subframe)==SF_DL) { - // If this is not an S-subframe - if (pthread_mutex_timedlock(&proc->mutex_feptx,&wait) != 0) { - printf("[RU] ERROR pthread_mutex_lock for feptx thread (IC %d)\n", proc->instance_cnt_feptx); - exit_fun( "error locking mutex_feptx" ); - return; - } - - if (proc->instance_cnt_feptx==0) { - printf("[RU] FEPtx thread busy\n"); - exit_fun("FEPtx thread busy"); - pthread_mutex_unlock( &proc->mutex_feptx ); - return; - } - - ++proc->instance_cnt_feptx; - - - if (pthread_cond_signal(&proc->cond_feptx) != 0) { - printf("[RU] ERROR pthread_cond_signal for feptx thread\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return; - } - //start_meas(&ru->ofdm_mod_wakeup_stats); - - pthread_mutex_unlock( &proc->mutex_feptx ); - } - - // call first slot in this thread - feptx0(ru,0); - start_meas(&ru->ofdm_mod_wait_stats); - wait_on_busy_condition(&proc->mutex_feptx,&proc->cond_feptx,&proc->instance_cnt_feptx,"feptx thread"); - stop_meas(&ru->ofdm_mod_wait_stats); - /*if(opp_enabled == 1 && ru->ofdm_mod_wait_stats.p_time>30*3000){ - print_meas_now(&ru->ofdm_mod_wait_stats,"fep wakeup",stderr); - printf("delay in feptx wait on codition in frame_rx: %d subframe_rx: %d \n",proc->frame_tx,proc->subframe_tx); - }*/ - - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 ); - - stop_meas(&ru->ofdm_mod_stats); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+ru->idx , 0 ); - -} - -void feptx_ofdm(RU_t *ru) { +void feptx_ofdm(RU_t *ru, L1_rxtx_proc_t* proc) { LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; @@ -281,7 +180,7 @@ void feptx_ofdm(RU_t *ru) { ((fp->Ncp==1) ? 6 : 7); int len,len2; int16_t *txdata; - int subframe = ru->proc.subframe_tx; + int subframe = proc->subframe_tx; // int CC_id = ru->proc.CC_id; @@ -402,18 +301,18 @@ void feptx_ofdm(RU_t *ru) { // } stop_meas(&ru->ofdm_mod_stats); - LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, subframe %d: txp (time %p) %d dB, txp (freq) %d dB\n", - ru->proc.frame_tx,subframe,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->samples_per_tti)), + LOG_D(PHY,"feptx_ofdm (TXPATH): subframe %d: txp (time %p) %d dB, txp (freq) %d dB\n", + subframe,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->samples_per_tti)), dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF))); } } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+ru->idx , 0 ); } -void feptx_prec(RU_t *ru) { +void feptx_prec(RU_t *ru, L1_rxtx_proc_t * proc) { int l,i,aa,p; - int subframe = ru->proc.subframe_tx; + int subframe = proc->subframe_tx; PHY_VARS_eNB **eNB_list = ru->eNB_list,*eNB; LTE_DL_FRAME_PARMS *fp; @@ -504,9 +403,8 @@ void feptx_prec(RU_t *ru) { } } -void fep0(RU_t *ru,int slot) { +void fep0(RU_t *ru,L1_rxtx_proc_t *proc, int slot) { - RU_proc_t *proc = &ru->proc; LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; int l; @@ -524,243 +422,8 @@ void fep0(RU_t *ru,int slot) { //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+slot, 0); } +void fep_full(RU_t *ru, L1_rxtx_proc_t *proc) { - -static void *fep_thread(void *param) { - - RU_t *ru = (RU_t *)param; - RU_proc_t *proc = &ru->proc; - - thread_top_init("fep_thread",1,100000,120000,5000000); - pthread_setname_np( pthread_self(),"fep processing"); - LOG_I(PHY,"thread fep created id=%ld\n", syscall(__NR_gettid)); - - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - //CPU_SET(2, &cpuset); - //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - //wait_sync("fep_thread"); - - while (!oai_exit) { - - if (wait_on_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread")<0) break; - if (oai_exit) break; - //stop_meas(&ru->ofdm_demod_wakeup_stats); - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1, 1 ); - fep0(ru,0); - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1, 0 ); - if (release_thread(&proc->mutex_fep,&proc->instance_cnt_fep,"fep thread")<0) break; - - if (pthread_cond_signal(&proc->cond_fep) != 0) { - printf("[eNB] ERROR pthread_cond_signal for fep thread exit\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return NULL; - } - /*if(opp_enabled == 1 && ru->ofdm_demod_wakeup_stats.p_time>30*3000){ - print_meas_now(&ru->ofdm_demod_wakeup_stats,"fep wakeup",stderr); - printf("delay in fep wakeup in frame_rx: %d subframe_rx: %d \n",proc->frame_rx,proc->subframe_rx); - }*/ - } - - - - return(NULL); -} - -void init_feptx_thread(RU_t *ru,pthread_attr_t *attr_feptx) { - - RU_proc_t *proc = &ru->proc; - - proc->instance_cnt_feptx = -1; - - pthread_mutex_init( &proc->mutex_feptx, NULL); - pthread_cond_init( &proc->cond_feptx, NULL); - - pthread_create(&proc->pthread_feptx, attr_feptx, feptx_thread, (void*)ru); - - -} - -void init_fep_thread(RU_t *ru,pthread_attr_t *attr_fep) { - - RU_proc_t *proc = &ru->proc; - - proc->instance_cnt_fep = -1; - - pthread_mutex_init( &proc->mutex_fep, NULL); - pthread_cond_init( &proc->cond_fep, NULL); - - pthread_create(&proc->pthread_fep, attr_fep, fep_thread, (void*)ru); - - -} - -extern void kill_fep_thread(RU_t *ru) -{ - RU_proc_t *proc = &ru->proc; - pthread_mutex_lock( &proc->mutex_fep ); - proc->instance_cnt_fep = 0; - pthread_cond_signal(&proc->cond_fep); - pthread_mutex_unlock( &proc->mutex_fep ); - LOG_D(PHY, "Joining pthread_fep\n"); - pthread_join(proc->pthread_fep, NULL); - pthread_mutex_destroy( &proc->mutex_fep ); - pthread_cond_destroy( &proc->cond_fep ); -} - -extern void kill_feptx_thread(RU_t *ru) -{ - RU_proc_t *proc = &ru->proc; - pthread_mutex_lock( &proc->mutex_feptx ); - proc->instance_cnt_feptx = 0; - pthread_cond_signal(&proc->cond_feptx); - pthread_mutex_unlock( &proc->mutex_feptx ); - LOG_D(PHY, "Joining pthread_feptx\n"); - pthread_join(proc->pthread_feptx, NULL); - pthread_mutex_destroy( &proc->mutex_feptx ); - pthread_cond_destroy( &proc->cond_feptx ); -} - -void ru_fep_full_2thread(RU_t *ru) { - - RU_proc_t *proc = &ru->proc; - //PHY_VARS_eNB *eNB = RC.eNB[0][0]; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - RU_CALIBRATION *calibration = &ru->calibration; - RRU_CONFIG_msg_t rru_config_msg; - int check_sync_pos; - - struct timespec wait; - if (proc->subframe_rx==1){ - //LOG_I(PHY,"subframe type %d, RU %d\n",subframe_select(fp,proc->subframe_rx),ru->idx); - } - else if ((fp->frame_type == TDD) && (subframe_select(fp,proc->subframe_rx) != SF_UL)) { - return; - } - //if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); - - wait.tv_sec=0; - wait.tv_nsec=5000000L; - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+ru->idx, 1 ); - start_meas(&ru->ofdm_demod_stats); - - if (pthread_mutex_timedlock(&proc->mutex_fep,&wait) != 0) { - printf("[RU] ERROR pthread_mutex_lock for fep thread (IC %d)\n", proc->instance_cnt_fep); - exit_fun( "error locking mutex_fep" ); - return; - } - - if (proc->instance_cnt_fep==0) { - printf("[RU] FEP thread busy\n"); - exit_fun("FEP thread busy"); - pthread_mutex_unlock( &proc->mutex_fep ); - return; - } - - ++proc->instance_cnt_fep; - - - if (pthread_cond_signal(&proc->cond_fep) != 0) { - printf("[RU] ERROR pthread_cond_signal for fep thread\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return; - } - //start_meas(&ru->ofdm_demod_wakeup_stats); - - pthread_mutex_unlock( &proc->mutex_fep ); - - // call second slot in this symbol - fep0(ru,1); - - start_meas(&ru->ofdm_demod_wait_stats); - wait_on_busy_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread"); - stop_meas(&ru->ofdm_demod_wait_stats); - if(opp_enabled == 1 && ru->ofdm_demod_wakeup_stats.p_time>30*3000){ - print_meas_now(&ru->ofdm_demod_wakeup_stats,"fep wakeup",stderr); - printf("delay in fep wait on condition in frame_rx: %d subframe_rx: %d \n",proc->frame_rx,proc->subframe_rx); - } - - if (proc->subframe_rx==1 && ru->is_slave==1/* && ru->state == RU_CHECK_SYNC*/) { - - //LOG_I(PHY,"Running check synchronization procedure for frame %d\n", proc->frame_rx); - ulsch_extract_rbs_single(ru->common.rxdataF, - calibration->rxdataF_ext, - 0, - fp->N_RB_DL, - 3%(fp->symbols_per_tti/2),// l = symbol within slot - 3/(fp->symbols_per_tti/2),// Ns = slot number - fp); - - /*lte_ul_channel_estimation((PHY_VARS_eNB *)NULL, - proc, - ru->idx, - 3%(fp->symbols_per_tti/2), - 3/(fp->symbols_per_tti/2)); - */ - lte_ul_channel_estimation_RRU(fp, - calibration->drs_ch_estimates, - calibration->drs_ch_estimates_time, - calibration->rxdataF_ext, - fp->N_RB_DL, //N_rb_alloc, - proc->frame_rx, - proc->subframe_rx, - 0,//u = 0..29 - 0,//v = 0,1 - /*eNB->ulsch[ru->idx]->cyclicShift,cyclic_shift,0..7*/0, - 3,//l, - 0,//interpolate, - 0 /*eNB->ulsch[ru->idx]->rnti rnti or ru->ulsch[eNB_id]->rnti*/); - - - - check_sync_pos = lte_est_timing_advance_pusch((PHY_VARS_eNB *)NULL, - ru->idx); - if (ru->state == RU_CHECK_SYNC) { - if ((check_sync_pos >= 0 && check_sync_pos<8) || (check_sync_pos < 0 && check_sync_pos>-8)) { - LOG_I(PHY,"~~~~~~~~~~~ check_sync_pos %d, frame %d, cnt %d\n",check_sync_pos,proc->frame_rx,ru->wait_check); - ru->wait_check++; - } - - if (ru->wait_check==20) { - ru->state = RU_RUN; - ru->wait_check = 0; - // Send RRU_sync_ok - rru_config_msg.type = RRU_sync_ok; - rru_config_msg.len = sizeof(RRU_CONFIG_msg_t); // TODO: set to correct msg len - LOG_I(PHY,"Sending RRU_sync_ok to RAU\n"); - AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),"Failed to send msg to RAU %d\n",ru->idx); - //LOG_I(PHY,"~~~~~~~~~ RU_RUN\n"); - /*LOG_M("dmrs_time.m","dmrstime",calibration->drs_ch_estimates_time[0], (fp->ofdm_symbol_size),1,1); - LOG_M("rxdataF_ext.m","rxdataFext",&calibration->rxdataF_ext[0][36*fp->N_RB_DL], 12*(fp->N_RB_DL),1,1); - LOG_M("drs_seq0.m","drsseq0",ul_ref_sigs_rx[0][0][23],600,1,1); - LOG_M("rxdata.m","rxdata",&ru->common.rxdata[0][0], fp->samples_per_tti*2,1,1); - exit(-1);*/ - } - } - else if (ru->state == RU_RUN) { - // check for synchronization error - if (check_sync_pos >= 8 || check_sync_pos<=-8) { - LOG_E(PHY,"~~~~~~~~~~~~~~ check_sync_pos %d, frame %d ---> LOST SYNC-EXIT\n", check_sync_pos, proc->frame_rx); -LOG_M("rxdata.m","rxdata",&ru->common.rxdata[0][0], fp->samples_per_tti*2,1,1); -exit(-1); - } - } - - else { - AssertFatal(1==0,"Should not get here\n"); - } - } - - stop_meas(&ru->ofdm_demod_stats); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+ru->idx, 0 ); -} - - - -void fep_full(RU_t *ru) { - - RU_proc_t *proc = &ru->proc; int l; LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; @@ -791,43 +454,3 @@ void fep_full(RU_t *ru) { } - -void do_prach_ru(RU_t *ru) { - - RU_proc_t *proc = &ru->proc; - LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,proc->frame_prach,proc->subframe_prach)>0) { - //accept some delay in processing - up to 5ms - int i; - for (i = 0; i < 10 && proc->instance_cnt_prach == 0; i++) { - LOG_W(PHY,"Frame %d Subframe %d, PRACH thread busy (IC %d)!!\n", proc->frame_prach,proc->subframe_prach, - proc->instance_cnt_prach); - usleep(500); - } - if (proc->instance_cnt_prach == 0) { - exit_fun( "PRACH thread busy" ); - return; - } - - // wake up thread for PRACH RX - if (pthread_mutex_lock(&proc->mutex_prach) != 0) { - LOG_E( PHY, "ERROR pthread_mutex_lock for PRACH thread (IC %d)\n", proc->instance_cnt_prach ); - exit_fun( "error locking mutex_prach" ); - return; - } - - ++proc->instance_cnt_prach; - - // the thread can now be woken up - if (pthread_cond_signal(&proc->cond_prach) != 0) { - LOG_E( PHY, "ERROR pthread_cond_signal for PRACH thread\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return; - } - - pthread_mutex_unlock( &proc->mutex_prach ); - } - -} diff --git a/openair1/SCHED/sched_common.h b/openair1/SCHED/sched_common.h index e9af869b05..f3e43d516e 100644 --- a/openair1/SCHED/sched_common.h +++ b/openair1/SCHED/sched_common.h @@ -311,7 +311,7 @@ void get_cqipmiri_params(PHY_VARS_UE *ue,uint8_t eNB_id); int8_t get_PHR(uint8_t Mod_id, uint8_t CC_id, uint8_t eNB_index); -void schedule_response(Sched_Rsp_t *Sched_INFO); +void schedule_response(Sched_Rsp_t *Sched_INFO, L1_rxtx_proc_t *proc); LTE_eNB_UE_stats* get_UE_stats(uint8_t Mod_id, uint8_t CC_id,uint16_t rnti); diff --git a/openair1/SCHED/sched_eNB.h b/openair1/SCHED/sched_eNB.h index 7fcabdc5dd..a38b594efe 100644 --- a/openair1/SCHED/sched_eNB.h +++ b/openair1/SCHED/sched_eNB.h @@ -128,7 +128,7 @@ void phy_procedures_eNB_S_RX(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc); @param br_flag indicator for eMTC PRACH */ #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) -void prach_procedures(PHY_VARS_eNB *eNB, +void prach_procedures(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int br_flag); #else void prach_procedures(PHY_VARS_eNB *eNB); @@ -195,7 +195,7 @@ int8_t find_ue_ulsch(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB); -void schedule_response(Sched_Rsp_t *Sched_INFO); +void schedule_response(Sched_Rsp_t *Sched_INFO, L1_rxtx_proc_t *proc); LTE_eNB_UE_stats* get_UE_stats(uint8_t Mod_id, uint8_t CC_id,uint16_t rnti); diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index 84db43933a..438c7228f1 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -3399,7 +3399,7 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, frame_rx%1024, subframe_rx,(ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]].p_time)/(cpuf*1000.0)); } - LOG_D(PHY," ------ end turbo decoder for AbsSubframe %d.%d ------ \n", frame_rx, subframe_rx); + LOG_D(PHY," ------ end turbo decoder for AbsSubframe %d.%d ------ iter %d \n", frame_rx, subframe_rx,ret1); // Check CRC for CW 0 if (ret == (1+dlsch0->max_turbo_iterations)) { diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index 5b3b6d5da6..e12ddb897d 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -693,7 +693,7 @@ static void dump_dl(Sched_Rsp_t *d) { /* debug utility functions end */ /****************************************************************************/ -void UL_indication(UL_IND_t *UL_info) { +void UL_indication(UL_IND_t *UL_info, L1_rxtx_proc_t *proc) { AssertFatal(UL_info!=NULL,"UL_INFO is null\n"); #ifdef DUMP_FAPI dump_ul(UL_info); @@ -775,7 +775,7 @@ void UL_indication(UL_IND_t *UL_info) { "schedule_response is null (mod %d, cc %d)\n", module_id, CC_id); - ifi->schedule_response(sched_info); + ifi->schedule_response(sched_info, proc ); } LOG_D(PHY,"Schedule_response: SFN_SF:%d%d dl_pdus:%d\n",sched_info->frame,sched_info->subframe,sched_info->DL_req->dl_config_request_body.number_pdu); diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h index c42ba992c9..0e8daf064f 100644 --- a/openair2/PHY_INTERFACE/IF_Module.h +++ b/openair2/PHY_INTERFACE/IF_Module.h @@ -34,6 +34,7 @@ #include +#include //#include "openair1/PHY/LTE_TRANSPORT/transport_eNB.h" #include "nfapi_interface.h" #include "platform_constants.h" @@ -138,11 +139,52 @@ typedef struct { int CC_id; nfapi_config_request_t *cfg; }PHY_Config_t; +#include +/// Context data structure for RX/TX portion of subframe processing +typedef struct { + /// Component Carrier index + uint8_t CC_id; + /// timestamp transmitted to HW + openair0_timestamp timestamp_tx; + openair0_timestamp timestamp_rx; + /// subframe to act upon for transmission + int subframe_tx; + /// subframe to act upon for reception + int subframe_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for reception + int frame_rx; + int frame_prach; + int subframe_prach; + int frame_prach_br; + int subframe_prach_br; + /// \brief Instance count for RXn-TXnp4 processing thread. + /// \internal This variable is protected by \ref mutex_rxtx. + int instance_cnt; + /// pthread structure for RXn-TXnp4 processing thread + pthread_t pthread; + /// pthread attributes for RXn-TXnp4 processing thread + pthread_attr_t attr; + /// condition variable for tx processing thread + pthread_cond_t cond; + /// mutex for RXn-TXnp4 processing thread + pthread_mutex_t mutex; + /// scheduling parameters for RXn-TXnp4 thread + struct sched_param sched_param_rxtx; + + /// \internal This variable is protected by \ref mutex_RUs. + int instance_cnt_RUs; + /// condition variable for tx processing thread + pthread_cond_t cond_RUs; + /// mutex for RXn-TXnp4 processing thread + pthread_mutex_t mutex_RUs; +} L1_rxtx_proc_t; typedef struct IF_Module_s{ //define the function pointer - void (*UL_indication)(UL_IND_t *UL_INFO); - void (*schedule_response)(Sched_Rsp_t *Sched_INFO); + void (*UL_indication)(UL_IND_t *UL_INFO, L1_rxtx_proc_t *proc); + void (*schedule_response)(Sched_Rsp_t *Sched_INFO, L1_rxtx_proc_t *proc); void (*PHY_config_req)(PHY_Config_t* config_INFO); uint32_t CC_mask; uint16_t current_frame; @@ -167,7 +209,7 @@ void IF_Module_kill(int Mod_id); /*Interface for uplink, transmitting the Preamble(list), ULSCH SDU, NAK, Tick (trigger scheduler) */ -void UL_indication(UL_IND_t *UL_INFO); +void UL_indication(UL_IND_t *UL_INFO, L1_rxtx_proc_t *proc); /*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/ void Schedule_Response(Sched_Rsp_t *Sched_INFO); From b760012adf3eaa2c7e9a8e56d6530ed2e73f7730 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 18 Oct 2019 16:48:40 +0200 Subject: [PATCH 052/175] CI: fix in looping attach / ping / detach Signed-off-by: Raphael Defosseux --- ci-scripts/main.py | 24 ++++-- ...b_ue_usrp210_band7_test_05mhz_tm1_nos1.xml | 2 +- .../enb_usrp210_band7_test_05mhz_tm1.xml | 84 ++++++++++--------- 3 files changed, 60 insertions(+), 50 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index bb00d806dd..0909b42747 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -879,20 +879,26 @@ class SSHConnection(): self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if not self.ADBCentralized: # Reboot UE - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) # Wait - time.sleep(60) + #time.sleep(60) # Put in LTE-Mode only - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) # enable data service - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) # we need to do radio on/off cycle to make sure of above changes # airplane mode off // radio on - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(10) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + #time.sleep(10) + # airplane mode on // radio off + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + + # normal procedure without reboot + # enable data service + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) # airplane mode on // radio off self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) self.close() diff --git a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml index dff0761bd3..c2835d0461 100644 --- a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml +++ b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1_nos1.xml @@ -24,7 +24,7 @@ test-05-tm1-nos1-tunnel Test-05MHz-TM1-noS1-tunnel tasks - 2 + 4 030201 090109 030101 000001 090101 000002 040501 040502 000001 040601 040602 040641 040642 000001 090109 030201 diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml index f5e095ba8a..6bc52568c3 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml @@ -19,7 +19,6 @@ For more information about the OpenAirInterface (OAI) Software Alliance: contact@openairinterface.org - 030103 000002 040301 000002 040504 040605 040606 040645 040646 000001 040401 000002 030201 --> test-05-tm1 @@ -28,44 +27,44 @@ 4 030201 040101 - 030103 000002 040301 - 000002 040504 000001 - 000002 040505 000001 - 000002 040506 000001 - 000002 040507 000001 - 000002 040508 000001 - 000002 040509 000001 - 000002 040510 000001 - 000002 040511 000001 - 000002 040512 000001 - 000002 040513 000001 - 000002 040514 000001 - 000002 040515 000001 - 000002 040516 000001 - 000002 040517 000001 - 000002 040518 000001 - 000002 040519 000001 - 000002 040520 000001 - 000002 040521 000001 - 000002 040522 000001 - 000002 040523 000001 - 000002 040524 000001 - 000002 040525 000001 - 000002 040526 000001 - 000002 040527 000001 - 000002 040528 000001 - 000002 040529 000001 - 000002 040530 000001 - 000002 040531 000001 - 000002 040532 000001 - 000002 040533 000001 - 000002 040534 000001 - 000002 040535 000001 - 000002 040536 000001 - 000002 040537 000001 - 000002 040538 000001 - 000002 040539 000001 - 040401 000002 030201 + 030103 000002 + 040301 000002 040504 000001 040401 + 040301 000002 040505 000001 040401 + 040301 000002 040506 000001 040401 + 040301 000002 040507 000001 040401 + 040301 000002 040508 000001 040401 + 040301 000002 040509 000001 040401 + 040301 000002 040510 000001 040401 + 040301 000002 040511 000001 040401 + 040301 000002 040512 000001 040401 + 040301 000002 040513 000001 040401 + 040301 000002 040514 000001 040401 + 040301 000002 040515 000001 040401 + 040301 000002 040516 000001 040401 + 040301 000002 040517 000001 040401 + 040301 000002 040518 000001 040401 + 040301 000002 040519 000001 040401 + 040301 000002 040520 000001 040401 + 040301 000002 040521 000001 040401 + 040301 000002 040522 000001 040401 + 040301 000002 040523 000001 040401 + 040301 000002 040524 000001 040401 + 040301 000002 040525 000001 040401 + 040301 000002 040526 000001 040401 + 040301 000002 040527 000001 040401 + 040301 000002 040528 000001 040401 + 040301 000002 040529 000001 040401 + 040301 000002 040530 000001 040401 + 040301 000002 040531 000001 040401 + 040301 000002 040532 000001 040401 + 040301 000002 040533 000001 040401 + 040301 000002 040534 000001 040401 + 040301 000002 040535 000001 040401 + 040301 000002 040536 000001 040401 + 040301 000002 040537 000001 040401 + 040301 000002 040538 000001 040401 + 040301 000002 040539 000001 040401 + 040201 000002 030201 @@ -74,6 +73,11 @@ Initialize UE + + Terminate_UE + Terminate UE + + IdleSleep Sleep for 10 sec @@ -86,7 +90,7 @@ 3 - + Initialize_eNB Initialize eNB (FDD/Band7/5MHz) -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT From 4c646e8d57453bfc830371bdccf95d4d7907772a Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 18 Oct 2019 18:04:00 +0200 Subject: [PATCH 053/175] try parallel du --- executables/main-fs6.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index b7f4c62293..c96e20e352 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1385,7 +1385,7 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx void DL_du_fs6(RU_t *ru) { static uint64_t lastTS; - L1_rxtx_proc_t L1_proc; + L1_rxtx_proc_t L1_proc={0}; for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); @@ -1533,7 +1533,7 @@ void *cu_fs6(void *arg) { initRefTimes(waitDUAndProcessingUL); initRefTimes(makeSendDL); initRefTimes(fullLoop); - L1_rxtx_proc_t L1proc; + L1_rxtx_proc_t L1proc={0}; while(1) { timeStamp+=ru->frame_parms.samples_per_tti; @@ -1549,7 +1549,16 @@ void *cu_fs6(void *arg) { return NULL; } -void *DlDu(void *arg) { +void *dutxfs6(void *arg) { + RU_t *ru = (RU_t *)arg; + initStaticTime(begingWait2); + initRefTimes(makeSendDL); + usleep(100); + while(1) { + pickStaticTime(begingWait2); + DL_du_fs6(ru); + updateTimesReset(begingWait2, &makeSendDL, 1000, true, "DU Time in build and send Tx"); + } return NULL; } @@ -1577,12 +1586,10 @@ void *du_fs6(void *arg) { LOG_E(HW,"Could not start the RF device\n"); else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); - - //threadCreate(&t, dutxfs6, (void *)ru, "DlDu", -1, OAI_PRIORITY_RT_MAX); + pthread_t t; + threadCreate(&t, dutxfs6, (void *)ru, "DlDu", -1, OAI_PRIORITY_RT_MAX); initStaticTime(begingWait); - initStaticTime(begingWait2); initRefTimes(waitRxAndProcessingUL); - initRefTimes(makeSendDL); initRefTimes(fullLoop); L1_rxtx_proc_t L1proc; @@ -1592,9 +1599,7 @@ void *du_fs6(void *arg) { pickStaticTime(begingWait); UL_du_fs6(ru, proc, proc->frame_rx,proc->subframe_rx); updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); - pickStaticTime(begingWait2); - DL_du_fs6(ru); - updateTimesReset(begingWait2, &makeSendDL, 1000, true, "DU Time in build and send Tx"); + } return NULL; From 283fed9c4ccab0fc62611547fc06eea5a7898517 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 21 Oct 2019 14:59:16 +0200 Subject: [PATCH 054/175] du RX/Tx in parallel, controled by the thread pool --- cmake_targets/CMakeLists.txt | 1 + executables/main-fs6.c | 36 +++++++++++++++++------------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 0615f91ae7..c1d4069915 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2105,6 +2105,7 @@ target_link_libraries (lte-softmodem add_executable(ocp-softmodem ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_DIR}/executables/main-ocp.c + ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c ${OPENAIR_DIR}/executables/main-fs6.c ${OPENAIR_DIR}/executables/transport_split.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c diff --git a/executables/main-fs6.c b/executables/main-fs6.c index c96e20e352..ab3ba61734 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define FS6_BUF_SIZE 1000*1000 @@ -1383,9 +1384,10 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx return; } -void DL_du_fs6(RU_t *ru) { +void DL_du_fs6(void *arg) { + RU_t *ru = *(RU_t **)arg; static uint64_t lastTS; - L1_rxtx_proc_t L1_proc={0}; + L1_rxtx_proc_t L1_proc= {0}; for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); @@ -1474,6 +1476,7 @@ void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { } sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); + return; } void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS) { @@ -1533,7 +1536,7 @@ void *cu_fs6(void *arg) { initRefTimes(waitDUAndProcessingUL); initRefTimes(makeSendDL); initRefTimes(fullLoop); - L1_rxtx_proc_t L1proc={0}; + L1_rxtx_proc_t L1proc= {0}; while(1) { timeStamp+=ru->frame_parms.samples_per_tti; @@ -1549,19 +1552,6 @@ void *cu_fs6(void *arg) { return NULL; } -void *dutxfs6(void *arg) { - RU_t *ru = (RU_t *)arg; - initStaticTime(begingWait2); - initRefTimes(makeSendDL); - usleep(100); - while(1) { - pickStaticTime(begingWait2); - DL_du_fs6(ru); - updateTimesReset(begingWait2, &makeSendDL, 1000, true, "DU Time in build and send Tx"); - } - return NULL; -} - void *du_fs6(void *arg) { setbuf(stdout, NULL); setbuf(stderr, NULL); @@ -1580,26 +1570,34 @@ void *du_fs6(void *arg) { remoteIP=CU_IP; AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, CU_PORT, &sockFS6), ""); + tpool_t pool; + tpool_t *Tpool = &pool; + char params[]="-1,-1"; + initTpool(params, Tpool, false); if (ru->start_rf) { if (ru->start_rf(ru) != 0) LOG_E(HW,"Could not start the RF device\n"); else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); - pthread_t t; - threadCreate(&t, dutxfs6, (void *)ru, "DlDu", -1, OAI_PRIORITY_RT_MAX); + initStaticTime(begingWait); initRefTimes(waitRxAndProcessingUL); initRefTimes(fullLoop); L1_rxtx_proc_t L1proc; + notifiedFIFO_t nf; + initNotifiedFIFO(&nf); while(1) { L1_rxtx_proc_t *proc = &L1proc; updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); + notifiedFIFO_elt_t *Msg=newNotifiedFIFO_elt(sizeof(ru),0,&nf, DL_du_fs6); + *(RU_t **)NotifiedFifoData(Msg)=ru; + pushTpool(Tpool, Msg); UL_du_fs6(ru, proc, proc->frame_rx,proc->subframe_rx); + notifiedFIFO_elt_t *res=pullTpool(&nf, Tpool); updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); - } return NULL; From 63c023029acc630288b4a50ffea46c623eb30b33 Mon Sep 17 00:00:00 2001 From: laurent Date: Sat, 26 Oct 2019 11:28:46 +0200 Subject: [PATCH 055/175] du in 2 threads, and fix UL in FS6 split --- common/utils/ocp_itti/intertask_interface.h | 2 +- executables/main-fs6.c | 77 ++++++++++----------- executables/main-ocp.c | 62 ++++++++++------- executables/split_headers.h | 6 +- openair2/RRC/LTE/rrc_eNB.c | 7 +- targets/COMMON/create_tasks.c | 2 +- 6 files changed, 84 insertions(+), 72 deletions(-) diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index 956d90072d..2290fbdbc4 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -285,7 +285,7 @@ typedef struct { TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_DATA_FORWARDING, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_END_MARKER, TASK_PRIORITY_MED, 200, NULL, NULL) \ - TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL,NULL)\ + TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, rrc_enb_process_itti_msg,NULL)\ TASK_DEF(TASK_RAL_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_X2AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ diff --git a/executables/main-fs6.c b/executables/main-fs6.c index ab3ba61734..1416572d76 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1384,39 +1384,43 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx return; } -void DL_du_fs6(void *arg) { - RU_t *ru = *(RU_t **)arg; +void *DL_du_fs6(void *arg) { + RU_t *ru=(RU_t *)arg; static uint64_t lastTS; L1_rxtx_proc_t L1_proc= {0}; - for (int i=0; inum_eNB; i++) { - initBufferZone(bufferZone); - initStaticTime(begingWait); - initRefTimes(fullLoop); - pickStaticTime(begingWait); - int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); - updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU"); + while (1) { + for (int i=0; inum_eNB; i++) { + initBufferZone(bufferZone); + initStaticTime(begingWait); + initRefTimes(fullLoop); + pickStaticTime(begingWait); + int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); + updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU"); - if (nb_blocks > 0) { - if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti != hUDP(bufferZone)->timestamp) { - LOG_E(HW,"Missed a subframe: expecting: %lu, received %lu\n", - lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, - hUDP(bufferZone)->timestamp); - } + if (nb_blocks > 0) { + if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti != hUDP(bufferZone)->timestamp) { + LOG_E(HW,"Missed a subframe: expecting: %lu, received %lu\n", + lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, + hUDP(bufferZone)->timestamp); + } - lastTS=hUDP(bufferZone)->timestamp; - setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1_proc); - phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1_proc, 1); - } else - LOG_E(PHY,"DL not received for subframe\n"); + lastTS=hUDP(bufferZone)->timestamp; + setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1_proc); + phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1_proc, 1); + } else + LOG_E(PHY,"DL not received for subframe\n"); + } + + feptx_prec(ru, &L1_proc); + feptx_ofdm(ru, &L1_proc); + tx_rf(ru, &L1_proc); } - feptx_prec(ru, &L1_proc); - feptx_ofdm(ru, &L1_proc); - tx_rf(ru, &L1_proc); + return NULL; } -void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc, int frame, int subframe) { +void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { initStaticTime(begingWait); initRefTimes(fullLoop); pickStaticTime(begingWait); @@ -1560,7 +1564,7 @@ void *du_fs6(void *arg) { fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); - openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + init_rf(ru); wait_sync("ru_thread"); char *remoteIP; @@ -1570,33 +1574,26 @@ void *du_fs6(void *arg) { remoteIP=CU_IP; AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, CU_PORT, &sockFS6), ""); - tpool_t pool; - tpool_t *Tpool = &pool; - char params[]="-1,-1"; - initTpool(params, Tpool, false); if (ru->start_rf) { if (ru->start_rf(ru) != 0) LOG_E(HW,"Could not start the RF device\n"); - else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); - } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + else + LOG_I(PHY,"RU %d rf device ready\n",ru->idx); + } else + LOG_I(PHY,"RU %d no rf device\n",ru->idx); initStaticTime(begingWait); initRefTimes(waitRxAndProcessingUL); initRefTimes(fullLoop); - L1_rxtx_proc_t L1proc; - notifiedFIFO_t nf; - initNotifiedFIFO(&nf); + pthread_t t; + threadCreate(&t, DL_du_fs6, (void *)ru, "MainDuTx", -1, OAI_PRIORITY_RT_MAX); while(1) { - L1_rxtx_proc_t *proc = &L1proc; + L1_rxtx_proc_t L1proc; updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); - notifiedFIFO_elt_t *Msg=newNotifiedFIFO_elt(sizeof(ru),0,&nf, DL_du_fs6); - *(RU_t **)NotifiedFifoData(Msg)=ru; - pushTpool(Tpool, Msg); - UL_du_fs6(ru, proc, proc->frame_rx,proc->subframe_rx); - notifiedFIFO_elt_t *res=pullTpool(&nf, Tpool); + UL_du_fs6(ru, &L1proc); updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); } diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 9a4743a295..5ae15c8a29 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -11,10 +11,11 @@ * The merger of OpenAir central code to this branch * should check if these 3 files are modified and analyze if code code has to be copied in here */ +#define _GNU_SOURCE +#include #include #include - static int DEFBANDS[] = {7}; static int DEFENBS[] = {0}; #include @@ -44,7 +45,6 @@ void reset_opp_meas(void) { // Fixme: there are many mistakes in the datamodel and in redondant variables // TDD is also mode complex void setAllfromTS(uint64_t TS, L1_rxtx_proc_t *proc) { - for (int i=0; i < RC.nb_inst; i++) { for (int j=0; jframe_parms; @@ -96,7 +96,6 @@ void init_eNB_proc(int inst) { } void init_RU_proc(RU_t *ru) { - pthread_t t; char *fs6=getenv("fs6"); @@ -104,7 +103,7 @@ void init_RU_proc(RU_t *ru) { if ( strncasecmp(fs6,"cu", 2) == 0 ) threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); else if ( strncasecmp(fs6,"du", 2) == 0 ) { - threadCreate(&t, du_fs6, (void *)ru, "MainDu", -1, OAI_PRIORITY_RT_MAX); + threadCreate(&t, du_fs6, (void *)ru, "MainDuRx", -1, OAI_PRIORITY_RT_MAX); } else AssertFatal(false, "environement variable fs6 is not cu or du"); } else @@ -415,7 +414,7 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) { } } -void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t * proc, int br_flag) { +void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int br_flag) { uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4],avg_preamble_energy[4]; RU_t *ru; int aa=0; @@ -436,7 +435,7 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t * proc, int br_flag) // run PRACH detection for CE-level 0 only for now when br_flag is set rx_prach(eNB, - proc, + proc, eNB->RU_list[0], &max_preamble[0], &max_preamble_energy[0], @@ -536,7 +535,7 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t * proc, int br_flag) } } // else br_flag -void prach_eNB(PHY_VARS_eNB *eNB, L1_rxtx_proc_t * proc, int frame,int subframe) { +void prach_eNB(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int frame,int subframe) { // check if we have to detect PRACH first if (is_prach_subframe(&eNB->frame_parms, frame,subframe)>0) { prach_procedures_ocp(eNB, proc, 0); @@ -576,7 +575,6 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name } void eNB_top(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int dummy1, int dummy2, char *string,RU_t *ru) { - if (!oai_exit) { if (rxtx(eNB,proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); @@ -590,7 +588,7 @@ void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { int i; openair0_timestamp ts=0, timestamp_rx; static openair0_timestamp old_ts=0; - + for (i=0; inb_rx; i++) //receive in the next slot rxp[i] = (void *)&ru->common.rxdata[i][((proc->subframe_rx+1)%10)*fp->samples_per_tti]; @@ -615,15 +613,17 @@ void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { } if (timestamp_rx - old_ts != fp->samples_per_tti) { - LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti); - //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); - //proc->timestamp_rx = ts-ru->ts_offset; + LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti); + //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); + //proc->timestamp_rx = ts-ru->ts_offset; } + old_ts=timestamp_rx; setAllfromTS(timestamp_rx, proc); } -void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { +int tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { + int ret=0; LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; void *txp[ru->nb_tx]; int i; @@ -671,29 +671,31 @@ void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { /* add fail safe for late command end */ // prepare tx buffer pointers - ru->rfdevice.trx_write_func(&ru->rfdevice, - proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, - txp, - siglen+sf_extension, - ru->nb_tx, - flags); + ret=ru->rfdevice.trx_write_func(&ru->rfdevice, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, subframe %d\n",ru->idx, (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->subframe_tx); } + + return ret; } static void *ru_thread( void *param ) { - setbuf(stdout, NULL); - setbuf(stderr, NULL); + setbuf(stdout, NULL); + setbuf(stderr, NULL); RU_t *ru = (RU_t *)param; L1_rxtx_proc_t L1proc; - L1_rxtx_proc_t * proc=&L1proc; + L1_rxtx_proc_t *proc=&L1proc; if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); - openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + init_rf(ru); } AssertFatal(setup_RU_buffers(ru)==0, "Exiting, cannot initialize RU Buffers\n"); @@ -714,7 +716,7 @@ static void *ru_thread( void *param ) { // do RX front-end processing (frequency-shift, dft) if needed if (ru->feprx) - ru->feprx(ru, proc); + ru->feprx(ru, proc); // At this point, all information for subframe has been received on FH interface // If this proc is to provide synchronization, do so @@ -750,8 +752,18 @@ static void *ru_thread( void *param ) { return NULL; } +int init_rf(RU_t *ru) { + char name[256]; + pthread_getname_np(pthread_self(),name, 255); + pthread_setname_np(pthread_self(),"UHD for OAI"); + int ret=openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + pthread_setname_np(pthread_self(),name); + return ret; +} + int start_rf(RU_t *ru) { - return(ru->rfdevice.trx_start_func(&ru->rfdevice)); + int ret=ru->rfdevice.trx_start_func(&ru->rfdevice); + return ret; } int stop_rf(RU_t *ru) { diff --git a/executables/split_headers.h b/executables/split_headers.h index 1f9443c00c..1849efffc7 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -11,7 +11,8 @@ #define DU_PORT "8787" #define MTU 65536 -#define UDP_TIMEOUT 1000L // in micro second (struct timeval, NOT struct timespec) +#define UDP_TIMEOUT 900000L // in micro second (struct timeval, NOT struct timespec) +// linux may timeout for a much longer time (up to 10ms) #define MAX_BLOCKS 16 #define blockAlign 32 //bytes @@ -236,8 +237,9 @@ void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_ void *cu_fs6(void *arg); void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); +int init_rf(RU_t *ru); void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc); -void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc); +int tx_rf(RU_t *ru, L1_rxtx_proc_t *proc); void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe); void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); bool dlsch_procedures(PHY_VARS_eNB *eNB, diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index d93510ac5d..8aefbf87aa 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -9124,9 +9124,10 @@ rrc_enb_task( itti_mark_task_ready(TASK_RRC_ENB); LOG_I(RRC,"Entering main loop of RRC message task\n"); - while (1) { - (void) rrc_enb_process_itti_msg(NULL); - } + //while (1) { + //(void) rrc_enb_process_itti_msg(NULL); + //} + return NULL; } /*------------------------------------------------------------------------------*/ diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 58be63a848..80721a1c28 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -61,7 +61,7 @@ int create_tasks(uint32_t enb_nb) { rc = itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL); AssertFatal(rc >= 0, "Create task for RRC eNB failed\n"); - if (EPC_MODE_ENABLED) { + if (EPC_MODE_ENABLED && !fs6Du ) { rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); AssertFatal(rc >= 0, "Create task for SCTP failed\n"); } From f0759d6e615e30c4f58be3dbdc4aedc543e994a7 Mon Sep 17 00:00:00 2001 From: laurent Date: Wed, 30 Oct 2019 11:10:41 +0100 Subject: [PATCH 056/175] dl in threadpool ok --- executables/main-ocp.c | 8 + openair1/PHY/LTE_TRANSPORT/dci_tools.c | 42 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 427 +++++++----------- openair1/PHY/LTE_TRANSPORT/pmch.c | 1 + openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 8 +- openair1/PHY/LTE_TRANSPORT/transport_proto.h | 2 + openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 60 +++ .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 2 - openair1/PHY/defs_eNB.h | 48 ++ openair1/SCHED/fapi_l1.c | 16 +- openair1/SCHED/phy_procedures_lte_eNb.c | 155 ++++++- openair2/PHY_INTERFACE/IF_Module.h | 6 + targets/RT/USER/lte-softmodem.h | 3 + 13 files changed, 462 insertions(+), 316 deletions(-) diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 5ae15c8a29..34cd950ce7 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -29,6 +29,7 @@ static int DEFENBS[] = {0}; #include #include #include +#include extern uint16_t sf_ahead; @@ -691,6 +692,13 @@ static void *ru_thread( void *param ) { L1_rxtx_proc_t L1proc; L1_rxtx_proc_t *proc=&L1proc; + if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) { + initTpool(get_softmodem_params()->threadPoolConfig, &L1proc.threadPool, true); + initNotifiedFIFO(&L1proc.respEncode); + initNotifiedFIFO(&L1proc.respDecode); + } else + initTpool("n", &L1proc.threadPool, true); + if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index a8032b3368..fafc009e51 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -314,17 +314,17 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t proc->frame_tx,proc->subframe_tx, dlsch0->rnti,dlsch0->harq_mask, rel8->rnti, rel8->rnti_type, rel8->harq_process, rel8->new_data_indicator_1, - dlsch0_harq->round, dlsch0->harq_mask, dlsch0_harq->ndi); + dlsch0_harq->DLround, dlsch0->harq_mask, dlsch0_harq->ndi); if (dlsch0->rnti != rel8->rnti) { // if rnti of dlsch is not the same as in the config, this is a new entry - dlsch0_harq->round=0; + dlsch0_harq->DLround=0; dlsch0->harq_mask=0; } if ((dlsch0->harq_mask & (1 << rel8->harq_process)) > 0) { if (rel8->new_data_indicator_1 != dlsch0_harq->ndi) - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; } else { // process is inactive, so activate and set round to 0 - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; } dlsch0_harq->ndi = rel8->new_data_indicator_1; @@ -335,12 +335,12 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0->active = 1; #endif if (rel8->rnti_type == 2) - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; LOG_D(PHY,"NFAPI: rel8[rnti %x dci_format %d harq_process %d ndi1 %d rnti type %d] dlsch0[rnti %x harq_mask %x] dlsch0_harq[round %d ndi %d]\n", rel8->rnti,rel8->dci_format,rel8->harq_process, rel8->new_data_indicator_1, rel8->rnti_type, dlsch0->rnti,dlsch0->harq_mask, - dlsch0_harq->round,dlsch0_harq->ndi + dlsch0_harq->DLround,dlsch0_harq->ndi ); switch (rel8->dci_format) { @@ -503,7 +503,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t NPRB = dlsch0_harq->nb_rb; I_mcs = get_I_TBS(rel8->mcs_1); } - AssertFatal(NPRB>0,"DCI 1A: NPRB = 0 (rnti %x, rnti type %d, tpc %d, round %d, resource_block_coding %d, harq process %d)\n",rel8->rnti,rel8->rnti_type,rel8->tpc,dlsch0_harq->round,rel8->resource_block_coding,rel8->harq_process); + AssertFatal(NPRB>0,"DCI 1A: NPRB = 0 (rnti %x, rnti type %d, tpc %d, round %d, resource_block_coding %d, harq process %d)\n",rel8->rnti,rel8->rnti_type,rel8->tpc,dlsch0_harq->DLround,rel8->resource_block_coding,rel8->harq_process); dlsch0_harq->rvidx = rel8->redundancy_version_1; dlsch0_harq->Nl = 1; dlsch0_harq->mimo_mode = (fp->nb_antenna_ports_eNB == 1) ? SISO : ALAMOUTI; @@ -523,12 +523,12 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t dlsch0->rnti = rel8->rnti; //dlsch0->harq_ids[subframe] = rel8->harq_process; - if (dlsch0_harq->round == 0) + if (dlsch0_harq->DLround == 0) dlsch0_harq->status = ACTIVE; dlsch0->harq_mask |= (1 << rel8->harq_process); - if (rel8->rnti_type == 1) LOG_D(PHY,"DCI 1A: round %d, mcs %d, TBS %d, rballoc %x, rv %d, rnti %x, harq process %d\n",dlsch0_harq->round,rel8->mcs_1,dlsch0_harq->TBS,rel8->resource_block_coding,rel8->redundancy_version_1,rel8->rnti,rel8->harq_process); + if (rel8->rnti_type == 1) LOG_D(PHY,"DCI 1A: round %d, mcs %d, TBS %d, rballoc %x, rv %d, rnti %x, harq process %d\n",dlsch0_harq->DLround,rel8->mcs_1,dlsch0_harq->TBS,rel8->resource_block_coding,rel8->redundancy_version_1,rel8->rnti,rel8->harq_process); break; case NFAPI_DL_DCI_FORMAT_1: @@ -690,7 +690,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t - if (dlsch0_harq->round == 0) { + if (dlsch0_harq->DLround == 0) { dlsch0_harq->status = ACTIVE; // printf("Setting DLSCH process %d to ACTIVE\n",rel8->harq_process); @@ -1042,16 +1042,16 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t // reset HARQ process if this is the first transmission #ifdef PHY_TX_THREAD - if ((dlsch0->active[subframe]==1) && (dlsch0_harq->round == 0)) + if ((dlsch0->active[subframe]==1) && (dlsch0_harq->DLround == 0)) #else - if ((dlsch0->active==1) && (dlsch0_harq->round == 0)) + if ((dlsch0->active==1) && (dlsch0_harq->DLround == 0)) #endif dlsch0_harq->status = ACTIVE; #ifdef PHY_TX_THREAD - if ((dlsch1->active[subframe]==1) && (dlsch1_harq->round == 0)) + if ((dlsch1->active[subframe]==1) && (dlsch1_harq->DLround == 0)) #else - if ((dlsch1->active==1) && (dlsch1_harq->round == 0)) + if ((dlsch1->active==1) && (dlsch1_harq->DLround == 0)) #endif dlsch1_harq->status = ACTIVE; @@ -1479,7 +1479,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t printf ("dlsch0 eNB: NBRB %d\n", dlsch0_harq->nb_rb); printf ("dlsch0 eNB: rballoc %x\n", dlsch0_harq->rb_alloc[0]); printf ("dlsch0 eNB: harq_pid %d\n", harq_pid); - printf ("dlsch0 eNB: round %d\n", dlsch0_harq->round); + printf ("dlsch0 eNB: round %d\n", dlsch0_harq->DLround); printf ("dlsch0 eNB: rvidx %d\n", dlsch0_harq->rvidx); printf ("dlsch0 eNB: TBS %d (NPRB %d)\n", dlsch0_harq->TBS, NPRB); printf ("dlsch0 eNB: mcs %d\n", dlsch0_harq->mcs); @@ -1493,7 +1493,7 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_proc_t printf ("dlsch1 eNB: NBRB %d\n", dlsch1_harq->nb_rb); printf ("dlsch1 eNB: rballoc %x\n", dlsch1_harq->rb_alloc[0]); printf ("dlsch1 eNB: harq_pid %d\n", harq_pid); - printf ("dlsch1 eNB: round %d\n", dlsch1_harq->round); + printf ("dlsch1 eNB: round %d\n", dlsch1_harq->DLround); printf ("dlsch1 eNB: rvidx %d\n", dlsch1_harq->rvidx); printf ("dlsch1 eNB: TBS %d (NPRB %d)\n", dlsch1_harq->TBS, NPRB); printf ("dlsch1 eNB: mcs %d\n", dlsch1_harq->mcs); @@ -1748,19 +1748,19 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,mDCI_ALLOC_t *dc dlsch0->subframe_tx[subframe] = 1; if (dlsch0->rnti != rel13->rnti) { // if rnti of dlsch is not the same as in the config, this is a new entry - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; dlsch0->harq_mask =0; printf("*********************** rnti %x => %x, pos %d\n",rel13->rnti,dlsch0->rnti,UE_id); } if ((dlsch0->harq_mask & (1 << rel13->harq_process)) > 0) { if ((rel13->new_data_indicator != dlsch0_harq->ndi)||(dci_alloc->ra_flag==1)) - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; } else { // process is inactive, so activate and set round to 0 - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; } dlsch0_harq->ndi = rel13->new_data_indicator; - if (dlsch0_harq->round == 0) { + if (dlsch0_harq->DLround == 0) { dlsch0_harq->status = ACTIVE; dlsch0_harq->mcs = rel13->mcs; if (dci_alloc->ra_flag == 0) // get TBS from table using mcs and nb_rb @@ -1782,7 +1782,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,mDCI_ALLOC_t *dc dlsch0->harq_ids[dlsch0_harq->frame%2][dlsch0_harq->subframe] = rel13->harq_process; dlsch0_harq->pdsch_start = rel13->start_symbol; - LOG_D(PHY,"Setting DLSCH harq %d round %d to active for %d.%d\n",rel13->harq_process,dlsch0_harq->round,dlsch0_harq->frame,dlsch0_harq->subframe); + LOG_D(PHY,"Setting DLSCH harq %d round %d to active for %d.%d\n",rel13->harq_process,dlsch0_harq->DLround,dlsch0_harq->frame,dlsch0_harq->subframe); dlsch0->rnti = rel13->rnti; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index b494f7bd6c..ea6bf29ac7 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -20,15 +20,15 @@ */ /*! \file PHY/LTE_TRANSPORT/dlsch_coding.c -* \brief Top-level routines for implementing Turbo-coded (DLSCH) transport channels from 36-212, V8.6 2009-03 -* \author R. Knopp -* \date 2011 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr -* \note -* \warning -*/ + * \brief Top-level routines for implementing Turbo-coded (DLSCH) transport channels from 36-212, V8.6 2009-03 + * \author R. Knopp + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr + * \note + * \warning + */ #include "PHY/defs_eNB.h" #include "PHY/phy_extern.h" @@ -42,21 +42,22 @@ #include "common/utils/LOG/log.h" #include #include "targets/RT/USER/rt_wrapper.h" +#include //#define DEBUG_DLSCH_CODING //#define DEBUG_DLSCH_FREE 1 /* -#define is_not_pilot(pilots,first_pilot,re) (pilots==0) || \ + #define is_not_pilot(pilots,first_pilot,re) (pilots==0) || \ ((pilots==1)&&(first_pilot==1)&&(((re>2)&&(re<6))||((re>8)&&(re<12)))) || \ ((pilots==1)&&(first_pilot==0)&&(((re<3))||((re>5)&&(re<9)))) \ */ #define is_not_pilot(pilots,first_pilot,re) (1) /*extern void thread_top_init(char *thread_name, - int affinity, - uint64_t runtime, - uint64_t deadline, - uint64_t period);*/ + int affinity, + uint64_t runtime, + uint64_t deadline, + uint64_t period);*/ extern WORKER_CONF_t get_thread_worker_conf(void); @@ -82,11 +83,6 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch) { free16(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); dlsch->harq_processes[i]->c[r] = NULL; } - - if (dlsch->harq_processes[i]->d[r]) { - free16(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144))); - dlsch->harq_processes[i]->d[r] = NULL; - } } free16(dlsch->harq_processes[i],sizeof(LTE_DL_eNB_HARQ_t)); @@ -100,26 +96,26 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch) { LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_t Nsoft,unsigned char N_RB_DL, uint8_t abstraction_flag, LTE_DL_FRAME_PARMS *frame_parms) { LTE_eNB_DLSCH_t *dlsch; - unsigned char exit_flag = 0,i,j,r,aa,layer; + unsigned char exit_flag = 0,i,r,aa,layer; int re; unsigned char bw_scaling =1; switch (N_RB_DL) { - case 6: - bw_scaling =16; - break; + case 6: + bw_scaling =16; + break; - case 25: - bw_scaling =4; - break; + case 25: + bw_scaling =4; + break; - case 50: - bw_scaling =2; - break; + case 50: + bw_scaling =2; + break; - default: - bw_scaling =1; - break; + default: + bw_scaling =1; + break; } dlsch = (LTE_eNB_DLSCH_t *)malloc16(sizeof(LTE_eNB_DLSCH_t)); @@ -145,11 +141,11 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ // NOTE: THIS HAS TO BE REVISED FOR RU, commenting to remove memory leak !!!!! /* - dlsch->calib_dl_ch_estimates = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); - for (aa=0; aanb_antennas_tx; aa++) { - dlsch->calib_dl_ch_estimates[aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + dlsch->calib_dl_ch_estimates = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + for (aa=0; aanb_antennas_tx; aa++) { + dlsch->calib_dl_ch_estimates[aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); - }*/ + }*/ for (i=0; i<20; i++) dlsch->harq_ids[i/10][i%10] = Mdlharq; @@ -175,7 +171,6 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ for (r=0; rharq_processes[i]->c[r] = (uint8_t *)malloc16(((r==0)?8:0) + 3+ 768); - dlsch->harq_processes[i]->d[r] = (uint8_t *)malloc16((96+12+3+(3*6144))); if (dlsch->harq_processes[i]->c[r]) { bzero(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+ 768); @@ -183,13 +178,6 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ printf("Can't get c\n"); exit_flag=2; } - - if (dlsch->harq_processes[i]->d[r]) { - bzero(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144))); - } else { - printf("Can't get d\n"); - exit_flag=2; - } } } } else { @@ -200,14 +188,7 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ if (exit_flag==0) { for (i=0; iharq_processes[i]->round=0; - - for (j=0; j<96; j++) - for (r=0; rharq_processes[%d]->d[%d] %p\n",i,r,dlsch->harq_processes[i]->d[r]); - if (dlsch->harq_processes[i]->d[r]) - dlsch->harq_processes[i]->d[r][j] = LTE_NULL; - } + dlsch->harq_processes[i]->DLround=0; } return(dlsch); @@ -222,7 +203,7 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch) { unsigned char Mdlharq; - unsigned char i,j,r; + unsigned char i; if (dlsch) { Mdlharq = dlsch->Mdlharq; @@ -244,92 +225,17 @@ void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch) { if (dlsch->harq_processes[i]) { // dlsch->harq_processes[i]->Ndi = 0; dlsch->harq_processes[i]->status = 0; - dlsch->harq_processes[i]->round = 0; + dlsch->harq_processes[i]->DLround = 0; - for (j=0; j<96; j++) - for (r=0; rharq_processes[i]->d[r]) - dlsch->harq_processes[i]->d[r][j] = LTE_NULL; } } } } - - - -int dlsch_encoding_2threads0(te_params *tep) { - LTE_eNB_DLSCH_t *dlsch = tep->dlsch; - unsigned int G = tep->G; - unsigned char harq_pid = tep->harq_pid; - unsigned int total_worker = tep->total_worker; - unsigned int current_worker = tep->current_worker; - unsigned short nb_rb = dlsch->harq_processes[harq_pid]->nb_rb; - unsigned int Kr=0,Kr_bytes,r,r_offset=0; - // unsigned short m=dlsch->harq_processes[harq_pid]->mcs; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING_W, VCD_FUNCTION_IN); - - if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet - for (r=(dlsch->harq_processes[harq_pid]->C/(total_worker+1))*current_worker; r<(dlsch->harq_processes[harq_pid]->C/(total_worker+1))*(current_worker+1); r++) { - if (rharq_processes[harq_pid]->Cminus) - Kr = dlsch->harq_processes[harq_pid]->Kminus; - else - Kr = dlsch->harq_processes[harq_pid]->Kplus; - - Kr_bytes = Kr>>3; - encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0 - ); - dlsch->harq_processes[harq_pid]->RTC[r] = - sub_block_interleaving_turbo(4+(Kr_bytes*8), - &dlsch->harq_processes[harq_pid]->d[r][96], - dlsch->harq_processes[harq_pid]->w[r]); - } - } - - // Fill in the "e"-sequence from 36-212, V8.6 2009-03, p. 16-17 (for each "e") and concatenate the - // outputs for each code segment, see Section 5.1.5 p.20 - - for (r=0,r_offset=0; r<(dlsch->harq_processes[harq_pid]->C/(total_worker+1))*(current_worker+1); r++) { - if(r<(dlsch->harq_processes[harq_pid]->C/(total_worker+1))*(current_worker)) { - int Nl=dlsch->harq_processes[harq_pid]->Nl; - int Qm=dlsch->harq_processes[harq_pid]->Qm; - int C = dlsch->harq_processes[harq_pid]->C; - int Gp = G/Nl/Qm; - int GpmodC = Gp%C; - - if (r < (C-(GpmodC))) - r_offset += Nl*Qm * (Gp/C); - else - r_offset += Nl*Qm * ((GpmodC==0?0:1) + (Gp/C)); - } else { - r_offset += lte_rate_matching_turbo(dlsch->harq_processes[harq_pid]->RTC[r], - G, //G - dlsch->harq_processes[harq_pid]->w[r], - dlsch->harq_processes[harq_pid]->e+r_offset, - dlsch->harq_processes[harq_pid]->C, // C - dlsch->Nsoft, // Nsoft, - dlsch->Mdlharq, - dlsch->Kmimo, - dlsch->harq_processes[harq_pid]->rvidx, - dlsch->harq_processes[harq_pid]->Qm, - dlsch->harq_processes[harq_pid]->Nl, - r, - nb_rb); - // m); // r - } - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING_W, VCD_FUNCTION_OUT); - return(0); -} - - extern int oai_exit; int dlsch_encoding_all(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, unsigned char *a, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch, @@ -342,45 +248,72 @@ int dlsch_encoding_all(PHY_VARS_eNB *eNB, time_stats_t *te_wakeup_stats0, time_stats_t *te_wakeup_stats1, time_stats_t *i_stats) { - int encoding_return = 0; - unsigned int L,C,B; uint8_t harq_pid = dlsch->harq_ids[frame%2][subframe]; if(harq_pid >= dlsch->Mdlharq) { LOG_E(PHY,"dlsch_encoding_all illegal harq_pid %d\n", harq_pid); return(-1); } - B = dlsch->harq_processes[harq_pid]->B; + + LOG_D(PHY,"B %d, harq_pid %d\n", + dlsch->harq_processes[harq_pid]->B, + dlsch->harq_ids[frame%2][subframe]); - LOG_D(PHY,"B %d, harq_pid %d\n",B,dlsch->harq_ids[frame%2][subframe]); + return dlsch_encoding(eNB, + proc, + a, + num_pdcch_symbols, + dlsch, + frame, + subframe, + rm_stats, + te_stats, + i_stats); - if(B<=6144) { - L=0; - C=1; - } else { - L=24; - C = B/(6144-L); - - if((6144-L)*C < B) { - C = C+1; - } - } - - encoding_return = - dlsch_encoding(eNB, - a, - num_pdcch_symbols, - dlsch, - frame, - subframe, - rm_stats, - te_stats, - i_stats); - - return encoding_return; } +static void TPencode(void * arg) { + turboEncode_t * rdata=(turboEncode_t *) arg; + unsigned char harq_pid = rdata->harq_pid; + LTE_DL_eNB_HARQ_t *hadlsch=rdata->dlsch->harq_processes[harq_pid]; + + if ( rdata-> round == 0) { + uint8_t tmp[96+12+3+3*6144]; + memset(tmp,LTE_NULL, TURBO_SIMD_SOFTBITS); + start_meas(rdata->te_stats); + encoder(rdata->input, + rdata->Kr_bytes, + tmp+96,//&dlsch->harq_processes[harq_pid]->d[r][96], + rdata->filler); + stop_meas(rdata->te_stats); + start_meas(rdata->i_stats); + hadlsch->RTC[rdata->r] = + sub_block_interleaving_turbo(4+(rdata->Kr_bytes*8), + tmp+96, + hadlsch->w[rdata->r]); + stop_meas(rdata->i_stats); + } + + // Fill in the "e"-sequence from 36-212, V8.6 2009-03, p. 16-17 (for each "e") and concatenate the + // outputs for each code segment, see Section 5.1.5 p.20 + start_meas(rdata->rm_stats); + lte_rate_matching_turbo(hadlsch->RTC[rdata->r], + rdata->G, //G + hadlsch->w[rdata->r], + hadlsch->e+rdata->r_offset, + hadlsch->C, // C + rdata->dlsch->Nsoft, // Nsoft, + rdata->dlsch->Mdlharq, + rdata->dlsch->Kmimo, + hadlsch->rvidx, + hadlsch->Qm, + hadlsch->Nl, + rdata->r, + hadlsch->nb_rb); + stop_meas(rdata->rm_stats); +} int dlsch_encoding(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, unsigned char *a, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch, @@ -389,8 +322,6 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, time_stats_t *rm_stats, time_stats_t *te_stats, time_stats_t *i_stats) { - unsigned int G; - unsigned int crc=1; LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms; unsigned char harq_pid = dlsch->harq_ids[frame%2][subframe]; if((harq_pid < 0) || (harq_pid >= dlsch->Mdlharq)) { @@ -398,136 +329,88 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, return(-1); } - unsigned short nb_rb = dlsch->harq_processes[harq_pid]->nb_rb; - unsigned int A; - unsigned char mod_order; - unsigned int Kr=0,Kr_bytes,r,r_offset=0; - // unsigned short m=dlsch->harq_processes[harq_pid]->mcs; + LTE_DL_eNB_HARQ_t *hadlsch=dlsch->harq_processes[harq_pid]; uint8_t beamforming_mode=0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN); - A = dlsch->harq_processes[harq_pid]->TBS; //6228 - // printf("Encoder: A: %d\n",A); - mod_order = dlsch->harq_processes[harq_pid]->Qm; - if(dlsch->harq_processes[harq_pid]->mimo_mode == TM7) + if(hadlsch->mimo_mode == TM7) beamforming_mode = 7; - else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM8) + else if(hadlsch->mimo_mode == TM8) beamforming_mode = 8; - else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM9_10) + else if(hadlsch->mimo_mode == TM9_10) beamforming_mode = 9; - G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,beamforming_mode); + unsigned int G = get_G(frame_parms,hadlsch->nb_rb, + hadlsch->rb_alloc, + hadlsch->Qm, // mod order + hadlsch->Nl, + num_pdcch_symbols, + frame,subframe,beamforming_mode); - // if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet - if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet -#ifdef DEBUG_DLSCH_CODING - printf("encoding thinks this is a new packet for harq_pid %d (%p), A %u \n",harq_pid,dlsch,A); -#endif - /* - int i; - printf("dlsch (tx): \n"); - for (i=0;i<(A>>3);i++) - printf("%02x.",a[i]); - printf("\n"); - */ + proc->nbEncode=0; + + // if (hadlsch->Ndi == 1) { // this is a new packet + if (hadlsch->DLround == 0) { // this is a new packet // Add 24-bit crc (polynomial A) to payload - crc = crc24a(a, + unsigned int A=hadlsch->TBS; //6228; + unsigned int crc = crc24a(a, A)>>8; a[A>>3] = ((uint8_t *)&crc)[2]; a[1+(A>>3)] = ((uint8_t *)&crc)[1]; a[2+(A>>3)] = ((uint8_t *)&crc)[0]; // printf("CRC %x (A %d)\n",crc,A); - dlsch->harq_processes[harq_pid]->B = A+24; - // dlsch->harq_processes[harq_pid]->b = a; - memcpy(dlsch->harq_processes[harq_pid]->b,a,(A/8)+4); - - if (lte_segmentation(dlsch->harq_processes[harq_pid]->b, - dlsch->harq_processes[harq_pid]->c, - dlsch->harq_processes[harq_pid]->B, - &dlsch->harq_processes[harq_pid]->C, - &dlsch->harq_processes[harq_pid]->Cplus, - &dlsch->harq_processes[harq_pid]->Cminus, - &dlsch->harq_processes[harq_pid]->Kplus, - &dlsch->harq_processes[harq_pid]->Kminus, - &dlsch->harq_processes[harq_pid]->F)<0) + hadlsch->B = A+24; + // hadlsch->b = a; + memcpy(hadlsch->b,a,(A/8)+4); + + if (lte_segmentation(hadlsch->b, + hadlsch->c, + hadlsch->B, + &hadlsch->C, + &hadlsch->Cplus, + &hadlsch->Cminus, + &hadlsch->Kplus, + &hadlsch->Kminus, + &hadlsch->F)<0) return(-1); - - for (r=0; rharq_processes[harq_pid]->C; r++) { - if (rharq_processes[harq_pid]->Cminus) - Kr = dlsch->harq_processes[harq_pid]->Kminus; - else - Kr = dlsch->harq_processes[harq_pid]->Kplus; - - Kr_bytes = Kr>>3; -#ifdef DEBUG_DLSCH_CODING - printf("Generating Code Segment %u (%u bits)\n",r,Kr); - // generate codewords - printf("bits_per_codeword (Kr)= %u, A %u\n",Kr,A); - printf("N_RB = %d\n",nb_rb); - printf("Ncp %d\n",frame_parms->Ncp); - printf("mod_order %d\n",mod_order); -#endif - start_meas(te_stats); - encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0 - ); - stop_meas(te_stats); -#ifdef DEBUG_DLSCH_CODING - - if (r==0) - LOG_M("enc_output0.m","enc0",&dlsch->harq_processes[harq_pid]->d[r][96],(3*8*Kr_bytes)+12,1,4); - -#endif - start_meas(i_stats); - dlsch->harq_processes[harq_pid]->RTC[r] = - sub_block_interleaving_turbo(4+(Kr_bytes*8), - &dlsch->harq_processes[harq_pid]->d[r][96], - dlsch->harq_processes[harq_pid]->w[r]); - stop_meas(i_stats); + } + + for (int r=0, r_offset=0; rC; r++) { + + union turboReqUnion id= {.s={dlsch->rnti,frame,subframe,r,0}}; + notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboEncode_t), id.p, &proc->respEncode, TPencode); + turboEncode_t * rdata=(turboEncode_t *) NotifiedFifoData(req); + rdata->input=hadlsch->c[r]; + rdata->Kr_bytes= ( rCminus ? hadlsch->Kminus : hadlsch->Kplus) >>3; + rdata->filler=(r==0) ? hadlsch->F : 0; + rdata->r=r; + rdata->harq_pid=harq_pid; + rdata->dlsch=dlsch; + rdata->rm_stats=rm_stats; + rdata->te_stats=te_stats; + rdata->i_stats=i_stats; + rdata->round=hadlsch->DLround; + rdata->r_offset=r_offset; + rdata->G=G; + + if ( proc->threadPool.activated) { + pushTpool(&proc->threadPool,req); + proc->nbEncode++; + } else { + TPencode(rdata); } + + int Qm=hadlsch->Qm; + int C=hadlsch->C; + int Nl=hadlsch->Nl; + int Gp = G/Nl/Qm; + int GpmodC = Gp%C; + if (r < (C-(GpmodC))) + r_offset += Nl*Qm * (Gp/C); + else + r_offset += Nl*Qm * ((GpmodC==0?0:1) + (Gp/C)); } - // Fill in the "e"-sequence from 36-212, V8.6 2009-03, p. 16-17 (for each "e") and concatenate the - // outputs for each code segment, see Section 5.1.5 p.20 - - for (r=0; rharq_processes[harq_pid]->C; r++) { -#ifdef DEBUG_DLSCH_CODING - printf("Rate Matching, Code segment %u (coded bits (G) %u,unpunctured/repeated bits per code segment %u,mod_order %d, nb_rb %d)...\n", - r, - G, - Kr*3, - mod_order,nb_rb); -#endif - start_meas(rm_stats); -#ifdef DEBUG_DLSCH_CODING - printf("rvidx in encoding = %d\n", dlsch->harq_processes[harq_pid]->rvidx); -#endif - r_offset += lte_rate_matching_turbo(dlsch->harq_processes[harq_pid]->RTC[r], - G, //G - dlsch->harq_processes[harq_pid]->w[r], - dlsch->harq_processes[harq_pid]->e+r_offset, - dlsch->harq_processes[harq_pid]->C, // C - dlsch->Nsoft, // Nsoft, - dlsch->Mdlharq, - dlsch->Kmimo, - dlsch->harq_processes[harq_pid]->rvidx, - dlsch->harq_processes[harq_pid]->Qm, - dlsch->harq_processes[harq_pid]->Nl, - r, - nb_rb); - // m); // r - stop_meas(rm_stats); -#ifdef DEBUG_DLSCH_CODING - - if (r==dlsch->harq_processes[harq_pid]->C-1) - LOG_M("enc_output.m","enc",dlsch->harq_processes[harq_pid]->e,r_offset,1,4); - -#endif - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_OUT); return(0); } diff --git a/openair1/PHY/LTE_TRANSPORT/pmch.c b/openair1/PHY/LTE_TRANSPORT/pmch.c index 6fab3dc59b..965ac66eef 100644 --- a/openair1/PHY/LTE_TRANSPORT/pmch.c +++ b/openair1/PHY/LTE_TRANSPORT/pmch.c @@ -102,6 +102,7 @@ void generate_mch(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc,uint8_t *a) AssertFatal(dlsch_encoding(eNB, + proc, a, 1, eNB->dlsch_MCH, diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 5feb1389be..9e78eb75a0 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -71,7 +71,7 @@ typedef struct { /// Subframe where current HARQ round was sent uint32_t subframe; /// Index of current HARQ round for this DLSCH - uint8_t round; + uint8_t DLround; /// Modulation order uint8_t Qm; /// MCS @@ -103,7 +103,7 @@ typedef struct { /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) uint8_t e[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); /// Turbo-code outputs (36-212 V8.6 2009-03, p.12 - uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))]; + //uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))]; /// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17) uint8_t w[MAX_NUM_DLSCH_SEGMENTS][3*6144]; /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) @@ -272,6 +272,7 @@ typedef struct { /// Pointer to the payload uint8_t *b; /// Pointers to transport block segments + //TBD uint8_t *c[MAX_NUM_ULSCH_SEGMENTS]; /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) uint32_t RTC[MAX_NUM_ULSCH_SEGMENTS]; @@ -288,7 +289,10 @@ typedef struct { /// soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) int16_t w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; /// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + //TBD int16_t *d[MAX_NUM_ULSCH_SEGMENTS]; + uint32_t processedSegments; + uint32_t processedBadSegment; /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) uint32_t C; /// Number of "small" code segments (for definition see 36-212 V8.6 2009-03, p.10) diff --git a/openair1/PHY/LTE_TRANSPORT/transport_proto.h b/openair1/PHY/LTE_TRANSPORT/transport_proto.h index a795ca79a0..a358df3ff3 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_proto.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_proto.h @@ -73,6 +73,7 @@ void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch); LTE_eNB_ULSCH_t *new_eNB_ulsch(uint8_t max_turbo_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag); int dlsch_encoding_all(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, unsigned char *a, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch, @@ -112,6 +113,7 @@ int dlsch_encoding_all(PHY_VARS_eNB *eNB, @returns status */ int32_t dlsch_encoding(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, uint8_t *a, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch, diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 1f8afe2609..64b83c524a 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -313,6 +313,14 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) r_offset += E; start_meas(&eNB->ulsch_deinterleaving_stats); + #if 0 + start_meas(&eNB->ulsch_deinterleaving_stats); + req=createRequest(DECODE,sizeof(turboDecode_t)); + req->startUELoop=eNB->proc.threadPool.startProcessingUE; + union turboReqUnion id= {.s={eNB->ulsch[UE_id]->rnti,frame,subframe,r,0}}; + req->id= id.p; + turboDecode_t * rdata=(turboDecode_t *) req->data; + #endif sub_block_deinterleaving_turbo(4+Kr, &ulsch_harq->d[r][96], ulsch_harq->w[r]); @@ -322,6 +330,58 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) crc_type = CRC24_A; else crc_type = CRC24_B; + #if 0 + rdata->frame=frame; + rdata->subframe=subframe; + rdata->UEid=UE_id; + rdata->harq_pid=harq_pid; + rdata->Kr=Kr; + rdata->maxIterations=eNB->ulsch[UE_id]->max_turbo_iterations; + rdata->ulsch_harq=ulsch_harq; + rdata->eNB=eNB; + rdata->nbSegments=ulsch_harq->C; + rdata->segment_r=r; + rdata->Fbits=(r==0) ? ulsch_harq->F : 0; + rdata->offset=offset; + rdata->function=td; + int Fbytes=rdata->Fbits>>3; + int blockSize=Kr_bytes - Fbytes - (rdata->nbSegments>1?3:0); + if ( eNB->proc.threadPool.activated) { + add_request(req, &eNB->proc.threadPool); + req=NULL; + } else { + req->startProcessingTime=rdtsc(); + rdata->decodeIterations = td( rdata->soft_bits+96, + rdata->decoded_bytes, + rdata->Kr, + f1f2mat_old[rdata->iind*2], + f1f2mat_old[(rdata->iind*2)+1], + rdata->maxIterations, + rdata->nbSegments == 1 ? CRC24_A: CRC24_B, + rdata->Fbits, + &eNB->ulsch_tc_init_stats, + &eNB->ulsch_tc_alpha_stats, + &eNB->ulsch_tc_beta_stats, + &eNB->ulsch_tc_gamma_stats, + &eNB->ulsch_tc_ext_stats, + &eNB->ulsch_tc_intl1_stats, + &eNB->ulsch_tc_intl2_stats); + + stop_meas(&eNB->ulsch_turbo_decoding_stats); + req->returnTime=req->endProcessingTime=rdtsc(); + req->decodeIterations=rdata->decodeIterations; + req->coreId=0; + req->processedBy[0]=0; + req->next=eNB->proc.threadPool.doneRequests; + eNB->proc.threadPool.doneRequests=req; + + if (rdata->decodeIterations > eNB->ulsch[UE_id]->max_turbo_iterations ) + // Entire TPU need retransmission + break; + } +offset += blockSize; + eNB->proc.threadPool.startProcessingUE=rdtsc(); + #endif start_meas(&eNB->ulsch_turbo_decoding_stats); ret = tc(&ulsch_harq->d[r][96], NULL, diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index da213c3919..0b9fd57d19 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1332,8 +1332,6 @@ void rx_ulsch_emul(PHY_VARS_eNB *eNB, eNB->ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch); sprintf(fname,"/tmp/ulsch_r%d_d",round); sprintf(vname,"/tmp/ulsch_r%d_dseq",round); - LOG_UM(fname,vname,&eNB->ulsch[UE_id]->harq_processes[harq_pid]->d[0][96], - eNB->ulsch[UE_id]->harq_processes[harq_pid]->Kplus*3,1,0); if (eNB->common_vars.rxdata) { sprintf(fname,"/tmp/rxsig0_r%d.m",round); sprintf(vname,"rxs0_r%d",round); diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index 1ae3515cd8..718ede5715 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -857,6 +857,54 @@ typedef struct PHY_VARS_eNB_s { uint8_t *FS6bufferZone; } PHY_VARS_eNB; +struct turboReqId { + uint16_t rnti; + uint16_t frame; + uint8_t subframe; + uint8_t codeblock; + uint16_t spare; +} __attribute__((packed)); + +union turboReqUnion { + struct turboReqId s; + uint64_t p; +}; + +typedef struct TurboDecode_s { + decoder_if_t *function; + int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32))); + uint8_t decoded_bytes[3+768] __attribute__((aligned(32))); + int UEid; + int harq_pid; + int frame; + int subframe; + int iind; + int Fbits; + int Kr; + LTE_UL_eNB_HARQ_t *ulsch_harq; + PHY_VARS_eNB *eNB; + int nbSegments; + int segment_r; + int offset; + int maxIterations; + int decodeIterations; +} turboDecode_t; + +#define TURBO_SIMD_SOFTBITS 96+12+3+3*6144 +typedef struct turboEncode_s { + uint8_t * input; + int Kr_bytes; + int filler; + unsigned int G; + int r; + int harq_pid; + int round; + int r_offset; + LTE_eNB_DLSCH_t *dlsch; + time_stats_t *rm_stats; + time_stats_t *te_stats; + time_stats_t *i_stats; +} turboEncode_t; #endif /* __PHY_DEFS_ENB__H__ */ diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index b52a2eb22c..1a088563f0 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -220,13 +220,13 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro dlsch0_harq->pdsch_start = eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols; - if (dlsch0_harq->round==0) { //get pointer to SDU if this a new SDU + if (dlsch0_harq->DLround==0) { //get pointer to SDU if this a new SDU if(sdu == NULL) { LOG_E(PHY, "NFAPI: SFN/SF:%04d%d proc:TX:[frame %d subframe %d]: programming dlsch for round 0, rnti %x, UE_id %d, harq_pid %d : sdu is null for pdu_index %d dlsch0_harq[round:%d SFN/SF:%d%d pdu:%p mcs:%d ndi:%d pdschstart:%d]\n", frame,subframe, proc->frame_tx,proc->subframe_tx,rel8->rnti,UE_id,harq_pid, - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index,dlsch0_harq->round,dlsch0_harq->frame,dlsch0_harq->subframe,dlsch0_harq->pdu,dlsch0_harq->mcs,dlsch0_harq->ndi,dlsch0_harq->pdsch_start); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index,dlsch0_harq->DLround,dlsch0_harq->frame,dlsch0_harq->subframe,dlsch0_harq->pdu,dlsch0_harq->mcs,dlsch0_harq->ndi,dlsch0_harq->pdsch_start); return; } @@ -241,7 +241,7 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro else dlsch1_harq->pdu = sdu; } else { if (rel8->rnti != 0xFFFF) LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:[frame %d, subframe %d]: programming dlsch for round %d, rnti %x, UE_id %d, harq_pid %d\n", - frame,subframe,proc->frame_tx,proc->subframe_tx,dlsch0_harq->round, + frame,subframe,proc->frame_tx,proc->subframe_tx,dlsch0_harq->DLround, rel8->rnti,UE_id,harq_pid); } @@ -321,7 +321,7 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro dlsch0_harq->Nl = 1; dlsch0_harq->mimo_mode = (eNB->frame_parms.nb_antenna_ports_eNB == 1) ? SISO : ALAMOUTI; dlsch0_harq->dl_power_off = 1; - dlsch0_harq->round = 0; + dlsch0_harq->DLround = 0; dlsch0_harq->status = ACTIVE; dlsch0_harq->TBS = rel8->length<<3; dlsch0_harq->Qm = rel8->modulation; @@ -346,13 +346,13 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro #else dlsch0->i0, #endif - dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->round, dlsch0_harq->status, + dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->DLround, dlsch0_harq->status, dlsch0_harq->TBS, dlsch0_harq->Qm, dlsch0_harq->codeword, dlsch0_harq->rb_alloc[0], rel8->length ); #else LOG_D(PHY,"dlsch0_harq[pdsch_start:%d nb_rb:%d vrb_type:%d rvidx:%d Nl:%d mimo_mode:%d dl_power_off:%d round:%d status:%d TBS:%d Qm:%d codeword:%d rb_alloc:%d] rel8[length:%d]\n", - dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->round, dlsch0_harq->status, + dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->DLround, dlsch0_harq->status, dlsch0_harq->TBS, dlsch0_harq->Qm, dlsch0_harq->codeword, dlsch0_harq->rb_alloc[0], rel8->length ); @@ -385,7 +385,7 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro #endif dlsch0_harq->pdsch_start = eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols; - if (dlsch0_harq->round==0) { //get pointer to SDU if this a new SDU + if (dlsch0_harq->DLround==0) { //get pointer to SDU if this a new SDU AssertFatal(sdu!=NULL,"NFAPI: frame %d, subframe %d: programming dlsch for round 0, rnti %x, UE_id %d, harq_pid %d : sdu is null for pdu_index %d\n", proc->frame_tx,proc->subframe_tx,rel8->rnti,UE_id,harq_pid, dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index); @@ -397,7 +397,7 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro else dlsch1_harq->pdu = sdu; } else { if (rel8->rnti != 0xFFFF) LOG_D(PHY,"NFAPI: frame %d, subframe %d: programming dlsch for round %d, rnti %x, UE_id %d, harq_pid %d\n", - proc->frame_tx,proc->subframe_tx,dlsch0_harq->round, + proc->frame_tx,proc->subframe_tx,dlsch0_harq->DLround, rel8->rnti,UE_id,harq_pid); } } diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index e5c767361d..94689ed246 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -260,16 +260,16 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, dlsch_harq->TBS, pmi2hex_2Ar1(dlsch_harq->pmi_alloc), dlsch_harq->rvidx, - dlsch_harq->round); + dlsch_harq->DLround); } if (ue_stats) ue_stats->dlsch_sliding_cnt++; - if (dlsch_harq->round == 0) { + if (dlsch_harq->DLround == 0) { if (ue_stats) ue_stats->dlsch_trials[harq_pid][0]++; } else { - ue_stats->dlsch_trials[harq_pid][dlsch_harq->round]++; + ue_stats->dlsch_trials[harq_pid][dlsch_harq->DLround]++; #ifdef DEBUG_PHY_PROC #ifdef DEBUG_DLSCH LOG_D (PHY, "[eNB] This DLSCH is a retransmission\n"); @@ -280,18 +280,19 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, if (dlsch->rnti!=0xffff) LOG_D(PHY,"Generating DLSCH/PDSCH pdu:%p pdsch_start:%d frame:%d subframe:%d nb_rb:%d rb_alloc:%d Qm:%d Nl:%d round:%d\n", dlsch_harq->pdu,dlsch_harq->pdsch_start,frame,subframe,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0], - dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round); + dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->DLround); // 36-212 if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF if (dlsch_harq->pdu==NULL) { LOG_E(PHY,"dlsch_harq->pdu == NULL SFN/SF:%04d%d dlsch[rnti:%x] dlsch_harq[pdu:%p pdsch_start:%d Qm:%d Nl:%d round:%d nb_rb:%d rb_alloc[0]:%d]\n", frame,subframe,dlsch->rnti, dlsch_harq->pdu, - dlsch_harq->pdsch_start,dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0]); + dlsch_harq->pdsch_start,dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->DLround,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0]); return false; } start_meas(&eNB->dlsch_encoding_stats); dlsch_encoding_all(eNB, + proc, dlsch_harq->pdu, dlsch_harq->pdsch_start, dlsch, @@ -306,6 +307,14 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, &eNB->dlsch_interleaving_stats); stop_meas(&eNB->dlsch_encoding_stats); + if ( proc->threadPool.activated ) { + // Wait all other threads finish to process + while (proc->nbEncode) { + pullTpool(&proc->respEncode, &proc->threadPool); + proc->nbEncode--; + } + } + if(eNB->dlsch_encoding_stats.p_time>500*3000 && opp_enabled == 1) { print_meas_now(&eNB->dlsch_encoding_stats,"total coding",stderr); } @@ -314,8 +323,8 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, #else dlsch->active = 0; #endif - dlsch_harq->round++; - LOG_D(PHY,"Generated DLSCH dlsch_harq[round:%d]\n",dlsch_harq->round); + dlsch_harq->DLround++; + LOG_D(PHY,"Generated DLSCH dlsch_harq[round:%d]\n",dlsch_harq->DLround); return true; } return false; @@ -359,7 +368,7 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, dlsch->ue_type==0 ? dlsch1 : (LTE_eNB_DLSCH_t *)NULL); stop_meas(&eNB->dlsch_modulation_stats); - LOG_D(PHY,"Generated PDSCH dlsch_harq[round:%d]\n",dlsch_harq->round); + LOG_D(PHY,"Generated PDSCH dlsch_harq[round:%d]\n",dlsch_harq->DLround); } @@ -1146,7 +1155,7 @@ uci_procedures(PHY_VARS_eNB *eNB, if (eNB->first_sr[uci->ue_id] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 eNB->first_sr[uci->ue_id] = 0; - eNB->dlsch[uci->ue_id][0]->harq_processes[0]->round = 0; + eNB->dlsch[uci->ue_id][0]->harq_processes[0]->DLround = 0; eNB->dlsch[uci->ue_id][0]->harq_processes[0]->status = SCH_IDLE; LOG_D (PHY, "[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[uci->ue_id]->rnti, frame, subframe); } @@ -1156,6 +1165,87 @@ uci_procedures(PHY_VARS_eNB *eNB, } // end loop for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { } +#if 0 +void post_decode(request_t* decodeResult) { + turboDecode_t * rdata=(turboDecode_t *) decodeResult->data; + LTE_eNB_ULSCH_t *ulsch = rdata->eNB->ulsch[rdata->UEid]; + LTE_UL_eNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; + PHY_VARS_eNB *eNB=rdata->eNB; + bool decodeSucess=rdata->decodeIterations <= rdata->maxIterations; + ulsch_harq->processedSegments++; + if (decodeSucess) { + int Fbytes=rdata->Fbits>>3; + int Kr=rdata->segment_r < ulsch_harq->Cminus? + ulsch_harq->Kminus: + ulsch_harq->Kplus; + int Kr_bytes = Kr>>3; + int blockSize=Kr_bytes - Fbytes - (rdata->nbSegments>1?3:0); + memcpy(ulsch_harq->b+rdata->offset, + rdata->decoded_bytes+Fbytes, + blockSize); + + } else { + if (rdata->nbSegments > 1 ) { + // Purge pending decoding of the same TDU + union turboReqUnion idInFailure= {.p=decodeResult->id}; + rnti_t rntiInFailure=idInFailure.s.rnti; + tpool_t * tp=&proc->threadPool; + mutexlock(tp->lockRequests); + request_t* pending=NULL; + while ( (pending=searchRNTI(tp, rntiInFailure)) != NULL) { + LOG_W(MAC,"removing a CB belonging to a bad TPU"); + freeRequest(pending); + mutexlock(tp->lockReportDone); + tp->notFinishedJobs--; + mutexunlock(tp->lockReportDone); + } + mutexunlock(tp->lockRequests); + } + } + + // Check if TDU is complete: either we have all blocks in success + // either at least one block can't be decoded + // Maybe we receive decoded block alter a first failure, + // so we protect ourselves against multiple executions + if ( (rdata->nbSegments == ulsch_harq->processedSegments || decodeSucess==false) && + ulsch_harq->processedBadSegment == 0 ) { + //compute the expected ULSCH RX power (for the stats) + ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,rdata->UEid,rdata->harq_pid, 0); // 0 means bw_factor is not considered + + if (ulsch_harq->cqi_crc_status == 1) + fill_ulsch_cqi_indication(eNB,rdata->frame,rdata->subframe, + ulsch_harq, + ulsch->rnti); + + fill_crc_indication(eNB,rdata->UEid,rdata->frame,rdata->subframe,decodeSucess?0:1); // indicate result to MAC + fill_rx_indication(eNB,rdata->UEid,rdata->frame,rdata->subframe); // indicate SDU to MAC + + if (!decodeSucess) { + ulsch_harq->processedBadSegment =1; + if (ulsch_harq->round >= 3) { + ulsch_harq->status = SCH_IDLE; + ulsch_harq->handled = 0; + ulsch->harq_mask &= ~(1 << rdata->harq_pid); + ulsch_harq->round = 0; + } + + /* Mark the HARQ process to release it later if max transmission reached + * (see below). + * MAC does not send the max transmission count, we have to deal with it + * locally in PHY. + */ + ulsch_harq->handled = 1; + } else { + ulsch_harq->status = SCH_IDLE; + ulsch->harq_mask &= ~(1 << rdata->harq_pid); + } // ulsch not in error + + if (ulsch_harq->O_ACK>0) + fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,rdata->frame,rdata->subframe,ulsch->bundling); + } +} +#endif + void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { uint32_t ret=0,i; uint32_t harq_pid; @@ -1354,6 +1444,49 @@ void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask); } } // for (i=0; ithreadPool.activated ) { + // Wait all other threads finish to process + //printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc->threadPool.notFinishedJobs); + int rr=0; + mutexlock(proc->threadPool.lockReportDone); + while ( proc->threadPool.notFinishedJobs > 0 ) { + //printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc->threadPool.notFinishedJobs); + struct timespec t; + clock_gettime(CLOCK_REALTIME,&t); + t.tv_nsec+=1*1000*1000; + if ( t.tv_nsec >= 1000*1000*1000 ) { + t.tv_nsec -= 1000*1000*1000; + t.tv_sec++; + } + if ((rr=pthread_cond_timedwait(&proc->threadPool.notifDone,&proc.threadPool.lockReportDone, &t))!=0) { + LOG_E(PHY,"timedwait1:%s,%p,%p,%p,%d\n", rr==ETIMEDOUT?"ETIMEDOUT":"other", + proc->threadPool.oldestRequests, + proc->threadPool.newestRequests, + proc->threadPool.doneRequests, + proc->threadPool.notFinishedJobs); + proc->threadPool.oldestRequests=NULL; + proc->threadPool.newestRequests=NULL; + proc->threadPool.doneRequests=NULL; + proc->threadPool.notFinishedJobs=0; + } + } + mutexunlock(proc->threadPool.lockReportDone); + } + + request_t* tmp; + while ((tmp=proc->threadPool.doneRequests)!=NULL) { + turboDecode_t * rdata=(turboDecode_t *) tmp->data; + tmp->decodeIterations=rdata->decodeIterations; + post_decode(tmp); + tmp->returnTime=rdtsc(); + tmp->cumulSubframe=tmp->returnTime-startTime; + // Ignore write error (if no trace listner) + if (write(proc->threadPool.traceFd, tmp, sizeof(request_t)- 2*sizeof(void*))) {}; + proc->threadPool.doneRequests=tmp->next; + freeRequest(tmp); + } + #endif } extern int oai_exit; @@ -1515,7 +1648,7 @@ static void do_release_harq(PHY_VARS_eNB *eNB, #endif - if (dlsch0_harq->round >= after_rounds) { + if (dlsch0_harq->DLround >= after_rounds) { dlsch0_harq->status = SCH_IDLE; dlsch0->harq_mask &= ~(1 << harq_pid); } @@ -1564,7 +1697,7 @@ static void do_release_harq(PHY_VARS_eNB *eNB, T_INT(harq_pid)); } #endif - if (dlsch0_harq->round >= after_rounds) { + if (dlsch0_harq->DLround >= after_rounds) { dlsch0_harq->status = SCH_IDLE; if ((dlsch1_harq == NULL) || ((dlsch1_harq != NULL) && (dlsch1_harq->status == SCH_IDLE))) { diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h index 0e8daf064f..790a5c98e6 100644 --- a/openair2/PHY_INTERFACE/IF_Module.h +++ b/openair2/PHY_INTERFACE/IF_Module.h @@ -39,6 +39,7 @@ #include "nfapi_interface.h" #include "platform_constants.h" #include "platform_types.h" +#include #define MAX_NUM_DL_PDU 100 #define MAX_NUM_UL_PDU 100 @@ -179,6 +180,11 @@ typedef struct { pthread_cond_t cond_RUs; /// mutex for RXn-TXnp4 processing thread pthread_mutex_t mutex_RUs; + tpool_t threadPool; + int nbEncode; + int nbDecode; + notifiedFIFO_t respEncode; + notifiedFIFO_t respDecode; } L1_rxtx_proc_t; typedef struct IF_Module_s{ diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 33d4dc3b09..3a02868f56 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -175,6 +175,7 @@ /* optname helpstr paramflags XXXptr defXXXval type numelt */ /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ #define RF_CONFIG_FILE softmodem_params.rf_config_file +#define TP_CONFIG softmodem_params.threadPoolConfig #define PHY_TEST softmodem_params.phy_test #define WAIT_FOR_SYNC softmodem_params.wait_for_sync #define SINGLE_THREAD_FLAG softmodem_params.single_thread_flag @@ -187,6 +188,7 @@ #define USIM_TEST softmodem_params.usim_test #define CMDLINE_PARAMS_DESC { \ {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)}, \ + {"turbo-thread-pool", NULL, 0, strptr:(char **)&TP_CONFIG, defstrval:NULL, TYPE_STRING, sizeof(TP_CONFIG)}, \ {"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \ {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \ {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \ @@ -253,6 +255,7 @@ typedef struct { uint64_t optmask; THREAD_STRUCT thread_struct; char rf_config_file[1024]; + char threadPoolConfig[1024]; int phy_test; uint8_t usim_test; int emulate_rf; From 13122a272e42014fcd48fec55a47fd6205d43924 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 31 Oct 2019 17:28:21 +0100 Subject: [PATCH 057/175] ul in parallel monolithic case, ul in parallel memory leak fix --- common/utils/threadPool/thread-pool.c | 7 +- common/utils/threadPool/thread-pool.h | 39 ++- executables/main-fs6.c | 2 +- executables/main-ocp.c | 9 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 1 + openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 1 + openair1/PHY/LTE_TRANSPORT/transport_proto.h | 2 + openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 342 ++++++++----------- openair1/PHY/defs_eNB.h | 9 +- openair1/SCHED/phy_procedures_lte_eNb.c | 329 +++++------------- 10 files changed, 272 insertions(+), 469 deletions(-) diff --git a/common/utils/threadPool/thread-pool.c b/common/utils/threadPool/thread-pool.c index 4cc56fc9b8..1b7aa960ba 100644 --- a/common/utils/threadPool/thread-pool.c +++ b/common/utils/threadPool/thread-pool.c @@ -84,7 +84,7 @@ void *one_thread(void *arg) { delNotifiedFIFO_elt(elt); else pushNotifiedFIFO(elt->reponseFifo, elt); - + myThread->runningOnKey=-1; mutexunlock(tp->incomingFifo.lockF); } } while (true); @@ -116,7 +116,7 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { pool->nbThreads=0; pool->restrictRNTI=false; curptr=strtok_r(params,",",&saveptr); - + struct one_thread * ptr; while ( curptr!=NULL ) { int c=toupper(curptr[0]); @@ -130,8 +130,9 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { break; default: + ptr=pool->allthreads; pool->allthreads=(struct one_thread *)malloc(sizeof(struct one_thread)); - pool->allthreads->next=pool->allthreads; + pool->allthreads->next=ptr; printf("create a thread for core %d\n", atoi(curptr)); pool->allthreads->coreID=atoi(curptr); pool->allthreads->id=pool->nbThreads; diff --git a/common/utils/threadPool/thread-pool.h b/common/utils/threadPool/thread-pool.h index 6f34508c5a..d68918a163 100644 --- a/common/utils/threadPool/thread-pool.h +++ b/common/utils/threadPool/thread-pool.h @@ -137,8 +137,9 @@ static inline notifiedFIFO_elt_t *pollNotifiedFIFO(notifiedFIFO_t *nf) { // This function aborts all messages matching the key // If the queue is used in thread pools, it doesn't cancels already running processing // because the message has already been picked -static inline void abortNotifiedFIFO(notifiedFIFO_t *nf, uint64_t key) { +static inline int abortNotifiedFIFO(notifiedFIFO_t *nf, uint64_t key) { mutexlock(nf->lockF); + int nbDeleted=0; notifiedFIFO_elt_t **start=&nf->outF; while(*start!=NULL) { @@ -146,13 +147,15 @@ static inline void abortNotifiedFIFO(notifiedFIFO_t *nf, uint64_t key) { notifiedFIFO_elt_t *request=*start; *start=(*start)->next; delNotifiedFIFO_elt(request); - } - - if (*start != NULL) + nbDeleted++; + } else start=&(*start)->next; } + if (nf->outF == NULL) + nf->inF=NULL; mutexunlock(nf->lockF); + return nbDeleted; } struct one_thread { @@ -181,8 +184,17 @@ typedef struct thread_pool { static inline void pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg) { if (t->measurePerf) msg->creationTime=rdtsc(); - - pushNotifiedFIFO(&t->incomingFifo, msg); + if ( t->activated) + pushNotifiedFIFO(&t->incomingFifo, msg); + else { + if (t->measurePerf) + msg->startProcessingTime=rdtsc(); + msg->processingFunc(NotifiedFifoData(msg)); + if (t->measurePerf) + msg->endProcessingTime=rdtsc(); + if (msg->reponseFifo) + pushNotifiedFIFO(msg->reponseFifo, msg); + } } static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) { @@ -212,7 +224,8 @@ static inline notifiedFIFO_elt_t *tryPullTpool(notifiedFIFO_t *responseFifo, tpo return msg; } -static inline void abortTpool(tpool_t *t, uint64_t key) { +static inline int abortTpool(tpool_t *t, uint64_t key) { + int nbRemoved=0; notifiedFIFO_t *nf=&t->incomingFifo; mutexlock(nf->lockF); notifiedFIFO_elt_t **start=&nf->outF; @@ -222,22 +235,26 @@ static inline void abortTpool(tpool_t *t, uint64_t key) { notifiedFIFO_elt_t *request=*start; *start=(*start)->next; delNotifiedFIFO_elt(request); - } - - if (*start != NULL) + nbRemoved++; + } else start=&(*start)->next; } + if (t->incomingFifo.outF==NULL) + t->incomingFifo.inF=NULL; struct one_thread *ptr=t->allthreads; while(ptr!=NULL) { - if (ptr->runningOnKey==key) + if (ptr->runningOnKey==key) { ptr->abortFlag=true; + nbRemoved++; + } ptr=ptr->next; } mutexunlock(nf->lockF); + return nbRemoved; } void initTpool(char *params,tpool_t *pool, bool performanceMeas); diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 1416572d76..f2c95f86d4 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -615,7 +615,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * &ulsch_harq->Kplus, &ulsch_harq->Kminus, &ulsch_harq->F); - int ret = ulsch_decoding_data(eNB, i, harq_pid, + int ret = ulsch_decoding_data(eNB, proc, i, harq_pid, ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); LOG_D(PHY, diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 34cd950ce7..4e657e6d28 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -692,13 +692,14 @@ static void *ru_thread( void *param ) { L1_rxtx_proc_t L1proc; L1_rxtx_proc_t *proc=&L1proc; - if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) { + if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) initTpool(get_softmodem_params()->threadPoolConfig, &L1proc.threadPool, true); - initNotifiedFIFO(&L1proc.respEncode); - initNotifiedFIFO(&L1proc.respDecode); - } else + else initTpool("n", &L1proc.threadPool, true); + initNotifiedFIFO(&L1proc.respEncode); + initNotifiedFIFO(&L1proc.respDecode); + if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); init_frame_parms(&ru->frame_parms,1); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index ea6bf29ac7..5024650d62 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -398,6 +398,7 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, proc->nbEncode++; } else { TPencode(rdata); + delNotifiedFIFO_elt(req); } int Qm=hadlsch->Qm; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 9e78eb75a0..0737d4c56a 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -288,6 +288,7 @@ typedef struct { uint8_t rvidx; /// soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) int16_t w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; + int16_t pusch_rep_buffer[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; /// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) //TBD int16_t *d[MAX_NUM_ULSCH_SEGMENTS]; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_proto.h b/openair1/PHY/LTE_TRANSPORT/transport_proto.h index a358df3ff3..0d8fcfa29e 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_proto.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_proto.h @@ -469,6 +469,7 @@ void rx_ulsch(PHY_VARS_eNB *eNB, int ulsch_decoding_data_all(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, int UE_id, int harq_pid, int llr8_flag); @@ -513,6 +514,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB, @returns 0 on success */ int ulsch_decoding_data(PHY_VARS_eNB *eNB, + L1_rxtx_proc_t *proc, int UE_id, int harq_pid, int llr8_flag); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 64b83c524a..4cfdcbdb41 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -213,72 +213,26 @@ uint8_t extract_cqi_crc(uint8_t *cqi,uint8_t CQI_LENGTH) { extern int oai_exit; -int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) { - unsigned int r,r_offset=0,Kr,Kr_bytes; - uint8_t crc_type; - int offset = 0; - int ret = 1; - int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; - LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; - LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - int G = ulsch_harq->G; - unsigned int E; - decoder_if_t *tc; - static int32_t pusch_rep_buffer[3*(6144+64)]; - int max_Ncb; - - if (llr8_flag == 0) - tc = *decoder16; - else - tc = *decoder8; - - if(ulsch_harq->repetition_number == 1) { - memset(pusch_rep_buffer,0,(sizeof(int32_t)*3*(6144+64))) ; // reset the buffer every new repetitions - } - - for (r=0; rC; r++) { - // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); - // Get Turbo interleaver parameters - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - memset(&dummy_w[r][0],0,3*(6144+64)*sizeof(short)); - ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), - (uint8_t *)&dummy_w[r][0], +void processULSegment(void * arg) { + turboDecode_t* rdata=(turboDecode_t*) arg; + PHY_VARS_eNB *eNB=rdata->eNB; + LTE_UL_eNB_HARQ_t *ulsch_harq=rdata->ulsch_harq; + int r=rdata->segment_r; + int G=ulsch_harq->G; + int Kr_bytes=rdata->Kr>>3; + int16_t dummy_w[3*(6144+64)]; + + memset(&dummy_w[0],0,3*(6144+64)*sizeof(short)); + ulsch_harq->RTC[r] = generate_dummy_w(4+(Kr_bytes*8), + (uint8_t *)&dummy_w[0], (r==0) ? ulsch_harq->F : 0); -#ifdef DEBUG_ULSCH_DECODING - printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, Nl %d, r_offset %d)...\n", - r, G, - Kr*3, - ulsch_harq->Qm, - ulsch_harq->Nl, r_offset); -#endif - start_meas(&eNB->ulsch_rate_unmatching_stats); - #ifdef FS6 - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { - int Gp=G/ulsch_harq->Qm; - int GpmodC = Gp%ulsch_harq->C; - - if (r < (ulsch_harq->C-(GpmodC))) - E = ulsch_harq->Qm * (Gp/ulsch_harq->C); - else - E = ulsch_harq->Qm * ((GpmodC==0?0:1) + (Gp/ulsch_harq->C)); - sendFs6Ul(eNB, UE_id, harq_pid, r, ulsch_harq->e+r_offset, E*sizeof(int16_t), r_offset); - - r_offset += E; - continue; - } - - #endif - - if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], + start_meas(&eNB->ulsch_deinterleaving_stats); + unsigned int E; + if (lte_rate_matching_turbo_rx(ulsch_harq->RTC[r], G, ulsch_harq->w[r], - (uint8_t *) &dummy_w[r][0], - ulsch_harq->e+r_offset, + (uint8_t *) &dummy_w[0], + ulsch_harq->e+rdata->r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -290,157 +244,131 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) r, &E)==-1) { LOG_E(PHY,"ulsch_decoding.c: Problem in rate matching\n"); - return(-1); + return; + } + stop_meas(&eNB->ulsch_rate_unmatching_stats); + int max_Ncb = 3*ulsch_harq->RTC[r]*32 ; + + if(ulsch_harq->repetition_number == 1) { + memset(ulsch_harq->pusch_rep_buffer[r],0,(sizeof(int32_t)*3*(6144+64))) ; // reset the buffer every new repetitions + } + if(ulsch_harq->total_number_of_repetitions > 1) { + if (ulsch_harq->rvidx==1) { + LOG_E(PHY,"Adding HARQ data for segment: %d\n", r); + // Store the result of HARQ combining in the last emtc repetitions of sequence 0,2,3,1 + for (int nn=0; nnpusch_rep_buffer[r][nn] += ulsch_harq->w[r][nn] ; } - stop_meas(&eNB->ulsch_rate_unmatching_stats); - max_Ncb = 3*ulsch_harq->RTC[r]*32 ; - - if(ulsch_harq->total_number_of_repetitions > 1) { - if (ulsch_harq->rvidx==1) { - // Store the result of HARQ combining in the last emtc repetitions of sequence 0,2,3,1 - for (int nn=0; nnw[r][nn] ; - } - } - - if (ulsch_harq->repetition_number == ulsch_harq->total_number_of_repetitions) { - for (int nn=0; nnw[r][nn] = pusch_rep_buffer[nn] ; - } - } - } - - r_offset += E; - start_meas(&eNB->ulsch_deinterleaving_stats); - #if 0 - start_meas(&eNB->ulsch_deinterleaving_stats); - req=createRequest(DECODE,sizeof(turboDecode_t)); - req->startUELoop=eNB->proc.threadPool.startProcessingUE; - union turboReqUnion id= {.s={eNB->ulsch[UE_id]->rnti,frame,subframe,r,0}}; - req->id= id.p; - turboDecode_t * rdata=(turboDecode_t *) req->data; - #endif - sub_block_deinterleaving_turbo(4+Kr, - &ulsch_harq->d[r][96], - ulsch_harq->w[r]); - stop_meas(&eNB->ulsch_deinterleaving_stats); - - if (ulsch_harq->C == 1) - crc_type = CRC24_A; - else - crc_type = CRC24_B; - #if 0 - rdata->frame=frame; - rdata->subframe=subframe; - rdata->UEid=UE_id; - rdata->harq_pid=harq_pid; - rdata->Kr=Kr; - rdata->maxIterations=eNB->ulsch[UE_id]->max_turbo_iterations; - rdata->ulsch_harq=ulsch_harq; - rdata->eNB=eNB; - rdata->nbSegments=ulsch_harq->C; - rdata->segment_r=r; - rdata->Fbits=(r==0) ? ulsch_harq->F : 0; - rdata->offset=offset; - rdata->function=td; - int Fbytes=rdata->Fbits>>3; - int blockSize=Kr_bytes - Fbytes - (rdata->nbSegments>1?3:0); - if ( eNB->proc.threadPool.activated) { - add_request(req, &eNB->proc.threadPool); - req=NULL; - } else { - req->startProcessingTime=rdtsc(); - rdata->decodeIterations = td( rdata->soft_bits+96, - rdata->decoded_bytes, - rdata->Kr, - f1f2mat_old[rdata->iind*2], - f1f2mat_old[(rdata->iind*2)+1], - rdata->maxIterations, - rdata->nbSegments == 1 ? CRC24_A: CRC24_B, - rdata->Fbits, - &eNB->ulsch_tc_init_stats, - &eNB->ulsch_tc_alpha_stats, - &eNB->ulsch_tc_beta_stats, - &eNB->ulsch_tc_gamma_stats, - &eNB->ulsch_tc_ext_stats, - &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats); - - stop_meas(&eNB->ulsch_turbo_decoding_stats); - req->returnTime=req->endProcessingTime=rdtsc(); - req->decodeIterations=rdata->decodeIterations; - req->coreId=0; - req->processedBy[0]=0; - req->next=eNB->proc.threadPool.doneRequests; - eNB->proc.threadPool.doneRequests=req; - - if (rdata->decodeIterations > eNB->ulsch[UE_id]->max_turbo_iterations ) - // Entire TPU need retransmission - break; - } -offset += blockSize; - eNB->proc.threadPool.startProcessingUE=rdtsc(); - #endif - start_meas(&eNB->ulsch_turbo_decoding_stats); - ret = tc(&ulsch_harq->d[r][96], - NULL, - ulsch_harq->c[r], - NULL, - Kr, - ulsch->max_turbo_iterations,//MAX_TURBO_ITERATIONS, - crc_type, - (r==0) ? ulsch_harq->F : 0, - &eNB->ulsch_tc_init_stats, - &eNB->ulsch_tc_alpha_stats, - &eNB->ulsch_tc_beta_stats, - &eNB->ulsch_tc_gamma_stats, - &eNB->ulsch_tc_ext_stats, - &eNB->ulsch_tc_intl1_stats, - &eNB->ulsch_tc_intl2_stats); - stop_meas(&eNB->ulsch_turbo_decoding_stats); - LOG_D(PHY,"turbo decode in %d iter\n",ret); - - // Reassembly of Transport block here - - if (ret != (1+ulsch->max_turbo_iterations)) { - if (rCminus) - Kr = ulsch_harq->Kminus; - else - Kr = ulsch_harq->Kplus; - - Kr_bytes = Kr>>3; - - if (r==0) { - memcpy(ulsch_harq->b, - &ulsch_harq->c[0][(ulsch_harq->F>>3)], - Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0)); - offset = Kr_bytes - (ulsch_harq->F>>3) - ((ulsch_harq->C>1)?3:0); - } else { - memcpy(ulsch_harq->b+offset, - ulsch_harq->c[r], - Kr_bytes - ((ulsch_harq->C>1)?3:0)); - offset += (Kr_bytes- ((ulsch_harq->C>1)?3:0)); - } - } else { - break; + if (ulsch_harq->repetition_number == ulsch_harq->total_number_of_repetitions) { + LOG_E(PHY,"Will use HARQ data sum up for segment: %d\n", r); + for (int nn=0; nnw[r][nn] = ulsch_harq->pusch_rep_buffer[r][nn] ; } } + int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32))); + sub_block_deinterleaving_turbo(4+rdata->Kr, + soft_bits+96, + ulsch_harq->w[r]); + stop_meas(&eNB->ulsch_deinterleaving_stats); + rdata->decodeIterations = rdata->function( soft_bits+96, + NULL, + rdata->decoded_bytes, + NULL, + rdata->Kr, + rdata->maxIterations, + rdata->nbSegments == 1 ? CRC24_A: CRC24_B, + rdata->Fbits, + &eNB->ulsch_tc_init_stats, + &eNB->ulsch_tc_alpha_stats, + &eNB->ulsch_tc_beta_stats, + &eNB->ulsch_tc_gamma_stats, + &eNB->ulsch_tc_ext_stats, + &eNB->ulsch_tc_intl1_stats, + &eNB->ulsch_tc_intl2_stats); + stop_meas(&eNB->ulsch_turbo_decoding_stats); + +} +int ulsch_decoding_data(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, + int UE_id,int harq_pid,int llr8_flag) { + unsigned int r_offset=0; + int offset = 0; + LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; + LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; + int G = ulsch_harq->G; + unsigned int E; + int ret=0; + + decoder_if_t * td=llr8_flag == 0 ? + *decoder16 : *decoder8; + ulsch_harq->processedSegments=0; + + for (int r=0; rC; r++) { + // printf("before subblock deinterleaving c[%d] = %p\n",r,ulsch_harq->c[r]); + // Get Turbo interleaver parameters + unsigned int Kr= rCminus ? + ulsch_harq->Kminus :ulsch_harq->Kplus; + unsigned int Kr_bytes = Kr>>3; + +#ifdef DEBUG_ULSCH_DECODING + printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, Nl %d, r_offset %d)...\n", + r, G, + Kr*3, + ulsch_harq->Qm, + ulsch_harq->Nl, r_offset); +#endif + int Gp=G/ulsch_harq->Qm; + int GpmodC = Gp%ulsch_harq->C; + + if (r < (ulsch_harq->C-(GpmodC))) + E = ulsch_harq->Qm * (Gp/ulsch_harq->C); + else + E = ulsch_harq->Qm * ((GpmodC==0?0:1) + (Gp/ulsch_harq->C)); +#ifdef FS6 + if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + + sendFs6Ul(eNB, UE_id, harq_pid, r, ulsch_harq->e+r_offset, E*sizeof(int16_t), r_offset); + + r_offset += E; + continue; + } + +#endif + + union turboReqUnion id= {.s={ulsch->rnti,proc->frame_rx,proc->subframe_rx,0,0}}; + notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboDecode_t), id.p, &proc->respDecode, processULSegment); + turboDecode_t * rdata=(turboDecode_t *) NotifiedFifoData(req); + + rdata->eNB=eNB; + rdata->frame=proc->frame_rx; + rdata->subframe=proc->subframe_rx; + rdata->UEid=UE_id; + rdata->harq_pid=harq_pid; + rdata->Kr=Kr; + rdata->maxIterations=eNB->ulsch[UE_id]->max_turbo_iterations; + rdata->ulsch_harq=ulsch_harq; + rdata->eNB=eNB; + rdata->nbSegments=ulsch_harq->C; + rdata->segment_r=r; + rdata->Fbits=(r==0) ? ulsch_harq->F : 0; + rdata->r_offset=r_offset; + rdata->offset=offset; + rdata->function=td; + int Fbytes=(r==0) ? rdata->Fbits>>3 : 0; + int sz=Kr_bytes - Fbytes - ((ulsch_harq->C>1)?3:0); + pushTpool(&proc->threadPool,req); + proc->nbDecode++; + LOG_D(PHY,"Added a block to decode, in pipe: %d\n",proc->nbDecode); + r_offset+=E; + offset+=sz; + } return(ret); } -int ulsch_decoding_data_all(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) { - int ret = 0; - /*if(get_thread_worker_conf() == WORKER_ENABLE) - { - ret = ulsch_decoding_data_2thread(eNB,UE_id,harq_pid,llr8_flag); - } - else*/ - { - ret = ulsch_decoding_data(eNB,UE_id,harq_pid,llr8_flag); - } - return ret; +int ulsch_decoding_data_all(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, + int UE_id,int harq_pid,int llr8_flag) { + return ulsch_decoding_data(eNB,proc,UE_id,harq_pid,llr8_flag); } static inline unsigned int lte_gold_unscram(unsigned int *x1, unsigned int *x2, unsigned char reset) __attribute__((always_inline)); @@ -1158,7 +1086,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, LOG_D(PHY,"frame %d subframe %d O_ACK:%d o_ACK[]=%d:%d:%d:%d\n",frame,subframe,ulsch_harq->O_ACK,ulsch_harq->o_ACK[0],ulsch_harq->o_ACK[1],ulsch_harq->o_ACK[2],ulsch_harq->o_ACK[3]); // Do ULSCH Decoding for data portion - ret = ulsch_decoding_data_all(eNB,UE_id,harq_pid,llr8_flag); + ret = ulsch_decoding_data_all(eNB,proc, UE_id,harq_pid,llr8_flag); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING0+harq_pid,0); return(ret); } diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index 718ede5715..51b2e9c4ae 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -871,20 +871,19 @@ union turboReqUnion { }; typedef struct TurboDecode_s { - decoder_if_t *function; - int16_t soft_bits[3*8*6144+12+96] __attribute__((aligned(32))); - uint8_t decoded_bytes[3+768] __attribute__((aligned(32))); + PHY_VARS_eNB *eNB; + decoder_if_t *function; + uint8_t decoded_bytes[3+1768] __attribute__((aligned(32))); int UEid; int harq_pid; int frame; int subframe; - int iind; int Fbits; int Kr; LTE_UL_eNB_HARQ_t *ulsch_harq; - PHY_VARS_eNB *eNB; int nbSegments; int segment_r; + int r_offset; int offset; int maxIterations; int decodeIterations; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 94689ed246..2b032c208a 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -310,7 +310,7 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, if ( proc->threadPool.activated ) { // Wait all other threads finish to process while (proc->nbEncode) { - pullTpool(&proc->respEncode, &proc->threadPool); + delNotifiedFIFO_elt(pullTpool(&proc->respEncode, &proc->threadPool)); proc->nbEncode--; } } @@ -1165,86 +1165,92 @@ uci_procedures(PHY_VARS_eNB *eNB, } // end loop for (int i = 0; i < NUMBER_OF_UE_MAX; i++) { } -#if 0 -void post_decode(request_t* decodeResult) { - turboDecode_t * rdata=(turboDecode_t *) decodeResult->data; - LTE_eNB_ULSCH_t *ulsch = rdata->eNB->ulsch[rdata->UEid]; - LTE_UL_eNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; - PHY_VARS_eNB *eNB=rdata->eNB; - bool decodeSucess=rdata->decodeIterations <= rdata->maxIterations; - ulsch_harq->processedSegments++; - if (decodeSucess) { - int Fbytes=rdata->Fbits>>3; - int Kr=rdata->segment_r < ulsch_harq->Cminus? - ulsch_harq->Kminus: - ulsch_harq->Kplus; - int Kr_bytes = Kr>>3; - int blockSize=Kr_bytes - Fbytes - (rdata->nbSegments>1?3:0); - memcpy(ulsch_harq->b+rdata->offset, - rdata->decoded_bytes+Fbytes, - blockSize); +void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req) { + turboDecode_t * rdata=(turboDecode_t *) NotifiedFifoData(req); - } else { - if (rdata->nbSegments > 1 ) { - // Purge pending decoding of the same TDU - union turboReqUnion idInFailure= {.p=decodeResult->id}; - rnti_t rntiInFailure=idInFailure.s.rnti; - tpool_t * tp=&proc->threadPool; - mutexlock(tp->lockRequests); - request_t* pending=NULL; - while ( (pending=searchRNTI(tp, rntiInFailure)) != NULL) { - LOG_W(MAC,"removing a CB belonging to a bad TPU"); - freeRequest(pending); - mutexlock(tp->lockReportDone); - tp->notFinishedJobs--; - mutexunlock(tp->lockReportDone); - } - mutexunlock(tp->lockRequests); - } + LTE_eNB_ULSCH_t *ulsch = rdata->eNB->ulsch[rdata->UEid]; + LTE_UL_eNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; + PHY_VARS_eNB *eNB=rdata->eNB; + + bool decodeSucess=rdata->decodeIterations <= rdata->maxIterations; + ulsch_harq->processedSegments++; + LOG_D(PHY, "processing result of segment: %d, ue %d, processed %d/%d\n", + rdata->segment_r, rdata->UEid, ulsch_harq->processedSegments, rdata->nbSegments); + proc->nbDecode--; + LOG_D(PHY,"remain to decoded in subframe: %d\n", proc->nbDecode); + if (decodeSucess) { + int Fbytes=(rdata->segment_r==0) ? rdata->Fbits>>3 : 0; + int sz=(rdata->Kr>>3) - Fbytes - ((ulsch_harq->C>1)?3:0); + memcpy(ulsch_harq->b+rdata->offset, + rdata->decoded_bytes+Fbytes, + sz); + } else { + if ( rdata->nbSegments != ulsch_harq->processedSegments ) { + int nb=abortTpool(&proc->threadPool, req->key); + printf("nb1:%d\n", nb); + nb+=abortNotifiedFIFO(&proc->respDecode, req->key); + printf("nb2:%d\n", nb); + proc->nbDecode-=nb; + LOG_I(PHY,"uplink segment error %d/%d, aborted %d segments",rdata->segment_r,rdata->nbSegments, nb); + AssertFatal(ulsch_harq->processedSegments+nb == rdata->nbSegments,"processed: %d, aborted: %d, total %d\n", + ulsch_harq->processedSegments, nb, rdata->nbSegments); + ulsch_harq->processedSegments=rdata->nbSegments; } + } - // Check if TDU is complete: either we have all blocks in success - // either at least one block can't be decoded - // Maybe we receive decoded block alter a first failure, - // so we protect ourselves against multiple executions - if ( (rdata->nbSegments == ulsch_harq->processedSegments || decodeSucess==false) && - ulsch_harq->processedBadSegment == 0 ) { - //compute the expected ULSCH RX power (for the stats) - ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,rdata->UEid,rdata->harq_pid, 0); // 0 means bw_factor is not considered - - if (ulsch_harq->cqi_crc_status == 1) - fill_ulsch_cqi_indication(eNB,rdata->frame,rdata->subframe, - ulsch_harq, - ulsch->rnti); - - fill_crc_indication(eNB,rdata->UEid,rdata->frame,rdata->subframe,decodeSucess?0:1); // indicate result to MAC - fill_rx_indication(eNB,rdata->UEid,rdata->frame,rdata->subframe); // indicate SDU to MAC - - if (!decodeSucess) { - ulsch_harq->processedBadSegment =1; - if (ulsch_harq->round >= 3) { - ulsch_harq->status = SCH_IDLE; - ulsch_harq->handled = 0; - ulsch->harq_mask &= ~(1 << rdata->harq_pid); - ulsch_harq->round = 0; - } - - /* Mark the HARQ process to release it later if max transmission reached - * (see below). - * MAC does not send the max transmission count, we have to deal with it - * locally in PHY. - */ - ulsch_harq->handled = 1; - } else { - ulsch_harq->status = SCH_IDLE; - ulsch->harq_mask &= ~(1 << rdata->harq_pid); - } // ulsch not in error - - if (ulsch_harq->O_ACK>0) - fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,rdata->frame,rdata->subframe,ulsch->bundling); - } + // if this UE segments are all done + if ( rdata->nbSegments == ulsch_harq->processedSegments) { + //compute the expected ULSCH RX power (for the stats) + int i=rdata->UEid; + ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,rdata->harq_pid, 0); // 0 means bw_factor is not considered + if (RC.mac != NULL) { /* ulsim does not use RC.mac context. */ + if (ulsch_harq->cqi_crc_status == 1) { + fill_ulsch_cqi_indication(eNB,rdata->frame,rdata->subframe,ulsch_harq,ulsch->rnti); + RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << rdata->subframe)); + } else { + if(RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag & (1 << rdata->subframe) ) { + RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << rdata->subframe)); + RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_timer=30; + LOG_D(PHY,"Frame %d,Subframe %d, We're supposed to get a cqi here. Set cqi_req_timer to 30.\n",rdata->frame,rdata->subframe); + } + } + } + + if (!decodeSucess) { + fill_crc_indication(eNB,i,rdata->frame,rdata->subframe,1); // indicate NAK to MAC + fill_rx_indication(eNB,i,rdata->frame,rdata->subframe); // indicate SDU to MAC + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", + eNB->Mod_id,rdata->harq_pid, + rdata->frame,rdata->subframe, i, + ulsch_harq->round, + ulsch->Mlimit, + ulsch_harq->o_ACK[0], + ulsch_harq->o_ACK[1]); + + if (ulsch_harq->round >= 3) { + ulsch_harq->status = SCH_IDLE; + ulsch_harq->handled = 0; + ulsch->harq_mask &= ~(1 << rdata->harq_pid); + ulsch_harq->round = 0; + } + /* Mark the HARQ process to release it later if max transmission reached + * (see below). + * MAC does not send the max transmission count, we have to deal with it + * locally in PHY. + */ + ulsch_harq->handled = 1; + } // ulsch in error + else if(ulsch_harq->repetition_number == ulsch_harq->total_number_of_repetitions){ + fill_crc_indication(eNB,i,rdata->frame,rdata->subframe,0); // indicate ACK to MAC + fill_rx_indication(eNB,i,rdata->frame,rdata->subframe); // indicate SDU to MAC + ulsch_harq->status = SCH_IDLE; + ulsch->harq_mask &= ~(1 << rdata->harq_pid); + } // ulsch not in error + + if (ulsch_harq->O_ACK>0) + fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,rdata->frame,rdata->subframe,ulsch->bundling); + } } -#endif void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { uint32_t ret=0,i; @@ -1316,121 +1322,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { ulsch_harq->V_UL_DAI, ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); - LOG_D(PHY, - "[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n", - eNB->Mod_id,harq_pid, - frame,subframe, - ulsch->rnti, - dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), - dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), - 30,//eNB->measurements.n0_power_dB[0], - 30,//eNB->measurements.n0_power_dB[1], - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1], - ret, - ulsch_harq->cqi_crc_status, - ulsch_harq->O_ACK, - eNB->ulsch_decoding_stats.p_time, eNB->ulsch_decoding_stats.max); - if (ulsch_harq->repetition_number < ulsch_harq->total_number_of_repetitions){ - ulsch_harq->rvidx = rvidx_tab[(ulsch_harq->repetition_number%4)] ; // Set the correct rvidx for the next emtc repetitions - ulsch_harq->repetition_number +=1 ; // Increment repetition_number for the next ULSCH allocation - } - //compute the expected ULSCH RX power (for the stats) - ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered - - if (RC.mac != NULL) { /* ulsim does not use RC.mac context. */ - if (ulsch_harq->cqi_crc_status == 1) { -#ifdef DEBUG_PHY_PROC - //if (((frame%10) == 0) || (frame < 50)) - print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL); -#endif - fill_ulsch_cqi_indication(eNB,frame,subframe,ulsch_harq,ulsch->rnti); - RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << subframe)); - } else { - if(RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag & (1 << subframe) ) { - RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << subframe)); - RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_timer=30; - LOG_D(PHY,"Frame %d,Subframe %d, We're supposed to get a cqi here. Set cqi_req_timer to 30.\n",frame,subframe); - } - } - } - - if (ret == (1+MAX_TURBO_ITERATIONS)) { - T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), - T_INT(harq_pid)); - fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC - fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC - LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", - eNB->Mod_id,harq_pid, - frame,subframe, i, - ulsch_harq->round, - ulsch->Mlimit, - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1]); - - if (ulsch_harq->round >= 3) { - ulsch_harq->status = SCH_IDLE; - ulsch_harq->handled = 0; - ulsch->harq_mask &= ~(1 << harq_pid); - ulsch_harq->round = 0; - } - - MSC_LOG_RX_DISCARDED_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u ULSCH received rnti %x harq id %u round %d", - frame,subframe, - ulsch->rnti,harq_pid, - ulsch_harq->round-1 - ); - /* Mark the HARQ process to release it later if max transmission reached - * (see below). - * MAC does not send the max transmission count, we have to deal with it - * locally in PHY. - */ - ulsch_harq->handled = 1; - } // ulsch in error - else if(ulsch_harq->repetition_number == ulsch_harq->total_number_of_repetitions){ - fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC - fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC - ulsch_harq->status = SCH_IDLE; - ulsch->harq_mask &= ~(1 << harq_pid); - T (T_ENB_PHY_ULSCH_UE_ACK, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (ulsch->rnti), T_INT (harq_pid)); - MSC_LOG_RX_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u ULSCH received rnti %x harq id %u", - frame,subframe, - ulsch->rnti,harq_pid - ); -#ifdef DEBUG_PHY_PROC -#ifdef DEBUG_ULSCH - LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe, - harq_pid,ulsch_harq->TBS>>3); - - for (j=0; jTBS>>3; j++) - LOG_T(PHY,"%x.",ulsch->harq_processes[harq_pid]->b[j]); - - LOG_T(PHY,"\n"); -#endif -#endif - } // ulsch not in error - - if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling); - - LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", - eNB->Mod_id,frame,subframe, - harq_pid, - i, - ret, - ulsch_harq->cqi_crc_status, - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1], - eNB->UE_stats[i].ulsch_errors[harq_pid], - eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]); - } // if ((ulsch) && - // (ulsch->rnti>0) && - // (ulsch_harq->status == ACTIVE)) + } else if ((ulsch) && (ulsch->rnti>0) && (ulsch_harq->status == ACTIVE) && @@ -1444,56 +1336,17 @@ void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask); } } // for (i=0; ithreadPool.activated ) { - // Wait all other threads finish to process - //printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc->threadPool.notFinishedJobs); - int rr=0; - mutexlock(proc->threadPool.lockReportDone); - while ( proc->threadPool.notFinishedJobs > 0 ) { - //printf("%s:%d:%d\n", __FILE__,__LINE__,eNB->proc->threadPool.notFinishedJobs); - struct timespec t; - clock_gettime(CLOCK_REALTIME,&t); - t.tv_nsec+=1*1000*1000; - if ( t.tv_nsec >= 1000*1000*1000 ) { - t.tv_nsec -= 1000*1000*1000; - t.tv_sec++; - } - if ((rr=pthread_cond_timedwait(&proc->threadPool.notifDone,&proc.threadPool.lockReportDone, &t))!=0) { - LOG_E(PHY,"timedwait1:%s,%p,%p,%p,%d\n", rr==ETIMEDOUT?"ETIMEDOUT":"other", - proc->threadPool.oldestRequests, - proc->threadPool.newestRequests, - proc->threadPool.doneRequests, - proc->threadPool.notFinishedJobs); - proc->threadPool.oldestRequests=NULL; - proc->threadPool.newestRequests=NULL; - proc->threadPool.doneRequests=NULL; - proc->threadPool.notFinishedJobs=0; - } - } - mutexunlock(proc->threadPool.lockReportDone); - } - - request_t* tmp; - while ((tmp=proc->threadPool.doneRequests)!=NULL) { - turboDecode_t * rdata=(turboDecode_t *) tmp->data; - tmp->decodeIterations=rdata->decodeIterations; - post_decode(tmp); - tmp->returnTime=rdtsc(); - tmp->cumulSubframe=tmp->returnTime-startTime; - // Ignore write error (if no trace listner) - if (write(proc->threadPool.traceFd, tmp, sizeof(request_t)- 2*sizeof(void*))) {}; - proc->threadPool.doneRequests=tmp->next; - freeRequest(tmp); - } - #endif + + while (proc->nbDecode > 0) { + notifiedFIFO_elt_t *req=pullTpool(&proc->respDecode, &proc->threadPool); + postDecode(proc, req); + delNotifiedFIFO_elt(req); + } } + extern int oai_exit; -extern void *td_thread (void *); - -extern void *te_thread (void *); void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) { nfapi_rx_indication_pdu_t *pdu; From aa10676e900746c0cfe745ee0948971ba47ce2fc Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 31 Oct 2019 17:48:31 +0100 Subject: [PATCH 058/175] parallel UL, split mode --- executables/main-fs6.c | 102 ++---------------------------------- executables/split_headers.h | 1 + 2 files changed, 6 insertions(+), 97 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index f2c95f86d4..15108b0e45 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -618,103 +618,6 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * int ret = ulsch_decoding_data(eNB, proc, i, harq_pid, ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); - LOG_D(PHY, - "[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n", - eNB->Mod_id,harq_pid, - frame,subframe, - ulsch->rnti, - dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), - dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), - 30,//eNB->measurements.n0_power_dB[0], - 30,//eNB->measurements.n0_power_dB[1], - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1], - ret, - ulsch_harq->cqi_crc_status, - ulsch_harq->O_ACK, - eNB->ulsch_decoding_stats.p_time, eNB->ulsch_decoding_stats.max); - //compute the expected ULSCH RX power (for the stats) - ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered - - if (RC.mac != NULL) { /* ulsim does not use RC.mac context. */ - if (ulsch_harq->cqi_crc_status == 1) { -#ifdef DEBUG_PHY_PROC - //if (((frame%10) == 0) || (frame < 50)) - print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL); -#endif - fill_ulsch_cqi_indication(eNB,frame,subframe,ulsch_harq,ulsch->rnti); - RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << subframe)); - } else { - if(RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag & (1 << subframe) ) { - RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << subframe)); - RC.mac[eNB->Mod_id]->UE_list.UE_sched_ctrl[i].cqi_req_timer=30; - LOG_D(PHY,"Frame %d,Subframe %d, We're supposed to get a cqi here. Set cqi_req_timer to 30.\n",frame,subframe); - } - } - } - - if (ret == (1+MAX_TURBO_ITERATIONS)) { - T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), - T_INT(harq_pid)); - fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC - fill_rx_indication_from_split(bufferZone, eNB,i,frame,subframe, ul_propa); // indicate SDU to MAC - LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", - eNB->Mod_id,harq_pid, - frame,subframe, i, - ulsch_harq->round, - ulsch->Mlimit, - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1]); - - if (ulsch_harq->round >= 3) { - ulsch_harq->status = SCH_IDLE; - ulsch_harq->handled = 0; - ulsch->harq_mask &= ~(1 << harq_pid); - ulsch_harq->round = 0; - } - - MSC_LOG_RX_DISCARDED_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u ULSCH received rnti %x harq id %u round %d", - frame,subframe, - ulsch->rnti,harq_pid, - ulsch_harq->round-1 - ); - /* Mark the HARQ process to release it later if max transmission reached - * (see below). - * MAC does not send the max transmission count, we have to deal with it - * locally in PHY. - */ - ulsch_harq->handled = 1; - } // ulsch in error - else { - fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC - fill_rx_indication_from_split(bufferZone, eNB,i,frame,subframe, ul_propa); // indicate SDU to MAC - ulsch_harq->status = SCH_IDLE; - ulsch->harq_mask &= ~(1 << harq_pid); - T (T_ENB_PHY_ULSCH_UE_ACK, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (ulsch->rnti), T_INT (harq_pid)); - MSC_LOG_RX_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u ULSCH received rnti %x harq id %u", - frame,subframe, - ulsch->rnti,harq_pid - ); - } // ulsch not in error - - if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling); - - LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", - eNB->Mod_id,frame,subframe, - harq_pid, - i, - ret, - ulsch_harq->cqi_crc_status, - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1], - eNB->UE_stats[i].ulsch_errors[harq_pid], - eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]); } // if ((ulsch) && // (ulsch->rnti>0) && // (ulsch_harq->status == ACTIVE)) @@ -731,6 +634,11 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask); } } // for (i=0; inbDecode > 0) { + notifiedFIFO_elt_t *req=pullTpool(&proc->respDecode, &proc->threadPool); + postDecode(proc, req); + delNotifiedFIFO_elt(req); + } } void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagation_t *ul_propa) { diff --git a/executables/split_headers.h b/executables/split_headers.h index 1849efffc7..b013617cfd 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -247,6 +247,7 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, int harq_pid, LTE_eNB_DLSCH_t *dlsch, LTE_eNB_UE_stats *ue_stats) ; +void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req); void pdsch_procedures(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int harq_pid, From 3ce5d400648335209992ef145d6c6aa832b33883 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 31 Oct 2019 20:49:42 +0100 Subject: [PATCH 059/175] add comments in data structures, gcc warnings fixed --- executables/main-fs6.c | 2 +- executables/main-ocp.c | 7 ++--- executables/split_headers.h | 36 +++++++++++++++-------- openair1/SCHED/phy_procedures_lte_eNb.c | 9 ++---- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 5 ++-- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 15108b0e45..f4ea039073 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -615,7 +615,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * &ulsch_harq->Kplus, &ulsch_harq->Kminus, &ulsch_harq->F); - int ret = ulsch_decoding_data(eNB, proc, i, harq_pid, + ulsch_decoding_data(eNB, proc, i, harq_pid, ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); } // if ((ulsch) && diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 4e657e6d28..3fe1334228 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -623,8 +623,7 @@ void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { setAllfromTS(timestamp_rx, proc); } -int tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { - int ret=0; +void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; void *txp[ru->nb_tx]; int i; @@ -672,7 +671,7 @@ int tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { /* add fail safe for late command end */ // prepare tx buffer pointers - ret=ru->rfdevice.trx_write_func(&ru->rfdevice, + ru->rfdevice.trx_write_func(&ru->rfdevice, proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, txp, siglen+sf_extension, @@ -682,7 +681,7 @@ int tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->subframe_tx); } - return ret; + return; } static void *ru_thread( void *param ) { diff --git a/executables/split_headers.h b/executables/split_headers.h index b013617cfd..a0c540e42f 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -13,10 +13,9 @@ #define MTU 65536 #define UDP_TIMEOUT 900000L // in micro second (struct timeval, NOT struct timespec) // linux may timeout for a much longer time (up to 10ms) -#define MAX_BLOCKS 16 -#define blockAlign 32 //bytes - +#define blockAlign 32 //bytes to align memory for SIMD copy (256 bits vectors) +// FS6 transport configuration and handler typedef struct { char *sourceIP; char *sourcePort; @@ -29,6 +28,8 @@ typedef struct { #define CTsentCUv0 0xA500 #define CTsentDUv0 0x5A00 +// Main FS6 transport layer header +// All packets starts with this header typedef struct commonUDP_s { uint64_t timestamp; // id of the group (subframe for LTE) uint16_t nbBlocks; // total number of blocks for this timestamp @@ -37,14 +38,8 @@ typedef struct commonUDP_s { uint16_t contentBytes; // will be sent in a UDP packet, so must be < 2^16 bytes } commonUDP_t; -typedef struct frequency_s { - int frame; - int subframe; - int sampleSize; - int nbAnt; - int nbSamples; -} frequency_t; - +// FS6 UL common header (DU to CU) +// gives the RACH detection data and is always sent to inform the CU that a subframe arrived typedef struct { uint16_t max_preamble[4]; uint16_t max_preamble_energy[4]; @@ -52,6 +47,8 @@ typedef struct { uint16_t avg_preamble_energy[4]; } fs6_ul_t; +// FS6 DL common header (CU to DU) +// gives the DCI configuration from each subframe typedef struct { uint8_t pbch_pdu[4]; int num_pdcch_symbols; @@ -62,6 +59,9 @@ typedef struct { LTE_eNB_PHICH phich_vars; } fs6_dl_t; +// a value to type all sub packets, +// to detect errors, and to be able to extend to other versions +// the first byte of each sub structure should match one of these values enum pckType { fs6UlConfig=25, fs6DlConfig=26, @@ -72,6 +72,8 @@ enum pckType { fs6ULindicationSr=41, }; +// CU to DU definition of a future UL subframe decode +// defines a UE future data plane typedef struct { enum pckType type:8; uint16_t UE_id; @@ -136,6 +138,8 @@ typedef struct { uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP]; } fs6_dl_ulsched_t; +// CU to DU defintion of a DL packet for a given UE +// The data itself is padded at the end of this structure typedef struct { enum pckType type:8; int UE_id; @@ -150,24 +154,28 @@ typedef struct { uint8_t pdsch_start; uint8_t sib1_br_flag; uint16_t i0; - uint32_t rb_alloc[4];; + uint32_t rb_alloc[4]; int dataLen; } fs6_dl_uespec_t; +// CU to DU definition of CCH channel typedef struct { int16_t UE_id; LTE_eNB_UCI cch_vars; } fs6_dl_uespec_ulcch_element_t; +// header to group all UE CCH channels definitions in one UDP packet typedef struct { enum pckType type:8; int16_t nb_active_ue; } fs6_dl_uespec_ulcch_t; +// code internal, not transmitted as this typedef struct { int ta; } ul_propagation_t; +// One UE UL data, data plane, UE data appended after the header typedef struct { enum pckType type:8; short UE_id; @@ -184,6 +192,7 @@ typedef struct { uint8_t cqi_crc_status; } fs6_ul_uespec_t; +// UL UCI (control plane), per UE typedef struct { enum pckType type:8; int UEid; @@ -198,6 +207,7 @@ typedef struct { int32_t stat; } fs6_ul_uespec_uci_element_t; +// all segments UCI grouped in one UDP packet typedef struct { enum pckType type:8; int16_t nb_active_ue; @@ -239,7 +249,7 @@ void *du_fs6(void *arg); void fill_rf_config(RU_t *ru, char *rf_config_file); int init_rf(RU_t *ru); void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc); -int tx_rf(RU_t *ru, L1_rxtx_proc_t *proc); +void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc); void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe); void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); bool dlsch_procedures(PHY_VARS_eNB *eNB, diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 2b032c208a..3036c383f2 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1187,11 +1187,9 @@ void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req) { } else { if ( rdata->nbSegments != ulsch_harq->processedSegments ) { int nb=abortTpool(&proc->threadPool, req->key); - printf("nb1:%d\n", nb); nb+=abortNotifiedFIFO(&proc->respDecode, req->key); - printf("nb2:%d\n", nb); proc->nbDecode-=nb; - LOG_I(PHY,"uplink segment error %d/%d, aborted %d segments",rdata->segment_r,rdata->nbSegments, nb); + LOG_I(PHY,"uplink segment error %d/%d, aborted %d segments\n",rdata->segment_r,rdata->nbSegments, nb); AssertFatal(ulsch_harq->processedSegments+nb == rdata->nbSegments,"processed: %d, aborted: %d, total %d\n", ulsch_harq->processedSegments, nb, rdata->nbSegments); ulsch_harq->processedSegments=rdata->nbSegments; @@ -1253,7 +1251,7 @@ void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req) { } void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { - uint32_t ret=0,i; + uint32_t i; uint32_t harq_pid; uint8_t nPRS; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; @@ -1262,7 +1260,6 @@ void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe); - int rvidx_tab[4] = {0,2,3,1}; for (i = 0; i < NUMBER_OF_UE_MAX; i++) { ulsch = eNB->ulsch[i]; @@ -1316,7 +1313,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { rx_ulsch(eNB,proc, i); stop_meas(&eNB->ulsch_demodulation_stats); start_meas(&eNB->ulsch_decoding_stats); - ret = ulsch_decoding(eNB,proc, + ulsch_decoding(eNB,proc, i, 0, // control_only_flag ulsch_harq->V_UL_DAI, diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 4aa09b59de..f41d866221 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -184,7 +184,7 @@ rx_sdu(const module_id_t enb_mod_idP, UE_template_ptr->scheduled_ul_bytes = 0; } } else { // sduP == NULL => error - LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x\n", + LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n", enb_mod_idP, harq_pid, CC_idP, @@ -193,7 +193,8 @@ rx_sdu(const module_id_t enb_mod_idP, UE_scheduling_control->round_UL[CC_idP][harq_pid], ul_cqi, UE_id, - current_rnti); + current_rnti, + sdu_lenP); if (ul_cqi > 200) { // too high energy pattern UE_scheduling_control->pusch_snr[CC_idP] = ul_cqi; From e8091083b0d817cf22f1f522aa6c46aa06ce0100 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 4 Nov 2019 16:11:09 +0100 Subject: [PATCH 060/175] restore ue compilation with ocp-softmodem, some RF simulator improvement --- executables/main-fs6.c | 3 +- executables/main-ocp.c | 10 +- executables/split_headers.h | 2 +- openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 2 +- .../PHY/LTE_UE_TRANSPORT/dlsch_decoding.c | 2 +- openair1/PHY/defs_eNB.h | 368 +++++++++- openair2/UTIL/MEM/mem_block.c | 668 ------------------ openair2/UTIL/MEM/mem_block.h | 110 --- openair2/UTIL/MEM/mem_mngt.c | 489 ------------- openair2/UTIL/MEM/mem_mngt_proto_extern.h | 21 - openair2/UTIL/MEM/mem_pool.h | 38 - targets/ARCH/rfsimulator/simulator.c | 106 +-- targets/RT/USER/lte-enb.c | 19 +- targets/RT/USER/lte-ru.c | 47 +- targets/RT/USER/lte-ue.c | 68 +- targets/RT/USER/lte-uesoftmodem.c | 6 + 16 files changed, 523 insertions(+), 1436 deletions(-) delete mode 100644 openair2/UTIL/MEM/mem_block.c delete mode 100644 openair2/UTIL/MEM/mem_mngt.c delete mode 100644 openair2/UTIL/MEM/mem_mngt_proto_extern.h delete mode 100644 openair2/UTIL/MEM/mem_pool.h diff --git a/executables/main-fs6.c b/executables/main-fs6.c index f4ea039073..471ad0f1eb 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -616,7 +616,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * &ulsch_harq->Kminus, &ulsch_harq->F); ulsch_decoding_data(eNB, proc, i, harq_pid, - ulsch_harq->nb_rb>20 ? 1 : 0); + ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); } // if ((ulsch) && // (ulsch->rnti>0) && @@ -634,6 +634,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask); } } // for (i=0; inbDecode > 0) { notifiedFIFO_elt_t *req=pullTpool(&proc->respDecode, &proc->threadPool); postDecode(proc, req); diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 3fe1334228..8810115197 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -672,11 +672,11 @@ void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { /* add fail safe for late command end */ // prepare tx buffer pointers ru->rfdevice.trx_write_func(&ru->rfdevice, - proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, - txp, - siglen+sf_extension, - ru->nb_tx, - flags); + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, subframe %d\n",ru->idx, (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->subframe_tx); } diff --git a/executables/split_headers.h b/executables/split_headers.h index a0c540e42f..550f189e02 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -73,7 +73,7 @@ enum pckType { }; // CU to DU definition of a future UL subframe decode -// defines a UE future data plane +// defines a UE future data plane typedef struct { enum pckType type:8; uint16_t UE_id; diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 0737d4c56a..99e954238c 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -103,7 +103,7 @@ typedef struct { /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) uint8_t e[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); /// Turbo-code outputs (36-212 V8.6 2009-03, p.12 - //uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))]; + uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))]; /// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17) uint8_t w[MAX_NUM_DLSCH_SEGMENTS][3*6144]; /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_decoding.c index 4ca9a7c762..f8d03fcb50 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_decoding.c @@ -705,7 +705,7 @@ int dlsch_encoding_SIC(PHY_VARS_UE *ue, G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,beamforming_mode); // if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet - if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet + if (dlsch->harq_processes[harq_pid]->DLround == 0) { // this is a new packet #ifdef DEBUG_DLSCH_CODING printf("SIC encoding thinks this is a new packet \n"); #endif diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index 51b2e9c4ae..e602382a71 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -73,6 +73,217 @@ +typedef struct RU_proc_t_s { + /// Pointer to associated RU descriptor + struct RU_t_s *ru; + /// timestamp received from HW + openair0_timestamp timestamp_rx; + /// timestamp to send to "slave rru" + openair0_timestamp timestamp_tx; + /// subframe to act upon for reception + int subframe_rx; + /// subframe to act upon for transmission + int subframe_tx; + /// subframe to act upon for reception of prach + int subframe_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// subframe to act upon for reception of prach BL/CE UEs + int subframe_prach_br; +#endif + /// frame to act upon for reception + int frame_rx; + /// frame to act upon for transmission + int frame_tx; + /// unwrapped frame count + int frame_tx_unwrap; + /// frame to act upon for reception of prach + int frame_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// frame to act upon for reception of prach + int frame_prach_br; +#endif + /// frame offset for slave RUs (to correct for frame asynchronism at startup) + int frame_offset; + /// \brief Instance count for FH processing thread. + /// \internal This variable is protected by \ref mutex_FH. + int instance_cnt_FH; + int instance_cnt_FH1; + /// \internal This variable is protected by \ref mutex_prach. + int instance_cnt_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// \internal This variable is protected by \ref mutex_prach. + int instance_cnt_prach_br; +#endif + /// \internal This variable is protected by \ref mutex_synch. + int instance_cnt_synch; + /// \internal This variable is protected by \ref mutex_eNBs. + int instance_cnt_eNBs; + /// \brief Instance count for rx processing thread. + /// \internal This variable is protected by \ref mutex_asynch_rxtx. + int instance_cnt_asynch_rxtx; + /// \internal This variable is protected by \ref mutex_fep + int instance_cnt_fep; + /// \internal This variable is protected by \ref mutex_feptx + int instance_cnt_feptx; + + /// \internal This variable is protected by \ref mutex_ru_thread + int instance_cnt_ru; + /// pthread structure for RU FH processing thread + pthread_t pthread_FH; + /// pthread structure for RU control thread + pthread_t pthread_ctrl; + + /// This varible is protected by \ref mutex_emulatedRF + int instance_cnt_emulateRF; + /// pthread structure for RU FH processing thread + + pthread_t pthread_FH1; + + /// pthread structure for RU prach processing thread + pthread_t pthread_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// pthread structure for RU prach processing thread BL/CE UEs + pthread_t pthread_prach_br; +#endif + /// pthread struct for RU synch thread + pthread_t pthread_synch; + /// pthread struct for RU RX FEP worker thread + pthread_t pthread_fep; + /// pthread struct for RU TX FEP worker thread + pthread_t pthread_feptx; + /// pthread struct for emulated RF + pthread_t pthread_emulateRF; + /// pthread structure for asychronous RX/TX processing thread + pthread_t pthread_asynch_rxtx; + /// flag to indicate first RX acquisition + int first_rx; + /// flag to indicate first TX transmission + int first_tx; + /// pthread attributes for RU FH processing thread + pthread_attr_t attr_FH; + + /// pthread attributes for RU control thread + pthread_attr_t attr_ctrl; + + pthread_attr_t attr_FH1; + + /// pthread attributes for RU prach + pthread_attr_t attr_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// pthread attributes for RU prach BL/CE UEs + pthread_attr_t attr_prach_br; +#endif + /// pthread attributes for RU synch thread + pthread_attr_t attr_synch; + /// pthread attributes for asynchronous RX thread + pthread_attr_t attr_asynch_rxtx; + /// pthread attributes for worker fep thread + pthread_attr_t attr_fep; + /// pthread attributes for worker feptx thread + pthread_attr_t attr_feptx; + /// pthread attributes for emulated RF + pthread_attr_t attr_emulateRF; + /// scheduling parameters for RU FH thread + struct sched_param sched_param_FH; + struct sched_param sched_param_FH1; + /// scheduling parameters for RU prach thread + struct sched_param sched_param_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// scheduling parameters for RU prach thread BL/CE UEs + struct sched_param sched_param_prach_br; +#endif + /// scheduling parameters for RU synch thread + struct sched_param sched_param_synch; + /// scheduling parameters for asynch_rxtx thread + struct sched_param sched_param_asynch_rxtx; + /// condition variable for RU FH thread + pthread_cond_t cond_FH; + pthread_cond_t cond_FH1; + /// condition variable for RU prach thread + pthread_cond_t cond_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// condition variable for RU prach thread BL/CE UEs + pthread_cond_t cond_prach_br; +#endif + /// condition variable for RU synch thread + pthread_cond_t cond_synch; + /// condition variable for asynch RX/TX thread + pthread_cond_t cond_asynch_rxtx; + /// condition variable for RU RX FEP thread + pthread_cond_t cond_fep; + /// condition variable for RU TX FEP thread + pthread_cond_t cond_feptx; + /// condition variable for emulated RF + pthread_cond_t cond_emulateRF; + /// condition variable for eNB signal + pthread_cond_t cond_eNBs; + /// condition variable for ru_thread + pthread_cond_t cond_ru_thread; + /// mutex for RU FH + pthread_mutex_t mutex_FH; + pthread_mutex_t mutex_FH1; + /// mutex for RU prach + pthread_mutex_t mutex_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// mutex for RU prach BL/CE UEs + pthread_mutex_t mutex_prach_br; +#endif + /// mutex for RU synch + pthread_mutex_t mutex_synch; + /// mutex for eNB signal + pthread_mutex_t mutex_eNBs; + /// mutex for asynch RX/TX thread + pthread_mutex_t mutex_asynch_rxtx; + /// mutex for fep RX worker thread + pthread_mutex_t mutex_fep; + /// mutex for fep TX worker thread + pthread_mutex_t mutex_feptx; + + /// mutex for ru_thread + pthread_mutex_t mutex_ru; + + /// mutex for emulated RF thread + pthread_mutex_t mutex_emulateRF; + + /// symbol mask for IF4p5 reception per subframe + uint32_t symbol_mask[10]; + /// time measurements for each subframe + struct timespec t[10]; + /// number of slave threads + int num_slaves; + /// array of pointers to slaves + struct RU_proc_t_s **slave_proc; +#ifdef PHY_TX_THREAD + /// pthread structure for PRACH thread + pthread_t pthread_phy_tx; + pthread_mutex_t mutex_phy_tx; + pthread_cond_t cond_phy_tx; + /// \internal This variable is protected by \ref mutex_phy_tx. + int instance_cnt_phy_tx; + /// frame to act upon for transmission + int frame_phy_tx; + /// subframe to act upon for transmission + int subframe_phy_tx; + /// timestamp to send to "slave rru" + openair0_timestamp timestamp_phy_tx; + /// pthread structure for RF TX thread + pthread_t pthread_rf_tx; + pthread_mutex_t mutex_rf_tx; + pthread_cond_t cond_rf_tx; + /// \internal This variable is protected by \ref mutex_rf_tx. + int instance_cnt_rf_tx; +#endif +#if defined(PRE_SCD_THREAD) + pthread_t pthread_pre_scd; + /// condition variable for time processing thread + pthread_cond_t cond_pre_scd; + /// mutex for time thread + pthread_mutex_t mutex_pre_scd; + int instance_pre_scd; +#endif + int emulate_rf_busy; +} RU_proc_t; + typedef enum { LOCAL_RF =0, REMOTE_IF5 =1, @@ -257,7 +468,7 @@ typedef struct RU_t_s{ /// value to be passed using command uint16_t cmdval; /// process scheduling variables - //RU_proc_t proc; + RU_proc_t proc; /// stats thread pthread descriptor pthread_t ru_stats_thread; /// OTA synchronization signal @@ -547,6 +758,159 @@ typedef struct { pthread_mutex_t mutex_te; } te_params; +/// Context data structure for eNB subframe processing +typedef struct L1_proc_t_s { + /// Component Carrier index + uint8_t CC_id; + /// thread index + int thread_index; + /// timestamp received from HW + openair0_timestamp timestamp_rx; + /// timestamp to send to "slave rru" + openair0_timestamp timestamp_tx; + /// subframe to act upon for reception + int subframe_rx; + /// subframe to act upon for PRACH + int subframe_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// subframe to act upon for reception of prach BL/CE UEs + int subframe_prach_br; +#endif + /// frame to act upon for reception + int frame_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for PRACH + int frame_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// frame to act upon for PRACH BL/CE UEs + int frame_prach_br; +#endif + /// \internal This variable is protected by \ref mutex_td. + int instance_cnt_td; + /// \internal This variable is protected by \ref mutex_te. + int instance_cnt_te; + /// \internal This variable is protected by \ref mutex_prach. + int instance_cnt_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// \internal This variable is protected by \ref mutex_prach for BL/CE UEs. + int instance_cnt_prach_br; +#endif + // instance count for over-the-air eNB synchronization + int instance_cnt_synch; + + + /// \internal This variable is protected by \ref mutex_asynch_rxtx. + int instance_cnt_asynch_rxtx; + /// pthread structure for asychronous RX/TX processing thread + pthread_t pthread_asynch_rxtx; + /// flag to indicate first RX acquisition + int first_rx; + /// flag to indicate first TX transmission + int first_tx; + /// pthread attributes for parallel turbo-decoder thread + pthread_attr_t attr_td; + /// pthread attributes for parallel turbo-encoder thread + pthread_attr_t attr_te; + /// pthread attributes for single eNB processing thread + pthread_attr_t attr_single; + /// pthread attributes for prach processing thread + pthread_attr_t attr_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// pthread attributes for prach processing thread BL/CE UEs + pthread_attr_t attr_prach_br; +#endif + /// pthread attributes for asynchronous RX thread + pthread_attr_t attr_asynch_rxtx; + /// scheduling parameters for parallel turbo-decoder thread + struct sched_param sched_param_td; + /// scheduling parameters for parallel turbo-encoder thread + struct sched_param sched_param_te; + /// scheduling parameters for single eNB thread + struct sched_param sched_param_single; + /// scheduling parameters for prach thread + struct sched_param sched_param_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// scheduling parameters for prach thread + struct sched_param sched_param_prach_br; +#endif + /// scheduling parameters for asynch_rxtx thread + struct sched_param sched_param_asynch_rxtx; + /// pthread structure for parallel turbo-decoder thread + pthread_t pthread_td; + /// pthread structure for parallel turbo-encoder thread + pthread_t pthread_te; + /// pthread structure for PRACH thread + pthread_t pthread_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// pthread structure for PRACH thread BL/CE UEs + pthread_t pthread_prach_br; +#endif + /// condition variable for parallel turbo-decoder thread + pthread_cond_t cond_td; + /// condition variable for parallel turbo-encoder thread + pthread_cond_t cond_te; + /// condition variable for PRACH processing thread; + pthread_cond_t cond_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// condition variable for PRACH processing thread BL/CE UEs; + pthread_cond_t cond_prach_br; +#endif + + /// condition variable for asynch RX/TX thread + pthread_cond_t cond_asynch_rxtx; + /// mutex for parallel turbo-decoder thread + pthread_mutex_t mutex_td; + /// mutex for parallel turbo-encoder thread + pthread_mutex_t mutex_te; + /// mutex for PRACH thread + pthread_mutex_t mutex_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// mutex for PRACH thread for BL/CE UEs + pthread_mutex_t mutex_prach_br; +#endif + /// mutex for asynch RX/TX thread + pthread_mutex_t mutex_asynch_rxtx; + /// mutex for RU access to eNB processing (PDSCH/PUSCH) + pthread_mutex_t mutex_RU; + /// mutex for eNB processing to access RU TX (PDSCH/PUSCH) + pthread_mutex_t mutex_RU_tx; + /// mutex for RU access to eNB processing (PRACH) + pthread_mutex_t mutex_RU_PRACH; + /// mutex for RU access to eNB processing (PRACH BR) + pthread_mutex_t mutex_RU_PRACH_br; + /// mask for RUs serving eNB (PDSCH/PUSCH) + int RU_mask[10]; + /// mask for RUs serving eNB (PDSCH/PUSCH) + int RU_mask_tx; + /// time measurements for RU arrivals + struct timespec t[10]; + /// Timing statistics (RU_arrivals) + time_stats_t ru_arrival_time; + /// mask for RUs serving eNB (PRACH) + int RU_mask_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /// mask for RUs serving eNB (PRACH) + int RU_mask_prach_br; +#endif + /// parameters for turbo-decoding worker thread + td_params tdp; + /// parameters for turbo-encoding worker thread + te_params tep[3]; + /// set of scheduling variables RXn-TXnp4 threads + L1_rxtx_proc_t L1_proc,L1_proc_tx; + /// stats thread pthread descriptor + pthread_t process_stats_thread; + /// for waking up tx procedure + RU_proc_t *ru_proc; +} L1_proc_t; + + + + + + + typedef struct { //unsigned int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (linear) //unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (dB) @@ -608,7 +972,7 @@ typedef struct PHY_VARS_eNB_s { module_id_t Mod_id; uint8_t CC_id; uint8_t configured; - //L1_proc_t proc; + L1_proc_t proc; int single_thread_flag; int abstraction_flag; int num_RU; diff --git a/openair2/UTIL/MEM/mem_block.c b/openair2/UTIL/MEM/mem_block.c deleted file mode 100644 index 0150ef00cd..0000000000 --- a/openair2/UTIL/MEM/mem_block.c +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*************************************************************************** - mem_block.c - description - ------------------- - AUTHOR : Lionel GAUTHIER - COMPANY : EURECOM - EMAIL : Lionel.Gauthier@eurecom.fr - - - ***************************************************************************/ -#define MEM_BLOCK_C -//#include "rtos_header.h" -#include "mem_block.h" -#include "mem_pool.h" -#include "list.h" -#include "LAYER2/MAC/mac_extern.h" -#include "assertions.h" -/* all function calls are protected by a mutex - * to ensure that many threads calling them at - * the same time don't mess up. - * We might be more clever in the future, it's a - * bit overkill. - * Commenting this define removes the protection, - * so be careful with it. - */ -#define MEMBLOCK_BIG_LOCK - -#ifdef MEMBLOCK_BIG_LOCK -static pthread_mutex_t mtex = PTHREAD_MUTEX_INITIALIZER; -#endif - -//----------------------------------------------------------------------------- -//#define DEBUG_MEM_MNGT_FREE -//#define DEBUG_MEM_MNGT_ALLOC_SIZE -//#define DEBUG_MEM_MNGT_ALLOC -//----------------------------------------------------------------------------- -#if defined(DEBUG_MEM_MNGT_ALLOC) -uint32_t counters[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -#endif -//----------------------------------------------------------------------------- -/* - * initialize all ures - */ -extern mem_pool *memBlockVar; -void * -pool_buffer_init (void) -{ - //----------------------------------------------------------------------------- - - uint32_t index, mb_index, pool_index; - mem_pool *memory = (mem_pool *) &mem_block_var; - memBlockVar=malloc(sizeof(mem_pool)); - int pool_sizes[14] = { MEM_MNGT_MB0_NB_BLOCKS, MEM_MNGT_MB1_NB_BLOCKS, - MEM_MNGT_MB2_NB_BLOCKS, MEM_MNGT_MB3_NB_BLOCKS, - MEM_MNGT_MB4_NB_BLOCKS, MEM_MNGT_MB5_NB_BLOCKS, - MEM_MNGT_MB6_NB_BLOCKS, MEM_MNGT_MB7_NB_BLOCKS, - MEM_MNGT_MB8_NB_BLOCKS, MEM_MNGT_MB9_NB_BLOCKS, - MEM_MNGT_MB10_NB_BLOCKS, MEM_MNGT_MB11_NB_BLOCKS, - MEM_MNGT_MB12_NB_BLOCKS, MEM_MNGT_MBCOPY_NB_BLOCKS - }; - -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_lock(&mtex)) abort(); -#endif - - memset (memory, 0, sizeof (mem_pool)); - mb_index = 0; - - // LG_TEST - for (pool_index = 0; pool_index <= MEM_MNGT_POOL_ID_COPY; pool_index++) { - list_init (&memory->mem_lists[pool_index], "POOL"); - - for (index = 0; index < pool_sizes[pool_index]; index++) { - //memory->mem_blocks[mb_index + index].previous = NULL; -> done in memset 0 - //memory->mem_blocks[mb_index + index].next = NULL; -> done in memset 0 - switch (pool_index) { - case 0: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool0[index][0]); - break; - - case 1: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool1[index][0]); - break; - - case 2: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool2[index][0]); - break; - - case 3: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool3[index][0]); - break; - - case 4: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool4[index][0]); - break; - - case 5: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool5[index][0]); - break; - - case 6: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool6[index][0]); - break; - - case 7: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool7[index][0]); - break; - - case 8: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool8[index][0]); - break; - - case 9: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool9[index][0]); - break; - - case 10: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool10[index][0]); - break; - - case 11: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool11[index][0]); - break; - - case 12: - memory->mem_blocks[mb_index + index].data = (unsigned char*)&(memory->mem_pool12[index][0]); - break; - - default: - ; - memory->mem_blocks[mb_index + index].data = NULL; // pool copy - - } - - memory->mem_blocks[mb_index + index].pool_id = pool_index; - list_add_tail_eurecom (&memory->mem_blocks[mb_index + index], &memory->mem_lists[pool_index]); - } - - mb_index += pool_sizes[pool_index]; - } - -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_unlock(&mtex)) abort(); -#endif - - return 0; -} - -//----------------------------------------------------------------------------- -void * -pool_buffer_clean (void *arg) -{ - //----------------------------------------------------------------------------- - return 0; -} -//----------------------------------------------------------------------------- -void -free_mem_block (mem_block_t * leP, const char* caller) -{ - //----------------------------------------------------------------------------- - - if (!(leP)) { - LOG_W (RLC,"[MEM_MNGT][FREE] WARNING FREE NULL MEM_BLOCK\n"); - return; - } - -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_lock(&mtex)) abort(); -#endif - -#ifdef DEBUG_MEM_MNGT_FREE - LOG_D (RLC,"[MEM_MNGT][FREE] free_mem_block() %p pool: %d\n", leP, leP->pool_id); -#endif -#ifdef DEBUG_MEM_MNGT_ALLOC - check_free_mem_block (leP); -#endif - - if (leP->pool_id <= MEM_MNGT_POOL_ID_COPY) { - list_add_tail_eurecom (leP, &mem_block_var.mem_lists[leP->pool_id]); -#ifdef DEBUG_MEM_MNGT_ALLOC - counters[leP->pool_id] -= 1; - LGO_D (RLC,"[%s][MEM_MNGT][INFO] after pool[%2d] freed: counters = {%2d %2d %2d %2d %2d %2d %2d %2d %2d %2d %2d %2d}\n", - caller, leP->pool_id, - counters[0],counters[1],counters[2],counters[3],counters[4], - counters[5],counters[6],counters[7],counters[8],counters[9], - counters[10],counters[11]); -#endif - leP = NULL; // this prevent from freeing the block twice - } else { - LOG_E (RLC,"[MEM_MNGT][FREE] ERROR free_mem_block() unknown pool_id : %d\n", leP->pool_id); - } - -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_unlock(&mtex)) abort(); -#endif -} - -//----------------------------------------------------------------------------- -mem_block_t * -get_free_mem_block (uint32_t sizeP, const char* caller) -{ - //----------------------------------------------------------------------------- - mem_block_t *le = NULL; - int pool_selected; - int size; - - if (sizeP > MEM_MNGT_MB12_BLOCK_SIZE) { - LOG_E (RLC,"[MEM_MNGT][ERROR][FATAL] size requested %d out of bounds\n", sizeP); - display_mem_load (); - AssertFatal(1==0,"get_free_mem_block size requested out of bounds"); - return NULL; - } - -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_lock(&mtex)) abort(); -#endif - - size = sizeP >> 6; - pool_selected = 0; - - while ((size)) { - pool_selected += 1; - size = size >> 1; - } - - // pool is selected according to the size requested, now get a block - // if no block is available pick one in an other pool - do { - if ((le = list_remove_head (&mem_block_var.mem_lists[pool_selected]))) { -#ifdef DEBUG_MEM_MNGT_ALLOC - counters[pool_selected] += 1; - LOG_D (RLC,"[%s][MEM_MNGT][INFO] after pool[%2d] allocated: counters = {%2d %2d %2d %2d %2d %2d %2d %2d %2d %2d %2d %2d}\n", - caller, - pool_selected, - counters[0],counters[1],counters[2],counters[3],counters[4], - counters[5],counters[6],counters[7],counters[8],counters[9], - counters[10],counters[11]); -#endif -#ifdef DEBUG_MEM_MNGT_ALLOC_SIZE - LOG_D (RLC,"[MEM_MNGT][INFO] ALLOC MEM_BLOCK SIZE %d bytes pool %d (%p)\n", sizeP, pool_selected,le); -#endif - - AssertFatal(le->pool_id == pool_selected, "Unexpected pool ID!"); - -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_unlock(&mtex)) abort(); -#endif - - return le; - } - -#ifdef DEBUG_MEM_MNGT_ALLOC - LOG_E (RLC,"[MEM_MNGT][ERROR][MINOR] memory pool %d is empty trying next pool alloc count = %d\n", pool_selected, counters[pool_selected]); - // display_mem_load (); - // check_mem_area ((void *)&mem_block_var); -#endif - } while (pool_selected++ < 12); - - LOG_E(PHY, "[MEM_MNGT][ERROR][FATAL] failed allocating MEM_BLOCK size %d byes (pool_selected=%d size=%d)\n", sizeP, pool_selected, size); -// display_mem_load(); -// AssertFatal(1==0,"get_free_mem_block failed"); - LOG_E(MAC,"[MEM_MNGT][ERROR][FATAL] get_free_mem_block failed!!!\n"); -#ifdef MEMBLOCK_BIG_LOCK - if (pthread_mutex_unlock(&mtex)) abort(); -#endif - - return NULL; -}; - -//----------------------------------------------------------------------------- -mem_block_t * -get_free_copy_mem_block (void) -{ - //----------------------------------------------------------------------------- - mem_block_t *le; - -#ifdef MEMBLOCK_BIG_LOCK - AssertFatal(0, "This function is not handled properly but not used anywhere. FIXME?\n"); -#endif - - if ((le = list_remove_head (&mem_block_var.mem_lists[MEM_MNGT_POOL_ID_COPY]))) { -#ifdef DEBUG_MEM_MNGT_ALLOC_SIZE - LOG_D (RLC,"[MEM_MNGT][INFO] ALLOC COPY MEM BLOCK (%p)\n",le); -#endif -#ifdef DEBUG_MEM_MNGT_ALLOC - counters[MEM_MNGT_POOL_ID_COPY] += 1; - LOG_D (RLC,"[MEM_MNGT][INFO] pool counters = {%2d %2d %2d %2d %2d %2d %2d %2d %2d %2d %2d %2d}\n", - counters[0],counters[1],counters[2],counters[3],counters[4], - counters[5],counters[6],counters[7],counters[8],counters[9], - counters[10],counters[11]); -#endif - return le; - } else { - LOG_E (RLC,"[MEM_MNGT][ERROR] POOL COPY IS EMPTY\n"); - //#ifdef DEBUG_MEM_MNGT_ALLOC - check_mem_area (); - // break_point (); - //#endif - - AssertFatal(1==0,"mem pool is empty"); - return NULL; - } -} - -//----------------------------------------------------------------------------- -mem_block_t * -copy_mem_block (mem_block_t * leP, mem_block_t * destP) -{ - //----------------------------------------------------------------------------- - -#ifdef MEMBLOCK_BIG_LOCK - AssertFatal(0, "This function is not handled properly but not used anywhere. FIXME?\n"); -#endif - - if ((destP != NULL) && (leP != NULL) && (destP->pool_id == MEM_MNGT_POOL_ID_COPY)) { - destP->data = leP->data; - } else { - LOG_E (RLC,"[MEM_MNGT][COPY] copy_mem_block() pool dest src or dest is NULL\n"); - } - - return destP; -} - -//----------------------------------------------------------------------------- -void -display_mem_load (void) -{ - //----------------------------------------------------------------------------- -#ifdef MEMBLOCK_BIG_LOCK - /* this function does not need to be protected, do nothing */ -#endif - - mem_pool *memory = (mem_pool *) &mem_block_var; - - LOG_D (RLC,"POOL 0 (%d elements of %d Bytes): ", MEM_MNGT_MB0_NB_BLOCKS, MEM_MNGT_MB0_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID0]); - LOG_D (RLC,"POOL 1 (%d elements of %d Bytes): ", MEM_MNGT_MB1_NB_BLOCKS, MEM_MNGT_MB1_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID1]); - LOG_D (RLC,"POOL 2 (%d elements of %d Bytes): ", MEM_MNGT_MB2_NB_BLOCKS, MEM_MNGT_MB2_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID2]); - LOG_D (RLC,"POOL 3 (%d elements of %d Bytes): ", MEM_MNGT_MB3_NB_BLOCKS, MEM_MNGT_MB3_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID3]); - LOG_D (RLC,"POOL 4 (%d elements of %d Bytes): ", MEM_MNGT_MB4_NB_BLOCKS, MEM_MNGT_MB4_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID4]); - LOG_D (RLC,"POOL 5 (%d elements of %d Bytes): ", MEM_MNGT_MB5_NB_BLOCKS, MEM_MNGT_MB5_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID5]); - LOG_D (RLC,"POOL 6 (%d elements of %d Bytes): ", MEM_MNGT_MB6_NB_BLOCKS, MEM_MNGT_MB6_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID6]); - LOG_D (RLC,"POOL 7 (%d elements of %d Bytes): ", MEM_MNGT_MB7_NB_BLOCKS, MEM_MNGT_MB7_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID7]); - LOG_D (RLC,"POOL 8 (%d elements of %d Bytes): ", MEM_MNGT_MB8_NB_BLOCKS, MEM_MNGT_MB8_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID8]); - LOG_D (RLC,"POOL 9 (%d elements of %d Bytes): ", MEM_MNGT_MB9_NB_BLOCKS, MEM_MNGT_MB9_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID9]); - LOG_D (RLC,"POOL 10 (%d elements of %d Bytes): ", MEM_MNGT_MB10_NB_BLOCKS, MEM_MNGT_MB10_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID10]); - LOG_D (RLC,"POOL 11 (%d elements of %d Bytes): ", MEM_MNGT_MB11_NB_BLOCKS, MEM_MNGT_MB11_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID11]); - LOG_D (RLC,"POOL 12 (%d elements of %d Bytes): ", MEM_MNGT_MB12_NB_BLOCKS, MEM_MNGT_MB12_BLOCK_SIZE); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID12]); - LOG_D (RLC,"POOL C (%d elements): ", MEM_MNGT_MBCOPY_NB_BLOCKS); - list_display (&memory->mem_lists[MEM_MNGT_POOL_ID_COPY]); -} - -//----------------------------------------------------------------------------- -void -check_mem_area (void) -{ - //----------------------------------------------------------------------------- - int index, mb_index; - mem_pool *memory = (mem_pool *) &mem_block_var; - -#ifdef MEMBLOCK_BIG_LOCK - AssertFatal(0, "This function is not handled properly but not used anywhere. FIXME?\n"); -#endif - - for (index = 0; index < MEM_MNGT_MB0_NB_BLOCKS; index++) { - if ((memory->mem_blocks[index].data != (unsigned char*)&(memory->mem_pool0[index][0])) && (memory->mem_blocks[index].pool_id != MEM_MNGT_POOL_ID0)) { - LOG_D (RLC,"[MEM] ERROR POOL0 block index %d\n", index); - } - } - - mb_index = MEM_MNGT_MB0_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB1_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool1[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID1)) { - LOG_D (RLC,"[MEM] ERROR POOL1 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB1_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB2_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool2[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID2)) { - LOG_D (RLC,"[MEM] ERROR POOL2 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB2_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB3_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool3[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID3)) { - LOG_D (RLC,"[MEM] ERROR POOL3 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB3_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB4_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool4[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID4)) { - LOG_D (RLC,"[MEM] ERROR POOL4 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB4_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB5_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool5[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID5)) { - LOG_D (RLC,"[MEM] ERROR POOL5 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB5_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB6_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool6[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID6)) { - LOG_D (RLC,"[MEM] ERROR POOL6 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB6_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB7_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool7[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID7)) { - LOG_D (RLC,"[MEM] ERROR POOL7 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB7_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB8_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool8[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID8)) { - LOG_D (RLC,"[MEM] ERROR POOL8 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB8_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB9_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool9[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID9)) { - LOG_D (RLC,"[MEM] ERROR POOL9 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB9_NB_BLOCKS; - - for (index = mb_index; index < MEM_MNGT_MB10_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool10[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID10)) { - LOG_D (RLC,"[MEM] ERROR POOL10 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB10_NB_BLOCKS; - - for (index = mb_index; index < MEM_MNGT_MB11_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool11[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID11)) { - LOG_D (RLC,"[MEM] ERROR POOL11 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB11_NB_BLOCKS; - - for (index = mb_index; index < MEM_MNGT_MB12_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != (unsigned char*)&(memory->mem_pool12[index][0])) - && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID12)) { - LOG_D (RLC,"[MEM] ERROR POOL12 block index %d\n", index); - } - } - - mb_index += MEM_MNGT_MB12_NB_BLOCKS; - - for (index = mb_index; index < MEM_MNGT_NB_ELEMENTS; index++) { - if ((memory->mem_blocks[index].data != NULL) && (memory->mem_blocks[index].pool_id != MEM_MNGT_POOL_ID_COPY)) { - LOG_D (RLC,"[MEM] ERROR POOL COPY block index %d\n", index); - } - } -} - -//----------------------------------------------------------------------------- -void -check_free_mem_block (mem_block_t * leP) -{ - //----------------------------------------------------------------------------- - ptrdiff_t block_index; - -#ifdef MEMBLOCK_BIG_LOCK - /* this function does not SEEM TO need to be protected, do nothing (for the moment) */ -#endif - - if ((leP >= mem_block_var.mem_blocks) && (leP <= &mem_block_var.mem_blocks[MEM_MNGT_NB_ELEMENTS-1])) { - // the pointer is inside the memory region - block_index = leP - mem_block_var.mem_blocks; - // block_index is now: 0 <= block_index < MEM_MNGT_NB_ELEMENTS - - if (block_index < MEM_MNGT_MB0_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool0[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID0)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB0_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB1_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool1[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID1)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB1_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB2_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool2[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID2)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB2_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB3_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool3[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID3)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB3_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB4_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool4[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID4)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB4_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB5_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool5[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID5)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB5_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB6_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool6[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID6)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB6_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB7_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool7[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID7)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB7_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB8_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool8[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID8)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB8_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB9_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool9[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID9)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB9_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB10_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool10[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID10)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB10_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB11_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool11[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID11)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - - block_index -= MEM_MNGT_MB11_NB_BLOCKS; - - if (block_index < MEM_MNGT_MB12_NB_BLOCKS) { - if ((leP->data != (unsigned char*)mem_block_var.mem_pool12[block_index]) && (leP->pool_id != MEM_MNGT_POOL_ID12)) { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - return; - } - } else { - LOG_D (RLC,"[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - - // the block is ok -} diff --git a/openair2/UTIL/MEM/mem_block.h b/openair2/UTIL/MEM/mem_block.h index 4d8ed4e89b..0d99430640 100644 --- a/openair2/UTIL/MEM/mem_block.h +++ b/openair2/UTIL/MEM/mem_block.h @@ -57,91 +57,8 @@ mem_block_t *get_free_copy_mem_block (void); mem_block_t *get_free_copy_mem_block_up (void); mem_block_t *copy_mem_block (mem_block_t * leP, mem_block_t * destP); void display_mem_load (void); - -void check_mem_area (void); -void check_free_mem_block (mem_block_t * leP); -# define MEM_SCALE MAX_MOBILES_PER_ENB -// definition of the size of the allocated memory area -# define MEM_MNGT_MB0_BLOCK_SIZE 64 -// 64 -# define MEM_MNGT_MB0_NB_BLOCKS 4096 * MEM_SCALE -# define MEM_MNGT_POOL_ID0 0 - -# define MEM_MNGT_MB1_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*2 -// 128 -# define MEM_MNGT_MB1_NB_BLOCKS 4096 * MEM_SCALE -# define MEM_MNGT_POOL_ID1 1 - -# define MEM_MNGT_MB2_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*4 -// 256 -# define MEM_MNGT_MB2_NB_BLOCKS 2048 * MEM_SCALE -# define MEM_MNGT_POOL_ID2 2 - -# define MEM_MNGT_MB3_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*8 -// 512 -# define MEM_MNGT_MB3_NB_BLOCKS 2048 * MEM_SCALE -# define MEM_MNGT_POOL_ID3 3 - -# define MEM_MNGT_MB4_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*16 -// 1024 -# define MEM_MNGT_MB4_NB_BLOCKS 1024 * MEM_SCALE -# define MEM_MNGT_POOL_ID4 4 - -# define MEM_MNGT_MB5_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*32 -// 2048 -# define MEM_MNGT_MB5_NB_BLOCKS 1024 * MEM_SCALE // LG WAS 1024 -# define MEM_MNGT_POOL_ID5 5 - -# define MEM_MNGT_MB6_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*64 -// 4096 -# define MEM_MNGT_MB6_NB_BLOCKS 1024 * MEM_SCALE // LG WAS 256 -# define MEM_MNGT_POOL_ID6 6 - -# define MEM_MNGT_MB7_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*128 -// 8192 -# define MEM_MNGT_MB7_NB_BLOCKS 64* MEM_SCALE // LG WAS 32 -# define MEM_MNGT_POOL_ID7 7 - -# define MEM_MNGT_MB8_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*256 - -#ifdef JUMBO_FRAMES -# define MEM_MNGT_MB8_NB_BLOCKS 256 * MEM_SCALE -#else -# define MEM_MNGT_MB8_NB_BLOCKS 16 * MEM_SCALE -// 16384 -#endif -# define MEM_MNGT_POOL_ID8 8 - -# define MEM_MNGT_MB9_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*512 -// 32768 -# define MEM_MNGT_MB9_NB_BLOCKS 8 * MEM_SCALE -# define MEM_MNGT_POOL_ID9 9 - -# define MEM_MNGT_MB10_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*1024 -// 65536 -# define MEM_MNGT_MB10_NB_BLOCKS 0 * MEM_SCALE -# define MEM_MNGT_POOL_ID10 10 - -# define MEM_MNGT_MB11_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*2048 -// 131072 -# define MEM_MNGT_MB11_NB_BLOCKS 0 * MEM_SCALE -# define MEM_MNGT_POOL_ID11 11 - -# define MEM_MNGT_MB12_BLOCK_SIZE MEM_MNGT_MB0_BLOCK_SIZE*4096 -// 262144 -# define MEM_MNGT_MB12_NB_BLOCKS 32 * MEM_SCALE -//# define MEM_MNGT_MB12_NB_BLOCKS 4096 * MEM_SCALE - -# define MEM_MNGT_POOL_ID12 12 - - -# define MEM_MNGT_MBCOPY_NB_BLOCKS 1024 -# define MEM_MNGT_NB_ELEMENTS MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS + MEM_MNGT_MB5_NB_BLOCKS + MEM_MNGT_MB6_NB_BLOCKS + MEM_MNGT_MB7_NB_BLOCKS + MEM_MNGT_MB8_NB_BLOCKS + MEM_MNGT_MB9_NB_BLOCKS + MEM_MNGT_MB10_NB_BLOCKS + MEM_MNGT_MB11_NB_BLOCKS + MEM_MNGT_MB12_NB_BLOCKS + MEM_MNGT_MBCOPY_NB_BLOCKS -# define MEM_MNGT_POOL_ID_COPY 13 - #define LIST_NAME_MAX_CHAR 32 - typedef struct { struct mem_block_t *head; struct mem_block_t *tail; @@ -156,33 +73,6 @@ typedef struct { char name[LIST_NAME_MAX_CHAR]; } list_t; - - -typedef struct { - //----------------------------------------------------------- - // basic memory management - //----------------------------------------------------------- - char mem_pool0[MEM_MNGT_MB0_NB_BLOCKS][MEM_MNGT_MB0_BLOCK_SIZE]; - char mem_pool1[MEM_MNGT_MB1_NB_BLOCKS][MEM_MNGT_MB1_BLOCK_SIZE]; - char mem_pool2[MEM_MNGT_MB2_NB_BLOCKS][MEM_MNGT_MB2_BLOCK_SIZE]; - char mem_pool3[MEM_MNGT_MB3_NB_BLOCKS][MEM_MNGT_MB3_BLOCK_SIZE]; - char mem_pool4[MEM_MNGT_MB4_NB_BLOCKS][MEM_MNGT_MB4_BLOCK_SIZE]; - char mem_pool5[MEM_MNGT_MB5_NB_BLOCKS][MEM_MNGT_MB5_BLOCK_SIZE]; - char mem_pool6[MEM_MNGT_MB6_NB_BLOCKS][MEM_MNGT_MB6_BLOCK_SIZE]; - char mem_pool7[MEM_MNGT_MB7_NB_BLOCKS][MEM_MNGT_MB7_BLOCK_SIZE]; - char mem_pool8[MEM_MNGT_MB8_NB_BLOCKS][MEM_MNGT_MB8_BLOCK_SIZE]; - char mem_pool9[MEM_MNGT_MB9_NB_BLOCKS][MEM_MNGT_MB9_BLOCK_SIZE]; - char mem_pool10[MEM_MNGT_MB10_NB_BLOCKS][MEM_MNGT_MB10_BLOCK_SIZE]; - char mem_pool11[MEM_MNGT_MB11_NB_BLOCKS][MEM_MNGT_MB11_BLOCK_SIZE]; - char mem_pool12[MEM_MNGT_MB12_NB_BLOCKS][MEM_MNGT_MB12_BLOCK_SIZE]; - mem_block_t mem_blocks[MEM_MNGT_NB_ELEMENTS]; - list_t mem_lists[14]; - -} mem_pool; - -mem_pool *memBlockVar; -#define mem_block_var (*memBlockVar) - #ifdef __cplusplus } #endif diff --git a/openair2/UTIL/MEM/mem_mngt.c b/openair2/UTIL/MEM/mem_mngt.c deleted file mode 100644 index 57c90ea4f9..0000000000 --- a/openair2/UTIL/MEM/mem_mngt.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*************************************************************************** - mem_mngt.c - description - ------------------- - AUTHOR : Lionel GAUTHIER - COMPANY : EURECOM - EMAIL : Lionel.Gauthier@eurecom.fr - - - ***************************************************************************/ -#define MEM_MNGT_C -#include "rtos_header.h" -#include "platform.h" -#include "protocol_vars_extern.h" -#include "print.h" - -#include "mem_block.h" -#include "mem_pool.h" -#include "lists_proto_extern.h" -#include "umts_sched.h" -//----------------------------------------------------------------------------- -#define DEBUG_MEM_MNGT_FREE -#define DEBUG_MEM_MNGT_ALLOC_SIZE -#define DEBUG_MEM_MNGT_ALLOC -#ifdef DEBUG_MEM_MNGT_ADDR -# define PRINT_MEM_MNGT_ADDR msg -#else -# define PRINT_MEM_MNGT_ADDR -// -#endif -//----------------------------------------------------------------------------- -uint32_t counters[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -//----------------------------------------------------------------------------- -/* - * initialize all ures - */ -void * -pool_buffer_init (void *arg) -{ - //----------------------------------------------------------------------------- - - uint32_t index, mb_index, pool_index; - mem_pool *memory = (mem_pool *) arg; - int pool_sizes[11] = { MEM_MNGT_MB0_NB_BLOCKS, MEM_MNGT_MB1_NB_BLOCKS, - MEM_MNGT_MB2_NB_BLOCKS, MEM_MNGT_MB3_NB_BLOCKS, - MEM_MNGT_MB4_NB_BLOCKS, MEM_MNGT_MB5_NB_BLOCKS, - MEM_MNGT_MB6_NB_BLOCKS, MEM_MNGT_MB7_NB_BLOCKS, - MEM_MNGT_MB8_NB_BLOCKS, MEM_MNGT_MB9_NB_BLOCKS, - MEM_MNGT_MBCOPY_NB_BLOCKS - }; - - memset (memory, 0, sizeof (mem_pool)); - mb_index = 0; - - // LG_TEST - for (pool_index = 0; pool_index <= MEM_MNGT_POOL_ID_COPY; pool_index++) { - init_list (&memory->mem_lists[pool_index], "POOL"); - - for (index = 0; index < pool_sizes[pool_index]; index++) { - //memory->mem_blocks[mb_index + index].previous = NULL; -> done in memset 0 - //memory->mem_blocks[mb_index + index].next = NULL; -> done in memset 0 - switch (pool_index) { - case 0: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool0[index][0]); - break; - - case 1: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool1[index][0]); - break; - - case 2: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool2[index][0]); - break; - - case 3: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool3[index][0]); - break; - - case 4: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool4[index][0]); - break; - - case 5: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool5[index][0]); - break; - - case 6: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool6[index][0]); - break; - - case 7: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool7[index][0]); - break; - - case 8: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool8[index][0]); - break; - - case 9: - memory->mem_blocks[mb_index + index].data = &(memory->mem_pool9[index][0]); - break; - - default: - ; - memory->mem_blocks[mb_index + index].data = NULL; // pool copy - - } - - memory->mem_blocks[mb_index + index].pool_id = pool_index; - add_tail (&memory->mem_blocks[mb_index + index], &memory->mem_lists[pool_index]); - } - - mb_index += pool_sizes[pool_index]; - } - - return 0; -} - -//----------------------------------------------------------------------------- -void * -pool_buffer_clean (void *arg) -{ - //----------------------------------------------------------------------------- -#ifndef NO_THREAD_SAFE - mem_pool *memory = (mem_pool *) arg; - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID0].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID1].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID2].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID3].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID4].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID5].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID6].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID7].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID8].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID9].mutex); - pthread_mutex_destroy (&memory->mem_lists[MEM_MNGT_POOL_ID_COPY].mutex); -#endif - return 0; -} -//----------------------------------------------------------------------------- -void -free_mem_block (mem_block_t * leP, __func__) -{ - //----------------------------------------------------------------------------- - - if (!(leP)) { - msg ("[MEM_MNGT][FREE] WARNING FREE NULL MEM_BLOCK\n"); - return; - } - -#ifdef DEBUG_MEM_MNGT_FREE - msg ("[MEM_MNGT][FREE] free_mem_block() %p pool: %d\n", leP, leP->pool_id, __func__); -#endif -#ifdef DEBUG_MEM_MNGT_ALLOC - check_free_mem_block (leP, __func__); -#endif - - if (leP->pool_id <= MEM_MNGT_POOL_ID_COPY) { - add_tail (leP, &mem->mem_lists[leP->pool_id]); -#ifdef DEBUG_MEM_MNGT_ALLOC - counters[leP->pool_id] -= 1; -#endif - leP = NULL; // this prevent from freeing the block twice - } else { - msg ("[MEM_MNGT][FREE] ERROR free_mem_block() unknown pool_id : %d\n", leP->pool_id, __func__); - } -} - - -//----------------------------------------------------------------------------- -mem_block_t * -get_free_mem_block (uint16_t sizeP, __func__) -{ - //----------------------------------------------------------------------------- - mem_block_t *le = NULL; - int pool_selected; - int size; - - if (sizeP > MEM_MNGT_MB9_BLOCK_SIZE) { - msg ("[MEM_MNGT][ERROR][FATAL] size requested %d out of bounds %d\n",sizeP,MEM_MNGT_MB9_BLOCK_SIZE); - wcdma_handle_error (WCDMA_ERROR_OUT_OF_MEM_BLOCK); - return NULL; - } - - size = sizeP >> 6; - pool_selected = 0; - - while ((size)) { - pool_selected += 1; - size = size >> 1; - } - - // pool is selected according to the size requested, now get a block - // if no block is available pick one in an other pool - do { - if ((le = remove_head (&mem->mem_lists[pool_selected]))) { -#ifdef DEBUG_MEM_MNGT_ALLOC - counters[pool_selected] += 1; -#endif -#ifdef DEBUG_MEM_MNGT_ALLOC_SIZE - msg ("[MEM_MNGT][INFO] ALLOC MEM_BLOCK SIZE %d bytes pool %d\n", sizeP, pool_selected); -#endif - return le; - } - -#ifdef DEBUG_MEM_MNGT_ALLOC - msg ("[MEM_MNGT][ERROR][MINOR] memory pool %d is empty trying next pool alloc count = %d\n", pool_selected, counters[pool_selected]); - display_mem_load (); - check_mem_area (mem); -#endif - } while (pool_selected++ < 9); - - msg ("[MEM_MNGT][ERROR][FATAL] size %d requested out of bounds or memory pools empty\n", sizeP); - wcdma_handle_error (WCDMA_ERROR_OUT_OF_MEM_BLOCK); - return NULL; -}; - -//----------------------------------------------------------------------------- -mem_block_t * -get_free_copy_mem_block (void) -{ - //----------------------------------------------------------------------------- - mem_block_t *le; - - if ((le = remove_head (&mem->mem_lists[MEM_MNGT_POOL_ID_COPY]))) { - return le; - } else { - msg ("[MEM_MNGT][ERROR] POOL COPY IS EMPTY\n"); - display_mem_load (); -#ifdef DEBUG_MEM_MNGT_ALLOC - check_mem_area (mem); - break_point (); -#endif - wcdma_handle_error (WCDMA_ERROR_OUT_OF_MEM_BLOCK); - - return NULL; - } -} - -//----------------------------------------------------------------------------- -mem_block_t * -copy_mem_block (mem_block_t * leP, mem_block_t * destP) -{ - //----------------------------------------------------------------------------- - - if ((destP != NULL) && (leP != NULL) && (destP->pool_id == MEM_MNGT_POOL_ID_COPY)) { - destP->data = leP->data; - } else { - msg ("[MEM_MNGT][COPY] copy_mem_block() pool dest src or dest is NULL\n"); - } - - return destP; -} - -//----------------------------------------------------------------------------- -void -display_mem_load (void) -{ - //----------------------------------------------------------------------------- - - msg ("POOL 0 (%d elements of %d Bytes): \n", MEM_MNGT_MB0_NB_BLOCKS, MEM_MNGT_MB0_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID0]); - msg ("POOL 1 (%d elements of %d Bytes): \n", MEM_MNGT_MB1_NB_BLOCKS, MEM_MNGT_MB1_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID1]); - msg ("POOL 2 (%d elements of %d Bytes): \n", MEM_MNGT_MB2_NB_BLOCKS, MEM_MNGT_MB2_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID2]); - msg ("POOL 3 (%d elements of %d Bytes): \n", MEM_MNGT_MB3_NB_BLOCKS, MEM_MNGT_MB3_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID3]); - msg ("POOL 4 (%d elements of %d Bytes): \n", MEM_MNGT_MB4_NB_BLOCKS, MEM_MNGT_MB4_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID4]); - msg ("POOL 5 (%d elements of %d Bytes): \n", MEM_MNGT_MB5_NB_BLOCKS, MEM_MNGT_MB5_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID5]); - msg ("POOL 6 (%d elements of %d Bytes): \n", MEM_MNGT_MB6_NB_BLOCKS, MEM_MNGT_MB6_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID6]); - msg ("POOL 7 (%d elements of %d Bytes): \n", MEM_MNGT_MB7_NB_BLOCKS, MEM_MNGT_MB7_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID7]); - msg ("POOL 8 (%d elements of %d Bytes): \n", MEM_MNGT_MB8_NB_BLOCKS, MEM_MNGT_MB8_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID8]); - msg ("POOL 9 (%d elements of %d Bytes): \n", MEM_MNGT_MB9_NB_BLOCKS, MEM_MNGT_MB9_BLOCK_SIZE); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID9]); - msg ("POOL C (%d elements): \n", MEM_MNGT_MBCOPY_NB_BLOCKS); - display_list (&mem->mem_lists[MEM_MNGT_POOL_ID_COPY]); -} - -//----------------------------------------------------------------------------- -void -check_mem_area (void *arg) -{ - //----------------------------------------------------------------------------- - int index, mb_index; - mem_pool *memory = (mem_pool *) arg; - - for (index = 0; index < MEM_MNGT_MB0_NB_BLOCKS; index++) { - if ((memory->mem_blocks[index].data != &(memory->mem_pool0[index][0])) && (memory->mem_blocks[index].pool_id != MEM_MNGT_POOL_ID0)) { - msg ("[MEM] ERROR POOL0 block index %d\n", index); - break_point (); - } - } - - mb_index = MEM_MNGT_MB0_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB1_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool1[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID1)) { - msg ("[MEM] ERROR POOL1 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB1_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB2_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool2[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID2)) { - msg ("[MEM] ERROR POOL2 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB2_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB3_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool3[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID3)) { - msg ("[MEM] ERROR POOL3 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB3_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB4_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool4[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID4)) { - msg ("[MEM] ERROR POOL4 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB4_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB5_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool5[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID5)) { - msg ("[MEM] ERROR POOL5 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB5_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB6_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool6[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID6)) { - msg ("[MEM] ERROR POOL6 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB6_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB7_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool7[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID7)) { - msg ("[MEM] ERROR POOL7 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB7_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB8_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool8[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID8)) { - msg ("[MEM] ERROR POOL8 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB8_NB_BLOCKS; - - for (index = 0; index < MEM_MNGT_MB9_NB_BLOCKS; index++) { - if ((memory->mem_blocks[mb_index + index].data != &(memory->mem_pool9[index][0])) && (memory->mem_blocks[mb_index + index].pool_id != MEM_MNGT_POOL_ID9)) { - msg ("[MEM] ERROR POOL9 block index %d\n", index); - break_point (); - } - } - - mb_index += MEM_MNGT_MB9_NB_BLOCKS; - - for (index = mb_index; index < MEM_MNGT_NB_ELEMENTS; index++) { - if ((memory->mem_blocks[index].data != NULL) && (memory->mem_blocks[index].pool_id != MEM_MNGT_POOL_ID_COPY)) { - msg ("[MEM] ERROR POOL COPY block index %d\n", index); - break_point (); - } - } -} - -//----------------------------------------------------------------------------- -void -check_free_mem_block (mem_block_t * leP, __func__) -{ - //----------------------------------------------------------------------------- - int block_index; - - if ((leP >= &mem->mem_blocks[0]) && (leP <= &mem->mem_blocks[MEM_MNGT_NB_ELEMENTS])) { - block_index = ((uint32_t) leP - (uint32_t) (&mem->mem_blocks[0])) / sizeof (mem_block_t); - - if (block_index < MEM_MNGT_MB0_NB_BLOCKS) { - if (((uint32_t) (leP->data) != (uint32_t) (&(mem->mem_pool0[block_index][0]))) && (leP->pool_id != MEM_MNGT_POOL_ID0)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < (MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS)) { - if ((leP->data != &(mem->mem_pool1[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID1)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool2[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID2)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool3[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID3)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool4[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID4)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS + - MEM_MNGT_MB5_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool5[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID5)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < - MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS + MEM_MNGT_MB5_NB_BLOCKS + - MEM_MNGT_MB6_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool6[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID6)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < - MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS + MEM_MNGT_MB5_NB_BLOCKS + - MEM_MNGT_MB6_NB_BLOCKS + - MEM_MNGT_MB7_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool7[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID7)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < - MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS + MEM_MNGT_MB5_NB_BLOCKS + - MEM_MNGT_MB6_NB_BLOCKS + - MEM_MNGT_MB7_NB_BLOCKS + MEM_MNGT_MB8_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool8[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID8)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } else if (block_index < - MEM_MNGT_MB0_NB_BLOCKS + MEM_MNGT_MB1_NB_BLOCKS + MEM_MNGT_MB2_NB_BLOCKS + MEM_MNGT_MB3_NB_BLOCKS + MEM_MNGT_MB4_NB_BLOCKS + MEM_MNGT_MB5_NB_BLOCKS + - MEM_MNGT_MB6_NB_BLOCKS + - MEM_MNGT_MB7_NB_BLOCKS + MEM_MNGT_MB8_NB_BLOCKS + MEM_MNGT_MB9_NB_BLOCKS) { - if ((leP->data != &(mem->mem_pool9[block_index][0])) && (leP->pool_id != MEM_MNGT_POOL_ID9)) { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } - } - - } else { - msg ("[MEM][ERROR][FATAL] free mem block is corrupted\n"); - } -} - -//----------------------------------------------------------------------------- -void -break_point (void) -{ - //----------------------------------------------------------------------------- - int break_var; - - msg ("[BREAK_POINT]\n"); - break_var = 1; -} diff --git a/openair2/UTIL/MEM/mem_mngt_proto_extern.h b/openair2/UTIL/MEM/mem_mngt_proto_extern.h deleted file mode 100644 index 4690bba42e..0000000000 --- a/openair2/UTIL/MEM/mem_mngt_proto_extern.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - diff --git a/openair2/UTIL/MEM/mem_pool.h b/openair2/UTIL/MEM/mem_pool.h deleted file mode 100644 index cc0face78c..0000000000 --- a/openair2/UTIL/MEM/mem_pool.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*************************************************************************** - mem_pool.h - description - ------------------- - AUTHOR : Lionel GAUTHIER - COMPANY : EURECOM - EMAIL : Lionel.Gauthier@eurecom.fr - - - ***************************************************************************/ -#ifndef __MEM_POOL_H__ -# define __MEM_POOL_H__ - -# include "list.h" -# include "mem_block.h" - - -#endif diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 7a7e1a31f8..b85cdb507a 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -33,7 +33,7 @@ #include #define PORT 4043 //default TCP port for this simulator -#define CirSize 3072000 // 100ms is enough +#define CirSize 307200 // 100ms is enough #define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t)) #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b))) @@ -106,7 +106,7 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) { ptr->headerMode=true; ptr->transferPtr=(char *)&ptr->th; ptr->remainToTransfer=sizeof(samplesBlockHeader_t); - int sendbuff=1000*1000*10; + int sendbuff=1000*1000*100; AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, ""); struct epoll_event ev= {0}; ev.events = EPOLLIN | EPOLLRDHUP; @@ -183,7 +183,7 @@ void setblocking(int sock, enum blocking_t active) { AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, ""); } -static bool flushInput(rfsimulator_state_t *t, int timeout); +static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps); void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) { if (t->saveIQfile != -1) { @@ -207,7 +207,8 @@ void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) { if(errno==EAGAIN) { // The opposite side is saturated // we read incoming sockets meawhile waiting - flushInput(t, 5); + //flushInput(t, 5); + usleep(500); continue; } else return; @@ -316,17 +317,19 @@ sin_addr: return 0; } -int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { - rfsimulator_state_t *t = device->priv; +static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); for (int i=0; ibuf[i]; if (b->conn_sock >= 0 ) { - if ( abs((double)b->lastWroteTS-timestamp) > (double)CirSize) - LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS); + pthread_mutex_lock(&Sockmutex); + if ( b->lastWroteTS != 0 && abs((double)b->lastWroteTS-timestamp) > (double)CirSize) + LOG_E(HW,"Discontinuous TX gap too large Tx:%lu, %lu\n", b->lastWroteTS, timestamp); + + AssertFatal(b->lastWroteTS <= timestamp+1, " Not supported to send Tx out of order (same in USRP) %lu, %lu\n", b->lastWroteTS, timestamp); samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp}; fullwrite(b->conn_sock,&header, sizeof(header), t); sample_t tmpSamples[nsamps][nbAnt]; @@ -342,19 +345,23 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); b->lastWroteTS=timestamp+nsamps; } + + pthread_mutex_unlock(&Sockmutex); } } LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) ); - // Let's verify we don't have incoming data - // This is mandatory when the opposite side don't transmit - flushInput(t, 0); - pthread_mutex_unlock(&Sockmutex); return nsamps; } -static bool flushInput(rfsimulator_state_t *t, int timeout) { +int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { + return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags); +} + + + +static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) { // Process all incoming events on sockets // store the data in lists struct epoll_event events[FD_SETSIZE]= {0}; @@ -375,7 +382,29 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { AssertFatal( (conn_sock = accept(t->listen_sock,NULL,NULL)) != -1, ""); setblocking(conn_sock, notBlocking); allocCirBuf(t, conn_sock); - LOG_I(HW,"A ue connected\n"); + LOG_I(HW,"A ue connected, sending the current time\n"); + struct complex16 v= {0}; + void *samplesVoid[t->tx_num_channels]; + + for ( int i=0; i < t->tx_num_channels; i++) + samplesVoid[i]=(void *)&v; + + pthread_mutex_lock(&Sockmutex); + openair0_timestamp timestamp=1; + + for (int i=0; ibuf[i]; + + if (t->buf[i].circularBuf != NULL && t->buf[i].lastWroteTS > 1) { + timestamp=b->lastWroteTS; + break; + } + } + + pthread_mutex_unlock(&Sockmutex); + rfsimulator_write_internal(t, timestamp-1, + samplesVoid, 1, + t->tx_num_channels, 1); } else { if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) { socketError(t,fd); @@ -432,26 +461,34 @@ static bool flushInput(rfsimulator_state_t *t, int timeout) { } if ( abs(b->th.timestamp-b->lastReceivedTS) > 50 ) - LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS ); + LOG_W(HW,"UEsock: %d gap of: %ld in reception\n", fd, b->th.timestamp-b->lastReceivedTS ); } b->lastReceivedTS=b->th.timestamp; - AssertFatal(b->lastWroteTS == 0 || ( abs((double)b->lastWroteTS-b->lastReceivedTS) < (double)CirSize), - "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS); + pthread_mutex_lock(&Sockmutex); + + if (b->lastWroteTS != 0 && ( abs((double)b->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) + LOG_E(HW,"UEsock: %d Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, b->lastWroteTS, b->lastReceivedTS); + + pthread_mutex_unlock(&Sockmutex); b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); } if ( b->headerMode==false ) { - LOG_D(HW,"Set b->lastReceivedTS %ld\n", b->lastReceivedTS); + LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS); b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); // First block in UE, resync with the eNB current TS - if ( t->nextTimestamp == 0 ) - t->nextTimestamp=b->lastReceivedTS-b->th.size; + if ( t->nextTimestamp == 0 && b->th.size < b->lastReceivedTS) { + t->nextTimestamp=b->lastReceivedTS > nsamps_for_initial ? + b->lastReceivedTS - nsamps_for_initial : + 0; + LOG_W(HW,"UE got first timestamp: starting at %lu\n", t->nextTimestamp); + } if ( b->remainToTransfer==0) { - LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS); + LOG_D(HW,"UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS); b->headerMode=true; b->transferPtr=(char *)&b->th; b->remainToTransfer=sizeof(samplesBlockHeader_t); @@ -469,7 +506,6 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo LOG_W(HW, "rfsimulator: only 1 antenna tested\n"); } - pthread_mutex_lock(&Sockmutex); rfsimulator_state_t *t = device->priv; LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps); // deliver data from received data @@ -485,7 +521,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo if ( t->nextTimestamp == 0) LOG_W(HW,"No connected device, generating void samples...\n"); - if (!flushInput(t, 10)) { + if (!flushInput(t, 10, nsamps)) { for (int x=0; x < nbAnt; x++) memset(samplesVoid[x],0,sampleToByte(nsamps,1)); @@ -495,7 +531,6 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp); *ptimestamp = t->nextTimestamp-nsamps; - pthread_mutex_unlock(&Sockmutex); return nsamps; } } else { @@ -507,26 +542,6 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo for ( int sock=0; sockbuf[sock]; - if ( b->circularBuf) { - LOG_D(HW,"sock: %d, lastWroteTS: %lu, lastRecvTS: %lu, TS must be avail: %lu\n", - sock, b->lastWroteTS, - b->lastReceivedTS, - t->nextTimestamp+nsamps); - - if ( b->lastReceivedTS > b->lastWroteTS ) { - // The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance - // This occurs for example when UE is in sync mode: it doesn't transmit - // with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power - struct complex16 v= {0}; - void *samplesVoid[b->th.nbAnt]; - - for ( int i=0; i th.nbAnt; i++) - samplesVoid[i]=(void *)&v; - - rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0); - } - } - if ( b->circularBuf ) if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) { have_to_wait=true; @@ -539,7 +554,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo ptr->lastReceivedTS, t->nextTimestamp+nsamps); */ - flushInput(t, 3); + flushInput(t, 3, nsamps); } while (have_to_wait); } @@ -586,7 +601,6 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo nsamps, *ptimestamp, t->nextTimestamp, signal_energy(samplesVoid[0], nsamps)); - pthread_mutex_unlock(&Sockmutex); return nsamps; } int rfsimulator_request(openair0_device *device, void *msg, ssize_t msg_len) { diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index e31149b665..f0f1829cad 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -264,7 +264,7 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name eNB->UL_INFO.subframe = proc->subframe_rx; eNB->UL_INFO.module_id = eNB->Mod_id; eNB->UL_INFO.CC_id = eNB->CC_id; - eNB->if_inst->UL_indication(&eNB->UL_INFO); + eNB->if_inst->UL_indication(&eNB->UL_INFO, proc); AssertFatal((ret= pthread_mutex_unlock(&eNB->UL_INFO_mutex))==0,"error unlocking UL_INFO_mutex, return %d\n",ret); /* this conflict resolution may be totally wrong, to be tested */ @@ -762,7 +762,7 @@ static void *eNB_thread_prach( void *param ) { if (oai_exit) break; LOG_D(PHY,"Running eNB prach procedures\n"); - prach_procedures(eNB + prach_procedures(eNB, &eNB->proc.L1_proc #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) ,0 #endif @@ -796,7 +796,7 @@ static void *eNB_thread_prach_br( void *param ) { if (oai_exit) break; LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); - prach_procedures(eNB,1); + prach_procedures(eNB, &eNB->proc.L1_proc,1); if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; } @@ -810,11 +810,6 @@ static void *eNB_thread_prach_br( void *param ) { -extern void init_td_thread(PHY_VARS_eNB *); -extern void init_te_thread(PHY_VARS_eNB *); -extern void kill_td_thread(PHY_VARS_eNB *); -extern void kill_te_thread(PHY_VARS_eNB *); - static void *process_stats_thread(void *param) { PHY_VARS_eNB *eNB = (PHY_VARS_eNB *)param; wait_sync("process_stats_thread"); @@ -919,12 +914,12 @@ void init_eNB_proc(int inst) { // attr_td = &proc->attr_td; // attr_te = &proc->attr_te; #endif - +/* if(get_thread_worker_conf() == WORKER_ENABLE) { init_te_thread(eNB); init_td_thread(eNB); } - +*/ LOG_I(PHY,"eNB->single_thread_flag:%d\n", eNB->single_thread_flag); if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { @@ -990,12 +985,12 @@ void kill_eNB_proc(int inst) { proc = &eNB->proc; L1_proc = &proc->L1_proc; L1_proc_tx = &proc->L1_proc_tx; - +/* if(get_thread_worker_conf() == WORKER_ENABLE) { kill_td_thread(eNB); kill_te_thread(eNB); } - +*/ LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst ); if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 9310d55595..90af3c4eed 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -176,7 +176,7 @@ static inline void fh_if4p5_south_out(RU_t *ru) { void fh_if5_south_in(RU_t *ru,int *frame, int *subframe) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; RU_proc_t *proc = &ru->proc; - recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); + recv_IF5(ru, &ru->eNB_list[0]->proc.L1_proc, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; @@ -391,7 +391,7 @@ void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { RU_proc_t *proc = &ru->proc; int subframe_tx,frame_tx; openair0_timestamp timestamp_tx; - recv_IF5(ru, ×tamp_tx, *subframe, IF5_RRH_GW_DL); + recv_IF5(ru,&ru->eNB_list[0]->proc.L1_proc, ×tamp_tx, *subframe, IF5_RRH_GW_DL); // printf("Received subframe %d (TS %llu) from RCC\n",subframe_tx,timestamp_tx); subframe_tx = (timestamp_tx/fp->samples_per_tti)%10; frame_tx = (timestamp_tx/(fp->samples_per_tti*10))&1023; @@ -482,9 +482,9 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_NORTH_ASYNCH_IN,subframe_tx); } - if (ru->feptx_ofdm) ru->feptx_ofdm(ru); + if (ru->feptx_ofdm) ru->feptx_ofdm(ru, &ru->eNB_list[0]->proc.L1_proc ); - if (ru->fh_south_out) ru->fh_south_out(ru); + if (ru->fh_south_out) ru->fh_south_out(ru , &ru->eNB_list[0]->proc.L1_proc); } void fh_if5_north_out(RU_t *ru) { @@ -931,12 +931,14 @@ void *ru_thread_prach( void *param ) { if (ru->eNB_list[0]) { prach_procedures( ru->eNB_list[0] + , &ru->eNB_list[0]->proc.L1_proc #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) ,0 #endif ); } else { rx_prach(NULL, + &ru->eNB_list[0]->proc.L1_proc, ru, NULL, NULL, @@ -976,6 +978,7 @@ void *ru_thread_prach_br( void *param ) { if (oai_exit) break; rx_prach(NULL, + &ru->eNB_list[0]->proc.L1_proc, ru, NULL, NULL, @@ -1176,7 +1179,7 @@ void wakeup_L1s(RU_t *ru) { if (ru->wait_cnt == 0) { if (ru->num_eNB==1 && ru->eNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) - ru->eNB_top(eNB_list[0],proc->frame_rx,proc->subframe_rx,string,ru); + ru->eNB_top(eNB_list[0],&proc->L1_proc, proc->frame_rx,proc->subframe_rx,string,ru); else { for (i=0; inum_eNB; i++) { eNB_list[i]->proc.ru_proc = &ru->proc; @@ -1493,14 +1496,14 @@ void *ru_thread_tx( void *param ) { if (oai_exit) break; // do TX front-end processing if needed (precoding and/or IDFTs) - if (ru->feptx_prec) ru->feptx_prec(ru); + if (ru->feptx_prec) ru->feptx_prec(ru, L1_proc); // do OFDM if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru, L1_proc); if(!(get_softmodem_params()->emulate_rf)) { // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru, L1_proc); } LOG_D(PHY,"ru_thread_tx: releasing RU TX in %d.%d\n",proc->frame_tx,proc->subframe_tx); @@ -1765,7 +1768,7 @@ void *ru_thread( void *param ) { wakeup_slaves(proc); // do RX front-end processing (frequency-shift, dft) if needed - if (ru->feprx) ru->feprx(ru); + if (ru->feprx) ru->feprx(ru, &ru->eNB_list[0]->proc.L1_proc); // wakeup all eNB processes waiting for this RU AssertFatal((ret=pthread_mutex_lock(&proc->mutex_eNBs))==0,"mutex_lock returns %d\n",ret); @@ -1801,14 +1804,14 @@ void *ru_thread( void *param ) { if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0) { // do TX front-end processing if needed (precoding and/or IDFTs) - if (ru->feptx_prec) ru->feptx_prec(ru); + if (ru->feptx_prec) ru->feptx_prec(ru, &ru->eNB_list[0]->proc.L1_proc); // do OFDM if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru, &ru->eNB_list[0]->proc.L1_proc); if(!(get_softmodem_params()->emulate_rf)) { // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru, &ru->eNB_list[0]->proc.L1_proc); if ((ru->fh_north_out) && (ru->state!=RU_CHECK_SYNC)) ru->fh_north_out(ru); } @@ -2240,12 +2243,12 @@ void init_RU_proc(RU_t *ru) { exit(-1); } } - +/* if (get_thread_worker_conf() == WORKER_ENABLE) { init_fep_thread(ru,NULL); init_feptx_thread(ru,NULL); } - +*/ if (opp_enabled == 1) pthread_create(&ru->ru_stats_thread,NULL,ru_stats_thread,(void *)ru); if (ru->function == eNodeB_3GPP) { @@ -2286,14 +2289,14 @@ void kill_RU_proc(RU_t *ru) { pthread_mutex_destroy( &proc->mutex_rf_tx); pthread_cond_destroy( &proc->cond_rf_tx); #endif - +/* if (get_thread_worker_conf() == WORKER_ENABLE) { LOG_D(PHY, "killing FEP thread\n"); kill_fep_thread(ru); LOG_D(PHY, "killing FEP TX thread\n"); kill_feptx_thread(ru); } - +*/ AssertFatal((ret=pthread_mutex_lock(&proc->mutex_FH))==0,"mutex_lock returns %d\n",ret); proc->instance_cnt_FH = 0; pthread_cond_signal(&proc->cond_FH); @@ -2453,8 +2456,8 @@ void set_function_spec_param(RU_t *ru) { ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception ru->fh_south_out = tx_rf; // send output to RF ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously - ru->feprx = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full :ru_fep_full_2thread; // RX DFTs - ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) + ru->feprx = fep_full; // RX DFTs + ru->feptx_ofdm = feptx_ofdm; // this is fep with idft only (no precoding in RRU) ru->feptx_prec = NULL; ru->start_if = start_if; // need to start the if interface for if4p5 ru->ifdevice.host_type = RRU_HOST; @@ -2475,8 +2478,8 @@ void set_function_spec_param(RU_t *ru) { malloc_IF4p5_buffer(ru); } else if (ru->function == eNodeB_3GPP) { ru->do_prach = 0; // no prach processing in RU - ru->feprx = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full : ru_fep_full_2thread; // RX DFTs - ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft and precoding + ru->feprx = fep_full; // RX DFTs + ru->feptx_ofdm = feptx_ofdm; // this is fep with idft and precoding ru->feptx_prec = feptx_prec; // this is fep with idft and precoding ru->fh_north_in = NULL; // no incoming fronthaul from north ru->fh_north_out = NULL; // no outgoing fronthaul to north @@ -2505,9 +2508,9 @@ void set_function_spec_param(RU_t *ru) { case REMOTE_IF5: // the remote unit is IF5 RRU ru->do_prach = 0; - ru->feprx = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full : fep_full; // this is frequency-shift + DFTs + ru->feprx = fep_full; // this is frequency-shift + DFTs ru->feptx_prec = feptx_prec; // need to do transmit Precoding + IDFTs - ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread; // need to do transmit Precoding + IDFTs + ru->feptx_ofdm = feptx_ofdm ; // need to do transmit Precoding + IDFTs if (ru->if_timing == synch_to_other) { ru->fh_south_in = fh_slave_south_in; // synchronize to master diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 6c4087d08f..23fc5e3aba 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1492,6 +1492,23 @@ static void *UE_phy_stub_thread_rxn_txnp4(void *arg) { * \param arg unused * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ +void write_dummy(PHY_VARS_UE *UE, openair0_timestamp timestamp) { + // we have to write to tell explicitly to the eNB, else it will wait for us forever + // we write the next subframe (always write in future of what we received) + // + struct complex16 v= {0}; + void *samplesVoid[UE->frame_parms.nb_antennas_tx]; + + for ( int i=0; i < UE->frame_parms.nb_antennas_tx; i++) + samplesVoid[i]=(void *)&v; + + AssertFatal( 1 == UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp+2*UE->frame_parms.samples_per_tti, + samplesVoid, + 1, + UE->frame_parms.nb_antennas_tx, + 1),""); +} void *UE_thread(void *arg) { PHY_VARS_UE *UE = (PHY_VARS_UE *) arg; @@ -1542,21 +1559,25 @@ void *UE_thread(void *arg) { int instance_cnt_synch = UE->proc.instance_cnt_synch; int is_synchronized = UE->is_synchronized; AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); - + if (is_synchronized == 0) { if (instance_cnt_synch < 0) { // we can invoke the synch // grab 10 ms of signal and wakeup synch thread - for (int i=0; iframe_parms.nb_antennas_rx; i++) - rxp[i] = (void *)&UE->common_vars.rxdata[i][0]; - if (UE->mode != loop_through_memory) - AssertFatal( UE->frame_parms.samples_per_tti*10 == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - rxp, - UE->frame_parms.samples_per_tti*10, - UE->frame_parms.nb_antennas_rx), ""); - + for(int sf=0; sf<10; sf++) { + for (int i=0; iframe_parms.nb_antennas_rx; i++) + rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.samples_per_tti*sf]; + + AssertFatal( UE->frame_parms.samples_per_tti == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_tti, + UE->frame_parms.nb_antennas_rx), ""); + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + } + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); instance_cnt_synch = ++UE->proc.instance_cnt_synch; @@ -1579,13 +1600,16 @@ void *UE_thread(void *arg) { for (int i=0; iframe_parms.nb_antennas_rx; i++) rxp[i] = (void *)&dummy_rx[i][0]; - for (int sf=0; sf<10; sf++) + for (int sf=0; sf<10; sf++) { // printf("Reading dummy sf %d\n",sf); UE->rfdevice.trx_read_func(&UE->rfdevice, ×tamp, rxp, UE->frame_parms.samples_per_tti, UE->frame_parms.nb_antennas_rx); + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + } } #endif @@ -1598,12 +1622,18 @@ void *UE_thread(void *arg) { if (UE->mode != loop_through_memory) { if (UE->no_timing_correction==0) { LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); - AssertFatal(UE->rx_offset == - UE->rfdevice.trx_read_func(&UE->rfdevice, - ×tamp, - (void **)UE->common_vars.rxdata, - UE->rx_offset, - UE->frame_parms.nb_antennas_rx),""); + while ( UE->rx_offset ) { + size_t s=min(UE->rx_offset,UE->frame_parms.samples_per_tti); + AssertFatal(s == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + (void **)UE->common_vars.rxdata, + s, + UE->frame_parms.nb_antennas_rx),""); + if (IS_SOFTMODEM_RFSIM ) + write_dummy(UE, timestamp); + UE->rx_offset-=s; + } } UE->rx_offset=0; @@ -1644,7 +1674,7 @@ void *UE_thread(void *arg) { pthread_mutex_unlock(&proc->mutex_rxtx); } - usleep(3000); + usleep(300); } LOG_D(PHY,"Process Subframe %d thread Idx %d \n", sub_frame, UE->current_thread_id[sub_frame]); diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 9995b43f90..88b9b13233 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -597,6 +597,11 @@ void init_pdcp(void) { pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind); } +// Stupid function addition because UE itti messages queues definition is common with eNB +void *rrc_enb_process_itti_msg(void *notUsed) { + return NULL; +} + int main( int argc, char **argv ) { int CC_id; uint8_t abstraction_flag=0; @@ -657,6 +662,7 @@ int main( int argc, char **argv ) { pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); printf("ITTI init\n"); +#define UE itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); // initialize mscgen log after ITTI From beda33b8f1a5f6c0f08c8fcdd04662b7d652ff9b Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Mon, 11 Nov 2019 20:15:27 +0100 Subject: [PATCH 061/175] CI: fix UL iperf in distributed env Signed-off-by: Raphael Defosseux --- ci-scripts/Jenkinsfile-inria-r2lab | 4 - ci-scripts/main.py | 99 ++++++++++++++++--- .../enb_ue_usrp210_band7_test_05mhz_tm1.xml | 2 +- .../enb_usrp210_band7_test_05mhz_tm1.xml | 86 ++++++++-------- 4 files changed, 129 insertions(+), 62 deletions(-) diff --git a/ci-scripts/Jenkinsfile-inria-r2lab b/ci-scripts/Jenkinsfile-inria-r2lab index 6ae7522999..778c571645 100644 --- a/ci-scripts/Jenkinsfile-inria-r2lab +++ b/ci-scripts/Jenkinsfile-inria-r2lab @@ -183,7 +183,6 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:m11 172.16.1.102 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:m10 192.168.10.110 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:sxu 172.55.55.102 up\"'" - sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:s1u 192.168.248.159 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:sxc 172.55.55.101 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:s5c 172.58.58.102 up\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ifconfig control:p5c 172.58.58.101 up\"'" @@ -195,9 +194,6 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ip rule add from 12.0.0.0/8 table lte\"'" sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labEPC0} \"echo ${fitpasswd} | sudo -S ip rule add from 12.1.1.0/8 table lte\"'" - // Adding a route on the eNB for the S1U interface - sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labENB0} \"echo ${fitpasswd} | sudo -S ip route add 192.168.248.0/24 via ${r2labEPC0IpAddr} dev control\"'" - // For the moment, simple way to route traffic from python executor to any UEs sh "ssh -t inria_oaici@faraday.inria.fr 'ssh -t -b 192.168.3.100 ${fituser}@${r2labPythonExe} \"echo ${fitpasswd} | sudo -S ip route add 12.1.1.0/24 via ${r2labEPC0IpAddr} dev control\"'" } diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 0909b42747..a60a31c04a 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -1856,11 +1856,27 @@ class SSHConnection(): def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) + # Launch ping on the EPC side (true for ltebox and old open-air-cn) + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False ping_time = re.findall("-c (\d+)",str(self.ping_args)) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + else: + cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + ping_status = ret.returncode + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' @@ -2170,7 +2186,7 @@ class SSHConnection(): req_bandwidth = '%.1f Gbits/sec' % req_bw req_bw = req_bw * 1000000000 - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) (\((?P[0-9\.]+)%\))', str(self.ssh.before)) + result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) if result is not None: bitrate = result.group('bitrate') packetloss = result.group('packetloss') @@ -2218,6 +2234,8 @@ class SSHConnection(): statusQueue.put(msg) lock.release() return 0 + else: + return -2 def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): @@ -2387,11 +2405,17 @@ class SSHConnection(): self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) self.close() else: - if udpIperf: - cmd = 'nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' else: - cmd = 'nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - logging.debug(cmd + '\n') + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + if udpIperf: + cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + else: + cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + logging.debug(cmd) subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') time.sleep(0.5) @@ -2416,7 +2440,12 @@ class SSHConnection(): if (device_id == 'OAI-UE'): iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: - iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + if self.ADBCentralized: + iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT Case if iperf_status < 0: self.close() @@ -2435,12 +2464,12 @@ class SSHConnection(): self.close() else: cmd = 'killall --signal SIGKILL iperf' - logging.debug(cmd + '\n') + logging.debug(cmd) subprocess.run(cmd, shell=True) time.sleep(1) self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') # in case of failure, retrieve server log - if (clientStatus == -1): + if (clientStatus == -1) or (clientStatus == -2): if launchFromEpc: time.sleep(1) if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): @@ -2459,6 +2488,8 @@ class SSHConnection(): return useIperf3 = False udpIperf = True + + self.ueIperfVersion = '2.0.5' if (device_id != 'OAI-UE'): self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it @@ -2478,9 +2509,30 @@ class SSHConnection(): self.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return + else: + if self.ADBCentralized: + self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' else: useIperf3 = True self.close() + else: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('iperf --version', '\$', 5) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' + self.close() # in case of iperf, UL has its own function if (not useIperf3): result = re.search('-R', str(self.iperf_args)) @@ -2515,7 +2567,7 @@ class SSHConnection(): self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) else: self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &\' > /dev/null 2>&1', self.ADBUserName, 60) + self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) time.sleep(0.5) self.close() @@ -2551,7 +2603,13 @@ class SSHConnection(): if launchFromEpc: iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: - cmd = 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' message = cmd + '\n' logging.debug(cmd) ret = subprocess.run(cmd, shell=True) @@ -2596,6 +2654,7 @@ class SSHConnection(): self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') else: self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI UE: @@ -2730,6 +2789,18 @@ class SSHConnection(): self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return + + self.dummyIperfVersion = '2.0.10' + #cmd = 'iperf --version' + #logging.debug(cmd + '\n') + #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) + #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.5' + #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.10' + multi_jobs = [] i = 0 ue_num = len(self.UEIPAddresses) diff --git a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml index 1471b9a016..0196bf1ab6 100644 --- a/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_ue_usrp210_band7_test_05mhz_tm1.xml @@ -68,7 +68,7 @@ Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml index 6bc52568c3..964550d872 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_test_05mhz_tm1.xml @@ -24,11 +24,11 @@ test-05-tm1 Test-05MHz-TM1 tasks - 4 + 1 - 030201 040101 + 040101 030201 030103 000002 - 040301 000002 040504 000001 040401 + 040301 000002 040504 040605 040606 040645 040646 040401 040301 000002 040505 000001 040401 040301 000002 040506 000001 040401 040301 000002 040507 000001 040401 @@ -114,252 +114,252 @@ Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 Ping ping (5MHz - 20 sec) - -I 192.168.248.159 -c 20 + -c 20 5 @@ -372,8 +372,8 @@ Iperf - iperf (5MHz - DL/12Mbps/UDP)(30 sec) - -u -b 12M -t 30 -i 1 -fm + iperf (5MHz - DL/15Mbps/UDP)(30 sec) + -u -b 15M -t 30 -i 1 -fm 50 @@ -386,8 +386,8 @@ Iperf - iperf (5MHz - UL/2Mbps/UDP)(30 sec) - -u -b 2M -t 30 -i 1 -fm -R + iperf (5MHz - UL/3.8Mbps/UDP)(30 sec) + -u -b 3.8M -t 30 -i 1 -fm -R 50 From 08ea6180670b359ae96feb6a9a58fb86136710bc Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 19 Nov 2019 13:27:28 +0100 Subject: [PATCH 062/175] fix important bug in CU, merge thread pool improvement and rf simulator improvements made initialy in 5G branch --- common/utils/threadPool/thread-pool.c | 30 ++---- common/utils/threadPool/thread-pool.h | 75 ++++++++------ executables/main-fs6.c | 17 ++- executables/main-ocp.c | 2 +- targets/ARCH/rfsimulator/simulator.c | 142 ++++++++++++++++---------- 5 files changed, 156 insertions(+), 110 deletions(-) diff --git a/common/utils/threadPool/thread-pool.c b/common/utils/threadPool/thread-pool.c index 1b7aa960ba..dd3d16d717 100644 --- a/common/utils/threadPool/thread-pool.c +++ b/common/utils/threadPool/thread-pool.c @@ -49,23 +49,6 @@ void *one_thread(void *arg) { struct one_thread *myThread=(struct one_thread *) arg; struct thread_pool *tp=myThread->pool; - // configure the thread core assignment - // TBD: reserve the core for us exclusively - if ( myThread->coreID >= 0 && myThread->coreID < get_nprocs_conf()) { - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(myThread->coreID, &cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - } - - //Configure the thread scheduler policy for Linux - struct sched_param sparam= {0}; - sparam.sched_priority = sched_get_priority_max(SCHED_RR); - pthread_setschedparam(pthread_self(), SCHED_RR, &sparam); - // set the thread name for debugging - sprintf(myThread->name,"Tpool_%d",myThread->coreID); - pthread_setname_np(pthread_self(), myThread->name ); - // Infinite loop to process requests do { notifiedFIFO_elt_t *elt=pullNotifiedFifoRemember(&tp->incomingFifo, myThread); @@ -106,10 +89,6 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { } else pool->traceFd=-1; - //Configure the thread scheduler policy for Linux - struct sched_param sparam= {0}; - sparam.sched_priority = sched_get_priority_max(SCHED_RR)-1; - pthread_setschedparam(pthread_self(), SCHED_RR, &sparam); pool->activated=true; initNotifiedFIFO(&pool->incomingFifo); char *saveptr, * curptr; @@ -137,7 +116,11 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { pool->allthreads->coreID=atoi(curptr); pool->allthreads->id=pool->nbThreads; pool->allthreads->pool=pool; - pthread_create(&pool->allthreads->threadID, NULL, one_thread, (void *)pool->allthreads); + //Configure the thread scheduler policy for Linux + // set the thread name for debugging + sprintf(pool->allthreads->name,"Tpool_%d",pool->allthreads->coreID); + threadCreate(&pool->allthreads->threadID, one_thread, (void *)pool->allthreads, + pool->allthreads->name, pool->allthreads->coreID, OAI_PRIORITY_RT); pool->nbThreads++; } @@ -152,6 +135,9 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { #ifdef TEST_THREAD_POOL +void exit_function(const char *file, const char *function, const int line, const char *s) { +} + struct testData { int id; char txt[30]; diff --git a/common/utils/threadPool/thread-pool.h b/common/utils/threadPool/thread-pool.h index d68918a163..d358db5f00 100644 --- a/common/utils/threadPool/thread-pool.h +++ b/common/utils/threadPool/thread-pool.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef DEBUG #define THREADINIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP @@ -77,41 +78,60 @@ static inline void delNotifiedFIFO_elt(notifiedFIFO_elt_t *elt) { //LOG_W(UTIL,"delNotifiedFIFO on something not allocated by newNotifiedFIFO\n"); } +static inline void initNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) { + nf->inF=NULL; + nf->outF=NULL; +} static inline void initNotifiedFIFO(notifiedFIFO_t *nf) { mutexinit(nf->lockF); condinit (nf->notifF); - nf->inF=NULL; - nf->outF=NULL; + initNotifiedFIFO_nothreadSafe(nf); // No delete function: the creator has only to free the memory } -static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) { - mutexlock(nf->lockF); +static inline void pushNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) { msg->next=NULL; if (nf->outF == NULL) nf->outF = msg; - if (nf->inF) + if (nf->inF != NULL) nf->inF->next = msg; nf->inF = msg; +} + +static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) { + mutexlock(nf->lockF); + pushNotifiedFIFO_nothreadSafe(nf,msg); condbroadcast(nf->notifF); mutexunlock(nf->lockF); } -static inline notifiedFIFO_elt_t *pullNotifiedFIFO(notifiedFIFO_t *nf) { - mutexlock(nf->lockF); - - while(!nf->outF) - condwait(nf->notifF, nf->lockF); +static inline notifiedFIFO_elt_t *pullNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) { + if (nf->outF == NULL) + return NULL; notifiedFIFO_elt_t *ret=nf->outF; + + if (nf->outF==nf->outF->next) + LOG_E(TMR,"Circular list in thread pool: push several times the same buffer is forbidden\n"); + nf->outF=nf->outF->next; if (nf->outF==NULL) nf->inF=NULL; + return ret; +} + +static inline notifiedFIFO_elt_t *pullNotifiedFIFO(notifiedFIFO_t *nf) { + mutexlock(nf->lockF); + notifiedFIFO_elt_t *ret; + + while((ret=pullNotifiedFIFO_nothreadSafe(nf)) == NULL) + condwait(nf->notifF, nf->lockF); + mutexunlock(nf->lockF); return ret; } @@ -122,14 +142,7 @@ static inline notifiedFIFO_elt_t *pollNotifiedFIFO(notifiedFIFO_t *nf) { if (tmp != 0 ) return NULL; - notifiedFIFO_elt_t *ret=nf->outF; - - if (ret!=NULL) - nf->outF=nf->outF->next; - - if (nf->outF==NULL) - nf->inF=NULL; - + notifiedFIFO_elt_t *ret=pullNotifiedFIFO_nothreadSafe(nf); mutexunlock(nf->lockF); return ret; } @@ -151,6 +164,7 @@ static inline int abortNotifiedFIFO(notifiedFIFO_t *nf, uint64_t key) { } else start=&(*start)->next; } + if (nf->outF == NULL) nf->inF=NULL; @@ -184,16 +198,20 @@ typedef struct thread_pool { static inline void pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg) { if (t->measurePerf) msg->creationTime=rdtsc(); + if ( t->activated) pushNotifiedFIFO(&t->incomingFifo, msg); else { - if (t->measurePerf) - msg->startProcessingTime=rdtsc(); - msg->processingFunc(NotifiedFifoData(msg)); - if (t->measurePerf) - msg->endProcessingTime=rdtsc(); - if (msg->reponseFifo) - pushNotifiedFIFO(msg->reponseFifo, msg); + if (t->measurePerf) + msg->startProcessingTime=rdtsc(); + + msg->processingFunc(NotifiedFifoData(msg)); + + if (t->measurePerf) + msg->endProcessingTime=rdtsc(); + + if (msg->reponseFifo) + pushNotifiedFIFO(msg->reponseFifo, msg); } } @@ -202,10 +220,8 @@ static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_ if (t->measurePerf) msg->returnTime=rdtsc(); - - if (t->traceFd) + if (t->traceFd >= 0) if(write(t->traceFd, msg, sizeof(*msg))); - return msg; } @@ -217,10 +233,8 @@ static inline notifiedFIFO_elt_t *tryPullTpool(notifiedFIFO_t *responseFifo, tpo if (t->measurePerf) msg->returnTime=rdtsc(); - if (t->traceFd) if(write(t->traceFd, msg, sizeof(*msg))); - return msg; } @@ -239,6 +253,7 @@ static inline int abortTpool(tpool_t *t, uint64_t key) { } else start=&(*start)->next; } + if (t->incomingFifo.outF==NULL) t->incomingFifo.inF=NULL; diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 471ad0f1eb..638db0ac11 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1324,6 +1324,9 @@ void *DL_du_fs6(void *arg) { feptx_prec(ru, &L1_proc); feptx_ofdm(ru, &L1_proc); tx_rf(ru, &L1_proc); + + if ( IS_SOFTMODEM_RFSIM ) + return NULL; } return NULL; @@ -1443,13 +1446,22 @@ void *cu_fs6(void *arg) { remoteIP=DU_IP; AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, DU_PORT, &sockFS6), ""); + + L1_rxtx_proc_t L1proc= {0}; + if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) + initTpool(get_softmodem_params()->threadPoolConfig, &L1proc.threadPool, true); + else + initTpool("n", &L1proc.threadPool, true); + + initNotifiedFIFO(&L1proc.respEncode); + initNotifiedFIFO(&L1proc.respDecode); + uint64_t timeStamp=0; initStaticTime(begingWait); initStaticTime(begingWait2); initRefTimes(waitDUAndProcessingUL); initRefTimes(makeSendDL); initRefTimes(fullLoop); - L1_rxtx_proc_t L1proc= {0}; while(1) { timeStamp+=ru->frame_parms.samples_per_tti; @@ -1496,6 +1508,7 @@ void *du_fs6(void *arg) { initRefTimes(waitRxAndProcessingUL); initRefTimes(fullLoop); pthread_t t; + if ( !IS_SOFTMODEM_RFSIM ) threadCreate(&t, DL_du_fs6, (void *)ru, "MainDuTx", -1, OAI_PRIORITY_RT_MAX); while(1) { @@ -1503,6 +1516,8 @@ void *du_fs6(void *arg) { updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); UL_du_fs6(ru, &L1proc); + if ( IS_SOFTMODEM_RFSIM ) + DL_du_fs6((void *)ru); updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); } diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 8810115197..819eab0ee6 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -688,7 +688,7 @@ static void *ru_thread( void *param ) { setbuf(stdout, NULL); setbuf(stderr, NULL); RU_t *ru = (RU_t *)param; - L1_rxtx_proc_t L1proc; + L1_rxtx_proc_t L1proc={0}; L1_rxtx_proc_t *proc=&L1proc; if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index b85cdb507a..95eeb38aa0 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -70,8 +70,8 @@ typedef struct complex16 sample_t; // 2*16 bits complex number typedef struct buffer_s { int conn_sock; openair0_timestamp lastReceivedTS; - openair0_timestamp lastWroteTS; bool headerMode; + bool trashingPacket; samplesBlockHeader_t th; char *transferPtr; uint64_t remainToTransfer; @@ -83,6 +83,7 @@ typedef struct buffer_s { typedef struct { int listen_sock, epollfd; openair0_timestamp nextTimestamp; + openair0_timestamp lastWroteTS; uint64_t typeStamp; char *ip; uint16_t port; @@ -102,8 +103,8 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) { ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; ptr->lastReceivedTS=0; - ptr->lastWroteTS=0; ptr->headerMode=true; + ptr->trashingPacket=false; ptr->transferPtr=(char *)&ptr->th; ptr->remainToTransfer=sizeof(samplesBlockHeader_t); int sendbuff=1000*1000*100; @@ -219,8 +220,6 @@ void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) { } } - - void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) { char *saveF=NULL; char *modelname=NULL; @@ -317,19 +316,16 @@ sin_addr: return 0; } -static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { +static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags, bool alreadyLocked) { + if (!alreadyLocked) + pthread_mutex_lock(&Sockmutex); + LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); for (int i=0; ibuf[i]; if (b->conn_sock >= 0 ) { - pthread_mutex_lock(&Sockmutex); - - if ( b->lastWroteTS != 0 && abs((double)b->lastWroteTS-timestamp) > (double)CirSize) - LOG_E(HW,"Discontinuous TX gap too large Tx:%lu, %lu\n", b->lastWroteTS, timestamp); - - AssertFatal(b->lastWroteTS <= timestamp+1, " Not supported to send Tx out of order (same in USRP) %lu, %lu\n", b->lastWroteTS, timestamp); samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp}; fullwrite(b->conn_sock,&header, sizeof(header), t); sample_t tmpSamples[nsamps][nbAnt]; @@ -343,24 +339,29 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp if (b->conn_sock >= 0 ) { fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); - b->lastWroteTS=timestamp+nsamps; } - - pthread_mutex_unlock(&Sockmutex); } } + if ( t->lastWroteTS != 0 && abs((double)t->lastWroteTS-timestamp) > (double)CirSize) + LOG_E(HW,"Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); + + AssertFatal(t->lastWroteTS <= timestamp+1, " Not supported to send Tx out of order (same in USRP) %lu, %lu\n", + t->lastWroteTS, timestamp); + t->lastWroteTS=timestamp+nsamps; + + if (!alreadyLocked) + pthread_mutex_unlock(&Sockmutex); + LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) ); return nsamps; } int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { - return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags); + return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, false); } - - static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) { // Process all incoming events on sockets // store the data in lists @@ -389,22 +390,9 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi for ( int i=0; i < t->tx_num_channels; i++) samplesVoid[i]=(void *)&v; - pthread_mutex_lock(&Sockmutex); - openair0_timestamp timestamp=1; - - for (int i=0; ibuf[i]; - - if (t->buf[i].circularBuf != NULL && t->buf[i].lastWroteTS > 1) { - timestamp=b->lastWroteTS; - break; - } - } - - pthread_mutex_unlock(&Sockmutex); - rfsimulator_write_internal(t, timestamp-1, + rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS-1 : 0, samplesVoid, 1, - t->tx_num_channels, 1); + t->tx_num_channels, 1, false); } else { if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) { socketError(t,fd); @@ -450,25 +438,41 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol"); b->headerMode=false; - if ( b->lastReceivedTS != b->th.timestamp) { + if ( t->nextTimestamp == 0 ) { // First block in UE, resync with the eNB current TS + t->nextTimestamp=b->th.timestamp> nsamps_for_initial ? + b->th.timestamp - nsamps_for_initial : + 0; + b->lastReceivedTS=b->th.timestamp> nsamps_for_initial ? + b->th.timestamp : + nsamps_for_initial; + LOG_W(HW,"UE got first timestamp: starting at %lu\n", t->nextTimestamp); + b->trashingPacket=true; + } else if ( b->lastReceivedTS < b->th.timestamp) { int nbAnt= b->th.nbAnt; - + for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) { for (int a=0; a < nbAnt; a++) { b->circularBuf[(index*nbAnt+a)%CirSize].r=0; b->circularBuf[(index*nbAnt+a)%CirSize].i=0; } } - - if ( abs(b->th.timestamp-b->lastReceivedTS) > 50 ) + if (b->lastReceivedTS != 0 && b->th.timestamp-b->lastReceivedTS > 50 ) LOG_W(HW,"UEsock: %d gap of: %ld in reception\n", fd, b->th.timestamp-b->lastReceivedTS ); - } + b->lastReceivedTS=b->th.timestamp; + + } else if ( b->lastReceivedTS > b->th.timestamp && b->th.size == 1 ) { + LOG_W(HW,"Received Rx/Tx synchro out of order\n"); + b->trashingPacket=true; + } else if ( b->lastReceivedTS == b->th.timestamp ) { + // normal case + } else { + abort(); + AssertFatal(false, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); } - b->lastReceivedTS=b->th.timestamp; pthread_mutex_lock(&Sockmutex); - if (b->lastWroteTS != 0 && ( abs((double)b->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) - LOG_E(HW,"UEsock: %d Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, b->lastWroteTS, b->lastReceivedTS); + if (t->lastWroteTS != 0 && ( abs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) + LOG_E(HW,"UEsock: %d Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS); pthread_mutex_unlock(&Sockmutex); b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; @@ -477,22 +481,17 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi if ( b->headerMode==false ) { LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS); - b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); + if ( ! b->trashingPacket ) { + b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); + } - // First block in UE, resync with the eNB current TS - if ( t->nextTimestamp == 0 && b->th.size < b->lastReceivedTS) { - t->nextTimestamp=b->lastReceivedTS > nsamps_for_initial ? - b->lastReceivedTS - nsamps_for_initial : - 0; - LOG_W(HW,"UE got first timestamp: starting at %lu\n", t->nextTimestamp); - } - - if ( b->remainToTransfer==0) { - LOG_D(HW,"UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS); - b->headerMode=true; - b->transferPtr=(char *)&b->th; - b->remainToTransfer=sizeof(samplesBlockHeader_t); - b->th.magic=-1; + if ( b->remainToTransfer==0) { + LOG_D(HW,"UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS); + b->headerMode=true; + b->transferPtr=(char *)&b->th; + b->remainToTransfer=sizeof(samplesBlockHeader_t); + b->th.magic=-1; + b->trashingPacket=false; } } } @@ -528,12 +527,43 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo t->nextTimestamp+=nsamps; if ( ((t->nextTimestamp/nsamps)%100) == 0) - LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp); + LOG_W(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextTimestamp); *ptimestamp = t->nextTimestamp-nsamps; return nsamps; } } else { + pthread_mutex_lock(&Sockmutex); + + if ( t->nextTimestamp > 0 && t->lastWroteTS < t->nextTimestamp) { + pthread_mutex_unlock(&Sockmutex); + usleep(10000); + pthread_mutex_lock(&Sockmutex); + if ( t->lastWroteTS < t->nextTimestamp ) { + // Assuming Tx is not done fully in another thread + // We can never write is the past from the received time + // So, the node perform receive but will never write these symbols + // let's tell this to the opposite node + // We send timestamp for nb samples required + // assuming this should have been done earlier if a Tx would exist + pthread_mutex_unlock(&Sockmutex); + struct complex16 v= {0}; + void *samplesVoid[t->tx_num_channels]; + + for ( int i=0; i < t->tx_num_channels; i++) + samplesVoid[i]=(void *)&v; + LOG_I(HW, "No samples Tx occured, so we send 1 sample to notify it: Tx:%lu, Rx:%lu\n", + t->lastWroteTS, t->nextTimestamp); + rfsimulator_write_internal(t, t->nextTimestamp, + samplesVoid, 1, + t->tx_num_channels, 1, true); + } else { + pthread_mutex_unlock(&Sockmutex); + LOG_W(HW, "trx_write came from another thread\n"); + } + } else + pthread_mutex_unlock(&Sockmutex); + bool have_to_wait; do { From f7a9226438296f2acadb074a0be89feb4a4850c5 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 29 Nov 2019 11:52:01 +0100 Subject: [PATCH 063/175] CI: add initial support to do X2 HO at Inria Signed-off-by: Raphael Defosseux --- ci-scripts/Jenkinsfile-inria-r2lab | 13 +- .../inria/enb_usrp210_band7_build.xml | 13 +- ...enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml | 128 ++++++++++++++++++ 3 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml diff --git a/ci-scripts/Jenkinsfile-inria-r2lab b/ci-scripts/Jenkinsfile-inria-r2lab index 778c571645..555017a533 100644 --- a/ci-scripts/Jenkinsfile-inria-r2lab +++ b/ci-scripts/Jenkinsfile-inria-r2lab @@ -59,6 +59,9 @@ def r2labEPC0IpAddr = r2labBaseIpAddr + r2labEPC0Idx def r2labUE0Idx = '6' def r2labUE0 = 'fit0' + r2labUE0Idx def r2labUE0IpAddr = r2labBaseIpAddr + r2labUE0Idx +def r2labENB1Idx = '16' +def r2labENB1 = 'fit' + r2labENB1Idx +def r2labENB1IpAddr = r2labBaseIpAddr + r2labENB1Idx pipeline { agent { @@ -144,9 +147,9 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labPythonExeIdx}'" echo '\u2705 \u001B[32mLoad Image for one eNB\u001B[0m' - sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx} > /dev/null 2>&1'" - sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labENB0Idx}'" - sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx}'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx},${r2labENB1Idx} > /dev/null 2>&1'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labENB0Idx},${r2labENB1Idx}'" + sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx},${r2labENB1Idx}'" echo '\u2705 \u001B[32mLoad Image for one OAI UE\u001B[0m' sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labUE0Idx} > /dev/null 2>&1'" @@ -157,7 +160,7 @@ pipeline { sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-epc ${r2labEPC0Idx} > /dev/null 2>&1'" sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labEPC0Idx}'" - sh "ssh -t inria_oaici@faraday.inria.fr 'nodes ${r2labUE0Idx},${r2labPythonExeIdx},${r2labEPC0Idx},${r2labENB0Idx} && st'" + sh "ssh -t inria_oaici@faraday.inria.fr 'nodes ${r2labUE0Idx},${r2labPythonExeIdx},${r2labEPC0Idx},${r2labENB0Idx},${r2labENB1Idx} && st'" } } } @@ -210,7 +213,7 @@ pipeline { String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") for (xmlFile in myXmlTestSuite) { try { - sh "ssh -t -t inria_oaici@faraday.inria.fr 'ssh -t -t -b 192.168.3.100 ${fituser}@${r2labPythonExe} \"cd openairinterface5g/ci-scripts && python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=${ranRepoBranch} --ranCommitID=${GIT_COMMIT_TO_RUN} --ranAllowMerge=false --eNBIPAddress=${r2labENB0IpAddr} --eNBUserName=${fituser} --eNBPassword=${fitpasswd} --eNBSourceCodePath=/home/${fituser}/openairinterface5g --UEIPAddress=${r2labUE0IpAddr} --UEUserName=${fituser} --UEPassword=${fitpasswd} --UESourceCodePath=/home/${fituser}/openairinterface5g --EPCIPAddress=${r2labEPC0IpAddr} --EPCType=OAI-Rel14-CUPS --EPCUserName=${fituser} --EPCPassword=${fitpasswd} --EPCSourceCodePath=/home/${fituser}/openair-cn --ADBIPAddress=${r2labEPC0IpAddr} --ADBUserName=${fituser} --ADBPassword=${fitpasswd} --ADBType=distributed --XMLTestFile=${xmlFile}\"'" + sh "ssh -t -t inria_oaici@faraday.inria.fr 'ssh -t -t -b 192.168.3.100 ${fituser}@${r2labPythonExe} \"cd openairinterface5g/ci-scripts && python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=${ranRepoBranch} --ranCommitID=${GIT_COMMIT_TO_RUN} --ranAllowMerge=false --eNBIPAddress=${r2labENB0IpAddr} --eNBUserName=${fituser} --eNBPassword=${fitpasswd} --eNBSourceCodePath=/home/${fituser}/openairinterface5g --eNB1IPAddress=${r2labENB1IpAddr} --eNB1UserName=${fituser} --eNB1Password=${fitpasswd} --eNB1SourceCodePath=/home/${fituser}/openairinterface5g --UEIPAddress=${r2labUE0IpAddr} --UEUserName=${fituser} --UEPassword=${fitpasswd} --UESourceCodePath=/home/${fituser}/openairinterface5g --EPCIPAddress=${r2labEPC0IpAddr} --EPCType=OAI-Rel14-CUPS --EPCUserName=${fituser} --EPCPassword=${fitpasswd} --EPCSourceCodePath=/home/${fituser}/openair-cn --ADBIPAddress=${r2labEPC0IpAddr} --ADBUserName=${fituser} --ADBPassword=${fitpasswd} --ADBType=distributed --XMLTestFile=${xmlFile}\"'" } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml index 776c92106d..d3e9825923 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_build.xml @@ -26,13 +26,24 @@ wrench 010101 + 010102 Build_eNB - Build eNB (USRP) + Build eNB #0 (USRP) -w USRP -c --eNB + 0 + 0 + + + + Build_eNB + Build eNB #1 (USRP) + -w USRP -c --eNB + 1 + 1 diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml new file mode 100644 index 0000000000..f10465f688 --- /dev/null +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml @@ -0,0 +1,128 @@ + + + test-x2-ho-05-tm1 + Test-X2-Handover-05MHz-TM1 + tasks + 1 + + 040101 030201 + 050102 + 030104 000002 + 040301 000002 040540 040615 040616 040655 040656 040401 + 040201 000002 030201 + 050202 + + + + + Initialize_UE + Initialize UE + + + + Terminate_UE + Terminate UE + + + + IdleSleep + Sleep for 10 sec + 10 + + + + IdleSleep + Sleep for 3 sec + 3 + + + + Initialize_eNB + Initialize eNB (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes + 0 + 0 + + + + Terminate_eNB + Terminate eNB + + + + Initialize_FlexranCtrl + Starting Flexran Controller + + + + Terminate_FlexranCtrl + Stopping Flexran Controller + + + + Attach_UE + Attach UE + + + + Detach_UE + Detach UE + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Iperf + iperf (5MHz - DL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - DL/15Mbps/UDP)(30 sec) + -u -b 15M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - UL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm -R + 50 + + + + Iperf + iperf (5MHz - UL/3.8Mbps/UDP)(30 sec) + -u -b 3.8M -t 30 -i 1 -fm -R + 50 + + + From 0b8a25ee90b1b5329eb9e4c8b79ae0e7b84bcd8a Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 29 Nov 2019 13:57:42 +0100 Subject: [PATCH 064/175] CI: finalizing offline the X2 handover scenario at inria --> to be tested Signed-off-by: Raphael Defosseux --- ci-scripts/main.py | 1 + ...enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml | 84 +++++++++++++++++-- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index a60a31c04a..bac3599150 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -821,6 +821,7 @@ class SSHConnection(): self.command('source oaienv', '\$', 5) self.command('cd cmake_targets', '\$', 5) self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) self.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml index f10465f688..af09934d2b 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml @@ -26,11 +26,16 @@ tasks 1 - 040101 030201 + 040101 030201 030202 050102 - 030104 000002 - 040301 000002 040540 040615 040616 040655 040656 040401 - 040201 000002 030201 + 030104 000002 030105 000002 + 040301 000002 + 040540 040615 040616 040655 040656 + 050401 000001 + 040541 040617 040618 040657 040658 + 040401 000001 + 040542 + 040201 000002 030201 030202 050202 @@ -59,15 +64,32 @@ Initialize_eNB - Initialize eNB (FDD/Band7/5MHz) - -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes + Initialize eNB #0 (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes --eNBs.[0].nr_cellid 123456 0 0 + + Initialize_eNB + Initialize eNB #1 (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes --eNBs.[0].target_enb_x2_ip_address.[0].ipv4 CI_RCC_IP_ADDR --eNBs.[0].target_enb_x2_ip_address.[0].preference ipv4 --eNBs.[0].eNB_ID 0xe01 --eNBs.[0].component_carriers.[0].Nid_cell 1 --eNBs.[0].nr_cellid 98765 + 1 + 1 + + Terminate_eNB - Terminate eNB + Terminate eNB #0 + 0 + 0 + + + + Terminate_eNB + Terminate eNB #1 + 1 + 1 @@ -97,6 +119,20 @@ 5 + + Ping + ping (5MHz - 20 sec) + -c 20 + 50 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 50 + + Iperf iperf (5MHz - DL/1Mbps/UDP)(30 sec) @@ -111,6 +147,20 @@ 50 + + Iperf + iperf (5MHz - DL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm + 50 + + + + Iperf + iperf (5MHz - DL/15Mbps/UDP)(30 sec) + -u -b 15M -t 30 -i 1 -fm + 50 + + Iperf iperf (5MHz - UL/1Mbps/UDP)(30 sec) @@ -125,4 +175,24 @@ 50 + + Iperf + iperf (5MHz - UL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 -i 1 -fm -R + 50 + + + + Iperf + iperf (5MHz - UL/3.8Mbps/UDP)(30 sec) + -u -b 3.8M -t 30 -i 1 -fm -R + 50 + + + + Perform_X2_Handover + Doing a Flexran-Controlled X2 Handover + network + + From 47abf562db29f1a1128990e8cbc27d29fba8a511 Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 6 Dec 2019 16:24:47 +0100 Subject: [PATCH 065/175] add FS6 transport time measurement --- common/config/config_userapi.c | 2 +- executables/main-fs6.c | 60 +++++++++++++++++++++----- executables/main-ocp.c | 2 +- executables/split_headers.h | 3 ++ executables/transport_split.c | 1 + nfapi/oai_integration/nfapi.c | 2 +- openair2/UTIL/OPT/probe.c | 6 +-- targets/ARCH/rfsimulator/simulator.c | 10 +++-- targets/RT/USER/lte-softmodem-common.c | 18 ++++---- targets/RT/USER/lte-uesoftmodem.c | 10 ++--- 10 files changed, 80 insertions(+), 34 deletions(-) diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index 9b42dd209f..9ba507a6ec 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -81,7 +81,7 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) { } if (*ptr == NULL) { - *ptr = malloc(length); + *ptr = malloc(length>40?length:40); // LTS: dummy fix, waiting Francois full fix in 4G branch if ( *ptr != NULL) { memset(*ptr,0,length); diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 638db0ac11..e39fad1c04 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -82,7 +82,34 @@ static inline void updateTimesReset(uint64_t start, Meas *M, int period, bool Ma } } +static inline void measTransportTime(uint64_t DuSend, uint64_t CuMicroSec, Meas *M, int period, bool MaxMin, char *txt) { + if (DuSend!=0) { + uint64_t end=rdtsc(); + long long diff=(end-DuSend)/(cpuf*1000)-CuMicroSec; + LOG_E(HW, "total: %f, cu time %lu\n", (end-DuSend)/(cpuf*1000), CuMicroSec); + M->maxArray[0]=diff; + M->sum+=diff; + M->iterations++; + + if ( MaxMin) + qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); + else + qsort(M->maxArray, 11, sizeof(uint64_t), cmpintRev); + + printMeas2(txt,M,period, MaxMin); + + if (M->iterations%period == 0 ) { + bzero(M,sizeof(*M)); + + if (!MaxMin) + for (int i=0; i<11; i++) + M->maxArray[i]=INT_MAX; + } + } +} + #define ceil16_bytes(a) ((((a+15)/16)*16)/8) + static void fs6Dlunpack(void *out, void *in, int szUnpacked) { static uint64_t *lut=NULL; @@ -1297,12 +1324,16 @@ void *DL_du_fs6(void *arg) { RU_t *ru=(RU_t *)arg; static uint64_t lastTS; L1_rxtx_proc_t L1_proc= {0}; + initStaticTime(begingWait); + initStaticTime(begingProcessing); + initRefTimes(fullLoop); + initRefTimes(DuHigh); + initRefTimes(DuLow); + initRefTimes(transportTime); while (1) { for (int i=0; inum_eNB; i++) { initBufferZone(bufferZone); - initStaticTime(begingWait); - initRefTimes(fullLoop); pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 ); updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU"); @@ -1313,18 +1344,22 @@ void *DL_du_fs6(void *arg) { lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, hUDP(bufferZone)->timestamp); } - + pickStaticTime(begingProcessing); lastTS=hUDP(bufferZone)->timestamp; setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1_proc); + measTransportTime(hDL(bufferZone)->DuClock, hDL(bufferZone)->CuSpentMicroSec, + &transportTime, 1000, false, "Transport time, to CU + from CU for one subframe"); phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1_proc, 1); + updateTimesReset(begingProcessing, &DuHigh, 1000, false, "DU high layer1 processing for DL"); } else LOG_E(PHY,"DL not received for subframe\n"); } - + pickStaticTime(begingProcessing); feptx_prec(ru, &L1_proc); feptx_ofdm(ru, &L1_proc); tx_rf(ru, &L1_proc); - + updateTimesReset(begingProcessing, &DuLow, 1000, false, "DU low layer1 processing for DL"); + if ( IS_SOFTMODEM_RFSIM ) return NULL; } @@ -1371,7 +1406,7 @@ void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { } } -void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { +void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t DuClock, uint64_t startCycle) { // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; pthread_mutex_lock(&eNB->UL_INFO_mutex); @@ -1390,17 +1425,21 @@ void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { hUDP(bufferZone)->blockID=0; hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t); } - + hDL(bufferZone)->DuClock=DuClock; + hDL(bufferZone)->CuSpentMicroSec=(rdtsc()-startCycle)/(cpuf*1000); + sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); return; } -void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS) { +void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS, uint64_t * DuClock, uint64_t * startProcessing) { initBufferZone(bufferZone); initStaticTime(begingWait); initRefTimes(fullLoop); pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentDUv0 ); + * DuClock=hUDP(bufferZone)->senderClock; + * startProcessing=rdtsc(); updateTimesReset(begingWait, &fullLoop, 1000, false, "CU wait DU"); if (nb_blocks ==0) { @@ -1462,15 +1501,16 @@ void *cu_fs6(void *arg) { initRefTimes(waitDUAndProcessingUL); initRefTimes(makeSendDL); initRefTimes(fullLoop); + uint64_t DuClock=0, startProcessing=0; while(1) { timeStamp+=ru->frame_parms.samples_per_tti; updateTimesReset(begingWait, &fullLoop, 1000, true, "CU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); + UL_cu_fs6(ru, &L1proc, &timeStamp, &DuClock, &startProcessing); updateTimesReset(begingWait, &waitDUAndProcessingUL, 1000, true,"CU Time in wait Rx + Ul processing"); - UL_cu_fs6(ru, &L1proc, &timeStamp); pickStaticTime(begingWait2); - DL_cu_fs6(ru, &L1proc); + DL_cu_fs6(ru, &L1proc, DuClock, startProcessing); updateTimesReset(begingWait2, &makeSendDL, 1000, true,"CU Time in DL build+send"); } diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 819eab0ee6..fe36d89bc4 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -613,7 +613,7 @@ void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { #endif } - if (timestamp_rx - old_ts != fp->samples_per_tti) { + if (old_ts != 0 && timestamp_rx - old_ts != fp->samples_per_tti) { LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti); //ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); //proc->timestamp_rx = ts-ru->ts_offset; diff --git a/executables/split_headers.h b/executables/split_headers.h index 550f189e02..93f1ac3bdf 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -36,6 +36,7 @@ typedef struct commonUDP_s { uint16_t blockID; // id: 0..nbBocks-1 uint16_t contentType; // defines the content format uint16_t contentBytes; // will be sent in a UDP packet, so must be < 2^16 bytes + uint64_t senderClock; } commonUDP_t; // FS6 UL common header (DU to CU) @@ -57,6 +58,8 @@ typedef struct { int num_mdci; int amp; LTE_eNB_PHICH phich_vars; + uint64_t DuClock; + uint64_t CuSpentMicroSec; } fs6_dl_t; // a value to type all sub packets, diff --git a/executables/transport_split.c b/executables/transport_split.c index d54b2692ca..ee19db082f 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -129,6 +129,7 @@ int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType) { commonUDP_t *UDPheader=(commonUDP_t *)bufferZone ; UDPheader->contentType=contentType; + UDPheader->senderClock=rdtsc(); int nbBlocks=UDPheader->nbBlocks; int blockId=0; diff --git a/nfapi/oai_integration/nfapi.c b/nfapi/oai_integration/nfapi.c index 4fc35fd951..86d1ae3127 100644 --- a/nfapi/oai_integration/nfapi.c +++ b/nfapi/oai_integration/nfapi.c @@ -29,7 +29,7 @@ typedef struct { nfapi_mode_t nfapi_mode; } nfapi_params_t; -static nfapi_params_t nfapi_params; +static nfapi_params_t nfapi_params = {0}; void set_thread_priority(int priority) { //printf("%s(priority:%d)\n", __FUNCTION__, priority); diff --git a/openair2/UTIL/OPT/probe.c b/openair2/UTIL/OPT/probe.c index 88adb1b209..2cfda081ee 100644 --- a/openair2/UTIL/OPT/probe.c +++ b/openair2/UTIL/OPT/probe.c @@ -98,8 +98,8 @@ int opt_enabled=0; //static unsigned char g_PDUBuffer[1600]; //static unsigned int g_PDUOffset; -static char *in_ip; -static char *in_path; +static char in_ip[128]={0}; +static char in_path[128]={0}; FILE *file_fd = NULL; pcap_hdr_t file_header = { 0xa1b2c3d4, /* magic number */ @@ -450,7 +450,7 @@ int init_opt(void) { char *in_type=NULL; paramdef_t opt_params[] = OPT_PARAMS_DESC ; checkedparam_t opt_checkParams[] = OPTPARAMS_CHECK_DESC; - uint16_t in_port; + uint16_t in_port=0; config_set_checkfunctions(opt_params, opt_checkParams, sizeof(opt_params)/sizeof(paramdef_t)); config_get( opt_params,sizeof(opt_params)/sizeof(paramdef_t),OPT_CONFIGPREFIX); diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 95eeb38aa0..ec5953e941 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -346,7 +346,8 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp if ( t->lastWroteTS != 0 && abs((double)t->lastWroteTS-timestamp) > (double)CirSize) LOG_E(HW,"Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); - AssertFatal(t->lastWroteTS <= timestamp+1, " Not supported to send Tx out of order (same in USRP) %lu, %lu\n", + if (t->lastWroteTS >= timestamp+1) + LOG_E(HW,"Not supported to send Tx out of order (same in USRP) %lu, %lu\n", t->lastWroteTS, timestamp); t->lastWroteTS=timestamp+nsamps; @@ -420,7 +421,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi if ( sz < 0 ) { if ( errno != EAGAIN ) { LOG_E(HW,"socket failed %s\n", strerror(errno)); - abort(); + //abort(); } } else if ( sz == 0 ) continue; @@ -466,8 +467,9 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi } else if ( b->lastReceivedTS == b->th.timestamp ) { // normal case } else { - abort(); - AssertFatal(false, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); } + LOG_E(HW, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); + b->trashingPacket=true; + } pthread_mutex_lock(&Sockmutex); diff --git a/targets/RT/USER/lte-softmodem-common.c b/targets/RT/USER/lte-softmodem-common.c index 5cc18362da..aaf7d4483d 100644 --- a/targets/RT/USER/lte-softmodem-common.c +++ b/targets/RT/USER/lte-softmodem-common.c @@ -54,16 +54,16 @@ softmodem_params_t *get_softmodem_params(void) { } void get_common_options(void) { - uint32_t online_log_messages; - uint32_t glog_level ; - uint32_t start_telnetsrv; - uint32_t noS1; - uint32_t nokrnmod; - uint32_t nonbiot; - uint32_t rfsim; - uint32_t basicsim; + uint32_t online_log_messages=0; + uint32_t glog_level =0; + uint32_t start_telnetsrv=0; + uint32_t noS1=0; + uint32_t nokrnmod=0; + uint32_t nonbiot=0; + uint32_t rfsim=0; + uint32_t basicsim=0; char *logmem_filename = NULL; - uint32_t do_forms; + uint32_t do_forms=0; paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ; paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ; checkedparam_t cmdline_log_CheckParams[] = CMDLINE_LOGPARAMS_CHECK_DESC; diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 88b9b13233..a2a7b69107 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -320,13 +320,13 @@ void exit_function(const char *file, const char *function, const int line, const extern int16_t dlsch_demod_shift; static void get_options(void) { - int CC_id; - int tddflag; + int CC_id=0; + int tddflag=0; char *loopfile=NULL; int dumpframe=0; - int timingadv; - uint8_t nfapi_mode; - int simL1flag ; + int timingadv=0; + uint8_t nfapi_mode=0; + int simL1flag =0; set_default_frame_parms(frame_parms); CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); /* unknown parameters on command line will be checked in main From 8dedd093fbb6df3ec958b6d3eee4b538fd5bb12d Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 6 Dec 2019 18:41:30 +0100 Subject: [PATCH 066/175] remove a forgotten test trace, re-indentation of modified source files --- executables/main-fs6.c | 37 +++++++++++++++++++---------------- executables/main-ocp.c | 2 +- executables/transport_split.c | 11 ++++++----- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index e39fad1c04..0dbd9a3b45 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -86,7 +86,6 @@ static inline void measTransportTime(uint64_t DuSend, uint64_t CuMicroSec, Meas if (DuSend!=0) { uint64_t end=rdtsc(); long long diff=(end-DuSend)/(cpuf*1000)-CuMicroSec; - LOG_E(HW, "total: %f, cu time %lu\n", (end-DuSend)/(cpuf*1000), CuMicroSec); M->maxArray[0]=diff; M->sum+=diff; M->iterations++; @@ -1344,24 +1343,26 @@ void *DL_du_fs6(void *arg) { lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, hUDP(bufferZone)->timestamp); } - pickStaticTime(begingProcessing); + + pickStaticTime(begingProcessing); lastTS=hUDP(bufferZone)->timestamp; setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1_proc); - measTransportTime(hDL(bufferZone)->DuClock, hDL(bufferZone)->CuSpentMicroSec, - &transportTime, 1000, false, "Transport time, to CU + from CU for one subframe"); + measTransportTime(hDL(bufferZone)->DuClock, hDL(bufferZone)->CuSpentMicroSec, + &transportTime, 1000, false, "Transport time, to CU + from CU for one subframe"); phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1_proc, 1); - updateTimesReset(begingProcessing, &DuHigh, 1000, false, "DU high layer1 processing for DL"); + updateTimesReset(begingProcessing, &DuHigh, 1000, false, "DU high layer1 processing for DL"); } else LOG_E(PHY,"DL not received for subframe\n"); } + pickStaticTime(begingProcessing); feptx_prec(ru, &L1_proc); feptx_ofdm(ru, &L1_proc); tx_rf(ru, &L1_proc); updateTimesReset(begingProcessing, &DuLow, 1000, false, "DU low layer1 processing for DL"); - - if ( IS_SOFTMODEM_RFSIM ) - return NULL; + + if ( IS_SOFTMODEM_RFSIM ) + return NULL; } return NULL; @@ -1425,21 +1426,21 @@ void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t DuClock, uint64_t start hUDP(bufferZone)->blockID=0; hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t); } + hDL(bufferZone)->DuClock=DuClock; hDL(bufferZone)->CuSpentMicroSec=(rdtsc()-startCycle)/(cpuf*1000); - sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); return; } -void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS, uint64_t * DuClock, uint64_t * startProcessing) { +void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS, uint64_t *DuClock, uint64_t *startProcessing) { initBufferZone(bufferZone); initStaticTime(begingWait); initRefTimes(fullLoop); pickStaticTime(begingWait); int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentDUv0 ); * DuClock=hUDP(bufferZone)->senderClock; - * startProcessing=rdtsc(); + * startProcessing=rdtsc(); updateTimesReset(begingWait, &fullLoop, 1000, false, "CU wait DU"); if (nb_blocks ==0) { @@ -1485,8 +1486,8 @@ void *cu_fs6(void *arg) { remoteIP=DU_IP; AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, DU_PORT, &sockFS6), ""); - L1_rxtx_proc_t L1proc= {0}; + if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) initTpool(get_softmodem_params()->threadPoolConfig, &L1proc.threadPool, true); else @@ -1494,7 +1495,6 @@ void *cu_fs6(void *arg) { initNotifiedFIFO(&L1proc.respEncode); initNotifiedFIFO(&L1proc.respDecode); - uint64_t timeStamp=0; initStaticTime(begingWait); initStaticTime(begingWait2); @@ -1548,16 +1548,19 @@ void *du_fs6(void *arg) { initRefTimes(waitRxAndProcessingUL); initRefTimes(fullLoop); pthread_t t; - if ( !IS_SOFTMODEM_RFSIM ) - threadCreate(&t, DL_du_fs6, (void *)ru, "MainDuTx", -1, OAI_PRIORITY_RT_MAX); + + if ( !IS_SOFTMODEM_RFSIM ) + threadCreate(&t, DL_du_fs6, (void *)ru, "MainDuTx", -1, OAI_PRIORITY_RT_MAX); while(1) { L1_rxtx_proc_t L1proc; updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); UL_du_fs6(ru, &L1proc); - if ( IS_SOFTMODEM_RFSIM ) - DL_du_fs6((void *)ru); + + if ( IS_SOFTMODEM_RFSIM ) + DL_du_fs6((void *)ru); + updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); } diff --git a/executables/main-ocp.c b/executables/main-ocp.c index fe36d89bc4..2fad1bf08f 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -688,7 +688,7 @@ static void *ru_thread( void *param ) { setbuf(stdout, NULL); setbuf(stderr, NULL); RU_t *ru = (RU_t *)param; - L1_rxtx_proc_t L1proc={0}; + L1_rxtx_proc_t L1proc= {0}; L1_rxtx_proc_t *proc=&L1proc; if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) diff --git a/executables/transport_split.c b/executables/transport_split.c index ee19db082f..1ed95db7a0 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -58,8 +58,10 @@ bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPo int enable=1; AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,""); struct timeval tv= {0,UDP_TIMEOUT}; + if (IS_SOFTMODEM_RFSIM) tv.tv_sec=2; //debug: wait 2 seconds for human understanding + AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,""); // Make a send/recv buffer larger than a a couple of subframe // so the kernel will store for us in and out paquets @@ -118,9 +120,9 @@ int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t rcved++; bufferZone+=ret; } - LOG_D(HW,"Received: blocks: %d/%d, size %d, TS: %lu\n", - rcved, bufOrigin->nbBlocks, ret, bufOrigin->timestamp); + LOG_D(HW,"Received: blocks: %d/%d, size %d, TS: %lu\n", + rcved, bufOrigin->nbBlocks, ret, bufOrigin->timestamp); } while ( rcved == 0 || rcved < bufOrigin->nbBlocks ); return rcved; @@ -159,11 +161,10 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, ui sz, ret, errno, strerror(errno)); LOG_D(HW,"Sent: TS: %lu, blocks %d/%d, block size : %d \n", - UDPheader->timestamp, UDPheader->nbBlocks-nbBlocks, UDPheader->nbBlocks, sz); - + UDPheader->timestamp, UDPheader->nbBlocks-nbBlocks, UDPheader->nbBlocks, sz); bufferZone+=sz; nbBlocks--; } while (nbBlocks); - return 0; + return 0; } From 9b1846ea767319ddfc3a4b26214259edaa29bed6 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 9 Dec 2019 14:20:38 +0100 Subject: [PATCH 067/175] que beau fichier --- ci-scripts/cnrie.sh | 1 + 1 file changed, 1 insertion(+) create mode 100644 ci-scripts/cnrie.sh diff --git a/ci-scripts/cnrie.sh b/ci-scripts/cnrie.sh new file mode 100644 index 0000000000..5b2c026ee6 --- /dev/null +++ b/ci-scripts/cnrie.sh @@ -0,0 +1 @@ +this is a bs \ No newline at end of file From a1cb460a0194fe283d397d1f0311164e01998676 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 9 Dec 2019 14:46:59 +0100 Subject: [PATCH 068/175] repeatCounts reading from command line instead than xml file --- ci-scripts/main-cnt-mod.py | 4927 ++++++++++++++++++++++++++++++++++++ 1 file changed, 4927 insertions(+) create mode 100644 ci-scripts/main-cnt-mod.py diff --git a/ci-scripts/main-cnt-mod.py b/ci-scripts/main-cnt-mod.py new file mode 100644 index 0000000000..439dc0cfe4 --- /dev/null +++ b/ci-scripts/main-cnt-mod.py @@ -0,0 +1,4927 @@ +# /* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + +#----------------------------------------------------------- +# Version +#----------------------------------------------------------- +Version = '0.1' + +#----------------------------------------------------------- +# Constants +#----------------------------------------------------------- +ALL_PROCESSES_OK = 0 +ENB_PROCESS_FAILED = -1 +ENB_PROCESS_OK = +1 +ENB_PROCESS_SEG_FAULT = -11 +ENB_PROCESS_ASSERTION = -12 +ENB_PROCESS_REALTIME_ISSUE = -13 +ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 +ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 +HSS_PROCESS_FAILED = -2 +HSS_PROCESS_OK = +2 +MME_PROCESS_FAILED = -3 +MME_PROCESS_OK = +3 +SPGW_PROCESS_FAILED = -4 +SPGW_PROCESS_OK = +4 +UE_IP_ADDRESS_ISSUE = -5 +OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 +OAI_UE_PROCESS_COULD_NOT_SYNC = -21 +OAI_UE_PROCESS_ASSERTION = -22 +OAI_UE_PROCESS_FAILED = -23 +OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 +OAI_UE_PROCESS_OK = +6 + +UE_STATUS_DETACHED = 0 +UE_STATUS_DETACHING = 1 +UE_STATUS_ATTACHING = 2 +UE_STATUS_ATTACHED = 3 + +X2_HO_REQ_STATE__IDLE = 0 +X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 +X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 +X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 +X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 + +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import sys # arg +import re # reg +import pexpect # pexpect +import time # sleep +import os +import subprocess +import xml.etree.ElementTree as ET +import logging +import datetime +import signal +from multiprocessing import Process, Lock, SimpleQueue +logging.basicConfig( + level=logging.DEBUG, + format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" +) + +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class SSHConnection(): + def __init__(self): + self.prematureExit = False + self.ranRepository = '' + self.ranBranch = '' + self.ranAllowMerge = False + self.ranCommitID = '' + self.ranTargetBranch = '' + self.eNBIPAddress = '' + self.eNBUserName = '' + self.eNBPassword = '' + self.eNBSourceCodePath = '' + self.EPCIPAddress = '' + self.EPCUserName = '' + self.EPCPassword = '' + self.eNB1IPAddress = '' + self.eNB1UserName = '' + self.eNB1Password = '' + self.eNB1SourceCodePath = '' + self.eNB2IPAddress = '' + self.eNB2UserName = '' + self.eNB2Password = '' + self.eNB2SourceCodePath = '' + self.EPCSourceCodePath = '' + self.EPCType = '' + self.EPC_PcapFileName = '' + self.ADBIPAddress = '' + self.ADBUserName = '' + self.ADBPassword = '' + self.ADBCentralized = True + self.testCase_id = '' + self.testXMLfiles = [] + self.nbTestXMLfiles = 0 + self.desc = '' + self.Build_eNB_args = '' + self.backgroundBuild = False + self.backgroundBuildTestId = ['', '', ''] + self.Initialize_eNB_args = '' + self.eNB_instance = '' + self.eNB_serverId = '' + self.eNBLogFiles = ['', '', ''] + self.eNBOptions = ['', '', ''] + self.ping_args = '' + self.ping_packetloss_threshold = '' + self.iperf_args = '' + self.iperf_packetloss_threshold = '' + self.iperf_profile = '' + self.nbMaxUEtoAttach = -1 + self.UEDevices = [] + self.UEDevicesStatus = [] + self.UEDevicesRemoteServer = [] + self.UEDevicesRemoteUser = [] + self.UEDevicesOffCmd = [] + self.UEDevicesOnCmd = [] + self.UEDevicesRebootCmd = [] + self.CatMDevices = [] + self.UEIPAddresses = [] + self.htmlFile = '' + self.htmlHeaderCreated = False + self.htmlFooterCreated = False + self.htmlUEConnected = -1 + self.htmleNBFailureMsg = '' + self.htmlUEFailureMsg = '' + self.picocom_closure = False + self.idle_sleep_time = 0 + self.x2_ho_options = 'network' + self.x2NbENBs = 0 + self.x2ENBBsIds = [] + self.x2ENBConnectedUEs = [] + self.htmlTabRefs = [] + self.htmlTabNames = [] + self.htmlTabIcons = [] + # repeatCounts was a list --> becomes an integer + self.repeatCounts = 1 + self.finalStatus = False + self.OsVersion = '' + self.KernelVersion = '' + self.UhdVersion = '' + self.UsrpBoard = '' + self.CpuNb = '' + self.CpuModel = '' + self.CpuMHz = '' + self.UEIPAddress = '' + self.UEUserName = '' + self.UEPassword = '' + self.UE_instance = '' + self.UESourceCodePath = '' + self.UELogFile = '' + self.Build_OAI_UE_args = '' + self.Initialize_OAI_UE_args = '' + self.flexranCtrlInstalled = False + self.flexranCtrlStarted = False + self.expectedNbOfConnectedUEs = 0 + self.startTime = 0 + + def open(self, ipaddress, username, password): + count = 0 + connect_status = False + while count < 4: + self.ssh = pexpect.spawn('ssh', [username + '@' + ipaddress], timeout = 5) + self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + self.ssh.sendline('yes') + self.ssh.expect('password:') + self.ssh.sendline(password) + self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + count = 10 + connect_status = True + else: + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + elif self.sshresponse == 1: + self.ssh.sendline(password) + self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + count = 10 + connect_status = True + else: + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + elif self.sshresponse == 2: + # Checking if we are really on the remote client defined by its IP address + self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) + result = re.search(str(ipaddress), str(self.ssh.before)) + if result is None: + self.close() + else: + count = 10 + connect_status = True + else: + # debug output + logging.debug(str(self.ssh.before)) + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + # adding a tempo when failure + if not connect_status: + time.sleep(1) + count += 1 + if connect_status: + pass + else: + sys.exit('SSH Connection Failed') + + def command(self, commandline, expectedline, timeout): + logging.debug(commandline) + self.ssh.timeout = timeout + self.ssh.sendline(commandline) + self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + return 0 + elif self.sshresponse == 1: + logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + sys.exit(self.sshresponse) + elif self.sshresponse == 2: + logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + result = re.search('ping |iperf |picocom', str(commandline)) + if result is None: + logging.debug(str(self.ssh.before)) + sys.exit(self.sshresponse) + else: + return -1 + else: + logging.debug('\u001B[1;37;41m Unexpected Others \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + sys.exit(self.sshresponse) + + def close(self): + self.ssh.timeout = 5 + self.ssh.sendline('exit') + self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + pass + elif self.sshresponse == 1: + if not self.picocom_closure: + logging.debug('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') + + def copyin(self, ipaddress, username, password, source, destination): + count = 0 + copy_status = False + logging.debug('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination) + while count < 10: + scp_spawn = pexpect.spawn('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) + scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + scp_spawn.sendline('yes') + scp_spawn.expect('password:') + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + count = 10 + copy_status = True + else: + logging.debug('1 - scp_response = ' + str(scp_response)) + elif scp_response == 1: + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0 or scp_response == 3: + count = 10 + copy_status = True + else: + logging.debug('2 - scp_response = ' + str(scp_response)) + elif scp_response == 2: + count = 10 + copy_status = True + else: + logging.debug('3 - scp_response = ' + str(scp_response)) + # adding a tempo when failure + if not copy_status: + time.sleep(1) + count += 1 + if copy_status: + return 0 + else: + return -1 + + def copyout(self, ipaddress, username, password, source, destination): + count = 0 + copy_status = False + logging.debug('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination) + while count < 4: + scp_spawn = pexpect.spawn('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) + scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + scp_spawn.sendline('yes') + scp_spawn.expect('password:') + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + count = 10 + copy_status = True + else: + logging.debug('1 - scp_response = ' + str(scp_response)) + elif scp_response == 1: + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0 or scp_response == 3: + count = 10 + copy_status = True + else: + logging.debug('2 - scp_response = ' + str(scp_response)) + elif scp_response == 2: + count = 10 + copy_status = True + else: + logging.debug('3 - scp_response = ' + str(scp_response)) + # adding a tempo when failure + if not copy_status: + time.sleep(1) + count += 1 + if copy_status: + pass + else: + sys.exit('SCP failed') + + def BuildeNB(self): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + Usage() + sys.exit('Insufficient Parameter') + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(lIpAddr, lUserName, lPassWord) + self.command('mkdir -p ' + lSourcePath, '\$', 5) + self.command('cd ' + lSourcePath, '\$', 5) + self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) + # Raphael: here add a check if git clone or git fetch went smoothly + self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + self.command('git config user.name "OAI Jenkins"', '\$', 5) + # Checking the BUILD INFO file + if not self.backgroundBuild: + self.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) + if result is not None: + mismatch = False + self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(self.ranCommitID, str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + result = re.search('YES', str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + result = re.search('develop', str(self.ssh.before)) + else: + result = re.search(self.ranTargetBranch, str(self.ssh.before)) + if result is None: + mismatch = True + else: + result = re.search('NO', str(self.ssh.before)) + if result is None: + mismatch = True + if not mismatch: + self.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + return + + self.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + self.command('git checkout -f ' + self.ranCommitID, '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (self.ranAllowMerge): + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('mkdir -p log', '\$', 5) + self.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + if self.backgroundBuild: + self.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) + self.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) + self.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id + return + self.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) + + def WaitBuildeNBisFinished(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(lIpAddr, lUserName, lPassWord) + count = 40 + buildOAIprocess = True + while (count > 0) and buildOAIprocess: + self.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) + result = re.search('build_oai', str(self.ssh.before)) + if result is None: + buildOAIprocess = False + else: + count -= 1 + time.sleep(30) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) + + def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): + self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) + self.command('ls lte_build_oai/build', '\$', 3) + self.command('ls lte_build_oai/build', '\$', 3) + buildStatus = True + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is None: + buildStatus = False + else: + # Generating a BUILD INFO file + self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + self.command('mkdir -p build_log_' + testcaseId, '\$', 5) + self.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) + self.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) + if self.eNB_serverId != '0': + self.command('cd cmake_targets', '\$', 5) + self.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) + self.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) + self.close() + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + os.remove('./tmp_build' + testcaseId + '.zip') + self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') + os.remove('./tmp_build' + testcaseId + '.zip') + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) + self.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) + self.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) + self.close() + else: + self.close() + + if buildStatus: + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + else: + logging.error('\u001B[1m Building OAI eNB Failed\u001B[0m') + self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) + self.CreateHtmlTabFooter(False) + sys.exit(1) + + def BuildOAIUE(self): + if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) + self.command('cd ' + self.UESourceCodePath, '\$', 5) + self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) + # here add a check if git clone or git fetch went smoothly + self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + self.command('git config user.name "OAI Jenkins"', '\$', 5) + self.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) + if result is not None: + mismatch = False + self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(self.ranCommitID, str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + result = re.search('YES', str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + result = re.search('develop', str(self.ssh.before)) + else: + result = re.search(self.ranTargetBranch, str(self.ssh.before)) + if result is None: + mismatch = True + else: + result = re.search('NO', str(self.ssh.before)) + if result is None: + mismatch = True + if not mismatch: + self.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + return + + self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + self.command('git checkout -f ' + self.ranCommitID, '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (self.ranAllowMerge): + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('mkdir -p log', '\$', 5) + self.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) + self.command('ls lte_build_oai/build', '\$', 3) + self.command('ls lte_build_oai/build', '\$', 3) + buildStatus = True + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is None: + buildStatus = False + self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) + self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) + self.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) + if buildStatus: + # Generating a BUILD INFO file + self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + self.close() + self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + else: + self.close() + logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') + self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') + self.CreateHtmlTabFooter(False) + sys.exit(1) + + def InitializeHSS(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') + EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) + self.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) + self.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) + self.command('chmod 755 ./my-hss.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC HSS') + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + logging.debug('Using the ltebox simulated HSS') + self.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + self.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('cd /opt/hss_sim0609', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + else: + logging.error('This option should not occur!') + self.close() + self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def InitializeMME(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 MME') + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) + self.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) + self.command('chmod 755 ./my-mme.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('stdbuf -o0 hostname', '\$', 5) + result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') + sys.exit(1) + host_name = result.group('host_name') + self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) + else: + logging.error('This option should not occur!') + self.close() + self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def InitializeSPGW(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) + self.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) + self.command('chmod 755 ./my-spgwc.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) + time.sleep(5) + self.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) + self.command('chmod 755 ./my-spgwu.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) + else: + logging.error('This option should not occur!') + self.close() + self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def CheckFlexranCtrlInstallation(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + return + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) + result = re.search('/opt/flexran_rtc/build/rt_controller', str(self.ssh.before)) + if result is not None: + self.flexranCtrlInstalled = True + logging.debug('Flexran Controller is installed') + self.close() + + def InitializeFlexranCtrl(self): + if self.flexranCtrlInstalled == False: + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd /opt/flexran_rtc', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) + self.command('ps -aux | grep --color=never rt_controller', '\$', 5) + result = re.search('rt_controller -c ', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') + self.flexranCtrlStarted = True + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def InitializeeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = False + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) + result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', str(self.ssh.before)) + if result is not None: + eth_interface = result.group('eth_interface') + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') + self.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) + self.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + self.close() + self.open(lIpAddr, lUserName, lPassWord) + self.command('cd ' + lSourcePath, '\$', 5) + # Initialize_eNB_args usually start with -O and followed by the location in repository + full_config_file = self.Initialize_eNB_args.replace('-O ','') + extra_options = '' + extIdx = full_config_file.find('.conf') + if (extIdx > 0): + extra_options = full_config_file[extIdx + 5:] + # if tracer options is on, compiling and running T Tracer + result = re.search('T_stdout', str(extra_options)) + if result is not None: + logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') + self.command('cd common/utils/T/tracer', '\$', 5) + self.command('make', '\$', 10) + self.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) + self.command('cd ' + lSourcePath, '\$', 5) + full_config_file = full_config_file[:extIdx + 5] + config_path, config_file = os.path.split(full_config_file) + else: + sys.exit('Insufficient Parameter') + ci_full_config_file = config_path + '/ci-' + config_file + rruCheck = False + result = re.search('^rru|^rcc|^du.band', str(config_file)) + if result is not None: + rruCheck = True + # do not reset board twice in IF4.5 case + result = re.search('^rru|^enb|^du.band', str(config_file)) + if result is not None: + self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) + result = re.search('type: b200', str(self.ssh.before)) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + self.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 15) + # Make a copy and adapt to EPC / eNB IP addresses + self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) + self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); + else: + self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); + # Launch eNB with the modified config file + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' + if extra_options != '': + self.eNBOptions[int(self.eNB_instance)] = extra_options + time.sleep(6) + doLoop = True + loopCounter = 10 + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # In case of T tracer recording, we may need to kill it + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.command('killall --signal SIGKILL record', '\$', 5) + self.close() + doLoop = False + logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) + # In case of T tracer recording, we need to kill tshark on EPC side + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if self.EPC_PcapFileName != '': + time.sleep(0.5) + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + self.close() + time.sleep(1) + if self.EPC_PcapFileName != '': + copyin_res = self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + if (copyin_res == 0): + self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + self.prematureExit = True + return + else: + self.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) + if rruCheck: + result = re.search('wait RUs', str(self.ssh.before)) + else: + result = re.search('got sync|Starting F1AP at CU', str(self.ssh.before)) + if result is None: + time.sleep(6) + else: + doLoop = False + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') + time.sleep(10) + + self.close() + + def InitializeUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if not self.ADBCentralized: + # Reboot UE + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) + # Wait + #time.sleep(60) + # Put in LTE-Mode only + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) + # enable data service + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + # we need to do radio on/off cycle to make sure of above changes + # airplane mode off // radio on + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + #time.sleep(10) + # airplane mode on // radio off + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + + # normal procedure without reboot + # enable data service + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + # airplane mode on // radio off + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + self.close() + return + # enable data service + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + + # The following commands are deprecated since we no longer work on Android 7+ + # self.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) + # self.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) + # a dedicated script has to be installed inside the UE + # airplane mode on means call /data/local/tmp/off + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + #airplane mode off means call /data/local/tmp/on + logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def InitializeUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.InitializeUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def InitializeOAIUE(self): + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is None: + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + # b2xx_fx3_utils reset procedure + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) + result = re.search('type: b200', str(self.ssh.before)) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) + else: + logging.debug('Did not find any B2xx device') + self.command('cd ' + self.UESourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets/lte_build_oai/build', '\$', 5) + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + # We may have to regenerate the .u* files + if result is None: + self.command('ls /tmp/*.sed', '\$', 5) + result = re.search('adapt_usim_parameters', str(self.ssh.before)) + if result is not None: + self.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + else: + self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) + # Launch UE with the modified config file + self.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.UELogFile = 'ue_' + self.testCase_id + '.log' + + # We are now looping several times to hope we really sync w/ an eNB + doOutterLoop = True + outterLoopCounter = 5 + gotSyncStatus = True + fullSyncStatus = True + while (doOutterLoop): + self.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + time.sleep(6) + self.command('cd ../..', '\$', 5) + doLoop = True + loopCounter = 10 + gotSyncStatus = True + # the 'got sync' message is for the UE threads synchronization + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # Here should never occur + logging.error('"got sync" message never showed!') + gotSyncStatus = False + doLoop = False + continue + self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + result = re.search('got sync', str(self.ssh.before)) + if result is None: + time.sleep(6) + else: + doLoop = False + logging.debug('Found "got sync" message!') + if gotSyncStatus == False: + # we certainly need to stop the lte-uesoftmodem process if it is still running! + self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + time.sleep(3) + # We are now checking if sync w/ eNB DOES NOT OCCUR + # Usually during the cell synchronization stage, the UE returns with No cell synchronization message + doLoop = True + loopCounter = 10 + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # Here we do have a great chance that the UE did cell-sync w/ eNB + doLoop = False + doOutterLoop = False + fullSyncStatus = True + continue + self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + result = re.search('No cell synchronization found', str(self.ssh.before)) + if result is None: + time.sleep(6) + else: + doLoop = False + fullSyncStatus = False + logging.debug('Found: "No cell synchronization" message! --> try again') + time.sleep(6) + self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + outterLoopCounter = outterLoopCounter - 1 + if (outterLoopCounter == 0): + doOutterLoop = False + + if fullSyncStatus and gotSyncStatus: + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is None: + self.command('ifconfig oaitun_ue1', '\$', 4) + # ifconfig output is different between ubuntu 16 and ubuntu 18 + result = re.search('inet addr:1|inet 1', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') + tunnelInterfaceStatus = True + else: + logging.debug(str(self.ssh.before)) + logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') + tunnelInterfaceStatus = False + else: + tunnelInterfaceStatus = True + + self.close() + if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') + if (self.ADBIPAddress != 'none'): + self.UEDevices = [] + self.UEDevices.append('OAI-UE') + self.UEDevicesStatus = [] + self.UEDevicesStatus.append(UE_STATUS_DETACHED) + else: + self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') + logging.error('\033[91mInitialize OAI UE Failed! \033[0m') + self.AutoTerminateUEandeNB() + + def checkDevTTYisUnlocked(self): + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + count = 0 + while count < 5: + self.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) + result = re.search('picocom', str(self.ssh.before)) + if result is None: + count = 10 + else: + time.sleep(5) + count = count + 1 + self.close() + + def InitializeCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.picocom_closure = True + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + # Disabling the Radio + self.command('AT+CFUN=0', 'OK', 5) + logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') + # Checking if auto-attach is enabled + self.command('AT^AUTOATT?', 'OK', 5) + result = re.search('AUTOATT: (?P[0-9\-]+)', str(self.ssh.before)) + if result is not None: + if result.group('state') is not None: + autoAttachState = int(result.group('state')) + if autoAttachState is not None: + if autoAttachState == 0: + self.command('AT^AUTOATT=1', 'OK', 5) + logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') + # Force closure of picocom but device might still be locked + self.close() + self.picocom_closure = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.checkDevTTYisUnlocked() + + def TerminateCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.picocom_closure = True + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + # Disabling the Radio + self.command('AT+CFUN=0', 'OK', 5) + logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') + self.close() + self.picocom_closure = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.checkDevTTYisUnlocked() + + def AttachCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.picocom_closure = True + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + # Enabling the Radio + self.command('AT+CFUN=1', 'SIMSTORE,READY', 5) + logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') + time.sleep(4) + # We should check if we register + count = 0 + attach_cnt = 0 + attach_status = False + while count < 5: + self.command('AT+CEREG?', 'OK', 5) + result = re.search('CEREG: 2,(?P[0-9\-]+),', str(self.ssh.before)) + if result is not None: + mDataConnectionState = int(result.group('state')) + if mDataConnectionState is not None: + if mDataConnectionState == 1: + count = 10 + attach_status = True + result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', str(self.ssh.before)) + if result is not None: + networky = result.group('networky') + networkz = result.group('networkz') + logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m') + else: + logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m') + else: + logging.debug('+CEREG: 2,' + str(mDataConnectionState)) + attach_cnt = attach_cnt + 1 + else: + logging.debug(str(self.ssh.before)) + attach_cnt = attach_cnt + 1 + count = count + 1 + time.sleep(1) + if attach_status: + self.command('AT+CESQ', 'OK', 5) + result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', str(self.ssh.before)) + if result is not None: + nRSRQ = int(result.group('rsrq')) + nRSRP = int(result.group('rsrp')) + if (nRSRQ is not None) and (nRSRP is not None): + logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') + logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') + self.close() + self.picocom_closure = False + html_queue = SimpleQueue() + self.checkDevTTYisUnlocked() + if attach_status: + html_cell = '

CAT-M module Attachment Completed in ' + str(attach_cnt+4) + ' seconds'
+			if (nRSRQ is not None) and (nRSRP is not None):
+				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
+				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm
' + else: + html_cell += '' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) + else: + logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') + html_cell = '
CAT-M module Attachment Failed
' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) + self.AutoTerminateUEandeNB() + + def PingCatM(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + try: + statusQueue = SimpleQueue() + lock = Lock() + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC HSS: not implemented yet') + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + else: + self.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) + result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', str(self.ssh.before)) + if result is not None: + moduleIPAddr = result.group('ipaddr') + else: + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + device_id = 'catm' + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + lock.acquire() + logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + lock.release() + self.close() + html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' + statusQueue.put(html_cell) + if (packetLossOK): + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) + self.AutoTerminateUEandeNB() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AttachUE_common(self, device_id, statusQueue, lock, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + else: + # airplane mode off // radio on + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + time.sleep(2) + max_count = 45 + count = max_count + while count > 0: + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put('mDataConnectionState Not Found!') + lock.release() + break + mDataConnectionState = int(result.group('state')) + if mDataConnectionState == 2: + logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') + lock.acquire() + statusQueue.put(max_count - count) + statusQueue.put(device_id) + statusQueue.put('Attach Completed') + lock.release() + break + count = count - 1 + if count == 15 or count == 30: + logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + time.sleep(0.5) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + time.sleep(0.5) + logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') + time.sleep(1) + if count == 0: + logging.debug('\u001B[1;37;41m UE (' + device_id + ') Attach Failed \u001B[0m') + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put('Attach Failed') + lock.release() + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AttachUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + status_queue = SimpleQueue() + lock = Lock() + nb_ue_to_connect = 0 + for device_id in self.UEDevices: + if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): + self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING + p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) + p.daemon = True + p.start() + multi_jobs.append(p) + nb_ue_to_connect = nb_ue_to_connect + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + return + else: + attach_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + attach_status = False + device_id = status_queue.get() + message = status_queue.get() + if (count < 0): + html_cell = '
UE (' + device_id + ')\n' + message + '
' + else: + html_cell = '
UE (' + device_id + ')\n' + message + ' in ' + str(count + 2) + ' seconds
' + html_queue.put(html_cell) + if (attach_status): + cnt = 0 + while cnt < len(self.UEDevices): + if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: + self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED + cnt += 1 + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + else: + self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def DetachUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DetachUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + cnt = 0 + for device_id in self.UEDevices: + self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING + p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) + p.daemon = True + p.start() + multi_jobs.append(p) + cnt += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + cnt = 0 + while cnt < len(self.UEDevices): + self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED + cnt += 1 + + def RebootUE_common(self, device_id): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + previousmDataConnectionStates = [] + # Save mDataConnectionState + self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') + sys.exit(1) + previousmDataConnectionStates.append(int(result.group('state'))) + # Reboot UE + self.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) + time.sleep(60) + previousmDataConnectionState = previousmDataConnectionStates.pop(0) + count = 180 + while count > 0: + count = count - 1 + self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + if result is None: + mDataConnectionState = None + else: + mDataConnectionState = int(result.group('state')) + logging.debug('mDataConnectionState = ' + result.group('state')) + if mDataConnectionState is None or (previousmDataConnectionState == 2 and mDataConnectionState != 2): + logging.debug('\u001B[1mWait UE (' + device_id + ') a second until reboot completion (' + str(180-count) + ' times)\u001B[0m') + time.sleep(1) + else: + logging.debug('\u001B[1mUE (' + device_id + ') Reboot Completed\u001B[0m') + break + if count == 0: + logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') + sys.exit(1) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def RebootUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + multi_jobs = [] + for device_id in self.UEDevices: + p = Process(target = self.RebootUE_common, args = (device_id,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def DataDisableUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # disable data service + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DataDisableUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.DataDisableUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def DataEnableUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # enable data service + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DataEnableUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.DataEnableUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def GetAllUEDevices(self, terminate_ue_flag): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('adb devices', '\$', 15) + self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",str(self.ssh.before)) + self.close() + else: + if (os.path.isfile('./phones_list.txt')): + os.remove('./phones_list.txt') + self.command('ls /etc/*/phones*.txt', '\$', 5) + result = re.search('/etc/ci/phones_list.txt', str(self.ssh.before)) + self.close() + if (result is not None) and (len(self.UEDevices) == 0): + self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') + if (os.path.isfile('./phones_list.txt')): + phone_list_file = open('./phones_list.txt', 'r') + for line in phone_list_file.readlines(): + line = line.strip() + result = re.search('^#', line) + if result is not None: + continue + comma_split = line.split(",") + self.UEDevices.append(comma_split[0]) + self.UEDevicesRemoteServer.append(comma_split[1]) + self.UEDevicesRemoteUser.append(comma_split[2]) + self.UEDevicesOffCmd.append(comma_split[3]) + self.UEDevicesOnCmd.append(comma_split[4]) + self.UEDevicesRebootCmd.append(comma_split[5]) + phone_list_file.close() + + if terminate_ue_flag == False: + if len(self.UEDevices) == 0: + logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') + sys.exit(1) + if len(self.UEDevicesStatus) == 0: + cnt = 0 + while cnt < len(self.UEDevices): + self.UEDevicesStatus.append(UE_STATUS_DETACHED) + cnt += 1 + + def GetAllCatMDevices(self, terminate_ue_flag): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) + self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",str(self.ssh.before)) + else: + if (os.path.isfile('./modules_list.txt')): + os.remove('./modules_list.txt') + self.command('ls /etc/*/modules*.txt', '\$', 5) + result = re.search('/etc/ci/modules_list.txt', str(self.ssh.before)) + self.close() + if result is not None: + logging.debug('Found a module list file on ADB server') + if terminate_ue_flag == False: + if len(self.CatMDevices) == 0: + logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') + sys.exit(1) + self.close() + + def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) + result = re.search('mServiceState=(?P[0-9]+)', str(self.ssh.before)) + serviceState = 'Service State: UNKNOWN' + if result is not None: + lServiceState = int(result.group('serviceState')) + if lServiceState == 3: + serviceState = 'Service State: RADIO_POWERED_OFF' + if lServiceState == 1: + serviceState = 'Service State: OUT_OF_SERVICE' + if lServiceState == 0: + serviceState = 'Service State: IN_SERVICE' + if lServiceState == 2: + serviceState = 'Service State: EMERGENCY_ONLY' + result = re.search('mDataConnectionState=(?P[0-9]+)', str(self.ssh.before)) + dataConnectionState = 'Data State: UNKNOWN' + if result is not None: + lDataConnectionState = int(result.group('dataConnectionState')) + if lDataConnectionState == 0: + dataConnectionState = 'Data State: DISCONNECTED' + if lDataConnectionState == 1: + dataConnectionState = 'Data State: CONNECTING' + if lDataConnectionState == 2: + dataConnectionState = 'Data State: CONNECTED' + if lDataConnectionState == 3: + dataConnectionState = 'Data State: SUSPENDED' + result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', str(self.ssh.before)) + dataConnectionReason = 'Data Reason: UNKNOWN' + if result is not None: + dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') + lock.acquire() + logging.debug('\u001B[1;37;44m Status Check (' + str(device_id) + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + serviceState + '\u001B[0m') + logging.debug('\u001B[1;34m ' + dataConnectionState + '\u001B[0m') + logging.debug('\u001B[1;34m ' + dataConnectionReason + '\u001B[0m') + statusQueue.put(0) + statusQueue.put(device_id) + qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason + statusQueue.put(qMsg) + lock.release() + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckStatusUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + multi_jobs = [] + lock = Lock() + status_queue = SimpleQueue() + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.CheckUEStatus_common, args = (lock,device_id,status_queue,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd /opt/flexran_rtc', '\$', 5) + self.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) + self.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) + result = re.search('Nb Connected UE = (?P[0-9]+)', str(self.ssh.before)) + passStatus = True + if result is not None: + nb_ues = int(result.group('nb_ues')) + htmlOptions = 'Nb Connected UE(s) to eNB = ' + str(nb_ues) + logging.debug('\u001B[1;37;44m ' + htmlOptions + ' \u001B[0m') + if self.expectedNbOfConnectedUEs > -1: + if nb_ues != self.expectedNbOfConnectedUEs: + passStatus = False + else: + htmlOptions = 'N/A' + self.close() + else: + passStatus = True + htmlOptions = 'N/A' + + if (status_queue.empty()): + self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + check_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + check_status = False + device_id = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\n' + message + '
' + html_queue.put(html_cell) + if check_status and passStatus: + self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def GetAllUEIPAddresses(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + ue_ip_status = 0 + self.UEIPAddresses = [] + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('ifconfig oaitun_ue1', '\$', 4) + result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', str(self.ssh.before)) + if result is not None: + if result.group('ueipaddress') is not None: + UE_IPAddress = result.group('ueipaddress') + else: + UE_IPAddress = result.group('ueipaddress2') + logging.debug('\u001B[1mUE (' + self.UEDevices[0] + ') IP Address is ' + UE_IPAddress + '\u001B[0m') + self.UEIPAddresses.append(UE_IPAddress) + else: + logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') + ue_ip_status -= 1 + self.close() + return ue_ip_status + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + idx = 0 + for device_id in self.UEDevices: + if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: + idx += 1 + continue + count = 0 + while count < 4: + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) + result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') + time.sleep(1) + count += 1 + else: + count = 10 + if count < 9: + ue_ip_status -= 1 + continue + UE_IPAddress = result.group('ueipaddress') + logging.debug('\u001B[1mUE (' + device_id + ') IP Address is ' + UE_IPAddress + '\u001B[0m') + for ueipaddress in self.UEIPAddresses: + if ueipaddress == UE_IPAddress: + logging.debug('\u001B[1mUE (' + device_id + ') IP Address ' + UE_IPAddress + ': has already been allocated to another device !' + '\u001B[0m') + ue_ip_status -= 1 + continue + self.UEIPAddresses.append(UE_IPAddress) + idx += 1 + self.close() + return ue_ip_status + + def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(message) + lock.release() + + def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): + try: + # Launch ping on the EPC side (true for ltebox and old open-air-cn) + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + else: + cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + ping_status = ret.returncode + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + lock.acquire() + logging.debug('\u001B[1;37;44m ping result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + if (packetLossOK): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(qMsg) + lock.release() + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def PingNoS1_wrong_exit(self, qMsg): + html_queue = SimpleQueue() + html_cell = '
OAI UE ping result\n' + qMsg + '
' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + + def PingNoS1(self): + check_eNB = True + check_OAI_UE = True + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) + if ping_from_eNB is not None: + if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + else: + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + Usage() + sys.exit('Insufficient Parameter') + try: + if ping_from_eNB is not None: + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) + else: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with OAI UE crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + logging.debug('\u001B[1;37;44m OAI UE ping result \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + self.close() + html_queue = SimpleQueue() + ip_addr = 'TBD' + html_cell = '
OAI UE ping result\n' + qMsg + '
' + html_queue.put(html_cell) + if packetLossOK: + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + + # copying on the EPC server for logCollection + if ping_from_eNB is not None: + copyin_res = self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + else: + copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def Ping(self): + result = re.search('noS1', str(self.Initialize_eNB_args)) + if result is not None: + self.PingNoS1() + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + check_OAI_UE = True + else: + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + i = 0 + lock = Lock() + status_queue = SimpleQueue() + for UE_IPAddress in self.UEIPAddresses: + device_id = self.UEDevices[i] + p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + ping_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + ping_status = False + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (ping_status): + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def Iperf_ComputeTime(self): + result = re.search('-t (?P\d+)', str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Iperf time Not Found! \u001B[0m') + sys.exit(1) + return result.group('iperf_time') + + def Iperf_ComputeModifiedBW(self, idx, ue_num): + result = re.search('-b (?P[0-9\.]+)[KMG]', str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Iperf bandwidth Not Found! \u001B[0m') + sys.exit(1) + iperf_bandwidth = result.group('iperf_bandwidth') + if self.iperf_profile == 'balanced': + iperf_bandwidth_new = float(iperf_bandwidth)/ue_num + if self.iperf_profile == 'single-ue': + iperf_bandwidth_new = float(iperf_bandwidth) + if self.iperf_profile == 'unbalanced': + # residual is 2% of max bw + residualBW = float(iperf_bandwidth) / 50 + if idx == 0: + iperf_bandwidth_new = float(iperf_bandwidth) - ((ue_num - 1) * residualBW) + else: + iperf_bandwidth_new = residualBW + iperf_bandwidth_str = '-b ' + iperf_bandwidth + iperf_bandwidth_str_new = '-b ' + ('%.2f' % iperf_bandwidth_new) + result = re.sub(iperf_bandwidth_str, iperf_bandwidth_str_new, str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Calculate Iperf bandwidth Failed! \u001B[0m') + sys.exit(1) + return result + + def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + self.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', str(self.ssh.before)) + if result is not None: + avgbitrate = result.group('average') + maxbitrate = result.group('maximum') + minbitrate = result.group('minimum') + lock.acquire() + logging.debug('\u001B[1;37;44m TCP iperf result (' + UE_IPAddress + ') \u001B[0m') + msg = 'TCP Stats :\n' + if avgbitrate is not None: + logging.debug('\u001B[1;34m Avg Bitrate : ' + avgbitrate + '\u001B[0m') + msg += 'Avg Bitrate : ' + avgbitrate + '\n' + if maxbitrate is not None: + logging.debug('\u001B[1;34m Max Bitrate : ' + maxbitrate + '\u001B[0m') + msg += 'Max Bitrate : ' + maxbitrate + '\n' + if minbitrate is not None: + logging.debug('\u001B[1;34m Min Bitrate : ' + minbitrate + '\u001B[0m') + msg += 'Min Bitrate : ' + minbitrate + '\n' + statusQueue.put(0) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + return 0 + + def Iperf_analyzeV2Output(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + result = re.search('-u', str(iperf_real_options)) + if result is None: + return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) + + result = re.search('Server Report:', str(self.ssh.before)) + if result is None: + result = re.search('read failed: Connection refused', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') + else: + logging.debug('\u001B[1;37;41m Server Report and Connection refused Not Found! \u001B[0m') + return -1 + # Computing the requested bandwidth in float + result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) + if result is not None: + req_bandwidth = result.group('iperf_bandwidth') + req_bw = float(req_bandwidth) + result = re.search('-b [0-9\.]+K', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Kbits/sec' % req_bw + req_bw = req_bw * 1000 + result = re.search('-b [0-9\.]+M', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Mbits/sec' % req_bw + req_bw = req_bw * 1000000 + result = re.search('-b [0-9\.]+G', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Gbits/sec' % req_bw + req_bw = req_bw * 1000000000 + + result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) + if result is not None: + bitrate = result.group('bitrate') + packetloss = result.group('packetloss') + jitter = result.group('jitter') + lock.acquire() + logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') + iperfStatus = True + msg = 'Req Bitrate : ' + req_bandwidth + '\n' + logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m') + if bitrate is not None: + msg += 'Bitrate : ' + bitrate + '\n' + logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') + result = re.search('(?P[0-9\.]+) [KMG]bits/sec', str(bitrate)) + if result is not None: + actual_bw = float(str(result.group('real_bw'))) + result = re.search('[0-9\.]+ K', bitrate) + if result is not None: + actual_bw = actual_bw * 1000 + result = re.search('[0-9\.]+ M', bitrate) + if result is not None: + actual_bw = actual_bw * 1000000 + result = re.search('[0-9\.]+ G', bitrate) + if result is not None: + actual_bw = actual_bw * 1000000000 + br_loss = 100 * actual_bw / req_bw + bitperf = '%.2f ' % br_loss + msg += 'Bitrate Perf: ' + bitperf + '%\n' + logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m') + if packetloss is not None: + msg += 'Packet Loss : ' + packetloss + '%\n' + logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') + if float(packetloss) > float(self.iperf_packetloss_threshold): + msg += 'Packet Loss too high!\n' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + iperfStatus = False + if jitter is not None: + msg += 'Jitter : ' + jitter + '\n' + logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m') + if (iperfStatus): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + return 0 + else: + return -2 + + def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') + return + # Computing the requested bandwidth in float + result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) + if result is None: + logging.debug('Iperf bandwidth Not Found!') + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not compute Iperf bandwidth!') + return + else: + req_bandwidth = result.group('iperf_bandwidth') + req_bw = float(req_bandwidth) + result = re.search('-b [0-9\.]+K', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Kbits/sec' % req_bw + req_bw = req_bw * 1000 + result = re.search('-b [0-9\.]+M', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Mbits/sec' % req_bw + req_bw = req_bw * 1000000 + result = re.search('-b [0-9\.]+G', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Gbits/sec' % req_bw + req_bw = req_bw * 1000000000 + + server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') + br_sum = 0.0 + ji_sum = 0.0 + pl_sum = 0 + ps_sum = 0 + row_idx = 0 + for line in server_file.readlines(): + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) + if result is not None: + bitrate = result.group('bitrate') + jitter = result.group('jitter') + packetlost = result.group('lostPack') + packetsent = result.group('sentPack') + br = bitrate.split(' ') + ji = jitter.split(' ') + row_idx = row_idx + 1 + curr_br = float(br[0]) + pl_sum = pl_sum + int(packetlost) + ps_sum = ps_sum + int(packetsent) + if (br[1] == 'Kbits/sec'): + curr_br = curr_br * 1000 + if (br[1] == 'Mbits/sec'): + curr_br = curr_br * 1000 * 1000 + br_sum = curr_br + br_sum + ji_sum = float(ji[0]) + ji_sum + if (row_idx > 0): + br_sum = br_sum / row_idx + ji_sum = ji_sum / row_idx + br_loss = 100 * br_sum / req_bw + if (br_sum > 1000): + br_sum = br_sum / 1000 + if (br_sum > 1000): + br_sum = br_sum / 1000 + bitrate = '%.2f Mbits/sec' % br_sum + else: + bitrate = '%.2f Kbits/sec' % br_sum + else: + bitrate = '%.2f bits/sec' % br_sum + bitperf = '%.2f ' % br_loss + bitperf += '%' + jitter = '%.2f ms' % (ji_sum) + if (ps_sum > 0): + pl = float(100 * pl_sum / ps_sum) + packetloss = '%2.1f ' % (pl) + packetloss += '%' + else: + packetloss = 'unknown' + lock.acquire() + if (br_loss < 90): + statusQueue.put(1) + else: + statusQueue.put(0) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + req_msg = 'Req Bitrate : ' + req_bandwidth + bir_msg = 'Bitrate : ' + bitrate + brl_msg = 'Bitrate Perf: ' + bitperf + jit_msg = 'Jitter : ' + jitter + pal_msg = 'Packet Loss : ' + packetloss + statusQueue.put(req_msg + '\n' + bir_msg + '\n' + brl_msg + '\n' + jit_msg + '\n' + pal_msg + '\n') + logging.debug('\u001B[1;37;45m iperf result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;35m ' + req_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + bir_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + brl_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + jit_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + pal_msg + '\u001B[0m') + lock.release() + else: + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') + + server_file.close() + + + def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', str(self.ssh.before)) + if result is None: + result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', str(self.ssh.before)) + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + if result is not None: + logging.debug('\u001B[1;37;41m ' + result.group('error') + ' \u001B[0m') + statusQueue.put(result.group('error')) + else: + logging.debug('\u001B[1;37;41m Bitrate and/or Packet Loss Not Found! \u001B[0m') + statusQueue.put('Bitrate and/or Packet Loss Not Found!') + lock.release() + + bitrate = result.group('bitrate') + packetloss = result.group('packetloss') + lock.acquire() + logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') + msg = 'Bitrate : ' + bitrate + '\n' + iperfStatus = True + if packetloss is not None: + logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') + msg += 'Packet Loss : ' + packetloss + '%\n' + if float(packetloss) > float(self.iperf_packetloss_threshold): + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + msg += 'Packet Loss too high!\n' + iperfStatus = False + if (iperfStatus): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + + def Iperf_UL_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): + udpIperf = True + result = re.search('-u', str(self.iperf_args)) + if result is None: + udpIperf = False + ipnumbers = UE_IPAddress.split('.') + if (len(ipnumbers) == 4): + ipnumbers[3] = '1' + EPC_Iperf_UE_IPAddress = ipnumbers[0] + '.' + ipnumbers[1] + '.' + ipnumbers[2] + '.' + ipnumbers[3] + + # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 + # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False + cmd = 'hostname -I' + ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') + if ret.stdout is not None: + EPC_Iperf_UE_IPAddress = ret.stdout.strip() + port = 5001 + idx + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if udpIperf: + self.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + else: + self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + self.close() + else: + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + if udpIperf: + cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + else: + cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + logging.debug(cmd) + subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') + time.sleep(0.5) + + # Launch iperf client on UE + if (device_id == 'OAI-UE'): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + else: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + iperf_time = self.Iperf_ComputeTime() + time.sleep(0.5) + + if udpIperf: + modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) + else: + modified_options = str(self.iperf_args) + modified_options = modified_options.replace('-R','') + time.sleep(0.5) + + self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if (device_id == 'OAI-UE'): + iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + if self.ADBCentralized: + iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # TIMEOUT Case + if iperf_status < 0: + self.close() + message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) + self.close() + + # Kill iperf server on EPC side + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) + self.close() + else: + cmd = 'killall --signal SIGKILL iperf' + logging.debug(cmd) + subprocess.run(cmd, shell=True) + time.sleep(1) + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + # in case of failure, retrieve server log + if (clientStatus == -1) or (clientStatus == -2): + if launchFromEpc: + time.sleep(1) + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') + self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + # in case of OAI-UE + if (device_id == 'OAI-UE'): + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + + def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): + try: + # Single-UE profile -- iperf only on one UE + if self.iperf_profile == 'single-ue' and idx != 0: + return + useIperf3 = False + udpIperf = True + + self.ueIperfVersion = '2.0.5' + if (device_id != 'OAI-UE'): + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it + self.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + # Checking if iperf / iperf3 are installed + if self.ADBCentralized: + self.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) + result = re.search('iperf3', str(self.ssh.before)) + if result is None: + result = re.search('iperf', str(self.ssh.before)) + if result is None: + message = 'Neither iperf nor iperf3 installed on UE!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + else: + if self.ADBCentralized: + self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' + else: + useIperf3 = True + self.close() + else: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('iperf --version', '\$', 5) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' + self.close() + # in case of iperf, UL has its own function + if (not useIperf3): + result = re.search('-R', str(self.iperf_args)) + if result is not None: + self.Iperf_UL_common(lock, UE_IPAddress, device_id, idx, ue_num, statusQueue) + return + + # Launch the IPERF server on the UE side for DL + if (device_id == 'OAI-UE'): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('-u', str(self.iperf_args)) + if result is None: + self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + udpIperf = False + else: + self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + else: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + if self.ADBCentralized: + if (useIperf3): + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) + else: + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('-u', str(self.iperf_args)) + if result is None: + self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + udpIperf = False + else: + self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + else: + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) + + time.sleep(0.5) + self.close() + + # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + iperf_time = self.Iperf_ComputeTime() + time.sleep(0.5) + + if udpIperf: + modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) + else: + modified_options = str(self.iperf_args) + time.sleep(0.5) + + if launchFromEpc: + self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + else: + if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') + if (useIperf3): + self.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + + clientStatus = 0 + self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) + else: + if launchFromEpc: + iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + iperf_status = ret.returncode + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if iperf_status < 0: + if launchFromEpc: + self.close() + message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) + self.close() + + # Kill the IPERF server that runs in background + if (device_id == 'OAI-UE'): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('killall iperf', '\$', 5) + else: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) + result = re.search('shell +(?P\d+)', str(self.ssh.before)) + if result is not None: + pid_iperf = result.group('pid') + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + self.close() + # if the client report is absent, try to analyze the server log file + if (clientStatus == -1): + time.sleep(1) + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') + if (device_id == 'OAI-UE'): + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + else: + self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + + # in case of OAI UE: + if (device_id == 'OAI-UE'): + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + if not launchFromEpc: + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + else: + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def IperfNoS1(self): + if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = True + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + server_on_enb = re.search('-R', str(self.iperf_args)) + if server_on_enb is not None: + iServerIPAddr = self.eNBIPAddress + iServerUser = self.eNBUserName + iServerPasswd = self.eNBPassword + iClientIPAddr = self.UEIPAddress + iClientUser = self.UEUserName + iClientPasswd = self.UEPassword + else: + iServerIPAddr = self.UEIPAddress + iServerUser = self.UEUserName + iServerPasswd = self.UEPassword + iClientIPAddr = self.eNBIPAddress + iClientUser = self.eNBUserName + iClientPasswd = self.eNBPassword + # Starting the iperf server + self.open(iServerIPAddr, iServerUser, iServerPasswd) + # args SHALL be "-c client -u any" + # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 + # -B 10.0.1.1 -u -s -i 1 -fm + server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) + server_options = server_options.replace('-c','-B') + self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) + self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) + time.sleep(0.5) + self.close() + + # Starting the iperf client + modified_options = self.Iperf_ComputeModifiedBW(0, 1) + modified_options = modified_options.replace('-R','') + iperf_time = self.Iperf_ComputeTime() + self.open(iClientIPAddr, iClientUser, iClientPasswd) + self.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) + iperf_status = self.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) + status_queue = SimpleQueue() + lock = Lock() + if iperf_status < 0: + message = 'iperf on OAI UE crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + clientStatus = -2 + else: + clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + self.close() + + # Stopping the iperf server + self.open(iServerIPAddr, iServerUser, iServerPasswd) + self.command('killall --signal SIGKILL iperf', '\$', 5) + time.sleep(0.5) + self.close() + if (clientStatus == -1): + if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '.log') + self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + + # copying on the EPC server for logCollection + copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + copyin_res = self.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + iperf_noperf = False + if status_queue.empty(): + iperf_status = False + else: + iperf_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + iperf_status = False + if (count > 0): + iperf_noperf = True + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (iperf_noperf and iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + elif (iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def Iperf(self): + result = re.search('noS1', str(self.Initialize_eNB_args)) + if result is not None: + self.IperfNoS1() + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + check_OAI_UE = True + else: + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB() + return + + self.dummyIperfVersion = '2.0.10' + #cmd = 'iperf --version' + #logging.debug(cmd + '\n') + #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) + #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.5' + #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.10' + + multi_jobs = [] + i = 0 + ue_num = len(self.UEIPAddresses) + lock = Lock() + status_queue = SimpleQueue() + for UE_IPAddress in self.UEIPAddresses: + device_id = self.UEDevices[i] + p = Process(target = SSH.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + iperf_status = True + iperf_noperf = False + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + iperf_status = False + if (count > 0): + iperf_noperf = True + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (iperf_noperf and iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + elif (iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def CheckProcessExist(self, check_eNB, check_OAI_UE): + multi_jobs = [] + status_queue = SimpleQueue() + # in noS1 config, no need to check status from EPC + result = re.search('noS1', str(self.Initialize_eNB_args)) + if result is None: + p = Process(target = SSH.CheckHSSProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + p = Process(target = SSH.CheckMMEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + p = Process(target = SSH.CheckSPGWProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + else: + if (check_eNB == False) and (check_OAI_UE == False): + return 0 + if check_eNB: + p = Process(target = SSH.CheckeNBProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + if check_OAI_UE: + p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + return -15 + else: + result = 0 + while (not status_queue.empty()): + status = status_queue.get() + if (status < 0): + result = status + if result == ENB_PROCESS_FAILED: + fileCheck = re.search('enb_', str(self.eNBLogFiles[0])) + if fileCheck is not None: + self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') + logStatus = self.AnalyzeLogFile_eNB(self.eNBLogFiles[0]) + if logStatus < 0: + result = logStatus + self.eNBLogFiles[0] = '' + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.TerminateFlexranCtrl() + return result + + def CheckOAIUEProcessExist(self, initialize_OAI_UE_flag): + multi_jobs = [] + status_queue = SimpleQueue() + if initialize_OAI_UE_flag == False: + p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + return -15 + else: + result = 0 + while (not status_queue.empty()): + status = status_queue.get() + if (status < 0): + result = status + if result == OAI_UE_PROCESS_FAILED: + fileCheck = re.search('ue_', str(self.UELogFile)) + if fileCheck is not None: + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + logStatus = self.AnalyzeLogFile_UE(self.UELogFile) + if logStatus < 0: + result = logStatus + return result + + def CheckOAIUEProcess(self, status_queue): + try: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') + status_queue.put(OAI_UE_PROCESS_FAILED) + else: + status_queue.put(OAI_UE_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckeNBProcess(self, status_queue): + try: + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') + status_queue.put(ENB_PROCESS_FAILED) + else: + status_queue.put(ENB_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckHSSProcess(self, status_queue): + try: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + result = re.search('oai_hss -j', str(self.ssh.before)) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + result = re.search('hss_sim s6as diam_hss', str(self.ssh.before)) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m HSS Process Not Found! \u001B[0m') + status_queue.put(HSS_PROCESS_FAILED) + else: + status_queue.put(HSS_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckMMEProcess(self, status_queue): + try: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + result = re.search('mme -c', str(self.ssh.before)) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + result = re.search('mme', str(self.ssh.before)) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m MME Process Not Found! \u001B[0m') + status_queue.put(MME_PROCESS_FAILED) + else: + status_queue.put(MME_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckSPGWProcess(self, status_queue): + try: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + result = re.search('spgwu -c ', str(self.ssh.before)) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) + result = re.search('xGw', str(self.ssh.before)) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m SPGW Process Not Found! \u001B[0m') + status_queue.put(SPGW_PROCESS_FAILED) + else: + status_queue.put(SPGW_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AnalyzeLogFile_eNB(self, eNBlogFile): + if (not os.path.isfile('./' + eNBlogFile)): + return -1 + enb_log_file = open('./' + eNBlogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + rrcSetupComplete = 0 + rrcReleaseRequest = 0 + rrcReconfigRequest = 0 + rrcReconfigComplete = 0 + rrcReestablishRequest = 0 + rrcReestablishComplete = 0 + rrcReestablishReject = 0 + rlcDiscardBuffer = 0 + rachCanceledProcedure = 0 + uciStatMsgCount = 0 + pdcpFailure = 0 + ulschFailure = 0 + cdrxActivationMessageCount = 0 + dropNotEnoughRBs = 0 + self.htmleNBFailureMsg = '' + isRRU = False + isSlave = False + slaveReceivesFrameResyncCmd = False + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures = 0 + X2HO_outNbProcedures = 0 + for line in enb_log_file.readlines(): + if X2HO_state == X2_HO_REQ_STATE__IDLE: + result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ + result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK + if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: + result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE + if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: + result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ + if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: + result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures += 1 + if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: + result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_outNbProcedures += 1 + + if self.eNBOptions[int(self.eNB_instance)] != '': + res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) + res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) + if res1 is not None and res2 is not None: + requested_option = int(res1.group('requested_option')) + applied_option = int(res2.group('applied_option')) + if requested_option == applied_option: + self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + else: + self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('[Ss]egmentation [Ff]ault', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./lte_build_oai/build/lte-softmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('Setting function for RU', str(line)) + if result is not None: + isRRU = True + if isRRU: + result = re.search('RU 0 is_slave=yes', str(line)) + if result is not None: + isSlave = True + if isSlave: + result = re.search('Received RRU_frame_resynch command', str(line)) + if result is not None: + slaveReceivesFrameResyncCmd = True + result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) + if result is not None: + rrcSetupComplete += 1 + result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) + if result is not None: + rrcReleaseRequest += 1 + result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) + if result is not None: + rrcReconfigRequest += 1 + result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) + if result is not None: + rrcReconfigComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) + if result is not None: + rrcReestablishRequest += 1 + result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) + if result is not None: + rrcReestablishComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) + if result is not None: + rrcReestablishReject += 1 + result = re.search('CDRX configuration activated after RRC Connection', str(line)) + if result is not None: + cdrxActivationMessageCount += 1 + result = re.search('uci->stat', str(line)) + if result is not None: + uciStatMsgCount += 1 + result = re.search('PDCP.*Out of Resources.*reason', str(line)) + if result is not None: + pdcpFailure += 1 + result = re.search('ULSCH in error in round', str(line)) + if result is not None: + ulschFailure += 1 + result = re.search('BAD all_segments_received', str(line)) + if result is not None: + rlcDiscardBuffer += 1 + result = re.search('Canceled RA procedure for UE rnti', str(line)) + if result is not None: + rachCanceledProcedure += 1 + result = re.search('dropping, not enough RBs', str(line)) + if result is not None: + dropNotEnoughRBs += 1 + enb_log_file.close() + logging.debug(' File analysis completed') + if uciStatMsgCount > 0: + statMsg = 'eNB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if pdcpFailure > 0: + statMsg = 'eNB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if ulschFailure > 0: + statMsg = 'eNB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if dropNotEnoughRBs > 0: + statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if rrcSetupComplete > 0: + rrcMsg = 'eNB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReleaseRequest > 0: + rrcMsg = 'eNB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: + rrcMsg = 'eNB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: + rrcMsg = 'eNB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_inNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_outNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if self.eNBOptions[int(self.eNB_instance)] != '': + res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) + if res1 is not None: + if cdrxActivationMessageCount > 0: + rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + else: + rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' + logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rachCanceledProcedure > 0: + rachMsg = 'eNB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' + logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rachMsg + '\n' + if isRRU: + if isSlave: + if slaveReceivesFrameResyncCmd: + rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + else: + rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + self.prematureExit = True + return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED + if foundSegFault: + logging.debug('\u001B[1;37;41m eNB ended with a Segmentation Fault! \u001B[0m') + return ENB_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;37;41m eNB ended with an assertion! \u001B[0m') + self.htmleNBFailureMsg += msgAssertion + return ENB_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m eNB faced real time issues! \u001B[0m') + self.htmleNBFailureMsg += 'eNB faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if rlcDiscardBuffer > 0: + rlcMsg = 'eNB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' + logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rlcMsg + '\n' + return ENB_PROCESS_REALTIME_ISSUE + return 0 + + def AnalyzeLogFile_UE(self, UElogFile): + if (not os.path.isfile('./' + UElogFile)): + return -1 + ue_log_file = open('./' + UElogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + uciStatMsgCount = 0 + pdcpDataReqFailedCount = 0 + badDciCount = 0 + rrcConnectionRecfgComplete = 0 + no_cell_sync_found = False + mib_found = False + frequency_found = False + plmn_found = False + self.htmlUEFailureMsg = '' + for line in ue_log_file.readlines(): + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./lte-uesoftmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('uci->stat', str(line)) + if result is not None and not exitSignalReceived: + uciStatMsgCount += 1 + result = re.search('PDCP data request failed', str(line)) + if result is not None and not exitSignalReceived: + pdcpDataReqFailedCount += 1 + result = re.search('bad DCI 1A', str(line)) + if result is not None and not exitSignalReceived: + badDciCount += 1 + result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) + if result is not None: + rrcConnectionRecfgComplete += 1 + # No cell synchronization found, abandoning + result = re.search('No cell synchronization found, abandoning', str(line)) + if result is not None: + no_cell_sync_found = True + result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) + if result is not None and (not mib_found): + try: + mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " nidcell = " + result.group('nidcell') + self.htmlUEFailureMsg += mibMsg + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " n_rb_dl = " + result.group('n_rb_dl') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " phich_duration = " + result.group('phich_duration') + self.htmlUEFailureMsg += mibMsg + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " phich_resource = " + result.group('phich_resource') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " tx_ant = " + result.group('tx_ant') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mib_found = True + except Exception as e: + logging.error('\033[91m' + "MIB marker was not found" + '\033[0m') + result = re.search("Measured Carrier Frequency (?P\d{1,15}) Hz", str(line)) + if result is not None and (not frequency_found): + try: + mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + frequency_found = True + except Exception as e: + logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') + result = re.search("PLMN MCC (?P\d{1,3}), MNC (?P\d{1,3}), TAC", str(line)) + if result is not None and (not plmn_found): + try: + mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + plmn_found = True + except Exception as e: + logging.error('\033[91m' + "PLMN not found" + '\033[0m') + result = re.search("Found (?P[\w,\s]{1,15}) \(name from internal table\)", str(line)) + if result is not None: + try: + mibMsg = "The operator is: " + result.group('operator') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + except Exception as e: + logging.error('\033[91m' + "Operator name not found" + '\033[0m') + result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line)) + if result is not None: + try: + mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) + self.htmlUEFailureMsg += mibMsg + ' -> ' + logging.debug('\033[94m' + mibMsg + '\033[0m') + except Exception as e: + logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') + result = re.search("DL Carrier Frequency/ARFCN : (?P\d{1,15}/\d{1,4})", str(line)) + if result is not None: + try: + freq = result.group('carrier_frequency') + new_freq = re.sub('/[0-9]+','',freq) + float_freq = float(new_freq) / 1000000 + self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' + logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') + except Exception as e: + logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') + result = re.search("AllowedMeasBandwidth : (?P\d{1,7})", str(line)) + if result is not None: + try: + prb = result.group('allowed_bandwidth') + self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' + logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') + except Exception as e: + logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') + ue_log_file.close() + if rrcConnectionRecfgComplete > 0: + statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' + logging.debug('\033[94m' + statMsg + '\033[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if uciStatMsgCount > 0: + statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if pdcpDataReqFailedCount > 0: + statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if badDciCount > 0: + statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1A" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if foundSegFault: + logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') + return ENB_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') + self.htmlUEFailureMsg += 'UE showed an assertion!\n' + if not mib_found or not frequency_found: + return OAI_UE_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') + self.htmlUEFailureMsg += 'UE faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if no_cell_sync_found and not mib_found: + logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') + self.htmlUEFailureMsg += 'UE could not synchronize!\n' + return OAI_UE_PROCESS_COULD_NOT_SYNC + return 0 + + def TerminateeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(lIpAddr, lUserName, lPassWord) + self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) + time.sleep(10) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) + time.sleep(5) + self.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.close() + # If tracer options is on, stopping tshark on EPC side + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + time.sleep(1) + if self.EPC_PcapFileName != '': + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + self.close() + logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') + self.open(lIpAddr, lUserName, lPassWord) + self.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) + enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] + raw_record_file = enbLogFile.replace('.log', '_record.raw') + replay_log_file = enbLogFile.replace('.log', '_replay.log') + extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') + extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') + self.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) + self.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) + self.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) + self.close() + self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') + logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBLogFiles[int(self.eNB_instance)] = '' + else: + analyzeFile = False + if self.eNBLogFiles[int(self.eNB_instance)] != '': + analyzeFile = True + fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] + self.eNBLogFiles[int(self.eNB_instance)] = '' + if analyzeFile: + copyin_res = self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy eNB logfile to analyze it! \u001B[0m') + self.htmleNBFailureMsg = 'Could not copy eNB logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + return + if self.eNB_serverId != '0': + self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') + logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m ' + fileToAnalyze) + logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) + if (logStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', logStatus) + self.preamtureExit = True + return + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateHSS(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + result = re.search('oai_hss -j', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) + self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) + time.sleep(1) + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) + else: + logging.error('This should not happen!') + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateMME(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) + result = re.search('mme -c', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) + self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) + else: + logging.error('This should not happen!') + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateSPGW(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + result = re.search('spgwc -c |spgwu -c ', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) + self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) + self.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) + result = re.search('-w ', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) + else: + logging.error('This should not happen!') + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateFlexranCtrl(self): + if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) + time.sleep(1) + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) + time.sleep(1) + self.close() + self.flexranCtrlStarted = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # back in airplane mode on (ie radio off) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') + + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) + result = re.search('shell +(?P\d+)', str(self.ssh.before)) + if result is not None: + pid_iperf = result.group('pid') + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def TerminateUE(self): + terminate_ue_flag = True + self.GetAllUEDevices(terminate_ue_flag) + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target= SSH.TerminateUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateOAIUE(self): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) + time.sleep(10) + self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) + time.sleep(5) + self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.close() + result = re.search('ue_', str(self.UELogFile)) + if result is not None: + copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') + self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + self.UELogFile = '' + return + logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_UE(self.UELogFile) + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is not None: + ueAction = 'Sniffing' + else: + ueAction = 'Connection' + if (logStatus < 0): + logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') + self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg + self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') + # In case of sniffing on commercial eNBs we have random results + # Not an error then + if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): + self.Initialize_OAI_UE_args = '' + self.AutoTerminateUEandeNB() + else: + logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') + self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.UELogFile = '' + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def AutoTerminateUEandeNB(self): + if (self.ADBIPAddress != 'none'): + self.testCase_id = 'AUTO-KILL-UE' + self.desc = 'Automatic Termination of UE' + self.ShowTestID() + self.TerminateUE() + if (self.Initialize_OAI_UE_args != ''): + self.testCase_id = 'AUTO-KILL-UE' + self.desc = 'Automatic Termination of UE' + self.ShowTestID() + self.TerminateOAIUE() + if (self.Initialize_eNB_args != ''): + self.testCase_id = 'AUTO-KILL-eNB' + self.desc = 'Automatic Termination of eNB' + self.ShowTestID() + self.eNB_instance = '0' + self.TerminateeNB() + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.testCase_id = 'AUTO-KILL-flexran-ctl' + self.desc = 'Automatic Termination of FlexRan CTL' + self.ShowTestID() + self.TerminateFlexranCtrl() + self.prematureExit = True + + def IdleSleep(self): + time.sleep(self.idle_sleep_time) + self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) + + def X2_Status(self, idx, fileName): + cmd = "curl --silent http://" + self.EPCIPAddress + ":9999/stats | jq '.' > " + fileName + message = cmd + '\n' + logging.debug(cmd) + subprocess.run(cmd, shell=True) + if idx == 0: + cmd = "jq '.mac_stats | length' " + fileName + strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2NbENBs = int(strNbEnbs.strip()) + cnt = 0 + while cnt < self.x2NbENBs: + cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName + bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2ENBBsIds[idx].append(bs_id.strip()) + cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName + stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) + nbUEs = int(stNbUEs.strip()) + ueIdx = 0 + self.x2ENBConnectedUEs[idx].append([]) + while ueIdx < nbUEs: + cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName + rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip()) + ueIdx += 1 + cnt += 1 + + msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" + logging.debug(msg) + message += msg + '\n' + cnt = 0 + while cnt < self.x2NbENBs: + msg = " -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][cnt])) + " UE(s)" + logging.debug(msg) + message += msg + '\n' + ueIdx = 0 + while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]): + msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx]) + logging.debug(msg) + message += msg + '\n' + ueIdx += 1 + cnt += 1 + return message + + def Perform_X2_Handover(self): + html_queue = SimpleQueue() + fullMessage = '
'
+		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
+		logging.debug(msg)
+		fullMessage += msg + '\n'
+		if self.x2_ho_options == 'network':
+			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
+				self.x2ENBBsIds = []
+				self.x2ENBConnectedUEs = []
+				self.x2ENBBsIds.append([])
+				self.x2ENBBsIds.append([])
+				self.x2ENBConnectedUEs.append([])
+				self.x2ENBConnectedUEs.append([])
+				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
+
+				msg = "Activating the X2 Net control on each eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				eNB_cnt = self.x2NbENBs
+				cnt = 0
+				while cnt < eNB_cnt:
+					cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1"
+					logging.debug(cmd)
+					fullMessage += cmd + '\n'
+					subprocess.run(cmd, shell=True)
+					cnt += 1
+				# Waiting for the activation to be active
+				time.sleep(10)
+				msg = "Switching UE(s) from eNB to eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				cnt = 0
+				while cnt < eNB_cnt:
+					ueIdx = 0
+					while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]):
+						cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
+						logging.debug(cmd)
+						fullMessage += cmd + '\n'
+						subprocess.run(cmd, shell=True)
+						ueIdx += 1
+					cnt += 1
+				time.sleep(10)
+				# check
+				logging.debug("Checking the Status after X2 Handover")
+				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
+				cnt = 0
+				x2Status = True
+				while cnt < eNB_cnt:
+					if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
+						x2Status = False
+					cnt += 1
+				if x2Status:
+					msg = "X2 Handover was successful"
+					logging.debug(msg)
+					fullMessage += msg + '
' + html_queue.put(fullMessage) + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + else: + msg = "X2 Handover FAILED" + logging.error(msg) + fullMessage += msg + '' + html_queue.put(fullMessage) + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) + + def LogCollectBuild(self): + if (self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != ''): + IPAddress = self.eNBIPAddress + UserName = self.eNBUserName + Password = self.eNBPassword + SourceCodePath = self.eNBSourceCodePath + elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + SourceCodePath = self.UESourceCodePath + else: + sys.exit('Insufficient Parameter') + self.open(IPAddress, UserName, Password) + self.command('cd ' + SourceCodePath, '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('rm -f build.log.zip', '\$', 5) + self.command('zip build.log.zip build_log_*/*', '\$', 60) + self.close() + + def LogCollecteNB(self): + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath, '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) + self.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) + self.close() + + def LogCollectPing(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('rm -f ping.log.zip', '\$', 5) + self.command('zip ping.log.zip ping*.log', '\$', 60) + self.command('rm ping*.log', '\$', 5) + self.close() + + def LogCollectIperf(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('rm -f iperf.log.zip', '\$', 5) + self.command('zip iperf.log.zip iperf*.log', '\$', 60) + self.command('rm iperf*.log', '\$', 5) + self.close() + + def LogCollectHSS(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f hss.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip hss.log.zip hss*.log', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) + self.command('zip hss.log.zip hss.log', '\$', 60) + else: + logging.error('This option should not occur!') + self.close() + + def LogCollectMME(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f mme.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip mme.log.zip mme*.log', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) + self.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) + else: + logging.error('This option should not occur!') + self.close() + + def LogCollectSPGW(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f spgw.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip spgw.log.zip spgw*.log', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) + self.command('zip spgw.log.zip xGwLog.0', '\$', 60) + else: + logging.error('This option should not occur!') + self.close() + + def LogCollectOAIUE(self): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath, '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) + self.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) + self.close() + + def RetrieveSystemVersion(self, machine): + if self.eNBIPAddress == 'none' or self.UEIPAddress == 'none': + self.OsVersion = 'Ubuntu 16.04.5 LTS' + self.KernelVersion = '4.15.0-45-generic' + self.UhdVersion = '3.13.0.1-0' + self.UsrpBoard = 'B210' + self.CpuNb = '4' + self.CpuModel = 'Intel(R) Core(TM) i5-6200U' + self.CpuMHz = '2399.996 MHz' + return 0 + if machine == 'eNB': + if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': + IPAddress = self.eNBIPAddress + UserName = self.eNBUserName + Password = self.eNBPassword + else: + return -1 + if machine == 'UE': + if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + else: + return -1 + + self.open(IPAddress, UserName, Password) + self.command('lsb_release -a', '\$', 5) + result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) + if result is not None: + self.OsVersion = result.group('os_type') + logging.debug('OS is: ' + self.OsVersion) + self.command('uname -r', '\$', 5) + result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', str(self.ssh.before)) + if result is not None: + self.KernelVersion = result.group('kernel_version') + logging.debug('Kernel Version is: ' + self.KernelVersion) + self.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) + result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', str(self.ssh.before)) + if result is not None: + self.UhdVersion = result.group('uhd_version') + logging.debug('UHD Version is: ' + self.UhdVersion) + self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) + result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) + if result is not None: + self.UsrpBoard = result.group('usrp_board') + logging.debug('USRP Board is: ' + self.UsrpBoard) + self.command('lscpu', '\$', 5) + result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', str(self.ssh.before)) + if result is not None: + self.CpuNb = result.group('nb_cpus') + logging.debug('nb_cpus: ' + self.CpuNb) + self.CpuModel = result.group('model') + logging.debug('model: ' + self.CpuModel) + self.CpuMHz = result.group('cpu_mhz') + ' MHz' + logging.debug('cpu_mhz: ' + self.CpuMHz) + self.close() + +#----------------------------------------------------------- +# HTML Reporting.... +#----------------------------------------------------------- + def CreateHtmlHeader(self): + if (not self.htmlHeaderCreated): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML header \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + self.htmlFile = open('test_results.html', 'w') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') + self.htmlFile.write('\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if self.ranAllowMerge != '': + commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + self.ranCommitID, shell=True, universal_newlines=True) + commit_message = commit_message.strip() + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranTargetBranch == ''): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + self.ranRepository + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + self.ranBranch + '
Source Commit ID Commit ID ' + self.ranCommitID + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + self.ranTargetBranch + '
\n') + + if (self.ADBIPAddress != 'none'): + terminate_ue_flag = True + self.GetAllUEDevices(terminate_ue_flag) + self.GetAllCatMDevices(terminate_ue_flag) + self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') + self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') + else: + self.UEDevices.append('OAI-UE') + self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.close() + + def CreateHtmlTabHeader(self): + if (not self.htmlHeaderCreated): + if (not os.path.isfile('test_results.html')): + self.CreateHtmlHeader() + self.htmlFile = open('test_results.html', 'a') + if (self.nbTestXMLfiles == 1): + self.htmlFile.write('
\n') + self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') + else: + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.htmlUEConnected == -1): + terminate_ue_flag = True + if (self.ADBIPAddress != 'none'): + self.GetAllUEDevices(terminate_ue_flag) + self.GetAllCatMDevices(terminate_ue_flag) + else: + self.UEDevices.append('OAI-UE') + self.htmlUEConnected = len(self.UEDevices) + + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' \n') + i += 1 + self.htmlFile.write(' \n') + self.htmlHeaderCreated = True + + def CreateHtmlTabFooter(self, passStatus): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') + self.htmlFile.write('
\n') + self.htmlFile.close() + time.sleep(1) + if passStatus: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" + subprocess.run(cmd, shell=True) + else: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" + subprocess.run(cmd, shell=True) + self.htmlFooterCreated = False + + def CreateHtmlFooter(self, passStatus): + if (os.path.isfile('test_results.html')): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML footer \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + + self.htmlFile = open('test_results.html', 'a') + self.htmlFile.write('
\n') + self.htmlFile.write('

\n') + self.htmlFile.write(' \n') + + machines = [ 'eNB', 'UE' ] + for machine in machines: + res = self.RetrieveSystemVersion(machine) + if res == -1: + continue + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') + self.htmlFile.write('

\n') + self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('\n') + self.htmlFile.close() + + def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + currentTime = int(round(time.time() * 1000)) - self.startTime + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + if (processesStatus == 0): + self.htmlFile.write(' ' + str(status) + '\n') + elif (processesStatus == ENB_PROCESS_FAILED): + self.htmlFile.write(' KO - eNB process not found\n') + elif (processesStatus == OAI_UE_PROCESS_FAILED): + self.htmlFile.write(' KO - OAI UE process not found\n') + elif (processesStatus == ENB_PROCESS_SEG_FAULT): + self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') + elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): + self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') + elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): + self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') + elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): + self.htmlFile.write(' OK?\n') + elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): + self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') + elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + self.htmlFile.write(' KO - UE could not sync\n') + elif (processesStatus == HSS_PROCESS_FAILED): + self.htmlFile.write(' KO - HSS process not found\n') + elif (processesStatus == MME_PROCESS_FAILED): + self.htmlFile.write(' KO - MME process not found\n') + elif (processesStatus == SPGW_PROCESS_FAILED): + self.htmlFile.write(' KO - SPGW process not found\n') + elif (processesStatus == UE_IP_ADDRESS_ISSUE): + self.htmlFile.write(' KO - Could not retrieve UE IP address\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + if (len(str(self.htmleNBFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') + self.htmleNBFailureMsg = '' + elif (len(str(self.htmlUEFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') + self.htmlUEFailureMsg = '' + else: + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + + def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + currentTime = int(round(time.time() * 1000)) - self.startTime + addOrangeBK = False + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + self.htmlFile.write(' ' + str(status) + '\n') + else: + addOrangeBK = True + self.htmlFile.write(' ' + str(status) + '\n') + i = 0 + while (i < self.htmlUEConnected): + if (i < ue_status): + if (not ue_queue.empty()): + if (addOrangeBK): + self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') + else: + self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') + else: + self.htmlFile.write(' -\n') + else: + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + +#----------------------------------------------------------- +# ShowTestID() +#----------------------------------------------------------- + def ShowTestID(self): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1mTest ID:' + self.testCase_id + '\u001B[0m') + logging.debug('\u001B[1m' + self.desc + '\u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + +#----------------------------------------------------------- +# Usage() +#----------------------------------------------------------- +def Usage(): + print('----------------------------------------------------------------------------------------------------------------------') + print('main.py Ver:' + Version) + print('----------------------------------------------------------------------------------------------------------------------') + print('Usage: python main.py [options]') + print(' --help Show this help.') + print(' --mode=[Mode]') + print(' TesteNB') + print(' InitiateHtml, FinalizeHtml') + print(' TerminateeNB, TerminateUE, TerminateHSS, TerminateMME, TerminateSPGW') + print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf') + print('---------------------------------------------------------------------------------------------------- Git Options --') + print(' --ranRepository=[OAI RAN Repository URL]') + print(' --ranBranch=[OAI RAN Repository Branch]') + print(' --ranCommitID=[OAI RAN Repository Commit SHA-1]') + print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)]') + print(' --ranTargetBranch=[Target Branch in case of a Merge Request]') + print('--------------------------------------------------------------------------------------------- eNB Server Options --') + print(' --eNBIPAddress=[eNB\'s IP Address]') + print(' --eNBUserName=[eNB\'s Login User Name]') + print(' --eNBPassword=[eNB\'s Login Password]') + print(' --eNBSourceCodePath=[eNB\'s Source Code Path]') + print('------------------------------------------------------------------------------------------ OAI UE Server Options --') + print(' --UEIPAddress=[UE\'s IP Address]') + print(' --UEUserName=[UE\'s Login User Name]') + print(' --UEPassword=[UE\'s Login Password]') + print(' --UESourceCodePath=[UE\'s Source Code Path]') + print('--------------------------------------------------------------------------------------------- EPC Server Options --') + print(' --EPCIPAddress=[EPC\'s IP Address]') + print(' --EPCUserName=[EPC\'s Login User Name]') + print(' --EPCPassword=[EPC\'s Login Password]') + print(' --EPCSourceCodePath=[EPC\'s Source Code Path]') + print(' --EPCType=[EPC\'s Type: OAI or ltebox or OAI-Rel14-CUPS]') + print('--------------------------------------------------------------------------------------------- ABD Server Options --') + print(' --ADBIPAddress=[ADB\'s IP Address]') + print(' --ADBUserName=[ADB\'s Login User Name]') + print(' --ADBPassword=[ADB\'s Login Password]') + print('----------------------------------------------------------------------------------------------------------------------') + print(' --XMLTestFile=[XML Test File to be run]') + print('----------------------------------------------------------------------------------------------------------------------') + +def CheckClassValidity(action,id): + if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': + logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) + return False + return True + +def GetParametersFromXML(action): + if action == 'Build_eNB': + SSH.Build_eNB_args = test.findtext('Build_eNB_args') + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + xmlBgBuildField = test.findtext('backgroundBuild') + if (xmlBgBuildField is None): + SSH.backgroundBuild = False + else: + if re.match('true', xmlBgBuildField, re.IGNORECASE): + SSH.backgroundBuild = True + else: + SSH.backgroundBuild = False + + if action == 'WaitEndBuild_eNB': + SSH.Build_eNB_args = test.findtext('Build_eNB_args') + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + + if action == 'Initialize_eNB': + SSH.Initialize_eNB_args = test.findtext('Initialize_eNB_args') + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + + if action == 'Terminate_eNB': + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + + if action == 'Attach_UE': + nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') + if (nbMaxUEtoAttach is None): + SSH.nbMaxUEtoAttach = -1 + else: + SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach) + + if action == 'CheckStatusUE': + expectedNBUE = test.findtext('expectedNbOfConnectedUEs') + if (expectedNBUE is None): + SSH.expectedNbOfConnectedUEs = -1 + else: + SSH.expectedNbOfConnectedUEs = int(expectedNBUE) + + if action == 'Build_OAI_UE': + SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') + + if action == 'Initialize_OAI_UE': + SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') + SSH.UE_instance = test.findtext('UE_instance') + if (SSH.UE_instance is None): + SSH.UE_instance = '0' + + if action == 'Terminate_OAI_UE': + SSH.eNB_instance = test.findtext('UE_instance') + if (SSH.UE_instance is None): + SSH.UE_instance = '0' + + if action == 'Ping' or action == 'Ping_CatM_module': + SSH.ping_args = test.findtext('ping_args') + SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') + + if action == 'Iperf': + SSH.iperf_args = test.findtext('iperf_args') + SSH.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') + SSH.iperf_profile = test.findtext('iperf_profile') + if (SSH.iperf_profile is None): + SSH.iperf_profile = 'balanced' + else: + if SSH.iperf_profile != 'balanced' and SSH.iperf_profile != 'unbalanced' and SSH.iperf_profile != 'single-ue': + logging.debug('ERROR: test-case has wrong profile ' + SSH.iperf_profile) + SSH.iperf_profile = 'balanced' + + if action == 'IdleSleep': + string_field = test.findtext('idle_sleep_time_in_sec') + if (string_field is None): + SSH.idle_sleep_time = 5 + else: + SSH.idle_sleep_time = int(string_field) + + if action == 'Perform_X2_Handover': + string_field = test.findtext('x2_ho_options') + if (string_field is None): + SSH.x2_ho_options = 'network' + else: + if string_field != 'network': + logging.error('ERROR: test-case has wrong option ' + string_field) + SSH.x2_ho_options = 'network' + else: + SSH.x2_ho_options = string_field + + +#check if given test is in list +#it is in list if one of the strings in 'list' is at the beginning of 'test' +def test_in_list(test, list): + for check in list: + check=check.replace('+','') + if (test.startswith(check)): + return True + return False + +def receive_signal(signum, frame): + sys.exit(1) + +#----------------------------------------------------------- +# Parameter Check +#----------------------------------------------------------- +mode = '' +SSH = SSHConnection() + +argvs = sys.argv +argc = len(argvs) +cwd = os.getcwd() + +while len(argvs) > 1: + myArgv = argvs.pop(1) # 0th is this file's name + if re.match('^\-\-help$', myArgv, re.IGNORECASE): + Usage() + sys.exit(0) + elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) + mode = matchReg.group(1) + elif re.match('^\-\-eNBRepository=(.+)$|^\-\-ranRepository(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) + SSH.ranRepository = matchReg.group(1) + elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) + doMerge = matchReg.group(1) + if ((doMerge == 'true') or (doMerge == 'True')): + SSH.ranAllowMerge = True + elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) + SSH.ranBranch = matchReg.group(1) + elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) + SSH.ranCommitID = matchReg.group(1) + elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) + SSH.ranTargetBranch = matchReg.group(1) + elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBIPAddress = matchReg.group(1) + elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1IPAddress = matchReg.group(1) + elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2IPAddress = matchReg.group(1) + elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBUserName = matchReg.group(1) + elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1UserName = matchReg.group(1) + elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2UserName = matchReg.group(1) + elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBPassword = matchReg.group(1) + elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1Password = matchReg.group(1) + elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2Password = matchReg.group(1) + elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBSourceCodePath = matchReg.group(1) + elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1SourceCodePath = matchReg.group(1) + elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2SourceCodePath = matchReg.group(1) + elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCIPAddress = matchReg.group(1) + elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCBranch = matchReg.group(1) + elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCUserName = matchReg.group(1) + elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCPassword = matchReg.group(1) + elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCSourceCodePath = matchReg.group(1) + elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) + if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): + SSH.EPCType = matchReg.group(1) + else: + sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') + elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.ADBIPAddress = matchReg.group(1) + elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.ADBUserName = matchReg.group(1) + elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) + if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): + if re.match('distributed', matchReg.group(1), re.IGNORECASE): + SSH.ADBCentralized = False + else: + SSH.ADBCentralized = True + else: + sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') + elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.ADBPassword = matchReg.group(1) + elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) + SSH.testXMLfiles.append(matchReg.group(1)) + SSH.nbTestXMLfiles += 1 + elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.UEIPAddress = matchReg.group(1) + elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.UEUserName = matchReg.group(1) + elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.UEPassword = matchReg.group(1) + elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.UESourceCodePath = matchReg.group(1) +# reading repeatCounts from command line + elif re.match('^\-\-repeatCounts=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-repeatCounts=(.+)$', myArgv, re.IGNORECASE) + SSH.repeatCounts = int(matchReg.group(1)) + elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) + finalStatus = matchReg.group(1) + if ((finalStatus == 'true') or (finalStatus == 'True')): + SSH.finalStatus = True + else: + Usage() + sys.exit('Invalid Parameter: ' + myArgv) + +if re.match('^TerminateeNB$', mode, re.IGNORECASE): + if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.eNB_serverId = '0' + SSH.eNB_instance = '0' + SSH.eNBSourceCodePath = '/tmp/' + SSH.TerminateeNB() +elif re.match('^TerminateUE$', mode, re.IGNORECASE): + if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): + Usage() + sys.exit('Insufficient Parameter') + signal.signal(signal.SIGUSR1, receive_signal) + SSH.TerminateUE() +elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): + if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '': + Usage() + sys.exit('Insufficient Parameter') + signal.signal(signal.SIGUSR1, receive_signal) + SSH.TerminateOAIUE() +elif re.match('^TerminateHSS$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.TerminateHSS() +elif re.match('^TerminateMME$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.TerminateMME() +elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.TerminateSPGW() +elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): + if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == ''): + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectBuild() +elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): + if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollecteNB() +elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectHSS() +elif re.match('^LogCollectMME$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectMME() +elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectSPGW() +elif re.match('^LogCollectPing$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectPing() +elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectIperf() +elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): + if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectOAIUE() +elif re.match('^InitiateHtml$', mode, re.IGNORECASE): + if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): + Usage() + sys.exit('Insufficient Parameter') + count = 0 + foundCount = 0 + while (count < SSH.nbTestXMLfiles): + xml_test_file = cwd + "/" + SSH.testXMLfiles[count] + xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count] + if (os.path.isfile(xml_test_file)): + xmlTree = ET.parse(xml_test_file) + xmlRoot = xmlTree.getroot() + SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) + SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + foundCount += 1 + count += 1 + if foundCount != SSH.nbTestXMLfiles: + SSH.nbTestXMLfiles = foundCount + SSH.CreateHtmlHeader() +elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): + SSH.CreateHtmlFooter(SSH.finalStatus) +elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): + if re.match('^TesteNB$', mode, re.IGNORECASE): + if SSH.eNBIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + + if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): + SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") + SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") + else: + if SSH.UEIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + Usage() + sys.exit('UE: Insufficient Parameter') + + #read test_case_list.xml file + # if no parameters for XML file, use default value + if (SSH.nbTestXMLfiles != 1): + xml_test_file = cwd + "/test_case_list.xml" + else: + xml_test_file = cwd + "/" + SSH.testXMLfiles[0] + + xmlTree = ET.parse(xml_test_file) + xmlRoot = xmlTree.getroot() + + exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') + requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') + if (SSH.nbTestXMLfiles == 1): + SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) +# repeatCounts not read from the xml file +# repeatCount = xmlRoot.findtext('repeatCount',default='1') +# SSH.repeatCounts.append(int(repeatCount)) + all_tests=xmlRoot.findall('testCase') + + exclusion_tests=exclusion_tests.split() + requested_tests=requested_tests.split() + + #check that exclusion tests are well formatted + #(6 digits or less than 6 digits followed by +) + for test in exclusion_tests: + if (not re.match('^[0-9]{6}$', test) and + not re.match('^[0-9]{1,5}\+$', test)): + logging.debug('ERROR: exclusion test is invalidly formatted: ' + test) + sys.exit(1) + else: + logging.debug(test) + + #check that requested tests are well formatted + #(6 digits or less than 6 digits followed by +) + #be verbose + for test in requested_tests: + if (re.match('^[0-9]{6}$', test) or + re.match('^[0-9]{1,5}\+$', test)): + logging.debug('INFO: test group/case requested: ' + test) + else: + logging.debug('ERROR: requested test is invalidly formatted: ' + test) + sys.exit(1) + if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): + SSH.CheckFlexranCtrlInstallation() + + #get the list of tests to be done + todo_tests=[] + for test in requested_tests: + if (test_in_list(test, exclusion_tests)): + logging.debug('INFO: test will be skipped: ' + test) + else: + #logging.debug('INFO: test will be run: ' + test) + todo_tests.append(test) + + signal.signal(signal.SIGUSR1, receive_signal) + + SSH.CreateHtmlTabHeader() + + cnt = 0 + SSH.prematureExit = True + SSH.startTime = int(round(time.time() * 1000)) +# repeatCounts becomes an integer (was SSH.repeatCounts[0] --> becomes SSH.repeatCounts) + while cnt < SSH.repeatCounts and SSH.prematureExit: + SSH.prematureExit = False + for test_case_id in todo_tests: + if SSH.prematureExit: + break + for test in all_tests: + if SSH.prematureExit: + break + id = test.get('id') + if test_case_id != id: + continue + SSH.testCase_id = id + SSH.desc = test.findtext('desc') + action = test.findtext('class') + if (CheckClassValidity(action, id) == False): + continue + SSH.ShowTestID() + GetParametersFromXML(action) + if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': + if (SSH.ADBIPAddress != 'none'): + terminate_ue_flag = False + SSH.GetAllUEDevices(terminate_ue_flag) + if action == 'Build_eNB': + SSH.BuildeNB() + elif action == 'WaitEndBuild_eNB': + SSH.WaitBuildeNBisFinished() + elif action == 'Initialize_eNB': + SSH.InitializeeNB() + elif action == 'Terminate_eNB': + SSH.TerminateeNB() + elif action == 'Initialize_UE': + SSH.InitializeUE() + elif action == 'Terminate_UE': + SSH.TerminateUE() + elif action == 'Attach_UE': + SSH.AttachUE() + elif action == 'Detach_UE': + SSH.DetachUE() + elif action == 'DataDisable_UE': + SSH.DataDisableUE() + elif action == 'DataEnable_UE': + SSH.DataEnableUE() + elif action == 'CheckStatusUE': + SSH.CheckStatusUE() + elif action == 'Build_OAI_UE': + SSH.BuildOAIUE() + elif action == 'Initialize_OAI_UE': + SSH.InitializeOAIUE() + elif action == 'Terminate_OAI_UE': + SSH.TerminateOAIUE() + elif action == 'Initialize_CatM_module': + SSH.InitializeCatM() + elif action == 'Terminate_CatM_module': + SSH.TerminateCatM() + elif action == 'Attach_CatM_module': + SSH.AttachCatM() + elif action == 'Detach_CatM_module': + SSH.TerminateCatM() + elif action == 'Ping_CatM_module': + SSH.PingCatM() + elif action == 'Ping': + SSH.Ping() + elif action == 'Iperf': + SSH.Iperf() + elif action == 'Reboot_UE': + SSH.RebootUE() + elif action == 'Initialize_HSS': + SSH.InitializeHSS() + elif action == 'Terminate_HSS': + SSH.TerminateHSS() + elif action == 'Initialize_MME': + SSH.InitializeMME() + elif action == 'Terminate_MME': + SSH.TerminateMME() + elif action == 'Initialize_SPGW': + SSH.InitializeSPGW() + elif action == 'Terminate_SPGW': + SSH.TerminateSPGW() + elif action == 'Initialize_FlexranCtrl': + SSH.InitializeFlexranCtrl() + elif action == 'Terminate_FlexranCtrl': + SSH.TerminateFlexranCtrl() + elif action == 'IdleSleep': + SSH.IdleSleep() + elif action == 'Perform_X2_Handover': + SSH.Perform_X2_Handover() + else: + sys.exit('Invalid action') + cnt += 1 +# repeatCounts becomes an integer (was SSH.repeatCounts[0] --> becomes SSH.repeatCounts) + if cnt == SSH.repeatCounts and SSH.prematureExit: + logging.debug('Testsuite failed ' + str(cnt) + ' time(s)') + SSH.CreateHtmlTabFooter(False) + sys.exit('Failed Scenario') + else: + logging.info('Testsuite passed after ' + str(cnt) + ' time(s)') + SSH.CreateHtmlTabFooter(True) +else: + Usage() + sys.exit('Invalid mode') +sys.exit(0) From 75642c34c4f3ab9d90a130752a331464533a6b6e Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 9 Dec 2019 15:36:44 +0100 Subject: [PATCH 069/175] add a new main file for test with cnt changed into self.cnt --- ci-scripts/main-index-to-class.py | 4921 +++++++++++++++++++++++++++++ 1 file changed, 4921 insertions(+) create mode 100644 ci-scripts/main-index-to-class.py diff --git a/ci-scripts/main-index-to-class.py b/ci-scripts/main-index-to-class.py new file mode 100644 index 0000000000..04a31302ae --- /dev/null +++ b/ci-scripts/main-index-to-class.py @@ -0,0 +1,4921 @@ +# /* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + +#----------------------------------------------------------- +# Version +#----------------------------------------------------------- +Version = '0.1' + +#----------------------------------------------------------- +# Constants +#----------------------------------------------------------- +ALL_PROCESSES_OK = 0 +ENB_PROCESS_FAILED = -1 +ENB_PROCESS_OK = +1 +ENB_PROCESS_SEG_FAULT = -11 +ENB_PROCESS_ASSERTION = -12 +ENB_PROCESS_REALTIME_ISSUE = -13 +ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 +ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 +HSS_PROCESS_FAILED = -2 +HSS_PROCESS_OK = +2 +MME_PROCESS_FAILED = -3 +MME_PROCESS_OK = +3 +SPGW_PROCESS_FAILED = -4 +SPGW_PROCESS_OK = +4 +UE_IP_ADDRESS_ISSUE = -5 +OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 +OAI_UE_PROCESS_COULD_NOT_SYNC = -21 +OAI_UE_PROCESS_ASSERTION = -22 +OAI_UE_PROCESS_FAILED = -23 +OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 +OAI_UE_PROCESS_OK = +6 + +UE_STATUS_DETACHED = 0 +UE_STATUS_DETACHING = 1 +UE_STATUS_ATTACHING = 2 +UE_STATUS_ATTACHED = 3 + +X2_HO_REQ_STATE__IDLE = 0 +X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 +X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 +X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 +X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 + +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import sys # arg +import re # reg +import pexpect # pexpect +import time # sleep +import os +import subprocess +import xml.etree.ElementTree as ET +import logging +import datetime +import signal +from multiprocessing import Process, Lock, SimpleQueue +logging.basicConfig( + level=logging.DEBUG, + format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" +) + +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class SSHConnection(): + def __init__(self): + self.cnt = 0 # cnt from index to object of a class + self.prematureExit = False + self.ranRepository = '' + self.ranBranch = '' + self.ranAllowMerge = False + self.ranCommitID = '' + self.ranTargetBranch = '' + self.eNBIPAddress = '' + self.eNBUserName = '' + self.eNBPassword = '' + self.eNBSourceCodePath = '' + self.EPCIPAddress = '' + self.EPCUserName = '' + self.EPCPassword = '' + self.eNB1IPAddress = '' + self.eNB1UserName = '' + self.eNB1Password = '' + self.eNB1SourceCodePath = '' + self.eNB2IPAddress = '' + self.eNB2UserName = '' + self.eNB2Password = '' + self.eNB2SourceCodePath = '' + self.EPCSourceCodePath = '' + self.EPCType = '' + self.EPC_PcapFileName = '' + self.ADBIPAddress = '' + self.ADBUserName = '' + self.ADBPassword = '' + self.ADBCentralized = True + self.testCase_id = '' + self.testXMLfiles = [] + self.nbTestXMLfiles = 0 + self.desc = '' + self.Build_eNB_args = '' + self.backgroundBuild = False + self.backgroundBuildTestId = ['', '', ''] + self.Initialize_eNB_args = '' + self.eNB_instance = '' + self.eNB_serverId = '' + self.eNBLogFiles = ['', '', ''] + self.eNBOptions = ['', '', ''] + self.ping_args = '' + self.ping_packetloss_threshold = '' + self.iperf_args = '' + self.iperf_packetloss_threshold = '' + self.iperf_profile = '' + self.nbMaxUEtoAttach = -1 + self.UEDevices = [] + self.UEDevicesStatus = [] + self.UEDevicesRemoteServer = [] + self.UEDevicesRemoteUser = [] + self.UEDevicesOffCmd = [] + self.UEDevicesOnCmd = [] + self.UEDevicesRebootCmd = [] + self.CatMDevices = [] + self.UEIPAddresses = [] + self.htmlFile = '' + self.htmlHeaderCreated = False + self.htmlFooterCreated = False + self.htmlUEConnected = -1 + self.htmleNBFailureMsg = '' + self.htmlUEFailureMsg = '' + self.picocom_closure = False + self.idle_sleep_time = 0 + self.x2_ho_options = 'network' + self.x2NbENBs = 0 + self.x2ENBBsIds = [] + self.x2ENBConnectedUEs = [] + self.htmlTabRefs = [] + self.htmlTabNames = [] + self.htmlTabIcons = [] + self.repeatCounts = [] + self.finalStatus = False + self.OsVersion = '' + self.KernelVersion = '' + self.UhdVersion = '' + self.UsrpBoard = '' + self.CpuNb = '' + self.CpuModel = '' + self.CpuMHz = '' + self.UEIPAddress = '' + self.UEUserName = '' + self.UEPassword = '' + self.UE_instance = '' + self.UESourceCodePath = '' + self.UELogFile = '' + self.Build_OAI_UE_args = '' + self.Initialize_OAI_UE_args = '' + self.flexranCtrlInstalled = False + self.flexranCtrlStarted = False + self.expectedNbOfConnectedUEs = 0 + self.startTime = 0 + + def open(self, ipaddress, username, password): + count = 0 + connect_status = False + while count < 4: + self.ssh = pexpect.spawn('ssh', [username + '@' + ipaddress], timeout = 5) + self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + self.ssh.sendline('yes') + self.ssh.expect('password:') + self.ssh.sendline(password) + self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + count = 10 + connect_status = True + else: + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + elif self.sshresponse == 1: + self.ssh.sendline(password) + self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + count = 10 + connect_status = True + else: + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + elif self.sshresponse == 2: + # Checking if we are really on the remote client defined by its IP address + self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) + result = re.search(str(ipaddress), str(self.ssh.before)) + if result is None: + self.close() + else: + count = 10 + connect_status = True + else: + # debug output + logging.debug(str(self.ssh.before)) + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + # adding a tempo when failure + if not connect_status: + time.sleep(1) + count += 1 + if connect_status: + pass + else: + sys.exit('SSH Connection Failed') + + def command(self, commandline, expectedline, timeout): + logging.debug(commandline) + self.ssh.timeout = timeout + self.ssh.sendline(commandline) + self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + return 0 + elif self.sshresponse == 1: + logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + sys.exit(self.sshresponse) + elif self.sshresponse == 2: + logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + result = re.search('ping |iperf |picocom', str(commandline)) + if result is None: + logging.debug(str(self.ssh.before)) + sys.exit(self.sshresponse) + else: + return -1 + else: + logging.debug('\u001B[1;37;41m Unexpected Others \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + sys.exit(self.sshresponse) + + def close(self): + self.ssh.timeout = 5 + self.ssh.sendline('exit') + self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + pass + elif self.sshresponse == 1: + if not self.picocom_closure: + logging.debug('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') + + def copyin(self, ipaddress, username, password, source, destination): + count = 0 + copy_status = False + logging.debug('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination) + while count < 10: + scp_spawn = pexpect.spawn('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) + scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + scp_spawn.sendline('yes') + scp_spawn.expect('password:') + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + count = 10 + copy_status = True + else: + logging.debug('1 - scp_response = ' + str(scp_response)) + elif scp_response == 1: + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0 or scp_response == 3: + count = 10 + copy_status = True + else: + logging.debug('2 - scp_response = ' + str(scp_response)) + elif scp_response == 2: + count = 10 + copy_status = True + else: + logging.debug('3 - scp_response = ' + str(scp_response)) + # adding a tempo when failure + if not copy_status: + time.sleep(1) + count += 1 + if copy_status: + return 0 + else: + return -1 + + def copyout(self, ipaddress, username, password, source, destination): + count = 0 + copy_status = False + logging.debug('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination) + while count < 4: + scp_spawn = pexpect.spawn('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) + scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + scp_spawn.sendline('yes') + scp_spawn.expect('password:') + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + count = 10 + copy_status = True + else: + logging.debug('1 - scp_response = ' + str(scp_response)) + elif scp_response == 1: + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0 or scp_response == 3: + count = 10 + copy_status = True + else: + logging.debug('2 - scp_response = ' + str(scp_response)) + elif scp_response == 2: + count = 10 + copy_status = True + else: + logging.debug('3 - scp_response = ' + str(scp_response)) + # adding a tempo when failure + if not copy_status: + time.sleep(1) + count += 1 + if copy_status: + pass + else: + sys.exit('SCP failed') + + def BuildeNB(self): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + Usage() + sys.exit('Insufficient Parameter') + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(lIpAddr, lUserName, lPassWord) + self.command('mkdir -p ' + lSourcePath, '\$', 5) + self.command('cd ' + lSourcePath, '\$', 5) + self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) + # Raphael: here add a check if git clone or git fetch went smoothly + self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + self.command('git config user.name "OAI Jenkins"', '\$', 5) + # Checking the BUILD INFO file + if not self.backgroundBuild: + self.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) + if result is not None: + mismatch = False + self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(self.ranCommitID, str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + result = re.search('YES', str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + result = re.search('develop', str(self.ssh.before)) + else: + result = re.search(self.ranTargetBranch, str(self.ssh.before)) + if result is None: + mismatch = True + else: + result = re.search('NO', str(self.ssh.before)) + if result is None: + mismatch = True + if not mismatch: + self.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + return + + self.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + self.command('git checkout -f ' + self.ranCommitID, '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (self.ranAllowMerge): + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('mkdir -p log', '\$', 5) + self.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + if self.backgroundBuild: + self.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) + self.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) + self.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id + return + self.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) + + def WaitBuildeNBisFinished(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(lIpAddr, lUserName, lPassWord) + count = 40 + buildOAIprocess = True + while (count > 0) and buildOAIprocess: + self.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) + result = re.search('build_oai', str(self.ssh.before)) + if result is None: + buildOAIprocess = False + else: + count -= 1 + time.sleep(30) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) + + def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): + self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) + self.command('ls lte_build_oai/build', '\$', 3) + self.command('ls lte_build_oai/build', '\$', 3) + buildStatus = True + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is None: + buildStatus = False + else: + # Generating a BUILD INFO file + self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + self.command('mkdir -p build_log_' + testcaseId, '\$', 5) + self.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) + self.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) + if self.eNB_serverId != '0': + self.command('cd cmake_targets', '\$', 5) + self.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) + self.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) + self.close() + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + os.remove('./tmp_build' + testcaseId + '.zip') + self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') + os.remove('./tmp_build' + testcaseId + '.zip') + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) + self.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) + self.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) + self.close() + else: + self.close() + + if buildStatus: + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + else: + logging.error('\u001B[1m Building OAI eNB Failed\u001B[0m') + self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) + self.CreateHtmlTabFooter(False) + sys.exit(1) + + def BuildOAIUE(self): + if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) + self.command('cd ' + self.UESourceCodePath, '\$', 5) + self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) + # here add a check if git clone or git fetch went smoothly + self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + self.command('git config user.name "OAI Jenkins"', '\$', 5) + self.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) + if result is not None: + mismatch = False + self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(self.ranCommitID, str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + result = re.search('YES', str(self.ssh.before)) + if result is None: + mismatch = True + self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + result = re.search('develop', str(self.ssh.before)) + else: + result = re.search(self.ranTargetBranch, str(self.ssh.before)) + if result is None: + mismatch = True + else: + result = re.search('NO', str(self.ssh.before)) + if result is None: + mismatch = True + if not mismatch: + self.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + return + + self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + self.command('git checkout -f ' + self.ranCommitID, '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (self.ranAllowMerge): + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('mkdir -p log', '\$', 5) + self.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) + self.command('ls lte_build_oai/build', '\$', 3) + self.command('ls lte_build_oai/build', '\$', 3) + buildStatus = True + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is None: + buildStatus = False + self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) + self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) + self.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) + if buildStatus: + # Generating a BUILD INFO file + self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + self.close() + self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + else: + self.close() + logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') + self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') + self.CreateHtmlTabFooter(False) + sys.exit(1) + + def InitializeHSS(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') + EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) + self.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) + self.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) + self.command('chmod 755 ./my-hss.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC HSS') + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + logging.debug('Using the ltebox simulated HSS') + self.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + self.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('cd /opt/hss_sim0609', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + else: + logging.error('This option should not occur!') + self.close() + self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def InitializeMME(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 MME') + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) + self.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) + self.command('chmod 755 ./my-mme.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('stdbuf -o0 hostname', '\$', 5) + result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') + sys.exit(1) + host_name = result.group('host_name') + self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) + else: + logging.error('This option should not occur!') + self.close() + self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def InitializeSPGW(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) + self.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) + self.command('chmod 755 ./my-spgwc.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) + time.sleep(5) + self.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) + self.command('chmod 755 ./my-spgwu.sh', '\$', 5) + self.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) + else: + logging.error('This option should not occur!') + self.close() + self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def CheckFlexranCtrlInstallation(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + return + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) + result = re.search('/opt/flexran_rtc/build/rt_controller', str(self.ssh.before)) + if result is not None: + self.flexranCtrlInstalled = True + logging.debug('Flexran Controller is installed') + self.close() + + def InitializeFlexranCtrl(self): + if self.flexranCtrlInstalled == False: + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd /opt/flexran_rtc', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) + self.command('ps -aux | grep --color=never rt_controller', '\$', 5) + result = re.search('rt_controller -c ', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') + self.flexranCtrlStarted = True + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def InitializeeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = False + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) + result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', str(self.ssh.before)) + if result is not None: + eth_interface = result.group('eth_interface') + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') + self.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) + self.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + self.close() + self.open(lIpAddr, lUserName, lPassWord) + self.command('cd ' + lSourcePath, '\$', 5) + # Initialize_eNB_args usually start with -O and followed by the location in repository + full_config_file = self.Initialize_eNB_args.replace('-O ','') + extra_options = '' + extIdx = full_config_file.find('.conf') + if (extIdx > 0): + extra_options = full_config_file[extIdx + 5:] + # if tracer options is on, compiling and running T Tracer + result = re.search('T_stdout', str(extra_options)) + if result is not None: + logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') + self.command('cd common/utils/T/tracer', '\$', 5) + self.command('make', '\$', 10) + self.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) + self.command('cd ' + lSourcePath, '\$', 5) + full_config_file = full_config_file[:extIdx + 5] + config_path, config_file = os.path.split(full_config_file) + else: + sys.exit('Insufficient Parameter') + ci_full_config_file = config_path + '/ci-' + config_file + rruCheck = False + result = re.search('^rru|^rcc|^du.band', str(config_file)) + if result is not None: + rruCheck = True + # do not reset board twice in IF4.5 case + result = re.search('^rru|^enb|^du.band', str(config_file)) + if result is not None: + self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) + result = re.search('type: b200', str(self.ssh.before)) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + self.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 15) + # Make a copy and adapt to EPC / eNB IP addresses + self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) + self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + self.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); + else: + self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); + # Launch eNB with the modified config file + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' + if extra_options != '': + self.eNBOptions[int(self.eNB_instance)] = extra_options + time.sleep(6) + doLoop = True + loopCounter = 10 + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # In case of T tracer recording, we may need to kill it + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.command('killall --signal SIGKILL record', '\$', 5) + self.close() + doLoop = False + logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) + # In case of T tracer recording, we need to kill tshark on EPC side + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if self.EPC_PcapFileName != '': + time.sleep(0.5) + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + self.close() + time.sleep(1) + if self.EPC_PcapFileName != '': + copyin_res = self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + if (copyin_res == 0): + self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + self.prematureExit = True + return + else: + self.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) + if rruCheck: + result = re.search('wait RUs', str(self.ssh.before)) + else: + result = re.search('got sync|Starting F1AP at CU', str(self.ssh.before)) + if result is None: + time.sleep(6) + else: + doLoop = False + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') + time.sleep(10) + + self.close() + + def InitializeUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if not self.ADBCentralized: + # Reboot UE + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) + # Wait + #time.sleep(60) + # Put in LTE-Mode only + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) + # enable data service + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + # we need to do radio on/off cycle to make sure of above changes + # airplane mode off // radio on + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + #time.sleep(10) + # airplane mode on // radio off + #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + + # normal procedure without reboot + # enable data service + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + # airplane mode on // radio off + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + self.close() + return + # enable data service + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + + # The following commands are deprecated since we no longer work on Android 7+ + # self.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) + # self.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) + # a dedicated script has to be installed inside the UE + # airplane mode on means call /data/local/tmp/off + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + #airplane mode off means call /data/local/tmp/on + logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def InitializeUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.InitializeUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def InitializeOAIUE(self): + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is None: + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + # b2xx_fx3_utils reset procedure + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) + result = re.search('type: b200', str(self.ssh.before)) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) + else: + logging.debug('Did not find any B2xx device') + self.command('cd ' + self.UESourceCodePath, '\$', 5) + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets/lte_build_oai/build', '\$', 5) + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + # We may have to regenerate the .u* files + if result is None: + self.command('ls /tmp/*.sed', '\$', 5) + result = re.search('adapt_usim_parameters', str(self.ssh.before)) + if result is not None: + self.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + else: + self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) + # Launch UE with the modified config file + self.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.UELogFile = 'ue_' + self.testCase_id + '.log' + + # We are now looping several times to hope we really sync w/ an eNB + doOutterLoop = True + outterLoopCounter = 5 + gotSyncStatus = True + fullSyncStatus = True + while (doOutterLoop): + self.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + time.sleep(6) + self.command('cd ../..', '\$', 5) + doLoop = True + loopCounter = 10 + gotSyncStatus = True + # the 'got sync' message is for the UE threads synchronization + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # Here should never occur + logging.error('"got sync" message never showed!') + gotSyncStatus = False + doLoop = False + continue + self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + result = re.search('got sync', str(self.ssh.before)) + if result is None: + time.sleep(6) + else: + doLoop = False + logging.debug('Found "got sync" message!') + if gotSyncStatus == False: + # we certainly need to stop the lte-uesoftmodem process if it is still running! + self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + time.sleep(3) + # We are now checking if sync w/ eNB DOES NOT OCCUR + # Usually during the cell synchronization stage, the UE returns with No cell synchronization message + doLoop = True + loopCounter = 10 + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # Here we do have a great chance that the UE did cell-sync w/ eNB + doLoop = False + doOutterLoop = False + fullSyncStatus = True + continue + self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + result = re.search('No cell synchronization found', str(self.ssh.before)) + if result is None: + time.sleep(6) + else: + doLoop = False + fullSyncStatus = False + logging.debug('Found: "No cell synchronization" message! --> try again') + time.sleep(6) + self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + outterLoopCounter = outterLoopCounter - 1 + if (outterLoopCounter == 0): + doOutterLoop = False + + if fullSyncStatus and gotSyncStatus: + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is None: + self.command('ifconfig oaitun_ue1', '\$', 4) + # ifconfig output is different between ubuntu 16 and ubuntu 18 + result = re.search('inet addr:1|inet 1', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') + tunnelInterfaceStatus = True + else: + logging.debug(str(self.ssh.before)) + logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') + tunnelInterfaceStatus = False + else: + tunnelInterfaceStatus = True + + self.close() + if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') + if (self.ADBIPAddress != 'none'): + self.UEDevices = [] + self.UEDevices.append('OAI-UE') + self.UEDevicesStatus = [] + self.UEDevicesStatus.append(UE_STATUS_DETACHED) + else: + self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') + logging.error('\033[91mInitialize OAI UE Failed! \033[0m') + self.AutoTerminateUEandeNB() + + def checkDevTTYisUnlocked(self): + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + count = 0 + while count < 5: + self.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) + result = re.search('picocom', str(self.ssh.before)) + if result is None: + count = 10 + else: + time.sleep(5) + count = count + 1 + self.close() + + def InitializeCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.picocom_closure = True + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + # Disabling the Radio + self.command('AT+CFUN=0', 'OK', 5) + logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') + # Checking if auto-attach is enabled + self.command('AT^AUTOATT?', 'OK', 5) + result = re.search('AUTOATT: (?P[0-9\-]+)', str(self.ssh.before)) + if result is not None: + if result.group('state') is not None: + autoAttachState = int(result.group('state')) + if autoAttachState is not None: + if autoAttachState == 0: + self.command('AT^AUTOATT=1', 'OK', 5) + logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') + # Force closure of picocom but device might still be locked + self.close() + self.picocom_closure = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.checkDevTTYisUnlocked() + + def TerminateCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.picocom_closure = True + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + # Disabling the Radio + self.command('AT+CFUN=0', 'OK', 5) + logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') + self.close() + self.picocom_closure = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.checkDevTTYisUnlocked() + + def AttachCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.picocom_closure = True + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + # Enabling the Radio + self.command('AT+CFUN=1', 'SIMSTORE,READY', 5) + logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') + time.sleep(4) + # We should check if we register + count = 0 + attach_cnt = 0 + attach_status = False + while count < 5: + self.command('AT+CEREG?', 'OK', 5) + result = re.search('CEREG: 2,(?P[0-9\-]+),', str(self.ssh.before)) + if result is not None: + mDataConnectionState = int(result.group('state')) + if mDataConnectionState is not None: + if mDataConnectionState == 1: + count = 10 + attach_status = True + result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', str(self.ssh.before)) + if result is not None: + networky = result.group('networky') + networkz = result.group('networkz') + logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m') + else: + logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m') + else: + logging.debug('+CEREG: 2,' + str(mDataConnectionState)) + attach_cnt = attach_cnt + 1 + else: + logging.debug(str(self.ssh.before)) + attach_cnt = attach_cnt + 1 + count = count + 1 + time.sleep(1) + if attach_status: + self.command('AT+CESQ', 'OK', 5) + result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', str(self.ssh.before)) + if result is not None: + nRSRQ = int(result.group('rsrq')) + nRSRP = int(result.group('rsrp')) + if (nRSRQ is not None) and (nRSRP is not None): + logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') + logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') + self.close() + self.picocom_closure = False + html_queue = SimpleQueue() + self.checkDevTTYisUnlocked() + if attach_status: + html_cell = '
CAT-M module Attachment Completed in ' + str(attach_cnt+4) + ' seconds'
+			if (nRSRQ is not None) and (nRSRP is not None):
+				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
+				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm
' + else: + html_cell += '' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) + else: + logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') + html_cell = '
CAT-M module Attachment Failed
' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) + self.AutoTerminateUEandeNB() + + def PingCatM(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + try: + statusQueue = SimpleQueue() + lock = Lock() + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC HSS: not implemented yet') + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + else: + self.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) + result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', str(self.ssh.before)) + if result is not None: + moduleIPAddr = result.group('ipaddr') + else: + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + device_id = 'catm' + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + lock.acquire() + logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + lock.release() + self.close() + html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' + statusQueue.put(html_cell) + if (packetLossOK): + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) + self.AutoTerminateUEandeNB() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AttachUE_common(self, device_id, statusQueue, lock, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + else: + # airplane mode off // radio on + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + time.sleep(2) + max_count = 45 + count = max_count + while count > 0: + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put('mDataConnectionState Not Found!') + lock.release() + break + mDataConnectionState = int(result.group('state')) + if mDataConnectionState == 2: + logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') + lock.acquire() + statusQueue.put(max_count - count) + statusQueue.put(device_id) + statusQueue.put('Attach Completed') + lock.release() + break + count = count - 1 + if count == 15 or count == 30: + logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + time.sleep(0.5) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + time.sleep(0.5) + logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') + time.sleep(1) + if count == 0: + logging.debug('\u001B[1;37;41m UE (' + device_id + ') Attach Failed \u001B[0m') + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put('Attach Failed') + lock.release() + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AttachUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + status_queue = SimpleQueue() + lock = Lock() + nb_ue_to_connect = 0 + for device_id in self.UEDevices: + if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): + self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING + p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) + p.daemon = True + p.start() + multi_jobs.append(p) + nb_ue_to_connect = nb_ue_to_connect + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + return + else: + attach_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + attach_status = False + device_id = status_queue.get() + message = status_queue.get() + if (count < 0): + html_cell = '
UE (' + device_id + ')\n' + message + '
' + else: + html_cell = '
UE (' + device_id + ')\n' + message + ' in ' + str(count + 2) + ' seconds
' + html_queue.put(html_cell) + if (attach_status): + # cnt from index to object of a class + self.cnt = 0 + while self.cnt < len(self.UEDevices): + if self.UEDevicesStatus[self.cnt] == UE_STATUS_ATTACHING: + self.UEDevicesStatus[self.cnt] = UE_STATUS_ATTACHED + self.cnt += 1 + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + else: + self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def DetachUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DetachUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + self.cnt = 0 + for device_id in self.UEDevices: + self.UEDevicesStatus[self.cnt] = UE_STATUS_DETACHING + p = Process(target = self.DetachUE_common, args = (device_id,self.cnt,)) + p.daemon = True + p.start() + multi_jobs.append(p) + self.cnt += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + self.cnt = 0 + while self.cnt < len(self.UEDevices): + self.UEDevicesStatus[self.cnt] = UE_STATUS_DETACHED + self.cnt += 1 + + def RebootUE_common(self, device_id): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + previousmDataConnectionStates = [] + # Save mDataConnectionState + self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') + sys.exit(1) + previousmDataConnectionStates.append(int(result.group('state'))) + # Reboot UE + self.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) + time.sleep(60) + previousmDataConnectionState = previousmDataConnectionStates.pop(0) + count = 180 + while count > 0: + count = count - 1 + self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + if result is None: + mDataConnectionState = None + else: + mDataConnectionState = int(result.group('state')) + logging.debug('mDataConnectionState = ' + result.group('state')) + if mDataConnectionState is None or (previousmDataConnectionState == 2 and mDataConnectionState != 2): + logging.debug('\u001B[1mWait UE (' + device_id + ') a second until reboot completion (' + str(180-count) + ' times)\u001B[0m') + time.sleep(1) + else: + logging.debug('\u001B[1mUE (' + device_id + ') Reboot Completed\u001B[0m') + break + if count == 0: + logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') + sys.exit(1) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def RebootUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + multi_jobs = [] + for device_id in self.UEDevices: + p = Process(target = self.RebootUE_common, args = (device_id,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def DataDisableUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # disable data service + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DataDisableUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.DataDisableUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def DataEnableUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # enable data service + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DataEnableUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.DataEnableUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def GetAllUEDevices(self, terminate_ue_flag): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('adb devices', '\$', 15) + self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",str(self.ssh.before)) + self.close() + else: + if (os.path.isfile('./phones_list.txt')): + os.remove('./phones_list.txt') + self.command('ls /etc/*/phones*.txt', '\$', 5) + result = re.search('/etc/ci/phones_list.txt', str(self.ssh.before)) + self.close() + if (result is not None) and (len(self.UEDevices) == 0): + self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') + if (os.path.isfile('./phones_list.txt')): + phone_list_file = open('./phones_list.txt', 'r') + for line in phone_list_file.readlines(): + line = line.strip() + result = re.search('^#', line) + if result is not None: + continue + comma_split = line.split(",") + self.UEDevices.append(comma_split[0]) + self.UEDevicesRemoteServer.append(comma_split[1]) + self.UEDevicesRemoteUser.append(comma_split[2]) + self.UEDevicesOffCmd.append(comma_split[3]) + self.UEDevicesOnCmd.append(comma_split[4]) + self.UEDevicesRebootCmd.append(comma_split[5]) + phone_list_file.close() + + if terminate_ue_flag == False: + if len(self.UEDevices) == 0: + logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') + sys.exit(1) + if len(self.UEDevicesStatus) == 0: + self.cnt = 0 + while self.cnt < len(self.UEDevices): + self.UEDevicesStatus.append(UE_STATUS_DETACHED) + self.cnt += 1 + + def GetAllCatMDevices(self, terminate_ue_flag): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) + self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",str(self.ssh.before)) + else: + if (os.path.isfile('./modules_list.txt')): + os.remove('./modules_list.txt') + self.command('ls /etc/*/modules*.txt', '\$', 5) + result = re.search('/etc/ci/modules_list.txt', str(self.ssh.before)) + self.close() + if result is not None: + logging.debug('Found a module list file on ADB server') + if terminate_ue_flag == False: + if len(self.CatMDevices) == 0: + logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') + sys.exit(1) + self.close() + + def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) + result = re.search('mServiceState=(?P[0-9]+)', str(self.ssh.before)) + serviceState = 'Service State: UNKNOWN' + if result is not None: + lServiceState = int(result.group('serviceState')) + if lServiceState == 3: + serviceState = 'Service State: RADIO_POWERED_OFF' + if lServiceState == 1: + serviceState = 'Service State: OUT_OF_SERVICE' + if lServiceState == 0: + serviceState = 'Service State: IN_SERVICE' + if lServiceState == 2: + serviceState = 'Service State: EMERGENCY_ONLY' + result = re.search('mDataConnectionState=(?P[0-9]+)', str(self.ssh.before)) + dataConnectionState = 'Data State: UNKNOWN' + if result is not None: + lDataConnectionState = int(result.group('dataConnectionState')) + if lDataConnectionState == 0: + dataConnectionState = 'Data State: DISCONNECTED' + if lDataConnectionState == 1: + dataConnectionState = 'Data State: CONNECTING' + if lDataConnectionState == 2: + dataConnectionState = 'Data State: CONNECTED' + if lDataConnectionState == 3: + dataConnectionState = 'Data State: SUSPENDED' + result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', str(self.ssh.before)) + dataConnectionReason = 'Data Reason: UNKNOWN' + if result is not None: + dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') + lock.acquire() + logging.debug('\u001B[1;37;44m Status Check (' + str(device_id) + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + serviceState + '\u001B[0m') + logging.debug('\u001B[1;34m ' + dataConnectionState + '\u001B[0m') + logging.debug('\u001B[1;34m ' + dataConnectionReason + '\u001B[0m') + statusQueue.put(0) + statusQueue.put(device_id) + qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason + statusQueue.put(qMsg) + lock.release() + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckStatusUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + multi_jobs = [] + lock = Lock() + status_queue = SimpleQueue() + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.CheckUEStatus_common, args = (lock,device_id,status_queue,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd /opt/flexran_rtc', '\$', 5) + self.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) + self.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) + result = re.search('Nb Connected UE = (?P[0-9]+)', str(self.ssh.before)) + passStatus = True + if result is not None: + nb_ues = int(result.group('nb_ues')) + htmlOptions = 'Nb Connected UE(s) to eNB = ' + str(nb_ues) + logging.debug('\u001B[1;37;44m ' + htmlOptions + ' \u001B[0m') + if self.expectedNbOfConnectedUEs > -1: + if nb_ues != self.expectedNbOfConnectedUEs: + passStatus = False + else: + htmlOptions = 'N/A' + self.close() + else: + passStatus = True + htmlOptions = 'N/A' + + if (status_queue.empty()): + self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + check_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + check_status = False + device_id = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\n' + message + '
' + html_queue.put(html_cell) + if check_status and passStatus: + self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def GetAllUEIPAddresses(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + ue_ip_status = 0 + self.UEIPAddresses = [] + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('ifconfig oaitun_ue1', '\$', 4) + result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', str(self.ssh.before)) + if result is not None: + if result.group('ueipaddress') is not None: + UE_IPAddress = result.group('ueipaddress') + else: + UE_IPAddress = result.group('ueipaddress2') + logging.debug('\u001B[1mUE (' + self.UEDevices[0] + ') IP Address is ' + UE_IPAddress + '\u001B[0m') + self.UEIPAddresses.append(UE_IPAddress) + else: + logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') + ue_ip_status -= 1 + self.close() + return ue_ip_status + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + idx = 0 + for device_id in self.UEDevices: + if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: + idx += 1 + continue + count = 0 + while count < 4: + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) + result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') + time.sleep(1) + count += 1 + else: + count = 10 + if count < 9: + ue_ip_status -= 1 + continue + UE_IPAddress = result.group('ueipaddress') + logging.debug('\u001B[1mUE (' + device_id + ') IP Address is ' + UE_IPAddress + '\u001B[0m') + for ueipaddress in self.UEIPAddresses: + if ueipaddress == UE_IPAddress: + logging.debug('\u001B[1mUE (' + device_id + ') IP Address ' + UE_IPAddress + ': has already been allocated to another device !' + '\u001B[0m') + ue_ip_status -= 1 + continue + self.UEIPAddresses.append(UE_IPAddress) + idx += 1 + self.close() + return ue_ip_status + + def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(message) + lock.release() + + def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): + try: + # Launch ping on the EPC side (true for ltebox and old open-air-cn) + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + else: + cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + ping_status = ret.returncode + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + lock.acquire() + logging.debug('\u001B[1;37;44m ping result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + if (packetLossOK): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(qMsg) + lock.release() + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def PingNoS1_wrong_exit(self, qMsg): + html_queue = SimpleQueue() + html_cell = '
OAI UE ping result\n' + qMsg + '
' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + + def PingNoS1(self): + check_eNB = True + check_OAI_UE = True + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) + if ping_from_eNB is not None: + if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + else: + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + Usage() + sys.exit('Insufficient Parameter') + try: + if ping_from_eNB is not None: + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) + else: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) + self.command('cd cmake_targets', '\$', 5) + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with OAI UE crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + logging.debug('\u001B[1;37;44m OAI UE ping result \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + self.close() + html_queue = SimpleQueue() + ip_addr = 'TBD' + html_cell = '
OAI UE ping result\n' + qMsg + '
' + html_queue.put(html_cell) + if packetLossOK: + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + + # copying on the EPC server for logCollection + if ping_from_eNB is not None: + copyin_res = self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + else: + copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def Ping(self): + result = re.search('noS1', str(self.Initialize_eNB_args)) + if result is not None: + self.PingNoS1() + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + check_OAI_UE = True + else: + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + i = 0 + lock = Lock() + status_queue = SimpleQueue() + for UE_IPAddress in self.UEIPAddresses: + device_id = self.UEDevices[i] + p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + ping_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + ping_status = False + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (ping_status): + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def Iperf_ComputeTime(self): + result = re.search('-t (?P\d+)', str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Iperf time Not Found! \u001B[0m') + sys.exit(1) + return result.group('iperf_time') + + def Iperf_ComputeModifiedBW(self, idx, ue_num): + result = re.search('-b (?P[0-9\.]+)[KMG]', str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Iperf bandwidth Not Found! \u001B[0m') + sys.exit(1) + iperf_bandwidth = result.group('iperf_bandwidth') + if self.iperf_profile == 'balanced': + iperf_bandwidth_new = float(iperf_bandwidth)/ue_num + if self.iperf_profile == 'single-ue': + iperf_bandwidth_new = float(iperf_bandwidth) + if self.iperf_profile == 'unbalanced': + # residual is 2% of max bw + residualBW = float(iperf_bandwidth) / 50 + if idx == 0: + iperf_bandwidth_new = float(iperf_bandwidth) - ((ue_num - 1) * residualBW) + else: + iperf_bandwidth_new = residualBW + iperf_bandwidth_str = '-b ' + iperf_bandwidth + iperf_bandwidth_str_new = '-b ' + ('%.2f' % iperf_bandwidth_new) + result = re.sub(iperf_bandwidth_str, iperf_bandwidth_str_new, str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Calculate Iperf bandwidth Failed! \u001B[0m') + sys.exit(1) + return result + + def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + self.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', str(self.ssh.before)) + if result is not None: + avgbitrate = result.group('average') + maxbitrate = result.group('maximum') + minbitrate = result.group('minimum') + lock.acquire() + logging.debug('\u001B[1;37;44m TCP iperf result (' + UE_IPAddress + ') \u001B[0m') + msg = 'TCP Stats :\n' + if avgbitrate is not None: + logging.debug('\u001B[1;34m Avg Bitrate : ' + avgbitrate + '\u001B[0m') + msg += 'Avg Bitrate : ' + avgbitrate + '\n' + if maxbitrate is not None: + logging.debug('\u001B[1;34m Max Bitrate : ' + maxbitrate + '\u001B[0m') + msg += 'Max Bitrate : ' + maxbitrate + '\n' + if minbitrate is not None: + logging.debug('\u001B[1;34m Min Bitrate : ' + minbitrate + '\u001B[0m') + msg += 'Min Bitrate : ' + minbitrate + '\n' + statusQueue.put(0) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + return 0 + + def Iperf_analyzeV2Output(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + result = re.search('-u', str(iperf_real_options)) + if result is None: + return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) + + result = re.search('Server Report:', str(self.ssh.before)) + if result is None: + result = re.search('read failed: Connection refused', str(self.ssh.before)) + if result is not None: + logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') + else: + logging.debug('\u001B[1;37;41m Server Report and Connection refused Not Found! \u001B[0m') + return -1 + # Computing the requested bandwidth in float + result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) + if result is not None: + req_bandwidth = result.group('iperf_bandwidth') + req_bw = float(req_bandwidth) + result = re.search('-b [0-9\.]+K', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Kbits/sec' % req_bw + req_bw = req_bw * 1000 + result = re.search('-b [0-9\.]+M', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Mbits/sec' % req_bw + req_bw = req_bw * 1000000 + result = re.search('-b [0-9\.]+G', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Gbits/sec' % req_bw + req_bw = req_bw * 1000000000 + + result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) + if result is not None: + bitrate = result.group('bitrate') + packetloss = result.group('packetloss') + jitter = result.group('jitter') + lock.acquire() + logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') + iperfStatus = True + msg = 'Req Bitrate : ' + req_bandwidth + '\n' + logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m') + if bitrate is not None: + msg += 'Bitrate : ' + bitrate + '\n' + logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') + result = re.search('(?P[0-9\.]+) [KMG]bits/sec', str(bitrate)) + if result is not None: + actual_bw = float(str(result.group('real_bw'))) + result = re.search('[0-9\.]+ K', bitrate) + if result is not None: + actual_bw = actual_bw * 1000 + result = re.search('[0-9\.]+ M', bitrate) + if result is not None: + actual_bw = actual_bw * 1000000 + result = re.search('[0-9\.]+ G', bitrate) + if result is not None: + actual_bw = actual_bw * 1000000000 + br_loss = 100 * actual_bw / req_bw + bitperf = '%.2f ' % br_loss + msg += 'Bitrate Perf: ' + bitperf + '%\n' + logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m') + if packetloss is not None: + msg += 'Packet Loss : ' + packetloss + '%\n' + logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') + if float(packetloss) > float(self.iperf_packetloss_threshold): + msg += 'Packet Loss too high!\n' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + iperfStatus = False + if jitter is not None: + msg += 'Jitter : ' + jitter + '\n' + logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m') + if (iperfStatus): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + return 0 + else: + return -2 + + def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') + return + # Computing the requested bandwidth in float + result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) + if result is None: + logging.debug('Iperf bandwidth Not Found!') + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not compute Iperf bandwidth!') + return + else: + req_bandwidth = result.group('iperf_bandwidth') + req_bw = float(req_bandwidth) + result = re.search('-b [0-9\.]+K', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Kbits/sec' % req_bw + req_bw = req_bw * 1000 + result = re.search('-b [0-9\.]+M', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Mbits/sec' % req_bw + req_bw = req_bw * 1000000 + result = re.search('-b [0-9\.]+G', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Gbits/sec' % req_bw + req_bw = req_bw * 1000000000 + + server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') + br_sum = 0.0 + ji_sum = 0.0 + pl_sum = 0 + ps_sum = 0 + row_idx = 0 + for line in server_file.readlines(): + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) + if result is not None: + bitrate = result.group('bitrate') + jitter = result.group('jitter') + packetlost = result.group('lostPack') + packetsent = result.group('sentPack') + br = bitrate.split(' ') + ji = jitter.split(' ') + row_idx = row_idx + 1 + curr_br = float(br[0]) + pl_sum = pl_sum + int(packetlost) + ps_sum = ps_sum + int(packetsent) + if (br[1] == 'Kbits/sec'): + curr_br = curr_br * 1000 + if (br[1] == 'Mbits/sec'): + curr_br = curr_br * 1000 * 1000 + br_sum = curr_br + br_sum + ji_sum = float(ji[0]) + ji_sum + if (row_idx > 0): + br_sum = br_sum / row_idx + ji_sum = ji_sum / row_idx + br_loss = 100 * br_sum / req_bw + if (br_sum > 1000): + br_sum = br_sum / 1000 + if (br_sum > 1000): + br_sum = br_sum / 1000 + bitrate = '%.2f Mbits/sec' % br_sum + else: + bitrate = '%.2f Kbits/sec' % br_sum + else: + bitrate = '%.2f bits/sec' % br_sum + bitperf = '%.2f ' % br_loss + bitperf += '%' + jitter = '%.2f ms' % (ji_sum) + if (ps_sum > 0): + pl = float(100 * pl_sum / ps_sum) + packetloss = '%2.1f ' % (pl) + packetloss += '%' + else: + packetloss = 'unknown' + lock.acquire() + if (br_loss < 90): + statusQueue.put(1) + else: + statusQueue.put(0) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + req_msg = 'Req Bitrate : ' + req_bandwidth + bir_msg = 'Bitrate : ' + bitrate + brl_msg = 'Bitrate Perf: ' + bitperf + jit_msg = 'Jitter : ' + jitter + pal_msg = 'Packet Loss : ' + packetloss + statusQueue.put(req_msg + '\n' + bir_msg + '\n' + brl_msg + '\n' + jit_msg + '\n' + pal_msg + '\n') + logging.debug('\u001B[1;37;45m iperf result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;35m ' + req_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + bir_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + brl_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + jit_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + pal_msg + '\u001B[0m') + lock.release() + else: + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') + + server_file.close() + + + def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', str(self.ssh.before)) + if result is None: + result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', str(self.ssh.before)) + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + if result is not None: + logging.debug('\u001B[1;37;41m ' + result.group('error') + ' \u001B[0m') + statusQueue.put(result.group('error')) + else: + logging.debug('\u001B[1;37;41m Bitrate and/or Packet Loss Not Found! \u001B[0m') + statusQueue.put('Bitrate and/or Packet Loss Not Found!') + lock.release() + + bitrate = result.group('bitrate') + packetloss = result.group('packetloss') + lock.acquire() + logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') + msg = 'Bitrate : ' + bitrate + '\n' + iperfStatus = True + if packetloss is not None: + logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') + msg += 'Packet Loss : ' + packetloss + '%\n' + if float(packetloss) > float(self.iperf_packetloss_threshold): + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + msg += 'Packet Loss too high!\n' + iperfStatus = False + if (iperfStatus): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + + def Iperf_UL_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): + udpIperf = True + result = re.search('-u', str(self.iperf_args)) + if result is None: + udpIperf = False + ipnumbers = UE_IPAddress.split('.') + if (len(ipnumbers) == 4): + ipnumbers[3] = '1' + EPC_Iperf_UE_IPAddress = ipnumbers[0] + '.' + ipnumbers[1] + '.' + ipnumbers[2] + '.' + ipnumbers[3] + + # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 + # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False + cmd = 'hostname -I' + ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') + if ret.stdout is not None: + EPC_Iperf_UE_IPAddress = ret.stdout.strip() + port = 5001 + idx + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if udpIperf: + self.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + else: + self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + self.close() + else: + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + if udpIperf: + cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + else: + cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + logging.debug(cmd) + subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') + time.sleep(0.5) + + # Launch iperf client on UE + if (device_id == 'OAI-UE'): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + else: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + iperf_time = self.Iperf_ComputeTime() + time.sleep(0.5) + + if udpIperf: + modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) + else: + modified_options = str(self.iperf_args) + modified_options = modified_options.replace('-R','') + time.sleep(0.5) + + self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if (device_id == 'OAI-UE'): + iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + if self.ADBCentralized: + iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # TIMEOUT Case + if iperf_status < 0: + self.close() + message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) + self.close() + + # Kill iperf server on EPC side + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) + self.close() + else: + cmd = 'killall --signal SIGKILL iperf' + logging.debug(cmd) + subprocess.run(cmd, shell=True) + time.sleep(1) + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + # in case of failure, retrieve server log + if (clientStatus == -1) or (clientStatus == -2): + if launchFromEpc: + time.sleep(1) + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') + self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + # in case of OAI-UE + if (device_id == 'OAI-UE'): + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + + def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): + try: + # Single-UE profile -- iperf only on one UE + if self.iperf_profile == 'single-ue' and idx != 0: + return + useIperf3 = False + udpIperf = True + + self.ueIperfVersion = '2.0.5' + if (device_id != 'OAI-UE'): + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it + self.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + # Checking if iperf / iperf3 are installed + if self.ADBCentralized: + self.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) + result = re.search('iperf3', str(self.ssh.before)) + if result is None: + result = re.search('iperf', str(self.ssh.before)) + if result is None: + message = 'Neither iperf nor iperf3 installed on UE!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + else: + if self.ADBCentralized: + self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' + else: + useIperf3 = True + self.close() + else: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('iperf --version', '\$', 5) + result = re.search('iperf version 2.0.5', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', str(self.ssh.before)) + if result is not None: + self.ueIperfVersion = '2.0.10' + self.close() + # in case of iperf, UL has its own function + if (not useIperf3): + result = re.search('-R', str(self.iperf_args)) + if result is not None: + self.Iperf_UL_common(lock, UE_IPAddress, device_id, idx, ue_num, statusQueue) + return + + # Launch the IPERF server on the UE side for DL + if (device_id == 'OAI-UE'): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('-u', str(self.iperf_args)) + if result is None: + self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + udpIperf = False + else: + self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + else: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + if self.ADBCentralized: + if (useIperf3): + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) + else: + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('-u', str(self.iperf_args)) + if result is None: + self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + udpIperf = False + else: + self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + else: + self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) + + time.sleep(0.5) + self.close() + + # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + launchFromEpc = False + if launchFromEpc: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + iperf_time = self.Iperf_ComputeTime() + time.sleep(0.5) + + if udpIperf: + modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) + else: + modified_options = str(self.iperf_args) + time.sleep(0.5) + + if launchFromEpc: + self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + else: + if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') + if (useIperf3): + self.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + + clientStatus = 0 + self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) + else: + if launchFromEpc: + iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + iperf_status = ret.returncode + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if iperf_status < 0: + if launchFromEpc: + self.close() + message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) + self.close() + + # Kill the IPERF server that runs in background + if (device_id == 'OAI-UE'): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('killall iperf', '\$', 5) + else: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) + result = re.search('shell +(?P\d+)', str(self.ssh.before)) + if result is not None: + pid_iperf = result.group('pid') + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + self.close() + # if the client report is absent, try to analyze the server log file + if (clientStatus == -1): + time.sleep(1) + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') + if (device_id == 'OAI-UE'): + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + else: + self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + + # in case of OAI UE: + if (device_id == 'OAI-UE'): + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + if not launchFromEpc: + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + else: + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def IperfNoS1(self): + if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = True + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + server_on_enb = re.search('-R', str(self.iperf_args)) + if server_on_enb is not None: + iServerIPAddr = self.eNBIPAddress + iServerUser = self.eNBUserName + iServerPasswd = self.eNBPassword + iClientIPAddr = self.UEIPAddress + iClientUser = self.UEUserName + iClientPasswd = self.UEPassword + else: + iServerIPAddr = self.UEIPAddress + iServerUser = self.UEUserName + iServerPasswd = self.UEPassword + iClientIPAddr = self.eNBIPAddress + iClientUser = self.eNBUserName + iClientPasswd = self.eNBPassword + # Starting the iperf server + self.open(iServerIPAddr, iServerUser, iServerPasswd) + # args SHALL be "-c client -u any" + # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 + # -B 10.0.1.1 -u -s -i 1 -fm + server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) + server_options = server_options.replace('-c','-B') + self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) + self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) + time.sleep(0.5) + self.close() + + # Starting the iperf client + modified_options = self.Iperf_ComputeModifiedBW(0, 1) + modified_options = modified_options.replace('-R','') + iperf_time = self.Iperf_ComputeTime() + self.open(iClientIPAddr, iClientUser, iClientPasswd) + self.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) + iperf_status = self.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) + status_queue = SimpleQueue() + lock = Lock() + if iperf_status < 0: + message = 'iperf on OAI UE crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + clientStatus = -2 + else: + clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + self.close() + + # Stopping the iperf server + self.open(iServerIPAddr, iServerUser, iServerPasswd) + self.command('killall --signal SIGKILL iperf', '\$', 5) + time.sleep(0.5) + self.close() + if (clientStatus == -1): + if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '.log') + self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + + # copying on the EPC server for logCollection + copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + copyin_res = self.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + iperf_noperf = False + if status_queue.empty(): + iperf_status = False + else: + iperf_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + iperf_status = False + if (count > 0): + iperf_noperf = True + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (iperf_noperf and iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + elif (iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def Iperf(self): + result = re.search('noS1', str(self.Initialize_eNB_args)) + if result is not None: + self.IperfNoS1() + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + check_eNB = True + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + check_OAI_UE = True + else: + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB() + return + + self.dummyIperfVersion = '2.0.10' + #cmd = 'iperf --version' + #logging.debug(cmd + '\n') + #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) + #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.5' + #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.10' + + multi_jobs = [] + i = 0 + ue_num = len(self.UEIPAddresses) + lock = Lock() + status_queue = SimpleQueue() + for UE_IPAddress in self.UEIPAddresses: + device_id = self.UEDevices[i] + p = Process(target = SSH.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + iperf_status = True + iperf_noperf = False + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + iperf_status = False + if (count > 0): + iperf_noperf = True + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (iperf_noperf and iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + elif (iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def CheckProcessExist(self, check_eNB, check_OAI_UE): + multi_jobs = [] + status_queue = SimpleQueue() + # in noS1 config, no need to check status from EPC + result = re.search('noS1', str(self.Initialize_eNB_args)) + if result is None: + p = Process(target = SSH.CheckHSSProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + p = Process(target = SSH.CheckMMEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + p = Process(target = SSH.CheckSPGWProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + else: + if (check_eNB == False) and (check_OAI_UE == False): + return 0 + if check_eNB: + p = Process(target = SSH.CheckeNBProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + if check_OAI_UE: + p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + return -15 + else: + result = 0 + while (not status_queue.empty()): + status = status_queue.get() + if (status < 0): + result = status + if result == ENB_PROCESS_FAILED: + fileCheck = re.search('enb_', str(self.eNBLogFiles[0])) + if fileCheck is not None: + self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') + logStatus = self.AnalyzeLogFile_eNB(self.eNBLogFiles[0]) + if logStatus < 0: + result = logStatus + self.eNBLogFiles[0] = '' + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.TerminateFlexranCtrl() + return result + + def CheckOAIUEProcessExist(self, initialize_OAI_UE_flag): + multi_jobs = [] + status_queue = SimpleQueue() + if initialize_OAI_UE_flag == False: + p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + return -15 + else: + result = 0 + while (not status_queue.empty()): + status = status_queue.get() + if (status < 0): + result = status + if result == OAI_UE_PROCESS_FAILED: + fileCheck = re.search('ue_', str(self.UELogFile)) + if fileCheck is not None: + self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + logStatus = self.AnalyzeLogFile_UE(self.UELogFile) + if logStatus < 0: + result = logStatus + return result + + def CheckOAIUEProcess(self, status_queue): + try: + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') + status_queue.put(OAI_UE_PROCESS_FAILED) + else: + status_queue.put(OAI_UE_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckeNBProcess(self, status_queue): + try: + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is None: + logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') + status_queue.put(ENB_PROCESS_FAILED) + else: + status_queue.put(ENB_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckHSSProcess(self, status_queue): + try: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + result = re.search('oai_hss -j', str(self.ssh.before)) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + result = re.search('hss_sim s6as diam_hss', str(self.ssh.before)) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m HSS Process Not Found! \u001B[0m') + status_queue.put(HSS_PROCESS_FAILED) + else: + status_queue.put(HSS_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckMMEProcess(self, status_queue): + try: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + result = re.search('mme -c', str(self.ssh.before)) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + result = re.search('mme', str(self.ssh.before)) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m MME Process Not Found! \u001B[0m') + status_queue.put(MME_PROCESS_FAILED) + else: + status_queue.put(MME_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckSPGWProcess(self, status_queue): + try: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + result = re.search('spgwu -c ', str(self.ssh.before)) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) + result = re.search('xGw', str(self.ssh.before)) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m SPGW Process Not Found! \u001B[0m') + status_queue.put(SPGW_PROCESS_FAILED) + else: + status_queue.put(SPGW_PROCESS_OK) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AnalyzeLogFile_eNB(self, eNBlogFile): + if (not os.path.isfile('./' + eNBlogFile)): + return -1 + enb_log_file = open('./' + eNBlogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + rrcSetupComplete = 0 + rrcReleaseRequest = 0 + rrcReconfigRequest = 0 + rrcReconfigComplete = 0 + rrcReestablishRequest = 0 + rrcReestablishComplete = 0 + rrcReestablishReject = 0 + rlcDiscardBuffer = 0 + rachCanceledProcedure = 0 + uciStatMsgCount = 0 + pdcpFailure = 0 + ulschFailure = 0 + cdrxActivationMessageCount = 0 + dropNotEnoughRBs = 0 + self.htmleNBFailureMsg = '' + isRRU = False + isSlave = False + slaveReceivesFrameResyncCmd = False + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures = 0 + X2HO_outNbProcedures = 0 + for line in enb_log_file.readlines(): + if X2HO_state == X2_HO_REQ_STATE__IDLE: + result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ + result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK + if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: + result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE + if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: + result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ + if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: + result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures += 1 + if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: + result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_outNbProcedures += 1 + + if self.eNBOptions[int(self.eNB_instance)] != '': + res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) + res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) + if res1 is not None and res2 is not None: + requested_option = int(res1.group('requested_option')) + applied_option = int(res2.group('applied_option')) + if requested_option == applied_option: + self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + else: + self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('[Ss]egmentation [Ff]ault', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./lte_build_oai/build/lte-softmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('Setting function for RU', str(line)) + if result is not None: + isRRU = True + if isRRU: + result = re.search('RU 0 is_slave=yes', str(line)) + if result is not None: + isSlave = True + if isSlave: + result = re.search('Received RRU_frame_resynch command', str(line)) + if result is not None: + slaveReceivesFrameResyncCmd = True + result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) + if result is not None: + rrcSetupComplete += 1 + result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) + if result is not None: + rrcReleaseRequest += 1 + result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) + if result is not None: + rrcReconfigRequest += 1 + result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) + if result is not None: + rrcReconfigComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) + if result is not None: + rrcReestablishRequest += 1 + result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) + if result is not None: + rrcReestablishComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) + if result is not None: + rrcReestablishReject += 1 + result = re.search('CDRX configuration activated after RRC Connection', str(line)) + if result is not None: + cdrxActivationMessageCount += 1 + result = re.search('uci->stat', str(line)) + if result is not None: + uciStatMsgCount += 1 + result = re.search('PDCP.*Out of Resources.*reason', str(line)) + if result is not None: + pdcpFailure += 1 + result = re.search('ULSCH in error in round', str(line)) + if result is not None: + ulschFailure += 1 + result = re.search('BAD all_segments_received', str(line)) + if result is not None: + rlcDiscardBuffer += 1 + result = re.search('Canceled RA procedure for UE rnti', str(line)) + if result is not None: + rachCanceledProcedure += 1 + result = re.search('dropping, not enough RBs', str(line)) + if result is not None: + dropNotEnoughRBs += 1 + enb_log_file.close() + logging.debug(' File analysis completed') + if uciStatMsgCount > 0: + statMsg = 'eNB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if pdcpFailure > 0: + statMsg = 'eNB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if ulschFailure > 0: + statMsg = 'eNB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if dropNotEnoughRBs > 0: + statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if rrcSetupComplete > 0: + rrcMsg = 'eNB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReleaseRequest > 0: + rrcMsg = 'eNB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: + rrcMsg = 'eNB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: + rrcMsg = 'eNB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_inNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_outNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if self.eNBOptions[int(self.eNB_instance)] != '': + res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) + if res1 is not None: + if cdrxActivationMessageCount > 0: + rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + else: + rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' + logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rachCanceledProcedure > 0: + rachMsg = 'eNB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' + logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rachMsg + '\n' + if isRRU: + if isSlave: + if slaveReceivesFrameResyncCmd: + rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + else: + rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + self.prematureExit = True + return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED + if foundSegFault: + logging.debug('\u001B[1;37;41m eNB ended with a Segmentation Fault! \u001B[0m') + return ENB_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;37;41m eNB ended with an assertion! \u001B[0m') + self.htmleNBFailureMsg += msgAssertion + return ENB_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m eNB faced real time issues! \u001B[0m') + self.htmleNBFailureMsg += 'eNB faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if rlcDiscardBuffer > 0: + rlcMsg = 'eNB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' + logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rlcMsg + '\n' + return ENB_PROCESS_REALTIME_ISSUE + return 0 + + def AnalyzeLogFile_UE(self, UElogFile): + if (not os.path.isfile('./' + UElogFile)): + return -1 + ue_log_file = open('./' + UElogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + uciStatMsgCount = 0 + pdcpDataReqFailedCount = 0 + badDciCount = 0 + rrcConnectionRecfgComplete = 0 + no_cell_sync_found = False + mib_found = False + frequency_found = False + plmn_found = False + self.htmlUEFailureMsg = '' + for line in ue_log_file.readlines(): + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./lte-uesoftmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('uci->stat', str(line)) + if result is not None and not exitSignalReceived: + uciStatMsgCount += 1 + result = re.search('PDCP data request failed', str(line)) + if result is not None and not exitSignalReceived: + pdcpDataReqFailedCount += 1 + result = re.search('bad DCI 1A', str(line)) + if result is not None and not exitSignalReceived: + badDciCount += 1 + result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) + if result is not None: + rrcConnectionRecfgComplete += 1 + # No cell synchronization found, abandoning + result = re.search('No cell synchronization found, abandoning', str(line)) + if result is not None: + no_cell_sync_found = True + result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) + if result is not None and (not mib_found): + try: + mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " nidcell = " + result.group('nidcell') + self.htmlUEFailureMsg += mibMsg + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " n_rb_dl = " + result.group('n_rb_dl') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " phich_duration = " + result.group('phich_duration') + self.htmlUEFailureMsg += mibMsg + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " phich_resource = " + result.group('phich_resource') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " tx_ant = " + result.group('tx_ant') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mib_found = True + except Exception as e: + logging.error('\033[91m' + "MIB marker was not found" + '\033[0m') + result = re.search("Measured Carrier Frequency (?P\d{1,15}) Hz", str(line)) + if result is not None and (not frequency_found): + try: + mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + frequency_found = True + except Exception as e: + logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') + result = re.search("PLMN MCC (?P\d{1,3}), MNC (?P\d{1,3}), TAC", str(line)) + if result is not None and (not plmn_found): + try: + mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + plmn_found = True + except Exception as e: + logging.error('\033[91m' + "PLMN not found" + '\033[0m') + result = re.search("Found (?P[\w,\s]{1,15}) \(name from internal table\)", str(line)) + if result is not None: + try: + mibMsg = "The operator is: " + result.group('operator') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + except Exception as e: + logging.error('\033[91m' + "Operator name not found" + '\033[0m') + result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line)) + if result is not None: + try: + mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) + self.htmlUEFailureMsg += mibMsg + ' -> ' + logging.debug('\033[94m' + mibMsg + '\033[0m') + except Exception as e: + logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') + result = re.search("DL Carrier Frequency/ARFCN : (?P\d{1,15}/\d{1,4})", str(line)) + if result is not None: + try: + freq = result.group('carrier_frequency') + new_freq = re.sub('/[0-9]+','',freq) + float_freq = float(new_freq) / 1000000 + self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' + logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') + except Exception as e: + logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') + result = re.search("AllowedMeasBandwidth : (?P\d{1,7})", str(line)) + if result is not None: + try: + prb = result.group('allowed_bandwidth') + self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' + logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') + except Exception as e: + logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') + ue_log_file.close() + if rrcConnectionRecfgComplete > 0: + statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' + logging.debug('\033[94m' + statMsg + '\033[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if uciStatMsgCount > 0: + statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if pdcpDataReqFailedCount > 0: + statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if badDciCount > 0: + statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1A" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if foundSegFault: + logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') + return ENB_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') + self.htmlUEFailureMsg += 'UE showed an assertion!\n' + if not mib_found or not frequency_found: + return OAI_UE_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') + self.htmlUEFailureMsg += 'UE faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if no_cell_sync_found and not mib_found: + logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') + self.htmlUEFailureMsg += 'UE could not synchronize!\n' + return OAI_UE_PROCESS_COULD_NOT_SYNC + return 0 + + def TerminateeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(lIpAddr, lUserName, lPassWord) + self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) + self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) + time.sleep(10) + self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-softmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) + time.sleep(5) + self.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.close() + # If tracer options is on, stopping tshark on EPC side + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + time.sleep(1) + if self.EPC_PcapFileName != '': + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + self.close() + logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') + self.open(lIpAddr, lUserName, lPassWord) + self.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) + enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] + raw_record_file = enbLogFile.replace('.log', '_record.raw') + replay_log_file = enbLogFile.replace('.log', '_replay.log') + extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') + extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') + self.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) + self.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) + self.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) + self.close() + self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') + logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBLogFiles[int(self.eNB_instance)] = '' + else: + analyzeFile = False + if self.eNBLogFiles[int(self.eNB_instance)] != '': + analyzeFile = True + fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] + self.eNBLogFiles[int(self.eNB_instance)] = '' + if analyzeFile: + copyin_res = self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy eNB logfile to analyze it! \u001B[0m') + self.htmleNBFailureMsg = 'Could not copy eNB logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + return + if self.eNB_serverId != '0': + self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') + logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m ' + fileToAnalyze) + logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) + if (logStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', logStatus) + self.preamtureExit = True + return + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateHSS(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + result = re.search('oai_hss -j', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) + self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) + time.sleep(1) + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) + else: + logging.error('This should not happen!') + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateMME(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) + result = re.search('mme -c', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) + self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) + else: + logging.error('This should not happen!') + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateSPGW(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + result = re.search('spgwc -c |spgwu -c ', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) + self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) + self.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) + result = re.search('-w ', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) + time.sleep(2) + self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cd /opt/ltebox/tools', '\$', 5) + self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) + else: + logging.error('This should not happen!') + self.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateFlexranCtrl(self): + if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: + return + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + Usage() + sys.exit('Insufficient Parameter') + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) + time.sleep(1) + self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) + time.sleep(1) + self.close() + self.flexranCtrlStarted = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateUE_common(self, device_id, idx): + try: + self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # back in airplane mode on (ie radio off) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') + + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) + result = re.search('shell +(?P\d+)', str(self.ssh.before)) + if result is not None: + pid_iperf = result.group('pid') + if self.ADBCentralized: + self.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) + else: + self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + self.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def TerminateUE(self): + terminate_ue_flag = True + self.GetAllUEDevices(terminate_ue_flag) + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target= SSH.TerminateUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateOAIUE(self): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) + time.sleep(10) + self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('lte-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) + time.sleep(5) + self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.close() + result = re.search('ue_', str(self.UELogFile)) + if result is not None: + copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') + self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + self.UELogFile = '' + return + logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_UE(self.UELogFile) + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is not None: + ueAction = 'Sniffing' + else: + ueAction = 'Connection' + if (logStatus < 0): + logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') + self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg + self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') + # In case of sniffing on commercial eNBs we have random results + # Not an error then + if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): + self.Initialize_OAI_UE_args = '' + self.AutoTerminateUEandeNB() + else: + logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') + self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.UELogFile = '' + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def AutoTerminateUEandeNB(self): + if (self.ADBIPAddress != 'none'): + self.testCase_id = 'AUTO-KILL-UE' + self.desc = 'Automatic Termination of UE' + self.ShowTestID() + self.TerminateUE() + if (self.Initialize_OAI_UE_args != ''): + self.testCase_id = 'AUTO-KILL-UE' + self.desc = 'Automatic Termination of UE' + self.ShowTestID() + self.TerminateOAIUE() + if (self.Initialize_eNB_args != ''): + self.testCase_id = 'AUTO-KILL-eNB' + self.desc = 'Automatic Termination of eNB' + self.ShowTestID() + self.eNB_instance = '0' + self.TerminateeNB() + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.testCase_id = 'AUTO-KILL-flexran-ctl' + self.desc = 'Automatic Termination of FlexRan CTL' + self.ShowTestID() + self.TerminateFlexranCtrl() + self.prematureExit = True + + def IdleSleep(self): + time.sleep(self.idle_sleep_time) + self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) + + def X2_Status(self, idx, fileName): + cmd = "curl --silent http://" + self.EPCIPAddress + ":9999/stats | jq '.' > " + fileName + message = cmd + '\n' + logging.debug(cmd) + subprocess.run(cmd, shell=True) + if idx == 0: + cmd = "jq '.mac_stats | length' " + fileName + strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2NbENBs = int(strNbEnbs.strip()) + self.cnt = 0 + while self.cnt < self.x2NbENBs: + cmd = "jq '.mac_stats[" + str(self.cnt) + "].bs_id' " + fileName + bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2ENBBsIds[idx].append(bs_id.strip()) + cmd = "jq '.mac_stats[" + str(self.cnt) + "].ue_mac_stats | length' " + fileName + stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) + nbUEs = int(stNbUEs.strip()) + ueIdx = 0 + self.x2ENBConnectedUEs[idx].append([]) + while ueIdx < nbUEs: + cmd = "jq '.mac_stats[" + str(self.cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName + rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2ENBConnectedUEs[idx][self.cnt].append(rnti.strip()) + ueIdx += 1 + self.cnt += 1 + + msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" + logging.debug(msg) + message += msg + '\n' + self.cnt = 0 + while self.cnt < self.x2NbENBs: + msg = " -- eNB: " + str(self.x2ENBBsIds[idx][self.cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][self.cnt])) + " UE(s)" + logging.debug(msg) + message += msg + '\n' + ueIdx = 0 + while ueIdx < len(self.x2ENBConnectedUEs[idx][self.cnt]): + msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][self.cnt][ueIdx]) + logging.debug(msg) + message += msg + '\n' + ueIdx += 1 + self.cnt += 1 + return message + + def Perform_X2_Handover(self): + html_queue = SimpleQueue() + fullMessage = '
'
+		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
+		logging.debug(msg)
+		fullMessage += msg + '\n'
+		if self.x2_ho_options == 'network':
+			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
+				self.x2ENBBsIds = []
+				self.x2ENBConnectedUEs = []
+				self.x2ENBBsIds.append([])
+				self.x2ENBBsIds.append([])
+				self.x2ENBConnectedUEs.append([])
+				self.x2ENBConnectedUEs.append([])
+				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
+
+				msg = "Activating the X2 Net control on each eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				eNB_cnt = self.x2NbENBs
+				self.cnt = 0
+				while self.cnt < eNB_cnt:
+					cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][self.cnt]) + "/1"
+					logging.debug(cmd)
+					fullMessage += cmd + '\n'
+					subprocess.run(cmd, shell=True)
+					self.cnt += 1
+				# Waiting for the activation to be active
+				time.sleep(10)
+				msg = "Switching UE(s) from eNB to eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				self.cnt = 0
+				while self.cnt < eNB_cnt:
+					ueIdx = 0
+					while ueIdx < len(self.x2ENBConnectedUEs[0][self.cnt]):
+						cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][self.cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
+						logging.debug(cmd)
+						fullMessage += cmd + '\n'
+						subprocess.run(cmd, shell=True)
+						ueIdx += 1
+					self.cnt += 1
+				time.sleep(10)
+				# check
+				logging.debug("Checking the Status after X2 Handover")
+				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
+				self.cnt = 0
+				x2Status = True
+				while self.cnt < eNB_cnt:
+					if len(self.x2ENBConnectedUEs[0][self.cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
+						x2Status = False
+					self.cnt += 1
+				if x2Status:
+					msg = "X2 Handover was successful"
+					logging.debug(msg)
+					fullMessage += msg + '
' + html_queue.put(fullMessage) + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + else: + msg = "X2 Handover FAILED" + logging.error(msg) + fullMessage += msg + '' + html_queue.put(fullMessage) + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) + + def LogCollectBuild(self): + if (self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != ''): + IPAddress = self.eNBIPAddress + UserName = self.eNBUserName + Password = self.eNBPassword + SourceCodePath = self.eNBSourceCodePath + elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + SourceCodePath = self.UESourceCodePath + else: + sys.exit('Insufficient Parameter') + self.open(IPAddress, UserName, Password) + self.command('cd ' + SourceCodePath, '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('rm -f build.log.zip', '\$', 5) + self.command('zip build.log.zip build_log_*/*', '\$', 60) + self.close() + + def LogCollecteNB(self): + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath, '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) + self.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) + self.close() + + def LogCollectPing(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('rm -f ping.log.zip', '\$', 5) + self.command('zip ping.log.zip ping*.log', '\$', 60) + self.command('rm ping*.log', '\$', 5) + self.close() + + def LogCollectIperf(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath, '\$', 5) + self.command('cd scripts', '\$', 5) + self.command('rm -f iperf.log.zip', '\$', 5) + self.command('zip iperf.log.zip iperf*.log', '\$', 60) + self.command('rm iperf*.log', '\$', 5) + self.close() + + def LogCollectHSS(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f hss.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip hss.log.zip hss*.log', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) + self.command('zip hss.log.zip hss.log', '\$', 60) + else: + logging.error('This option should not occur!') + self.close() + + def LogCollectMME(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f mme.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip mme.log.zip mme*.log', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) + self.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) + else: + logging.error('This option should not occur!') + self.close() + + def LogCollectSPGW(self): + self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + self.command('rm -f spgw.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + self.command('zip spgw.log.zip spgw*.log', '\$', 60) + self.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + self.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) + self.command('zip spgw.log.zip xGwLog.0', '\$', 60) + else: + logging.error('This option should not occur!') + self.close() + + def LogCollectOAIUE(self): + self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + self.command('cd ' + self.UESourceCodePath, '\$', 5) + self.command('cd cmake_targets', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) + self.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) + self.close() + + def RetrieveSystemVersion(self, machine): + if self.eNBIPAddress == 'none' or self.UEIPAddress == 'none': + self.OsVersion = 'Ubuntu 16.04.5 LTS' + self.KernelVersion = '4.15.0-45-generic' + self.UhdVersion = '3.13.0.1-0' + self.UsrpBoard = 'B210' + self.CpuNb = '4' + self.CpuModel = 'Intel(R) Core(TM) i5-6200U' + self.CpuMHz = '2399.996 MHz' + return 0 + if machine == 'eNB': + if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': + IPAddress = self.eNBIPAddress + UserName = self.eNBUserName + Password = self.eNBPassword + else: + return -1 + if machine == 'UE': + if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + else: + return -1 + + self.open(IPAddress, UserName, Password) + self.command('lsb_release -a', '\$', 5) + result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) + if result is not None: + self.OsVersion = result.group('os_type') + logging.debug('OS is: ' + self.OsVersion) + self.command('uname -r', '\$', 5) + result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', str(self.ssh.before)) + if result is not None: + self.KernelVersion = result.group('kernel_version') + logging.debug('Kernel Version is: ' + self.KernelVersion) + self.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) + result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', str(self.ssh.before)) + if result is not None: + self.UhdVersion = result.group('uhd_version') + logging.debug('UHD Version is: ' + self.UhdVersion) + self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) + result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) + if result is not None: + self.UsrpBoard = result.group('usrp_board') + logging.debug('USRP Board is: ' + self.UsrpBoard) + self.command('lscpu', '\$', 5) + result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', str(self.ssh.before)) + if result is not None: + self.CpuNb = result.group('nb_cpus') + logging.debug('nb_cpus: ' + self.CpuNb) + self.CpuModel = result.group('model') + logging.debug('model: ' + self.CpuModel) + self.CpuMHz = result.group('cpu_mhz') + ' MHz' + logging.debug('cpu_mhz: ' + self.CpuMHz) + self.close() + +#----------------------------------------------------------- +# HTML Reporting.... +#----------------------------------------------------------- + def CreateHtmlHeader(self): + if (not self.htmlHeaderCreated): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML header \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + self.htmlFile = open('test_results.html', 'w') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') + self.htmlFile.write('\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if self.ranAllowMerge != '': + commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + self.ranCommitID, shell=True, universal_newlines=True) + commit_message = commit_message.strip() + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranTargetBranch == ''): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + self.ranRepository + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + self.ranBranch + '
Source Commit ID Commit ID ' + self.ranCommitID + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + self.ranTargetBranch + '
\n') + + if (self.ADBIPAddress != 'none'): + terminate_ue_flag = True + self.GetAllUEDevices(terminate_ue_flag) + self.GetAllCatMDevices(terminate_ue_flag) + self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') + self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') + else: + self.UEDevices.append('OAI-UE') + self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.close() + + def CreateHtmlTabHeader(self): + if (not self.htmlHeaderCreated): + if (not os.path.isfile('test_results.html')): + self.CreateHtmlHeader() + self.htmlFile = open('test_results.html', 'a') + if (self.nbTestXMLfiles == 1): + self.htmlFile.write('
\n') + self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') + else: + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.htmlUEConnected == -1): + terminate_ue_flag = True + if (self.ADBIPAddress != 'none'): + self.GetAllUEDevices(terminate_ue_flag) + self.GetAllCatMDevices(terminate_ue_flag) + else: + self.UEDevices.append('OAI-UE') + self.htmlUEConnected = len(self.UEDevices) + + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' \n') + i += 1 + self.htmlFile.write(' \n') + self.htmlHeaderCreated = True + + def CreateHtmlTabFooter(self, passStatus): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') + self.htmlFile.write('
\n') + self.htmlFile.close() + time.sleep(1) + if passStatus: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" + subprocess.run(cmd, shell=True) + else: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" + subprocess.run(cmd, shell=True) + self.htmlFooterCreated = False + + def CreateHtmlFooter(self, passStatus): + if (os.path.isfile('test_results.html')): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML footer \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + + self.htmlFile = open('test_results.html', 'a') + self.htmlFile.write('
\n') + self.htmlFile.write('

\n') + self.htmlFile.write(' \n') + + machines = [ 'eNB', 'UE' ] + for machine in machines: + res = self.RetrieveSystemVersion(machine) + if res == -1: + continue + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') + self.htmlFile.write('

\n') + self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('\n') + self.htmlFile.close() + + def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + currentTime = int(round(time.time() * 1000)) - self.startTime + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + if (processesStatus == 0): + self.htmlFile.write(' ' + str(status) + '\n') + elif (processesStatus == ENB_PROCESS_FAILED): + self.htmlFile.write(' KO - eNB process not found\n') + elif (processesStatus == OAI_UE_PROCESS_FAILED): + self.htmlFile.write(' KO - OAI UE process not found\n') + elif (processesStatus == ENB_PROCESS_SEG_FAULT): + self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') + elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): + self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') + elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): + self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') + elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): + self.htmlFile.write(' OK?\n') + elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): + self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') + elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + self.htmlFile.write(' KO - UE could not sync\n') + elif (processesStatus == HSS_PROCESS_FAILED): + self.htmlFile.write(' KO - HSS process not found\n') + elif (processesStatus == MME_PROCESS_FAILED): + self.htmlFile.write(' KO - MME process not found\n') + elif (processesStatus == SPGW_PROCESS_FAILED): + self.htmlFile.write(' KO - SPGW process not found\n') + elif (processesStatus == UE_IP_ADDRESS_ISSUE): + self.htmlFile.write(' KO - Could not retrieve UE IP address\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + if (len(str(self.htmleNBFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') + self.htmleNBFailureMsg = '' + elif (len(str(self.htmlUEFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') + self.htmlUEFailureMsg = '' + else: + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + + def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + currentTime = int(round(time.time() * 1000)) - self.startTime + addOrangeBK = False + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + self.htmlFile.write(' ' + str(status) + '\n') + else: + addOrangeBK = True + self.htmlFile.write(' ' + str(status) + '\n') + i = 0 + while (i < self.htmlUEConnected): + if (i < ue_status): + if (not ue_queue.empty()): + if (addOrangeBK): + self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') + else: + self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') + else: + self.htmlFile.write(' -\n') + else: + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + +#----------------------------------------------------------- +# ShowTestID() +#----------------------------------------------------------- + def ShowTestID(self): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1mTest ID:' + self.testCase_id + '\u001B[0m') + logging.debug('\u001B[1m' + self.desc + '\u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + +#----------------------------------------------------------- +# Usage() +#----------------------------------------------------------- +def Usage(): + print('----------------------------------------------------------------------------------------------------------------------') + print('main.py Ver:' + Version) + print('----------------------------------------------------------------------------------------------------------------------') + print('Usage: python main.py [options]') + print(' --help Show this help.') + print(' --mode=[Mode]') + print(' TesteNB') + print(' InitiateHtml, FinalizeHtml') + print(' TerminateeNB, TerminateUE, TerminateHSS, TerminateMME, TerminateSPGW') + print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf') + print('---------------------------------------------------------------------------------------------------- Git Options --') + print(' --ranRepository=[OAI RAN Repository URL]') + print(' --ranBranch=[OAI RAN Repository Branch]') + print(' --ranCommitID=[OAI RAN Repository Commit SHA-1]') + print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)]') + print(' --ranTargetBranch=[Target Branch in case of a Merge Request]') + print('--------------------------------------------------------------------------------------------- eNB Server Options --') + print(' --eNBIPAddress=[eNB\'s IP Address]') + print(' --eNBUserName=[eNB\'s Login User Name]') + print(' --eNBPassword=[eNB\'s Login Password]') + print(' --eNBSourceCodePath=[eNB\'s Source Code Path]') + print('------------------------------------------------------------------------------------------ OAI UE Server Options --') + print(' --UEIPAddress=[UE\'s IP Address]') + print(' --UEUserName=[UE\'s Login User Name]') + print(' --UEPassword=[UE\'s Login Password]') + print(' --UESourceCodePath=[UE\'s Source Code Path]') + print('--------------------------------------------------------------------------------------------- EPC Server Options --') + print(' --EPCIPAddress=[EPC\'s IP Address]') + print(' --EPCUserName=[EPC\'s Login User Name]') + print(' --EPCPassword=[EPC\'s Login Password]') + print(' --EPCSourceCodePath=[EPC\'s Source Code Path]') + print(' --EPCType=[EPC\'s Type: OAI or ltebox or OAI-Rel14-CUPS]') + print('--------------------------------------------------------------------------------------------- ABD Server Options --') + print(' --ADBIPAddress=[ADB\'s IP Address]') + print(' --ADBUserName=[ADB\'s Login User Name]') + print(' --ADBPassword=[ADB\'s Login Password]') + print('----------------------------------------------------------------------------------------------------------------------') + print(' --XMLTestFile=[XML Test File to be run]') + print('----------------------------------------------------------------------------------------------------------------------') + +def CheckClassValidity(action,id): + if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': + logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) + return False + return True + +def GetParametersFromXML(action): + if action == 'Build_eNB': + SSH.Build_eNB_args = test.findtext('Build_eNB_args') + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + xmlBgBuildField = test.findtext('backgroundBuild') + if (xmlBgBuildField is None): + SSH.backgroundBuild = False + else: + if re.match('true', xmlBgBuildField, re.IGNORECASE): + SSH.backgroundBuild = True + else: + SSH.backgroundBuild = False + + if action == 'WaitEndBuild_eNB': + SSH.Build_eNB_args = test.findtext('Build_eNB_args') + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + + if action == 'Initialize_eNB': + SSH.Initialize_eNB_args = test.findtext('Initialize_eNB_args') + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + + if action == 'Terminate_eNB': + SSH.eNB_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.eNB_serverId = test.findtext('eNB_serverId') + if (SSH.eNB_serverId is None): + SSH.eNB_serverId = '0' + + if action == 'Attach_UE': + nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') + if (nbMaxUEtoAttach is None): + SSH.nbMaxUEtoAttach = -1 + else: + SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach) + + if action == 'CheckStatusUE': + expectedNBUE = test.findtext('expectedNbOfConnectedUEs') + if (expectedNBUE is None): + SSH.expectedNbOfConnectedUEs = -1 + else: + SSH.expectedNbOfConnectedUEs = int(expectedNBUE) + + if action == 'Build_OAI_UE': + SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') + + if action == 'Initialize_OAI_UE': + SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') + SSH.UE_instance = test.findtext('UE_instance') + if (SSH.UE_instance is None): + SSH.UE_instance = '0' + + if action == 'Terminate_OAI_UE': + SSH.eNB_instance = test.findtext('UE_instance') + if (SSH.UE_instance is None): + SSH.UE_instance = '0' + + if action == 'Ping' or action == 'Ping_CatM_module': + SSH.ping_args = test.findtext('ping_args') + SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') + + if action == 'Iperf': + SSH.iperf_args = test.findtext('iperf_args') + SSH.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') + SSH.iperf_profile = test.findtext('iperf_profile') + if (SSH.iperf_profile is None): + SSH.iperf_profile = 'balanced' + else: + if SSH.iperf_profile != 'balanced' and SSH.iperf_profile != 'unbalanced' and SSH.iperf_profile != 'single-ue': + logging.debug('ERROR: test-case has wrong profile ' + SSH.iperf_profile) + SSH.iperf_profile = 'balanced' + + if action == 'IdleSleep': + string_field = test.findtext('idle_sleep_time_in_sec') + if (string_field is None): + SSH.idle_sleep_time = 5 + else: + SSH.idle_sleep_time = int(string_field) + + if action == 'Perform_X2_Handover': + string_field = test.findtext('x2_ho_options') + if (string_field is None): + SSH.x2_ho_options = 'network' + else: + if string_field != 'network': + logging.error('ERROR: test-case has wrong option ' + string_field) + SSH.x2_ho_options = 'network' + else: + SSH.x2_ho_options = string_field + + +#check if given test is in list +#it is in list if one of the strings in 'list' is at the beginning of 'test' +def test_in_list(test, list): + for check in list: + check=check.replace('+','') + if (test.startswith(check)): + return True + return False + +def receive_signal(signum, frame): + sys.exit(1) + +#----------------------------------------------------------- +# Parameter Check +#----------------------------------------------------------- +mode = '' +SSH = SSHConnection() + +argvs = sys.argv +argc = len(argvs) +cwd = os.getcwd() + +while len(argvs) > 1: + myArgv = argvs.pop(1) # 0th is this file's name + if re.match('^\-\-help$', myArgv, re.IGNORECASE): + Usage() + sys.exit(0) + elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) + mode = matchReg.group(1) + elif re.match('^\-\-eNBRepository=(.+)$|^\-\-ranRepository(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) + SSH.ranRepository = matchReg.group(1) + elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) + doMerge = matchReg.group(1) + if ((doMerge == 'true') or (doMerge == 'True')): + SSH.ranAllowMerge = True + elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) + SSH.ranBranch = matchReg.group(1) + elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) + SSH.ranCommitID = matchReg.group(1) + elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) + SSH.ranTargetBranch = matchReg.group(1) + elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBIPAddress = matchReg.group(1) + elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1IPAddress = matchReg.group(1) + elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2IPAddress = matchReg.group(1) + elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBUserName = matchReg.group(1) + elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1UserName = matchReg.group(1) + elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2UserName = matchReg.group(1) + elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBPassword = matchReg.group(1) + elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1Password = matchReg.group(1) + elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2Password = matchReg.group(1) + elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.eNBSourceCodePath = matchReg.group(1) + elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB1SourceCodePath = matchReg.group(1) + elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.eNB2SourceCodePath = matchReg.group(1) + elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCIPAddress = matchReg.group(1) + elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCBranch = matchReg.group(1) + elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCUserName = matchReg.group(1) + elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCPassword = matchReg.group(1) + elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.EPCSourceCodePath = matchReg.group(1) + elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) + if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): + SSH.EPCType = matchReg.group(1) + else: + sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') + elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.ADBIPAddress = matchReg.group(1) + elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.ADBUserName = matchReg.group(1) + elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) + if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): + if re.match('distributed', matchReg.group(1), re.IGNORECASE): + SSH.ADBCentralized = False + else: + SSH.ADBCentralized = True + else: + sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') + elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.ADBPassword = matchReg.group(1) + elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) + SSH.testXMLfiles.append(matchReg.group(1)) + SSH.nbTestXMLfiles += 1 + elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) + SSH.UEIPAddress = matchReg.group(1) + elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) + SSH.UEUserName = matchReg.group(1) + elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) + SSH.UEPassword = matchReg.group(1) + elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) + SSH.UESourceCodePath = matchReg.group(1) + elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) + finalStatus = matchReg.group(1) + if ((finalStatus == 'true') or (finalStatus == 'True')): + SSH.finalStatus = True + else: + Usage() + sys.exit('Invalid Parameter: ' + myArgv) + +if re.match('^TerminateeNB$', mode, re.IGNORECASE): + if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.eNB_serverId = '0' + SSH.eNB_instance = '0' + SSH.eNBSourceCodePath = '/tmp/' + SSH.TerminateeNB() +elif re.match('^TerminateUE$', mode, re.IGNORECASE): + if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): + Usage() + sys.exit('Insufficient Parameter') + signal.signal(signal.SIGUSR1, receive_signal) + SSH.TerminateUE() +elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): + if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '': + Usage() + sys.exit('Insufficient Parameter') + signal.signal(signal.SIGUSR1, receive_signal) + SSH.TerminateOAIUE() +elif re.match('^TerminateHSS$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.TerminateHSS() +elif re.match('^TerminateMME$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.TerminateMME() +elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.TerminateSPGW() +elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): + if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == ''): + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectBuild() +elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): + if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollecteNB() +elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectHSS() +elif re.match('^LogCollectMME$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectMME() +elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectSPGW() +elif re.match('^LogCollectPing$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectPing() +elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): + if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectIperf() +elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): + if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectOAIUE() +elif re.match('^InitiateHtml$', mode, re.IGNORECASE): + if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): + Usage() + sys.exit('Insufficient Parameter') + count = 0 + foundCount = 0 + while (count < SSH.nbTestXMLfiles): + xml_test_file = cwd + "/" + SSH.testXMLfiles[count] + xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count] + if (os.path.isfile(xml_test_file)): + xmlTree = ET.parse(xml_test_file) + xmlRoot = xmlTree.getroot() + SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) + SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + foundCount += 1 + count += 1 + if foundCount != SSH.nbTestXMLfiles: + SSH.nbTestXMLfiles = foundCount + SSH.CreateHtmlHeader() +elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): + SSH.CreateHtmlFooter(SSH.finalStatus) +elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): + if re.match('^TesteNB$', mode, re.IGNORECASE): + if SSH.eNBIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': + Usage() + sys.exit('Insufficient Parameter') + + if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): + SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") + SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") + else: + if SSH.UEIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + Usage() + sys.exit('UE: Insufficient Parameter') + + #read test_case_list.xml file + # if no parameters for XML file, use default value + if (SSH.nbTestXMLfiles != 1): + xml_test_file = cwd + "/test_case_list.xml" + else: + xml_test_file = cwd + "/" + SSH.testXMLfiles[0] + + xmlTree = ET.parse(xml_test_file) + xmlRoot = xmlTree.getroot() + + exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') + requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') + if (SSH.nbTestXMLfiles == 1): + SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) + repeatCount = xmlRoot.findtext('repeatCount',default='1') + SSH.repeatCounts.append(int(repeatCount)) + all_tests=xmlRoot.findall('testCase') + + exclusion_tests=exclusion_tests.split() + requested_tests=requested_tests.split() + + #check that exclusion tests are well formatted + #(6 digits or less than 6 digits followed by +) + for test in exclusion_tests: + if (not re.match('^[0-9]{6}$', test) and + not re.match('^[0-9]{1,5}\+$', test)): + logging.debug('ERROR: exclusion test is invalidly formatted: ' + test) + sys.exit(1) + else: + logging.debug(test) + + #check that requested tests are well formatted + #(6 digits or less than 6 digits followed by +) + #be verbose + for test in requested_tests: + if (re.match('^[0-9]{6}$', test) or + re.match('^[0-9]{1,5}\+$', test)): + logging.debug('INFO: test group/case requested: ' + test) + else: + logging.debug('ERROR: requested test is invalidly formatted: ' + test) + sys.exit(1) + if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): + SSH.CheckFlexranCtrlInstallation() + + #get the list of tests to be done + todo_tests=[] + for test in requested_tests: + if (test_in_list(test, exclusion_tests)): + logging.debug('INFO: test will be skipped: ' + test) + else: + #logging.debug('INFO: test will be run: ' + test) + todo_tests.append(test) + + signal.signal(signal.SIGUSR1, receive_signal) + + SSH.CreateHtmlTabHeader() + + self.cnt = 0 + SSH.prematureExit = True + SSH.startTime = int(round(time.time() * 1000)) + while self.cnt < SSH.repeatCounts[0] and SSH.prematureExit: + SSH.prematureExit = False + for test_case_id in todo_tests: + if SSH.prematureExit: + break + for test in all_tests: + if SSH.prematureExit: + break + id = test.get('id') + if test_case_id != id: + continue + SSH.testCase_id = id + SSH.desc = test.findtext('desc') + action = test.findtext('class') + if (CheckClassValidity(action, id) == False): + continue + SSH.ShowTestID() + GetParametersFromXML(action) + if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': + if (SSH.ADBIPAddress != 'none'): + terminate_ue_flag = False + SSH.GetAllUEDevices(terminate_ue_flag) + if action == 'Build_eNB': + SSH.BuildeNB() + elif action == 'WaitEndBuild_eNB': + SSH.WaitBuildeNBisFinished() + elif action == 'Initialize_eNB': + SSH.InitializeeNB() + elif action == 'Terminate_eNB': + SSH.TerminateeNB() + elif action == 'Initialize_UE': + SSH.InitializeUE() + elif action == 'Terminate_UE': + SSH.TerminateUE() + elif action == 'Attach_UE': + SSH.AttachUE() + elif action == 'Detach_UE': + SSH.DetachUE() + elif action == 'DataDisable_UE': + SSH.DataDisableUE() + elif action == 'DataEnable_UE': + SSH.DataEnableUE() + elif action == 'CheckStatusUE': + SSH.CheckStatusUE() + elif action == 'Build_OAI_UE': + SSH.BuildOAIUE() + elif action == 'Initialize_OAI_UE': + SSH.InitializeOAIUE() + elif action == 'Terminate_OAI_UE': + SSH.TerminateOAIUE() + elif action == 'Initialize_CatM_module': + SSH.InitializeCatM() + elif action == 'Terminate_CatM_module': + SSH.TerminateCatM() + elif action == 'Attach_CatM_module': + SSH.AttachCatM() + elif action == 'Detach_CatM_module': + SSH.TerminateCatM() + elif action == 'Ping_CatM_module': + SSH.PingCatM() + elif action == 'Ping': + SSH.Ping() + elif action == 'Iperf': + SSH.Iperf() + elif action == 'Reboot_UE': + SSH.RebootUE() + elif action == 'Initialize_HSS': + SSH.InitializeHSS() + elif action == 'Terminate_HSS': + SSH.TerminateHSS() + elif action == 'Initialize_MME': + SSH.InitializeMME() + elif action == 'Terminate_MME': + SSH.TerminateMME() + elif action == 'Initialize_SPGW': + SSH.InitializeSPGW() + elif action == 'Terminate_SPGW': + SSH.TerminateSPGW() + elif action == 'Initialize_FlexranCtrl': + SSH.InitializeFlexranCtrl() + elif action == 'Terminate_FlexranCtrl': + SSH.TerminateFlexranCtrl() + elif action == 'IdleSleep': + SSH.IdleSleep() + elif action == 'Perform_X2_Handover': + SSH.Perform_X2_Handover() + else: + sys.exit('Invalid action') + self.cnt += 1 + if self.cnt == SSH.repeatCounts[0] and SSH.prematureExit: + logging.debug('Testsuite failed ' + str(self.cnt) + ' time(s)') + SSH.CreateHtmlTabFooter(False) + sys.exit('Failed Scenario') + else: + logging.info('Testsuite passed after ' + str(self.cnt) + ' time(s)') + SSH.CreateHtmlTabFooter(True) +else: + Usage() + sys.exit('Invalid mode') +sys.exit(0) From 28eb2d61bb2c55caad713b0af2d2ec88116464f5 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 9 Dec 2019 22:04:22 +0100 Subject: [PATCH 070/175] fixing self.cnt to SSH.cnt mistake --- ci-scripts/main-index-to-class.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ci-scripts/main-index-to-class.py b/ci-scripts/main-index-to-class.py index 04a31302ae..e782d30ae0 100644 --- a/ci-scripts/main-index-to-class.py +++ b/ci-scripts/main-index-to-class.py @@ -4816,10 +4816,10 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.CreateHtmlTabHeader() - self.cnt = 0 + SSH.cnt = 0 SSH.prematureExit = True SSH.startTime = int(round(time.time() * 1000)) - while self.cnt < SSH.repeatCounts[0] and SSH.prematureExit: + while SSH.cnt < SSH.repeatCounts[0] and SSH.prematureExit: SSH.prematureExit = False for test_case_id in todo_tests: if SSH.prematureExit: @@ -4907,13 +4907,13 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.Perform_X2_Handover() else: sys.exit('Invalid action') - self.cnt += 1 - if self.cnt == SSH.repeatCounts[0] and SSH.prematureExit: - logging.debug('Testsuite failed ' + str(self.cnt) + ' time(s)') + SSH.cnt += 1 + if SSH.cnt == SSH.repeatCounts[0] and SSH.prematureExit: + logging.debug('Testsuite failed ' + str(SSH.cnt) + ' time(s)') SSH.CreateHtmlTabFooter(False) sys.exit('Failed Scenario') else: - logging.info('Testsuite passed after ' + str(self.cnt) + ' time(s)') + logging.info('Testsuite passed after ' + str(SSH.cnt) + ' time(s)') SSH.CreateHtmlTabFooter(True) else: Usage() From 581e46f1d3d447dc3af86ff0305ba9133a84fb3a Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Wed, 11 Dec 2019 14:28:14 +0100 Subject: [PATCH 071/175] introduced a class object FailRepeatCnt in place of a static counter --- ci-scripts/main-index-to-class.py | 98 +++++++++++++++---------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/ci-scripts/main-index-to-class.py b/ci-scripts/main-index-to-class.py index e782d30ae0..68b9558740 100644 --- a/ci-scripts/main-index-to-class.py +++ b/ci-scripts/main-index-to-class.py @@ -93,7 +93,7 @@ logging.basicConfig( #----------------------------------------------------------- class SSHConnection(): def __init__(self): - self.cnt = 0 # cnt from index to object of a class + self.FailReportCnt = 0 # FailReportCnt was an index inside the SSH instantiation (called "cnt"), now it becomes an object self.prematureExit = False self.ranRepository = '' self.ranBranch = '' @@ -1433,11 +1433,11 @@ class SSHConnection(): html_queue.put(html_cell) if (attach_status): # cnt from index to object of a class - self.cnt = 0 - while self.cnt < len(self.UEDevices): - if self.UEDevicesStatus[self.cnt] == UE_STATUS_ATTACHING: - self.UEDevicesStatus[self.cnt] = UE_STATUS_ATTACHED - self.cnt += 1 + cnt = 0 + while cnt < len(self.UEDevices): + if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: + self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED + cnt += 1 self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: @@ -1474,14 +1474,14 @@ class SSHConnection(): self.AutoTerminateUEandeNB() return multi_jobs = [] - self.cnt = 0 + cnt = 0 for device_id in self.UEDevices: - self.UEDevicesStatus[self.cnt] = UE_STATUS_DETACHING - p = Process(target = self.DetachUE_common, args = (device_id,self.cnt,)) + self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING + p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) p.daemon = True p.start() multi_jobs.append(p) - self.cnt += 1 + cnt += 1 for job in multi_jobs: job.join() self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) @@ -1489,10 +1489,10 @@ class SSHConnection(): if result is not None: logging.debug('Waiting 5 seconds to fill up record file') time.sleep(5) - self.cnt = 0 - while self.cnt < len(self.UEDevices): - self.UEDevicesStatus[self.cnt] = UE_STATUS_DETACHED - self.cnt += 1 + cnt = 0 + while cnt < len(self.UEDevices): + self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED + cnt += 1 def RebootUE_common(self, device_id): try: @@ -1650,10 +1650,10 @@ class SSHConnection(): logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') sys.exit(1) if len(self.UEDevicesStatus) == 0: - self.cnt = 0 - while self.cnt < len(self.UEDevices): + cnt = 0 + while cnt < len(self.UEDevices): self.UEDevicesStatus.append(UE_STATUS_DETACHED) - self.cnt += 1 + cnt += 1 def GetAllCatMDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': @@ -3735,38 +3735,38 @@ class SSHConnection(): cmd = "jq '.mac_stats | length' " + fileName strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) self.x2NbENBs = int(strNbEnbs.strip()) - self.cnt = 0 - while self.cnt < self.x2NbENBs: - cmd = "jq '.mac_stats[" + str(self.cnt) + "].bs_id' " + fileName + cnt = 0 + while cnt < self.x2NbENBs: + cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) self.x2ENBBsIds[idx].append(bs_id.strip()) - cmd = "jq '.mac_stats[" + str(self.cnt) + "].ue_mac_stats | length' " + fileName + cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) nbUEs = int(stNbUEs.strip()) ueIdx = 0 self.x2ENBConnectedUEs[idx].append([]) while ueIdx < nbUEs: - cmd = "jq '.mac_stats[" + str(self.cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName + cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBConnectedUEs[idx][self.cnt].append(rnti.strip()) + self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip()) ueIdx += 1 - self.cnt += 1 + cnt += 1 msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" logging.debug(msg) message += msg + '\n' - self.cnt = 0 - while self.cnt < self.x2NbENBs: - msg = " -- eNB: " + str(self.x2ENBBsIds[idx][self.cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][self.cnt])) + " UE(s)" + cnt = 0 + while cnt < self.x2NbENBs: + msg = " -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][self.cnt])) + " UE(s)" logging.debug(msg) message += msg + '\n' ueIdx = 0 - while ueIdx < len(self.x2ENBConnectedUEs[idx][self.cnt]): - msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][self.cnt][ueIdx]) + while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]): + msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx]) logging.debug(msg) message += msg + '\n' ueIdx += 1 - self.cnt += 1 + cnt += 1 return message def Perform_X2_Handover(self): @@ -3789,38 +3789,38 @@ class SSHConnection(): logging.debug(msg) fullMessage += msg + '\n' eNB_cnt = self.x2NbENBs - self.cnt = 0 - while self.cnt < eNB_cnt: - cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][self.cnt]) + "/1" + cnt = 0 + while cnt < eNB_cnt: + cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1" logging.debug(cmd) fullMessage += cmd + '\n' subprocess.run(cmd, shell=True) - self.cnt += 1 + cnt += 1 # Waiting for the activation to be active time.sleep(10) msg = "Switching UE(s) from eNB to eNB" logging.debug(msg) fullMessage += msg + '\n' - self.cnt = 0 - while self.cnt < eNB_cnt: + cnt = 0 + while cnt < eNB_cnt: ueIdx = 0 - while ueIdx < len(self.x2ENBConnectedUEs[0][self.cnt]): - cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][self.cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1]) + while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]): + cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1]) logging.debug(cmd) fullMessage += cmd + '\n' subprocess.run(cmd, shell=True) ueIdx += 1 - self.cnt += 1 + cnt += 1 time.sleep(10) # check logging.debug("Checking the Status after X2 Handover") fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') - self.cnt = 0 + cnt = 0 x2Status = True - while self.cnt < eNB_cnt: - if len(self.x2ENBConnectedUEs[0][self.cnt]) == len(self.x2ENBConnectedUEs[1][cnt]): + while cnt < eNB_cnt: + if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]): x2Status = False - self.cnt += 1 + cnt += 1 if x2Status: msg = "X2 Handover was successful" logging.debug(msg) @@ -4816,10 +4816,10 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.CreateHtmlTabHeader() - SSH.cnt = 0 + SSH.FailReportCnt = 0 SSH.prematureExit = True SSH.startTime = int(round(time.time() * 1000)) - while SSH.cnt < SSH.repeatCounts[0] and SSH.prematureExit: + while SSH.FailReportCnt < SSH.repeatCounts[0] and SSH.prematureExit: SSH.prematureExit = False for test_case_id in todo_tests: if SSH.prematureExit: @@ -4907,13 +4907,13 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.Perform_X2_Handover() else: sys.exit('Invalid action') - SSH.cnt += 1 - if SSH.cnt == SSH.repeatCounts[0] and SSH.prematureExit: - logging.debug('Testsuite failed ' + str(SSH.cnt) + ' time(s)') + SSH.FailReportCnt += 1 + if SSH.FailReportCnt == SSH.repeatCounts[0] and SSH.prematureExit: + logging.debug('Testsuite failed ' + str(SSH.FailReportCnt) + ' time(s)') SSH.CreateHtmlTabFooter(False) sys.exit('Failed Scenario') else: - logging.info('Testsuite passed after ' + str(SSH.cnt) + ' time(s)') + logging.info('Testsuite passed after ' + str(SSH.FailReportCnt) + ' time(s)') SSH.CreateHtmlTabFooter(True) else: Usage() From ed6559ffa970503b5dcac77ec340457bf1b006f3 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 12 Dec 2019 10:37:53 +0100 Subject: [PATCH 072/175] add CU measurement: whole CPU active time per subframe --- executables/main-fs6.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 0dbd9a3b45..ab57bc611d 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1408,6 +1408,7 @@ void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { } void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t DuClock, uint64_t startCycle) { + initRefTimes(CUprocessing); // Fixme: datamodel issue PHY_VARS_eNB *eNB = RC.eNB[0][0]; pthread_mutex_lock(&eNB->UL_INFO_mutex); @@ -1429,6 +1430,7 @@ void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t DuClock, uint64_t start hDL(bufferZone)->DuClock=DuClock; hDL(bufferZone)->CuSpentMicroSec=(rdtsc()-startCycle)/(cpuf*1000); + updateTimesReset(startCycle, &CUprocessing, 1000, true,"CU entire processing from recv to send"); sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 ); return; } From ae3a540f40d80119abd6770d851ddc7f811b3fd2 Mon Sep 17 00:00:00 2001 From: projetstc <> Date: Mon, 16 Dec 2019 11:37:51 +0100 Subject: [PATCH 073/175] scope autoscale --- openair1/PHY/TOOLS/lte_phy_scope.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 3ac1676983..c5111957e9 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -325,12 +325,18 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, // PUSCH I/Q of MF Output if (pusch_comp!=NULL) { ind=0; + int range=80*1000*1000; for (k=0; ksymbols_per_tti; k++) { for (i=0; i<12*frame_parms->N_RB_UL; i++) { - I[ind] = pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i]; - Q[ind] = pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i+1]; - ind++; + if ( pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i] > -range && + pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i] < range && + pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i+1] > -range && + pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i+1] < range ) { + I[ind] = pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i]; + Q[ind] = pusch_comp[(2*frame_parms->N_RB_UL*12*k)+2*i+1]; + ind++; + } } } From 091be33b629e69e66598be17b93cb619c0a47da6 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 16 Dec 2019 15:59:54 +0100 Subject: [PATCH 074/175] main.py mods: coloured rows between retries and variable cnt become an object (FailReportCnt) --- ci-scripts/main.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index bac3599150..78c0d1fc99 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -93,6 +93,7 @@ logging.basicConfig( #----------------------------------------------------------- class SSHConnection(): def __init__(self): + self.FailReportCnt = 0 self.prematureExit = False self.ranRepository = '' self.ranBranch = '' @@ -4213,6 +4214,12 @@ class SSHConnection(): self.htmlFile.write('\n') self.htmlFile.close() + def CreateHtmlRetrySeparator(self): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile.write(' \n') + self.htmlFile.write(' Try Run #' + str(self.FailReportCnt) + '\n') + self.htmlFile.write(' \n') + def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): currentTime = int(round(time.time() * 1000)) - self.startTime @@ -4814,11 +4821,13 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.CreateHtmlTabHeader() - cnt = 0 + SSH.FailReportCnt = 0 SSH.prematureExit = True SSH.startTime = int(round(time.time() * 1000)) - while cnt < SSH.repeatCounts[0] and SSH.prematureExit: + while SSH.FailReportCnt < SSH.repeatCounts[0] and SSH.prematureExit: SSH.prematureExit = False + # At every iteratin of the retry loop, a separator will be added + SSH.CreateHtmlRetrySeparator() for test_case_id in todo_tests: if SSH.prematureExit: break @@ -4905,13 +4914,13 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.Perform_X2_Handover() else: sys.exit('Invalid action') - cnt += 1 - if cnt == SSH.repeatCounts[0] and SSH.prematureExit: - logging.debug('Testsuite failed ' + str(cnt) + ' time(s)') + SSH.FailReportCnt += 1 + if SSH.FailReportCnt == SSH.repeatCounts[0] and SSH.prematureExit: + logging.debug('Testsuite failed ' + str(SSH.FailReportCnt) + ' time(s)') SSH.CreateHtmlTabFooter(False) sys.exit('Failed Scenario') else: - logging.info('Testsuite passed after ' + str(cnt) + ' time(s)') + logging.info('Testsuite passed after ' + str(SSH.FailReportCnt) + ' time(s)') SSH.CreateHtmlTabFooter(True) else: Usage() From 4d57f1bda8b4e068c70c1f4c9d208278117bea89 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 7 Jan 2020 14:43:49 +0100 Subject: [PATCH 075/175] class name changed from SSH to CiTestObj --- ci-scripts/main.py | 420 ++++++++++++++++++++++----------------------- 1 file changed, 210 insertions(+), 210 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 78c0d1fc99..bb0e92a23f 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -91,7 +91,7 @@ logging.basicConfig( #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- -class SSHConnection(): +class OaiCiTest(): def __init__(self): self.FailReportCnt = 0 self.prematureExit = False @@ -230,7 +230,7 @@ class SSHConnection(): if connect_status: pass else: - sys.exit('SSH Connection Failed') + sys.exit('CiTestObj.Connection Failed') def command(self, commandline, expectedline, timeout): logging.debug(commandline) @@ -2810,7 +2810,7 @@ class SSHConnection(): status_queue = SimpleQueue() for UE_IPAddress in self.UEIPAddresses: device_id = self.UEDevices[i] - p = Process(target = SSH.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) + p = Process(target = CiTestObj.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2850,15 +2850,15 @@ class SSHConnection(): # in noS1 config, no need to check status from EPC result = re.search('noS1', str(self.Initialize_eNB_args)) if result is None: - p = Process(target = SSH.CheckHSSProcess, args = (status_queue,)) + p = Process(target = CiTestObj.CheckHSSProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) - p = Process(target = SSH.CheckMMEProcess, args = (status_queue,)) + p = Process(target = CiTestObj.CheckMMEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) - p = Process(target = SSH.CheckSPGWProcess, args = (status_queue,)) + p = Process(target = CiTestObj.CheckSPGWProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2866,12 +2866,12 @@ class SSHConnection(): if (check_eNB == False) and (check_OAI_UE == False): return 0 if check_eNB: - p = Process(target = SSH.CheckeNBProcess, args = (status_queue,)) + p = Process(target = CiTestObj.CheckeNBProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) if check_OAI_UE: - p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) + p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2902,7 +2902,7 @@ class SSHConnection(): multi_jobs = [] status_queue = SimpleQueue() if initialize_OAI_UE_flag == False: - p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) + p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -3639,7 +3639,7 @@ class SSHConnection(): multi_jobs = [] i = 0 for device_id in self.UEDevices: - p = Process(target= SSH.TerminateUE_common, args = (device_id,i,)) + p = Process(target= CiTestObj.TerminateUE_common, args = (device_id,i,)) p.daemon = True p.start() multi_jobs.append(p) @@ -4382,108 +4382,108 @@ def CheckClassValidity(action,id): def GetParametersFromXML(action): if action == 'Build_eNB': - SSH.Build_eNB_args = test.findtext('Build_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' + CiTestObj.Build_eNB_args = test.findtext('Build_eNB_args') + CiTestObj.eNB_instance = test.findtext('eNB_instance') + if (CiTestObj.eNB_instance is None): + CiTestObj.eNB_instance = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' xmlBgBuildField = test.findtext('backgroundBuild') if (xmlBgBuildField is None): - SSH.backgroundBuild = False + CiTestObj.backgroundBuild = False else: if re.match('true', xmlBgBuildField, re.IGNORECASE): - SSH.backgroundBuild = True + CiTestObj.backgroundBuild = True else: - SSH.backgroundBuild = False + CiTestObj.backgroundBuild = False if action == 'WaitEndBuild_eNB': - SSH.Build_eNB_args = test.findtext('Build_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' + CiTestObj.Build_eNB_args = test.findtext('Build_eNB_args') + CiTestObj.eNB_instance = test.findtext('eNB_instance') + if (CiTestObj.eNB_instance is None): + CiTestObj.eNB_instance = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' if action == 'Initialize_eNB': - SSH.Initialize_eNB_args = test.findtext('Initialize_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' + CiTestObj.Initialize_eNB_args = test.findtext('Initialize_eNB_args') + CiTestObj.eNB_instance = test.findtext('eNB_instance') + if (CiTestObj.eNB_instance is None): + CiTestObj.eNB_instance = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' if action == 'Terminate_eNB': - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' + CiTestObj.eNB_instance = test.findtext('eNB_instance') + if (CiTestObj.eNB_instance is None): + CiTestObj.eNB_instance = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' if action == 'Attach_UE': nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') if (nbMaxUEtoAttach is None): - SSH.nbMaxUEtoAttach = -1 + CiTestObj.nbMaxUEtoAttach = -1 else: - SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach) + CiTestObj.nbMaxUEtoAttach = int(nbMaxUEtoAttach) if action == 'CheckStatusUE': expectedNBUE = test.findtext('expectedNbOfConnectedUEs') if (expectedNBUE is None): - SSH.expectedNbOfConnectedUEs = -1 + CiTestObj.expectedNbOfConnectedUEs = -1 else: - SSH.expectedNbOfConnectedUEs = int(expectedNBUE) + CiTestObj.expectedNbOfConnectedUEs = int(expectedNBUE) if action == 'Build_OAI_UE': - SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') + CiTestObj.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') if action == 'Initialize_OAI_UE': - SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') - SSH.UE_instance = test.findtext('UE_instance') - if (SSH.UE_instance is None): - SSH.UE_instance = '0' + CiTestObj.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') + CiTestObj.UE_instance = test.findtext('UE_instance') + if (CiTestObj.UE_instance is None): + CiTestObj.UE_instance = '0' if action == 'Terminate_OAI_UE': - SSH.eNB_instance = test.findtext('UE_instance') - if (SSH.UE_instance is None): - SSH.UE_instance = '0' + CiTestObj.eNB_instance = test.findtext('UE_instance') + if (CiTestObj.UE_instance is None): + CiTestObj.UE_instance = '0' if action == 'Ping' or action == 'Ping_CatM_module': - SSH.ping_args = test.findtext('ping_args') - SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') + CiTestObj.ping_args = test.findtext('ping_args') + CiTestObj.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') if action == 'Iperf': - SSH.iperf_args = test.findtext('iperf_args') - SSH.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') - SSH.iperf_profile = test.findtext('iperf_profile') - if (SSH.iperf_profile is None): - SSH.iperf_profile = 'balanced' + CiTestObj.iperf_args = test.findtext('iperf_args') + CiTestObj.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') + CiTestObj.iperf_profile = test.findtext('iperf_profile') + if (CiTestObj.iperf_profile is None): + CiTestObj.iperf_profile = 'balanced' else: - if SSH.iperf_profile != 'balanced' and SSH.iperf_profile != 'unbalanced' and SSH.iperf_profile != 'single-ue': - logging.debug('ERROR: test-case has wrong profile ' + SSH.iperf_profile) - SSH.iperf_profile = 'balanced' + if CiTestObj.iperf_profile != 'balanced' and CiTestObj.iperf_profile != 'unbalanced' and CiTestObj.iperf_profile != 'single-ue': + logging.debug('ERROR: test-case has wrong profile ' + CiTestObj.iperf_profile) + CiTestObj.iperf_profile = 'balanced' if action == 'IdleSleep': string_field = test.findtext('idle_sleep_time_in_sec') if (string_field is None): - SSH.idle_sleep_time = 5 + CiTestObj.idle_sleep_time = 5 else: - SSH.idle_sleep_time = int(string_field) + CiTestObj.idle_sleep_time = int(string_field) if action == 'Perform_X2_Handover': string_field = test.findtext('x2_ho_options') if (string_field is None): - SSH.x2_ho_options = 'network' + CiTestObj.x2_ho_options = 'network' else: if string_field != 'network': logging.error('ERROR: test-case has wrong option ' + string_field) - SSH.x2_ho_options = 'network' + CiTestObj.x2_ho_options = 'network' else: - SSH.x2_ho_options = string_field + CiTestObj.x2_ho_options = string_field #check if given test is in list @@ -4502,7 +4502,7 @@ def receive_signal(signum, frame): # Parameter Check #----------------------------------------------------------- mode = '' -SSH = SSHConnection() +CiTestObj = OaiCiTest() argvs = sys.argv argc = len(argvs) @@ -4521,7 +4521,7 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) - SSH.ranRepository = matchReg.group(1) + CiTestObj.ranRepository = matchReg.group(1) elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) @@ -4529,257 +4529,257 @@ while len(argvs) > 1: matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) doMerge = matchReg.group(1) if ((doMerge == 'true') or (doMerge == 'True')): - SSH.ranAllowMerge = True + CiTestObj.ranAllowMerge = True elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) - SSH.ranBranch = matchReg.group(1) + CiTestObj.ranBranch = matchReg.group(1) elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) - SSH.ranCommitID = matchReg.group(1) + CiTestObj.ranCommitID = matchReg.group(1) elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) - SSH.ranTargetBranch = matchReg.group(1) + CiTestObj.ranTargetBranch = matchReg.group(1) elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBIPAddress = matchReg.group(1) + CiTestObj.eNBIPAddress = matchReg.group(1) elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1IPAddress = matchReg.group(1) + CiTestObj.eNB1IPAddress = matchReg.group(1) elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2IPAddress = matchReg.group(1) + CiTestObj.eNB2IPAddress = matchReg.group(1) elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBUserName = matchReg.group(1) + CiTestObj.eNBUserName = matchReg.group(1) elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1UserName = matchReg.group(1) + CiTestObj.eNB1UserName = matchReg.group(1) elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2UserName = matchReg.group(1) + CiTestObj.eNB2UserName = matchReg.group(1) elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBPassword = matchReg.group(1) + CiTestObj.eNBPassword = matchReg.group(1) elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1Password = matchReg.group(1) + CiTestObj.eNB1Password = matchReg.group(1) elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2Password = matchReg.group(1) + CiTestObj.eNB2Password = matchReg.group(1) elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBSourceCodePath = matchReg.group(1) + CiTestObj.eNBSourceCodePath = matchReg.group(1) elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1SourceCodePath = matchReg.group(1) + CiTestObj.eNB1SourceCodePath = matchReg.group(1) elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2SourceCodePath = matchReg.group(1) + CiTestObj.eNB2SourceCodePath = matchReg.group(1) elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCIPAddress = matchReg.group(1) + CiTestObj.EPCIPAddress = matchReg.group(1) elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCBranch = matchReg.group(1) + CiTestObj.EPCBranch = matchReg.group(1) elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCUserName = matchReg.group(1) + CiTestObj.EPCUserName = matchReg.group(1) elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCPassword = matchReg.group(1) + CiTestObj.EPCPassword = matchReg.group(1) elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCSourceCodePath = matchReg.group(1) + CiTestObj.EPCSourceCodePath = matchReg.group(1) elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): - SSH.EPCType = matchReg.group(1) + CiTestObj.EPCType = matchReg.group(1) else: sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBIPAddress = matchReg.group(1) + CiTestObj.ADBIPAddress = matchReg.group(1) elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBUserName = matchReg.group(1) + CiTestObj.ADBUserName = matchReg.group(1) elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): if re.match('distributed', matchReg.group(1), re.IGNORECASE): - SSH.ADBCentralized = False + CiTestObj.ADBCentralized = False else: - SSH.ADBCentralized = True + CiTestObj.ADBCentralized = True else: sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBPassword = matchReg.group(1) + CiTestObj.ADBPassword = matchReg.group(1) elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) - SSH.testXMLfiles.append(matchReg.group(1)) - SSH.nbTestXMLfiles += 1 + CiTestObj.testXMLfiles.append(matchReg.group(1)) + CiTestObj.nbTestXMLfiles += 1 elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.UEIPAddress = matchReg.group(1) + CiTestObj.UEIPAddress = matchReg.group(1) elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.UEUserName = matchReg.group(1) + CiTestObj.UEUserName = matchReg.group(1) elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.UEPassword = matchReg.group(1) + CiTestObj.UEPassword = matchReg.group(1) elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.UESourceCodePath = matchReg.group(1) + CiTestObj.UESourceCodePath = matchReg.group(1) elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) finalStatus = matchReg.group(1) if ((finalStatus == 'true') or (finalStatus == 'True')): - SSH.finalStatus = True + CiTestObj.finalStatus = True else: Usage() sys.exit('Invalid Parameter: ' + myArgv) if re.match('^TerminateeNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '': + if CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '': Usage() sys.exit('Insufficient Parameter') - SSH.eNB_serverId = '0' - SSH.eNB_instance = '0' - SSH.eNBSourceCodePath = '/tmp/' - SSH.TerminateeNB() + CiTestObj.eNB_serverId = '0' + CiTestObj.eNB_instance = '0' + CiTestObj.eNBSourceCodePath = '/tmp/' + CiTestObj.TerminateeNB() elif re.match('^TerminateUE$', mode, re.IGNORECASE): - if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): + if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): Usage() sys.exit('Insufficient Parameter') signal.signal(signal.SIGUSR1, receive_signal) - SSH.TerminateUE() + CiTestObj.TerminateUE() elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '': + if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '': Usage() sys.exit('Insufficient Parameter') signal.signal(signal.SIGUSR1, receive_signal) - SSH.TerminateOAIUE() + CiTestObj.TerminateOAIUE() elif re.match('^TerminateHSS$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.TerminateHSS() + CiTestObj.TerminateHSS() elif re.match('^TerminateMME$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.TerminateMME() + CiTestObj.TerminateMME() elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.TerminateSPGW() + CiTestObj.TerminateSPGW() elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): - if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == ''): + if (CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectBuild() + CiTestObj.LogCollectBuild() elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '': + if CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollecteNB() + CiTestObj.LogCollecteNB() elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectHSS() + CiTestObj.LogCollectHSS() elif re.match('^LogCollectMME$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectMME() + CiTestObj.LogCollectMME() elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectSPGW() + CiTestObj.LogCollectSPGW() elif re.match('^LogCollectPing$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectPing() + CiTestObj.LogCollectPing() elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': + if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectIperf() + CiTestObj.LogCollectIperf() elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - SSH.LogCollectOAIUE() + CiTestObj.LogCollectOAIUE() elif re.match('^InitiateHtml$', mode, re.IGNORECASE): - if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): + if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): Usage() sys.exit('Insufficient Parameter') count = 0 foundCount = 0 - while (count < SSH.nbTestXMLfiles): - xml_test_file = cwd + "/" + SSH.testXMLfiles[count] - xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count] + while (count < CiTestObj.nbTestXMLfiles): + xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[count] + xml_test_file = sys.path[0] + "/" + CiTestObj.testXMLfiles[count] if (os.path.isfile(xml_test_file)): xmlTree = ET.parse(xml_test_file) xmlRoot = xmlTree.getroot() - SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) + CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) foundCount += 1 count += 1 - if foundCount != SSH.nbTestXMLfiles: - SSH.nbTestXMLfiles = foundCount - SSH.CreateHtmlHeader() + if foundCount != CiTestObj.nbTestXMLfiles: + CiTestObj.nbTestXMLfiles = foundCount + CiTestObj.CreateHtmlHeader() elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - SSH.CreateHtmlFooter(SSH.finalStatus) + CiTestObj.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': + if CiTestObj.eNBIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '' or CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') - if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): - SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") - SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") + if (CiTestObj.EPCIPAddress != '') and (CiTestObj.EPCIPAddress != 'none'): + CiTestObj.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") + CiTestObj.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") else: - if SSH.UEIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + if CiTestObj.UEIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': Usage() sys.exit('UE: Insufficient Parameter') #read test_case_list.xml file # if no parameters for XML file, use default value - if (SSH.nbTestXMLfiles != 1): + if (CiTestObj.nbTestXMLfiles != 1): xml_test_file = cwd + "/test_case_list.xml" else: - xml_test_file = cwd + "/" + SSH.testXMLfiles[0] + xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0] xmlTree = ET.parse(xml_test_file) xmlRoot = xmlTree.getroot() exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') - if (SSH.nbTestXMLfiles == 1): - SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) + if (CiTestObj.nbTestXMLfiles == 1): + CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) repeatCount = xmlRoot.findtext('repeatCount',default='1') - SSH.repeatCounts.append(int(repeatCount)) + CiTestObj.repeatCounts.append(int(repeatCount)) all_tests=xmlRoot.findall('testCase') exclusion_tests=exclusion_tests.split() @@ -4805,8 +4805,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re else: logging.debug('ERROR: requested test is invalidly formatted: ' + test) sys.exit(1) - if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): - SSH.CheckFlexranCtrlInstallation() + if (CiTestObj.EPCIPAddress != '') and (CiTestObj.EPCIPAddress != 'none'): + CiTestObj.CheckFlexranCtrlInstallation() #get the list of tests to be done todo_tests=[] @@ -4819,109 +4819,109 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re signal.signal(signal.SIGUSR1, receive_signal) - SSH.CreateHtmlTabHeader() + CiTestObj.CreateHtmlTabHeader() - SSH.FailReportCnt = 0 - SSH.prematureExit = True - SSH.startTime = int(round(time.time() * 1000)) - while SSH.FailReportCnt < SSH.repeatCounts[0] and SSH.prematureExit: - SSH.prematureExit = False + CiTestObj.FailReportCnt = 0 + CiTestObj.prematureExit = True + CiTestObj.startTime = int(round(time.time() * 1000)) + while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: + CiTestObj.prematureExit = False # At every iteratin of the retry loop, a separator will be added - SSH.CreateHtmlRetrySeparator() + CiTestObj.CreateHtmlRetrySeparator() for test_case_id in todo_tests: - if SSH.prematureExit: + if CiTestObj.prematureExit: break for test in all_tests: - if SSH.prematureExit: + if CiTestObj.prematureExit: break id = test.get('id') if test_case_id != id: continue - SSH.testCase_id = id - SSH.desc = test.findtext('desc') + CiTestObj.testCase_id = id + CiTestObj.desc = test.findtext('desc') action = test.findtext('class') if (CheckClassValidity(action, id) == False): continue - SSH.ShowTestID() + CiTestObj.ShowTestID() GetParametersFromXML(action) if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': - if (SSH.ADBIPAddress != 'none'): + if (CiTestObj.ADBIPAddress != 'none'): terminate_ue_flag = False - SSH.GetAllUEDevices(terminate_ue_flag) + CiTestObj.GetAllUEDevices(terminate_ue_flag) if action == 'Build_eNB': - SSH.BuildeNB() + CiTestObj.BuildeNB() elif action == 'WaitEndBuild_eNB': - SSH.WaitBuildeNBisFinished() + CiTestObj.WaitBuildeNBisFinished() elif action == 'Initialize_eNB': - SSH.InitializeeNB() + CiTestObj.InitializeeNB() elif action == 'Terminate_eNB': - SSH.TerminateeNB() + CiTestObj.TerminateeNB() elif action == 'Initialize_UE': - SSH.InitializeUE() + CiTestObj.InitializeUE() elif action == 'Terminate_UE': - SSH.TerminateUE() + CiTestObj.TerminateUE() elif action == 'Attach_UE': - SSH.AttachUE() + CiTestObj.AttachUE() elif action == 'Detach_UE': - SSH.DetachUE() + CiTestObj.DetachUE() elif action == 'DataDisable_UE': - SSH.DataDisableUE() + CiTestObj.DataDisableUE() elif action == 'DataEnable_UE': - SSH.DataEnableUE() + CiTestObj.DataEnableUE() elif action == 'CheckStatusUE': - SSH.CheckStatusUE() + CiTestObj.CheckStatusUE() elif action == 'Build_OAI_UE': - SSH.BuildOAIUE() + CiTestObj.BuildOAIUE() elif action == 'Initialize_OAI_UE': - SSH.InitializeOAIUE() + CiTestObj.InitializeOAIUE() elif action == 'Terminate_OAI_UE': - SSH.TerminateOAIUE() + CiTestObj.TerminateOAIUE() elif action == 'Initialize_CatM_module': - SSH.InitializeCatM() + CiTestObj.InitializeCatM() elif action == 'Terminate_CatM_module': - SSH.TerminateCatM() + CiTestObj.TerminateCatM() elif action == 'Attach_CatM_module': - SSH.AttachCatM() + CiTestObj.AttachCatM() elif action == 'Detach_CatM_module': - SSH.TerminateCatM() + CiTestObj.TerminateCatM() elif action == 'Ping_CatM_module': - SSH.PingCatM() + CiTestObj.PingCatM() elif action == 'Ping': - SSH.Ping() + CiTestObj.Ping() elif action == 'Iperf': - SSH.Iperf() + CiTestObj.Iperf() elif action == 'Reboot_UE': - SSH.RebootUE() + CiTestObj.RebootUE() elif action == 'Initialize_HSS': - SSH.InitializeHSS() + CiTestObj.InitializeHSS() elif action == 'Terminate_HSS': - SSH.TerminateHSS() + CiTestObj.TerminateHSS() elif action == 'Initialize_MME': - SSH.InitializeMME() + CiTestObj.InitializeMME() elif action == 'Terminate_MME': - SSH.TerminateMME() + CiTestObj.TerminateMME() elif action == 'Initialize_SPGW': - SSH.InitializeSPGW() + CiTestObj.InitializeSPGW() elif action == 'Terminate_SPGW': - SSH.TerminateSPGW() + CiTestObj.TerminateSPGW() elif action == 'Initialize_FlexranCtrl': - SSH.InitializeFlexranCtrl() + CiTestObj.InitializeFlexranCtrl() elif action == 'Terminate_FlexranCtrl': - SSH.TerminateFlexranCtrl() + CiTestObj.TerminateFlexranCtrl() elif action == 'IdleSleep': - SSH.IdleSleep() + CiTestObj.IdleSleep() elif action == 'Perform_X2_Handover': - SSH.Perform_X2_Handover() + CiTestObj.Perform_X2_Handover() else: sys.exit('Invalid action') - SSH.FailReportCnt += 1 - if SSH.FailReportCnt == SSH.repeatCounts[0] and SSH.prematureExit: - logging.debug('Testsuite failed ' + str(SSH.FailReportCnt) + ' time(s)') - SSH.CreateHtmlTabFooter(False) + CiTestObj.FailReportCnt += 1 + if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: + logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)') + CiTestObj.CreateHtmlTabFooter(False) sys.exit('Failed Scenario') else: - logging.info('Testsuite passed after ' + str(SSH.FailReportCnt) + ' time(s)') - SSH.CreateHtmlTabFooter(True) + logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') + CiTestObj.CreateHtmlTabFooter(True) else: Usage() sys.exit('Invalid mode') From 8f476a99044195fae635b92a14528de05963fc1d Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Fri, 10 Jan 2020 14:14:08 +0100 Subject: [PATCH 076/175] creating a file sshconnection.py with class SSHConnection (methods: open, command, close, copyin, copyout); and modifying main.py to import this file and call the SSHConnection class from the new file --- ci-scripts/main.py | 1218 ++++++++++++++++++----------------- ci-scripts/sshconnection.py | 167 +++++ 2 files changed, 777 insertions(+), 608 deletions(-) create mode 100644 ci-scripts/sshconnection.py diff --git a/ci-scripts/main.py b/ci-scripts/main.py index bb0e92a23f..dfbde89c45 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -87,6 +87,7 @@ logging.basicConfig( level=logging.DEBUG, format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" ) +import sshconnection.py #----------------------------------------------------------- # Class Declaration @@ -212,10 +213,10 @@ class OaiCiTest(): logging.debug('self.sshresponse = ' + str(self.sshresponse)) elif self.sshresponse == 2: # Checking if we are really on the remote client defined by its IP address - self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) + SSH.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) result = re.search(str(ipaddress), str(self.ssh.before)) if result is None: - self.close() + SSH.close() else: count = 10 connect_status = True @@ -369,29 +370,29 @@ class OaiCiTest(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': Usage() sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - self.command('mkdir -p ' + lSourcePath, '\$', 5) - self.command('cd ' + lSourcePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('mkdir -p ' + lSourcePath, '\$', 5) + SSH.command('cd ' + lSourcePath, '\$', 5) + SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) # Raphael: here add a check if git clone or git fetch went smoothly - self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - self.command('git config user.name "OAI Jenkins"', '\$', 5) + SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + SSH.command('git config user.name "OAI Jenkins"', '\$', 5) # Checking the BUILD INFO file if not self.backgroundBuild: - self.command('ls *.txt', '\$', 5) + SSH.command('ls *.txt', '\$', 5) result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) if result is not None: mismatch = False - self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) result = re.search(self.ranCommitID, str(self.ssh.before)) if result is None: mismatch = True - self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if (self.ranAllowMerge): result = re.search('YES', str(self.ssh.before)) if result is None: mismatch = True - self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if self.ranTargetBranch == '': result = re.search('develop', str(self.ssh.before)) else: @@ -403,37 +404,37 @@ class OaiCiTest(): if result is None: mismatch = True if not mismatch: - self.close() + SSH.close() self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) return - self.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) + SSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) # if the commit ID is provided use it to point to it if self.ranCommitID != '': - self.command('git checkout -f ' + self.ranCommitID, '\$', 5) + SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) # if the branch is not develop, then it is a merge request and we need to do # the potential merge. Note that merge conflicts should already been checked earlier if (self.ranAllowMerge): if self.ranTargetBranch == '': if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) else: logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('mkdir -p log', '\$', 5) - self.command('chmod 777 log', '\$', 5) + SSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('mkdir -p log', '\$', 5) + SSH.command('chmod 777 log', '\$', 5) # no need to remove in log (git clean did the trick) if self.backgroundBuild: - self.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) - self.close() + SSH.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) + SSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) + SSH.close() self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id return - self.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) + SSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) def WaitBuildeNBisFinished(self): @@ -455,11 +456,11 @@ class OaiCiTest(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': Usage() sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) + SSH.open(lIpAddr, lUserName, lPassWord) count = 40 buildOAIprocess = True while (count > 0) and buildOAIprocess: - self.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) + SSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) result = re.search('build_oai', str(self.ssh.before)) if result is None: buildOAIprocess = False @@ -469,46 +470,46 @@ class OaiCiTest(): self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): - self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) + SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) + SSH.command('ls lte_build_oai/build', '\$', 3) + SSH.command('ls lte_build_oai/build', '\$', 3) buildStatus = True result = re.search('lte-softmodem', str(self.ssh.before)) if result is None: buildStatus = False else: # Generating a BUILD INFO file - self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) if (self.ranAllowMerge): - self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) if self.ranTargetBranch == '': - self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: - self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: - self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('mkdir -p build_log_' + testcaseId, '\$', 5) - self.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) - self.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) + SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('mkdir -p build_log_' + testcaseId, '\$', 5) + SSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) + SSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) if self.eNB_serverId != '0': - self.command('cd cmake_targets', '\$', 5) - self.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) - self.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) - self.close() + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) + SSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) + SSH.close() if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): os.remove('./tmp_build' + testcaseId + '.zip') - self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') + SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') + SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') os.remove('./tmp_build' + testcaseId + '.zip') - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) - self.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) - self.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) - self.close() + SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + SSH.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) + SSH.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) + SSH.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) + SSH.close() else: - self.close() + SSH.close() if buildStatus: self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) @@ -522,27 +523,27 @@ class OaiCiTest(): if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) + SSH.command('cd ' + self.UESourceCodePath, '\$', 5) + SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) # here add a check if git clone or git fetch went smoothly - self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - self.command('git config user.name "OAI Jenkins"', '\$', 5) - self.command('ls *.txt', '\$', 5) + SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + SSH.command('git config user.name "OAI Jenkins"', '\$', 5) + SSH.command('ls *.txt', '\$', 5) result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) if result is not None: mismatch = False - self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) result = re.search(self.ranCommitID, str(self.ssh.before)) if result is None: mismatch = True - self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if (self.ranAllowMerge): result = re.search('YES', str(self.ssh.before)) if result is None: mismatch = True - self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if self.ranTargetBranch == '': result = re.search('develop', str(self.ssh.before)) else: @@ -554,54 +555,54 @@ class OaiCiTest(): if result is None: mismatch = True if not mismatch: - self.close() + SSH.close() self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) return - self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) + SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) # if the commit ID is provided use it to point to it if self.ranCommitID != '': - self.command('git checkout -f ' + self.ranCommitID, '\$', 5) + SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) # if the branch is not develop, then it is a merge request and we need to do # the potential merge. Note that merge conflicts should already been checked earlier if (self.ranAllowMerge): if self.ranTargetBranch == '': if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) else: logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('mkdir -p log', '\$', 5) - self.command('chmod 777 log', '\$', 5) + SSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('mkdir -p log', '\$', 5) + SSH.command('chmod 777 log', '\$', 5) # no need to remove in log (git clean did the trick) - self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) - self.command('ls lte_build_oai/build', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) + SSH.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) + SSH.command('ls lte_build_oai/build', '\$', 3) + SSH.command('ls lte_build_oai/build', '\$', 3) buildStatus = True result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is None: buildStatus = False - self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) - self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) - self.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) + SSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) + SSH.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) + SSH.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) if buildStatus: # Generating a BUILD INFO file - self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) if (self.ranAllowMerge): - self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) if self.ranTargetBranch == '': - self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: - self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: - self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - self.close() + SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.close() self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') else: - self.close() + SSH.close() logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') self.CreateHtmlTabFooter(False) @@ -611,107 +612,107 @@ class OaiCiTest(): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) - self.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) - self.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) - self.command('chmod 755 ./my-hss.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) + SSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) + SSH.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) + SSH.command('chmod 755 ./my-hss.sh', '\$', 5) + SSH.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) elif re.match('OAI', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC HSS') - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) elif re.match('ltebox', self.EPCType, re.IGNORECASE): logging.debug('Using the ltebox simulated HSS') - self.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - self.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('cd /opt/hss_sim0609', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + SSH.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd /opt/hss_sim0609', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) else: logging.error('This option should not occur!') - self.close() + SSH.close() self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def InitializeMME(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 MME') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) - self.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) - self.command('chmod 755 ./my-mme.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) + SSH.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) + SSH.command('chmod 755 ./my-mme.sh', '\$', 5) + SSH.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('stdbuf -o0 hostname', '\$', 5) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('stdbuf -o0 hostname', '\$', 5) result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') sys.exit(1) host_name = result.group('host_name') - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) + SSH.command('cd /opt/ltebox/tools', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) else: logging.error('This option should not occur!') - self.close() + SSH.close() self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def InitializeSPGW(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) - self.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) - self.command('chmod 755 ./my-spgwc.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) + SSH.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) + SSH.command('chmod 755 ./my-spgwc.sh', '\$', 5) + SSH.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) time.sleep(5) - self.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) - self.command('chmod 755 ./my-spgwu.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) + SSH.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) + SSH.command('chmod 755 ./my-spgwu.sh', '\$', 5) + SSH.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) + SSH.command('cd /opt/ltebox/tools', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) else: logging.error('This option should not occur!') - self.close() + SSH.close() self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def CheckFlexranCtrlInstallation(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': return - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) result = re.search('/opt/flexran_rtc/build/rt_controller', str(self.ssh.before)) if result is not None: self.flexranCtrlInstalled = True logging.debug('Flexran Controller is installed') - self.close() + SSH.close() def InitializeFlexranCtrl(self): if self.flexranCtrlInstalled == False: @@ -719,18 +720,18 @@ class OaiCiTest(): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd /opt/flexran_rtc', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) - self.command('ps -aux | grep --color=never rt_controller', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd /opt/flexran_rtc', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) + SSH.command('ps -aux | grep --color=never rt_controller', '\$', 5) result = re.search('rt_controller -c ', str(self.ssh.before)) if result is not None: logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') self.flexranCtrlStarted = True - self.close() + SSH.close() self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def InitializeeNB(self): @@ -762,18 +763,18 @@ class OaiCiTest(): # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', str(self.ssh.before)) if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') self.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - self.close() - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath, '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) + SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + SSH.close() + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('cd ' + lSourcePath, '\$', 5) # Initialize_eNB_args usually start with -O and followed by the location in repository full_config_file = self.Initialize_eNB_args.replace('-O ','') extra_options = '' @@ -784,10 +785,10 @@ class OaiCiTest(): result = re.search('T_stdout', str(extra_options)) if result is not None: logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') - self.command('cd common/utils/T/tracer', '\$', 5) - self.command('make', '\$', 10) - self.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) - self.command('cd ' + lSourcePath, '\$', 5) + SSH.command('cd common/utils/T/tracer', '\$', 5) + SSH.command('make', '\$', 10) + SSH.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) + SSH.command('cd ' + lSourcePath, '\$', 5) full_config_file = full_config_file[:extIdx + 5] config_path, config_file = os.path.split(full_config_file) else: @@ -800,32 +801,32 @@ class OaiCiTest(): # do not reset board twice in IF4.5 case result = re.search('^rru|^enb|^du.band', str(config_file)) if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) + SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) result = re.search('type: b200', str(self.ssh.before)) if result is not None: logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + SSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) # Reloading FGPA bin firmware - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 15) + SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 15) # Make a copy and adapt to EPC / eNB IP addresses - self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) + SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); else: - self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); # Launch eNB with the modified config file - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' if extra_options != '': self.eNBOptions[int(self.eNB_instance)] = extra_options @@ -838,30 +839,30 @@ class OaiCiTest(): # In case of T tracer recording, we may need to kill it result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - self.command('killall --signal SIGKILL record', '\$', 5) - self.close() + SSH.command('killall --signal SIGKILL record', '\$', 5) + SSH.close() doLoop = False logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) if self.EPC_PcapFileName != '': time.sleep(0.5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.close() + SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + SSH.close() time.sleep(1) if self.EPC_PcapFileName != '': - copyin_res = self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + copyin_res = SSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') if (copyin_res == 0): - self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + SSH.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') self.prematureExit = True return else: - self.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) + SSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) if rruCheck: result = re.search('wait RUs', str(self.ssh.before)) else: @@ -874,52 +875,52 @@ class OaiCiTest(): logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') time.sleep(10) - self.close() + SSH.close() def InitializeUE_common(self, device_id, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if not self.ADBCentralized: # Reboot UE - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) # Wait #time.sleep(60) # Put in LTE-Mode only - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) # enable data service - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) # we need to do radio on/off cycle to make sure of above changes # airplane mode off // radio on - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) #time.sleep(10) # airplane mode on // radio off - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) # normal procedure without reboot # enable data service - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) # airplane mode on // radio off - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - self.close() + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + SSH.close() return # enable data service - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) # The following commands are deprecated since we no longer work on Android 7+ - # self.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) - # self.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) + # SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) + # SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) # a dedicated script has to be installed inside the UE # airplane mode on means call /data/local/tmp/off if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) #airplane mode off means call /data/local/tmp/on logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -952,34 +953,34 @@ class OaiCiTest(): self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) self.CreateHtmlTabFooter(False) sys.exit(1) - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) # b2xx_fx3_utils reset procedure - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) + SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) result = re.search('type: b200', str(self.ssh.before)) if result is not None: logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + SSH.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) # Reloading FGPA bin firmware - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) + SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) else: logging.debug('Did not find any B2xx device') - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets/lte_build_oai/build', '\$', 5) + SSH.command('cd ' + self.UESourceCodePath, '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets/lte_build_oai/build', '\$', 5) result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) # We may have to regenerate the .u* files if result is None: - self.command('ls /tmp/*.sed', '\$', 5) + SSH.command('ls /tmp/*.sed', '\$', 5) result = re.search('adapt_usim_parameters', str(self.ssh.before)) if result is not None: - self.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + SSH.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) else: - self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) + SSH.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) # Launch UE with the modified config file - self.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) self.UELogFile = 'ue_' + self.testCase_id + '.log' # We are now looping several times to hope we really sync w/ an eNB @@ -988,11 +989,11 @@ class OaiCiTest(): gotSyncStatus = True fullSyncStatus = True while (doOutterLoop): - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) time.sleep(6) - self.command('cd ../..', '\$', 5) + SSH.command('cd ../..', '\$', 5) doLoop = True loopCounter = 10 gotSyncStatus = True @@ -1005,7 +1006,7 @@ class OaiCiTest(): gotSyncStatus = False doLoop = False continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) result = re.search('got sync', str(self.ssh.before)) if result is None: time.sleep(6) @@ -1014,10 +1015,10 @@ class OaiCiTest(): logging.debug('Found "got sync" message!') if gotSyncStatus == False: # we certainly need to stop the lte-uesoftmodem process if it is still running! - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) time.sleep(3) # We are now checking if sync w/ eNB DOES NOT OCCUR # Usually during the cell synchronization stage, the UE returns with No cell synchronization message @@ -1031,7 +1032,7 @@ class OaiCiTest(): doOutterLoop = False fullSyncStatus = True continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) result = re.search('No cell synchronization found', str(self.ssh.before)) if result is None: time.sleep(6) @@ -1040,10 +1041,10 @@ class OaiCiTest(): fullSyncStatus = False logging.debug('Found: "No cell synchronization" message! --> try again') time.sleep(6) - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) outterLoopCounter = outterLoopCounter - 1 if (outterLoopCounter == 0): doOutterLoop = False @@ -1051,7 +1052,7 @@ class OaiCiTest(): if fullSyncStatus and gotSyncStatus: result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) if result is None: - self.command('ifconfig oaitun_ue1', '\$', 4) + SSH.command('ifconfig oaitun_ue1', '\$', 4) # ifconfig output is different between ubuntu 16 and ubuntu 18 result = re.search('inet addr:1|inet 1', str(self.ssh.before)) if result is not None: @@ -1064,7 +1065,7 @@ class OaiCiTest(): else: tunnelInterfaceStatus = True - self.close() + SSH.close() if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') @@ -1080,48 +1081,48 @@ class OaiCiTest(): self.AutoTerminateUEandeNB() def checkDevTTYisUnlocked(self): - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) count = 0 while count < 5: - self.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) + SSH.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) result = re.search('picocom', str(self.ssh.before)) if result is None: count = 10 else: time.sleep(5) count = count + 1 - self.close() + SSH.close() def InitializeCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) time.sleep(1) # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) # Disabling the Radio - self.command('AT+CFUN=0', 'OK', 5) + SSH.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') # Checking if auto-attach is enabled - self.command('AT^AUTOATT?', 'OK', 5) + SSH.command('AT^AUTOATT?', 'OK', 5) result = re.search('AUTOATT: (?P[0-9\-]+)', str(self.ssh.before)) if result is not None: if result.group('state') is not None: autoAttachState = int(result.group('state')) if autoAttachState is not None: if autoAttachState == 0: - self.command('AT^AUTOATT=1', 'OK', 5) + SSH.command('AT^AUTOATT=1', 'OK', 5) logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') else: logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') # Force closure of picocom but device might still be locked - self.close() + SSH.close() self.picocom_closure = False self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() @@ -1131,18 +1132,18 @@ class OaiCiTest(): Usage() sys.exit('Insufficient Parameter') self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) time.sleep(1) # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) # Disabling the Radio - self.command('AT+CFUN=0', 'OK', 5) + SSH.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - self.close() + SSH.close() self.picocom_closure = False self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() @@ -1152,16 +1153,16 @@ class OaiCiTest(): Usage() sys.exit('Insufficient Parameter') self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) time.sleep(1) # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) # Enabling the Radio - self.command('AT+CFUN=1', 'SIMSTORE,READY', 5) + SSH.command('AT+CFUN=1', 'SIMSTORE,READY', 5) logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') time.sleep(4) # We should check if we register @@ -1169,7 +1170,7 @@ class OaiCiTest(): attach_cnt = 0 attach_status = False while count < 5: - self.command('AT+CEREG?', 'OK', 5) + SSH.command('AT+CEREG?', 'OK', 5) result = re.search('CEREG: 2,(?P[0-9\-]+),', str(self.ssh.before)) if result is not None: mDataConnectionState = int(result.group('state')) @@ -1193,7 +1194,7 @@ class OaiCiTest(): count = count + 1 time.sleep(1) if attach_status: - self.command('AT+CESQ', 'OK', 5) + SSH.command('AT+CESQ', 'OK', 5) result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', str(self.ssh.before)) if result is not None: nRSRQ = int(result.group('rsrq')) @@ -1201,7 +1202,7 @@ class OaiCiTest(): if (nRSRQ is not None) and (nRSRP is not None): logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') - self.close() + SSH.close() self.picocom_closure = False html_queue = SimpleQueue() self.checkDevTTYisUnlocked() @@ -1235,16 +1236,16 @@ class OaiCiTest(): try: statusQueue = SimpleQueue() lock = Lock() - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('cd scripts', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC HSS: not implemented yet') self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.CreateHtmlTabFooter(False) sys.exit(1) else: - self.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) + SSH.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', str(self.ssh.before)) if result is not None: moduleIPAddr = result.group('ipaddr') @@ -1254,33 +1255,33 @@ class OaiCiTest(): return ping_time = re.findall("-c (\d+)",str(self.ping_args)) device_id = 'catm' - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) return result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) if result is None: message = 'Packet Loss Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) return packetloss = result.group('packetloss') if float(packetloss) == 100: message = 'Packet Loss is 100%' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) return result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) if result is None: message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) return rtt_min = result.group('rtt_min') @@ -1307,7 +1308,7 @@ class OaiCiTest(): qMsg += '\nPacket Loss is not 0%' logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') lock.release() - self.close() + SSH.close() html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' statusQueue.put(html_cell) if (packetLossOK): @@ -1320,23 +1321,23 @@ class OaiCiTest(): def AttachUE_common(self, device_id, statusQueue, lock, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) else: # airplane mode off // radio on - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) time.sleep(2) max_count = 45 count = max_count while count > 0: if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') @@ -1360,19 +1361,19 @@ class OaiCiTest(): logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') if self.ADBCentralized: if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) time.sleep(0.5) if self.ADBCentralized: if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) time.sleep(0.5) logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') time.sleep(1) @@ -1383,7 +1384,7 @@ class OaiCiTest(): statusQueue.put(device_id) statusQueue.put('Attach Failed') lock.release() - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1448,16 +1449,16 @@ class OaiCiTest(): def DetachUE_common(self, device_id, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1495,24 +1496,24 @@ class OaiCiTest(): def RebootUE_common(self, device_id): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) previousmDataConnectionStates = [] # Save mDataConnectionState - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') sys.exit(1) previousmDataConnectionStates.append(int(result.group('state'))) # Reboot UE - self.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) time.sleep(60) previousmDataConnectionState = previousmDataConnectionStates.pop(0) count = 180 while count > 0: count = count - 1 - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) if result is None: mDataConnectionState = None @@ -1528,7 +1529,7 @@ class OaiCiTest(): if count == 0: logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') sys.exit(1) - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1555,14 +1556,14 @@ class OaiCiTest(): def DataDisableUE_common(self, device_id, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # disable data service if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1584,14 +1585,14 @@ class OaiCiTest(): def DataEnableUE_common(self, device_id, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # enable data service if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1615,19 +1616,19 @@ class OaiCiTest(): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: - self.command('adb devices', '\$', 15) + SSH.command('adb devices', '\$', 15) self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",str(self.ssh.before)) - self.close() + SSH.close() else: if (os.path.isfile('./phones_list.txt')): os.remove('./phones_list.txt') - self.command('ls /etc/*/phones*.txt', '\$', 5) + SSH.command('ls /etc/*/phones*.txt', '\$', 5) result = re.search('/etc/ci/phones_list.txt', str(self.ssh.before)) - self.close() + SSH.close() if (result is not None) and (len(self.UEDevices) == 0): - self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') + SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') if (os.path.isfile('./phones_list.txt')): phone_list_file = open('./phones_list.txt', 'r') for line in phone_list_file.readlines(): @@ -1658,31 +1659,31 @@ class OaiCiTest(): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: - self.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) + SSH.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",str(self.ssh.before)) else: if (os.path.isfile('./modules_list.txt')): os.remove('./modules_list.txt') - self.command('ls /etc/*/modules*.txt', '\$', 5) + SSH.command('ls /etc/*/modules*.txt', '\$', 5) result = re.search('/etc/ci/modules_list.txt', str(self.ssh.before)) - self.close() + SSH.close() if result is not None: logging.debug('Found a module list file on ADB server') if terminate_ue_flag == False: if len(self.CatMDevices) == 0: logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') sys.exit(1) - self.close() + SSH.close() def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) result = re.search('mServiceState=(?P[0-9]+)', str(self.ssh.before)) serviceState = 'Service State: UNKNOWN' if result is not None: @@ -1721,7 +1722,7 @@ class OaiCiTest(): qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason statusQueue.put(qMsg) lock.release() - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1749,10 +1750,10 @@ class OaiCiTest(): for job in multi_jobs: job.join() if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd /opt/flexran_rtc', '\$', 5) - self.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) - self.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd /opt/flexran_rtc', '\$', 5) + SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) + SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) result = re.search('Nb Connected UE = (?P[0-9]+)', str(self.ssh.before)) passStatus = True if result is not None: @@ -1764,7 +1765,7 @@ class OaiCiTest(): passStatus = False else: htmlOptions = 'N/A' - self.close() + SSH.close() else: passStatus = True htmlOptions = 'N/A' @@ -1799,8 +1800,8 @@ class OaiCiTest(): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('ifconfig oaitun_ue1', '\$', 4) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('ifconfig oaitun_ue1', '\$', 4) result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', str(self.ssh.before)) if result is not None: if result.group('ueipaddress') is not None: @@ -1812,9 +1813,9 @@ class OaiCiTest(): else: logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') ue_ip_status -= 1 - self.close() + SSH.close() return ue_ip_status - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) idx = 0 for device_id in self.UEDevices: if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: @@ -1823,9 +1824,9 @@ class OaiCiTest(): count = 0 while count < 4: if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') @@ -1845,7 +1846,7 @@ class OaiCiTest(): continue self.UEIPAddresses.append(UE_IPAddress) idx += 1 - self.close() + SSH.close() return ue_ip_status def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): @@ -1866,45 +1867,45 @@ class OaiCiTest(): ping_time = re.findall("-c (\d+)",str(self.ping_args)) if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('cd scripts', '\$', 5) + ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) else: cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' message = cmd + '\n' logging.debug(cmd) ret = subprocess.run(cmd, shell=True) ping_status = ret.returncode - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) if result is None: message = 'Packet Loss Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return packetloss = result.group('packetloss') if float(packetloss) == 100: message = 'Packet Loss is 100%' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) if result is None: message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return rtt_min = result.group('rtt_min') @@ -1938,7 +1939,7 @@ class OaiCiTest(): statusQueue.put(UE_IPAddress) statusQueue.put(qMsg) lock.release() - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1967,14 +1968,14 @@ class OaiCiTest(): sys.exit('Insufficient Parameter') try: if ping_from_eNB is not None: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) + SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + SSH.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) else: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) - self.command('cd cmake_targets', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) ping_time = re.findall("-c (\d+)",str(self.ping_args)) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) + ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with OAI UE crashed due to TIMEOUT!' @@ -2021,7 +2022,7 @@ class OaiCiTest(): elif float(packetloss) > 0: qMsg += '\nPacket Loss is not 0%' logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - self.close() + SSH.close() html_queue = SimpleQueue() ip_addr = 'TBD' html_cell = '
OAI UE ping result\n' + qMsg + '
' @@ -2033,11 +2034,11 @@ class OaiCiTest(): # copying on the EPC server for logCollection if ping_from_eNB is not None: - copyin_res = self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + copyin_res = SSH.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') else: - copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') except: os.kill(os.getppid(),signal.SIGUSR1) @@ -2132,7 +2133,7 @@ class OaiCiTest(): return result def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - self.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', str(self.ssh.before)) if result is not None: avgbitrate = result.group('average') @@ -2398,14 +2399,14 @@ class OaiCiTest(): EPC_Iperf_UE_IPAddress = ret.stdout.strip() port = 5001 + idx if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if udpIperf: - self.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) else: - self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) - self.close() + SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + SSH.close() else: if self.ueIperfVersion == self.dummyIperfVersion: prefix = '' @@ -2423,11 +2424,11 @@ class OaiCiTest(): # Launch iperf client on UE if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) iperf_time = self.Iperf_ComputeTime() time.sleep(0.5) @@ -2438,50 +2439,50 @@ class OaiCiTest(): modified_options = modified_options.replace('-R','') time.sleep(0.5) - self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if (device_id == 'OAI-UE'): - iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + iperf_status = SSH.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: if self.ADBCentralized: - iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + iperf_status = SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: - iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + iperf_status = SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + SSH.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT Case if iperf_status < 0: - self.close() + SSH.close() message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - self.close() + SSH.close() # Kill iperf server on EPC side if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) - self.close() + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) + SSH.close() else: cmd = 'killall --signal SIGKILL iperf' logging.debug(cmd) subprocess.run(cmd, shell=True) time.sleep(1) - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') # in case of failure, retrieve server log if (clientStatus == -1) or (clientStatus == -2): if launchFromEpc: time.sleep(1) if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI-UE if (device_id == 'OAI-UE'): - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): try: @@ -2493,29 +2494,29 @@ class OaiCiTest(): self.ueIperfVersion = '2.0.5' if (device_id != 'OAI-UE'): - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - self.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) # Checking if iperf / iperf3 are installed if self.ADBCentralized: - self.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) + SSH.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) result = re.search('iperf3', str(self.ssh.before)) if result is None: result = re.search('iperf', str(self.ssh.before)) if result is None: message = 'Neither iperf nor iperf3 installed on UE!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() + SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return else: if self.ADBCentralized: - self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) + SSH.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) result = re.search('iperf version 2.0.5', str(self.ssh.before)) if result is not None: self.ueIperfVersion = '2.0.5' @@ -2524,17 +2525,17 @@ class OaiCiTest(): self.ueIperfVersion = '2.0.10' else: useIperf3 = True - self.close() + SSH.close() else: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('iperf --version', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('iperf --version', '\$', 5) result = re.search('iperf version 2.0.5', str(self.ssh.before)) if result is not None: self.ueIperfVersion = '2.0.5' result = re.search('iperf version 2.0.10', str(self.ssh.before)) if result is not None: self.ueIperfVersion = '2.0.10' - self.close() + SSH.close() # in case of iperf, UL has its own function if (not useIperf3): result = re.search('-R', str(self.iperf_args)) @@ -2544,35 +2545,35 @@ class OaiCiTest(): # Launch the IPERF server on the UE side for DL if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) result = re.search('-u', str(self.iperf_args)) if result is None: - self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) udpIperf = False else: - self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) if self.ADBCentralized: if (useIperf3): - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) else: - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) result = re.search('-u', str(self.iperf_args)) if result is None: - self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + SSH.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) udpIperf = False else: - self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + SSH.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) else: - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) time.sleep(0.5) - self.close() + SSH.close() # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn # But for OAI-Rel14-CUPS, we launch from python executor @@ -2580,8 +2581,8 @@ class OaiCiTest(): if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): launchFromEpc = False if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) iperf_time = self.Iperf_ComputeTime() time.sleep(0.5) @@ -2592,18 +2593,18 @@ class OaiCiTest(): time.sleep(0.5) if launchFromEpc: - self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) else: if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') if (useIperf3): - self.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + SSH.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) clientStatus = 0 self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) else: if launchFromEpc: - iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + iperf_status = SSH.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) else: if self.ueIperfVersion == self.dummyIperfVersion: prefix = '' @@ -2616,57 +2617,57 @@ class OaiCiTest(): logging.debug(cmd) ret = subprocess.run(cmd, shell=True) iperf_status = ret.returncode - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if iperf_status < 0: if launchFromEpc: - self.close() + SSH.close() message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - self.close() + SSH.close() # Kill the IPERF server that runs in background if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('killall iperf', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('killall iperf', '\$', 5) else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) result = re.search('shell +(?P\d+)', str(self.ssh.before)) if result is not None: pid_iperf = result.group('pid') if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - self.close() + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + SSH.close() # if the client report is absent, try to analyze the server log file if (clientStatus == -1): time.sleep(1) if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') if (device_id == 'OAI-UE'): - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') else: - self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI UE: if (device_id == 'OAI-UE'): if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): if not launchFromEpc: - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') else: - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') except: os.kill(os.getppid(),signal.SIGUSR1) @@ -2697,24 +2698,24 @@ class OaiCiTest(): iClientUser = self.eNBUserName iClientPasswd = self.eNBPassword # Starting the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) + SSH.open(iServerIPAddr, iServerUser, iServerPasswd) # args SHALL be "-c client -u any" # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 # -B 10.0.1.1 -u -s -i 1 -fm server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) server_options = server_options.replace('-c','-B') - self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) - self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) + SSH.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) + SSH.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) time.sleep(0.5) - self.close() + SSH.close() # Starting the iperf client modified_options = self.Iperf_ComputeModifiedBW(0, 1) modified_options = modified_options.replace('-R','') iperf_time = self.Iperf_ComputeTime() - self.open(iClientIPAddr, iClientUser, iClientPasswd) - self.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) - iperf_status = self.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) + SSH.open(iClientIPAddr, iClientUser, iClientPasswd) + SSH.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) + iperf_status = SSH.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) status_queue = SimpleQueue() lock = Lock() if iperf_status < 0: @@ -2723,26 +2724,26 @@ class OaiCiTest(): clientStatus = -2 else: clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - self.close() + SSH.close() # Stopping the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - self.command('killall --signal SIGKILL iperf', '\$', 5) + SSH.open(iServerIPAddr, iServerUser, iServerPasswd) + SSH.command('killall --signal SIGKILL iperf', '\$', 5) time.sleep(0.5) - self.close() + SSH.close() if (clientStatus == -1): if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '.log') - self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) # copying on the EPC server for logCollection - copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + copyin_res = SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') - copyin_res = self.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + copyin_res = SSH.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') iperf_noperf = False if status_queue.empty(): iperf_status = False @@ -2889,7 +2890,7 @@ class OaiCiTest(): if result == ENB_PROCESS_FAILED: fileCheck = re.search('enb_', str(self.eNBLogFiles[0])) if fileCheck is not None: - self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') + SSH.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') logStatus = self.AnalyzeLogFile_eNB(self.eNBLogFiles[0]) if logStatus < 0: result = logStatus @@ -2920,7 +2921,7 @@ class OaiCiTest(): if result == OAI_UE_PROCESS_FAILED: fileCheck = re.search('ue_', str(self.UELogFile)) if fileCheck is not None: - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') logStatus = self.AnalyzeLogFile_UE(self.UELogFile) if logStatus < 0: result = logStatus @@ -2928,36 +2929,36 @@ class OaiCiTest(): def CheckOAIUEProcess(self, status_queue): try: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') status_queue.put(OAI_UE_PROCESS_FAILED) else: status_queue.put(OAI_UE_PROCESS_OK) - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) def CheckeNBProcess(self, status_queue): try: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-softmodem', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') status_queue.put(ENB_PROCESS_FAILED) else: status_queue.put(ENB_PROCESS_OK) - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) def CheckHSSProcess(self, status_queue): try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): result = re.search('oai_hss -j', str(self.ssh.before)) elif re.match('OAI', self.EPCType, re.IGNORECASE): @@ -2971,14 +2972,14 @@ class OaiCiTest(): status_queue.put(HSS_PROCESS_FAILED) else: status_queue.put(HSS_PROCESS_OK) - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) def CheckMMEProcess(self, status_queue): try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): result = re.search('mme -c', str(self.ssh.before)) elif re.match('OAI', self.EPCType, re.IGNORECASE): @@ -2992,21 +2993,21 @@ class OaiCiTest(): status_queue.put(MME_PROCESS_FAILED) else: status_queue.put(MME_PROCESS_OK) - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) def CheckSPGWProcess(self, status_queue): try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) result = re.search('spgwu -c ', str(self.ssh.before)) elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) result = re.search('xGw', str(self.ssh.before)) else: logging.error('This should not happen!') @@ -3015,7 +3016,7 @@ class OaiCiTest(): status_queue.put(SPGW_PROCESS_FAILED) else: status_queue.put(SPGW_PROCESS_OK) - self.close() + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -3444,46 +3445,46 @@ class OaiCiTest(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': Usage() sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-softmodem', str(self.ssh.before)) if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) time.sleep(10) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-softmodem', str(self.ssh.before)) if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) time.sleep(5) - self.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.close() + SSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.close() # If tracer options is on, stopping tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) if self.EPC_PcapFileName != '': - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') - self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') - self.close() + SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + SSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + SSH.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + SSH.close() logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] raw_record_file = enbLogFile.replace('.log', '_record.raw') replay_log_file = enbLogFile.replace('.log', '_replay.log') extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') - self.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) - self.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) - self.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) - self.close() - self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') + SSH.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) + SSH.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) + SSH.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) + SSH.close() + SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) @@ -3495,14 +3496,14 @@ class OaiCiTest(): fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] self.eNBLogFiles[int(self.eNB_instance)] = '' if analyzeFile: - copyin_res = self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') + copyin_res = SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy eNB logfile to analyze it! \u001B[0m') self.htmleNBFailureMsg = 'Could not copy eNB logfile to analyze it!' self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) return if self.eNB_serverId != '0': - self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') + SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m ' + fileToAnalyze) logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) if (logStatus < 0): @@ -3515,79 +3516,79 @@ class OaiCiTest(): self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateHSS(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) result = re.search('oai_hss -j', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) + SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) time.sleep(1) - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) else: logging.error('This should not happen!') - self.close() + SSH.close() self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateMME(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) result = re.search('mme -c', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) + SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) + SSH.command('cd /opt/ltebox/tools', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) else: logging.error('This should not happen!') - self.close() + SSH.close() self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateSPGW(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) result = re.search('spgwc -c |spgwu -c ', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) - self.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) + SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) result = re.search('-w ', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + SSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) + SSH.command('cd /opt/ltebox/tools', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) else: logging.error('This should not happen!') - self.close() + SSH.close() self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateFlexranCtrl(self): @@ -3596,40 +3597,40 @@ class OaiCiTest(): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': Usage() sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) time.sleep(1) - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) time.sleep(1) - self.close() + SSH.close() self.flexranCtrlStarted = False self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateUE_common(self, device_id, idx): try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # back in airplane mode on (ie radio off) if self.ADBCentralized: if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) result = re.search('shell +(?P\d+)', str(self.ssh.before)) if result is not None: pid_iperf = result.group('pid') if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - self.close() + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -3649,24 +3650,24 @@ class OaiCiTest(): self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateOAIUE(self): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) time.sleep(10) - self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) time.sleep(5) - self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.close() + SSH.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.close() result = re.search('ue_', str(self.UELogFile)) if result is not None: - copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' @@ -3848,93 +3849,93 @@ class OaiCiTest(): SourceCodePath = self.UESourceCodePath else: sys.exit('Insufficient Parameter') - self.open(IPAddress, UserName, Password) - self.command('cd ' + SourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('rm -f build.log.zip', '\$', 5) - self.command('zip build.log.zip build_log_*/*', '\$', 60) - self.close() + SSH.open(IPAddress, UserName, Password) + SSH.command('cd ' + SourceCodePath, '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('rm -f build.log.zip', '\$', 5) + SSH.command('zip build.log.zip build_log_*/*', '\$', 60) + SSH.close() def LogCollecteNB(self): - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) - self.close() + SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + SSH.command('cd ' + self.eNBSourceCodePath, '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) + SSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) + SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) + SSH.close() def LogCollectPing(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('rm -f ping.log.zip', '\$', 5) - self.command('zip ping.log.zip ping*.log', '\$', 60) - self.command('rm ping*.log', '\$', 5) - self.close() + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('rm -f ping.log.zip', '\$', 5) + SSH.command('zip ping.log.zip ping*.log', '\$', 60) + SSH.command('rm ping*.log', '\$', 5) + SSH.close() def LogCollectIperf(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('rm -f iperf.log.zip', '\$', 5) - self.command('zip iperf.log.zip iperf*.log', '\$', 60) - self.command('rm iperf*.log', '\$', 5) - self.close() + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('rm -f iperf.log.zip', '\$', 5) + SSH.command('zip iperf.log.zip iperf*.log', '\$', 60) + SSH.command('rm iperf*.log', '\$', 5) + SSH.close() def LogCollectHSS(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f hss.log.zip', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('rm -f hss.log.zip', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip hss.log.zip hss*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) + SSH.command('zip hss.log.zip hss*.log', '\$', 60) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) + SSH.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) - self.command('zip hss.log.zip hss.log', '\$', 60) + SSH.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) + SSH.command('zip hss.log.zip hss.log', '\$', 60) else: logging.error('This option should not occur!') - self.close() + SSH.close() def LogCollectMME(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f mme.log.zip', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('rm -f mme.log.zip', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip mme.log.zip mme*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) + SSH.command('zip mme.log.zip mme*.log', '\$', 60) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) - self.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) + SSH.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) + SSH.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) else: logging.error('This option should not occur!') - self.close() + SSH.close() def LogCollectSPGW(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f spgw.log.zip', '\$', 5) + SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('rm -f spgw.log.zip', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip spgw.log.zip spgw*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) + SSH.command('zip spgw.log.zip spgw*.log', '\$', 60) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) - self.command('zip spgw.log.zip xGwLog.0', '\$', 60) + SSH.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) + SSH.command('zip spgw.log.zip xGwLog.0', '\$', 60) else: logging.error('This option should not occur!') - self.close() + SSH.close() def LogCollectOAIUE(self): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) - self.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) - self.close() + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath, '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) + SSH.close() def RetrieveSystemVersion(self, machine): if self.eNBIPAddress == 'none' or self.UEIPAddress == 'none': @@ -3961,28 +3962,28 @@ class OaiCiTest(): else: return -1 - self.open(IPAddress, UserName, Password) - self.command('lsb_release -a', '\$', 5) + SSH.open(IPAddress, UserName, Password) + SSH.command('lsb_release -a', '\$', 5) result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) if result is not None: self.OsVersion = result.group('os_type') logging.debug('OS is: ' + self.OsVersion) - self.command('uname -r', '\$', 5) + SSH.command('uname -r', '\$', 5) result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', str(self.ssh.before)) if result is not None: self.KernelVersion = result.group('kernel_version') logging.debug('Kernel Version is: ' + self.KernelVersion) - self.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) + SSH.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', str(self.ssh.before)) if result is not None: self.UhdVersion = result.group('uhd_version') logging.debug('UHD Version is: ' + self.UhdVersion) - self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) + SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) if result is not None: self.UsrpBoard = result.group('usrp_board') logging.debug('USRP Board is: ' + self.UsrpBoard) - self.command('lscpu', '\$', 5) + SSH.command('lscpu', '\$', 5) result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', str(self.ssh.before)) if result is not None: self.CpuNb = result.group('nb_cpus') @@ -3991,7 +3992,7 @@ class OaiCiTest(): logging.debug('model: ' + self.CpuModel) self.CpuMHz = result.group('cpu_mhz') + ' MHz' logging.debug('cpu_mhz: ' + self.CpuMHz) - self.close() + SSH.close() #----------------------------------------------------------- # HTML Reporting.... @@ -4503,6 +4504,7 @@ def receive_signal(signum, frame): #----------------------------------------------------------- mode = '' CiTestObj = OaiCiTest() +SSH = SSHConnection() argvs = sys.argv argc = len(argvs) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py new file mode 100644 index 0000000000..b74fa14f58 --- /dev/null +++ b/ci-scripts/sshconnection.py @@ -0,0 +1,167 @@ +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class SSHConnection(): + def __init__(self): + def open(self, ipaddress, username, password): + count = 0 + connect_status = False + while count < 4: + self.ssh = pexpect.spawn('ssh', [username + '@' + ipaddress], timeout = 5) + self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + self.ssh.sendline('yes') + self.ssh.expect('password:') + self.ssh.sendline(password) + self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + count = 10 + connect_status = True + else: + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + elif self.sshresponse == 1: + self.ssh.sendline(password) + self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + count = 10 + connect_status = True + else: + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + elif self.sshresponse == 2: + # Checking if we are really on the remote client defined by its IP address + self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) + result = re.search(str(ipaddress), str(self.ssh.before)) + if result is None: + self.close() + else: + count = 10 + connect_status = True + else: + # debug output + logging.debug(str(self.ssh.before)) + logging.debug('self.sshresponse = ' + str(self.sshresponse)) + # adding a tempo when failure + if not connect_status: + time.sleep(1) + count += 1 + if connect_status: + pass + else: + sys.exit('CiTestObj.Connection Failed') + + + def command(self, commandline, expectedline, timeout): + logging.debug(commandline) + self.ssh.timeout = timeout + self.ssh.sendline(commandline) + self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + return 0 + elif self.sshresponse == 1: + logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + sys.exit(self.sshresponse) + elif self.sshresponse == 2: + logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + result = re.search('ping |iperf |picocom', str(commandline)) + if result is None: + logging.debug(str(self.ssh.before)) + sys.exit(self.sshresponse) + else: + return -1 + else: + logging.debug('\u001B[1;37;41m Unexpected Others \u001B[0m') + logging.debug('Expected Line : ' + expectedline) + sys.exit(self.sshresponse) + + def close(self): + self.ssh.timeout = 5 + self.ssh.sendline('exit') + self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: + pass + elif self.sshresponse == 1: + if not self.picocom_closure: + logging.debug('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') + + def copyin(self, ipaddress, username, password, source, destination): + count = 0 + copy_status = False + logging.debug('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination) + while count < 10: + scp_spawn = pexpect.spawn('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) + scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + scp_spawn.sendline('yes') + scp_spawn.expect('password:') + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + count = 10 + copy_status = True + else: + logging.debug('1 - scp_response = ' + str(scp_response)) + elif scp_response == 1: + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0 or scp_response == 3: + count = 10 + copy_status = True + else: + logging.debug('2 - scp_response = ' + str(scp_response)) + elif scp_response == 2: + count = 10 + copy_status = True + else: + logging.debug('3 - scp_response = ' + str(scp_response)) + # adding a tempo when failure + if not copy_status: + time.sleep(1) + count += 1 + if copy_status: + return 0 + else: + return -1 + + def copyout(self, ipaddress, username, password, source, destination): + count = 0 + copy_status = False + logging.debug('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination) + while count < 4: + scp_spawn = pexpect.spawn('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) + scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + scp_spawn.sendline('yes') + scp_spawn.expect('password:') + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0: + count = 10 + copy_status = True + else: + logging.debug('1 - scp_response = ' + str(scp_response)) + elif scp_response == 1: + scp_spawn.sendline(password) + scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) + if scp_response == 0 or scp_response == 3: + count = 10 + copy_status = True + else: + logging.debug('2 - scp_response = ' + str(scp_response)) + elif scp_response == 2: + count = 10 + copy_status = True + else: + logging.debug('3 - scp_response = ' + str(scp_response)) + # adding a tempo when failure + if not copy_status: + time.sleep(1) + count += 1 + if copy_status: + pass + else: + sys.exit('SCP failed') + From ba9786dfeab199fb4546506ca9f2aef41130adbe Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 13 Jan 2020 15:12:33 +0100 Subject: [PATCH 077/175] review of modified main.py and sshconnection.py --- ci-scripts/main.py | 202 +++++++++--------- ci-scripts/pMain.sh | 9 + ci-scripts/sshconnection.py | 10 + .../xml_files/enb_usrp210_band7_epc_start.xml | 54 +++++ 4 files changed, 175 insertions(+), 100 deletions(-) create mode 100755 ci-scripts/pMain.sh create mode 100644 ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml diff --git a/ci-scripts/main.py b/ci-scripts/main.py index dfbde89c45..9b332313bb 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -87,7 +87,6 @@ logging.basicConfig( level=logging.DEBUG, format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" ) -import sshconnection.py #----------------------------------------------------------- # Class Declaration @@ -214,7 +213,7 @@ class OaiCiTest(): elif self.sshresponse == 2: # Checking if we are really on the remote client defined by its IP address SSH.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) - result = re.search(str(ipaddress), str(self.ssh.before)) + result = re.search(str(ipaddress), SSH.getBefore()) if result is None: SSH.close() else: @@ -222,7 +221,7 @@ class OaiCiTest(): connect_status = True else: # debug output - logging.debug(str(self.ssh.before)) + logging.debug(SSH.getBefore()) logging.debug('self.sshresponse = ' + str(self.sshresponse)) # adding a tempo when failure if not connect_status: @@ -249,7 +248,7 @@ class OaiCiTest(): logging.debug('Expected Line : ' + expectedline) result = re.search('ping |iperf |picocom', str(commandline)) if result is None: - logging.debug(str(self.ssh.before)) + logging.debug(SSH.getBefore()) sys.exit(self.sshresponse) else: return -1 @@ -380,27 +379,27 @@ class OaiCiTest(): # Checking the BUILD INFO file if not self.backgroundBuild: SSH.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) + result = re.search('LAST_BUILD_INFO', SSH.getBefore()) if result is not None: mismatch = False SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, str(self.ssh.before)) + result = re.search(self.ranCommitID, SSH.getBefore()) if result is None: mismatch = True SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if (self.ranAllowMerge): - result = re.search('YES', str(self.ssh.before)) + result = re.search('YES', SSH.getBefore()) if result is None: mismatch = True SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if self.ranTargetBranch == '': - result = re.search('develop', str(self.ssh.before)) + result = re.search('develop', SSH.getBefore()) else: - result = re.search(self.ranTargetBranch, str(self.ssh.before)) + result = re.search(self.ranTargetBranch, SSH.getBefore()) if result is None: mismatch = True else: - result = re.search('NO', str(self.ssh.before)) + result = re.search('NO', SSH.getBefore()) if result is None: mismatch = True if not mismatch: @@ -461,7 +460,7 @@ class OaiCiTest(): buildOAIprocess = True while (count > 0) and buildOAIprocess: SSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) - result = re.search('build_oai', str(self.ssh.before)) + result = re.search('build_oai', SSH.getBefore()) if result is None: buildOAIprocess = False else: @@ -474,7 +473,7 @@ class OaiCiTest(): SSH.command('ls lte_build_oai/build', '\$', 3) SSH.command('ls lte_build_oai/build', '\$', 3) buildStatus = True - result = re.search('lte-softmodem', str(self.ssh.before)) + result = re.search('lte-softmodem', SSH.getBefore()) if result is None: buildStatus = False else: @@ -531,27 +530,27 @@ class OaiCiTest(): SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) SSH.command('git config user.name "OAI Jenkins"', '\$', 5) SSH.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) + result = re.search('LAST_BUILD_INFO', SSH.getBefore()) if result is not None: mismatch = False SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, str(self.ssh.before)) + result = re.search(self.ranCommitID, SSH.getBefore()) if result is None: mismatch = True SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if (self.ranAllowMerge): - result = re.search('YES', str(self.ssh.before)) + result = re.search('YES', SSH.getBefore()) if result is None: mismatch = True SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) if self.ranTargetBranch == '': - result = re.search('develop', str(self.ssh.before)) + result = re.search('develop', SSH.getBefore()) else: - result = re.search(self.ranTargetBranch, str(self.ssh.before)) + result = re.search(self.ranTargetBranch, SSH.getBefore()) if result is None: mismatch = True else: - result = re.search('NO', str(self.ssh.before)) + result = re.search('NO', SSH.getBefore()) if result is None: mismatch = True if not mismatch: @@ -581,7 +580,7 @@ class OaiCiTest(): SSH.command('ls lte_build_oai/build', '\$', 3) SSH.command('ls lte_build_oai/build', '\$', 3) buildStatus = True - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + result = re.search('lte-uesoftmodem', SSH.getBefore()) if result is None: buildStatus = False SSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) @@ -660,7 +659,7 @@ class OaiCiTest(): SSH.command('source oaienv', '\$', 5) SSH.command('cd scripts', '\$', 5) SSH.command('stdbuf -o0 hostname', '\$', 5) - result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', str(self.ssh.before)) + result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') sys.exit(1) @@ -708,7 +707,7 @@ class OaiCiTest(): return SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) - result = re.search('/opt/flexran_rtc/build/rt_controller', str(self.ssh.before)) + result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) if result is not None: self.flexranCtrlInstalled = True logging.debug('Flexran Controller is installed') @@ -727,7 +726,7 @@ class OaiCiTest(): SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) SSH.command('ps -aux | grep --color=never rt_controller', '\$', 5) - result = re.search('rt_controller -c ', str(self.ssh.before)) + result = re.search('rt_controller -c ', SSH.getBefore()) if result is not None: logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') self.flexranCtrlStarted = True @@ -765,7 +764,7 @@ class OaiCiTest(): if result is not None: SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', str(self.ssh.before)) + result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', SSH.getBefore()) if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') @@ -802,7 +801,7 @@ class OaiCiTest(): result = re.search('^rru|^enb|^du.band', str(config_file)) if result is not None: SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) + result = re.search('type: b200', SSH.getBefore()) if result is not None: logging.debug('Found a B2xx device --> resetting it') SSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) @@ -864,9 +863,9 @@ class OaiCiTest(): else: SSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) if rruCheck: - result = re.search('wait RUs', str(self.ssh.before)) + result = re.search('wait RUs', SSH.getBefore()) else: - result = re.search('got sync|Starting F1AP at CU', str(self.ssh.before)) + result = re.search('got sync|Starting F1AP at CU', SSH.getBefore()) if result is None: time.sleep(6) else: @@ -956,7 +955,7 @@ class OaiCiTest(): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) # b2xx_fx3_utils reset procedure SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) + result = re.search('type: b200', SSH.getBefore()) if result is not None: logging.debug('Found a B2xx device --> resetting it') SSH.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) @@ -971,7 +970,7 @@ class OaiCiTest(): # We may have to regenerate the .u* files if result is None: SSH.command('ls /tmp/*.sed', '\$', 5) - result = re.search('adapt_usim_parameters', str(self.ssh.before)) + result = re.search('adapt_usim_parameters', SSH.getBefore()) if result is not None: SSH.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) else: @@ -1007,7 +1006,7 @@ class OaiCiTest(): doLoop = False continue SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('got sync', str(self.ssh.before)) + result = re.search('got sync', SSH.getBefore()) if result is None: time.sleep(6) else: @@ -1016,7 +1015,7 @@ class OaiCiTest(): if gotSyncStatus == False: # we certainly need to stop the lte-uesoftmodem process if it is still running! SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + result = re.search('lte-uesoftmodem', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) time.sleep(3) @@ -1033,7 +1032,7 @@ class OaiCiTest(): fullSyncStatus = True continue SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('No cell synchronization found', str(self.ssh.before)) + result = re.search('No cell synchronization found', SSH.getBefore()) if result is None: time.sleep(6) else: @@ -1042,7 +1041,7 @@ class OaiCiTest(): logging.debug('Found: "No cell synchronization" message! --> try again') time.sleep(6) SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + result = re.search('lte-uesoftmodem', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) outterLoopCounter = outterLoopCounter - 1 @@ -1054,12 +1053,12 @@ class OaiCiTest(): if result is None: SSH.command('ifconfig oaitun_ue1', '\$', 4) # ifconfig output is different between ubuntu 16 and ubuntu 18 - result = re.search('inet addr:1|inet 1', str(self.ssh.before)) + result = re.search('inet addr:1|inet 1', SSH.getBefore()) if result is not None: logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') tunnelInterfaceStatus = True else: - logging.debug(str(self.ssh.before)) + logging.debug(SSH.getBefore()) logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') tunnelInterfaceStatus = False else: @@ -1085,7 +1084,7 @@ class OaiCiTest(): count = 0 while count < 5: SSH.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) - result = re.search('picocom', str(self.ssh.before)) + result = re.search('picocom', SSH.getBefore()) if result is None: count = 10 else: @@ -1111,7 +1110,7 @@ class OaiCiTest(): logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') # Checking if auto-attach is enabled SSH.command('AT^AUTOATT?', 'OK', 5) - result = re.search('AUTOATT: (?P[0-9\-]+)', str(self.ssh.before)) + result = re.search('AUTOATT: (?P[0-9\-]+)', SSH.getBefore()) if result is not None: if result.group('state') is not None: autoAttachState = int(result.group('state')) @@ -1171,14 +1170,14 @@ class OaiCiTest(): attach_status = False while count < 5: SSH.command('AT+CEREG?', 'OK', 5) - result = re.search('CEREG: 2,(?P[0-9\-]+),', str(self.ssh.before)) + result = re.search('CEREG: 2,(?P[0-9\-]+),', SSH.getBefore()) if result is not None: mDataConnectionState = int(result.group('state')) if mDataConnectionState is not None: if mDataConnectionState == 1: count = 10 attach_status = True - result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', str(self.ssh.before)) + result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', SSH.getBefore()) if result is not None: networky = result.group('networky') networkz = result.group('networkz') @@ -1189,13 +1188,13 @@ class OaiCiTest(): logging.debug('+CEREG: 2,' + str(mDataConnectionState)) attach_cnt = attach_cnt + 1 else: - logging.debug(str(self.ssh.before)) + logging.debug(SSH.getBefore()) attach_cnt = attach_cnt + 1 count = count + 1 time.sleep(1) if attach_status: SSH.command('AT+CESQ', 'OK', 5) - result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', str(self.ssh.before)) + result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', SSH.getBefore()) if result is not None: nRSRQ = int(result.group('rsrq')) nRSRP = int(result.group('rsrp')) @@ -1246,7 +1245,7 @@ class OaiCiTest(): sys.exit(1) else: SSH.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) - result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', str(self.ssh.before)) + result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', SSH.getBefore()) if result is not None: moduleIPAddr = result.group('ipaddr') else: @@ -1263,7 +1262,7 @@ class OaiCiTest(): SSH.close() self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) if result is None: message = 'Packet Loss Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -1277,7 +1276,7 @@ class OaiCiTest(): SSH.close() self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) if result is None: message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -1338,7 +1337,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') lock.acquire() @@ -1501,7 +1500,7 @@ class OaiCiTest(): # Save mDataConnectionState SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') sys.exit(1) @@ -1514,7 +1513,7 @@ class OaiCiTest(): while count > 0: count = count - 1 SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) if result is None: mDataConnectionState = None else: @@ -1619,13 +1618,14 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: SSH.command('adb devices', '\$', 15) - self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",str(self.ssh.before)) + #self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) + self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) SSH.close() else: if (os.path.isfile('./phones_list.txt')): os.remove('./phones_list.txt') SSH.command('ls /etc/*/phones*.txt', '\$', 5) - result = re.search('/etc/ci/phones_list.txt', str(self.ssh.before)) + result = re.search('/etc/ci/phones_list.txt', SSH.getBefore()) SSH.close() if (result is not None) and (len(self.UEDevices) == 0): SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') @@ -1662,12 +1662,13 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: SSH.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) - self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",str(self.ssh.before)) + #self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) + self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) else: if (os.path.isfile('./modules_list.txt')): os.remove('./modules_list.txt') SSH.command('ls /etc/*/modules*.txt', '\$', 5) - result = re.search('/etc/ci/modules_list.txt', str(self.ssh.before)) + result = re.search('/etc/ci/modules_list.txt', SSH.getBefore()) SSH.close() if result is not None: logging.debug('Found a module list file on ADB server') @@ -1684,7 +1685,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) - result = re.search('mServiceState=(?P[0-9]+)', str(self.ssh.before)) + result = re.search('mServiceState=(?P[0-9]+)', SSH.getBefore()) serviceState = 'Service State: UNKNOWN' if result is not None: lServiceState = int(result.group('serviceState')) @@ -1696,7 +1697,7 @@ class OaiCiTest(): serviceState = 'Service State: IN_SERVICE' if lServiceState == 2: serviceState = 'Service State: EMERGENCY_ONLY' - result = re.search('mDataConnectionState=(?P[0-9]+)', str(self.ssh.before)) + result = re.search('mDataConnectionState=(?P[0-9]+)', SSH.getBefore()) dataConnectionState = 'Data State: UNKNOWN' if result is not None: lDataConnectionState = int(result.group('dataConnectionState')) @@ -1708,7 +1709,7 @@ class OaiCiTest(): dataConnectionState = 'Data State: CONNECTED' if lDataConnectionState == 3: dataConnectionState = 'Data State: SUSPENDED' - result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', str(self.ssh.before)) + result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', SSH.getBefore()) dataConnectionReason = 'Data Reason: UNKNOWN' if result is not None: dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') @@ -1754,7 +1755,7 @@ class OaiCiTest(): SSH.command('cd /opt/flexran_rtc', '\$', 5) SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) - result = re.search('Nb Connected UE = (?P[0-9]+)', str(self.ssh.before)) + result = re.search('Nb Connected UE = (?P[0-9]+)', SSH.getBefore()) passStatus = True if result is not None: nb_ues = int(result.group('nb_ues')) @@ -1802,7 +1803,7 @@ class OaiCiTest(): sys.exit('Insufficient Parameter') SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('ifconfig oaitun_ue1', '\$', 4) - result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', str(self.ssh.before)) + result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', SSH.getBefore()) if result is not None: if result.group('ueipaddress') is not None: UE_IPAddress = result.group('ueipaddress') @@ -1827,7 +1828,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) - result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', str(self.ssh.before)) + result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') time.sleep(1) @@ -1887,7 +1888,7 @@ class OaiCiTest(): SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) if result is None: message = 'Packet Loss Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -1901,7 +1902,7 @@ class OaiCiTest(): SSH.close() self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) if result is None: message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -1982,7 +1983,7 @@ class OaiCiTest(): logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') self.PingNoS1_wrong_exit(message) return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) if result is None: message = 'Packet Loss Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -1994,7 +1995,7 @@ class OaiCiTest(): logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') self.PingNoS1_wrong_exit(message) return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) if result is None: message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -2134,7 +2135,7 @@ class OaiCiTest(): def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): SSH.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', str(self.ssh.before)) + result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', SSH.getBefore()) if result is not None: avgbitrate = result.group('average') maxbitrate = result.group('maximum') @@ -2163,9 +2164,9 @@ class OaiCiTest(): if result is None: return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) - result = re.search('Server Report:', str(self.ssh.before)) + result = re.search('Server Report:', SSH.getBefore()) if result is None: - result = re.search('read failed: Connection refused', str(self.ssh.before)) + result = re.search('read failed: Connection refused', SSH.getBefore()) if result is not None: logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') else: @@ -2189,7 +2190,7 @@ class OaiCiTest(): req_bandwidth = '%.1f Gbits/sec' % req_bw req_bw = req_bw * 1000000000 - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) + result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', SSH.getBefore()) if result is not None: bitrate = result.group('bitrate') packetloss = result.group('packetloss') @@ -2340,9 +2341,9 @@ class OaiCiTest(): def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', str(self.ssh.before)) + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', SSH.getBefore()) if result is None: - result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', str(self.ssh.before)) + result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', SSH.getBefore()) lock.acquire() statusQueue.put(-1) statusQueue.put(device_id) @@ -2503,9 +2504,9 @@ class OaiCiTest(): SSH.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) - result = re.search('iperf3', str(self.ssh.before)) + result = re.search('iperf3', SSH.getBefore()) if result is None: - result = re.search('iperf', str(self.ssh.before)) + result = re.search('iperf', SSH.getBefore()) if result is None: message = 'Neither iperf nor iperf3 installed on UE!' logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') @@ -2517,10 +2518,10 @@ class OaiCiTest(): SSH.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) - result = re.search('iperf version 2.0.5', str(self.ssh.before)) + result = re.search('iperf version 2.0.5', SSH.getBefore()) if result is not None: self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', str(self.ssh.before)) + result = re.search('iperf version 2.0.10', SSH.getBefore()) if result is not None: self.ueIperfVersion = '2.0.10' else: @@ -2529,10 +2530,10 @@ class OaiCiTest(): else: SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('iperf --version', '\$', 5) - result = re.search('iperf version 2.0.5', str(self.ssh.before)) + result = re.search('iperf version 2.0.5', SSH.getBefore()) if result is not None: self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', str(self.ssh.before)) + result = re.search('iperf version 2.0.10', SSH.getBefore()) if result is not None: self.ueIperfVersion = '2.0.10' SSH.close() @@ -2640,7 +2641,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) - result = re.search('shell +(?P\d+)', str(self.ssh.before)) + result = re.search('shell +(?P\d+)', SSH.getBefore()) if result is not None: pid_iperf = result.group('pid') if self.ADBCentralized: @@ -2931,7 +2932,7 @@ class OaiCiTest(): try: SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + result = re.search('lte-uesoftmodem', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') status_queue.put(OAI_UE_PROCESS_FAILED) @@ -2945,7 +2946,7 @@ class OaiCiTest(): try: SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) + result = re.search('lte-softmodem', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') status_queue.put(ENB_PROCESS_FAILED) @@ -2960,11 +2961,11 @@ class OaiCiTest(): SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) SSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('oai_hss -j', str(self.ssh.before)) + result = re.search('oai_hss -j', SSH.getBefore()) elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('hss_sim s6as diam_hss', str(self.ssh.before)) + result = re.search('hss_sim s6as diam_hss', SSH.getBefore()) else: logging.error('This should not happen!') if result is None: @@ -2981,11 +2982,11 @@ class OaiCiTest(): SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) SSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('mme -c', str(self.ssh.before)) + result = re.search('mme -c', SSH.getBefore()) elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('mme', str(self.ssh.before)) + result = re.search('mme', SSH.getBefore()) else: logging.error('This should not happen!') if result is None: @@ -3002,13 +3003,13 @@ class OaiCiTest(): SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('spgwu -c ', str(self.ssh.before)) + result = re.search('spgwu -c ', SSH.getBefore()) elif re.match('OAI', self.EPCType, re.IGNORECASE): SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) elif re.match('ltebox', self.EPCType, re.IGNORECASE): SSH.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) - result = re.search('xGw', str(self.ssh.before)) + result = re.search('xGw', SSH.getBefore()) else: logging.error('This should not happen!') if result is None: @@ -3448,13 +3449,13 @@ class OaiCiTest(): SSH.open(lIpAddr, lUserName, lPassWord) SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) + result = re.search('lte-softmodem', SSH.getBefore()) if result is not None: SSH.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) time.sleep(10) SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) + result = re.search('lte-softmodem', SSH.getBefore()) if result is not None: SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) time.sleep(5) @@ -3521,7 +3522,7 @@ class OaiCiTest(): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) time.sleep(2) SSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('oai_hss -j', str(self.ssh.before)) + result = re.search('oai_hss -j', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) @@ -3529,7 +3530,7 @@ class OaiCiTest(): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) time.sleep(2) SSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): @@ -3549,7 +3550,7 @@ class OaiCiTest(): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) time.sleep(2) SSH.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) - result = re.search('mme -c', str(self.ssh.before)) + result = re.search('mme -c', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) @@ -3567,12 +3568,12 @@ class OaiCiTest(): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) time.sleep(2) SSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('spgwc -c |spgwu -c ', str(self.ssh.before)) + result = re.search('spgwc -c |spgwu -c ', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) SSH.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) - result = re.search('-w ', str(self.ssh.before)) + result = re.search('-w ', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) @@ -3580,7 +3581,7 @@ class OaiCiTest(): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) time.sleep(2) SSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) + result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) elif re.match('ltebox', self.EPCType, re.IGNORECASE): @@ -3623,7 +3624,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) - result = re.search('shell +(?P\d+)', str(self.ssh.before)) + result = re.search('shell +(?P\d+)', SSH.getBefore()) if result is not None: pid_iperf = result.group('pid') if self.ADBCentralized: @@ -3653,13 +3654,13 @@ class OaiCiTest(): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + result = re.search('lte-uesoftmodem', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) time.sleep(10) SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + result = re.search('lte-uesoftmodem', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) time.sleep(5) @@ -3964,27 +3965,27 @@ class OaiCiTest(): SSH.open(IPAddress, UserName, Password) SSH.command('lsb_release -a', '\$', 5) - result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) + result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) if result is not None: self.OsVersion = result.group('os_type') logging.debug('OS is: ' + self.OsVersion) SSH.command('uname -r', '\$', 5) - result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', str(self.ssh.before)) + result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', SSH.getBefore()) if result is not None: self.KernelVersion = result.group('kernel_version') logging.debug('Kernel Version is: ' + self.KernelVersion) SSH.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) - result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', str(self.ssh.before)) + result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', SSH.getBefore()) if result is not None: self.UhdVersion = result.group('uhd_version') logging.debug('UHD Version is: ' + self.UhdVersion) SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) - result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) + result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', SSH.getBefore()) if result is not None: self.UsrpBoard = result.group('usrp_board') logging.debug('USRP Board is: ' + self.UsrpBoard) SSH.command('lscpu', '\$', 5) - result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', str(self.ssh.before)) + result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', SSH.getBefore()) if result is not None: self.CpuNb = result.group('nb_cpus') logging.debug('nb_cpus: ' + self.CpuNb) @@ -4504,6 +4505,7 @@ def receive_signal(signum, frame): #----------------------------------------------------------- mode = '' CiTestObj = OaiCiTest() +from sshconnection import * SSH = SSHConnection() argvs = sys.argv diff --git a/ci-scripts/pMain.sh b/ci-scripts/pMain.sh new file mode 100755 index 0000000000..7708e349b4 --- /dev/null +++ b/ci-scripts/pMain.sh @@ -0,0 +1,9 @@ +python3 main.py --mode=InitiateHtml --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_build.xml --XMLTestFile=xml_files/dummy_ltebox_start.xml --XMLTestFile=xml_files/dummy_enb_test.xml --XMLTestFile=xml_files/dummy_ltebox_stop.xml +python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_build.xml + +python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_ltebox_start.xml + +python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_enb_test.xml +python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_ltebox_stop.xml +python3 main.py --mode=FinalizeHtml --finalStatus=true --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux + diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index b74fa14f58..d10edf360b 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -1,8 +1,16 @@ +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import pexpect # pexpect +import logging + #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class SSHConnection(): def __init__(self): + self.ssh = '' + def open(self, ipaddress, username, password): count = 0 connect_status = False @@ -165,3 +173,5 @@ class SSHConnection(): else: sys.exit('SCP failed') + def getBefore(self): + return str(self.ssh.before) diff --git a/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml b/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml new file mode 100644 index 0000000000..3f982f0446 --- /dev/null +++ b/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml @@ -0,0 +1,54 @@ + + + epc-start + EPC-Start + log-in + + 010101 + 050101 060101 070101 + + + + + Build_eNB + Build eNB (USRP) + -w USRP -c --eNB + + + + Initialize_HSS + Initialize HSS + + + + Initialize_MME + Initialize MME + + + + Initialize_SPGW + Initialize SPGW + + + From ec258105f63fcb6ee2f7dc7ae9bb228e64ab26f1 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 14 Jan 2020 14:52:57 +0100 Subject: [PATCH 078/175] Removed the old ssh commands from orignal implementaion location FIx missing replacement --- ci-scripts/main.py | 165 +----------------- ci-scripts/pMain.sh | 9 - .../xml_files/enb_usrp210_band7_epc_start.xml | 54 ------ 3 files changed, 2 insertions(+), 226 deletions(-) delete mode 100755 ci-scripts/pMain.sh delete mode 100644 ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 9b332313bb..5d66ab9ee8 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -186,167 +186,6 @@ class OaiCiTest(): self.expectedNbOfConnectedUEs = 0 self.startTime = 0 - def open(self, ipaddress, username, password): - count = 0 - connect_status = False - while count < 4: - self.ssh = pexpect.spawn('ssh', [username + '@' + ipaddress], timeout = 5) - self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - self.ssh.sendline('yes') - self.ssh.expect('password:') - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 1: - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 2: - # Checking if we are really on the remote client defined by its IP address - SSH.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) - result = re.search(str(ipaddress), SSH.getBefore()) - if result is None: - SSH.close() - else: - count = 10 - connect_status = True - else: - # debug output - logging.debug(SSH.getBefore()) - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - # adding a tempo when failure - if not connect_status: - time.sleep(1) - count += 1 - if connect_status: - pass - else: - sys.exit('CiTestObj.Connection Failed') - - def command(self, commandline, expectedline, timeout): - logging.debug(commandline) - self.ssh.timeout = timeout - self.ssh.sendline(commandline) - self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - return 0 - elif self.sshresponse == 1: - logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) - elif self.sshresponse == 2: - logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - result = re.search('ping |iperf |picocom', str(commandline)) - if result is None: - logging.debug(SSH.getBefore()) - sys.exit(self.sshresponse) - else: - return -1 - else: - logging.debug('\u001B[1;37;41m Unexpected Others \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) - - def close(self): - self.ssh.timeout = 5 - self.ssh.sendline('exit') - self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - pass - elif self.sshresponse == 1: - if not self.picocom_closure: - logging.debug('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') - else: - logging.debug('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') - - def copyin(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.debug('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination) - while count < 10: - scp_spawn = pexpect.spawn('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.debug('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.debug('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.debug('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - return 0 - else: - return -1 - - def copyout(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.debug('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination) - while count < 4: - scp_spawn = pexpect.spawn('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.debug('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.debug('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.debug('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - pass - else: - sys.exit('SCP failed') - def BuildeNB(self): if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': Usage() @@ -4760,8 +4599,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re sys.exit('Insufficient Parameter') if (CiTestObj.EPCIPAddress != '') and (CiTestObj.EPCIPAddress != 'none'): - CiTestObj.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") - CiTestObj.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") + SSH.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") + SSH.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") else: if CiTestObj.UEIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': Usage() diff --git a/ci-scripts/pMain.sh b/ci-scripts/pMain.sh deleted file mode 100755 index 7708e349b4..0000000000 --- a/ci-scripts/pMain.sh +++ /dev/null @@ -1,9 +0,0 @@ -python3 main.py --mode=InitiateHtml --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_build.xml --XMLTestFile=xml_files/dummy_ltebox_start.xml --XMLTestFile=xml_files/dummy_enb_test.xml --XMLTestFile=xml_files/dummy_ltebox_stop.xml -python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_build.xml - -python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_ltebox_start.xml - -python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_enb_test.xml -python3 main.py --mode=TesteNB --ranRepository=https://gitlab.eurecom.fr/oai/openairinterface5g --ranBranch=develop --ranCommitID=424bf5c53e879af7d66aaa50e0cd969eeb570dbd --ranAllowMerge=false --ranTargetBranch=develop --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux --eNBSourceCodePath=/tmp/CI-gabriele --EPCIPAddress=192.168.12.240 --EPCType=ltebox --EPCUserName=bourdon --EPCPassword=linux --EPCSourceCodePath=/tmp/CI-eNB --ADBIPAddress=192.168.12.240 --ADBUserName=bourdon --ADBPassword=linux --XMLTestFile=xml_files/dummy_ltebox_stop.xml -python3 main.py --mode=FinalizeHtml --finalStatus=true --eNBIPAddress=192.168.12.161 --eNBUserName=acilius --eNBPassword=linux - diff --git a/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml b/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml deleted file mode 100644 index 3f982f0446..0000000000 --- a/ci-scripts/xml_files/enb_usrp210_band7_epc_start.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - epc-start - EPC-Start - log-in - - 010101 - 050101 060101 070101 - - - - - Build_eNB - Build eNB (USRP) - -w USRP -c --eNB - - - - Initialize_HSS - Initialize HSS - - - - Initialize_MME - Initialize MME - - - - Initialize_SPGW - Initialize SPGW - - - From 5d1f16c3e92908000249d89b084cc821084a8414 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 14 Jan 2020 14:54:53 +0100 Subject: [PATCH 079/175] fix gitignore file --- ci-scripts/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci-scripts/.gitignore b/ci-scripts/.gitignore index d77a672c0c..dc5e7c7476 100644 --- a/ci-scripts/.gitignore +++ b/ci-scripts/.gitignore @@ -5,3 +5,5 @@ iperf_*.* phones_list.txt modules_list.txt test_results*.html +pMain* +__pycache__ From b104c26212baa92c1e033011ded767cdd3784381 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 14 Jan 2020 15:25:21 +0100 Subject: [PATCH 080/175] overwriting config file mnc with the proper mnc (93) --- ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml index 3b07ed4950..6bc60b113a 100644 --- a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml @@ -108,7 +108,7 @@ Initialize_eNB Initialize eNB (FDD/Band7/5MHz) - -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].plmn_list.[0].mnc 93 From 0235b8c0e7b359795ab38b32bdd83efbda01318b Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 21 Jan 2020 13:50:44 +0100 Subject: [PATCH 081/175] CI: first draft of separating EPC functions Signed-off-by: Gabriele Perrone --- ci-scripts/constants.py | 71 +++++++++ ci-scripts/epc.py | 330 +++++++++++++++++++++++++++++++++++++++ ci-scripts/helpreadme.py | 51 ++++++ ci-scripts/main.py | 296 ++++++++++++++++++----------------- 4 files changed, 603 insertions(+), 145 deletions(-) create mode 100644 ci-scripts/constants.py create mode 100644 ci-scripts/epc.py create mode 100644 ci-scripts/helpreadme.py diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py new file mode 100644 index 0000000000..f07fd81b43 --- /dev/null +++ b/ci-scripts/constants.py @@ -0,0 +1,71 @@ + +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + +#----------------------------------------------------------- +# Version +#----------------------------------------------------------- +Version = '0.1' + +#----------------------------------------------------------- +# Constants +#----------------------------------------------------------- +ALL_PROCESSES_OK = 0 +ENB_PROCESS_FAILED = -1 +ENB_PROCESS_OK = +1 +ENB_PROCESS_SEG_FAULT = -11 +ENB_PROCESS_ASSERTION = -12 +ENB_PROCESS_REALTIME_ISSUE = -13 +ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 +ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 +HSS_PROCESS_FAILED = -2 +HSS_PROCESS_OK = +2 +MME_PROCESS_FAILED = -3 +MME_PROCESS_OK = +3 +SPGW_PROCESS_FAILED = -4 +SPGW_PROCESS_OK = +4 +UE_IP_ADDRESS_ISSUE = -5 +OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 +OAI_UE_PROCESS_COULD_NOT_SYNC = -21 +OAI_UE_PROCESS_ASSERTION = -22 +OAI_UE_PROCESS_FAILED = -23 +OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 +OAI_UE_PROCESS_OK = +6 + +UE_STATUS_DETACHED = 0 +UE_STATUS_DETACHING = 1 +UE_STATUS_ATTACHING = 2 +UE_STATUS_ATTACHED = 3 + +X2_HO_REQ_STATE__IDLE = 0 +X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 +X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 +X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 +X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 + diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py new file mode 100644 index 0000000000..3ebb3cfb04 --- /dev/null +++ b/ci-scripts/epc.py @@ -0,0 +1,330 @@ +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import sys # arg +import re # reg +import logging +import os +import time +from multiprocessing import Process, Lock, SimpleQueue + +#----------------------------------------------------------- +# OAI Testing modules +#----------------------------------------------------------- +import sshconnection as SSH +#from sshconnection import SSHConnection as SSH +import helpreadme as HELP +import constants as CONST + +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class EPCManagement(): + def __init__(self): + self.EPCIPAddress = '' + self.EPCUserName = '' + self.EPCPassword = '' + self.EPCSourceCodePath = '' + self.EPCType = '' + self.EPC_PcapFileName = '' + + def InitializeHSS(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + HELP.GenericHelp() + HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) + sys.exit('Insufficient EPC Parameters') + #mySSH = SSH() + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') + mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') + EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) + mySSH.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) + mySSH.command('chmod 755 ./my-hss.sh', '\$', 5) + mySSH.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC HSS') + mySSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + mySSH.command('source oaienv', '\$', 5) + mySSH.command('cd scripts', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + logging.debug('Using the ltebox simulated HSS') + mySSH.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.EPCPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + mySSH.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + mySSH.command('cd /opt/hss_sim0609', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + else: + logging.error('This option should not occur!') + mySSH.close() + #self.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) + + def InitializeMME(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + HELP.GenericHelp() + HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) + sys.exit('Insufficient EPC Parameters') + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 MME') + mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) + mySSH.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) + mySSH.command('chmod 755 ./my-mme.sh', '\$', 5) + mySSH.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + mySSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + mySSH.command('source oaienv', '\$', 5) + mySSH.command('cd scripts', '\$', 5) + mySSH.command('stdbuf -o0 hostname', '\$', 5) + result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', mySSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') + sys.exit(1) + host_name = result.group('host_name') + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cd /opt/ltebox/tools', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) + else: + logging.error('This option should not occur!') + mySSH.close() + #self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + def InitializeSPGW(self): + if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + HELP.GenericHelp() + HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) + sys.exit('Insufficient EPC Parameters') + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') + mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) + mySSH.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) + mySSH.command('chmod 755 ./my-spgwc.sh', '\$', 5) + mySSH.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) + time.sleep(5) + mySSH.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) + mySSH.command('chmod 755 ./my-spgwu.sh', '\$', 5) + mySSH.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + mySSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + mySSH.command('source oaienv', '\$', 5) + mySSH.command('cd scripts', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cd /opt/ltebox/tools', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) + else: + logging.error('This option should not occur!') + mySSH.close() + #self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + + + def CheckHSSProcess(self, status_queue): + try: + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + mySSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + result = re.search('oai_hss -j', mySSH.getBefore()) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + result = re.search('\/bin\/bash .\/run_', mySSH.getBefore()) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + result = re.search('hss_sim s6as diam_hss', mySSH.getBefore()) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m HSS Process Not Found! \u001B[0m') + status_queue.put(CONST.HSS_PROCESS_FAILED) + else: + status_queue.put(CONST.HSS_PROCESS_OK) + mySSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckMMEProcess(self, status_queue): + try: + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + mySSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + result = re.search('mme -c', mySSH.getBefore()) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + result = re.search('\/bin\/bash .\/run_', mySSH.getBefore()) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + result = re.search('mme', mySSH.getBefore()) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m MME Process Not Found! \u001B[0m') + status_queue.put(CONST.MME_PROCESS_FAILED) + else: + status_queue.put(CONST.MME_PROCESS_OK) + mySSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckSPGWProcess(self, status_queue): + try: + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + result = re.search('spgwu -c ', mySSH.getBefore()) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + mySSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', mySSH.getBefore()) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) + result = re.search('xGw', mySSH.getBefore()) + else: + logging.error('This should not happen!') + if result is None: + logging.debug('\u001B[1;37;41m SPGW Process Not Found! \u001B[0m') + status_queue.put(CONST.SPGW_PROCESS_FAILED) + else: + status_queue.put(CONST.SPGW_PROCESS_OK) + mySSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + + def TerminateHSS(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) + time.sleep(2) + mySSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + result = re.search('oai_hss -j', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) + mySSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) + time.sleep(2) + mySSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + mySSH.command('cd scripts', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) + time.sleep(1) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) + else: + logging.error('This should not happen!') + mySSH.close() + #self.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + + def TerminateMME(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) + time.sleep(2) + mySSH.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) + result = re.search('mme -c', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) + mySSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cd /opt/ltebox/tools', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) + else: + logging.error('This should not happen!') + mySSH.close() + #self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateSPGW(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) + time.sleep(2) + mySSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + result = re.search('spgwc -c |spgwu -c ', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) + mySSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) + mySSH.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) + result = re.search('-w ', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) + elif re.match('OAI', self.EPCType, re.IGNORECASE): + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) + time.sleep(2) + mySSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) + result = re.search('\/bin\/bash .\/run_', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cd /opt/ltebox/tools', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) + else: + logging.error('This should not happen!') + mySSH.close() + #self.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + + + def LogCollectHSS(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + mySSH.command('rm -f hss.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('zip hss.log.zip hss*.log', '\$', 60) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) + if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) + mySSH.command('zip hss.log.zip hss.log', '\$', 60) + else: + logging.error('This option should not occur!') + mySSH.close() + + def LogCollectMME(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + mySSH.command('rm -f mme.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('zip mme.log.zip mme*.log', '\$', 60) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) + mySSH.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) + else: + logging.error('This option should not occur!') + mySSH.close() + + def LogCollectSPGW(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + mySSH.command('rm -f spgw.log.zip', '\$', 5) + if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + mySSH.command('zip spgw.log.zip spgw*.log', '\$', 60) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) + elif re.match('ltebox', self.EPCType, re.IGNORECASE): + mySSH.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) + mySSH.command('zip spgw.log.zip xGwLog.0', '\$', 60) + else: + logging.error('This option should not occur!') + mySSH.close() + diff --git a/ci-scripts/helpreadme.py b/ci-scripts/helpreadme.py new file mode 100644 index 0000000000..ed4fc5ecec --- /dev/null +++ b/ci-scripts/helpreadme.py @@ -0,0 +1,51 @@ +#----------------------------------------------------------- +# Functions Declaration +#----------------------------------------------------------- + +def GenericHelp(): + print('----------------------------------------------------------------------------------------------------------------------') + print('main.py Ver: 0.1') + print('----------------------------------------------------------------------------------------------------------------------') + print('Usage: python main.py [options]') + print(' --help Show this help.') + print(' --mode=[Mode]') + print(' TesteNB') + print(' InitiateHtml, FinalizeHtml') + print(' TerminateeNB, TerminateUE, TerminateHSS, TerminateMME, TerminateSPGW') + print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf') + +def GitSrvHelp(repository,branch,commit,mergeallow,targetbranch): + print(' --ranRepository=[OAI RAN Repository URL] -- ' + repository) + print(' --ranBranch=[OAI RAN Repository Branch] -- ' + branch) + print(' --ranCommitID=[OAI RAN Repository Commit SHA-1] -- ' + commit) + print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)] -- ' + mergeallow) + print(' --ranTargetBranch=[Target Branch in case of a Merge Request] -- ' + targetbranch) + +def eNBSrvHelp(ipaddr, username, password, sourcepath): + print(' --eNBIPAddress=[eNB\'s IP Address] -- ' + ipaddr) + print(' --eNBUserName=[eNB\'s Login User Name] -- ' + username) + print(' --eNBPassword=[eNB\'s Login Password] -- ' + password) + print(' --eNBSourceCodePath=[eNB\'s Source Code Path] -- ' + sourcepath) + +def OAIUESrvHelp(ipaddr, username, password, sourcepath): + print(' --UEIPAddress=[UE\'s IP Address] -- ' + ipaddr) + print(' --UEUserName=[UE\'s Login User Name] -- ' + username) + print(' --UEPassword=[UE\'s Login Password] -- ' + password) + print(' --UESourceCodePath=[UE\'s Source Code Path] -- ' + sourcepath) + +def EPCSrvHelp(ipaddr, username, password, sourcepath, epctype): + print(' --EPCIPAddress=[EPC\'s IP Address] -- ' + ipaddr) + print(' --EPCUserName=[EPC\'s Login User Name] -- ' + username) + print(' --EPCPassword=[EPC\'s Login Password] -- ' + password) + print(' --EPCSourceCodePath=[EPC\'s Source Code Path] -- ' + sourcepath) + print(' --EPCType=[EPC\'s Type: OAI or ltebox or OAI-Rel14-CUPS] -- ' + epctype) + +def ADBSrvHelp(ipaddr, username, password): + print(' --ADBIPAddress=[ADB\'s IP Address] -- ' + ipaddr) + print(' --ADBUserName=[ADB\'s Login User Name] -- ' + username) + print(' --ADBPassword=[ADB\'s Login Password] -- ' + password) + +def XmlHelp(filename): + print(' --XMLTestFile=[XML Test File to be run] -- ' + filename) + print(' Note: multiple xml files can be specified (--XMLFile=File1 ... --XMLTestFile=FileN) when HTML headers are created ("InitiateHtml" mode)') + diff --git a/ci-scripts/main.py b/ci-scripts/main.py index d3a700899f..1b1cd4efce 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -1,4 +1,4 @@ -# /* + # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -104,9 +104,9 @@ class OaiCiTest(): self.eNBUserName = '' self.eNBPassword = '' self.eNBSourceCodePath = '' - self.EPCIPAddress = '' - self.EPCUserName = '' - self.EPCPassword = '' + #self.EPCIPAddress = '' + #self.EPCUserName = '' + #self.EPCPassword = '' self.eNB1IPAddress = '' self.eNB1UserName = '' self.eNB1Password = '' @@ -115,9 +115,9 @@ class OaiCiTest(): self.eNB2UserName = '' self.eNB2Password = '' self.eNB2SourceCodePath = '' - self.EPCSourceCodePath = '' - self.EPCType = '' - self.EPC_PcapFileName = '' + #self.EPCSourceCodePath = '' + #self.EPCType = '' + #self.EPC_PcapFileName = '' self.ADBIPAddress = '' self.ADBUserName = '' self.ADBPassword = '' @@ -450,45 +450,45 @@ class OaiCiTest(): sys.exit(1) def InitializeHSS(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': Usage() sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) - SSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) + SSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + EPC.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.EPCUserName, 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) SSH.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) SSH.command('chmod 755 ./my-hss.sh', '\$', 5) - SSH.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): + SSH.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + EPC.EPCSourceCodePath + '/scripts -o ' + EPC.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) + elif re.match('OAI', EPC.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC HSS') - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) SSH.command('source oaienv', '\$', 5) SSH.command('cd scripts', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) + elif re.match('ltebox', EPC.EPCType, re.IGNORECASE): logging.debug('Using the ltebox simulated HSS') - SSH.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - SSH.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('if [ -d ' + EPC.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + EPC.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('mkdir -p ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) SSH.command('cd /opt/hss_sim0609', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) else: logging.error('This option should not occur!') SSH.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + self.CreateHtmlTestRow(EPC.EPCType, 'OK', ALL_PROCESSES_OK) def InitializeMME(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + if self.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': Usage() sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 MME') SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) @@ -516,10 +516,10 @@ class OaiCiTest(): self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def InitializeSPGW(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': + if self.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': Usage() sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) @@ -545,9 +545,9 @@ class OaiCiTest(): self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def CheckFlexranCtrlInstallation(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': return - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) if result is not None: @@ -558,15 +558,15 @@ class OaiCiTest(): def InitializeFlexranCtrl(self): if self.flexranCtrlInstalled == False: return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': Usage() sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('cd /opt/flexran_rtc', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) SSH.command('ps -aux | grep --color=never rt_controller', '\$', 5) result = re.search('rt_controller -c ', SSH.getBefore()) if result is not None: @@ -604,15 +604,15 @@ class OaiCiTest(): # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', SSH.getBefore()) if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - self.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) - SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + EPC.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.EPCUserName, 5) SSH.close() SSH.open(lIpAddr, lUserName, lPassWord) SSH.command('cd ' + lSourcePath, '\$', 5) @@ -651,7 +651,7 @@ class OaiCiTest(): SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) # Make a copy and adapt to EPC / eNB IP addresses SSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); SSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); SSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); @@ -700,18 +700,18 @@ class OaiCiTest(): # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if self.EPC_PcapFileName != '': + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if EPC.EPC_PcapFileName != '': time.sleep(0.5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) SSH.close() time.sleep(1) - if self.EPC_PcapFileName != '': - copyin_res = SSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') + if EPC.EPC_PcapFileName != '': + copyin_res = SSH.copyin(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, '/tmp/' + EPC.EPC_PcapFileName , '.') if (copyin_res == 0): - SSH.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') self.prematureExit = True return else: @@ -1106,7 +1106,7 @@ class OaiCiTest(): self.AutoTerminateUEandeNB() def PingCatM(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') check_eNB = True @@ -1119,10 +1119,10 @@ class OaiCiTest(): try: statusQueue = SimpleQueue() lock = Lock() - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) SSH.command('cd scripts', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE): + if re.match('OAI', EPC.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC HSS: not implemented yet') self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.CreateHtmlTabFooter(False) @@ -1635,7 +1635,7 @@ class OaiCiTest(): for job in multi_jobs: job.join() if self.flexranCtrlInstalled and self.flexranCtrlStarted: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('cd /opt/flexran_rtc', '\$', 5) SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) @@ -1747,13 +1747,13 @@ class OaiCiTest(): # Launch ping on the EPC side (true for ltebox and old open-air-cn) # But for OAI-Rel14-CUPS, we launch from python executor launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): launchFromEpc = False ping_time = re.findall("-c (\d+)",str(self.ping_args)) if launchFromEpc: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) SSH.command('cd scripts', '\$', 5) ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) else: @@ -1762,9 +1762,9 @@ class OaiCiTest(): logging.debug(cmd) ret = subprocess.run(cmd, shell=True) ping_status = ret.returncode - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cat ' + EPC.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' @@ -1923,7 +1923,7 @@ class OaiCiTest(): else: copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') if (copyin_res == 0): - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'ping_' + self.testCase_id + '.log', EPC.EPCSourceCodePath + '/scripts') except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1932,7 +1932,7 @@ class OaiCiTest(): if result is not None: self.PingNoS1() return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') check_eNB = True @@ -2276,7 +2276,7 @@ class OaiCiTest(): # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): launchFromEpc = False cmd = 'hostname -I' ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') @@ -2284,13 +2284,13 @@ class OaiCiTest(): EPC_Iperf_UE_IPAddress = ret.stdout.strip() port = 5001 + idx if launchFromEpc: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if udpIperf: - SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.EPCUserName, 5) else: - SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) + SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.EPCUserName, 5) SSH.close() else: if self.ueIperfVersion == self.dummyIperfVersion: @@ -2313,7 +2313,7 @@ class OaiCiTest(): SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) else: SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) iperf_time = self.Iperf_ComputeTime() time.sleep(0.5) @@ -2347,27 +2347,27 @@ class OaiCiTest(): # Kill iperf server on EPC side if launchFromEpc: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('killall --signal SIGKILL iperf', EPC.EPCUserName, 5) SSH.close() else: cmd = 'killall --signal SIGKILL iperf' logging.debug(cmd) subprocess.run(cmd, shell=True) time.sleep(1) - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') # in case of failure, retrieve server log if (clientStatus == -1) or (clientStatus == -2): if launchFromEpc: time.sleep(1) if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - SSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyin(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, EPC.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI-UE if (device_id == 'OAI-UE'): SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): try: @@ -2381,8 +2381,8 @@ class OaiCiTest(): if (device_id != 'OAI-UE'): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - SSH.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('if [ ! -d ' + EPC.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) # Checking if iperf / iperf3 are installed if self.ADBCentralized: SSH.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) @@ -2441,7 +2441,7 @@ class OaiCiTest(): SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) else: SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) if self.ADBCentralized: if (useIperf3): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) @@ -2463,11 +2463,11 @@ class OaiCiTest(): # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn # But for OAI-Rel14-CUPS, we launch from python executor launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): + if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): launchFromEpc = False if launchFromEpc: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) iperf_time = self.Iperf_ComputeTime() time.sleep(0.5) @@ -2502,9 +2502,9 @@ class OaiCiTest(): logging.debug(cmd) ret = subprocess.run(cmd, shell=True) iperf_status = ret.returncode - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cat ' + EPC.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if iperf_status < 0: if launchFromEpc: SSH.close() @@ -2541,7 +2541,7 @@ class OaiCiTest(): if (device_id == 'OAI-UE'): SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') else: - SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) @@ -2549,10 +2549,10 @@ class OaiCiTest(): if (device_id == 'OAI-UE'): if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): if not launchFromEpc: - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') else: SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') except: os.kill(os.getppid(),signal.SIGUSR1) @@ -2636,10 +2636,10 @@ class OaiCiTest(): if (clientStatus == -1): copyin_res = SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', EPC.EPCSourceCodePath + '/scripts') copyin_res = SSH.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): - SSH.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', EPC.EPCSourceCodePath + '/scripts') iperf_noperf = False if status_queue.empty(): iperf_status = False @@ -2670,7 +2670,7 @@ class OaiCiTest(): if result is not None: self.IperfNoS1() return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') check_eNB = True @@ -2747,15 +2747,15 @@ class OaiCiTest(): # in noS1 config, no need to check status from EPC result = re.search('noS1', str(self.Initialize_eNB_args)) if result is None: - p = Process(target = CiTestObj.CheckHSSProcess, args = (status_queue,)) + p = Process(target = EPC.CheckHSSProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) - p = Process(target = CiTestObj.CheckMMEProcess, args = (status_queue,)) + p = Process(target = EPC.CheckMMEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) - p = Process(target = CiTestObj.CheckSPGWProcess, args = (status_queue,)) + p = Process(target = EPC.CheckSPGWProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2870,7 +2870,7 @@ class OaiCiTest(): def CheckHSSProcess(self, status_queue): try: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): result = re.search('oai_hss -j', SSH.getBefore()) @@ -2891,7 +2891,7 @@ class OaiCiTest(): def CheckMMEProcess(self, status_queue): try: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): result = re.search('mme -c', SSH.getBefore()) @@ -2912,7 +2912,7 @@ class OaiCiTest(): def CheckSPGWProcess(self, status_queue): try: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) result = re.search('spgwu -c ', SSH.getBefore()) @@ -3399,14 +3399,14 @@ class OaiCiTest(): # If tracer options is on, stopping tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) - if self.EPC_PcapFileName != '': - SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - SSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') - SSH.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') + if EPC.EPC_PcapFileName != '': + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.copyin(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, '/tmp/' + EPC.EPC_PcapFileName , '.') + SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') SSH.close() logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') SSH.open(lIpAddr, lUserName, lPassWord) @@ -3456,7 +3456,7 @@ class OaiCiTest(): self.eNBstatuses[int(self.eNB_instance)] = -1 def TerminateHSS(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) time.sleep(2) @@ -3484,7 +3484,7 @@ class OaiCiTest(): self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateMME(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) time.sleep(2) @@ -3502,7 +3502,7 @@ class OaiCiTest(): self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateSPGW(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) time.sleep(2) @@ -3515,7 +3515,7 @@ class OaiCiTest(): result = re.search('-w ', SSH.getBefore()) if result is not None: SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) + SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + EPC.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) elif re.match('OAI', self.EPCType, re.IGNORECASE): SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) time.sleep(2) @@ -3534,13 +3534,13 @@ class OaiCiTest(): def TerminateFlexranCtrl(self): if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': Usage() sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) time.sleep(1) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) + SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) time.sleep(1) SSH.close() self.flexranCtrlStarted = False @@ -3667,7 +3667,7 @@ class OaiCiTest(): self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) def X2_Status(self, idx, fileName): - cmd = "curl --silent http://" + self.EPCIPAddress + ":9999/stats | jq '.' > " + fileName + cmd = "curl --silent http://" + EPC.EPCIPAddress + ":9999/stats | jq '.' > " + fileName message = cmd + '\n' logging.debug(cmd) subprocess.run(cmd, shell=True) @@ -3731,7 +3731,7 @@ class OaiCiTest(): eNB_cnt = self.x2NbENBs cnt = 0 while cnt < eNB_cnt: - cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1" + cmd = "curl -XPOST http://" + EPC.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1" logging.debug(cmd) fullMessage += cmd + '\n' subprocess.run(cmd, shell=True) @@ -3745,7 +3745,7 @@ class OaiCiTest(): while cnt < eNB_cnt: ueIdx = 0 while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]): - cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1]) + cmd = "curl -XPOST http://" + EPC.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1]) logging.debug(cmd) fullMessage += cmd + '\n' subprocess.run(cmd, shell=True) @@ -3806,8 +3806,8 @@ class OaiCiTest(): SSH.close() def LogCollectPing(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) SSH.command('cd scripts', '\$', 5) SSH.command('rm -f ping.log.zip', '\$', 5) SSH.command('zip ping.log.zip ping*.log', '\$', 60) @@ -3815,8 +3815,8 @@ class OaiCiTest(): SSH.close() def LogCollectIperf(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) SSH.command('cd scripts', '\$', 5) SSH.command('rm -f iperf.log.zip', '\$', 5) SSH.command('zip iperf.log.zip iperf*.log', '\$', 60) @@ -3824,7 +3824,7 @@ class OaiCiTest(): SSH.close() def LogCollectHSS(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) SSH.command('rm -f hss.log.zip', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): @@ -3841,7 +3841,7 @@ class OaiCiTest(): SSH.close() def LogCollectMME(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) SSH.command('rm -f mme.log.zip', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): @@ -3855,7 +3855,7 @@ class OaiCiTest(): SSH.close() def LogCollectSPGW(self): - SSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) SSH.command('rm -f spgw.log.zip', '\$', 5) if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): @@ -4451,8 +4451,14 @@ def receive_signal(signum, frame): #----------------------------------------------------------- mode = '' CiTestObj = OaiCiTest() + from sshconnection import * +from epc import * +from helpreadme import * SSH = SSHConnection() +EPC = EPCManagement() +#HELP = HelpReadme() +#HELP.GenericHelp() argvs = sys.argv argc = len(argvs) @@ -4540,23 +4546,23 @@ while len(argvs) > 1: CiTestObj.eNB2SourceCodePath = matchReg.group(1) elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.EPCIPAddress = matchReg.group(1) + EPC.EPCIPAddress = matchReg.group(1) elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) CiTestObj.EPCBranch = matchReg.group(1) elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.EPCUserName = matchReg.group(1) + EPC.EPCUserName = matchReg.group(1) elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.EPCPassword = matchReg.group(1) + EPC.EPCPassword = matchReg.group(1) elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.EPCSourceCodePath = matchReg.group(1) + EPC.EPCSourceCodePath = matchReg.group(1) elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): - CiTestObj.EPCType = matchReg.group(1) + EPC.EPCType = matchReg.group(1) else: sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): @@ -4623,17 +4629,17 @@ elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): signal.signal(signal.SIGUSR1, receive_signal) CiTestObj.TerminateOAIUE() elif re.match('^TerminateHSS$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') CiTestObj.TerminateHSS() elif re.match('^TerminateMME$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') CiTestObj.TerminateMME() elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') CiTestObj.TerminateSPGW() @@ -4648,27 +4654,27 @@ elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): sys.exit('Insufficient Parameter') CiTestObj.LogCollecteNB() elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - CiTestObj.LogCollectHSS() + EPC.LogCollectHSS() elif re.match('^LogCollectMME$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - CiTestObj.LogCollectMME() + EPC.LogCollectMME() elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - CiTestObj.LogCollectSPGW() + EPC.LogCollectSPGW() elif re.match('^LogCollectPing$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') CiTestObj.LogCollectPing() elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): - if CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCSourceCodePath == '': + if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': Usage() sys.exit('Insufficient Parameter') CiTestObj.LogCollectIperf() @@ -4701,13 +4707,13 @@ elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): CiTestObj.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): - if CiTestObj.eNBIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '' or CiTestObj.EPCIPAddress == '' or CiTestObj.EPCUserName == '' or CiTestObj.EPCPassword == '' or CiTestObj.EPCType == '' or CiTestObj.EPCSourceCodePath == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': + if CiTestObj.eNBIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '' or EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') - if (CiTestObj.EPCIPAddress != '') and (CiTestObj.EPCIPAddress != 'none'): - SSH.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") - SSH.copyout(CiTestObj.EPCIPAddress, CiTestObj.EPCUserName, CiTestObj.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") + if (EPC.EPCIPAddress != '') and (EPC.EPCIPAddress != 'none'): + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") + SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") else: if CiTestObj.UEIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': Usage() @@ -4755,7 +4761,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re else: logging.debug('ERROR: requested test is invalidly formatted: ' + test) sys.exit(1) - if (CiTestObj.EPCIPAddress != '') and (CiTestObj.EPCIPAddress != 'none'): + if (EPC.EPCIPAddress != '') and (EPC.EPCIPAddress != 'none'): CiTestObj.CheckFlexranCtrlInstallation() #get the list of tests to be done @@ -4843,17 +4849,17 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'Reboot_UE': CiTestObj.RebootUE() elif action == 'Initialize_HSS': - CiTestObj.InitializeHSS() + EPC.InitializeHSS() elif action == 'Terminate_HSS': - CiTestObj.TerminateHSS() + EPC.TerminateHSS() elif action == 'Initialize_MME': - CiTestObj.InitializeMME() + EPC.InitializeMME() elif action == 'Terminate_MME': - CiTestObj.TerminateMME() + EPC.TerminateMME() elif action == 'Initialize_SPGW': - CiTestObj.InitializeSPGW() + EPC.InitializeSPGW() elif action == 'Terminate_SPGW': - CiTestObj.TerminateSPGW() + EPC.TerminateSPGW() elif action == 'Initialize_FlexranCtrl': CiTestObj.InitializeFlexranCtrl() elif action == 'Terminate_FlexranCtrl': From 3f546cb48acfd9406ec7924d832e6d3322bb7d81 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Thu, 23 Jan 2020 10:41:49 +0100 Subject: [PATCH 082/175] minor changes to epc.py, helpreadme.py, main.py to complete the export of EPC functions from main --- ci-scripts/epc.py | 6 +++--- ci-scripts/helpreadme.py | 4 ++-- ci-scripts/main.py | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 3ebb3cfb04..258cd2e09b 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -30,7 +30,7 @@ class EPCManagement(): def InitializeHSS(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - HELP.GenericHelp() + HELP.GenericHelp(Version) HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) sys.exit('Insufficient EPC Parameters') #mySSH = SSH() @@ -68,7 +68,7 @@ class EPCManagement(): def InitializeMME(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - HELP.GenericHelp() + HELP.GenericHelp(Version) HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) sys.exit('Insufficient EPC Parameters') mySSH = SSH.SSHConnection() @@ -101,7 +101,7 @@ class EPCManagement(): def InitializeSPGW(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - HELP.GenericHelp() + HELP.GenericHelp(Version) HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) sys.exit('Insufficient EPC Parameters') mySSH = SSH.SSHConnection() diff --git a/ci-scripts/helpreadme.py b/ci-scripts/helpreadme.py index ed4fc5ecec..fba2c40698 100644 --- a/ci-scripts/helpreadme.py +++ b/ci-scripts/helpreadme.py @@ -2,9 +2,9 @@ # Functions Declaration #----------------------------------------------------------- -def GenericHelp(): +def GenericHelp(vers): print('----------------------------------------------------------------------------------------------------------------------') - print('main.py Ver: 0.1') + print('main.py Ver: ' + vers) print('----------------------------------------------------------------------------------------------------------------------') print('Usage: python main.py [options]') print(' --help Show this help.') diff --git a/ci-scripts/main.py b/ci-scripts/main.py index fa3a5ce7f7..9740017542 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -486,7 +486,7 @@ class OaiCiTest(): self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') self.CreateHtmlTabFooter(False) sys.exit(1) - + """ def InitializeHSS(self): if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': Usage() @@ -581,7 +581,7 @@ class OaiCiTest(): logging.error('This option should not occur!') SSH.close() self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - + """ def CheckFlexranCtrlInstallation(self): if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': return @@ -2934,7 +2934,7 @@ class OaiCiTest(): SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) - + """ def CheckHSSProcess(self, status_queue): try: SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) @@ -2999,7 +2999,7 @@ class OaiCiTest(): SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) - + """ def AnalyzeLogFile_eNB(self, eNBlogFile): if (not os.path.isfile('./' + eNBlogFile)): return -1 @@ -3603,7 +3603,7 @@ class OaiCiTest(): self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBstatuses[int(self.eNB_instance)] = -1 - + """ def TerminateHSS(self): SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): @@ -3679,7 +3679,7 @@ class OaiCiTest(): logging.error('This should not happen!') SSH.close() self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - + """ def TerminateFlexranCtrl(self): if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: return @@ -3975,7 +3975,7 @@ class OaiCiTest(): SSH.command('zip iperf.log.zip iperf*.log', '\$', 60) SSH.command('rm iperf*.log', '\$', 5) SSH.close() - + """ def LogCollectHSS(self): SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) @@ -4020,7 +4020,7 @@ class OaiCiTest(): else: logging.error('This option should not occur!') SSH.close() - + """ def LogCollectOAIUE(self): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('cd ' + self.UESourceCodePath, '\$', 5) From 92811568728f8c1c1708dc53ac554bea35489e57 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 27 Jan 2020 11:45:03 +0100 Subject: [PATCH 083/175] rework of the help from embedded Usage() function to external helpreadme.py file --- ci-scripts/epc.py | 25 ++ ci-scripts/helpreadme.py | 2 +- ci-scripts/main.py | 612 ++++++++++----------------------------- 3 files changed, 171 insertions(+), 468 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 258cd2e09b..58a0958d4b 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -28,6 +28,31 @@ class EPCManagement(): self.EPCType = '' self.EPC_PcapFileName = '' + def SetIPAddress(self, ipaddress): + self.EPCIPAddress = ipaddress + def GetIPAddress(self): + return self.EPCIPAddress + def SetUserName(self, username): + self.EPCUserName = username + def GetUserName(self): + return self.EPCUserName + def SetPassword(self, password): + self.EPCPassword = password + def GetPassword(self): + return self.EPCPassword + def SetSourceCodePath(self, sourcecodepath): + self.EPCSourceCodePath = sourcecodepath + def GetSourceCodePath(self): + return self.EPCSourceCodePath + def SetType(self, typ): + self.EPCType = typ + def GetType(self): + return self.EPCType + def Set_PcapFileName(self, pcapfn): + self.PcapFileName = pcapfn + def Get_PcapFileName(self): + return self.PcapFileName + def InitializeHSS(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': HELP.GenericHelp(Version) diff --git a/ci-scripts/helpreadme.py b/ci-scripts/helpreadme.py index fba2c40698..294454e270 100644 --- a/ci-scripts/helpreadme.py +++ b/ci-scripts/helpreadme.py @@ -6,7 +6,7 @@ def GenericHelp(vers): print('----------------------------------------------------------------------------------------------------------------------') print('main.py Ver: ' + vers) print('----------------------------------------------------------------------------------------------------------------------') - print('Usage: python main.py [options]') + print('python main.py [options]') print(' --help Show this help.') print(' --mode=[Mode]') print(' TesteNB') diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 9740017542..c9da55041c 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -1,4 +1,4 @@ -#/* + # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -195,7 +195,7 @@ class OaiCiTest(): def BuildeNB(self): if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress @@ -213,7 +213,7 @@ class OaiCiTest(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(lIpAddr, lUserName, lPassWord) # Check if we build an 5G-NR gNB or an LTE eNB @@ -314,7 +314,7 @@ class OaiCiTest(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(lIpAddr, lUserName, lPassWord) count = 40 @@ -386,7 +386,7 @@ class OaiCiTest(): def BuildOAIUE(self): if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) result = re.search('--nrUE', self.Build_OAI_UE_args) @@ -486,106 +486,11 @@ class OaiCiTest(): self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') self.CreateHtmlTabFooter(False) sys.exit(1) - """ - def InitializeHSS(self): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') - SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) - logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') - EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) - SSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + EPC.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.EPCUserName, 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) - SSH.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) - SSH.command('chmod 755 ./my-hss.sh', '\$', 5) - SSH.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + EPC.EPCSourceCodePath + '/scripts -o ' + EPC.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) - elif re.match('OAI', EPC.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC HSS') - SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) - SSH.command('source oaienv', '\$', 5) - SSH.command('cd scripts', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) - elif re.match('ltebox', EPC.EPCType, re.IGNORECASE): - logging.debug('Using the ltebox simulated HSS') - SSH.command('if [ -d ' + EPC.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + EPC.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - SSH.command('mkdir -p ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) - SSH.command('cd /opt/hss_sim0609', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) - else: - logging.error('This option should not occur!') - SSH.close() - self.CreateHtmlTestRow(EPC.EPCType, 'OK', ALL_PROCESSES_OK) - - def InitializeMME(self): - if self.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 MME') - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) - SSH.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) - SSH.command('chmod 755 ./my-mme.sh', '\$', 5) - SSH.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) - SSH.command('source oaienv', '\$', 5) - SSH.command('cd scripts', '\$', 5) - SSH.command('stdbuf -o0 hostname', '\$', 5) - result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') - sys.exit(1) - host_name = result.group('host_name') - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cd /opt/ltebox/tools', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) - else: - logging.error('This option should not occur!') - SSH.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def InitializeSPGW(self): - if self.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or EPC.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) - SSH.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) - SSH.command('chmod 755 ./my-spgwc.sh', '\$', 5) - SSH.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) - time.sleep(5) - SSH.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) - SSH.command('chmod 755 ./my-spgwu.sh', '\$', 5) - SSH.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) - SSH.command('source oaienv', '\$', 5) - SSH.command('cd scripts', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cd /opt/ltebox/tools', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) - else: - logging.error('This option should not occur!') - SSH.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - """ + def CheckFlexranCtrlInstallation(self): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': return - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) if result is not None: @@ -596,15 +501,15 @@ class OaiCiTest(): def InitializeFlexranCtrl(self): if self.flexranCtrlInstalled == False: return - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('cd /opt/flexran_rtc', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f log/*.log', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) SSH.command('ps -aux | grep --color=never rt_controller', '\$', 5) result = re.search('rt_controller -c ', SSH.getBefore()) if result is not None: @@ -630,7 +535,7 @@ class OaiCiTest(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = False check_OAI_UE = False @@ -642,15 +547,15 @@ class OaiCiTest(): # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', SSH.getBefore()) if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') EPC.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S rm -f /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.EPCUserName, 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) SSH.close() SSH.open(lIpAddr, lUserName, lPassWord) SSH.command('cd ' + lSourcePath, '\$', 5) @@ -689,7 +594,7 @@ class OaiCiTest(): SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) # Make a copy and adapt to EPC / eNB IP addresses SSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.GetIPAddress() + '/\' ' + ci_full_config_file, '\$', 2); SSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); SSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); @@ -742,16 +647,16 @@ class OaiCiTest(): # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) if EPC.EPC_PcapFileName != '': time.sleep(0.5) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) SSH.close() time.sleep(1) if EPC.EPC_PcapFileName != '': - copyin_res = SSH.copyin(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, '/tmp/' + EPC.EPC_PcapFileName , '.') + copyin_res = SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') if (copyin_res == 0): SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') self.prematureExit = True @@ -840,7 +745,7 @@ class OaiCiTest(): def InitializeUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') multi_jobs = [] i = 0 @@ -856,7 +761,7 @@ class OaiCiTest(): def InitializeOAIUE(self): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') if self.air_interface == 'lte': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) @@ -1045,7 +950,7 @@ class OaiCiTest(): def InitializeCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') self.picocom_closure = True SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -1079,7 +984,7 @@ class OaiCiTest(): def TerminateCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') self.picocom_closure = True SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -1100,7 +1005,7 @@ class OaiCiTest(): def AttachCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') self.picocom_closure = True SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -1173,8 +1078,8 @@ class OaiCiTest(): self.AutoTerminateUEandeNB() def PingCatM(self): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -1186,10 +1091,10 @@ class OaiCiTest(): try: statusQueue = SimpleQueue() lock = Lock() - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) SSH.command('cd scripts', '\$', 5) - if re.match('OAI', EPC.EPCType, re.IGNORECASE): + if re.match('OAI', EPC.GetType(), re.IGNORECASE): logging.debug('Using the OAI EPC HSS: not implemented yet') self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.CreateHtmlTabFooter(False) @@ -1340,7 +1245,7 @@ class OaiCiTest(): def AttachUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -1414,7 +1319,7 @@ class OaiCiTest(): def DetachUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -1485,7 +1390,7 @@ class OaiCiTest(): def RebootUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -1519,7 +1424,7 @@ class OaiCiTest(): def DataDisableUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') multi_jobs = [] i = 0 @@ -1548,7 +1453,7 @@ class OaiCiTest(): def DataEnableUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') multi_jobs = [] i = 0 @@ -1564,7 +1469,7 @@ class OaiCiTest(): def GetAllUEDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: @@ -1608,7 +1513,7 @@ class OaiCiTest(): def GetAllCatMDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: @@ -1680,7 +1585,7 @@ class OaiCiTest(): def CheckStatusUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -1702,7 +1607,7 @@ class OaiCiTest(): for job in multi_jobs: job.join() if self.flexranCtrlInstalled and self.flexranCtrlStarted: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('cd /opt/flexran_rtc', '\$', 5) SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) @@ -1744,13 +1649,13 @@ class OaiCiTest(): def GetAllUEIPAddresses(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') ue_ip_status = 0 self.UEIPAddresses = [] if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('ifconfig oaitun_ue1', '\$', 4) @@ -1814,13 +1719,13 @@ class OaiCiTest(): # Launch ping on the EPC side (true for ltebox and old open-air-cn) # But for OAI-Rel14-CUPS, we launch from python executor launchFromEpc = True - if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): + if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): launchFromEpc = False ping_time = re.findall("-c (\d+)",str(self.ping_args)) if launchFromEpc: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) SSH.command('cd scripts', '\$', 5) ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) else: @@ -1829,9 +1734,9 @@ class OaiCiTest(): logging.debug(cmd) ret = subprocess.run(cmd, shell=True) ping_status = ret.returncode - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cat ' + EPC.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cat ' + EPC.GetSourceCodePath() + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' @@ -1912,11 +1817,11 @@ class OaiCiTest(): ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) if ping_from_eNB is not None: if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') else: if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') try: if ping_from_eNB is not None: @@ -1989,7 +1894,7 @@ class OaiCiTest(): else: copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') if (copyin_res == 0): - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'ping_' + self.testCase_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'ping_' + self.testCase_id + '.log', EPC.GetSourceCodePath() + '/scripts') except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1998,8 +1903,8 @@ class OaiCiTest(): if result is not None: self.PingNoS1() return - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): @@ -2342,7 +2247,7 @@ class OaiCiTest(): # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address launchFromEpc = True - if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): + if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): launchFromEpc = False cmd = 'hostname -I' ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') @@ -2350,13 +2255,13 @@ class OaiCiTest(): EPC_Iperf_UE_IPAddress = ret.stdout.strip() port = 5001 + idx if launchFromEpc: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if udpIperf: - SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.EPCUserName, 5) + SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.GetUserName(), 5) else: - SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.EPCUserName, 5) + SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.GetUserName(), 5) SSH.close() else: if self.ueIperfVersion == self.dummyIperfVersion: @@ -2379,7 +2284,7 @@ class OaiCiTest(): SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) else: SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) iperf_time = self.Iperf_ComputeTime() time.sleep(0.5) @@ -2413,27 +2318,27 @@ class OaiCiTest(): # Kill iperf server on EPC side if launchFromEpc: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('killall --signal SIGKILL iperf', EPC.EPCUserName, 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('killall --signal SIGKILL iperf', EPC.GetUserName(), 5) SSH.close() else: cmd = 'killall --signal SIGKILL iperf' logging.debug(cmd) subprocess.run(cmd, shell=True) time.sleep(1) - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') # in case of failure, retrieve server log if (clientStatus == -1) or (clientStatus == -2): if launchFromEpc: time.sleep(1) if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - SSH.copyin(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, EPC.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI-UE if (device_id == 'OAI-UE'): SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): try: @@ -2447,8 +2352,8 @@ class OaiCiTest(): if (device_id != 'OAI-UE'): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - SSH.command('if [ ! -d ' + EPC.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) # Checking if iperf / iperf3 are installed if self.ADBCentralized: SSH.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) @@ -2507,7 +2412,7 @@ class OaiCiTest(): SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) else: SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) if self.ADBCentralized: if (useIperf3): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) @@ -2529,11 +2434,11 @@ class OaiCiTest(): # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn # But for OAI-Rel14-CUPS, we launch from python executor launchFromEpc = True - if re.match('OAI-Rel14-CUPS', EPC.EPCType, re.IGNORECASE): + if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): launchFromEpc = False if launchFromEpc: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath + '/scripts', '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) iperf_time = self.Iperf_ComputeTime() time.sleep(0.5) @@ -2568,9 +2473,9 @@ class OaiCiTest(): logging.debug(cmd) ret = subprocess.run(cmd, shell=True) iperf_status = ret.returncode - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cat ' + EPC.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cat ' + EPC.GetSourceCodePath() + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) if iperf_status < 0: if launchFromEpc: SSH.close() @@ -2607,7 +2512,7 @@ class OaiCiTest(): if (device_id == 'OAI-UE'): SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') else: - SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) @@ -2615,16 +2520,16 @@ class OaiCiTest(): if (device_id == 'OAI-UE'): if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): if not launchFromEpc: - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') else: SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') except: os.kill(os.getppid(),signal.SIGUSR1) def IperfNoS1(self): if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = True @@ -2702,10 +2607,10 @@ class OaiCiTest(): if (clientStatus == -1): copyin_res = SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_OAI-UE.log', EPC.GetSourceCodePath() + '/scripts') copyin_res = SSH.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') if (copyin_res == 0): - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', EPC.EPCSourceCodePath + '/scripts') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_OAI-UE.log', EPC.GetSourceCodePath() + '/scripts') iperf_noperf = False if status_queue.empty(): iperf_status = False @@ -2736,8 +2641,8 @@ class OaiCiTest(): if result is not None: self.IperfNoS1() return - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): @@ -2934,72 +2839,7 @@ class OaiCiTest(): SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) - """ - def CheckHSSProcess(self, status_queue): - try: - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('oai_hss -j', SSH.getBefore()) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('hss_sim s6as diam_hss', SSH.getBefore()) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m HSS Process Not Found! \u001B[0m') - status_queue.put(HSS_PROCESS_FAILED) - else: - status_queue.put(HSS_PROCESS_OK) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckMMEProcess(self, status_queue): - try: - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('mme -c', SSH.getBefore()) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('mme', SSH.getBefore()) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m MME Process Not Found! \u001B[0m') - status_queue.put(MME_PROCESS_FAILED) - else: - status_queue.put(MME_PROCESS_OK) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckSPGWProcess(self, status_queue): - try: - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('spgwu -c ', SSH.getBefore()) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - SSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) - result = re.search('xGw', SSH.getBefore()) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m SPGW Process Not Found! \u001B[0m') - status_queue.put(SPGW_PROCESS_FAILED) - else: - status_queue.put(SPGW_PROCESS_OK) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - """ + def AnalyzeLogFile_eNB(self, eNBlogFile): if (not os.path.isfile('./' + eNBlogFile)): return -1 @@ -3524,7 +3364,7 @@ class OaiCiTest(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(lIpAddr, lUserName, lPassWord) SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) @@ -3548,13 +3388,13 @@ class OaiCiTest(): # If tracer options is on, stopping tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) if EPC.EPC_PcapFileName != '': - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.copyin(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, '/tmp/' + EPC.EPC_PcapFileName , '.') + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') SSH.close() logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') @@ -3603,93 +3443,17 @@ class OaiCiTest(): self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBstatuses[int(self.eNB_instance)] = -1 - """ - def TerminateHSS(self): - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) - time.sleep(2) - SSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('oai_hss -j', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) - SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) - time.sleep(2) - SSH.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) - SSH.command('cd scripts', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) - time.sleep(1) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) - else: - logging.error('This should not happen!') - SSH.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateMME(self): - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) - time.sleep(2) - SSH.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) - result = re.search('mme -c', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) - SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cd /opt/ltebox/tools', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) - else: - logging.error('This should not happen!') - SSH.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateSPGW(self): - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) - time.sleep(2) - SSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('spgwc -c |spgwu -c ', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) - SSH.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) - SSH.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) - result = re.search('-w ', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + EPC.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) - time.sleep(2) - SSH.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cd /opt/ltebox/tools', '\$', 5) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) - else: - logging.error('This should not happen!') - SSH.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - """ + def TerminateFlexranCtrl(self): if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: return - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) time.sleep(1) - SSH.command('echo ' + EPC.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) time.sleep(1) SSH.close() self.flexranCtrlStarted = False @@ -3820,7 +3584,7 @@ class OaiCiTest(): self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) def X2_Status(self, idx, fileName): - cmd = "curl --silent http://" + EPC.EPCIPAddress + ":9999/stats | jq '.' > " + fileName + cmd = "curl --silent http://" + EPC.GetIPAddress() + ":9999/stats | jq '.' > " + fileName message = cmd + '\n' logging.debug(cmd) subprocess.run(cmd, shell=True) @@ -3884,7 +3648,7 @@ class OaiCiTest(): eNB_cnt = self.x2NbENBs cnt = 0 while cnt < eNB_cnt: - cmd = "curl -XPOST http://" + EPC.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1" + cmd = "curl -XPOST http://" + EPC.GetIPAddress() + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1" logging.debug(cmd) fullMessage += cmd + '\n' subprocess.run(cmd, shell=True) @@ -3898,7 +3662,7 @@ class OaiCiTest(): while cnt < eNB_cnt: ueIdx = 0 while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]): - cmd = "curl -XPOST http://" + EPC.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1]) + cmd = "curl -XPOST http://" + EPC.GetIPAddress() + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1]) logging.debug(cmd) fullMessage += cmd + '\n' subprocess.run(cmd, shell=True) @@ -3959,8 +3723,8 @@ class OaiCiTest(): SSH.close() def LogCollectPing(self): - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) SSH.command('cd scripts', '\$', 5) SSH.command('rm -f ping.log.zip', '\$', 5) SSH.command('zip ping.log.zip ping*.log', '\$', 60) @@ -3968,59 +3732,14 @@ class OaiCiTest(): SSH.close() def LogCollectIperf(self): - SSH.open(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + EPC.EPCSourceCodePath, '\$', 5) + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) SSH.command('cd scripts', '\$', 5) SSH.command('rm -f iperf.log.zip', '\$', 5) SSH.command('zip iperf.log.zip iperf*.log', '\$', 60) SSH.command('rm iperf*.log', '\$', 5) SSH.close() - """ - def LogCollectHSS(self): - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - SSH.command('rm -f hss.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('zip hss.log.zip hss*.log', '\$', 60) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) - SSH.command('zip hss.log.zip hss.log', '\$', 60) - else: - logging.error('This option should not occur!') - SSH.close() - - def LogCollectMME(self): - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - SSH.command('rm -f mme.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('zip mme.log.zip mme*.log', '\$', 60) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) - SSH.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) - else: - logging.error('This option should not occur!') - SSH.close() - - def LogCollectSPGW(self): - SSH.open(self.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword) - SSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - SSH.command('rm -f spgw.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - SSH.command('zip spgw.log.zip spgw*.log', '\$', 60) - SSH.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - SSH.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) - SSH.command('zip spgw.log.zip xGwLog.0', '\$', 60) - else: - logging.error('This option should not occur!') - SSH.close() - """ + def LogCollectOAIUE(self): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('cd ' + self.UESourceCodePath, '\$', 5) @@ -4448,50 +4167,6 @@ class OaiCiTest(): logging.debug('\u001B[1m' + self.desc + '\u001B[0m') logging.debug('\u001B[1m----------------------------------------\u001B[0m') -#----------------------------------------------------------- -# Usage() -#----------------------------------------------------------- -def Usage(): - print('----------------------------------------------------------------------------------------------------------------------') - print('main.py Ver:' + Version) - print('----------------------------------------------------------------------------------------------------------------------') - print('Usage: python main.py [options]') - print(' --help Show this help.') - print(' --mode=[Mode]') - print(' TesteNB') - print(' InitiateHtml, FinalizeHtml') - print(' TerminateeNB, TerminateUE, TerminateHSS, TerminateMME, TerminateSPGW') - print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf') - print('---------------------------------------------------------------------------------------------------- Git Options --') - print(' --ranRepository=[OAI RAN Repository URL]') - print(' --ranBranch=[OAI RAN Repository Branch]') - print(' --ranCommitID=[OAI RAN Repository Commit SHA-1]') - print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)]') - print(' --ranTargetBranch=[Target Branch in case of a Merge Request]') - print('--------------------------------------------------------------------------------------------- eNB Server Options --') - print(' --eNBIPAddress=[eNB\'s IP Address]') - print(' --eNBUserName=[eNB\'s Login User Name]') - print(' --eNBPassword=[eNB\'s Login Password]') - print(' --eNBSourceCodePath=[eNB\'s Source Code Path]') - print('------------------------------------------------------------------------------------------ OAI UE Server Options --') - print(' --UEIPAddress=[UE\'s IP Address]') - print(' --UEUserName=[UE\'s Login User Name]') - print(' --UEPassword=[UE\'s Login Password]') - print(' --UESourceCodePath=[UE\'s Source Code Path]') - print('--------------------------------------------------------------------------------------------- EPC Server Options --') - print(' --EPCIPAddress=[EPC\'s IP Address]') - print(' --EPCUserName=[EPC\'s Login User Name]') - print(' --EPCPassword=[EPC\'s Login Password]') - print(' --EPCSourceCodePath=[EPC\'s Source Code Path]') - print(' --EPCType=[EPC\'s Type: OAI or ltebox or OAI-Rel14-CUPS]') - print('--------------------------------------------------------------------------------------------- ABD Server Options --') - print(' --ADBIPAddress=[ADB\'s IP Address]') - print(' --ADBUserName=[ADB\'s Login User Name]') - print(' --ADBPassword=[ADB\'s Login Password]') - print('----------------------------------------------------------------------------------------------------------------------') - print(' --XMLTestFile=[XML Test File to be run]') - print('----------------------------------------------------------------------------------------------------------------------') - def CheckClassValidity(action,id): if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) @@ -4672,7 +4347,7 @@ cwd = os.getcwd() while len(argvs) > 1: myArgv = argvs.pop(1) # 0th is this file's name if re.match('^\-\-help$', myArgv, re.IGNORECASE): - Usage() + GenericHelp(Version) sys.exit(0) elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) @@ -4751,23 +4426,23 @@ while len(argvs) > 1: CiTestObj.eNB2SourceCodePath = matchReg.group(1) elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) - EPC.EPCIPAddress = matchReg.group(1) + EPC.SetIPAddress(matchReg.group(1)) elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) CiTestObj.EPCBranch = matchReg.group(1) elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) - EPC.EPCUserName = matchReg.group(1) + EPC.SetUserName(matchReg.group(1)) elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) - EPC.EPCPassword = matchReg.group(1) + EPC.SetPassword(matchReg.group(1)) elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - EPC.EPCSourceCodePath = matchReg.group(1) + EPC.SetSourceCodePath(matchReg.group(1)) elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): - EPC.EPCType = matchReg.group(1) + EPC.SetType(matchReg.group(1)) else: sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): @@ -4810,12 +4485,12 @@ while len(argvs) > 1: if ((finalStatus == 'true') or (finalStatus == 'True')): CiTestObj.finalStatus = True else: - Usage() + GenericHelp(Version) sys.exit('Invalid Parameter: ' + myArgv) if re.match('^TerminateeNB$', mode, re.IGNORECASE): if CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.eNB_serverId = '0' CiTestObj.eNB_instance = '0' @@ -4823,74 +4498,74 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE): CiTestObj.TerminateeNB() elif re.match('^TerminateUE$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') signal.signal(signal.SIGUSR1, receive_signal) CiTestObj.TerminateUE() elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') signal.signal(signal.SIGUSR1, receive_signal) CiTestObj.TerminateOAIUE() elif re.match('^TerminateHSS$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.TerminateHSS() elif re.match('^TerminateMME$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.TerminateMME() elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.TerminateSPGW() elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): if (CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectBuild() elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): if CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollecteNB() elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') EPC.LogCollectHSS() elif re.match('^LogCollectMME$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') EPC.LogCollectMME() elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') EPC.LogCollectSPGW() elif re.match('^LogCollectPing$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectPing() elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): - if EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCSourceCodePath == '': - Usage() + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectIperf() elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectOAIUE() elif re.match('^InitiateHtml$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): - Usage() + GenericHelp(Version) sys.exit('Insufficient Parameter') count = 0 foundCount = 0 @@ -4915,16 +4590,19 @@ elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): CiTestObj.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): - if CiTestObj.eNBIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '' or EPC.EPCIPAddress == '' or EPC.EPCUserName == '' or EPC.EPCPassword == '' or EPC.EPCType == '' or EPC.EPCSourceCodePath == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': - Usage() + if CiTestObj.eNBIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': + GenericHelp(Version) + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or EPC.GetType() == '': + EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) + # Gabriele: other if conditions relevant to eNB etc. to be added sys.exit('Insufficient Parameter') - if (EPC.EPCIPAddress != '') and (EPC.EPCIPAddress != 'none'): - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") - SSH.copyout(EPC.EPCIPAddress, EPC.EPCUserName, EPC.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") + if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/tcp_iperf_stats.awk", "/tmp") + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/active_net_interfaces.awk", "/tmp") else: if CiTestObj.UEIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': - Usage() + GenericHelp(Version) sys.exit('UE: Insufficient Parameter') #read test_case_list.xml file @@ -4969,7 +4647,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re else: logging.debug('ERROR: requested test is invalidly formatted: ' + test) sys.exit(1) - if (EPC.EPCIPAddress != '') and (EPC.EPCIPAddress != 'none'): + if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): CiTestObj.CheckFlexranCtrlInstallation() #get the list of tests to be done @@ -5087,6 +4765,6 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') CiTestObj.CreateHtmlTabFooter(True) else: - Usage() + GenericHelp(Version) sys.exit('Invalid mode') sys.exit(0) From b2765ac23a3b07dfd3555f9f1d66cd04614eadf9 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Tue, 28 Jan 2020 13:41:59 +0100 Subject: [PATCH 084/175] some changes in pucchsim --- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c | 13 ++--- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h | 4 +- openair1/SIMULATION/NR_PHY/pucchsim.c | 67 ++++++++++++++----------- openair2/GNB_APP/RRC_nr_paramsvalues.h | 24 ++++----- 4 files changed, 55 insertions(+), 53 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index 351c4ea22a..d68b3ea1a4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -46,6 +46,7 @@ #define DEBUG_PUCCH_TX #define DEBUG_NR_PUCCH_TX #endif + //#define ONE_OVER_SQRT2 23170 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2) void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, @@ -74,10 +75,7 @@ void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, // Corresponds to L1 parameter 'HoppingID' (see 38.211, section 6.3.2.2) BIT STRING (SIZE (10)) //uint16_t n_id = ue->pucch_config_common_nr->hoppingId; // from higher layers FIXME!!! #ifdef DEBUG_NR_PUCCH_TX - // initialization to be removed - PUCCH_GroupHopping=neither; - n_id=10; - printf("\t\t [nr_group_sequence_hopping] initialization PUCCH_GroupHopping=%u, n_id=%u -> variable initializations TO BE REMOVED\n",PUCCH_GroupHopping,n_id); + printf("\t\t [nr_group_sequence_hopping] PUCCH_GroupHopping=%u, n_id=%u \n",PUCCH_GroupHopping,n_id); #endif uint8_t f_ss=0,f_gh=0; *u=0; @@ -156,11 +154,7 @@ double nr_cyclic_shift_hopping(uint32_t n_id, // alpha_init initialized to 2*PI/12=0.5235987756 double alpha = 0.5235987756; uint32_t c_init = n_id; // we initialize c_init again to calculate n_cs -#ifdef DEBUG_NR_PUCCH_TX - // initialization to be remo.ved - c_init=10; - printf("\t\t [nr_cyclic_shift_hopping] initialization c_init=%u -> variable initialization TO BE REMOVED\n",c_init); -#endif + uint32_t x1,s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 uint8_t n_cs=0; int l = 32, minShift = (14*8*nr_tti_tx )+ 8*(lnormal+lprime); @@ -188,6 +182,7 @@ double nr_cyclic_shift_hopping(uint32_t n_id, #endif return(alpha); } + void nr_generate_pucch0(PHY_VARS_NR_UE *ue, int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index e8cd147526..fbc193e7b1 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -139,8 +139,8 @@ void nr_generate_pucch3_4(PHY_VARS_NR_UE *ue, uint8_t occ_index_format4); // tables for mcs values for different payloads - static const uint8_t table1_mcs[]={0,3,6,9}; - static const uint8_t table2_mcs[]={0,1,3,4,6,7,9,10}; + static const uint8_t table1_mcs[]={0,6,3,9}; + static const uint8_t table2_mcs[]={0,3,9,6,1,4,10,7}; /* * The following tables implement TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (rows->u {0,1,..,29} / columns->n {0,1,...,M_ZC-1) diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 6af2837901..a9dcdca754 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -87,12 +87,13 @@ int main(int argc, char **argv) uint8_t nacktoack_flag=0; int16_t amp=0x7FFF; int nr_tti_tx=0; - uint64_t actual_payload=0,payload_received;//payload bits b7b6...b2b1b0 where b7..b3=0 b2b1=HARQ b0 is SR. payload maximum value is 7 for pucch format 0 + uint64_t actual_payload=0,payload_received; int nr_bit=1; // maximum value possible is 2 uint8_t m0=0;// higher layer paramater initial cyclic shift uint8_t nrofSymbols=1; //number of OFDM symbols can be 1-2 for format 1 uint8_t startingSymbolIndex=0; // resource allocated see 9.2.1, 38.213 for more info.should be actually present in the resource set provided uint16_t startingPRB=0,startingPRB_intraSlotHopping=0; //PRB number not sure see 9.2.1, 38.213 for more info. Should be actually present in the resource set provided + uint32_t hoppingId=40; uint8_t timeDomainOCC=0; SCM_t channel_model=AWGN;//Rayleigh1_anticorr; @@ -114,7 +115,7 @@ int main(int argc, char **argv) logInit(); set_glog(loglvl); - while ((c = getopt (argc, argv, "f:hA:f:g:i:P:b:T:n:o:s:S:x:y:z:N:F:GR:IL")) != -1) { + while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL")) != -1) { switch (c) { case 'f': //write_output_file=1; @@ -257,12 +258,24 @@ int main(int argc, char **argv) case 'i': nrofSymbols=(uint8_t)atoi(optarg); break; + case 'I': + startingSymbolIndex=(uint8_t)atoi(optarg); + break; + case 'r': + startingPRB=atoi(optarg); + break; case 'P': format=atoi(optarg); break; + case 'm': + m0=atoi(optarg); + break; case 'b': nr_bit=atoi(optarg); break; + case 'B': + actual_payload=atoi(optarg); + break; case 'T': nacktoack_flag=(uint8_t)atoi(optarg); target_error_rate=0.001; @@ -292,8 +305,11 @@ int main(int argc, char **argv) printf("-f Output filename (.txt format) for Pe/SNR results\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); printf("-i Enter number of ofdm symbols for pucch\n"); + printf("-r PUCCCH starting PRB\n"); printf("-P Enter the format of PUCCH\n"); printf("-b number of HARQ bits (1-2)\n"); + printf("-B payload to be transmitted on PUCCH\n"); + printf("-m initial cyclic shift m0\n"); printf("-T to check nacktoack miss for format 1"); exit (-1); break; @@ -304,6 +320,16 @@ int main(int argc, char **argv) printf("Initializing gNodeB for mu %d, N_RB_DL %d\n",mu,N_RB_DL); + if((format!=0) && (format!=1)){ + printf("PUCCH format %d not supported\n",format); + exit(0); + } + + AssertFatal((nr_bit<3)&&(actual_payload<4),"Only format 0 and 1 currently supported. 2 bits max supported"); + + if (nr_bit==1) actual_payload = actual_payload&1; + + printf("Transmitted payload is %ld\n",actual_payload); RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *)); RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB)); @@ -398,6 +424,7 @@ int main(int argc, char **argv) //configure UE UE = malloc(sizeof(PHY_VARS_NR_UE)); memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS)); + UE->pucch_config_common_nr->hoppingId = hoppingId; //phy_init_nr_top(UE); //called from init_nr_ue_signal UE->perfect_ce = 0; @@ -414,35 +441,15 @@ int main(int argc, char **argv) startingPRB_intraSlotHopping=N_RB_DL-1; pucch_GroupHopping_t PUCCH_GroupHopping=UE->pucch_config_common_nr->pucch_GroupHopping; uint32_t n_id=UE->pucch_config_common_nr->hoppingId; - if((format!=0) && (format!=1)){ - printf("format not supported\n"); - exit(0); + + if(format==0){ + // for now we are not considering SR just HARQ-ACK + if(nr_bit==1) + mcs=table1_mcs[actual_payload]; + else if(nr_bit==2) + mcs=table2_mcs[actual_payload]; } - if(nacktoack_flag==0){ - if(format==0){ - if(nr_bit==1){ - actual_payload=2; - mcs=table1_mcs[actual_payload]; - } - else if(nr_bit==2){ - actual_payload=6; - mcs=table2_mcs[actual_payload]; - } - else{ - printf("Number of HARQ bits possible is 1-2\n"); - exit(0); - } - } - else { - if(nr_bit==1) - actual_payload=1; - else if(nr_bit==2) - actual_payload=3; - else{ - printf("number of bits carried by PUCCH format1 is 1-2\n"); - } - } - } + for(SNR=snr0;SNR<=snr1;SNR=SNR+1){ ack_nack_errors=0; n_errors = 0; diff --git a/openair2/GNB_APP/RRC_nr_paramsvalues.h b/openair2/GNB_APP/RRC_nr_paramsvalues.h index 0b54b62e4a..847936179e 100644 --- a/openair2/GNB_APP/RRC_nr_paramsvalues.h +++ b/openair2/GNB_APP/RRC_nr_paramsvalues.h @@ -128,18 +128,18 @@ #define GNB_CONFIG_STRING_RARESPONSEWINDOW "ra_ResponseWindow" #define GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSBPR "ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR" #define GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSB "ssb_perRACH_OccasionAndCB_PreamblesPerSSB" -#define GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER "ra_ContentionResolutionTimer" -#define GNB_CONFIG_STRING_RSRPTHRESHOLDSSB "rsrp_ThresholdSSB" -#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR "prach_RootSequenceIndex_PR" -#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX "prach_RootSequenceIndex" -#define GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING "msg1_SubcarrierSpacing" -#define GNB_CONFIG_STRING_RESTRICTEDSETCONFIG "restrictedSetConfig" -#define GNB_CONFIG_STRING_PUSCHTIMEDOMAINALLOCATIONLIST "puschTimeDomainAllocationList" -#define GNB_CONFIG_STRING_MSG3DELTAPREABMLE "msg3_DeltaPreamble" -#define GNB_CONFIG_STRING_P0NOMINALWITHGRANT "p0_NominalWithGrant" -#define GNB_CONFIG_STRING_PUCCHGROUPHOPPING "pucchGroupHopping" -#define GNB_CONFIG_STRING_HOPPINGID "hoppingId" -#define GNB_CONFIG_STRING_P0NOMINAL "p0_nominal" +#define GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER "ra_ContentionResolutionTimer" +#define GNB_CONFIG_STRING_RSRPTHRESHOLDSSB "rsrp_ThresholdSSB" +#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR "prach_RootSequenceIndex_PR" +#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX "prach_RootSequenceIndex" +#define GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING "msg1_SubcarrierSpacing" +#define GNB_CONFIG_STRING_RESTRICTEDSETCONFIG "restrictedSetConfig" +#define GNB_CONFIG_STRING_PUSCHTIMEDOMAINALLOCATIONLIST "puschTimeDomainAllocationList" +#define GNB_CONFIG_STRING_MSG3DELTAPREABMLE "msg3_DeltaPreamble" +#define GNB_CONFIG_STRING_P0NOMINALWITHGRANT "p0_NominalWithGrant" +#define GNB_CONFIG_STRING_PUCCHGROUPHOPPING "pucchGroupHopping" +#define GNB_CONFIG_STRING_HOPPINGID "hoppingId" +#define GNB_CONFIG_STRING_P0NOMINAL "p0_nominal" #define GNB_CONFIG_STRING_INITIALULBWPK2_0 "initialULBWPk2_0" #define GNB_CONFIG_STRING_INITIALULBWPMAPPINGTYPE_0 "initialULBWPmappingType_0" #define GNB_CONFIG_STRING_INITIALULBWPSTARTSYMBOLANDLENGTH_0 "initialULBWPstartSymbolAndLength_0" From 0e550ff2f592c0145f8996aa5c66cdc3920e7e1e Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Tue, 28 Jan 2020 16:13:46 +0100 Subject: [PATCH 085/175] fix for pucch0 resource allocation --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 27 ++++++++----------------- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c | 27 +++++-------------------- openair1/SIMULATION/NR_PHY/pucchsim.c | 1 + 3 files changed, 14 insertions(+), 41 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index b74b078dfd..d6dc708042 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -107,26 +107,13 @@ void nr_decode_pucch0( int32_t **rxdataF, */ uint32_t re_offset=0; for (l=0; lN_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } - if ((startingPRB >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))); - } - if ((startingPRB < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } - if ((startingPRB > (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))) + 6; - } - if ((startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB contains DC - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } + + re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; + if (re_offset>= frame_parms->ofdm_symbol_size) + re_offset-=frame_parms->ofdm_symbol_size; + for (n=0; n<12; n++){ - if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { - // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB) - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size); - } + r_re[(12*l)+n]=((int16_t *)&rxdataF[0][re_offset])[0]; r_im[(12*l)+n]=((int16_t *)&rxdataF[0][re_offset])[1]; #ifdef DEBUG_NR_PUCCH_RX @@ -135,6 +122,8 @@ void nr_decode_pucch0( int32_t **rxdataF, l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]); #endif re_offset++; + if (re_offset>= frame_parms->ofdm_symbol_size) + re_offset-=frame_parms->ofdm_symbol_size; } } double corr[nr_sequences],corr_re[nr_sequences],corr_im[nr_sequences]; diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index d68b3ea1a4..5d2640cd74 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -268,32 +268,13 @@ void nr_generate_pucch0(PHY_VARS_NR_UE *ue, uint32_t re_offset=0; for (int l=0; lN_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } - if ((startingPRB >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))); - } - - if ((startingPRB < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } - - if ((startingPRB > (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))) + 6; - } - - if ((startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB contains DC - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } + re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; + if (re_offset>= frame_parms->ofdm_symbol_size) + re_offset-=frame_parms->ofdm_symbol_size; //txptr = &txdataF[0][re_offset]; for (int n=0; n<12; n++) { - if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { - // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB) - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size); - } ((int16_t *)&txdataF[0][re_offset])[0] = (int16_t)(((int32_t)(amp) * x_n_re[(12*l)+n])>>15); ((int16_t *)&txdataF[0][re_offset])[1] = (int16_t)(((int32_t)(amp) * x_n_im[(12*l)+n])>>15); @@ -306,6 +287,8 @@ void nr_generate_pucch0(PHY_VARS_NR_UE *ue, l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]); #endif re_offset++; + if (re_offset>= frame_parms->ofdm_symbol_size) + re_offset-=frame_parms->ofdm_symbol_size; } } } diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index a9dcdca754..32bbbfc7dd 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -495,6 +495,7 @@ int main(int argc, char **argv) } n_errors=((actual_payload^payload_received)&1)+(((actual_payload^payload_received)&2)>>1)+(((actual_payload^payload_received)&4)>>2)+n_errors; } + printf("Decoded payload is %ld\n",payload_received); printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,n_errors); if((float)ack_nack_errors/(float)(nr_bit*n_trials)<=target_error_rate){ printf("PUCCH test OK\n"); From cdde88302c388efeab122ebfbfad97e1972dcc07 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Tue, 28 Jan 2020 16:38:02 +0100 Subject: [PATCH 086/175] completing previous fix --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 14 +++++++++----- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c | 14 ++++++++------ openair1/SIMULATION/NR_PHY/pucchsim.c | 1 + 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index d6dc708042..940f3aee71 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -106,20 +106,24 @@ void nr_decode_pucch0( int32_t **rxdataF, * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources FIXME! */ uint32_t re_offset=0; + uint8_t l2; + for (l=0; lofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; + l2 = l+startingSymbolIndex; + re_offset = (12*startingPRB) + frame_parms->first_carrier_offset; if (re_offset>= frame_parms->ofdm_symbol_size) re_offset-=frame_parms->ofdm_symbol_size; for (n=0; n<12; n++){ - r_re[(12*l)+n]=((int16_t *)&rxdataF[0][re_offset])[0]; - r_im[(12*l)+n]=((int16_t *)&rxdataF[0][re_offset])[1]; + r_re[(12*l)+n]=((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[0]; + r_im[(12*l)+n]=((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[1]; #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", - amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,re_offset, - l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]); + amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,(l2*frame_parms->ofdm_symbol_size)+re_offset, + l,n,((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[0], + ((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[1]); #endif re_offset++; if (re_offset>= frame_parms->ofdm_symbol_size) diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index 5d2640cd74..148ee51a69 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -266,25 +266,27 @@ void nr_generate_pucch0(PHY_VARS_NR_UE *ue, */ //int32_t *txptr; uint32_t re_offset=0; + uint8_t l2; for (int l=0; lofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; + l2=l+startingSymbolIndex; + re_offset = (12*startingPRB) + frame_parms->first_carrier_offset; if (re_offset>= frame_parms->ofdm_symbol_size) re_offset-=frame_parms->ofdm_symbol_size; //txptr = &txdataF[0][re_offset]; for (int n=0; n<12; n++) { - ((int16_t *)&txdataF[0][re_offset])[0] = (int16_t)(((int32_t)(amp) * x_n_re[(12*l)+n])>>15); - ((int16_t *)&txdataF[0][re_offset])[1] = (int16_t)(((int32_t)(amp) * x_n_im[(12*l)+n])>>15); + ((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[0] = (int16_t)(((int32_t)(amp) * x_n_re[(12*l)+n])>>15); + ((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[1] = (int16_t)(((int32_t)(amp) * x_n_im[(12*l)+n])>>15); //((int16_t *)txptr[0][re_offset])[0] = (int16_t)((int32_t)amp * x_n_re[(12*l)+n])>>15; //((int16_t *)txptr[0][re_offset])[1] = (int16_t)((int32_t)amp * x_n_im[(12*l)+n])>>15; //txptr[re_offset] = (x_n_re[(12*l)+n]<<16) + x_n_im[(12*l)+n]; #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", - amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,re_offset, - l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]); + amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,(l2*frame_parms->ofdm_symbol_size) + re_offset, + l2,n,((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[0], + ((int16_t *)&txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset])[1]); #endif re_offset++; if (re_offset>= frame_parms->ofdm_symbol_size) diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 32bbbfc7dd..35e9713b27 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -305,6 +305,7 @@ int main(int argc, char **argv) printf("-f Output filename (.txt format) for Pe/SNR results\n"); printf("-F Input filename (.txt format) for RX conformance testing\n"); printf("-i Enter number of ofdm symbols for pucch\n"); + printf("-I Starting symbol index for pucch\n"); printf("-r PUCCCH starting PRB\n"); printf("-P Enter the format of PUCCH\n"); printf("-b number of HARQ bits (1-2)\n"); From 84bed899cb7f8130f0fb0064edbd49a0200eb5f6 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Thu, 30 Jan 2020 16:49:13 +0100 Subject: [PATCH 087/175] bitmap for scheduling dlsch and ulsch in phytest and a bugfix in dlsch coding --- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 4 +- openair2/GNB_APP/RRC_nr_paramsvalues.h | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 3 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 96 +++++++++++++-------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 5 ++ 5 files changed, 71 insertions(+), 39 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 7f52443fce..20d995f69c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -273,7 +273,7 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, LOG_D(PHY,"new_gNB_dlsch exit flag %d, size of %ld\n", exit_flag, sizeof(NR_gNB_DLSCH_t)); - free_gNB_dlsch(dlsch,N_RB); + free_gNB_dlsch(&dlsch,N_RB); return(NULL); @@ -323,7 +323,7 @@ int nr_dlsch_encoding(unsigned char *a, unsigned int G; unsigned int crc=1; - uint8_t harq_pid = dlsch->harq_ids[frame&2][slot]; + uint8_t harq_pid = dlsch->harq_ids[frame%2][slot]; AssertFatal(harq_pid<8 && harq_pid>=0,"illegal harq_pid %d\b",harq_pid); nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_processes[harq_pid]->pdsch_pdu.pdsch_pdu_rel15; uint16_t nb_rb = rel15->rbSize; diff --git a/openair2/GNB_APP/RRC_nr_paramsvalues.h b/openair2/GNB_APP/RRC_nr_paramsvalues.h index 847936179e..4c5da80764 100644 --- a/openair2/GNB_APP/RRC_nr_paramsvalues.h +++ b/openair2/GNB_APP/RRC_nr_paramsvalues.h @@ -301,7 +301,7 @@ {GNB_CONFIG_STRING_PRACHMSG1FDM,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM,defint64val:NR_RACH_ConfigGeneric__msg1_FDM_one,TYPE_INT64,0/*72*/},\ {GNB_CONFIG_STRING_PRACHMSG1FREQUENCYSTART,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart,defint64val:0,TYPE_INT64,0/*73*/},\ {GNB_CONFIG_STRING_ZEROCORRELATIONZONECONFIG,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,defint64val:13,TYPE_INT64,0/*74*/},\ -{GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,iptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,defintval:-118,TYPE_INT32,0/*75*/},\ +{GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,defintval:-118,TYPE_INT64,0/*75*/},\ {GNB_CONFIG_STRING_PREAMBLETRANSMAX,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax,defint64val:NR_RACH_ConfigGeneric__preambleTransMax_n10,TYPE_INT64,0/*76*/},\ {GNB_CONFIG_STRING_POWERRAMPINGSTEP,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep,defint64val:NR_RACH_ConfigGeneric__powerRampingStep_dB2,TYPE_INT64,0/*77*/},\ {GNB_CONFIG_STRING_RARESPONSEWINDOW,NULL,0,i64ptr:&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow,defint64val:NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20,TYPE_INT64,0/*78*/},\ diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 44a3f11711..d7d72fb6fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -50,7 +50,7 @@ extern RAN_CONTEXT_t RC; //extern int l2_init_gNB(void); extern void mac_top_init_gNB(void); extern uint8_t nfapi_mode; - +uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160}; void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) { @@ -281,6 +281,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm else LOG_I(PHY,"TDD has been properly configurated\n"); } + RC.nrmac[Mod_idP]->common_channels[0].num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])>>(7-cfg->tdd_table.tdd_period.value); /* // PDCCH-ConfigCommon diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index ce5b8754e4..b561a44d28 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -308,6 +308,14 @@ void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) } */ +bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){ + + if((bitmap>>slot)&0x01) + return true; + else + return false; +} + void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame_rxP, sub_frame_t slot_rxP, @@ -318,8 +326,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, protocol_ctxt_t ctxt; int CC_id; - + NR_COMMON_channels_t *cc = RC.nrmac[module_idP]->common_channels; + //nfapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = NULL; start_meas(&RC.nrmac[module_idP]->eNB_scheduler); @@ -328,62 +337,79 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, pdcp_run(&ctxt); //rrc_rx_tx(&ctxt, CC_id); - RC.nrmac[module_idP]->frame = frame_rxP; RC.nrmac[module_idP]->slot = slot_rxP; + uint64_t *dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch + uint64_t *ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch + + // hardcoding dlsch to be in slot 1 + if (phy_test && !(slot_txP%cc->num_slots_per_tdd)) { + if(slot_txP==0) + *dlsch_in_slot_bitmap = 0x02; + else + *dlsch_in_slot_bitmap = 0x00; + } + + // hardcoding ulsch to be in slot 8 + if (phy_test && !(slot_rxP%cc->num_slots_per_tdd)) { + if(slot_rxP==0) + *ulsch_in_slot_bitmap = 0x100; + else + *ulsch_in_slot_bitmap = 0x00; + } // Check if there are downlink symbols in the slot, if (is_nr_DL_slot(cc->ServingCellConfigCommon,slot_txP)) { - memset(RC.nrmac[module_idP]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int)); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //mbsfn_status[CC_id] = 0; + memset(RC.nrmac[module_idP]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int)); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + //mbsfn_status[CC_id] = 0; - // clear vrb_maps - memset(cc[CC_id].vrb_map, 0, 100); - memset(cc[CC_id].vrb_map_UL, 0, 100); + // clear vrb_maps + memset(cc[CC_id].vrb_map, 0, 100); + memset(cc[CC_id].vrb_map_UL, 0, 100); - clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP); - } + clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP); + } - // refresh UE list based on UEs dropped by PHY in previous subframe - /* - for (i = 0; i < MAX_MOBILES_PER_GNB; i++) { - if (UE_list->active[i]) { + // refresh UE list based on UEs dropped by PHY in previous subframe + /* + for (i = 0; i < MAX_MOBILES_PER_GNB; i++) { + if (UE_list->active[i]) { - nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id]; + nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id]; - rnti = 0;//UE_RNTI(module_idP, i); - CC_id = 0;//UE_PCCID(module_idP, i); + rnti = 0;//UE_RNTI(module_idP, i); + CC_id = 0;//UE_PCCID(module_idP, i); - } //END if (UE_list->active[i]) - } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++) - */ - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES,NOT_A_RNTI, frame_txP, slot_txP,module_idP); + } //END if (UE_list->active[i]) + } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++) + */ + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES,NOT_A_RNTI, frame_txP, slot_txP,module_idP); - // This schedules MIB - if((slot_txP == 0) && (frame_txP & 7) == 0){ - schedule_nr_mib(module_idP, frame_txP, slot_txP); - } + // This schedules MIB + if((slot_txP == 0) && (frame_txP & 7) == 0){ + schedule_nr_mib(module_idP, frame_txP, slot_txP); + } - // Phytest scheduling - if (phy_test && slot_txP==1){ - nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP,NULL); - } + // Phytest scheduling + if (phy_test && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%cc->num_slots_per_tdd))) { + nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP,NULL); + } - /* - // Allocate CCEs for good after scheduling is done - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) - allocate_CCEs(module_idP, CC_id, subframeP, 0); - */ + /* + // Allocate CCEs for good after scheduling is done + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) + allocate_CCEs(module_idP, CC_id, subframeP, 0); + */ } //is_nr_DL_slot if (is_nr_UL_slot(cc->ServingCellConfigCommon,slot_rxP)) { - if (phy_test && slot_rxP==8){ + if (phy_test && (is_xlsch_in_slot(*ulsch_in_slot_bitmap,slot_rxP%cc->num_slots_per_tdd))){ nr_schedule_uss_ulsch_phytest(module_idP, frame_rxP, slot_rxP); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 18bc034ae4..77501a0487 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -98,6 +98,8 @@ typedef struct { uint8_t vrb_map_UL[100]; /// number of subframe allocation pattern available for MBSFN sync area uint8_t num_sf_allocation_pattern; + /// number of slots per TDD period + uint8_t num_slots_per_tdd; } NR_COMMON_channels_t; /*! \brief scheduling control information set through an API (not used)*/ @@ -153,6 +155,9 @@ typedef struct gNB_MAC_INST_s { nfapi_nr_tx_data_request_t TX_req[NFAPI_CC_MAX]; NR_UE_list_t UE_list; + uint64_t dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch + uint64_t ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch + /// UL handle uint32_t ul_handle; From 06e700a048e47137eb68bee8d2741fd2f45788ff Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Fri, 31 Jan 2020 16:32:49 +0100 Subject: [PATCH 088/175] bitmap for scheduling dlsch and ulsch in UE list --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 37 +++++++++++++--------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 7 ++-- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index b561a44d28..c9b63fe25c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -326,6 +326,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, protocol_ctxt_t ctxt; int CC_id; + int UE_id; + uint64_t *dlsch_in_slot_bitmap=NULL; + uint64_t *ulsch_in_slot_bitmap=NULL; + + if (phy_test) UE_id=0; NR_COMMON_channels_t *cc = RC.nrmac[module_idP]->common_channels; @@ -340,23 +345,25 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, RC.nrmac[module_idP]->frame = frame_rxP; RC.nrmac[module_idP]->slot = slot_rxP; - uint64_t *dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch - uint64_t *ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch + if (phy_test) { + dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.dlsch_in_slot_bitmap[UE_id]; // static bitmap signaling which slot in a tdd period contains dlsch + ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.ulsch_in_slot_bitmap[UE_id]; // static bitmap signaling which slot in a tdd period contains ulsch - // hardcoding dlsch to be in slot 1 - if (phy_test && !(slot_txP%cc->num_slots_per_tdd)) { - if(slot_txP==0) - *dlsch_in_slot_bitmap = 0x02; - else - *dlsch_in_slot_bitmap = 0x00; - } + // hardcoding dlsch to be in slot 1 + if (!(slot_txP%cc->num_slots_per_tdd)) { + if(slot_txP==0) + *dlsch_in_slot_bitmap = 0x02; + else + *dlsch_in_slot_bitmap = 0x00; + } - // hardcoding ulsch to be in slot 8 - if (phy_test && !(slot_rxP%cc->num_slots_per_tdd)) { - if(slot_rxP==0) - *ulsch_in_slot_bitmap = 0x100; - else - *ulsch_in_slot_bitmap = 0x00; + // hardcoding ulsch to be in slot 8 + if (!(slot_rxP%cc->num_slots_per_tdd)) { + if(slot_rxP==0) + *ulsch_in_slot_bitmap = 0x100; + else + *ulsch_in_slot_bitmap = 0x00; + } } // Check if there are downlink symbols in the slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 77501a0487..b9df20d4c2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -122,9 +122,11 @@ typedef struct { boolean_t active[MAX_MOBILES_PER_GNB]; rnti_t rnti[MAX_MOBILES_PER_GNB]; NR_CellGroupConfig_t *secondaryCellGroup[MAX_MOBILES_PER_GNB]; + uint64_t dlsch_in_slot_bitmap[MAX_MOBILES_PER_GNB]; // static bitmap signaling which slot in a tdd period contains dlsch + uint64_t ulsch_in_slot_bitmap[MAX_MOBILES_PER_GNB]; // static bitmap signaling which slot in a tdd period contains ulsch } NR_UE_list_t; -/*! \brief top level eNB MAC structure */ +/*! \brief top level gNB MAC structure */ typedef struct gNB_MAC_INST_s { /// Ethernet parameters for northbound midhaul interface eth_params_t eth_params_n; @@ -155,9 +157,6 @@ typedef struct gNB_MAC_INST_s { nfapi_nr_tx_data_request_t TX_req[NFAPI_CC_MAX]; NR_UE_list_t UE_list; - uint64_t dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch - uint64_t ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch - /// UL handle uint32_t ul_handle; From c36636be9597c0aea2caa82ac9103d643fe7d6ac Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Mon, 3 Feb 2020 11:53:05 +0100 Subject: [PATCH 089/175] function to configure scf fapi for pucch (not yet called) --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 16 +-- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 135 ++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 4 + 3 files changed, 144 insertions(+), 11 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 32e8aedc06..2fe553a055 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -262,14 +262,10 @@ int configure_fapi_dl_Tx(int Mod_idP, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu; nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu; int TBS; - - int bwp_id=1; - int UE_id = 0; NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; - NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id]; AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1, "downlinkBWP_ToAddModList has %d BWP!\n", @@ -422,7 +418,6 @@ int configure_fapi_dl_Tx(int Mod_idP, TBS); dl_req->nPDUs+=2; - TX_req->PDU_length = pdsch_pdu_rel15->TBSize[0]; TX_req->PDU_index = nr_mac->pdu_index[0]++; @@ -740,12 +735,12 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP, UL_tti_req->SFN = frameP; UL_tti_req->Slot = slotP; - UL_tti_req->n_pdus = 1; - UL_tti_req->pdus_list[0].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE; - UL_tti_req->pdus_list[0].pdu_size = sizeof(nfapi_nr_pusch_pdu_t); - nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t); + nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pusch_pdu; memset(pusch_pdu,0,sizeof(nfapi_nr_pusch_pdu_t)); - + UL_tti_req->n_pdus+=1; + LOG_D(MAC, "Scheduling UE specific PUSCH\n"); //UL_tti_req = &nr_mac->UL_tti_req[CC_id]; /* @@ -842,7 +837,6 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP, 1, // ue-specific, scc, bwp); - dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index df9c37f687..273c09e246 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -547,6 +547,141 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, } +// This function configures pucch_pdu according to pucch_ResourceId value +void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, + NR_PUCCH_ResourceId_t pucch_ResourceId, + NR_ServingCellConfigCommon_t *scc, + NR_BWP_Uplink_t *bwp){ + + NR_PUCCH_Config_t *pucch_Config; + NR_PUCCH_Resource_t *pucchres; + NR_PUCCH_FormatConfig_t *pucchfmt; + NR_PUSCH_Config_t *pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup; + long *pusch_id = pusch_Config->dataScramblingIdentityPUSCH; + long *id0 = NULL; + int n_list; + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) + id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0; + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) + id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0; + + // hop flags and hopping id are valid for any BWP + switch (scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping){ + case 0 : + // if neither, both disabled + pucch_pdu->group_hop_flag = 0; + pucch_pdu->sequence_hop_flag = 0; + break; + case 1 : + // if enable, group enabled + pucch_pdu->group_hop_flag = 1; + pucch_pdu->sequence_hop_flag = 0; + break; + case 2 : + // if disable, sequence disabled + pucch_pdu->group_hop_flag = 0; + pucch_pdu->sequence_hop_flag = 1; + break; + default: + AssertFatal(1==0,"msg1 FDM identifier %ld undefined (0,1,2,3) \n", scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM); + } + + if (scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId != NULL) + pucch_pdu->hopping_id = *scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId; + else + pucch_pdu->hopping_id = *scc->physCellId; + + if (bwp) { // This is not the InitialBWP + + pucch_pdu->bwp_size = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275); + pucch_pdu->bwp_start = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,275); + pucch_pdu->subcarrier_spacing = bwp->bwp_Common->genericParameters.subcarrierSpacing; + pucch_pdu->cyclic_prefix = (bwp->bwp_Common->genericParameters.cyclicPrefix==NULL) ? 0 : *bwp->bwp_Common->genericParameters.cyclicPrefix; + + pucch_Config = bwp->bwp_Dedicated->pucch_Config->choice.setup; + + AssertFatal(pucch_Config->resourceToAddModList!=NULL, + "PUCCH resourceToAddModList is null\n"); + + n_list = pucch_Config->resourceToAddModList->list.count; + AssertFatal(n_list>0,"PUCCH resourceToAddModList is empty\n"); + + for (int i=0; iresourceToAddModList->list.array[i]; + if (pucchres->pucch_ResourceId == pucch_ResourceId) { + pucch_pdu->prb_start = pucchres->startingPRB; + pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ? 1 : 0; + pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ? *pucchres->secondHopPRB : 0; + + switch(pucchres->format.present) { + case NR_PUCCH_Resource__format_PR_format0 : + pucch_pdu->format_type = 0; + pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format0->initialCyclicShift; + pucch_pdu->nr_of_symbols = pucchres->format.choice.format0->nrofSymbols; + pucch_pdu->start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex; + break; + case NR_PUCCH_Resource__format_PR_format1 : + pucch_pdu->format_type = 1; + pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format1->initialCyclicShift; + pucch_pdu->nr_of_symbols = pucchres->format.choice.format1->nrofSymbols; + pucch_pdu->start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex; + pucch_pdu->time_domain_occ_idx = pucchres->format.choice.format1->timeDomainOCC; + break; + case NR_PUCCH_Resource__format_PR_format2 : + pucch_pdu->format_type = 2; + pucch_pdu->nr_of_symbols = pucchres->format.choice.format2->nrofSymbols; + pucch_pdu->start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex; + pucch_pdu->prb_size = pucchres->format.choice.format2->nrofPRBs; + pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId; + pucch_pdu->dmrs_scrambling_id = id0!= NULL ? *id0 : *scc->physCellId; + break; + case NR_PUCCH_Resource__format_PR_format3 : + pucch_pdu->format_type = 3; + pucch_pdu->nr_of_symbols = pucchres->format.choice.format3->nrofSymbols; + pucch_pdu->start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex; + pucch_pdu->prb_size = pucchres->format.choice.format3->nrofPRBs; + pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId; + if (pucch_Config->format3 == NULL) { + pucch_pdu->pi_2bpsk = 0; + pucch_pdu->add_dmrs_flag = 0; + } + else { + pucchfmt = pucch_Config->format3->choice.setup; + pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ? 1 : 0; + pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ? 1 : 0; + } + break; + case NR_PUCCH_Resource__format_PR_format4 : + pucch_pdu->format_type = 4; + pucch_pdu->nr_of_symbols = pucchres->format.choice.format4->nrofSymbols; + pucch_pdu->start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex; + pucch_pdu->pre_dft_occ_len = pucchres->format.choice.format4->occ_Length; + pucch_pdu->pre_dft_occ_idx = pucchres->format.choice.format4->occ_Index; + pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId; + if (pucch_Config->format3 == NULL) { + pucch_pdu->pi_2bpsk = 0; + pucch_pdu->add_dmrs_flag = 0; + } + else { + pucchfmt = pucch_Config->format3->choice.setup; + pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ? 1 : 0; + pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ? 1 : 0; + } + break; + default : + AssertFatal(1==0,"Undefined PUCCH format \n"); + } + } + } + + } + else { // this is for InitialBWP + AssertFatal(1==0,"Fill in InitialBWP PUCCH configuration\n"); + } + +} + + void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, dci_pdu_rel15_t *dci_pdu_rel15, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 3c95d076c0..694473c16b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -103,6 +103,10 @@ int nr_is_dci_opportunity(nfapi_nr_search_space_t search_space, uint16_t slot, nfapi_nr_config_request_scf_t cfg); */ +void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, + NR_PUCCH_ResourceId_t pucch_ResourceId, + NR_ServingCellConfigCommon_t *scc, + NR_BWP_Uplink_t *bwp); void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, int ss_type, NR_ServingCellConfigCommon_t *scc, From 10b046f5b8c0110b69c37c60fdb0daebeb4ec27a Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 3 Feb 2020 15:25:50 +0100 Subject: [PATCH 090/175] merge continue: take develop latest commits, fix compilation for test tools --- openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c | 2 +- openair1/PHY/LTE_TRANSPORT/pucch.c | 2 +- openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/nr_prach.c | 2 +- openair1/PHY/TOOLS/tools_defs.h | 8 ++++++++ openair1/SCHED_NR_UE/phy_frame_config_nr.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 6 +++--- openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- openair2/LAYER2/RLC/rlc.h | 4 ++-- 11 files changed, 21 insertions(+), 13 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index 2e4f3e6036..880c056578 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -1029,7 +1029,7 @@ void lte_ue_measurements(PHY_VARS_UE *ue, int N_RB_DL = frame_parms->N_RB_DL; - int rank_tm3_tm4; + int rank_tm3_tm4=-1; ue->measurements.nb_antennas_rx = frame_parms->nb_antennas_rx; diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index 8c19f44d2f..e3f741629c 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -180,7 +180,7 @@ uint16_t pucchfmt3_ChannelEstimation( int16_t SubCarrierDeMapData[NB_ANTENNAS_RX uint16_t n3_pucch_array[NUMBER_OF_UE_MAX], uint8_t ncs_cell[20][7] ) { uint32_t aa, symNo, k, slotNo, sym, i, j; - int16_t np, np_n, ip_ind; + int16_t np, np_n, ip_ind=-1; //int16_t npucch_sf; int16_t calctmp[2]; int16_t BsCshData[NB_ANTENNAS_RX][D_NSYM1SF][D_NSC1RB][2]; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c index 49fa484c26..a1b7898a2d 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c @@ -65,7 +65,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 uint16_t *prach_root_sequence_map; uint16_t preamble_offset,preamble_shift; uint16_t preamble_index0,n_shift_ra,n_shift_ra_bar; - uint16_t d_start,numshift; + uint16_t d_start=-1,numshift; uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type); //uint8_t Nsp=2; //uint8_t f_ra,t1_ra; diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 69077f0276..0fabf8c639 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -2070,7 +2070,7 @@ uint16_t nr_dci_format_size (PHY_VARS_NR_UE *ue, dl_res_alloc_type_1 = 1; } - uint8_t n_bits_freq_dom_res_assign_dl=0,n_dl_RGB_tmp; + uint8_t n_bits_freq_dom_res_assign_dl=0,n_dl_RGB_tmp=-1; if (dl_res_alloc_type_0 == 1) { // implementation of Table 5.1.2.2.1-1 TC 38.214 subclause 6.1.2.2.1 // config1: PDSCH-Config IE contains rbg-Size ENUMERATED {config1, config2} diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c index f4f4ac8926..d7a0aaeca6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c @@ -585,7 +585,7 @@ int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t *prach_root_sequence_map; uint16_t preamble_offset,preamble_shift; uint16_t preamble_index0,n_shift_ra,n_shift_ra_bar; - uint16_t d_start,numshift; + uint16_t d_start=-1,numshift; uint16_t prach_fmt = get_nr_prach_fmt(prach_ConfigIndex); //uint8_t Nsp=2; diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 57f5a782de..5ba956fd39 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -29,6 +29,10 @@ */ +#ifdef __cplusplus +extern "C" { +#endif + #include #include "PHY/sse_intrin.h" @@ -428,4 +432,8 @@ double interp(double x, double *xs, double *ys, int count); int write_output(const char *fname,const char *vname,void *data,int length,int dec,char format); +#ifdef __cplusplus +} +#endif + #endif //__PHY_TOOLS_DEFS__H__ diff --git a/openair1/SCHED_NR_UE/phy_frame_config_nr.c b/openair1/SCHED_NR_UE/phy_frame_config_nr.c index fc1c459ba4..e93eb09b8e 100644 --- a/openair1/SCHED_NR_UE/phy_frame_config_nr.c +++ b/openair1/SCHED_NR_UE/phy_frame_config_nr.c @@ -135,7 +135,7 @@ int set_tdd_config_nr(NR_DL_FRAME_PARMS *frame_parms, int dl_UL_TransmissionPeri void add_tdd_dedicated_configuration_nr(NR_DL_FRAME_PARMS *frame_parms, int slotIndex, int nrofDownlinkSymbols, int nrofUplinkSymbols) { TDD_UL_DL_SlotConfig_t *p_TDD_UL_DL_ConfigDedicated = frame_parms->p_TDD_UL_DL_ConfigDedicated; - TDD_UL_DL_SlotConfig_t *p_previous_TDD_UL_DL_ConfigDedicated; + TDD_UL_DL_SlotConfig_t *p_previous_TDD_UL_DL_ConfigDedicated=NULL; int next = 0; while (p_TDD_UL_DL_ConfigDedicated != NULL) { diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 6706b0f912..a47a174702 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -515,7 +515,7 @@ int main(int argc, char **argv) { char fname[32],vname[32]; FILE *bler_fd; char bler_fname[256]; - FILE *time_meas_fd; + FILE *time_meas_fd=NULL; char time_meas_fname[256]; // FILE *tikz_fd; // char tikz_fname[256]; @@ -1446,7 +1446,7 @@ int main(int argc, char **argv) { sched_resp.subframe=subframe; sched_resp.frame=proc_eNB->frame_tx; eNB->abstraction_flag=0; - schedule_response(&sched_resp); + schedule_response(&sched_resp, proc_eNB); phy_procedures_eNB_TX(eNB,proc_eNB,1); if (uncoded_ber_bit == NULL) { @@ -1480,7 +1480,7 @@ int main(int argc, char **argv) { TX_req.tx_request_body.number_of_pdus=0; proc_eNB->subframe_tx = subframe+1; sched_resp.subframe=subframe+1; - schedule_response(&sched_resp); + schedule_response(&sched_resp, proc_eNB); phy_procedures_eNB_TX(eNB,proc_eNB,0); ru->proc.tti_tx=(subframe+1)%10; feptx_prec(ru,proc_eNB->frame_tx,subframe+1); diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 91592f8ed5..0459109a7c 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -995,7 +995,7 @@ int main(int argc, char **argv) { srs_flag); sched_resp.subframe=(subframe+6)%10; sched_resp.frame=(1024+eNB->proc.frame_rx+((subframe<4)?-1:0))&1023; - schedule_response(&sched_resp); + schedule_response(&sched_resp, proc_rxtx); ///////////////////// if (abstx) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 579f5c6928..59dc1b06c9 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2067,7 +2067,7 @@ void nr_ue_send_sdu(module_id_t module_idP, if (opt_enabled) { trace_pdu(DIRECTION_DOWNLINK, pduP, pdu_len, module_idP, WS_C_RNTI, - (int) UE_mac_inst[module_idP].cs_RNTI, frameP, ttiP, 0, 0); //subframeP + *UE_mac_inst[module_idP].cs_RNTI, frameP, ttiP, 0, 0); //subframeP LOG_D(OPT, "[UE %d][DLSCH] Frame %d trace pdu for rnti %p with size %d\n", module_idP, frameP, UE_mac_inst[module_idP].cs_RNTI, pdu_len); } diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index dfdf527123..b337bcac7e 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -137,7 +137,7 @@ void (*rlc_rrc_data_ind)( const protocol_ctxt_t *const ctxtP, const rb_id_t rb_idP, const sdu_size_t sdu_sizeP, - const uint8_t *const sduP); + const uint8_t *const sduP) __attribute__ ((aligned(32))); void (*rlc_rrc_data_conf)( const protocol_ctxt_t *const ctxtP, @@ -250,7 +250,7 @@ logical_chan_id_t rlc_mbms_rbid2lcid_eNB[MAX_eNB][NB_RB_MBMS_MAX]; (((hash_key_t)(sESSION_ID)) << 37) | \ (((hash_key_t)(0x0000000000000001)) << 63)) -hash_table_t *rlc_coll_p; +hash_table_t *rlc_coll_p __attribute__ ((aligned(32))); /*! \fn tbs_size_t mac_rlc_serialize_tb (char* bufferP, list_t transport_blocksP) * \brief Serialize a list of transport blocks coming from RLC in order to be processed by MAC. From 59fc607c4e14b890630c681ea4eb7889b7db5e96 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Tue, 4 Feb 2020 12:33:54 +0100 Subject: [PATCH 091/175] mac function to configure fapi for pucch updated (not yet called) --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 60 ++++++++++++++++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 7 ++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 273c09e246..93b525a308 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -547,19 +547,29 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, } -// This function configures pucch_pdu according to pucch_ResourceId value +// This function configures pucch pdu fapi structure void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, - NR_PUCCH_ResourceId_t pucch_ResourceId, NR_ServingCellConfigCommon_t *scc, - NR_BWP_Uplink_t *bwp){ + NR_BWP_Uplink_t *bwp, + uint8_t pucch_resource, + uint16_t O_uci, + uint16_t O_ack, + uint8_t SR_flag) { NR_PUCCH_Config_t *pucch_Config; NR_PUCCH_Resource_t *pucchres; + NR_PUCCH_ResourceSet_t *pucchresset; NR_PUCCH_FormatConfig_t *pucchfmt; + NR_PUCCH_ResourceId_t *resource_id = NULL; NR_PUSCH_Config_t *pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup; long *pusch_id = pusch_Config->dataScramblingIdentityPUSCH; long *id0 = NULL; - int n_list; + int n_list, n_set; + uint16_t N2,N3; + int res_found = 0; + + pucch_pdu->bit_len_harq = O_ack; + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0; if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) @@ -600,25 +610,60 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_Config = bwp->bwp_Dedicated->pucch_Config->choice.setup; + AssertFatal(pucch_Config->resourceSetToAddModList!=NULL, + "PUCCH resourceSetToAddModList is null\n"); + + n_set = pucch_Config->resourceSetToAddModList->list.count; + AssertFatal(n_set>0,"PUCCH resourceSetToAddModList is empty\n"); + + N2 = 2; + // procedure to select pucch resource id from resource sets according to + // number of uci bits and pucch resource indicator pucch_resource + // ( see table 9.2.3.2 in 38.213) + for (int i=0; iresourceSetToAddModList->list.array[i]; + n_list = pucchresset->resourceList.list.count; + if (pucchresset->pucch_ResourceSetId == 0 && O_uci<3) { + if (pucch_resource < n_list) + resource_id = pucchresset->resourceList.list.array[pucch_resource]; + else + AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci); + } + else { + N3 = pucchresset->maxPayloadMinus1!= NULL ? *pucchresset->maxPayloadMinus1 : 1706; + if (N2O_uci) { + if (pucch_resource < n_list) + resource_id = pucchresset->resourceList.list.array[pucch_resource]; + else + AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci); + } + else N2 = N3; + } + } + + AssertFatal(resource_id!=NULL,"Couldn-t find any matching PUCCH resource in the PUCCH resource sets"); + AssertFatal(pucch_Config->resourceToAddModList!=NULL, "PUCCH resourceToAddModList is null\n"); n_list = pucch_Config->resourceToAddModList->list.count; AssertFatal(n_list>0,"PUCCH resourceToAddModList is empty\n"); + // going through the list of PUCCH resources to find the one indexed by resource_id for (int i=0; iresourceToAddModList->list.array[i]; - if (pucchres->pucch_ResourceId == pucch_ResourceId) { + if (pucchres->pucch_ResourceId == *resource_id) { + res_found = 1; pucch_pdu->prb_start = pucchres->startingPRB; pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ? 1 : 0; pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ? *pucchres->secondHopPRB : 0; - switch(pucchres->format.present) { case NR_PUCCH_Resource__format_PR_format0 : pucch_pdu->format_type = 0; pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format0->initialCyclicShift; pucch_pdu->nr_of_symbols = pucchres->format.choice.format0->nrofSymbols; pucch_pdu->start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex; + pucch_pdu->sr_flag = SR_flag; break; case NR_PUCCH_Resource__format_PR_format1 : pucch_pdu->format_type = 1; @@ -626,6 +671,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->nr_of_symbols = pucchres->format.choice.format1->nrofSymbols; pucch_pdu->start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex; pucch_pdu->time_domain_occ_idx = pucchres->format.choice.format1->timeDomainOCC; + pucch_pdu->sr_flag = SR_flag; break; case NR_PUCCH_Resource__format_PR_format2 : pucch_pdu->format_type = 2; @@ -673,7 +719,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, } } } - + AssertFatal(res_found==1,"No PUCCH resource found corresponding to id %ld\n",*resource_id); } else { // this is for InitialBWP AssertFatal(1==0,"Fill in InitialBWP PUCCH configuration\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 694473c16b..aa705cedf9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -104,9 +104,12 @@ int nr_is_dci_opportunity(nfapi_nr_search_space_t search_space, nfapi_nr_config_request_scf_t cfg); */ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, - NR_PUCCH_ResourceId_t pucch_ResourceId, NR_ServingCellConfigCommon_t *scc, - NR_BWP_Uplink_t *bwp); + NR_BWP_Uplink_t *bwp, + uint8_t pucch_resource, + uint16_t O_uci, + uint16_t O_ack, + uint8_t SR_flag); void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, int ss_type, NR_ServingCellConfigCommon_t *scc, From b1d259663ed0446042020e2f9984948433a3a3df Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Tue, 4 Feb 2020 15:36:47 +0100 Subject: [PATCH 092/175] configuration of pucch0 rx from fapi structure --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 50 +++++++++++-------------- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h | 18 +++------ 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 940f3aee71..e89c6739da 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -18,27 +18,25 @@ #include "T.h" -void nr_decode_pucch0( int32_t **rxdataF, - pucch_GroupHopping_t pucch_GroupHopping, - uint32_t n_id, // hoppingID higher layer parameter - uint64_t *payload, - NR_DL_FRAME_PARMS *frame_parms, - int16_t amp, - int nr_tti_tx, - uint8_t m0, // should come from resource set - uint8_t nrofSymbols, // should come from resource set - uint8_t startingSymbolIndex, // should come from resource set - uint16_t startingPRB, // should come from resource set - uint8_t nr_bit) { // is number of UCI bits to be decoded +void nr_decode_pucch0(int32_t **rxdataF, + uint64_t *payload, + NR_DL_FRAME_PARMS *frame_parms, + int slot, + int16_t amp, + nfapi_nr_pucch_pdu_t* pucch_pdu) { + int nr_sequences; const uint8_t *mcs; - if(nr_bit==1){ + + pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); + + if(pucch_pdu->bit_len_harq==1){ mcs=table1_mcs; - nr_sequences=4; + nr_sequences=4>>(1-pucch_pdu->sr_flag); } else{ mcs=table2_mcs; - nr_sequences=8; + nr_sequences=8>>(1-pucch_pdu->sr_flag); } /* * Implement TS 38.211 Subclause 6.3.2.3.1 Sequence generation @@ -53,8 +51,6 @@ void nr_decode_pucch0( int32_t **rxdataF, //uint8_t lnormal; // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] //uint8_t lprime; - // mcs is provided by TC 38.213 subclauses 9.2.3, 9.2.4, 9.2.5 FIXME! - //uint8_t mcs; /* * in TS 38.213 Subclause 9.2.1 it is said that: @@ -73,19 +69,17 @@ void nr_decode_pucch0( int32_t **rxdataF, // if frequency hopping is enabled by the higher-layer parameter PUCCH-frequency-hopping // n_hop = 0 for first hop // n_hop = 1 for second hop - uint8_t n_hop = 0; - //uint8_t PUCCH_Frequency_Hopping; // from higher layers FIXME!! + uint8_t n_hop = 0; // Frequnecy hopping not implemented FIXME!! // x_n contains the sequence r_u_v_alpha_delta(n) int16_t x_n_re[nr_sequences][24],x_n_im[nr_sequences][24]; int n,i,l; for(i=0;inr_of_symbols; l++){ + + nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,n_hop,slot,&u,&v); // calculating u and v value + alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id,pucch_pdu->initial_cyclic_shift,mcs[i],l,pucch_pdu->start_symbol_index,slot); #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d)\n",u,v,alpha,l); #endif @@ -108,10 +102,10 @@ void nr_decode_pucch0( int32_t **rxdataF, uint32_t re_offset=0; uint8_t l2; - for (l=0; lnr_of_symbols; l++) { - l2 = l+startingSymbolIndex; - re_offset = (12*startingPRB) + frame_parms->first_carrier_offset; + l2 = l+pucch_pdu->start_symbol_index; + re_offset = (12*pucch_pdu->prb_start) + frame_parms->first_carrier_offset; if (re_offset>= frame_parms->ofdm_symbol_size) re_offset-=frame_parms->ofdm_symbol_size; @@ -135,7 +129,7 @@ void nr_decode_pucch0( int32_t **rxdataF, memset(corr_re,0,nr_sequences*sizeof(double)); memset(corr_im,0,nr_sequences*sizeof(double)); for(i=0;inr_of_symbols;l++){ for(n=0;n<12;n++){ corr_re[i]+= (double)(r_re[12*l+n])/32767*(double)(x_n_re[i][12*l+n])/32767+(double)(r_im[12*l+n])/32767*(double)(x_n_im[i][12*l+n])/32767; corr_im[i]+= (double)(r_re[12*l+n])/32767*(double)(x_n_im[i][12*l+n])/32767-(double)(r_im[12*l+n])/32767*(double)(x_n_re[i][12*l+n])/32767; diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index fbc193e7b1..a33972aaa7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -57,18 +57,12 @@ void nr_decode_pucch1( int32_t **rxdataF, uint8_t timeDomainOCC, uint8_t nr_bit); -void nr_decode_pucch0( int32_t **rxdataF, - pucch_GroupHopping_t PUCCH_GroupHopping, - uint32_t n_id, //PHY_VARS_gNB *gNB, generally rxdataf is in gNB->common_vars - uint64_t *payload, - NR_DL_FRAME_PARMS *frame_parms, - int16_t amp, - int nr_tti_tx, - uint8_t m0, // should come from resource set - uint8_t nrofSymbols, // should come from resource set - uint8_t startingSymbolIndex, // should come from resource set - uint16_t startingPRB, // should come from resource set - uint8_t nr_bit); +void nr_decode_pucch0(int32_t **rxdataF, + uint64_t *payload, + NR_DL_FRAME_PARMS *frame_parms, + int slot, + int16_t amp, + nfapi_nr_pucch_pdu_t* pucch_pdu); void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, uint32_t n_id, From 5320469402fc9e344895e20a024b1199cd0d7185 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Wed, 5 Feb 2020 18:05:18 +0100 Subject: [PATCH 093/175] scheduling of PUCCH on MAC, passing PUCCH FAPI down to PHY (to be finished), filling DCI structures according to PUCCH (to be finished) --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 15 ++-- openair2/LAYER2/NR_MAC_gNB/config.c | 3 - openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 82 +++++++++++++++++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 22 ++--- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 62 +++++++++++++- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 13 ++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 18 ++-- 7 files changed, 176 insertions(+), 39 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 910e60b36e..da80fa4640 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -347,15 +347,13 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { nfapi_nr_ul_tti_request_t *UL_tti_req = &gNB->UL_tti_req; - int num_pusch_pdu = UL_tti_req->n_pdus; + int num_pdus = UL_tti_req->n_pdus; - LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d, num_pusch_pdu %d\n",frame_rx,slot_rx,num_pusch_pdu); + LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d, num_pdus %d\n",frame_rx,slot_rx,num_pdus); - for (int i = 0; i < num_pusch_pdu; i++) { - + for (int i = 0; i < num_pdus; i++) { switch (UL_tti_req->pdus_list[i].pdu_type) { - case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: - { + case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE\n",frame_rx,slot_rx); nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu; @@ -373,7 +371,10 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) //LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); nr_fill_rx_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); // indicate SDU to MAC - } + break; + case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: + LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE\n",frame_rx,slot_rx); + break; } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index d7d72fb6fd..2201e4f991 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -50,7 +50,6 @@ extern RAN_CONTEXT_t RC; //extern int l2_init_gNB(void); extern void mac_top_init_gNB(void); extern uint8_t nfapi_mode; -uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160}; void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) { @@ -281,8 +280,6 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm else LOG_I(PHY,"TDD has been properly configurated\n"); } - RC.nrmac[Mod_idP]->common_channels[0].num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])>>(7-cfg->tdd_table.tdd_period.value); - /* // PDCCH-ConfigCommon cfg->pdcch_config.controlResourceSetZero.value = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index c9b63fe25c..6f3f7a7f65 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -70,6 +70,8 @@ extern uint8_t nfapi_mode; uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; +uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160}; + void clear_nr_nfapi_information(gNB_MAC_INST * gNB, int CC_idP, frame_t frameP, @@ -308,6 +310,61 @@ void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) } */ +void nr_schedule_pucch(int Mod_idP, + int UE_id, + frame_t frameP, + sub_frame_t slotP) { + + uint16_t O_uci; + uint16_t O_ack; + uint8_t SR_flag = 0; // no SR in PUCCH implemented for now + uint8_t pucch_resource = 0; // in PHY test only one UE -> only one PUCCH resource used + NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; + NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; + AssertFatal(UE_list->active[UE_id] >=0,"Cannot find UE_id %d is not active\n",UE_id); + + NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id]; + int bwp_id=1; + NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]; + nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0]; + + NR_sched_pucch *curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch; + NR_sched_pucch *temp_pucch; + int release_pucch = 0; + + if (curr_pucch != NULL) { + if ((frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) { + UL_tti_req->SFN = frameP; + UL_tti_req->Slot = slotP; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t); + nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu; + memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t)); + UL_tti_req->n_pdus+=1; + + O_ack = curr_pucch->dai_c; + O_uci = O_ack; // for now we are just sending acknacks in pucch + + nr_configure_pucch(pucch_pdu, + scc, + ubwp, + pucch_resource, + O_uci, + O_ack, + SR_flag); + + release_pucch = 1; + } + } + + if (release_pucch) { + temp_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch; + UE_list->UE_sched_ctrl[UE_id].sched_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch->next_sched_pucch; + free(temp_pucch); + } + +} + bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){ if((bitmap>>slot)&0x01) @@ -329,10 +386,13 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, int UE_id; uint64_t *dlsch_in_slot_bitmap=NULL; uint64_t *ulsch_in_slot_bitmap=NULL; - + NR_sched_pucch *pucch_sched = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch)); + if (phy_test) UE_id=0; NR_COMMON_channels_t *cc = RC.nrmac[module_idP]->common_channels; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + int num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])>>(7-scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity); //nfapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = NULL; @@ -346,11 +406,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, RC.nrmac[module_idP]->slot = slot_rxP; if (phy_test) { - dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.dlsch_in_slot_bitmap[UE_id]; // static bitmap signaling which slot in a tdd period contains dlsch - ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.ulsch_in_slot_bitmap[UE_id]; // static bitmap signaling which slot in a tdd period contains ulsch + dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch + ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch // hardcoding dlsch to be in slot 1 - if (!(slot_txP%cc->num_slots_per_tdd)) { + if (!(slot_txP%num_slots_per_tdd)) { if(slot_txP==0) *dlsch_in_slot_bitmap = 0x02; else @@ -358,7 +418,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } // hardcoding ulsch to be in slot 8 - if (!(slot_rxP%cc->num_slots_per_tdd)) { + if (!(slot_rxP%num_slots_per_tdd)) { if(slot_rxP==0) *ulsch_in_slot_bitmap = 0x100; else @@ -403,8 +463,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } // Phytest scheduling - if (phy_test && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%cc->num_slots_per_tdd))) { - nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP,NULL); + if (phy_test && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%num_slots_per_tdd))) { + nr_update_pucch_scheduling(module_idP, UE_id, frame_txP, slot_txP, num_slots_per_tdd,pucch_sched); + nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL); } /* @@ -416,8 +477,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } //is_nr_DL_slot if (is_nr_UL_slot(cc->ServingCellConfigCommon,slot_rxP)) { - if (phy_test && (is_xlsch_in_slot(*ulsch_in_slot_bitmap,slot_rxP%cc->num_slots_per_tdd))){ - nr_schedule_uss_ulsch_phytest(module_idP, frame_rxP, slot_rxP); + if (phy_test) { + nr_schedule_pucch(module_idP, UE_id, frame_rxP, slot_rxP); + if (is_xlsch_in_slot(*ulsch_in_slot_bitmap,slot_rxP%num_slots_per_tdd)){ + nr_schedule_uss_ulsch_phytest(module_idP, frame_rxP, slot_rxP); + } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 2fe553a055..1d286742de 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -247,9 +247,11 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP, } int configure_fapi_dl_Tx(int Mod_idP, + sub_frame_t slotP, int *CCEIndex, nfapi_nr_dl_tti_request_body_t *dl_req, nfapi_nr_pdu_t *TX_req, + NR_sched_pucch *pucch_sched, uint8_t *mcsIndex, uint16_t *rbSize, uint16_t *rbStart) { @@ -350,10 +352,10 @@ int configure_fapi_dl_Tx(int Mod_idP, dci_pdu_rel15[0].ndi = 1; dci_pdu_rel15[0].rv = 0; dci_pdu_rel15[0].harq_pid = 0; - dci_pdu_rel15[0].dai = 2; + dci_pdu_rel15[0].dai = (pucch_sched->dai_c)&3; dci_pdu_rel15[0].tpc = 2; - dci_pdu_rel15[0].pucch_resource_indicator = 7; - dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = 7; + dci_pdu_rel15[0].pucch_resource_indicator = 7; //FIXME + dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->ul_slot - slotP; //FIXME put check on validity of indicator depending on type of DCI LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n", dci_pdu_rel15[0].frequency_domain_assignment, @@ -373,9 +375,6 @@ int configure_fapi_dl_Tx(int Mod_idP, scc, bwp); - - - pdcch_pdu_rel15->numDlDci = 1; pdcch_pdu_rel15->AggregationLevel[0] = 4; pdcch_pdu_rel15->RNTI[0]=UE_list->rnti[0]; @@ -466,15 +465,16 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, + NR_sched_pucch *pucch_sched, nfapi_nr_dl_tti_pdsch_pdu_rel15_t *dlsch_config) { LOG_D(MAC, "In nr_schedule_uss_dlsch_phytest \n"); - - gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; + + gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; //NR_COMMON_channels_t *cc = nr_mac->common_channels; //NR_ServingCellConfigCommon_t *scc=cc->ServingCellConfigCommon; nfapi_nr_dl_tti_request_body_t *dl_req; - nfapi_nr_pdu_t *TX_req; + nfapi_nr_pdu_t *TX_req; int TBS; int TBS_bytes; @@ -630,9 +630,11 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, CCEIndices[0] = CCEIndex; TBS_bytes = configure_fapi_dl_Tx(module_idP, + slotP, CCEIndices, dl_req, TX_req, + pucch_sched, dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL, dlsch_config!=NULL ? &dlsch_config->rbSize : NULL, dlsch_config!=NULL ? &dlsch_config->rbStart : NULL); @@ -670,7 +672,7 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, int CCEIndices[2]; CCEIndices[0] = CCEIndex; LOG_D(MAC,"Configuring DL_TX in %d.%d\n",frameP,slotP); - TBS_bytes = configure_fapi_dl_Tx(module_idP,CCEIndices,dl_req, TX_req, + TBS_bytes = configure_fapi_dl_Tx(module_idP,slotP,CCEIndices,dl_req, TX_req, pucch_sched, dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL, dlsch_config!=NULL ? &dlsch_config->rbSize : NULL, dlsch_config!=NULL ? &dlsch_config->rbStart : NULL); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 93b525a308..61e1e42250 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -655,6 +655,8 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, if (pucchres->pucch_ResourceId == *resource_id) { res_found = 1; pucch_pdu->prb_start = pucchres->startingPRB; + // FIXME why there is only one frequency hopping flag + // what about inter slot frequency hopping? pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ? 1 : 0; pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ? *pucchres->secondHopPRB : 0; switch(pucchres->format.present) { @@ -732,8 +734,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, dci_pdu_rel15_t *dci_pdu_rel15, int *dci_formats, - int *rnti_types - ) { + int *rnti_types) { uint16_t N_RB = pdcch_pdu_rel15->BWPSize; uint8_t fsize=0, pos=0; @@ -1245,6 +1246,63 @@ int add_new_nr_ue(module_id_t mod_idP, return -1; } +// function to update pucch scheduling parameters in UE list when a USS DL is scheduled +void nr_update_pucch_scheduling(int Mod_idP, + int UE_id, + frame_t frameP, + sub_frame_t slotP, + int slots_per_tdd, + NR_sched_pucch *sched_pucch) { + + NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; + NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; + int first_ul_slot_tdd,next_slot; + NR_sched_pucch *curr_pucch; + + // if the list of pucch to be scheduled is empty + if (UE_list->UE_sched_ctrl[UE_id].sched_pucch == NULL) { + sched_pucch->frame = frameP; + sched_pucch->next_sched_pucch = NULL; + sched_pucch->dai_c = 1; + if ( (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots!=0) || (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)) { + // first pucch occasion in first UL or MIXED slot + first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; + // computing slot in which pucch is scheduled + sched_pucch->ul_slot = first_ul_slot_tdd + slotP - (slotP % slots_per_tdd); + } + else + AssertFatal(1==0,"No Uplink Slots in this Frame\n"); + + UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch; + } + else { + curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch; + while (curr_pucch->next_sched_pucch != NULL) + curr_pucch = curr_pucch->next_sched_pucch; + // we are scheduling at most 11 ack nacks in the same pucch + if (curr_pucch->dai_c==11) { + next_slot = curr_pucch->ul_slot + 1; + if (next_slot == slots_per_tdd) + AssertFatal(1==0,"No more slots in this TDD period\n"); + else { + // generating a new item in the list + sched_pucch->frame = frameP; + sched_pucch->next_sched_pucch = NULL; + sched_pucch->dai_c = 1; + sched_pucch->ul_slot = next_slot; + curr_pucch->next_sched_pucch = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch)); + curr_pucch->next_sched_pucch = sched_pucch; + } + } + else { + sched_pucch = curr_pucch; + sched_pucch->dai_c = 1 + sched_pucch->dai_c; + } + } + +} + + /*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg, nfapi_nr_coreset_t *coreset, nfapi_nr_search_space_t *search_space) { diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index aa705cedf9..ca3b19107d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -68,9 +68,11 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP, sub_frame_t subframeP); int configure_fapi_dl_Tx(int Mod_id, + sub_frame_t slotP, int *CCEIndeces, nfapi_nr_dl_tti_request_body_t *dl_req, nfapi_nr_pdu_t *TX_req, + NR_sched_pucch *pucch_sched, uint8_t *mcsIndex, uint16_t *rbSize, uint16_t *rbStart); @@ -79,11 +81,19 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,nfapi_nr_pusch_pdu_t *pusch_pdu,nfapi_nr void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, + NR_sched_pucch *pucch_sched, nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_config); void nr_schedule_uss_ulsch_phytest(int Mod_idP, frame_t frameP, sub_frame_t slotP); + +void nr_update_pucch_scheduling(int Mod_idP, + int UE_id, + frame_t frameP, + sub_frame_t slotP, + int slots_per_tdd, + NR_sched_pucch *sched_pucch); void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, nr_scs_e scs_common, @@ -117,8 +127,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, dci_pdu_rel15_t *dci_pdu_rel15, int *dci_formats, - int *rnti_types - ); + int *rnti_types); int get_spf(nfapi_nr_config_request_scf_t *cfg); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index b9df20d4c2..10b5e49d36 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -98,13 +98,21 @@ typedef struct { uint8_t vrb_map_UL[100]; /// number of subframe allocation pattern available for MBSFN sync area uint8_t num_sf_allocation_pattern; - /// number of slots per TDD period - uint8_t num_slots_per_tdd; } NR_COMMON_channels_t; -/*! \brief scheduling control information set through an API (not used)*/ +typedef struct NR_sched_pucch { + int frame; + int ul_slot; + uint8_t dai_c; + uint8_t dai_t; + struct NR_sched_pucch *next_sched_pucch; +} NR_sched_pucch; + +/*! \brief scheduling control information set through an API */ typedef struct { - int dummy; + uint64_t dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch + uint64_t ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch + NR_sched_pucch *sched_pucch; } NR_UE_sched_ctrl_t; /*! \brief UE list used by eNB to order UEs/CC for scheduling*/ @@ -122,8 +130,6 @@ typedef struct { boolean_t active[MAX_MOBILES_PER_GNB]; rnti_t rnti[MAX_MOBILES_PER_GNB]; NR_CellGroupConfig_t *secondaryCellGroup[MAX_MOBILES_PER_GNB]; - uint64_t dlsch_in_slot_bitmap[MAX_MOBILES_PER_GNB]; // static bitmap signaling which slot in a tdd period contains dlsch - uint64_t ulsch_in_slot_bitmap[MAX_MOBILES_PER_GNB]; // static bitmap signaling which slot in a tdd period contains ulsch } NR_UE_list_t; /*! \brief top level gNB MAC structure */ From 255d32389ca51888955457e06d48e89fde8e6498 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 6 Feb 2020 11:01:54 +0100 Subject: [PATCH 094/175] real time ok in monolithic cases, phy test tools fixed --- cmake_targets/CMakeLists.txt | 4 +++- common/utils/threadPool/thread-pool.h | 6 +++--- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 1 + openair1/SIMULATION/LTE_PHY/dlsim.c | 4 ++++ openair1/SIMULATION/LTE_PHY/ulsim.c | 4 ++++ targets/RT/USER/lte-softmodem.c | 14 ++++++++++++-- 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index d45f655561..e2c58033d2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -186,7 +186,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${CMAKE_CU # these changes are related to hardcoded path to include .h files set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -Og") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -Og") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3") set(GIT_BRANCH "UNKNOWN") set(GIT_COMMIT_HASH "UNKNOWN") @@ -2449,6 +2449,7 @@ add_executable(lte-softmodem ${OPENAIR_TARGETS}/RT/USER/ru_control.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c + ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c @@ -2828,6 +2829,7 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr add_executable(${myExe} ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c + ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c ${OPENAIR_DIR}/common/utils/backtrace.c ${OPENAIR_DIR}/common/utils/system.c ${XFORMS_SOURCE} diff --git a/common/utils/threadPool/thread-pool.h b/common/utils/threadPool/thread-pool.h index 9a2681a828..1b59fb1589 100644 --- a/common/utils/threadPool/thread-pool.h +++ b/common/utils/threadPool/thread-pool.h @@ -217,11 +217,11 @@ static inline void pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg) { static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) { notifiedFIFO_elt_t *msg= pullNotifiedFIFO(responseFifo); - + AssertFatal(t->traceFd, "Thread pool used while not initialized"); if (t->measurePerf) msg->returnTime=rdtsc(); - if (t->traceFd >= 0) + if (t->traceFd > 0) if(write(t->traceFd, msg, sizeof(*msg))); return msg; @@ -229,7 +229,7 @@ static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_ static inline notifiedFIFO_elt_t *tryPullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) { notifiedFIFO_elt_t *msg= pollNotifiedFIFO(responseFifo); - + AssertFatal(t->traceFd, "Thread pool used while not initialized"); if (msg == NULL) return NULL; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 1eea6474f3..408da13718 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -11,6 +11,7 @@ #include "stddef.h" #include "nfapi_interface.h" +#include #define NFAPI_NR_MAX_NB_CCE_AGGREGATION_LEVELS 5 #define NFAPI_NR_MAX_NB_TCI_STATES_PDCCH 64 diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index a47a174702..d8ac505d14 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1266,6 +1266,10 @@ int main(int argc, char **argv) { } L1_rxtx_proc_t *proc_eNB = &eNB->proc.L1_proc; + initTpool("n", &proc_eNB->threadPool, true); + initNotifiedFIFO(&proc_eNB->respEncode); + initNotifiedFIFO(&proc_eNB->respDecode); + proc_eNB->frame_tx=0; if (input_fd==NULL) { diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 0459109a7c..34237771aa 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -793,6 +793,10 @@ int main(int argc, char **argv) { proc_rxtx_ue->frame_rx = (subframe<4)?(proc_rxtx->frame_tx-1):(proc_rxtx->frame_tx); proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; proc_rxtx_ue->subframe_rx = (proc_rxtx->subframe_tx+6)%10; + initTpool("n", &proc_rxtx->threadPool, true); + initNotifiedFIFO(&proc_rxtx->respEncode); + initNotifiedFIFO(&proc_rxtx->respDecode); + printf("Init UL hopping UE\n"); init_ul_hopping(&UE->frame_parms); printf("Init UL hopping eNB\n"); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 737b7d02b4..a06797ee4b 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -665,9 +665,19 @@ int main ( int argc, char **argv ) if (RC.nb_L1_inst > 0) { printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", get_softmodem_params()->single_thread_flag,get_softmodem_params()->wait_for_sync); init_eNB(get_softmodem_params()->single_thread_flag,get_softmodem_params()->wait_for_sync); - // for (inst=0;instproc.L1_proc; + if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) + initTpool(get_softmodem_params()->threadPoolConfig, &L1proc->threadPool, true); + else + initTpool("n", &L1proc->threadPool, true); + initNotifiedFIFO(&L1proc->respEncode); + initNotifiedFIFO(&L1proc->respDecode); + } + + } printf("wait_eNBs()\n"); From 3e5682d8bb261db1fcb19894ac5aa20b98c0ff99 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Mon, 10 Feb 2020 10:11:45 +0100 Subject: [PATCH 095/175] including uci indication --- cmake_targets/CMakeLists.txt | 4 +- executables/nr-gnb.c | 4 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 37 ++-- openair1/PHY/NR_TRANSPORT/nr_transport.h | 22 +++ .../NR_TRANSPORT/nr_transport_common_proto.h | 12 ++ .../PHY/NR_TRANSPORT/nr_uci_tools_common.c | 167 ++++++++++++++++++ openair1/PHY/NR_TRANSPORT/pucch_rx.c | 42 +++-- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c | 136 +------------- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h | 33 ---- openair1/PHY/defs_gNB.h | 15 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 33 +++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 6 +- 12 files changed, 289 insertions(+), 222 deletions(-) create mode 100644 openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 808efee345..f5e23f7383 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1361,7 +1361,8 @@ set(PHY_SRC_UE ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} ${PHY_LDPCSRC} - ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c + ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c + ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c ) set(PHY_NR_UE_SRC @@ -1387,6 +1388,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dci_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dci_tools_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/pucch_nr.c + ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index c6f71024aa..318ec73621 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -966,12 +966,12 @@ void init_gNB(int single_thread_flag,int wait_for_sync) { gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO)); LOG_I(PHY,"Setting indication lists\n"); - gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = gNB->rx_pdu_list; + /*gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = gNB->rx_pdu_list; gNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = gNB->crc_pdu_list; gNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = gNB->sr_pdu_list; gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list; gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list; - gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list; + gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list;*/ gNB->prach_energy_counter = 0; } diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index ee1550a5bb..941150be4d 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -19,6 +19,7 @@ #define NFAPI_MAX_NUM_UL_UE_PER_GROUP 6 #define NFAPI_MAX_NUM_UL_PDU 8 +#define NFAPI_MAX_NUM_UCI_INDICATION 8 #define NFAPI_MAX_NUM_GROUPS 8 #define NFAPI_MAX_NUM_CB 8 @@ -1519,8 +1520,8 @@ typedef struct uint8_t ul_cqi; uint16_t timing_advance; uint16_t rssi; - nfapi_nr_sr_pdu_0_1_t sr;//67 - nfapi_nr_harq_pdu_0_1_t harq;//68 + nfapi_nr_sr_pdu_0_1_t *sr;//67 + nfapi_nr_harq_pdu_0_1_t *harq;//68 }nfapi_nr_uci_pucch_pdu_format_0_1_t; @@ -1542,28 +1543,22 @@ typedef struct }nfapi_nr_uci_pucch_pdu_format_2_3_4_t; -//for SR, HARQ and CSI Part 1/ 2 PDUs +typedef enum { + NFAPI_NR_UCI_PDCCH_PDU_TYPE = 0, + NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE = 1, + NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE = 2, +} nfapi_nr_uci_pdu_type_e; typedef struct { - nfapi_nr_uci_pusch_pdu_t* pusch_pdu; - nfapi_nr_uci_pucch_pdu_format_0_1_t* pucch_pdu_format_0_1; - nfapi_nr_uci_pucch_pdu_format_2_3_4_t* pucch_pdu_format_2_3_4; - nfapi_nr_sr_pdu_0_1_t* sr_pdu_0_1; - nfapi_nr_sr_pdu_2_3_4_t* sr_pdu_2_3_4; - nfapi_nr_harq_pdu_0_1_t* harq_pdu_0_1; - nfapi_nr_harq_pdu_2_3_4_t* harq_pdu_2_3_4; - nfapi_nr_csi_part1_pdu_t* csi_part1_pdu; - nfapi_nr_csi_part2_pdu_t* csi_part2_pdu; - -} nfapi_nr_uci_pdu_information_t; - -typedef struct -{ - uint16_t pdu_type; + uint16_t pdu_type; // 0 for PDU on PUSCH, 1 for PUCCH format 0 or 1, 2 for PUCCH format 2 to 4 uint16_t pdu_size; - nfapi_nr_uci_pdu_information_t uci_pdu; - + union + { + nfapi_nr_uci_pusch_pdu_t pusch_pdu; + nfapi_nr_uci_pucch_pdu_format_0_1_t pucch_pdu_format_0_1; + nfapi_nr_uci_pucch_pdu_format_2_3_4_t pucch_pdu_format_2_3_4; + }; } nfapi_nr_uci_t; typedef struct @@ -1571,7 +1566,7 @@ typedef struct uint16_t sfn; uint16_t slot; uint16_t num_ucis; - nfapi_nr_uci_t* uci_list; + nfapi_nr_uci_t uci_list[NFAPI_MAX_NUM_UCI_INDICATION]; } nfapi_nr_uci_indication_t; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport.h b/openair1/PHY/NR_TRANSPORT/nr_transport.h index be73875058..ba0791d33a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport.h @@ -123,4 +123,26 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); +void nr_decode_pucch1(int32_t **rxdataF, + pucch_GroupHopping_t pucch_GroupHopping, + uint32_t n_id, // hoppingID higher layer parameter + uint64_t *payload, + NR_DL_FRAME_PARMS *frame_parms, + int16_t amp, + int nr_tti_tx, + uint8_t m0, + uint8_t nrofSymbols, + uint8_t startingSymbolIndex, + uint16_t startingPRB, + uint16_t startingPRB_intraSlotHopping, + uint8_t timeDomainOCC, + uint8_t nr_bit); + +void nr_decode_pucch0(int32_t **rxdataF, + NR_DL_FRAME_PARMS *frame_parms, + int slot, + nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu, + nfapi_nr_pucch_pdu_t* pucch_pdu); + + #endif /*__NR_TRANSPORT__H__*/ diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h index 762346048f..85f3c00b90 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h @@ -41,7 +41,19 @@ #define NR_PUSCH_y 3 // UCI placeholder bit +void nr_group_sequence_hopping(pucch_GroupHopping_t PUCCH_GroupHopping, + uint32_t n_id, + uint8_t n_hop, + int nr_tti_tx, + uint8_t *u, + uint8_t *v); +double nr_cyclic_shift_hopping(uint32_t n_id, + uint8_t m0, + uint8_t mcs, + uint8_t lnormal, + uint8_t lprime, + int nr_tti_tx); /** \brief Computes available bits G. */ diff --git a/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c b/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c new file mode 100644 index 0000000000..2b0cbe72b3 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c @@ -0,0 +1,167 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/NR_TRANSPORT/nr_dci_tools_common.c + * \brief + * \author + * \date 2020 + * \version 0.1 + * \company Eurecom + * \email: + * \note + * \warning + */ + +#include "nr_dci.h" + +void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, + uint32_t n_id, + uint8_t n_hop, + int nr_tti_tx, + uint8_t *u, + uint8_t *v) { + /* + * Implements TS 38.211 subclause 6.3.2.2.1 Group and sequence hopping + * The following variables are set by higher layers: + * - PUCCH_GroupHopping: + * - n_id: higher-layer parameter hoppingId + * - n_hop: frequency hopping index + * if intra-slot frequency hopping is disabled by the higher-layer parameter PUCCH-frequency-hopping + * n_hop=0 + * if frequency hopping is enabled by the higher-layer parameter PUCCH-frequency-hopping + * n_hop=0 for the first hop + * n_hop=1 for the second hop + */ + // depending on the value of the PUCCH_GroupHopping, we will obtain different values for u,v + //pucch_GroupHopping_t PUCCH_GroupHopping = ue->pucch_config_common_nr->pucch_GroupHopping; // from higher layers FIXME!!! + // n_id defined as per TS 38.211 subclause 6.3.2.2.1 (is given by the higher-layer parameter hoppingId) + // it is hoppingId from PUCCH-ConfigCommon: + // Cell-Specific scrambling ID for group hoppping and sequence hopping if enabled + // Corresponds to L1 parameter 'HoppingID' (see 38.211, section 6.3.2.2) BIT STRING (SIZE (10)) + //uint16_t n_id = ue->pucch_config_common_nr->hoppingId; // from higher layers FIXME!!! +#ifdef DEBUG_NR_PUCCH_TX + printf("\t\t [nr_group_sequence_hopping] PUCCH_GroupHopping=%u, n_id=%u \n",PUCCH_GroupHopping,n_id); +#endif + uint8_t f_ss=0,f_gh=0; + *u=0; + *v=0; + uint32_t c_init = 0; + uint32_t x1,s; // TS 38.211 Subclause 5.2.1 + int l = 32, minShift = ((2*nr_tti_tx+n_hop)<<3); + int tmpShift =0; +#ifdef DEBUG_NR_PUCCH_TX + printf("\t\t [nr_group_sequence_hopping] calculating u,v -> "); +#endif + + if (PUCCH_GroupHopping == neither) { // PUCCH_GroupHopping 'neither' + f_ss = n_id%30; + } + + if (PUCCH_GroupHopping == enable) { // PUCCH_GroupHopping 'enabled' + c_init = floor(n_id/30); // we initialize c_init to calculate u,v according to 6.3.2.2.1 of 38.211 + s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 + for (int m=0; m<8; m++) { + while(minShift >= l) { + s = lte_gold_generic(&x1, &c_init, 0); + l = l+32; + } + + tmpShift = (minShift&((1<<5)-1)); //minShift%32; + f_gh = f_gh + ((1<>tmpShift)&1))); + minShift ++; + } + + f_gh = f_gh%30; + f_ss = n_id%30; + /* for (int m=0; m<8; m++){ + f_gh = f_gh + ((1<>(8*(2*nr_tti_tx+n_hop)+m))&1))); // Not sure we have to use nr_tti_tx FIXME!!! + } + f_gh = f_gh%30; + f_ss = n_id%30;*/ + } + + if (PUCCH_GroupHopping == disable) { // PUCCH_GroupHopping 'disabled' + c_init = (1<<5)*floor(n_id/30)+(n_id%30); // we initialize c_init to calculate u,v + s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 + f_ss = n_id%30; + l = 32, minShift = (2*nr_tti_tx+n_hop); + + while(minShift >= l) { + s = lte_gold_generic(&x1, &c_init, 0); + l = l+32; + } + + tmpShift = (minShift&((1<<5)-1)); //minShift%32; + *v = (uint8_t)((s>>tmpShift)&1); + // *v = (uint8_t)((s>>(2*nr_tti_tx+n_hop))&1); // Not sure we have to use nr_tti_tx FIXME!!! + } + + *u = (f_gh+f_ss)%30; +#ifdef DEBUG_NR_PUCCH_TX + printf("%d,%d\n",*u,*v); +#endif +} + +double nr_cyclic_shift_hopping(uint32_t n_id, + uint8_t m0, + uint8_t mcs, + uint8_t lnormal, + uint8_t lprime, + int nr_tti_tx) { + /* + * Implements TS 38.211 subclause 6.3.2.2.2 Cyclic shift hopping + * - n_id: higher-layer parameter hoppingId + * - m0: provided by higher layer parameter PUCCH-F0-F1-initial-cyclic-shift of PUCCH-F0-resource-config + * - mcs: mcs=0 except for PUCCH format 0 when it depends on information to be transmitted according to TS 38.213 subclause 9.2 + * - lnormal: lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission + * - lprime: lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] + */ + // alpha_init initialized to 2*PI/12=0.5235987756 + double alpha = 0.5235987756; + uint32_t c_init = n_id; // we initialize c_init again to calculate n_cs + + uint32_t x1,s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 + uint8_t n_cs=0; + int l = 32, minShift = (14*8*nr_tti_tx )+ 8*(lnormal+lprime); + int tmpShift =0; +#ifdef DEBUG_NR_PUCCH_TX + printf("\t\t [nr_cyclic_shift_hopping] calculating alpha (cyclic shift) using c_init=%u -> \n",c_init); +#endif + + for (int m=0; m<8; m++) { + while(minShift >= l) { + s = lte_gold_generic(&x1, &c_init, 0); + l = l+32; + } + + tmpShift = (minShift&((1<<5)-1)); //minShift%32; + minShift ++; + n_cs = n_cs+((1<>tmpShift)&1))); + // calculating n_cs (Not sure we have to use nr_tti_tx FIXME!!!) + // n_cs = n_cs+((1<>((14*8*nr_tti_tx) + 8*(lnormal+lprime) + m))&1))); + } + + alpha = (alpha * (double)((m0+mcs+n_cs)%12)); +#ifdef DEBUG_NR_PUCCH_TX + printf("n_cs=%d -> %lf\n",n_cs,alpha); +#endif + return(alpha); +} diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index e89c6739da..c1e202994b 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -10,8 +10,8 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_nr_UE.h" #include "PHY/NR_UE_TRANSPORT/pucch_nr.h" -#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" - +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" @@ -19,10 +19,9 @@ void nr_decode_pucch0(int32_t **rxdataF, - uint64_t *payload, NR_DL_FRAME_PARMS *frame_parms, int slot, - int16_t amp, + nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu, nfapi_nr_pucch_pdu_t* pucch_pdu) { int nr_sequences; @@ -84,9 +83,9 @@ void nr_decode_pucch0(int32_t **rxdataF, printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d)\n",u,v,alpha,l); #endif for (n=0; n<12; n++){ - x_n_re[i][(12*l)+n] = (int16_t)((int32_t)(amp)*(int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) + x_n_re[i][(12*l)+n] = (int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)))>>15); // Re part of base sequence shifted by alpha - x_n_im[i][(12*l)+n] =(int16_t)((int32_t)(amp)* (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) + x_n_im[i][(12*l)+n] =(int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)))>>15); // Im part of base sequence shifted by alpha #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \tx_n(l=%d,n=%d)=(%d,%d)\n", @@ -97,7 +96,7 @@ void nr_decode_pucch0(int32_t **rxdataF, } int16_t r_re[24],r_im[24]; /* - * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources FIXME! + * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources */ uint32_t re_offset=0; uint8_t l2; @@ -114,8 +113,8 @@ void nr_decode_pucch0(int32_t **rxdataF, r_re[(12*l)+n]=((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[0]; r_im[(12*l)+n]=((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[1]; #ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", - amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,(l2*frame_parms->ofdm_symbol_size)+re_offset, + printf("\t [nr_generate_pucch0] mapping to RE \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", + frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,(l2*frame_parms->ofdm_symbol_size)+re_offset, l,n,((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[0], ((int16_t *)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset])[1]); #endif @@ -138,14 +137,35 @@ void nr_decode_pucch0(int32_t **rxdataF, corr[i]=corr_re[i]*corr_re[i]+corr_im[i]*corr_im[i]; } float max_corr=corr[0]; - int index=0; + uint8_t index=0; for(i=1;imax_corr){ index= i; max_corr=corr[i]; } } - *payload=(uint64_t)index; // payload bits 00..b3b2b0, b0 is the SR bit and b3b2 are HARQ bits + + // first bit of bitmap for sr presence and second bit for acknack presence + uci_pdu->pdu_bit_map = pucch_pdu->sr_flag | ((pucch_pdu->bit_len_harq>0)<<1); + uci_pdu->pucch_format = 0; // format 0 + uci_pdu->ul_cqi = 0xff; // currently not valid + uci_pdu->timing_advance = 0xffff; // currently not valid + uci_pdu->rssi = 0xffff; // currently not valid + if (pucch_pdu->sr_flag) { + //currently not supported + } + else + uci_pdu->sr = NULL; + if (pucch_pdu->bit_len_harq>0) { + uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq)); + uci_pdu->harq->num_harq = pucch_pdu->bit_len_harq; + uci_pdu->harq->harq_confidence_level = 0xff; // currently not valid + uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(uci_pdu->harq->num_harq); + for (i=0; iharq->num_harq; i++) // FIXME for non present + uci_pdu->harq->harq_list[i].harq_value = (index>>i)&0x01; + } + else + uci_pdu->harq = NULL; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index 148ee51a69..d63cef5085 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -37,7 +37,7 @@ //#include "LAYER2/MAC/extern.h" #include "PHY/NR_UE_TRANSPORT/pucch_nr.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" - +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" @@ -49,140 +49,6 @@ //#define ONE_OVER_SQRT2 23170 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2) -void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, - uint32_t n_id, - uint8_t n_hop, - int nr_tti_tx, - uint8_t *u, - uint8_t *v) { - /* - * Implements TS 38.211 subclause 6.3.2.2.1 Group and sequence hopping - * The following variables are set by higher layers: - * - PUCCH_GroupHopping: - * - n_id: higher-layer parameter hoppingId - * - n_hop: frequency hopping index - * if intra-slot frequency hopping is disabled by the higher-layer parameter PUCCH-frequency-hopping - * n_hop=0 - * if frequency hopping is enabled by the higher-layer parameter PUCCH-frequency-hopping - * n_hop=0 for the first hop - * n_hop=1 for the second hop - */ - // depending on the value of the PUCCH_GroupHopping, we will obtain different values for u,v - //pucch_GroupHopping_t PUCCH_GroupHopping = ue->pucch_config_common_nr->pucch_GroupHopping; // from higher layers FIXME!!! - // n_id defined as per TS 38.211 subclause 6.3.2.2.1 (is given by the higher-layer parameter hoppingId) - // it is hoppingId from PUCCH-ConfigCommon: - // Cell-Specific scrambling ID for group hoppping and sequence hopping if enabled - // Corresponds to L1 parameter 'HoppingID' (see 38.211, section 6.3.2.2) BIT STRING (SIZE (10)) - //uint16_t n_id = ue->pucch_config_common_nr->hoppingId; // from higher layers FIXME!!! -#ifdef DEBUG_NR_PUCCH_TX - printf("\t\t [nr_group_sequence_hopping] PUCCH_GroupHopping=%u, n_id=%u \n",PUCCH_GroupHopping,n_id); -#endif - uint8_t f_ss=0,f_gh=0; - *u=0; - *v=0; - uint32_t c_init = 0; - uint32_t x1,s; // TS 38.211 Subclause 5.2.1 - int l = 32, minShift = ((2*nr_tti_tx+n_hop)<<3); - int tmpShift =0; -#ifdef DEBUG_NR_PUCCH_TX - printf("\t\t [nr_group_sequence_hopping] calculating u,v -> "); -#endif - - if (PUCCH_GroupHopping == neither) { // PUCCH_GroupHopping 'neither' - f_ss = n_id%30; - } - - if (PUCCH_GroupHopping == enable) { // PUCCH_GroupHopping 'enabled' - c_init = floor(n_id/30); // we initialize c_init to calculate u,v according to 6.3.2.2.1 of 38.211 - s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 - for (int m=0; m<8; m++) { - while(minShift >= l) { - s = lte_gold_generic(&x1, &c_init, 0); - l = l+32; - } - - tmpShift = (minShift&((1<<5)-1)); //minShift%32; - f_gh = f_gh + ((1<>tmpShift)&1))); - minShift ++; - } - - f_gh = f_gh%30; - f_ss = n_id%30; - /* for (int m=0; m<8; m++){ - f_gh = f_gh + ((1<>(8*(2*nr_tti_tx+n_hop)+m))&1))); // Not sure we have to use nr_tti_tx FIXME!!! - } - f_gh = f_gh%30; - f_ss = n_id%30;*/ - } - - if (PUCCH_GroupHopping == disable) { // PUCCH_GroupHopping 'disabled' - c_init = (1<<5)*floor(n_id/30)+(n_id%30); // we initialize c_init to calculate u,v - s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 - f_ss = n_id%30; - l = 32, minShift = (2*nr_tti_tx+n_hop); - - while(minShift >= l) { - s = lte_gold_generic(&x1, &c_init, 0); - l = l+32; - } - - tmpShift = (minShift&((1<<5)-1)); //minShift%32; - *v = (uint8_t)((s>>tmpShift)&1); - // *v = (uint8_t)((s>>(2*nr_tti_tx+n_hop))&1); // Not sure we have to use nr_tti_tx FIXME!!! - } - - *u = (f_gh+f_ss)%30; -#ifdef DEBUG_NR_PUCCH_TX - printf("%d,%d\n",*u,*v); -#endif -} - -double nr_cyclic_shift_hopping(uint32_t n_id, - uint8_t m0, - uint8_t mcs, - uint8_t lnormal, - uint8_t lprime, - int nr_tti_tx) { - /* - * Implements TS 38.211 subclause 6.3.2.2.2 Cyclic shift hopping - * - n_id: higher-layer parameter hoppingId - * - m0: provided by higher layer parameter PUCCH-F0-F1-initial-cyclic-shift of PUCCH-F0-resource-config - * - mcs: mcs=0 except for PUCCH format 0 when it depends on information to be transmitted according to TS 38.213 subclause 9.2 - * - lnormal: lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission - * - lprime: lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] - */ - // alpha_init initialized to 2*PI/12=0.5235987756 - double alpha = 0.5235987756; - uint32_t c_init = n_id; // we initialize c_init again to calculate n_cs - - uint32_t x1,s = lte_gold_generic(&x1, &c_init, 1); // TS 38.211 Subclause 5.2.1 - uint8_t n_cs=0; - int l = 32, minShift = (14*8*nr_tti_tx )+ 8*(lnormal+lprime); - int tmpShift =0; -#ifdef DEBUG_NR_PUCCH_TX - printf("\t\t [nr_cyclic_shift_hopping] calculating alpha (cyclic shift) using c_init=%u -> \n",c_init); -#endif - - for (int m=0; m<8; m++) { - while(minShift >= l) { - s = lte_gold_generic(&x1, &c_init, 0); - l = l+32; - } - - tmpShift = (minShift&((1<<5)-1)); //minShift%32; - minShift ++; - n_cs = n_cs+((1<>tmpShift)&1))); - // calculating n_cs (Not sure we have to use nr_tti_tx FIXME!!!) - // n_cs = n_cs+((1<>((14*8*nr_tti_tx) + 8*(lnormal+lprime) + m))&1))); - } - - alpha = (alpha * (double)((m0+mcs+n_cs)%12)); -#ifdef DEBUG_NR_PUCCH_TX - printf("n_cs=%d -> %lf\n",n_cs,alpha); -#endif - return(alpha); -} - void nr_generate_pucch0(PHY_VARS_NR_UE *ue, int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index a33972aaa7..4c4847d7de 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -42,40 +42,7 @@ #include "T.h" #define ONE_OVER_SQRT2 23170 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2) -void nr_decode_pucch1( int32_t **rxdataF, - pucch_GroupHopping_t pucch_GroupHopping, - uint32_t n_id, // hoppingID higher layer parameter - uint64_t *payload, - NR_DL_FRAME_PARMS *frame_parms, - int16_t amp, - int nr_tti_tx, - uint8_t m0, - uint8_t nrofSymbols, - uint8_t startingSymbolIndex, - uint16_t startingPRB, - uint16_t startingPRB_intraSlotHopping, - uint8_t timeDomainOCC, - uint8_t nr_bit); -void nr_decode_pucch0(int32_t **rxdataF, - uint64_t *payload, - NR_DL_FRAME_PARMS *frame_parms, - int slot, - int16_t amp, - nfapi_nr_pucch_pdu_t* pucch_pdu); - -void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, - uint32_t n_id, - uint8_t n_hop, - int nr_tti_tx, - uint8_t *u, - uint8_t *v); -double nr_cyclic_shift_hopping(uint32_t n_id, - uint8_t m0, - uint8_t mcs, - uint8_t lnormal, - uint8_t lprime, - int nr_tti_tx); void nr_generate_pucch0(PHY_VARS_NR_UE *ue, int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 52aade312a..f5e41e00e8 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -605,23 +605,12 @@ typedef struct PHY_VARS_gNB_s { NR_UL_IND_t UL_INFO; pthread_mutex_t UL_INFO_mutex; - /// NFAPI RX ULSCH information - nfapi_rx_indication_pdu_t rx_pdu_list[NFAPI_RX_IND_MAX_PDU]; - /// NFAPI RX ULSCH CRC information - nfapi_crc_indication_pdu_t crc_pdu_list[NFAPI_CRC_IND_MAX_PDU]; - /// NFAPI HARQ information - nfapi_harq_indication_pdu_t harq_pdu_list[NFAPI_HARQ_IND_MAX_PDU]; - /// NFAPI SR information - nfapi_sr_indication_pdu_t sr_pdu_list[NFAPI_SR_IND_MAX_PDU]; - /// NFAPI CQI information - nfapi_cqi_indication_pdu_t cqi_pdu_list[NFAPI_CQI_IND_MAX_PDU]; - /// NFAPI CQI information (raw component) - nfapi_cqi_indication_raw_pdu_t cqi_raw_pdu_list[NFAPI_CQI_IND_MAX_PDU]; - /// NFAPI PRACH information + /// NFAPI PRACH information (to be removed) nfapi_preamble_pdu_t preamble_list[MAX_NUM_RX_PRACH_PREAMBLES]; //Sched_Rsp_t Sched_INFO; nfapi_nr_ul_tti_request_t UL_tti_req; + nfapi_nr_uci_indication_t uci_indication; nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu; nfapi_nr_ul_dci_request_pdus_t *ul_dci_pdu; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index da80fa4640..461da165f7 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -27,6 +27,7 @@ #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" +#include "PHY/NR_UE_TRANSPORT/pucch_nr.h" #include "SCHED/sched_eNB.h" #include "sched_nr.h" #include "SCHED/sched_common_extern.h" @@ -260,7 +261,7 @@ void nr_fill_rx_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_ // -------------------- // [hna] TO BE CLEANED // -------------------- - + // [FM] This structure is not SCF fapi structure and shouldn't be used // nfapi_rx_indication_pdu_t *pdu; int timing_advance_update; @@ -346,9 +347,14 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { - nfapi_nr_ul_tti_request_t *UL_tti_req = &gNB->UL_tti_req; + nfapi_nr_ul_tti_request_t *UL_tti_req = &gNB->UL_tti_req; int num_pdus = UL_tti_req->n_pdus; + nfapi_nr_uci_indication_t *uci_indication = &gNB->uci_indication; + uci_indication->sfn = frame_rx; + uci_indication->slot = slot_rx; + uci_indication->num_ucis = 0; + LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d, num_pdus %d\n",frame_rx,slot_rx,num_pdus); for (int i = 0; i < num_pdus; i++) { @@ -356,7 +362,7 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE\n",frame_rx,slot_rx); - nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu; + nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[i].pusch_pdu; nr_fill_ulsch(gNB,frame_rx,slot_rx,pusch_pdu); uint8_t ULSCH_id = find_nr_ulsch(pusch_pdu->rnti,gNB,SEARCH_EXIST); @@ -374,6 +380,27 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) break; case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE\n",frame_rx,slot_rx); + + nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[i].pucch_pdu; + switch (pucch_pdu->format_type) { + case 0: + uci_indication->uci_list[uci_indication->num_ucis].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; + uci_indication->uci_list[uci_indication->num_ucis].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); + nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci_indication->uci_list[uci_indication->num_ucis].pucch_pdu_format_0_1; + + nr_decode_pucch0(gNB->common_vars.rxdataF, + &gNB->frame_parms, + slot_rx, + uci_pdu_format0, + pucch_pdu); + + uci_indication->num_ucis += 1; + break; + case 1: + break; + default: + AssertFatal(1==0,"Only PUCCH format 0 and 1 are currently supported\n"); + } break; } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 1d286742de..6f299fa3d3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -352,10 +352,10 @@ int configure_fapi_dl_Tx(int Mod_idP, dci_pdu_rel15[0].ndi = 1; dci_pdu_rel15[0].rv = 0; dci_pdu_rel15[0].harq_pid = 0; - dci_pdu_rel15[0].dai = (pucch_sched->dai_c)&3; + dci_pdu_rel15[0].dai = (pucch_sched->dai_c-1)&3; dci_pdu_rel15[0].tpc = 2; - dci_pdu_rel15[0].pucch_resource_indicator = 7; //FIXME - dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->ul_slot - slotP; //FIXME put check on validity of indicator depending on type of DCI + dci_pdu_rel15[0].pucch_resource_indicator = 0; //FIXME this is fixed to 0 in phy test with only one user + dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->ul_slot - slotP; //FIXME check on validity of indicator depending on type of DCI LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n", dci_pdu_rel15[0].frequency_domain_assignment, From 795ed9a814cd23e130a6dad60a5ebfed61d5c825 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Mon, 10 Feb 2020 16:39:50 +0100 Subject: [PATCH 096/175] fix in pucch configuration --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 6 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 68 ++++++++++--------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 6f299fa3d3..7641d25483 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -260,7 +260,9 @@ int configure_fapi_dl_Tx(int Mod_idP, gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP]; NR_COMMON_channels_t *cc = nr_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - + + int pucch_fb_timing = pucch_sched->ul_slot - slotP; + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu; nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu; int TBS; @@ -355,7 +357,7 @@ int configure_fapi_dl_Tx(int Mod_idP, dci_pdu_rel15[0].dai = (pucch_sched->dai_c-1)&3; dci_pdu_rel15[0].tpc = 2; dci_pdu_rel15[0].pucch_resource_indicator = 0; //FIXME this is fixed to 0 in phy test with only one user - dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->ul_slot - slotP; //FIXME check on validity of indicator depending on type of DCI + dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_fb_timing-1; //FIXME valid only for format 1_0 LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n", dci_pdu_rel15[0].frequency_domain_assignment, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 61e1e42250..adc366f35f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -561,8 +561,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_PUCCH_ResourceSet_t *pucchresset; NR_PUCCH_FormatConfig_t *pucchfmt; NR_PUCCH_ResourceId_t *resource_id = NULL; - NR_PUSCH_Config_t *pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup; - long *pusch_id = pusch_Config->dataScramblingIdentityPUSCH; + long *id0 = NULL; int n_list, n_set; uint16_t N2,N3; @@ -570,39 +569,42 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->bit_len_harq = O_ack; - if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) - id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0; - if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) - id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0; - - // hop flags and hopping id are valid for any BWP - switch (scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping){ - case 0 : - // if neither, both disabled - pucch_pdu->group_hop_flag = 0; - pucch_pdu->sequence_hop_flag = 0; - break; - case 1 : - // if enable, group enabled - pucch_pdu->group_hop_flag = 1; - pucch_pdu->sequence_hop_flag = 0; - break; - case 2 : - // if disable, sequence disabled - pucch_pdu->group_hop_flag = 0; - pucch_pdu->sequence_hop_flag = 1; - break; - default: - AssertFatal(1==0,"msg1 FDM identifier %ld undefined (0,1,2,3) \n", scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM); - } - - if (scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId != NULL) - pucch_pdu->hopping_id = *scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId; - else - pucch_pdu->hopping_id = *scc->physCellId; - if (bwp) { // This is not the InitialBWP + NR_PUSCH_Config_t *pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup; + long *pusch_id = pusch_Config->dataScramblingIdentityPUSCH; + + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) + id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0; + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) + id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0; + + // hop flags and hopping id are valid for any BWP + switch (bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping){ + case 0 : + // if neither, both disabled + pucch_pdu->group_hop_flag = 0; + pucch_pdu->sequence_hop_flag = 0; + break; + case 1 : + // if enable, group enabled + pucch_pdu->group_hop_flag = 1; + pucch_pdu->sequence_hop_flag = 0; + break; + case 2 : + // if disable, sequence disabled + pucch_pdu->group_hop_flag = 0; + pucch_pdu->sequence_hop_flag = 1; + break; + default: + AssertFatal(1==0,"Group hopping flag %ld undefined (0,1,2) \n", bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping); + } + + if (bwp->bwp_Common->pucch_ConfigCommon->choice.setup->hoppingId != NULL) + pucch_pdu->hopping_id = *bwp->bwp_Common->pucch_ConfigCommon->choice.setup->hoppingId; + else + pucch_pdu->hopping_id = *scc->physCellId; + pucch_pdu->bwp_size = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275); pucch_pdu->bwp_start = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,275); pucch_pdu->subcarrier_spacing = bwp->bwp_Common->genericParameters.subcarrierSpacing; From 57a612c52de1a9ed4170a69f6eb5a2135848fa11 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Wed, 12 Feb 2020 09:34:07 +0100 Subject: [PATCH 097/175] update of pucch scheduler --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 6 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 6 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 156 +++++++++++++++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 5 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 3 +- 5 files changed, 143 insertions(+), 33 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 6f3f7a7f65..978e6cfe1b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -318,7 +318,6 @@ void nr_schedule_pucch(int Mod_idP, uint16_t O_uci; uint16_t O_ack; uint8_t SR_flag = 0; // no SR in PUCCH implemented for now - uint8_t pucch_resource = 0; // in PHY test only one UE -> only one PUCCH resource used NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; AssertFatal(UE_list->active[UE_id] >=0,"Cannot find UE_id %d is not active\n",UE_id); @@ -340,15 +339,14 @@ void nr_schedule_pucch(int Mod_idP, UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t); nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu; memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t)); - UL_tti_req->n_pdus+=1; - + UL_tti_req->n_pdus+=1; O_ack = curr_pucch->dai_c; O_uci = O_ack; // for now we are just sending acknacks in pucch nr_configure_pucch(pucch_pdu, scc, ubwp, - pucch_resource, + curr_pucch->resource_indicator, O_uci, O_ack, SR_flag); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 7641d25483..4c0f529d4c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -261,8 +261,6 @@ int configure_fapi_dl_Tx(int Mod_idP, NR_COMMON_channels_t *cc = nr_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - int pucch_fb_timing = pucch_sched->ul_slot - slotP; - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu; nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu; int TBS; @@ -356,8 +354,8 @@ int configure_fapi_dl_Tx(int Mod_idP, dci_pdu_rel15[0].harq_pid = 0; dci_pdu_rel15[0].dai = (pucch_sched->dai_c-1)&3; dci_pdu_rel15[0].tpc = 2; - dci_pdu_rel15[0].pucch_resource_indicator = 0; //FIXME this is fixed to 0 in phy test with only one user - dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_fb_timing-1; //FIXME valid only for format 1_0 + dci_pdu_rel15[0].pucch_resource_indicator = pucch_sched->resource_indicator; + dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->timing_indicator; LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n", dci_pdu_rel15[0].frequency_domain_assignment, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index adc366f35f..4f675fecc4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1248,6 +1248,53 @@ int add_new_nr_ue(module_id_t mod_idP, return -1; } + +void get_pdsch_to_harq_feedback(int Mod_idP, + int UE_id, + NR_SearchSpace__searchSpaceType_PR ss_type, + uint8_t *pdsch_to_harq_feedback) { + + int bwp_id=1; + NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; + NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id]; + NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; + NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]; + + NR_SearchSpace_t *ss; + + // common search type uses DCI format 1_0 + if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { + for (int i=0; i<8; i++) + pdsch_to_harq_feedback[i] = i+1; + } + else { + // searching for a ue specific search space + int found=0; + + for (int i=0;ibwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) { + ss=bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; + AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n"); + AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n"); + if (ss->searchSpaceType->present == ss_type) { + found=1; + break; + } + } + AssertFatal(found==1,"Couldn't find a ue specific searchspace\n"); + if (ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0) { + for (int i=0; i<8; i++) + pdsch_to_harq_feedback[i] = i+1; + } + else { + if(ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK != NULL) + pdsch_to_harq_feedback = (uint8_t *)ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK; + else + AssertFatal(found==1,"There is no allocated dl_DataToUL_ACK for pdsch to harq feedback\n"); + } + } +} + + // function to update pucch scheduling parameters in UE list when a USS DL is scheduled void nr_update_pucch_scheduling(int Mod_idP, int UE_id, @@ -1258,50 +1305,111 @@ void nr_update_pucch_scheduling(int Mod_idP, NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list; - int first_ul_slot_tdd,next_slot; + int first_ul_slot_tdd,k; NR_sched_pucch *curr_pucch; + uint8_t pdsch_to_harq_feedback[8]; + int found = 0; + int i = 0; + int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots; + if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0) + nr_ulmix_slots++; + + // this is hardcoded for now as ue specific + NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + get_pdsch_to_harq_feedback(Mod_idP,UE_id,ss_type,pdsch_to_harq_feedback); // if the list of pucch to be scheduled is empty if (UE_list->UE_sched_ctrl[UE_id].sched_pucch == NULL) { sched_pucch->frame = frameP; sched_pucch->next_sched_pucch = NULL; sched_pucch->dai_c = 1; - if ( (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots!=0) || (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)) { + sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource + if ( nr_ulmix_slots > 0 ) { // first pucch occasion in first UL or MIXED slot first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; - // computing slot in which pucch is scheduled - sched_pucch->ul_slot = first_ul_slot_tdd + slotP - (slotP % slots_per_tdd); + for (k=0; kul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd)); + sched_pucch->timing_indicator = pdsch_to_harq_feedback[i]; + } + else + AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n"); } else AssertFatal(1==0,"No Uplink Slots in this Frame\n"); UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch; } - else { + else { // to be tested curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch; - while (curr_pucch->next_sched_pucch != NULL) - curr_pucch = curr_pucch->next_sched_pucch; - // we are scheduling at most 11 ack nacks in the same pucch - if (curr_pucch->dai_c==11) { - next_slot = curr_pucch->ul_slot + 1; - if (next_slot == slots_per_tdd) - AssertFatal(1==0,"No more slots in this TDD period\n"); - else { - // generating a new item in the list - sched_pucch->frame = frameP; - sched_pucch->next_sched_pucch = NULL; - sched_pucch->dai_c = 1; - sched_pucch->ul_slot = next_slot; - curr_pucch->next_sched_pucch = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch)); - curr_pucch->next_sched_pucch = sched_pucch; + if (curr_pucch->dai_c<11) { // we are scheduling at most 11 harq-ack in the same pucch + while (i<8 && found == 0) { // look if timing indicator is among allowed values for current pucch + if (pdsch_to_harq_feedback[i]==(curr_pucch->ul_slot % slots_per_tdd)-(slotP % slots_per_tdd)) + found = 1; + if (found == 0) i++; + } + if (found == 1) { // scheduling this harq-ack in current pucch + sched_pucch = curr_pucch; + sched_pucch->dai_c = 1 + sched_pucch->dai_c; + sched_pucch->timing_indicator = pdsch_to_harq_feedback[i]; } } - else { - sched_pucch = curr_pucch; - sched_pucch->dai_c = 1 + sched_pucch->dai_c; + if (curr_pucch->dai_c==11 || found == 0) { // if current pucch is full or no timing indicator allowed + // look for pucch occasions in other UL of mixed slots + for (k=scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; kul_slot % slots_per_tdd)) { // skip current scheduled slot (already checked) + i = 0; + while (i<8 && found == 0) { // look if timing indicator is among allowed values + if (pdsch_to_harq_feedback[i]==k-(slotP % slots_per_tdd)) + found = 1; + if (found == 0) i++; + } + if (found == 1) { + if (k<(curr_pucch->ul_slot % slots_per_tdd)) { // we need to add a pucch occasion before current pucch + sched_pucch->frame = frameP; + sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd)); + sched_pucch->next_sched_pucch = curr_pucch; + sched_pucch->dai_c = 1; + sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource + sched_pucch->timing_indicator = pdsch_to_harq_feedback[i]; + UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch; + } + else { + while (curr_pucch->next_sched_pucch != NULL && k!=(curr_pucch->ul_slot % slots_per_tdd)) + curr_pucch = curr_pucch->next_sched_pucch; + if (curr_pucch == NULL) { // creating a new item in the list + sched_pucch->frame = frameP; + sched_pucch->next_sched_pucch = NULL; + sched_pucch->dai_c = 1; + sched_pucch->timing_indicator = pdsch_to_harq_feedback[i]; + sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource + sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd)); + curr_pucch->next_sched_pucch = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch)); + curr_pucch->next_sched_pucch = sched_pucch; + } + else { + if (curr_pucch->dai_c==11) + found = 0; // if pucch at index k is already full we have to find a new one in a following occasion + else { // scheduling this harq-ack in current pucch + sched_pucch = curr_pucch; + sched_pucch->dai_c = 1 + sched_pucch->dai_c; + sched_pucch->timing_indicator = pdsch_to_harq_feedback[i]; + } + } + } + } + } + } } } - } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index ca3b19107d..cbbac3a55a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -94,6 +94,11 @@ void nr_update_pucch_scheduling(int Mod_idP, sub_frame_t slotP, int slots_per_tdd, NR_sched_pucch *sched_pucch); + +void get_pdsch_to_harq_feedback(int Mod_idP, + int UE_id, + NR_SearchSpace__searchSpaceType_PR ss_type, + uint8_t *pdsch_to_harq_feedback); void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, nr_scs_e scs_common, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 10b5e49d36..90cd09c021 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -104,7 +104,8 @@ typedef struct NR_sched_pucch { int frame; int ul_slot; uint8_t dai_c; - uint8_t dai_t; + uint8_t timing_indicator; + uint8_t resource_indicator; struct NR_sched_pucch *next_sched_pucch; } NR_sched_pucch; From ee7300f102392d5a6f28206f12fbb5fd43279cb4 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Thu, 13 Feb 2020 15:11:48 +0100 Subject: [PATCH 098/175] experiment of export of enb classes from main.py to enb.py --- ci-scripts/epc.py | 4 +- ci-scripts/main_enb.py | 4780 +++++++++++++++++++++++++++++++++++ ci-scripts/ran.py | 765 ++++++ ci-scripts/sshconnection.py | 3 +- 4 files changed, 5549 insertions(+), 3 deletions(-) create mode 100644 ci-scripts/main_enb.py create mode 100644 ci-scripts/ran.py diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 58a0958d4b..91d722a72f 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -66,8 +66,8 @@ class EPCManagement(): mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) - mySSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + self.EPC_PcapFileName, '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) mySSH.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) diff --git a/ci-scripts/main_enb.py b/ci-scripts/main_enb.py new file mode 100644 index 0000000000..e8c530a70b --- /dev/null +++ b/ci-scripts/main_enb.py @@ -0,0 +1,4780 @@ + +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + +#----------------------------------------------------------- +# Version +#----------------------------------------------------------- +Version = '0.1' + +#----------------------------------------------------------- +# Constants +#----------------------------------------------------------- +ALL_PROCESSES_OK = 0 +ENB_PROCESS_FAILED = -1 +ENB_PROCESS_OK = +1 +ENB_PROCESS_SEG_FAULT = -11 +ENB_PROCESS_ASSERTION = -12 +ENB_PROCESS_REALTIME_ISSUE = -13 +ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 +ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 +HSS_PROCESS_FAILED = -2 +HSS_PROCESS_OK = +2 +MME_PROCESS_FAILED = -3 +MME_PROCESS_OK = +3 +SPGW_PROCESS_FAILED = -4 +SPGW_PROCESS_OK = +4 +UE_IP_ADDRESS_ISSUE = -5 +OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 +OAI_UE_PROCESS_COULD_NOT_SYNC = -21 +OAI_UE_PROCESS_ASSERTION = -22 +OAI_UE_PROCESS_FAILED = -23 +OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 +OAI_UE_PROCESS_SEG_FAULT = -25 +OAI_UE_PROCESS_OK = +6 + +UE_STATUS_DETACHED = 0 +UE_STATUS_DETACHING = 1 +UE_STATUS_ATTACHING = 2 +UE_STATUS_ATTACHED = 3 + +X2_HO_REQ_STATE__IDLE = 0 +X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 +X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 +X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 +X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 + +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import sys # arg +import re # reg +import pexpect # pexpect +import time # sleep +import os +import subprocess +import xml.etree.ElementTree as ET +import logging +import datetime +import signal +from multiprocessing import Process, Lock, SimpleQueue +logging.basicConfig( + level=logging.DEBUG, + format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" +) + +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class OaiCiTest(): + def __init__(self): + self.FailReportCnt = 0 + self.prematureExit = False + #self.ranRepository = '' + #self.ranBranch = '' + #RAN.GetranAllowMerge() = False + #self.ranCommitID = '' + #RAN.GetranTargetBranch() = '' + #self.eNBIPAddress = '' + #self.eNBUserName = '' + #self.eNBPassword = '' + #RAN.GeteNBSourceCodePath() = '' + #self.EPCIPAddress = '' + #self.EPCUserName = '' + #self.EPCPassword = '' + #self.eNB1IPAddress = '' + #self.eNB1UserName = '' + #self.eNB1Password = '' + #self.eNB1SourceCodePath = '' + #self.eNB2IPAddress = '' + #self.eNB2UserName = '' + #self.eNB2Password = '' + #self.eNB2SourceCodePath = '' + #self.EPCSourceCodePath = '' + #self.EPCType = '' + #self.EPC_PcapFileName = '' + self.ADBIPAddress = '' + self.ADBUserName = '' + self.ADBPassword = '' + self.ADBCentralized = True + self.testCase_id = '' + self.testXMLfiles = [] + self.nbTestXMLfiles = 0 + self.desc = '' + #RAN.GetBuild_eNB_args() = '' + #self.backgroundBuild = False + #self.backgroundBuildTestId = ['', '', ''] + #self.Build_eNB_forced_workspace_cleanup = False + #RAN.GetInitialize_eNB_args() = '' + self.air_interface = 'lte' + #self.eNB_instance = '' + #self.eNB_serverId = '' + #self.eNBLogFiles = ['', '', ''] + #self.eNBOptions = ['', '', ''] + #self.eNBmbmsEnables = [False, False, False] + #self.eNBstatuses = [-1, -1, -1] + self.ping_args = '' + self.ping_packetloss_threshold = '' + self.iperf_args = '' + self.iperf_packetloss_threshold = '' + self.iperf_profile = '' + self.iperf_options = '' + self.nbMaxUEtoAttach = -1 + self.UEDevices = [] + self.UEDevicesStatus = [] + self.UEDevicesRemoteServer = [] + self.UEDevicesRemoteUser = [] + self.UEDevicesOffCmd = [] + self.UEDevicesOnCmd = [] + self.UEDevicesRebootCmd = [] + self.CatMDevices = [] + self.UEIPAddresses = [] + self.htmlFile = '' + self.htmlHeaderCreated = False + self.htmlFooterCreated = False + self.htmlUEConnected = -1 + self.htmleNBFailureMsg = '' + self.htmlUEFailureMsg = '' + self.picocom_closure = False + self.idle_sleep_time = 0 + self.x2_ho_options = 'network' + self.x2NbENBs = 0 + self.x2ENBBsIds = [] + self.x2ENBConnectedUEs = [] + self.htmlTabRefs = [] + self.htmlTabNames = [] + self.htmlTabIcons = [] + self.repeatCounts = [] + self.finalStatus = False + self.OsVersion = '' + self.KernelVersion = '' + self.UhdVersion = '' + self.UsrpBoard = '' + self.CpuNb = '' + self.CpuModel = '' + self.CpuMHz = '' + self.UEIPAddress = '' + self.UEUserName = '' + self.UEPassword = '' + self.UE_instance = '' + self.UESourceCodePath = '' + self.UELogFile = '' + self.Build_OAI_UE_args = '' + self.Initialize_OAI_UE_args = '' + self.clean_repository = True + self.flexranCtrlInstalled = False + self.flexranCtrlStarted = False + self.expectedNbOfConnectedUEs = 0 + self.startTime = 0 +''' + def BuildeNB(self): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = RAN.GeteNBSourceCodePath() + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(lIpAddr, lUserName, lPassWord) + # Check if we build an 5G-NR gNB or an LTE eNB + result = re.search('--gNB', RAN.GetBuild_eNB_args()) + if result is not None: + self.air_interface = 'nr' + else: + self.air_interface = 'lte' + # Worakround for some servers, we need to erase completely the workspace + if self.Build_eNB_forced_workspace_cleanup: + SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) + # on RedHat/CentOS .git extension is mandatory + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) + if result is not None: + full_ran_repo_name = self.ranRepository + else: + full_ran_repo_name = self.ranRepository + '.git' + SSH.command('mkdir -p ' + lSourcePath, '\$', 5) + SSH.command('cd ' + lSourcePath, '\$', 5) + SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) + # Raphael: here add a check if git clone or git fetch went smoothly + SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + SSH.command('git config user.name "OAI Jenkins"', '\$', 5) + # Checking the BUILD INFO file + if not self.backgroundBuild: + SSH.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', SSH.getBefore()) + if result is not None: + mismatch = False + SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(self.ranCommitID, SSH.getBefore()) + if result is None: + mismatch = True + SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (RAN.GetranAllowMerge()): + result = re.search('YES', SSH.getBefore()) + if result is None: + mismatch = True + SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if RAN.GetranTargetBranch() == '': + result = re.search('develop', SSH.getBefore()) + else: + result = re.search(RAN.GetranTargetBranch(), SSH.getBefore()) + if result is None: + mismatch = True + else: + result = re.search('NO', SSH.getBefore()) + if result is None: + mismatch = True + if not mismatch: + SSH.close() + self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) + return + + SSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (RAN.GetranAllowMerge()): + if RAN.GetranTargetBranch() == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + RAN.GetranTargetBranch()) + SSH.command('git merge --ff origin/' + RAN.GetranTargetBranch() + ' -m "Temporary merge for CI"', '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('mkdir -p log', '\$', 5) + SSH.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + if self.backgroundBuild: + SSH.command('echo "./build_oai ' + RAN.GetBuild_eNB_args() + '" > ./my-lte-softmodem-build.sh', '\$', 5) + SSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) + SSH.close() + self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) + self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id + return + SSH.command('stdbuf -o0 ./build_oai ' + RAN.GetBuild_eNB_args() + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) + + def WaitBuildeNBisFinished(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = RAN.GeteNBSourceCodePath() + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(lIpAddr, lUserName, lPassWord) + count = 40 + buildOAIprocess = True + while (count > 0) and buildOAIprocess: + SSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) + result = re.search('build_oai', SSH.getBefore()) + if result is None: + buildOAIprocess = False + else: + count -= 1 + time.sleep(30) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) + + def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): + SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) + SSH.command('ls ran_build/build', '\$', 3) + SSH.command('ls ran_build/build', '\$', 3) + if self.air_interface == 'nr': + nodeB_prefix = 'g' + else: + nodeB_prefix = 'e' + buildStatus = True + result = re.search(self.air_interface + '-softmodem', SSH.getBefore()) + if result is None: + buildStatus = False + else: + # Generating a BUILD INFO file + SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (RAN.GetranAllowMerge()): + SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if RAN.GetranTargetBranch() == '': + SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + SSH.command('echo "TGT_BRANCH: ' + RAN.GetranTargetBranch() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('mkdir -p build_log_' + testcaseId, '\$', 5) + SSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) + SSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) + if self.eNB_serverId != '0': + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) + SSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) + SSH.close() + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + os.remove('./tmp_build' + testcaseId + '.zip') + SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', RAN.GeteNBSourceCodePath() + '/cmake_targets/.') + os.remove('./tmp_build' + testcaseId + '.zip') + SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + SSH.command('cd ' + RAN.GeteNBSourceCodePath() + '/cmake_targets', '\$', 5) + SSH.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) + SSH.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) + SSH.close() + else: + SSH.close() + + if buildStatus: + logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') + self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) + else: + logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') + self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'KO', ALL_PROCESSES_OK) + self.CreateHtmlTabFooter(False) + sys.exit(1) +''' + def BuildOAIUE(self): + if self.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + result = re.search('--nrUE', self.Build_OAI_UE_args) + if result is not None: + RAN.Setair_interface() = 'nr' + ue_prefix = 'NR ' + else: + RAN.Setair_interface() = 'lte' + ue_prefix = '' + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', RAN.GetranRepository()) + if result is not None: + full_ran_repo_name = RAN.GetranRepository() + else: + full_ran_repo_name = RAN.GetranRepository() + '.git' + SSH.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) + SSH.command('cd ' + self.UESourceCodePath, '\$', 5) + SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) + # here add a check if git clone or git fetch went smoothly + SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + SSH.command('git config user.name "OAI Jenkins"', '\$', 5) + if self.clean_repository: + SSH.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', SSH.getBefore()) + if result is not None: + mismatch = False + SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(RAN.GetranCommitID(), SSH.getBefore()) + if result is None: + mismatch = True + SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (RAN.GetranAllowMerge()): + result = re.search('YES', SSH.getBefore()) + if result is None: + mismatch = True + SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if RAN.GetranTargetBranch() == '': + result = re.search('develop', SSH.getBefore()) + else: + result = re.search(RAN.GetranTargetBranch(), SSH.getBefore()) + if result is None: + mismatch = True + else: + result = re.search('NO', SSH.getBefore()) + if result is None: + mismatch = True + if not mismatch: + SSH.close() + self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) + return + + SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) + + # if the commit ID is provided use it to point to it + if RAN.GetranCommitID() != '': + SSH.command('git checkout -f ' + RAN.GetranCommitID(), '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (RAN.GetranAllowMerge()): + if RAN.GetranTargetBranch() == '': + if (RAN.GetranBranch() != 'develop') and (RAN.GetranBranch() != 'origin/develop'): + SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + RAN.GetranTargetBranch()) + SSH.command('git merge --ff origin/' + RAN.GetranTargetBranch() + ' -m "Temporary merge for CI"', '\$', 5) + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('mkdir -p log', '\$', 5) + SSH.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + SSH.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) + SSH.command('ls ran_build/build', '\$', 3) + SSH.command('ls ran_build/build', '\$', 3) + buildStatus = True + result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) + if result is None: + buildStatus = False + SSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) + SSH.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) + SSH.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) + if buildStatus: + # Generating a BUILD INFO file + SSH.command('echo "SRC_BRANCH: ' + RAN.GetranBranch() + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_COMMIT: ' + RAN.GetranCommitID() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (RAN.GetranAllowMerge): + SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if RAN.GetranTargetBranch() == '': + SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + SSH.command('echo "TGT_BRANCH: ' + RAN.GetranTargetBranch() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.close() + self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + else: + SSH.close() + logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') + self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') + self.CreateHtmlTabFooter(False) + sys.exit(1) + + def CheckFlexranCtrlInstallation(self): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': + return + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) + result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) + if result is not None: + self.flexranCtrlInstalled = True + logging.debug('Flexran Controller is installed') + SSH.close() + + def InitializeFlexranCtrl(self): + if self.flexranCtrlInstalled == False: + return + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd /opt/flexran_rtc', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f log/*.log', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) + SSH.command('ps -aux | grep --color=never rt_controller', '\$', 5) + result = re.search('rt_controller -c ', SSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') + self.flexranCtrlStarted = True + SSH.close() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) +''' + def InitializeeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = RAN.GeteNBSourceCodePath() + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = False + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(RAN.GetInitialize_eNB_args(), 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) + if result is not None: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) + result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', SSH.getBefore()) + if result is not None: + eth_interface = result.group('eth_interface') + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') + EPC.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) + SSH.close() + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('cd ' + lSourcePath, '\$', 5) + # Initialize_eNB_args usually start with -O and followed by the location in repository + full_config_file = RAN.GetInitialize_eNB_args().replace('-O ','') + extra_options = '' + extIdx = full_config_file.find('.conf') + if (extIdx > 0): + extra_options = full_config_file[extIdx + 5:] + # if tracer options is on, compiling and running T Tracer + result = re.search('T_stdout', str(extra_options)) + if result is not None: + logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') + SSH.command('cd common/utils/T/tracer', '\$', 5) + SSH.command('make', '\$', 10) + SSH.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) + SSH.command('cd ' + lSourcePath, '\$', 5) + full_config_file = full_config_file[:extIdx + 5] + config_path, config_file = os.path.split(full_config_file) + else: + sys.exit('Insufficient Parameter') + ci_full_config_file = config_path + '/ci-' + config_file + rruCheck = False + result = re.search('^rru|^rcc|^du.band', str(config_file)) + if result is not None: + rruCheck = True + # do not reset board twice in IF4.5 case + result = re.search('^rru|^enb|^du.band', str(config_file)) + if result is not None: + SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) + result = re.search('type: b200', SSH.getBefore()) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + SSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) + # Make a copy and adapt to EPC / eNB IP addresses + SSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) + SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.GetIPAddress() + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + SSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); + else: + SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); + self.eNBmbmsEnables[int(self.eNB_instance)] = False + SSH.command('grep enable_enb_m2 ' + ci_full_config_file, '\$', 2); + result = re.search('yes', SSH.getBefore()) + if result is not None: + self.eNBmbmsEnables[int(self.eNB_instance)] = True + logging.debug('\u001B[1m MBMS is enabled on this eNB\u001B[0m') + result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) + eNBinNoS1 = False + if result is not None: + eNBinNoS1 = True + logging.debug('\u001B[1m eNB is in noS1 configuration \u001B[0m') + # Launch eNB with the modified config file + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface + '-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) + SSH.command('hostnamectl','\$', 5) + result = re.search('CentOS Linux 7', SSH.getBefore()) + if result is not None: + SSH.command('echo $USER; nohup sudo ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log 2>&1 &', lUserName, 10) + else: + SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' + if extra_options != '': + self.eNBOptions[int(self.eNB_instance)] = extra_options + time.sleep(6) + doLoop = True + loopCounter = 20 + enbDidSync = False + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # In case of T tracer recording, we may need to kill it + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) + if result is not None: + SSH.command('killall --signal SIGKILL record', '\$', 5) + SSH.close() + doLoop = False + logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) + # In case of T tracer recording, we need to kill tshark on EPC side + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) + if result is not None: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if EPC.EPC_PcapFileName != '': + time.sleep(0.5) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.close() + time.sleep(1) + if EPC.EPC_PcapFileName != '': + copyin_res = SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') + if (copyin_res == 0): + SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') + self.prematureExit = True + return + else: + SSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) + if rruCheck: + result = re.search('wait RUs', SSH.getBefore()) + else: + result = re.search('got sync|Starting F1AP at CU', SSH.getBefore()) + if result is None: + time.sleep(6) + else: + doLoop = False + enbDidSync = True + time.sleep(10) + + if enbDidSync and eNBinNoS1: + SSH.command('ifconfig oaitun_enb1', '\$', 4) + SSH.command('ifconfig oaitun_enb1', '\$', 4) + result = re.search('inet addr:1|inet 1', SSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m oaitun_enb1 interface is mounted and configured\u001B[0m') + else: + logging.error('\u001B[1m oaitun_enb1 interface is either NOT mounted or NOT configured\u001B[0m') + if self.eNBmbmsEnables[int(self.eNB_instance)]: + SSH.command('ifconfig oaitun_enm1', '\$', 4) + result = re.search('inet addr', SSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m oaitun_enm1 interface is mounted and configured\u001B[0m') + else: + logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m') + if enbDidSync: + self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) + + SSH.close() + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') +''' + def InitializeUE_common(self, device_id, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if not self.ADBCentralized: + # Reboot UE + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) + # Wait + #time.sleep(60) + # Put in LTE-Mode only + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) + # enable data service + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + # we need to do radio on/off cycle to make sure of above changes + # airplane mode off // radio on + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + #time.sleep(10) + # airplane mode on // radio off + #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + + # normal procedure without reboot + # enable data service + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + # airplane mode on // radio off + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + SSH.close() + return + # enable data service + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + + # The following commands are deprecated since we no longer work on Android 7+ + # SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) + # SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) + # a dedicated script has to be installed inside the UE + # airplane mode on means call /data/local/tmp/off + if device_id == '84B7N16418004022': + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + #airplane mode off means call /data/local/tmp/on + logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def InitializeUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.InitializeUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def InitializeOAIUE(self): + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + if RAN.Getair_interface() == 'lte': + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is None: + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + UE_prefix = '' + else: + UE_prefix = 'NR ' + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + # b2xx_fx3_utils reset procedure + SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 60) + result = re.search('type: b200', SSH.getBefore()) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + SSH.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 30) + result = re.search('type: n3xx', SSH.getBefore()) + if result is not None: + logging.debug('Found a N3xx device --> resetting it') + SSH.command('cd ' + self.UESourceCodePath, '\$', 5) + # Initialize_OAI_UE_args usually start with -C and followed by the location in repository + SSH.command('source oaienv', '\$', 5) + SSH.command('cd cmake_targets/ran_build/build', '\$', 5) + if RAN.Getair_interface() == 'lte': + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + # We may have to regenerate the .u* files + if result is None: + SSH.command('ls /tmp/*.sed', '\$', 5) + result = re.search('adapt_usim_parameters', SSH.getBefore()) + if result is not None: + SSH.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + else: + SSH.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) + SSH.command('echo "ulimit -c unlimited && ./'+ RAN.Getair_interface() +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) + self.UELogFile = 'ue_' + self.testCase_id + '.log' + + # We are now looping several times to hope we really sync w/ an eNB + doOutterLoop = True + outterLoopCounter = 5 + gotSyncStatus = True + fullSyncStatus = True + while (doOutterLoop): + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/ran_build/build', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) + #use nohup instead of daemon + #SSH.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/ran_build/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('echo $USER; nohup sudo ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh' + ' > ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ' + ' 2>&1 &', self.UEUserName, 5) + time.sleep(6) + SSH.command('cd ../..', '\$', 5) + doLoop = True + loopCounter = 10 + gotSyncStatus = True + # the 'got sync' message is for the UE threads synchronization + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # Here should never occur + logging.error('"got sync" message never showed!') + gotSyncStatus = False + doLoop = False + continue + SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + if RAN.Getair_interface() == 'nr': + result = re.search('Starting sync detection', SSH.getBefore()) + else: + result = re.search('got sync', SSH.getBefore()) + if result is None: + time.sleep(10) + else: + doLoop = False + logging.debug('Found "got sync" message!') + if gotSyncStatus == False: + # we certainly need to stop the lte-uesoftmodem process if it is still running! + SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + result = re.search('-uesoftmodem', SSH.getBefore()) + if result is not None: + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT -r *-uesoftmodem', '\$', 4) + time.sleep(3) + continue + if RAN.Getair_interface() == 'nr': + fullSyncStatus = True + doOutterLoop = False + else: + # We are now checking if sync w/ eNB DOES NOT OCCUR + # Usually during the cell synchronization stage, the UE returns with No cell synchronization message + doLoop = True + loopCounter = 10 + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # Here we do have a great chance that the UE did cell-sync w/ eNB + doLoop = False + doOutterLoop = False + fullSyncStatus = True + continue + SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) + result = re.search('No cell synchronization found', SSH.getBefore()) + if result is None: + time.sleep(6) + else: + doLoop = False + fullSyncStatus = False + logging.debug('Found: "No cell synchronization" message! --> try again') + time.sleep(6) + SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) + result = re.search('lte-uesoftmodem', SSH.getBefore()) + if result is not None: + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) + outterLoopCounter = outterLoopCounter - 1 + if (outterLoopCounter == 0): + doOutterLoop = False + + if fullSyncStatus and gotSyncStatus and RAN.Getair_interface() == 'lte': + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is None: + SSH.command('ifconfig oaitun_ue1', '\$', 4) + SSH.command('ifconfig oaitun_ue1', '\$', 4) + # ifconfig output is different between ubuntu 16 and ubuntu 18 + result = re.search('inet addr:1|inet 1', SSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') + tunnelInterfaceStatus = True + else: + logging.debug(SSH.getBefore()) + logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') + tunnelInterfaceStatus = False + if RAN.GeteNBmbmsEnables[0]: + self.command('ifconfig oaitun_uem1', '\$', 4) + result = re.search('inet addr', SSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m oaitun_uem1 interface is mounted and configured\u001B[0m') + tunnelInterfaceStatus = tunnelInterfaceStatus and True + else: + logging.error('\u001B[1m oaitun_uem1 interface is either NOT mounted or NOT configured\u001B[0m') + tunnelInterfaceStatus = False + else: + tunnelInterfaceStatus = True + else: + tunnelInterfaceStatus = True + + SSH.close() + if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') + if (self.ADBIPAddress != 'none'): + self.UEDevices = [] + self.UEDevices.append('OAI-UE') + self.UEDevicesStatus = [] + self.UEDevicesStatus.append(UE_STATUS_DETACHED) + else: + if RAN.Getair_interface() == 'lte': + if RAN.GeteNBmbmsEnables[0]: + self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' + else: + self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') + else: + self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') + logging.error('\033[91mInitialize OAI UE Failed! \033[0m') + self.AutoTerminateUEandeNB() + + def checkDevTTYisUnlocked(self): + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + count = 0 + while count < 5: + SSH.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) + result = re.search('picocom', SSH.getBefore()) + if result is None: + count = 10 + else: + time.sleep(5) + count = count + 1 + SSH.close() + + def InitializeCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + self.picocom_closure = True + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) + # Doing a power cycle + self.command('AT^RESET', 'SIMSTORE,READY', 15) + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + self.command('ATE1', 'OK', 5) + # Disabling the Radio + SSH.command('AT+CFUN=0', 'OK', 5) + logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') + # Checking if auto-attach is enabled + SSH.command('AT^AUTOATT?', 'OK', 5) + result = re.search('AUTOATT: (?P[0-9\-]+)', SSH.getBefore()) + if result is not None: + if result.group('state') is not None: + autoAttachState = int(result.group('state')) + if autoAttachState is not None: + if autoAttachState == 0: + SSH.command('AT^AUTOATT=1', 'OK', 5) + logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') + else: + logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') + # Force closure of picocom but device might still be locked + SSH.close() + self.picocom_closure = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.checkDevTTYisUnlocked() + + def TerminateCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + self.picocom_closure = True + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) + # Disabling the Radio + SSH.command('AT+CFUN=0', 'OK', 5) + logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') + SSH.close() + self.picocom_closure = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.checkDevTTYisUnlocked() + + def AttachCatM(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + self.picocom_closure = True + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` + SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) + SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) + time.sleep(1) + # Calling twice AT to clear all buffers + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) + # Enabling the Radio + SSH.command('AT+CFUN=1', 'SIMSTORE,READY', 5) + logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') + time.sleep(4) + # We should check if we register + count = 0 + attach_cnt = 0 + attach_status = False + while count < 5: + SSH.command('AT+CEREG?', 'OK', 5) + result = re.search('CEREG: 2,(?P[0-9\-]+),', SSH.getBefore()) + if result is not None: + mDataConnectionState = int(result.group('state')) + if mDataConnectionState is not None: + if mDataConnectionState == 1: + count = 10 + attach_status = True + result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', SSH.getBefore()) + if result is not None: + networky = result.group('networky') + networkz = result.group('networkz') + logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m') + else: + logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m') + else: + logging.debug('+CEREG: 2,' + str(mDataConnectionState)) + attach_cnt = attach_cnt + 1 + else: + logging.debug(SSH.getBefore()) + attach_cnt = attach_cnt + 1 + count = count + 1 + time.sleep(1) + if attach_status: + SSH.command('AT+CESQ', 'OK', 5) + result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', SSH.getBefore()) + if result is not None: + nRSRQ = int(result.group('rsrq')) + nRSRP = int(result.group('rsrp')) + if (nRSRQ is not None) and (nRSRP is not None): + logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') + logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') + SSH.close() + self.picocom_closure = False + html_queue = SimpleQueue() + self.checkDevTTYisUnlocked() + if attach_status: + html_cell = '
CAT-M module Attachment Completed in ' + str(attach_cnt+4) + ' seconds'
+			if (nRSRQ is not None) and (nRSRP is not None):
+				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
+				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm
' + else: + html_cell += '' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) + else: + logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') + html_cell = '
CAT-M module Attachment Failed
' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) + self.AutoTerminateUEandeNB() + + def PingCatM(self): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + try: + statusQueue = SimpleQueue() + lock = Lock() + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) + SSH.command('cd scripts', '\$', 5) + if re.match('OAI', EPC.GetType(), re.IGNORECASE): + logging.debug('Using the OAI EPC HSS: not implemented yet') + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + else: + SSH.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) + result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', SSH.getBefore()) + if result is not None: + moduleIPAddr = result.group('ipaddr') + else: + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + device_id = 'catm' + ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + lock.acquire() + logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + lock.release() + SSH.close() + html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' + statusQueue.put(html_cell) + if (packetLossOK): + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) + self.AutoTerminateUEandeNB() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AttachUE_common(self, device_id, statusQueue, lock, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + else: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + else: + # airplane mode off // radio on + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + time.sleep(2) + max_count = 45 + count = max_count + while count > 0: + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put('mDataConnectionState Not Found!') + lock.release() + break + mDataConnectionState = int(result.group('state')) + if mDataConnectionState == 2: + logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') + lock.acquire() + statusQueue.put(max_count - count) + statusQueue.put(device_id) + statusQueue.put('Attach Completed') + lock.release() + break + count = count - 1 + if count == 15 or count == 30: + logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') + if self.ADBCentralized: + if device_id == '84B7N16418004022': + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + time.sleep(0.5) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) + else: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) + time.sleep(0.5) + logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') + time.sleep(1) + if count == 0: + logging.debug('\u001B[1;37;41m UE (' + device_id + ') Attach Failed \u001B[0m') + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put('Attach Failed') + lock.release() + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def AttachUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + status_queue = SimpleQueue() + lock = Lock() + nb_ue_to_connect = 0 + for device_id in self.UEDevices: + if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): + self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING + p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) + p.daemon = True + p.start() + multi_jobs.append(p) + nb_ue_to_connect = nb_ue_to_connect + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + return + else: + attach_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + attach_status = False + device_id = status_queue.get() + message = status_queue.get() + if (count < 0): + html_cell = '
UE (' + device_id + ')\n' + message + '
' + else: + html_cell = '
UE (' + device_id + ')\n' + message + ' in ' + str(count + 2) + ' seconds
' + html_queue.put(html_cell) + if (attach_status): + cnt = 0 + while cnt < len(self.UEDevices): + if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: + self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED + cnt += 1 + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + else: + self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def DetachUE_common(self, device_id, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DetachUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + cnt = 0 + for device_id in self.UEDevices: + self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING + p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) + p.daemon = True + p.start() + multi_jobs.append(p) + cnt += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) + if result is not None: + logging.debug('Waiting 5 seconds to fill up record file') + time.sleep(5) + cnt = 0 + while cnt < len(self.UEDevices): + self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED + cnt += 1 + + def RebootUE_common(self, device_id): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + previousmDataConnectionStates = [] + # Save mDataConnectionState + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') + sys.exit(1) + previousmDataConnectionStates.append(int(result.group('state'))) + # Reboot UE + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) + time.sleep(60) + previousmDataConnectionState = previousmDataConnectionStates.pop(0) + count = 180 + while count > 0: + count = count - 1 + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) + result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) + if result is None: + mDataConnectionState = None + else: + mDataConnectionState = int(result.group('state')) + logging.debug('mDataConnectionState = ' + result.group('state')) + if mDataConnectionState is None or (previousmDataConnectionState == 2 and mDataConnectionState != 2): + logging.debug('\u001B[1mWait UE (' + device_id + ') a second until reboot completion (' + str(180-count) + ' times)\u001B[0m') + time.sleep(1) + else: + logging.debug('\u001B[1mUE (' + device_id + ') Reboot Completed\u001B[0m') + break + if count == 0: + logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') + sys.exit(1) + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def RebootUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + multi_jobs = [] + for device_id in self.UEDevices: + p = Process(target = self.RebootUE_common, args = (device_id,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def DataDisableUE_common(self, device_id, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # disable data service + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DataDisableUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.DataDisableUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def DataEnableUE_common(self, device_id, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # enable data service + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def DataEnableUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.DataEnableUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def GetAllUEDevices(self, terminate_ue_flag): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + SSH.command('adb devices', '\$', 15) + #self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) + self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) + SSH.close() + else: + if (os.path.isfile('./phones_list.txt')): + os.remove('./phones_list.txt') + SSH.command('ls /etc/*/phones*.txt', '\$', 5) + result = re.search('/etc/ci/phones_list.txt', SSH.getBefore()) + SSH.close() + if (result is not None) and (len(self.UEDevices) == 0): + SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') + if (os.path.isfile('./phones_list.txt')): + phone_list_file = open('./phones_list.txt', 'r') + for line in phone_list_file.readlines(): + line = line.strip() + result = re.search('^#', line) + if result is not None: + continue + comma_split = line.split(",") + self.UEDevices.append(comma_split[0]) + self.UEDevicesRemoteServer.append(comma_split[1]) + self.UEDevicesRemoteUser.append(comma_split[2]) + self.UEDevicesOffCmd.append(comma_split[3]) + self.UEDevicesOnCmd.append(comma_split[4]) + self.UEDevicesRebootCmd.append(comma_split[5]) + phone_list_file.close() + + if terminate_ue_flag == False: + if len(self.UEDevices) == 0: + logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') + sys.exit(1) + if len(self.UEDevicesStatus) == 0: + cnt = 0 + while cnt < len(self.UEDevices): + self.UEDevicesStatus.append(UE_STATUS_DETACHED) + cnt += 1 + + def GetAllCatMDevices(self, terminate_ue_flag): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + SSH.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) + #self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) + self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) + else: + if (os.path.isfile('./modules_list.txt')): + os.remove('./modules_list.txt') + SSH.command('ls /etc/*/modules*.txt', '\$', 5) + result = re.search('/etc/ci/modules_list.txt', SSH.getBefore()) + SSH.close() + if result is not None: + logging.debug('Found a module list file on ADB server') + if terminate_ue_flag == False: + if len(self.CatMDevices) == 0: + logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') + sys.exit(1) + SSH.close() + + def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) + result = re.search('mServiceState=(?P[0-9]+)', SSH.getBefore()) + serviceState = 'Service State: UNKNOWN' + if result is not None: + lServiceState = int(result.group('serviceState')) + if lServiceState == 3: + serviceState = 'Service State: RADIO_POWERED_OFF' + if lServiceState == 1: + serviceState = 'Service State: OUT_OF_SERVICE' + if lServiceState == 0: + serviceState = 'Service State: IN_SERVICE' + if lServiceState == 2: + serviceState = 'Service State: EMERGENCY_ONLY' + result = re.search('mDataConnectionState=(?P[0-9]+)', SSH.getBefore()) + dataConnectionState = 'Data State: UNKNOWN' + if result is not None: + lDataConnectionState = int(result.group('dataConnectionState')) + if lDataConnectionState == 0: + dataConnectionState = 'Data State: DISCONNECTED' + if lDataConnectionState == 1: + dataConnectionState = 'Data State: CONNECTING' + if lDataConnectionState == 2: + dataConnectionState = 'Data State: CONNECTED' + if lDataConnectionState == 3: + dataConnectionState = 'Data State: SUSPENDED' + result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', SSH.getBefore()) + dataConnectionReason = 'Data Reason: UNKNOWN' + if result is not None: + dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') + lock.acquire() + logging.debug('\u001B[1;37;44m Status Check (' + str(device_id) + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + serviceState + '\u001B[0m') + logging.debug('\u001B[1;34m ' + dataConnectionState + '\u001B[0m') + logging.debug('\u001B[1;34m ' + dataConnectionReason + '\u001B[0m') + statusQueue.put(0) + statusQueue.put(device_id) + qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason + statusQueue.put(qMsg) + lock.release() + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def CheckStatusUE(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + multi_jobs = [] + lock = Lock() + status_queue = SimpleQueue() + i = 0 + for device_id in self.UEDevices: + p = Process(target = self.CheckUEStatus_common, args = (lock,device_id,status_queue,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd /opt/flexran_rtc', '\$', 5) + SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) + SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) + result = re.search('Nb Connected UE = (?P[0-9]+)', SSH.getBefore()) + passStatus = True + if result is not None: + nb_ues = int(result.group('nb_ues')) + htmlOptions = 'Nb Connected UE(s) to eNB = ' + str(nb_ues) + logging.debug('\u001B[1;37;44m ' + htmlOptions + ' \u001B[0m') + if self.expectedNbOfConnectedUEs > -1: + if nb_ues != self.expectedNbOfConnectedUEs: + passStatus = False + else: + htmlOptions = 'N/A' + SSH.close() + else: + passStatus = True + htmlOptions = 'N/A' + + if (status_queue.empty()): + self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + check_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + check_status = False + device_id = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\n' + message + '
' + html_queue.put(html_cell) + if check_status and passStatus: + self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def GetAllUEIPAddresses(self): + if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + ue_ip_status = 0 + self.UEIPAddresses = [] + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('ifconfig oaitun_ue1', '\$', 4) + result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', SSH.getBefore()) + if result is not None: + if result.group('ueipaddress') is not None: + UE_IPAddress = result.group('ueipaddress') + else: + UE_IPAddress = result.group('ueipaddress2') + logging.debug('\u001B[1mUE (' + self.UEDevices[0] + ') IP Address is ' + UE_IPAddress + '\u001B[0m') + self.UEIPAddresses.append(UE_IPAddress) + else: + logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') + ue_ip_status -= 1 + SSH.close() + return ue_ip_status + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + idx = 0 + for device_id in self.UEDevices: + if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: + idx += 1 + continue + count = 0 + while count < 4: + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) + result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', SSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') + time.sleep(1) + count += 1 + else: + count = 10 + if count < 9: + ue_ip_status -= 1 + continue + UE_IPAddress = result.group('ueipaddress') + logging.debug('\u001B[1mUE (' + device_id + ') IP Address is ' + UE_IPAddress + '\u001B[0m') + for ueipaddress in self.UEIPAddresses: + if ueipaddress == UE_IPAddress: + logging.debug('\u001B[1mUE (' + device_id + ') IP Address ' + UE_IPAddress + ': has already been allocated to another device !' + '\u001B[0m') + ue_ip_status -= 1 + continue + self.UEIPAddresses.append(UE_IPAddress) + idx += 1 + SSH.close() + return ue_ip_status + + def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(message) + lock.release() + + def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): + try: + # Launch ping on the EPC side (true for ltebox and old open-air-cn) + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): + launchFromEpc = False + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + + if launchFromEpc: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) + SSH.command('cd scripts', '\$', 5) + ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + else: + cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + ping_status = ret.returncode + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cat ' + EPC.GetSourceCodePath() + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + lock.acquire() + logging.debug('\u001B[1;37;44m ping result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + if (packetLossOK): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(qMsg) + lock.release() + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def PingNoS1_wrong_exit(self, qMsg): + html_queue = SimpleQueue() + html_cell = '
OAI UE ping result\n' + qMsg + '
' + html_queue.put(html_cell) + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + + def PingNoS1(self): + check_eNB = True + check_OAI_UE = True + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) + if ping_from_eNB is not None: + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + else: + if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + try: + if ping_from_eNB is not None: + SSH.open(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword) + SSH.command('cd ' + RAN.GeteNBSourceCodePath() + '/cmake_targets/', '\$', 5) + else: + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) + ping_time = re.findall("-c (\d+)",str(self.ping_args)) + ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) + # TIMEOUT CASE + if ping_status < 0: + message = 'Ping with OAI UE crashed due to TIMEOUT!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) + if result is None: + message = 'Packet Loss Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + packetloss = result.group('packetloss') + if float(packetloss) == 100: + message = 'Packet Loss is 100%' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) + if result is None: + message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.PingNoS1_wrong_exit(message) + return + rtt_min = result.group('rtt_min') + rtt_avg = result.group('rtt_avg') + rtt_max = result.group('rtt_max') + pal_msg = 'Packet Loss : ' + packetloss + '%' + min_msg = 'RTT(Min) : ' + rtt_min + ' ms' + avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' + max_msg = 'RTT(Max) : ' + rtt_max + ' ms' + logging.debug('\u001B[1;37;44m OAI UE ping result \u001B[0m') + logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') + logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') + qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + packetLossOK = True + if packetloss is not None: + if float(packetloss) > float(self.ping_packetloss_threshold): + qMsg += '\nPacket Loss too high' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + packetLossOK = False + elif float(packetloss) > 0: + qMsg += '\nPacket Loss is not 0%' + logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') + SSH.close() + html_queue = SimpleQueue() + ip_addr = 'TBD' + html_cell = '
OAI UE ping result\n' + qMsg + '
' + html_queue.put(html_cell) + if packetLossOK: + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + + # copying on the EPC server for logCollection + if ping_from_eNB is not None: + copyin_res = SSH.copyin(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword, RAN.GeteNBSourceCodePath() + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + else: + copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + if (copyin_res == 0): + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'ping_' + self.testCase_id + '.log', EPC.GetSourceCodePath() + '/scripts') + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def Ping(self): + result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) + if result is not None: + self.PingNoS1() + return + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + check_OAI_UE = True + else: + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB() + return + multi_jobs = [] + i = 0 + lock = Lock() + status_queue = SimpleQueue() + for UE_IPAddress in self.UEIPAddresses: + device_id = self.UEDevices[i] + p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + ping_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + ping_status = False + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (ping_status): + self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def Iperf_ComputeTime(self): + result = re.search('-t (?P\d+)', str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Iperf time Not Found! \u001B[0m') + sys.exit(1) + return result.group('iperf_time') + + def Iperf_ComputeModifiedBW(self, idx, ue_num): + result = re.search('-b (?P[0-9\.]+)[KMG]', str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Iperf bandwidth Not Found! \u001B[0m') + sys.exit(1) + iperf_bandwidth = result.group('iperf_bandwidth') + if self.iperf_profile == 'balanced': + iperf_bandwidth_new = float(iperf_bandwidth)/ue_num + if self.iperf_profile == 'single-ue': + iperf_bandwidth_new = float(iperf_bandwidth) + if self.iperf_profile == 'unbalanced': + # residual is 2% of max bw + residualBW = float(iperf_bandwidth) / 50 + if idx == 0: + iperf_bandwidth_new = float(iperf_bandwidth) - ((ue_num - 1) * residualBW) + else: + iperf_bandwidth_new = residualBW + iperf_bandwidth_str = '-b ' + iperf_bandwidth + iperf_bandwidth_str_new = '-b ' + ('%.2f' % iperf_bandwidth_new) + result = re.sub(iperf_bandwidth_str, iperf_bandwidth_str_new, str(self.iperf_args)) + if result is None: + logging.debug('\u001B[1;37;41m Calculate Iperf bandwidth Failed! \u001B[0m') + sys.exit(1) + return result + + def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + SSH.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', SSH.getBefore()) + if result is not None: + avgbitrate = result.group('average') + maxbitrate = result.group('maximum') + minbitrate = result.group('minimum') + lock.acquire() + logging.debug('\u001B[1;37;44m TCP iperf result (' + UE_IPAddress + ') \u001B[0m') + msg = 'TCP Stats :\n' + if avgbitrate is not None: + logging.debug('\u001B[1;34m Avg Bitrate : ' + avgbitrate + '\u001B[0m') + msg += 'Avg Bitrate : ' + avgbitrate + '\n' + if maxbitrate is not None: + logging.debug('\u001B[1;34m Max Bitrate : ' + maxbitrate + '\u001B[0m') + msg += 'Max Bitrate : ' + maxbitrate + '\n' + if minbitrate is not None: + logging.debug('\u001B[1;34m Min Bitrate : ' + minbitrate + '\u001B[0m') + msg += 'Min Bitrate : ' + minbitrate + '\n' + statusQueue.put(0) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + return 0 + + def Iperf_analyzeV2Output(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + result = re.search('-u', str(iperf_real_options)) + if result is None: + return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) + + result = re.search('Server Report:', SSH.getBefore()) + if result is None: + result = re.search('read failed: Connection refused', SSH.getBefore()) + if result is not None: + logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') + else: + logging.debug('\u001B[1;37;41m Server Report and Connection refused Not Found! \u001B[0m') + return -1 + # Computing the requested bandwidth in float + result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) + if result is not None: + req_bandwidth = result.group('iperf_bandwidth') + req_bw = float(req_bandwidth) + result = re.search('-b [0-9\.]+K', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Kbits/sec' % req_bw + req_bw = req_bw * 1000 + result = re.search('-b [0-9\.]+M', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Mbits/sec' % req_bw + req_bw = req_bw * 1000000 + result = re.search('-b [0-9\.]+G', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Gbits/sec' % req_bw + req_bw = req_bw * 1000000000 + + result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', SSH.getBefore()) + if result is not None: + bitrate = result.group('bitrate') + packetloss = result.group('packetloss') + jitter = result.group('jitter') + lock.acquire() + logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') + iperfStatus = True + msg = 'Req Bitrate : ' + req_bandwidth + '\n' + logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m') + if bitrate is not None: + msg += 'Bitrate : ' + bitrate + '\n' + logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') + result = re.search('(?P[0-9\.]+) [KMG]bits/sec', str(bitrate)) + if result is not None: + actual_bw = float(str(result.group('real_bw'))) + result = re.search('[0-9\.]+ K', bitrate) + if result is not None: + actual_bw = actual_bw * 1000 + result = re.search('[0-9\.]+ M', bitrate) + if result is not None: + actual_bw = actual_bw * 1000000 + result = re.search('[0-9\.]+ G', bitrate) + if result is not None: + actual_bw = actual_bw * 1000000000 + br_loss = 100 * actual_bw / req_bw + bitperf = '%.2f ' % br_loss + msg += 'Bitrate Perf: ' + bitperf + '%\n' + logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m') + if packetloss is not None: + msg += 'Packet Loss : ' + packetloss + '%\n' + logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') + if float(packetloss) > float(self.iperf_packetloss_threshold): + msg += 'Packet Loss too high!\n' + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + iperfStatus = False + if jitter is not None: + msg += 'Jitter : ' + jitter + '\n' + logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m') + if (iperfStatus): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + return 0 + else: + return -2 + + def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): + if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') + return + # Computing the requested bandwidth in float + result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) + if result is None: + logging.debug('Iperf bandwidth Not Found!') + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not compute Iperf bandwidth!') + return + else: + req_bandwidth = result.group('iperf_bandwidth') + req_bw = float(req_bandwidth) + result = re.search('-b [0-9\.]+K', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Kbits/sec' % req_bw + req_bw = req_bw * 1000 + result = re.search('-b [0-9\.]+M', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Mbits/sec' % req_bw + req_bw = req_bw * 1000000 + result = re.search('-b [0-9\.]+G', str(iperf_real_options)) + if result is not None: + req_bandwidth = '%.1f Gbits/sec' % req_bw + req_bw = req_bw * 1000000000 + + server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') + br_sum = 0.0 + ji_sum = 0.0 + pl_sum = 0 + ps_sum = 0 + row_idx = 0 + for line in server_file.readlines(): + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) + if result is not None: + bitrate = result.group('bitrate') + jitter = result.group('jitter') + packetlost = result.group('lostPack') + packetsent = result.group('sentPack') + br = bitrate.split(' ') + ji = jitter.split(' ') + row_idx = row_idx + 1 + curr_br = float(br[0]) + pl_sum = pl_sum + int(packetlost) + ps_sum = ps_sum + int(packetsent) + if (br[1] == 'Kbits/sec'): + curr_br = curr_br * 1000 + if (br[1] == 'Mbits/sec'): + curr_br = curr_br * 1000 * 1000 + br_sum = curr_br + br_sum + ji_sum = float(ji[0]) + ji_sum + if (row_idx > 0): + br_sum = br_sum / row_idx + ji_sum = ji_sum / row_idx + br_loss = 100 * br_sum / req_bw + if (br_sum > 1000): + br_sum = br_sum / 1000 + if (br_sum > 1000): + br_sum = br_sum / 1000 + bitrate = '%.2f Mbits/sec' % br_sum + else: + bitrate = '%.2f Kbits/sec' % br_sum + else: + bitrate = '%.2f bits/sec' % br_sum + bitperf = '%.2f ' % br_loss + bitperf += '%' + jitter = '%.2f ms' % (ji_sum) + if (ps_sum > 0): + pl = float(100 * pl_sum / ps_sum) + packetloss = '%2.1f ' % (pl) + packetloss += '%' + else: + packetloss = 'unknown' + lock.acquire() + if (br_loss < 90): + statusQueue.put(1) + else: + statusQueue.put(0) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + req_msg = 'Req Bitrate : ' + req_bandwidth + bir_msg = 'Bitrate : ' + bitrate + brl_msg = 'Bitrate Perf: ' + bitperf + jit_msg = 'Jitter : ' + jitter + pal_msg = 'Packet Loss : ' + packetloss + statusQueue.put(req_msg + '\n' + bir_msg + '\n' + brl_msg + '\n' + jit_msg + '\n' + pal_msg + '\n') + logging.debug('\u001B[1;37;45m iperf result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;35m ' + req_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + bir_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + brl_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + jit_msg + '\u001B[0m') + logging.debug('\u001B[1;35m ' + pal_msg + '\u001B[0m') + lock.release() + else: + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') + + server_file.close() + + + def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', SSH.getBefore()) + if result is None: + result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', SSH.getBefore()) + lock.acquire() + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + if result is not None: + logging.debug('\u001B[1;37;41m ' + result.group('error') + ' \u001B[0m') + statusQueue.put(result.group('error')) + else: + logging.debug('\u001B[1;37;41m Bitrate and/or Packet Loss Not Found! \u001B[0m') + statusQueue.put('Bitrate and/or Packet Loss Not Found!') + lock.release() + + bitrate = result.group('bitrate') + packetloss = result.group('packetloss') + lock.acquire() + logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') + logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') + msg = 'Bitrate : ' + bitrate + '\n' + iperfStatus = True + if packetloss is not None: + logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') + msg += 'Packet Loss : ' + packetloss + '%\n' + if float(packetloss) > float(self.iperf_packetloss_threshold): + logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') + msg += 'Packet Loss too high!\n' + iperfStatus = False + if (iperfStatus): + statusQueue.put(0) + else: + statusQueue.put(-1) + statusQueue.put(device_id) + statusQueue.put(UE_IPAddress) + statusQueue.put(msg) + lock.release() + + def Iperf_UL_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): + udpIperf = True + result = re.search('-u', str(self.iperf_args)) + if result is None: + udpIperf = False + ipnumbers = UE_IPAddress.split('.') + if (len(ipnumbers) == 4): + ipnumbers[3] = '1' + EPC_Iperf_UE_IPAddress = ipnumbers[0] + '.' + ipnumbers[1] + '.' + ipnumbers[2] + '.' + ipnumbers[3] + + # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 + # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): + launchFromEpc = False + cmd = 'hostname -I' + ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') + if ret.stdout is not None: + EPC_Iperf_UE_IPAddress = ret.stdout.strip() + port = 5001 + idx + if launchFromEpc: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if udpIperf: + SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.GetUserName(), 5) + else: + SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.GetUserName(), 5) + SSH.close() + else: + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + if udpIperf: + cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + else: + cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' + logging.debug(cmd) + subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') + time.sleep(0.5) + + # Launch iperf client on UE + if (device_id == 'OAI-UE'): + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + else: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) + iperf_time = self.Iperf_ComputeTime() + time.sleep(0.5) + + if udpIperf: + modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) + else: + modified_options = str(self.iperf_args) + modified_options = modified_options.replace('-R','') + time.sleep(0.5) + + SSH.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if (device_id == 'OAI-UE'): + iperf_status = SSH.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + if self.ADBCentralized: + iperf_status = SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + iperf_status = SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + SSH.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # TIMEOUT Case + if iperf_status < 0: + SSH.close() + message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) + SSH.close() + + # Kill iperf server on EPC side + if launchFromEpc: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('killall --signal SIGKILL iperf', EPC.GetUserName(), 5) + SSH.close() + else: + cmd = 'killall --signal SIGKILL iperf' + logging.debug(cmd) + subprocess.run(cmd, shell=True) + time.sleep(1) + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + # in case of failure, retrieve server log + if (clientStatus == -1) or (clientStatus == -2): + if launchFromEpc: + time.sleep(1) + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') + SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + # in case of OAI-UE + if (device_id == 'OAI-UE'): + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + + def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): + try: + # Single-UE profile -- iperf only on one UE + if self.iperf_profile == 'single-ue' and idx != 0: + return + useIperf3 = False + udpIperf = True + + self.ueIperfVersion = '2.0.5' + if (device_id != 'OAI-UE'): + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it + SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) + # Checking if iperf / iperf3 are installed + if self.ADBCentralized: + SSH.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) + result = re.search('iperf3', SSH.getBefore()) + if result is None: + result = re.search('iperf', SSH.getBefore()) + if result is None: + message = 'Neither iperf nor iperf3 installed on UE!' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + SSH.close() + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + else: + if self.ADBCentralized: + SSH.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) + result = re.search('iperf version 2.0.5', SSH.getBefore()) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', SSH.getBefore()) + if result is not None: + self.ueIperfVersion = '2.0.10' + else: + useIperf3 = True + SSH.close() + else: + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('iperf --version', '\$', 5) + result = re.search('iperf version 2.0.5', SSH.getBefore()) + if result is not None: + self.ueIperfVersion = '2.0.5' + result = re.search('iperf version 2.0.10', SSH.getBefore()) + if result is not None: + self.ueIperfVersion = '2.0.10' + SSH.close() + # in case of iperf, UL has its own function + if (not useIperf3): + result = re.search('-R', str(self.iperf_args)) + if result is not None: + self.Iperf_UL_common(lock, UE_IPAddress, device_id, idx, ue_num, statusQueue) + return + + # Launch the IPERF server on the UE side for DL + if (device_id == 'OAI-UE'): + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('-u', str(self.iperf_args)) + if result is None: + SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + udpIperf = False + else: + SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) + else: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) + if self.ADBCentralized: + if (useIperf3): + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) + else: + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + result = re.search('-u', str(self.iperf_args)) + if result is None: + SSH.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + udpIperf = False + else: + SSH.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) + else: + SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + SSH.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) + + time.sleep(0.5) + SSH.close() + + # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn + # But for OAI-Rel14-CUPS, we launch from python executor + launchFromEpc = True + if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): + launchFromEpc = False + if launchFromEpc: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) + iperf_time = self.Iperf_ComputeTime() + time.sleep(0.5) + + if udpIperf: + modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) + else: + modified_options = str(self.iperf_args) + time.sleep(0.5) + + if launchFromEpc: + SSH.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + else: + if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') + if (useIperf3): + SSH.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + + clientStatus = 0 + self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) + else: + if launchFromEpc: + iperf_status = SSH.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) + else: + if self.ueIperfVersion == self.dummyIperfVersion: + prefix = '' + else: + prefix = '' + if self.ueIperfVersion == '2.0.5': + prefix = '/opt/iperf-2.0.5/bin/' + cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' + message = cmd + '\n' + logging.debug(cmd) + ret = subprocess.run(cmd, shell=True) + iperf_status = ret.returncode + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cat ' + EPC.GetSourceCodePath() + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + if iperf_status < 0: + if launchFromEpc: + SSH.close() + message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) + return + clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) + SSH.close() + + # Kill the IPERF server that runs in background + if (device_id == 'OAI-UE'): + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('killall iperf', '\$', 5) + else: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) + result = re.search('shell +(?P\d+)', SSH.getBefore()) + if result is not None: + pid_iperf = result.group('pid') + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + SSH.close() + # if the client report is absent, try to analyze the server log file + if (clientStatus == -1): + time.sleep(1) + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') + if (device_id == 'OAI-UE'): + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + else: + SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # fromdos has to be called on the python executor not on ADB server + cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log' + subprocess.run(cmd, shell=True) + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + + # in case of OAI UE: + if (device_id == 'OAI-UE'): + if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): + if not launchFromEpc: + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + else: + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def IperfNoS1(self): + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + check_OAI_UE = True + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + server_on_enb = re.search('-R', str(self.iperf_args)) + if server_on_enb is not None: + iServerIPAddr = RAN.GeteNBIPAddress + iServerUser = RAN.GeteNBUserName + iServerPasswd = RAN.GeteNBPassword + iClientIPAddr = self.UEIPAddress + iClientUser = self.UEUserName + iClientPasswd = self.UEPassword + else: + iServerIPAddr = self.UEIPAddress + iServerUser = self.UEUserName + iServerPasswd = self.UEPassword + iClientIPAddr = RAN.GeteNBIPAddress + iClientUser = RAN.GeteNBUserName + iClientPasswd = RAN.GeteNBPassword + if self.iperf_options != 'sink': + # Starting the iperf server + SSH.open(iServerIPAddr, iServerUser, iServerPasswd) + # args SHALL be "-c client -u any" + # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 + # -B 10.0.1.1 -u -s -i 1 -fm + server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) + server_options = server_options.replace('-c','-B') + SSH.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) + SSH.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) + time.sleep(0.5) + SSH.close() + + # Starting the iperf client + modified_options = self.Iperf_ComputeModifiedBW(0, 1) + modified_options = modified_options.replace('-R','') + iperf_time = self.Iperf_ComputeTime() + SSH.open(iClientIPAddr, iClientUser, iClientPasswd) + SSH.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) + iperf_status = SSH.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) + status_queue = SimpleQueue() + lock = Lock() + if iperf_status < 0: + message = 'iperf on OAI UE crashed due to TIMEOUT !' + logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') + clientStatus = -2 + else: + if self.iperf_options == 'sink': + clientStatus = 0 + status_queue.put(0) + status_queue.put('OAI-UE') + status_queue.put('10.0.1.2') + status_queue.put('Sink Test : no check') + else: + clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + SSH.close() + + # Stopping the iperf server + if self.iperf_options != 'sink': + SSH.open(iServerIPAddr, iServerUser, iServerPasswd) + SSH.command('killall --signal SIGKILL iperf', '\$', 5) + time.sleep(0.5) + SSH.close() + + if (clientStatus == -1): + if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): + os.remove('iperf_server_' + self.testCase_id + '.log') + SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) + + # copying on the EPC server for logCollection + if (clientStatus == -1): + copyin_res = SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_OAI-UE.log', EPC.GetSourceCodePath() + '/scripts') + copyin_res = SSH.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') + if (copyin_res == 0): + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_OAI-UE.log', EPC.GetSourceCodePath() + '/scripts') + iperf_noperf = False + if status_queue.empty(): + iperf_status = False + else: + iperf_status = True + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + iperf_status = False + if (count > 0): + iperf_noperf = True + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (iperf_noperf and iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + elif (iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def Iperf(self): + result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) + if result is not None: + self.IperfNoS1() + return + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + check_eNB = True + if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): + check_OAI_UE = True + else: + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + self.AutoTerminateUEandeNB() + return + ueIpStatus = self.GetAllUEIPAddresses() + if (ueIpStatus < 0): + self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) + self.AutoTerminateUEandeNB() + return + + self.dummyIperfVersion = '2.0.10' + #cmd = 'iperf --version' + #logging.debug(cmd + '\n') + #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) + #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.5' + #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) + #if result is not None: + # dummyIperfVersion = '2.0.10' + + multi_jobs = [] + i = 0 + ue_num = len(self.UEIPAddresses) + lock = Lock() + status_queue = SimpleQueue() + for UE_IPAddress in self.UEIPAddresses: + device_id = self.UEDevices[i] + p = Process(target = CiTestObj.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i = i + 1 + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) + self.AutoTerminateUEandeNB() + else: + iperf_status = True + iperf_noperf = False + html_queue = SimpleQueue() + while (not status_queue.empty()): + count = status_queue.get() + if (count < 0): + iperf_status = False + if (count > 0): + iperf_noperf = True + device_id = status_queue.get() + ip_addr = status_queue.get() + message = status_queue.get() + html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' + html_queue.put(html_cell) + if (iperf_noperf and iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + elif (iperf_status): + self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + self.AutoTerminateUEandeNB() + + def CheckProcessExist(self, check_eNB, check_OAI_UE): + multi_jobs = [] + status_queue = SimpleQueue() + # in noS1 config, no need to check status from EPC + # in gNB also currently no need to check + result = re.search('noS1|band78', str(RAN.GetInitialize_eNB_args())) + if result is None: + p = Process(target = EPC.CheckHSSProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + p = Process(target = EPC.CheckMMEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + p = Process(target = EPC.CheckSPGWProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + else: + if (check_eNB == False) and (check_OAI_UE == False): + return 0 + if check_eNB: + p = Process(target = CiTestObj.CheckeNBProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + if check_OAI_UE: + p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + return -15 + else: + result = 0 + while (not status_queue.empty()): + status = status_queue.get() + if (status < 0): + result = status + if result == ENB_PROCESS_FAILED: + fileCheck = re.search('enb_', str(RAN.GeteNBLogFiles[0])) + if fileCheck is not None: + SSH.copyin(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword, RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') + logStatus = self.AnalyzeLogFile_eNB(RAN.GeteNBLogFiles[0]) + if logStatus < 0: + result = logStatus + RAN.SeteNBLogFiles[0] = '' + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.TerminateFlexranCtrl() + return result + + def CheckOAIUEProcessExist(self, initialize_OAI_UE_flag): + multi_jobs = [] + status_queue = SimpleQueue() + if initialize_OAI_UE_flag == False: + p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) + p.daemon = True + p.start() + multi_jobs.append(p) + for job in multi_jobs: + job.join() + + if (status_queue.empty()): + return -15 + else: + result = 0 + while (not status_queue.empty()): + status = status_queue.get() + if (status < 0): + result = status + if result == OAI_UE_PROCESS_FAILED: + fileCheck = re.search('ue_', str(self.UELogFile)) + if fileCheck is not None: + SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + logStatus = self.AnalyzeLogFile_UE(self.UELogFile) + if logStatus < 0: + result = logStatus + return result + + def CheckOAIUEProcess(self, status_queue): + try: + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + RAN.Getair_interface() + '-uesoftmodem | grep -v grep', '\$', 5) + result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') + status_queue.put(OAI_UE_PROCESS_FAILED) + else: + status_queue.put(OAI_UE_PROCESS_OK) + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) +''' + def CheckeNBProcess(self, status_queue): + try: + # At least the instance 0 SHALL be on! + if self.eNBstatuses[0] == 0: + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + elif self.eNBstatuses[0] == 1: + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + elif self.eNBstatuses[0] == 2: + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + else: + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-softmodem | grep -v grep', '\$', 5) + result = re.search(self.air_interface + '-softmodem', SSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') + status_queue.put(ENB_PROCESS_FAILED) + else: + status_queue.put(ENB_PROCESS_OK) + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) +''' + def AnalyzeLogFile_eNB(self, eNBlogFile): + if (not os.path.isfile('./' + eNBlogFile)): + return -1 + enb_log_file = open('./' + eNBlogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + rrcSetupComplete = 0 + rrcReleaseRequest = 0 + rrcReconfigRequest = 0 + rrcReconfigComplete = 0 + rrcReestablishRequest = 0 + rrcReestablishComplete = 0 + rrcReestablishReject = 0 + rlcDiscardBuffer = 0 + rachCanceledProcedure = 0 + uciStatMsgCount = 0 + pdcpFailure = 0 + ulschFailure = 0 + cdrxActivationMessageCount = 0 + dropNotEnoughRBs = 0 + mbmsRequestMsg = 0 + self.htmleNBFailureMsg = '' + isRRU = False + isSlave = False + slaveReceivesFrameResyncCmd = False + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures = 0 + X2HO_outNbProcedures = 0 + for line in enb_log_file.readlines(): + if X2HO_state == X2_HO_REQ_STATE__IDLE: + result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ + result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK + if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: + result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE + if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: + result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ + if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: + result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures += 1 + if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: + result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_outNbProcedures += 1 + + if RAN.SeteNBOptions[int(RAN.GeteNB_instance())] != '': + res1 = re.search('max_rxgain (?P[0-9]+)', RAN.GeteNBOptions[int(RAN.GeteNB_instance())]) + res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) + if res1 is not None and res2 is not None: + requested_option = int(res1.group('requested_option')) + applied_option = int(res2.group('applied_option')) + if requested_option == applied_option: + self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + RAN.GeteNBOptions[int(RAN.GeteNB_instance())] + '\n\n' + else: + self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + RAN.GeteNBOptions[int(RAN.GeteNB_instance())] + '\n\n' + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('[Ss]egmentation [Ff]ault', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./ran_build/build/lte-softmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('Setting function for RU', str(line)) + if result is not None: + isRRU = True + if isRRU: + result = re.search('RU 0 is_slave=yes', str(line)) + if result is not None: + isSlave = True + if isSlave: + result = re.search('Received RRU_frame_resynch command', str(line)) + if result is not None: + slaveReceivesFrameResyncCmd = True + result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) + if result is not None: + rrcSetupComplete += 1 + result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) + if result is not None: + rrcReleaseRequest += 1 + result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) + if result is not None: + rrcReconfigRequest += 1 + result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) + if result is not None: + rrcReconfigComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) + if result is not None: + rrcReestablishRequest += 1 + result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) + if result is not None: + rrcReestablishComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) + if result is not None: + rrcReestablishReject += 1 + result = re.search('CDRX configuration activated after RRC Connection', str(line)) + if result is not None: + cdrxActivationMessageCount += 1 + result = re.search('uci->stat', str(line)) + if result is not None: + uciStatMsgCount += 1 + result = re.search('PDCP.*Out of Resources.*reason', str(line)) + if result is not None: + pdcpFailure += 1 + result = re.search('ULSCH in error in round', str(line)) + if result is not None: + ulschFailure += 1 + result = re.search('BAD all_segments_received', str(line)) + if result is not None: + rlcDiscardBuffer += 1 + result = re.search('Canceled RA procedure for UE rnti', str(line)) + if result is not None: + rachCanceledProcedure += 1 + result = re.search('dropping, not enough RBs', str(line)) + if result is not None: + dropNotEnoughRBs += 1 + if RAN.GeteNBmbmsEnables[int(RAN.GeteNB_instance())]: + result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line)) + if result is not None: + mbmsRequestMsg += 1 + enb_log_file.close() + logging.debug(' File analysis completed') + self.htmleNBFailureMsg = '' + if RAN.Getair_interface() == 'lte': + nodeB_prefix = 'e' + else: + nodeB_prefix = 'g' + if uciStatMsgCount > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if pdcpFailure > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if ulschFailure > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if dropNotEnoughRBs > 0: + statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if rrcSetupComplete > 0: + rrcMsg = nodeB_prefix + 'NB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcSetupComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReleaseRequest > 0: + rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: + rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: + rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if RAN.GeteNBmbmsEnables[int(RAN.GeteNB_instance())]: + if mbmsRequestMsg > 0: + rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_inNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_outNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if RAN.SeteNBOptions[int(RAN.GeteNB_instance())] != '': + res1 = re.search('drx_Config_present prSetup', RAN.GeteNBOptions[int(RAN.GeteNB_instance())]) + if res1 is not None: + if cdrxActivationMessageCount > 0: + rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + else: + rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' + logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rachCanceledProcedure > 0: + rachMsg = nodeB_prefix + 'NB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' + logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rachMsg + '\n' + if isRRU: + if isSlave: + if slaveReceivesFrameResyncCmd: + rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + else: + rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + self.prematureExit = True + return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED + if foundSegFault: + logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m') + return ENB_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m') + self.htmleNBFailureMsg += msgAssertion + return ENB_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') + self.htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if rlcDiscardBuffer > 0: + rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' + logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rlcMsg + '\n' + return ENB_PROCESS_REALTIME_ISSUE + return 0 + + def AnalyzeLogFile_UE(self, UElogFile): + if (not os.path.isfile('./' + UElogFile)): + return -1 + ue_log_file = open('./' + UElogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + uciStatMsgCount = 0 + pdcpDataReqFailedCount = 0 + badDciCount = 0 + f1aRetransmissionCount = 0 + fatalErrorCount = 0 + macBsrTimerExpiredCount = 0 + rrcConnectionRecfgComplete = 0 + no_cell_sync_found = False + mib_found = False + frequency_found = False + plmn_found = False + nrUEFlag = False + nrDecodeMib = 0 + nrFoundDCI = 0 + nrCRCOK = 0 + mbms_messages = 0 + self.htmlUEFailureMsg = '' + for line in ue_log_file.readlines(): + result = re.search('nr_synchro_time', str(line)) + if result is not None: + nrUEFlag = True + if nrUEFlag: + result = re.search('decode mib', str(line)) + if result is not None: + nrDecodeMib += 1 + result = re.search('found 1 DCIs', str(line)) + if result is not None: + nrFoundDCI += 1 + result = re.search('CRC OK', str(line)) + if result is not None: + nrCRCOK += 1 + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./lte-uesoftmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('uci->stat', str(line)) + if result is not None and not exitSignalReceived: + uciStatMsgCount += 1 + result = re.search('PDCP data request failed', str(line)) + if result is not None and not exitSignalReceived: + pdcpDataReqFailedCount += 1 + result = re.search('bad DCI 1', str(line)) + if result is not None and not exitSignalReceived: + badDciCount += 1 + result = re.search('Format1A Retransmission but TBS are different', str(line)) + if result is not None and not exitSignalReceived: + f1aRetransmissionCount += 1 + result = re.search('FATAL ERROR', str(line)) + if result is not None and not exitSignalReceived: + fatalErrorCount += 1 + result = re.search('MAC BSR Triggered ReTxBSR Timer expiry', str(line)) + if result is not None and not exitSignalReceived: + macBsrTimerExpiredCount += 1 + result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) + if result is not None: + rrcConnectionRecfgComplete += 1 + # No cell synchronization found, abandoning + result = re.search('No cell synchronization found, abandoning', str(line)) + if result is not None: + no_cell_sync_found = True + if RAN.GeteNBmbmsEnables[0]: + result = re.search('TRIED TO PUSH MBMS DATA', str(line)) + if result is not None: + mbms_messages += 1 + result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) + if result is not None and (not mib_found): + try: + mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " nidcell = " + result.group('nidcell') + self.htmlUEFailureMsg += mibMsg + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " n_rb_dl = " + result.group('n_rb_dl') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " phich_duration = " + result.group('phich_duration') + self.htmlUEFailureMsg += mibMsg + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " phich_resource = " + result.group('phich_resource') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mibMsg = " tx_ant = " + result.group('tx_ant') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + mib_found = True + except Exception as e: + logging.error('\033[91m' + "MIB marker was not found" + '\033[0m') + result = re.search("Measured Carrier Frequency (?P\d{1,15}) Hz", str(line)) + if result is not None and (not frequency_found): + try: + mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + frequency_found = True + except Exception as e: + logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') + result = re.search("PLMN MCC (?P\d{1,3}), MNC (?P\d{1,3}), TAC", str(line)) + if result is not None and (not plmn_found): + try: + mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + plmn_found = True + except Exception as e: + logging.error('\033[91m' + "PLMN not found" + '\033[0m') + result = re.search("Found (?P[\w,\s]{1,15}) \(name from internal table\)", str(line)) + if result is not None: + try: + mibMsg = "The operator is: " + result.group('operator') + self.htmlUEFailureMsg += mibMsg + '\n' + logging.debug('\033[94m' + mibMsg + '\033[0m') + except Exception as e: + logging.error('\033[91m' + "Operator name not found" + '\033[0m') + result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line)) + if result is not None: + try: + mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) + self.htmlUEFailureMsg += mibMsg + ' -> ' + logging.debug('\033[94m' + mibMsg + '\033[0m') + except Exception as e: + logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') + result = re.search("DL Carrier Frequency/ARFCN : (?P\d{1,15}/\d{1,4})", str(line)) + if result is not None: + try: + freq = result.group('carrier_frequency') + new_freq = re.sub('/[0-9]+','',freq) + float_freq = float(new_freq) / 1000000 + self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' + logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') + except Exception as e: + logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') + result = re.search("AllowedMeasBandwidth : (?P\d{1,7})", str(line)) + if result is not None: + try: + prb = result.group('allowed_bandwidth') + self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' + logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') + except Exception as e: + logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') + ue_log_file.close() + if rrcConnectionRecfgComplete > 0: + statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' + logging.debug('\033[94m' + statMsg + '\033[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if nrUEFlag: + if nrDecodeMib > 0: + statMsg = 'UE showed ' + str(nrDecodeMib) + ' MIB decode message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if nrFoundDCI > 0: + statMsg = 'UE showed ' + str(nrFoundDCI) + ' DCI found message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if nrCRCOK > 0: + statMsg = 'UE showed ' + str(nrCRCOK) + ' PDSCH decoding message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if not frequency_found: + statMsg = 'NR-UE could NOT synch!' + logging.error('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if uciStatMsgCount > 0: + statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if pdcpDataReqFailedCount > 0: + statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if badDciCount > 0: + statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1(A)" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if f1aRetransmissionCount > 0: + statMsg = 'UE showed ' + str(f1aRetransmissionCount) + ' "Format1A Retransmission but TBS are different" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if fatalErrorCount > 0: + statMsg = 'UE showed ' + str(fatalErrorCount) + ' "FATAL ERROR:" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if macBsrTimerExpiredCount > 0: + statMsg = 'UE showed ' + str(fatalErrorCount) + ' "MAC BSR Triggered ReTxBSR Timer expiry" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if RAN.GeteNBmbmsEnables[0]: + if mbms_messages > 0: + statMsg = 'UE showed ' + str(mbms_messages) + ' "TRIED TO PUSH MBMS DATA" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + else: + statMsg = 'UE did NOT SHOW "TRIED TO PUSH MBMS DATA" message(s)' + logging.debug('\u001B[1;30;41m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if foundSegFault: + logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') + if not nrUEFlag: + return OAI_UE_PROCESS_SEG_FAULT + else: + if not frequency_found: + return OAI_UE_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') + self.htmlUEFailureMsg += 'UE showed an assertion!\n' + if not nrUEFlag: + if not mib_found or not frequency_found: + return OAI_UE_PROCESS_ASSERTION + else: + if not frequency_found: + return OAI_UE_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') + self.htmlUEFailureMsg += 'UE faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if nrUEFlag: + if not frequency_found: + return OAI_UE_PROCESS_COULD_NOT_SYNC + else: + if no_cell_sync_found and not mib_found: + logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') + self.htmlUEFailureMsg += 'UE could not synchronize!\n' + return OAI_UE_PROCESS_COULD_NOT_SYNC + return 0 +''' + def TerminateeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = RAN.GeteNBSourceCodePath() + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + if self.air_interface == 'lte': + nodeB_prefix = 'e' + else: + nodeB_prefix = 'g' + SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('-softmodem', SSH.getBefore()) + if result is not None: + SSH.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) + SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5) + time.sleep(10) + SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('-softmodem', SSH.getBefore()) + if result is not None: + SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5) + time.sleep(5) + SSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + SSH.close() + # If tracer options is on, stopping tshark on EPC side + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) + if result is not None: + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + time.sleep(1) + if EPC.EPC_PcapFileName != '': + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) + SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') + SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') + SSH.close() + logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') + SSH.open(lIpAddr, lUserName, lPassWord) + SSH.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) + enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] + raw_record_file = enbLogFile.replace('.log', '_record.raw') + replay_log_file = enbLogFile.replace('.log', '_replay.log') + extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') + extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') + SSH.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) + SSH.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) + SSH.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) + SSH.close() + SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') + logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBLogFiles[int(self.eNB_instance)] = '' + else: + analyzeFile = False + if self.eNBLogFiles[int(self.eNB_instance)] != '': + analyzeFile = True + fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] + self.eNBLogFiles[int(self.eNB_instance)] = '' + if analyzeFile: + copyin_res = SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') + self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + self.eNBmbmsEnables[int(self.eNB_instance)] = False + return + if self.eNB_serverId != '0': + SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, RAN.GeteNBSourceCodePath() + '/cmake_targets/') + logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) + logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) + if (logStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', logStatus) + self.preamtureExit = True + self.eNBmbmsEnables[int(self.eNB_instance)] = False + return + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBmbmsEnables[int(self.eNB_instance)] = False + self.eNBstatuses[int(self.eNB_instance)] = -1 +''' + def TerminateFlexranCtrl(self): + if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: + return + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) + time.sleep(1) + SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) + time.sleep(1) + SSH.close() + self.flexranCtrlStarted = False + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateUE_common(self, device_id, idx): + try: + SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) + # back in airplane mode on (ie radio off) + if self.ADBCentralized: + if device_id == '84B7N16418004022': + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) + else: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) + logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') + + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) + result = re.search('shell +(?P\d+)', SSH.getBefore()) + if result is not None: + pid_iperf = result.group('pid') + if self.ADBCentralized: + SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) + else: + SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) + SSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + def TerminateUE(self): + terminate_ue_flag = True + self.GetAllUEDevices(terminate_ue_flag) + multi_jobs = [] + i = 0 + for device_id in self.UEDevices: + p = Process(target= CiTestObj.TerminateUE_common, args = (device_id,i,)) + p.daemon = True + p.start() + multi_jobs.append(p) + i += 1 + for job in multi_jobs: + job.join() + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def TerminateOAIUE(self): + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) + SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('-uesoftmodem', SSH.getBefore()) + if result is not None: + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT -r .*-uesoftmodem || true', '\$', 5) + time.sleep(10) + SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('-uesoftmodem', SSH.getBefore()) + if result is not None: + SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL -r .*-uesoftmodem || true', '\$', 5) + time.sleep(5) + SSH.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.close() + result = re.search('ue_', str(self.UELogFile)) + if result is not None: + copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') + self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + self.UELogFile = '' + return + logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_UE(self.UELogFile) + result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) + if result is not None: + ueAction = 'Sniffing' + else: + ueAction = 'Connection' + if (logStatus < 0): + logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') + self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg + self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') + if RAN.Getair_interface() == 'lte': + # In case of sniffing on commercial eNBs we have random results + # Not an error then + if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): + self.Initialize_OAI_UE_args = '' + self.AutoTerminateUEandeNB() + else: + if (logStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + self.Initialize_OAI_UE_args = '' + self.AutoTerminateUEandeNB() + else: + logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') + self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.UELogFile = '' + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + + def AutoTerminateUEandeNB(self): + if (self.ADBIPAddress != 'none'): + self.testCase_id = 'AUTO-KILL-UE' + self.desc = 'Automatic Termination of UE' + self.ShowTestID() + self.TerminateUE() + if (self.Initialize_OAI_UE_args != ''): + self.testCase_id = 'AUTO-KILL-UE' + self.desc = 'Automatic Termination of UE' + self.ShowTestID() + self.TerminateOAIUE() + if (RAN.GetInitialize_eNB_args() != ''): + self.testCase_id = 'AUTO-KILL-eNB' + self.desc = 'Automatic Termination of eNB' + self.ShowTestID() + RAN.SeteNB_instance() = '0' + self.TerminateeNB() + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + self.testCase_id = 'AUTO-KILL-flexran-ctl' + self.desc = 'Automatic Termination of FlexRan CTL' + self.ShowTestID() + self.TerminateFlexranCtrl() + self.prematureExit = True + + def IdleSleep(self): + time.sleep(self.idle_sleep_time) + self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) + + def X2_Status(self, idx, fileName): + cmd = "curl --silent http://" + EPC.GetIPAddress() + ":9999/stats | jq '.' > " + fileName + message = cmd + '\n' + logging.debug(cmd) + subprocess.run(cmd, shell=True) + if idx == 0: + cmd = "jq '.mac_stats | length' " + fileName + strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2NbENBs = int(strNbEnbs.strip()) + cnt = 0 + while cnt < self.x2NbENBs: + cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName + bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2ENBBsIds[idx].append(bs_id.strip()) + cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName + stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) + nbUEs = int(stNbUEs.strip()) + ueIdx = 0 + self.x2ENBConnectedUEs[idx].append([]) + while ueIdx < nbUEs: + cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName + rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) + self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip()) + ueIdx += 1 + cnt += 1 + + msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" + logging.debug(msg) + message += msg + '\n' + cnt = 0 + while cnt < self.x2NbENBs: + msg = " -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][cnt])) + " UE(s)" + logging.debug(msg) + message += msg + '\n' + ueIdx = 0 + while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]): + msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx]) + logging.debug(msg) + message += msg + '\n' + ueIdx += 1 + cnt += 1 + return message + + def Perform_X2_Handover(self): + html_queue = SimpleQueue() + fullMessage = '
'
+		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
+		logging.debug(msg)
+		fullMessage += msg + '\n'
+		if self.x2_ho_options == 'network':
+			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
+				self.x2ENBBsIds = []
+				self.x2ENBConnectedUEs = []
+				self.x2ENBBsIds.append([])
+				self.x2ENBBsIds.append([])
+				self.x2ENBConnectedUEs.append([])
+				self.x2ENBConnectedUEs.append([])
+				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
+
+				msg = "Activating the X2 Net control on each eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				eNB_cnt = self.x2NbENBs
+				cnt = 0
+				while cnt < eNB_cnt:
+					cmd = "curl -XPOST http://" + EPC.GetIPAddress() + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1"
+					logging.debug(cmd)
+					fullMessage += cmd + '\n'
+					subprocess.run(cmd, shell=True)
+					cnt += 1
+				# Waiting for the activation to be active
+				time.sleep(10)
+				msg = "Switching UE(s) from eNB to eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				cnt = 0
+				while cnt < eNB_cnt:
+					ueIdx = 0
+					while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]):
+						cmd = "curl -XPOST http://" + EPC.GetIPAddress() + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
+						logging.debug(cmd)
+						fullMessage += cmd + '\n'
+						subprocess.run(cmd, shell=True)
+						ueIdx += 1
+					cnt += 1
+				time.sleep(10)
+				# check
+				logging.debug("Checking the Status after X2 Handover")
+				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
+				cnt = 0
+				x2Status = True
+				while cnt < eNB_cnt:
+					if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
+						x2Status = False
+					cnt += 1
+				if x2Status:
+					msg = "X2 Handover was successful"
+					logging.debug(msg)
+					fullMessage += msg + '
' + html_queue.put(fullMessage) + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + else: + msg = "X2 Handover FAILED" + logging.error(msg) + fullMessage += msg + '' + html_queue.put(fullMessage) + self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + else: + self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) + + def LogCollectBuild(self): + if (RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != ''): + IPAddress = RAN.GeteNBIPAddress + UserName = RAN.GeteNBUserName + Password = RAN.GeteNBPassword + SourceCodePath = RAN.GeteNBSourceCodePath() + elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + SourceCodePath = self.UESourceCodePath + else: + sys.exit('Insufficient Parameter') + SSH.open(IPAddress, UserName, Password) + SSH.command('cd ' + SourceCodePath, '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('rm -f build.log.zip', '\$', 5) + SSH.command('zip build.log.zip build_log_*/*', '\$', 60) + SSH.close() +''' + def LogCollecteNB(self): + SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + SSH.command('cd ' + RAN.GeteNBSourceCodePath(), '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) + SSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) + SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) + SSH.close() +''' + def LogCollectPing(self): + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('rm -f ping.log.zip', '\$', 5) + SSH.command('zip ping.log.zip ping*.log', '\$', 60) + SSH.command('rm ping*.log', '\$', 5) + SSH.close() + + def LogCollectIperf(self): + SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) + SSH.command('cd scripts', '\$', 5) + SSH.command('rm -f iperf.log.zip', '\$', 5) + SSH.command('zip iperf.log.zip iperf*.log', '\$', 60) + SSH.command('rm iperf*.log', '\$', 5) + SSH.close() + + def LogCollectOAIUE(self): + SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) + SSH.command('cd ' + self.UESourceCodePath, '\$', 5) + SSH.command('cd cmake_targets', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) + SSH.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) + SSH.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) + SSH.close() + + def RetrieveSystemVersion(self, machine): + if RAN.GeteNBIPAddress() == 'none' or self.UEIPAddress == 'none': + self.OsVersion = 'Ubuntu 16.04.5 LTS' + self.KernelVersion = '4.15.0-45-generic' + self.UhdVersion = '3.13.0.1-0' + self.UsrpBoard = 'B210' + self.CpuNb = '4' + self.CpuModel = 'Intel(R) Core(TM) i5-6200U' + self.CpuMHz = '2399.996 MHz' + return 0 + if machine == 'eNB': + if RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != '': + IPAddress = RAN.GeteNBIPAddress + UserName = RAN.GeteNBUserName + Password = RAN.GeteNBPassword + else: + return -1 + if machine == 'UE': + if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + else: + return -1 + + SSH.open(IPAddress, UserName, Password) + SSH.command('lsb_release -a', '\$', 5) + result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) + if result is not None: + self.OsVersion = result.group('os_type') + logging.debug('OS is: ' + self.OsVersion) + else: + SSH.command('hostnamectl', '\$', 5) + result = re.search('Operating System: (?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) + if result is not None: + self.OsVersion = result.group('os_type') + if self.OsVersion == 'CentOS Linux 7 ': + SSH.command('cat /etc/redhat-release', '\$', 5) + result = re.search('CentOS Linux release (?P[0-9\.]+)', SSH.getBefore()) + if result is not None: + self.OsVersion = self.OsVersion.replace('7 ', result.group('os_version')) + logging.debug('OS is: ' + self.OsVersion) + SSH.command('uname -r', '\$', 5) + result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', SSH.getBefore()) + if result is not None: + self.KernelVersion = result.group('kernel_version') + logging.debug('Kernel Version is: ' + self.KernelVersion) + SSH.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) + result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', SSH.getBefore()) + if result is not None: + self.UhdVersion = result.group('uhd_version') + logging.debug('UHD Version is: ' + self.UhdVersion) + else: + SSH.command('uhd_config_info --version', '\$', 5) + result = re.search('UHD (?P[a-zA-Z0-9\.\-]+)', SSH.getBefore()) + if result is not None: + self.UhdVersion = result.group('uhd_version') + logging.debug('UHD Version is: ' + self.UhdVersion) + SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 30) + usrp_boards = re.findall('product: ([0-9A-Za-z]+)\\\\r\\\\n', SSH.getBefore()) + count = 0 + for board in usrp_boards: + if count == 0: + self.UsrpBoard = board + else: + self.UsrpBoard += ',' + board + count += 1 + if count > 0: + logging.debug('USRP Board(s) : ' + self.UsrpBoard) + SSH.command('lscpu', '\$', 5) + result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', SSH.getBefore()) + if result is not None: + self.CpuNb = result.group('nb_cpus') + logging.debug('nb_cpus: ' + self.CpuNb) + self.CpuModel = result.group('model') + logging.debug('model: ' + self.CpuModel) + self.CpuMHz = result.group('cpu_mhz') + ' MHz' + logging.debug('cpu_mhz: ' + self.CpuMHz) + SSH.close() + +#----------------------------------------------------------- +# HTML Reporting.... +#----------------------------------------------------------- + def CreateHtmlHeader(self): + if (not self.htmlHeaderCreated): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML header \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + self.htmlFile = open('test_results.html', 'w') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') + self.htmlFile.write('\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (RAN.GetranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (RAN.GetranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (RAN.GetranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if RAN.GetranAllowMerge() != '': + commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + RAN.GetranCommitID, shell=True, universal_newlines=True) + commit_message = commit_message.strip() + self.htmlFile.write(' \n') + if (RAN.GetranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (RAN.GetranAllowMerge): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (RAN.GetranTargetBranch() == ''): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + RAN.GetranRepository() + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + RAN.GetranBranch() + '
Source Commit ID Commit ID ' + RAN.GetranCommitID() + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + RAN.GetranTargetBranch() + '
\n') + + if (self.ADBIPAddress != 'none'): + terminate_ue_flag = True + self.GetAllUEDevices(terminate_ue_flag) + self.GetAllCatMDevices(terminate_ue_flag) + self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') + self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') + else: + self.UEDevices.append('OAI-UE') + self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.close() + + def CreateHtmlTabHeader(self): + if (not self.htmlHeaderCreated): + if (not os.path.isfile('test_results.html')): + self.CreateHtmlHeader() + self.htmlFile = open('test_results.html', 'a') + if (self.nbTestXMLfiles == 1): + self.htmlFile.write('
\n') + self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') + else: + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.htmlUEConnected == -1): + terminate_ue_flag = True + if (self.ADBIPAddress != 'none'): + self.GetAllUEDevices(terminate_ue_flag) + self.GetAllCatMDevices(terminate_ue_flag) + else: + self.UEDevices.append('OAI-UE') + self.htmlUEConnected = len(self.UEDevices) + + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' \n') + i += 1 + self.htmlFile.write(' \n') + self.htmlHeaderCreated = True + + def CreateHtmlTabFooter(self, passStatus): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') + self.htmlFile.write('
\n') + self.htmlFile.close() + time.sleep(1) + if passStatus: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" + subprocess.run(cmd, shell=True) + else: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" + subprocess.run(cmd, shell=True) + self.htmlFooterCreated = False + + def CreateHtmlFooter(self, passStatus): + if (os.path.isfile('test_results.html')): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML footer \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + + self.htmlFile = open('test_results.html', 'a') + self.htmlFile.write('
\n') + self.htmlFile.write('

\n') + self.htmlFile.write(' \n') + + machines = [ 'eNB', 'UE' ] + for machine in machines: + res = self.RetrieveSystemVersion(machine) + if res == -1: + continue + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') + self.htmlFile.write('

\n') + self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('\n') + self.htmlFile.close() + + def CreateHtmlRetrySeparator(self): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile.write(' \n') + self.htmlFile.write(' Try Run #' + str(self.FailReportCnt) + '\n') + self.htmlFile.write(' \n') + + def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + currentTime = int(round(time.time() * 1000)) - self.startTime + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + if (processesStatus == 0): + self.htmlFile.write(' ' + str(status) + '\n') + elif (processesStatus == ENB_PROCESS_FAILED): + self.htmlFile.write(' KO - eNB process not found\n') + elif (processesStatus == OAI_UE_PROCESS_FAILED): + self.htmlFile.write(' KO - OAI UE process not found\n') + elif (processesStatus == ENB_PROCESS_SEG_FAULT) or (processesStatus == OAI_UE_PROCESS_SEG_FAULT): + self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') + elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): + self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') + elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): + self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') + elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): + self.htmlFile.write(' OK?\n') + elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): + self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') + elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + self.htmlFile.write(' KO - UE could not sync\n') + elif (processesStatus == HSS_PROCESS_FAILED): + self.htmlFile.write(' KO - HSS process not found\n') + elif (processesStatus == MME_PROCESS_FAILED): + self.htmlFile.write(' KO - MME process not found\n') + elif (processesStatus == SPGW_PROCESS_FAILED): + self.htmlFile.write(' KO - SPGW process not found\n') + elif (processesStatus == UE_IP_ADDRESS_ISSUE): + self.htmlFile.write(' KO - Could not retrieve UE IP address\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + if (len(str(self.htmleNBFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') + self.htmleNBFailureMsg = '' + elif (len(str(self.htmlUEFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') + self.htmlUEFailureMsg = '' + else: + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + + def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + currentTime = int(round(time.time() * 1000)) - self.startTime + addOrangeBK = False + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + self.htmlFile.write(' ' + str(status) + '\n') + else: + addOrangeBK = True + self.htmlFile.write(' ' + str(status) + '\n') + i = 0 + while (i < self.htmlUEConnected): + if (i < ue_status): + if (not ue_queue.empty()): + if (addOrangeBK): + self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') + else: + self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') + else: + self.htmlFile.write(' -\n') + else: + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + +#----------------------------------------------------------- +# ShowTestID() +#----------------------------------------------------------- + def ShowTestID(self): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1mTest ID:' + self.testCase_id + '\u001B[0m') + logging.debug('\u001B[1m' + self.desc + '\u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + +def CheckClassValidity(action,id): + if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': + logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) + return False + return True + +def GetParametersFromXML(action): + if action == 'Build_eNB': + RAN.SetBuild_eNB_args() = test.findtext('Build_eNB_args') + forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') + if (forced_workspace_cleanup is None): + RAN.SetBuild_eNB_forced_workspace_cleanup() = False + else: + if re.match('true', forced_workspace_cleanup, re.IGNORECASE): + RAN.SetBuild_eNB_forced_workspace_cleanup() = True + else: + RAN.SetBuild_eNB_forced_workspace_cleanup() = False + RAN.SeteNB_instance() = test.findtext('eNB_instance') + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance() = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' + xmlBgBuildField = test.findtext('backgroundBuild') + if (xmlBgBuildField is None): + RAN.SetbackgroundBuild() = False + else: + if re.match('true', xmlBgBuildField, re.IGNORECASE): + RAN.SetbackgroundBuild() = True + else: + RAN.SetbackgroundBuild() = False + + if action == 'WaitEndBuild_eNB': + RAN.SetBuild_eNB_args() = test.findtext('Build_eNB_args') + RAN.SeteNB_instance() = test.findtext('eNB_instance') + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance() = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' + + if action == 'Initialize_eNB': + RAN.SetInitialize_eNB_args() = test.findtext('Initialize_eNB_args') + RAN.SeteNB_instance() = test.findtext('eNB_instance') + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' + CiTestObj.air_interface = test.findtext('air_interface') + if (CiTestObj.air_interface is None): + CiTestObj.air_interface = 'lte' + else: + CiTestObj.air_interface = CiTestObj.air_interface.lower() + + if action == 'Terminate_eNB': + RAN.SeteNB_instance() = test.findtext('eNB_instance') + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance() = '0' + CiTestObj.eNB_serverId = test.findtext('eNB_serverId') + if (CiTestObj.eNB_serverId is None): + CiTestObj.eNB_serverId = '0' + CiTestObj.air_interface = test.findtext('air_interface') + if (CiTestObj.air_interface is None): + CiTestObj.air_interface = 'lte' + else: + CiTestObj.air_interface = CiTestObj.air_interface.lower() + + if action == 'Attach_UE': + nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') + if (nbMaxUEtoAttach is None): + CiTestObj.nbMaxUEtoAttach = -1 + else: + CiTestObj.nbMaxUEtoAttach = int(nbMaxUEtoAttach) + + if action == 'CheckStatusUE': + expectedNBUE = test.findtext('expectedNbOfConnectedUEs') + if (expectedNBUE is None): + CiTestObj.expectedNbOfConnectedUEs = -1 + else: + CiTestObj.expectedNbOfConnectedUEs = int(expectedNBUE) + + if action == 'Build_OAI_UE': + CiTestObj.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') + CiTestObj.clean_repository = test.findtext('clean_repository') + if (CiTestObj.clean_repository == 'false'): + CiTestObj.clean_repository = False + else: + CiTestObj.clean_repository = True + + if action == 'Initialize_OAI_UE': + CiTestObj.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') + CiTestObj.UE_instance = test.findtext('UE_instance') + if (CiTestObj.UE_instance is None): + CiTestObj.UE_instance = '0' + CiTestObj.air_interface = test.findtext('air_interface') + if (CiTestObj.air_interface is None): + CiTestObj.air_interface = 'lte' + else: + CiTestObj.air_interface = SSH.air_interface.lower() + + if action == 'Terminate_OAI_UE': + RAN.SeteNB_instance = test.findtext('UE_instance') + if (CiTestObj.UE_instance is None): + CiTestObj.UE_instance = '0' + + if action == 'Ping' or action == 'Ping_CatM_module': + CiTestObj.ping_args = test.findtext('ping_args') + CiTestObj.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') + + if action == 'Iperf': + CiTestObj.iperf_args = test.findtext('iperf_args') + CiTestObj.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') + CiTestObj.iperf_profile = test.findtext('iperf_profile') + if (CiTestObj.iperf_profile is None): + CiTestObj.iperf_profile = 'balanced' + else: + if CiTestObj.iperf_profile != 'balanced' and CiTestObj.iperf_profile != 'unbalanced' and CiTestObj.iperf_profile != 'single-ue': + logging.debug('ERROR: test-case has wrong profile ' + CiTestObj.iperf_profile) + CiTestObj.iperf_profile = 'balanced' + CiTestObj.iperf_options = test.findtext('iperf_options') + if (CiTestObj.iperf_options is None): + CiTestObj.iperf_options = 'check' + else: + if CiTestObj.iperf_options != 'check' and CiTestObj.iperf_options != 'sink': + logging.debug('ERROR: test-case has wrong option ' + CiTestObj.iperf_options) + CiTestObj.iperf_options = 'check' + + if action == 'IdleSleep': + string_field = test.findtext('idle_sleep_time_in_sec') + if (string_field is None): + CiTestObj.idle_sleep_time = 5 + else: + CiTestObj.idle_sleep_time = int(string_field) + + if action == 'Perform_X2_Handover': + string_field = test.findtext('x2_ho_options') + if (string_field is None): + CiTestObj.x2_ho_options = 'network' + else: + if string_field != 'network': + logging.error('ERROR: test-case has wrong option ' + string_field) + CiTestObj.x2_ho_options = 'network' + else: + CiTestObj.x2_ho_options = string_field + + +#check if given test is in list +#it is in list if one of the strings in 'list' is at the beginning of 'test' +def test_in_list(test, list): + for check in list: + check=check.replace('+','') + if (test.startswith(check)): + return True + return False + +def receive_signal(signum, frame): + sys.exit(1) + +#----------------------------------------------------------- +# Parameter Check +#----------------------------------------------------------- +mode = '' +CiTestObj = OaiCiTest() + +from sshconnection import * +from epc import * +from helpreadme import * +from enb import * +SSH = SSHConnection() +EPC = EPCManagement() +RAN = RANManagement() +#HELP = HelpReadme() +#HELP.GenericHelp() + +argvs = sys.argv +argc = len(argvs) +cwd = os.getcwd() + +while len(argvs) > 1: + myArgv = argvs.pop(1) # 0th is this file's name + if re.match('^\-\-help$', myArgv, re.IGNORECASE): + GenericHelp(Version) + sys.exit(0) + elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) + mode = matchReg.group(1) + elif re.match('^\-\-eNBRepository=(.+)$|^\-\-ranRepository(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) + RAN.SetranRepository() = matchReg.group(1) + elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) + doMerge = matchReg.group(1) + if ((doMerge == 'true') or (doMerge == 'True')): + RAN.SetranAllowMerge() = True + elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) + RAN.SetranBranch() = matchReg.group(1) + elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) + RAN.SetranCommitID() = matchReg.group(1) + elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) + else: + matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) + RAN.SetranTargetBranch() = matchReg.group(1) + elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNBIPAddress() = matchReg.group(1) + elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB1IPAddress() = matchReg.group(1) + elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB2IPAddress() = matchReg.group(1) + elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNBUserName() = matchReg.group(1) + elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB1UserName() = matchReg.group(1) + elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB2UserName() = matchReg.group(1) + elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNBPassword() = matchReg.group(1) + elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB1Password() = matchReg.group(1) + elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB2Password() = matchReg.group(1) + elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNBSourceCodePath() = matchReg.group(1) + elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB1SourceCodePath() = matchReg.group(1) + elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) + RAN.SeteNB2SourceCodePath() = matchReg.group(1) + elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) + EPC.SetIPAddress(matchReg.group(1)) + elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.EPCBranch = matchReg.group(1) + elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) + EPC.SetUserName(matchReg.group(1)) + elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) + EPC.SetPassword(matchReg.group(1)) + elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) + EPC.SetSourceCodePath(matchReg.group(1)) + elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) + if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): + EPC.SetType(matchReg.group(1)) + else: + sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') + elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.ADBIPAddress = matchReg.group(1) + elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.ADBUserName = matchReg.group(1) + elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) + if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): + if re.match('distributed', matchReg.group(1), re.IGNORECASE): + CiTestObj.ADBCentralized = False + else: + CiTestObj.ADBCentralized = True + else: + sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') + elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.ADBPassword = matchReg.group(1) + elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.testXMLfiles.append(matchReg.group(1)) + CiTestObj.nbTestXMLfiles += 1 + elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.UEIPAddress = matchReg.group(1) + elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.UEUserName = matchReg.group(1) + elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.UEPassword = matchReg.group(1) + elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.UESourceCodePath = matchReg.group(1) + elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) + finalStatus = matchReg.group(1) + if ((finalStatus == 'true') or (finalStatus == 'True')): + CiTestObj.finalStatus = True + else: + GenericHelp(Version) + sys.exit('Invalid Parameter: ' + myArgv) + +if re.match('^TerminateeNB$', mode, re.IGNORECASE): + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.eNB_serverId = '0' + RAN.SeteNB_instance = '0' + RAN.GeteNBSourceCodePath() = '/tmp/' + CiTestObj.TerminateeNB() +elif re.match('^TerminateUE$', mode, re.IGNORECASE): + if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): + GenericHelp(Version) + sys.exit('Insufficient Parameter') + signal.signal(signal.SIGUSR1, receive_signal) + CiTestObj.TerminateUE() +elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): + if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + signal.signal(signal.SIGUSR1, receive_signal) + CiTestObj.TerminateOAIUE() +elif re.match('^TerminateHSS$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.TerminateHSS() +elif re.match('^TerminateMME$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.TerminateMME() +elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.TerminateSPGW() +elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): + if (RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.LogCollectBuild() +elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.LogCollecteNB() +elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + EPC.LogCollectHSS() +elif re.match('^LogCollectMME$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + EPC.LogCollectMME() +elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + EPC.LogCollectSPGW() +elif re.match('^LogCollectPing$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.LogCollectPing() +elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.LogCollectIperf() +elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): + if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + CiTestObj.LogCollectOAIUE() +elif re.match('^InitiateHtml$', mode, re.IGNORECASE): + if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): + GenericHelp(Version) + sys.exit('Insufficient Parameter') + count = 0 + foundCount = 0 + while (count < CiTestObj.nbTestXMLfiles): + #xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[count] + xml_test_file = sys.path[0] + "/" + CiTestObj.testXMLfiles[count] + if (os.path.isfile(xml_test_file)): + try: + xmlTree = ET.parse(xml_test_file) + except: + print("Error while parsing file: " + xml_test_file) + xmlRoot = xmlTree.getroot() + CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) + CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + foundCount += 1 + count += 1 + if foundCount != CiTestObj.nbTestXMLfiles: + CiTestObj.nbTestXMLfiles = foundCount + CiTestObj.CreateHtmlHeader() +elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): + CiTestObj.CreateHtmlFooter(CiTestObj.finalStatus) +elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): + if re.match('^TesteNB$', mode, re.IGNORECASE): + if RAN.GeteNBIPAddress() == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': + GenericHelp(Version) + if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or EPC.GetType() == '': + EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) + # Gabriele: other if conditions relevant to eNB etc. to be added + sys.exit('Insufficient Parameter') + + if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/tcp_iperf_stats.awk", "/tmp") + SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/active_net_interfaces.awk", "/tmp") + else: + if CiTestObj.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': + GenericHelp(Version) + sys.exit('UE: Insufficient Parameter') + + #read test_case_list.xml file + # if no parameters for XML file, use default value + if (CiTestObj.nbTestXMLfiles != 1): + xml_test_file = cwd + "/test_case_list.xml" + else: + xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0] + + xmlTree = ET.parse(xml_test_file) + xmlRoot = xmlTree.getroot() + + exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') + requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') + if (CiTestObj.nbTestXMLfiles == 1): + CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) + repeatCount = xmlRoot.findtext('repeatCount',default='1') + CiTestObj.repeatCounts.append(int(repeatCount)) + all_tests=xmlRoot.findall('testCase') + + exclusion_tests=exclusion_tests.split() + requested_tests=requested_tests.split() + + #check that exclusion tests are well formatted + #(6 digits or less than 6 digits followed by +) + for test in exclusion_tests: + if (not re.match('^[0-9]{6}$', test) and + not re.match('^[0-9]{1,5}\+$', test)): + logging.debug('ERROR: exclusion test is invalidly formatted: ' + test) + sys.exit(1) + else: + logging.debug(test) + + #check that requested tests are well formatted + #(6 digits or less than 6 digits followed by +) + #be verbose + for test in requested_tests: + if (re.match('^[0-9]{6}$', test) or + re.match('^[0-9]{1,5}\+$', test)): + logging.debug('INFO: test group/case requested: ' + test) + else: + logging.debug('ERROR: requested test is invalidly formatted: ' + test) + sys.exit(1) + if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): + CiTestObj.CheckFlexranCtrlInstallation() + + #get the list of tests to be done + todo_tests=[] + for test in requested_tests: + if (test_in_list(test, exclusion_tests)): + logging.debug('INFO: test will be skipped: ' + test) + else: + #logging.debug('INFO: test will be run: ' + test) + todo_tests.append(test) + + signal.signal(signal.SIGUSR1, receive_signal) + + CiTestObj.CreateHtmlTabHeader() + + CiTestObj.FailReportCnt = 0 + CiTestObj.prematureExit = True + CiTestObj.startTime = int(round(time.time() * 1000)) + while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: + CiTestObj.prematureExit = False + # At every iteratin of the retry loop, a separator will be added + CiTestObj.CreateHtmlRetrySeparator() + for test_case_id in todo_tests: + if CiTestObj.prematureExit: + break + for test in all_tests: + if CiTestObj.prematureExit: + break + id = test.get('id') + if test_case_id != id: + continue + CiTestObj.testCase_id = id + CiTestObj.desc = test.findtext('desc') + action = test.findtext('class') + if (CheckClassValidity(action, id) == False): + continue + CiTestObj.ShowTestID() + GetParametersFromXML(action) + if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': + if (CiTestObj.ADBIPAddress != 'none'): + terminate_ue_flag = False + CiTestObj.GetAllUEDevices(terminate_ue_flag) + if action == 'Build_eNB': + RAN.BuildeNB() + elif action == 'WaitEndBuild_eNB': + RAN.WaitBuildeNBisFinished() + elif action == 'Initialize_eNB': + RAN.InitializeeNB() + elif action == 'Terminate_eNB': + RAN.TerminateeNB() + elif action == 'Initialize_UE': + CiTestObj.InitializeUE() + elif action == 'Terminate_UE': + CiTestObj.TerminateUE() + elif action == 'Attach_UE': + CiTestObj.AttachUE() + elif action == 'Detach_UE': + CiTestObj.DetachUE() + elif action == 'DataDisable_UE': + CiTestObj.DataDisableUE() + elif action == 'DataEnable_UE': + CiTestObj.DataEnableUE() + elif action == 'CheckStatusUE': + CiTestObj.CheckStatusUE() + elif action == 'Build_OAI_UE': + CiTestObj.BuildOAIUE() + elif action == 'Initialize_OAI_UE': + CiTestObj.InitializeOAIUE() + elif action == 'Terminate_OAI_UE': + CiTestObj.TerminateOAIUE() + elif action == 'Initialize_CatM_module': + CiTestObj.InitializeCatM() + elif action == 'Terminate_CatM_module': + CiTestObj.TerminateCatM() + elif action == 'Attach_CatM_module': + CiTestObj.AttachCatM() + elif action == 'Detach_CatM_module': + CiTestObj.TerminateCatM() + elif action == 'Ping_CatM_module': + CiTestObj.PingCatM() + elif action == 'Ping': + CiTestObj.Ping() + elif action == 'Iperf': + CiTestObj.Iperf() + elif action == 'Reboot_UE': + CiTestObj.RebootUE() + elif action == 'Initialize_HSS': + EPC.InitializeHSS() + elif action == 'Terminate_HSS': + EPC.TerminateHSS() + elif action == 'Initialize_MME': + EPC.InitializeMME() + elif action == 'Terminate_MME': + EPC.TerminateMME() + elif action == 'Initialize_SPGW': + EPC.InitializeSPGW() + elif action == 'Terminate_SPGW': + EPC.TerminateSPGW() + elif action == 'Initialize_FlexranCtrl': + CiTestObj.InitializeFlexranCtrl() + elif action == 'Terminate_FlexranCtrl': + CiTestObj.TerminateFlexranCtrl() + elif action == 'IdleSleep': + CiTestObj.IdleSleep() + elif action == 'Perform_X2_Handover': + CiTestObj.Perform_X2_Handover() + else: + sys.exit('Invalid action') + CiTestObj.FailReportCnt += 1 + if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: + logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)') + CiTestObj.CreateHtmlTabFooter(False) + sys.exit('Failed Scenario') + else: + logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') + CiTestObj.CreateHtmlTabFooter(True) +else: + GenericHelp(Version) + sys.exit('Invalid mode') +sys.exit(0) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py new file mode 100644 index 0000000000..2145557343 --- /dev/null +++ b/ci-scripts/ran.py @@ -0,0 +1,765 @@ +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import sys # arg +import re # reg +import logging +import os +import time +from multiprocessing import Process, Lock, SimpleQueue + +#----------------------------------------------------------- +# OAI Testing modules +#----------------------------------------------------------- +import sshconnection as mySSH +#from sshconnection import mySSHConnection as mySSH +import helpreadme as HELP +import constants as CONST + + +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class RANManagement(): + def __init__(self): + # self.FailReportCnt = 0 + # self.prematureExit = False + self.ranRepository = '' + self.ranBranch = '' + self.ranAllowMerge = False + self.ranCommitID = '' + self.ranTargetBranch = '' + self.eNBIPAddress = '' + self.eNBUserName = '' + self.eNBPassword = '' + self.eNBSourceCodePath = '' + self.eNB1IPAddress = '' + self.eNB1UserName = '' + self.eNB1Password = '' + self.eNB1SourceCodePath = '' + self.eNB2IPAddress = '' + self.eNB2UserName = '' + self.eNB2Password = '' + self.eNB2SourceCodePath = '' + #self.ADBIPAddress = '' + #self.ADBUserName = '' + #self.ADBPassword = '' + #self.ADBCentralized = True + #self.testCase_id = '' + #self.testXMLfiles = [] + #self.nbTestXMLfiles = 0 + #self.desc = '' + self.Build_eNB_args = '' + self.backgroundBuild = False + self.backgroundBuildTestId = ['', '', ''] + self.Build_eNB_forced_workspace_cleanup = False + self.Initialize_eNB_args = '' + self.air_interface = 'lte' + self.eNB_instance = '' + self.eNB_serverId = '' + self.eNBLogFiles = ['', '', ''] + self.eNBOptions = ['', '', ''] + self.eNBmbmsEnables = [False, False, False] + self.eNBstatuses = [-1, -1, -1] + #self.ping_args = '' + #self.ping_packetloss_threshold = '' + #self.iperf_args = '' + #self.iperf_packetloss_threshold = '' + #self.iperf_profile = '' + #self.iperf_options = '' + #self.nbMaxUEtoAttach = -1 + #self.UEDevices = [] + #self.UEDevicesStatus = [] + #self.UEDevicesRemoteServer = [] + #self.UEDevicesRemoteUser = [] + #self.UEDevicesOffCmd = [] + #self.UEDevicesOnCmd = [] + #self.UEDevicesRebootCmd = [] + #self.CatMDevices = [] + #self.UEIPAddresses = [] + #self.htmlFile = '' + #self.htmlHeaderCreated = False + #self.htmlFooterCreated = False + #self.htmlUEConnected = -1 + #self.htmleNBFailureMsg = '' + #self.htmlUEFailureMsg = '' + #self.picocom_closure = False + #self.idle_sleep_time = 0 + #self.x2_ho_options = 'network' + #self.x2NbENBs = 0 + #self.x2ENBBsIds = [] + #self.x2ENBConnectedUEs = [] + #self.htmlTabRefs = [] + #self.htmlTabNames = [] + #self.htmlTabIcons = [] + #self.repeatCounts = [] + #self.finalStatus = False + #self.OsVersion = '' + #self.KernelVersion = '' + #self.UhdVersion = '' + #self.UsrpBoard = '' + #self.CpuNb = '' + #self.CpuModel = '' + #self.CpuMHz = '' + #self.UEIPAddress = '' + #self.UEUserName = '' + #self.UEPassword = '' + #self.UE_instance = '' + #self.UESourceCodePath = '' + #self.UELogFile = '' + #self.Build_OAI_UE_args = '' + #self.Initialize_OAI_UE_args = '' + #self.clean_repository = True + #self.flexranCtrlInstalled = False + #self.flexranCtrlStarted = False + #self.expectedNbOfConnectedUEs = 0 + #self.startTime = 0 + + + def SetranRepository(self, repository): + self.ranRepository = repository + def GetranRepository(self): + return self.ranRepository + def SetranBranch(self, branch): + self.ranBranch = branch + def GetranBranch(self): + return self.ranBranch + def SetranCommitID(self, commitid): + self.ranCommitID = commitid + def GetranCommitID(self): + return self.ranCommitID + def SeteNB_serverId(self, enbsrvid): + self.eNB_serverId = enbsrvid + def GeteNB_serverId(self): + return self.eNB_serverId + def SeteNBIPAddress(self, enbip): + self.eNBIPAddress = enbip + def GeteNBIPAddress(self): + return self.eNBIPAddress + def SeteNBUserName(self, enbusr): + self.eNBUserName = enbusr + def GeteNBUserName(self): + return self.eNBUserName + def SeteNBPassword(self, enbpw): + self.eNBPassword = enbpw + def GeteNBPassword(self): + return self.eNBPassword + def SeteNBSourceCodePath(self, enbcodepath): + self.eNBSourceCodePath = enbcodepath + def GeteNBSourceCodePath(self): + return self.eNBSourceCodePath + def SetranAllowMerge(self, merge): + self.ranAllowMerge = merge + def GetranAllowMerge(self): + return self.ranAllowMerge + def SetranTargetBranch(self, tbranch): + self.ranTargetBranch = tbranch + def GetranTargetBranch(self): + return self.ranTargetBranch + def SetBuild_eNB_args(self, enbbuildarg): + self.Build_eNB_args = enbbuildarg + def GetBuild_eNB_args(self): + return self.Build_eNB_args + def SetInitialize_eNB_args(self, initenbarg): + self.Initialize_eNB_args = initenbarg + def GetInitialize_eNB_args(self): + return self.Initialize_eNB_args + def SetbackgroundBuild(self, bkbuild): + self.backgroundBuild = bkbuild + def GetbackgroundBuild(self): + return self.backgroundBuild + def SetbackgroundBuildTestId(self, bkbuildid): + self.backgroundBuildTestId = bkbuildid + def GetbackgroundBuildTestId(self): + return self.backgroundBuildTestId + def SetBuild_eNB_forced_workspace_cleanup(self, fcdwspclean): + self.Build_eNB_forced_workspace_cleanup = fcdwspclean + def GetBuild_eNB_forced_workspace_cleanup(self): + return self.Build_eNB_forced_workspace_cleanup + def Setair_interface(self, airif): + self.air_interface = airif + def Getair_interface(self): + return self.air_interface + def SeteNB_instance(self, enbinst): + self.eNB_instance = enbinst + def GeteNB_instance(self): + return self.eNB_instance + + def SeteNBLogFiles(self, enblogs): + self.eNBLogFiles = enblogs + def GeteNBLogFiles(self): + return self.eNBLogFiles + + def SeteNBOptions(self, enbopt): + self.eNBOptions = enbopt + def GeteNBOptions(self): + return self.eNBOptions + + def SeteNBmbmsEnables(self, enbmbms): + self.eNBmbmsEnables = enbmbms + def GeteNBmbmsEnables(self): + return self.eNBmbmsEnables + + def SeteNBstatuses(self, enbstatus): + self.eNBstatuses = enbstatus + def GeteNBstatuses(self): + return self.eNBstatuses + + + + def SeteNB1IPAddress(self, enb1ip): + self.eNB1IPAddress = enb1ip + def GeteNB1IPAddress(self): + return self.eNB1IPAddress + def SeteNB1UserName(self, enb1usr): + self.eNB1UserName = enb1usr + def GeteNB1UserName(self): + return self.eNB1UserName + def SeteNB1Password(self, enb1pw): + self.eNB1Password = enb1pw + def GeteNB1Password(self): + return self.eNB1Password + def SeteNB1SourceCodePath(self, enb1codepath): + self.eNB1SourceCodePath = enb1codepath + def GeteNB1SourceCodePath(self): + return self.eNB1SourceCodePath + + def SeteNB2IPAddress(self, enbip): + self.eNB2IPAddress = enb2ip + def GeteNB2IPAddress(self): + return self.eNB2IPAddress + def SeteNB2UserName(self, enb2usr): + self.eNB2UserName = enb2usr + def GeteNB2UserName(self): + return self.eNB2UserName + def SeteNB2Password(self, enb2pw): + self.eNB2Password = enb2pw + def GeteNB2Password(self): + return self.eNB2Password + def SeteNB2SourceCodePath(self, enb2codepath): + self.eNB2SourceCodePath = enb2codepath + def GeteNB2SourceCodePath(self): + return self.eNB2SourceCodePath + + + + def BuildeNB(self): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + # Check if we build an 5G-NR gNB or an LTE eNB + result = re.search('--gNB', self.Build_eNB_args) + if result is not None: + self.air_interface = 'nr' + else: + self.air_interface = 'lte' + # Worakround for some servers, we need to erase completely the workspace + if self.Build_eNB_forced_workspace_cleanup: + mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) + # on RedHat/CentOS .git extension is mandatory + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) + if result is not None: + full_ran_repo_name = self.ranRepository + else: + full_ran_repo_name = self.ranRepository + '.git' + mySSH.command('mkdir -p ' + lSourcePath, '\$', 5) + mySSH.command('cd ' + lSourcePath, '\$', 5) + mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) + # Raphael: here add a check if git clone or git fetch went smoothly + mySSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) + mySSH.command('git config user.name "OAI Jenkins"', '\$', 5) + # Checking the BUILD INFO file + if not self.backgroundBuild: + mySSH.command('ls *.txt', '\$', 5) + result = re.search('LAST_BUILD_INFO', mySSH.getBefore()) + if result is not None: + mismatch = False + mySSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) + result = re.search(self.ranCommitID, mySSH.getBefore()) + if result is None: + mismatch = True + mySSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + result = re.search('YES', mySSH.getBefore()) + if result is None: + mismatch = True + mySSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + result = re.search('develop', mySSH.getBefore()) + else: + result = re.search(self.ranTargetBranch, mySSH.getBefore()) + if result is None: + mismatch = True + else: + result = re.search('NO', mySSH.getBefore()) + if result is None: + mismatch = True + if not mismatch: + mySSH.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + return + + mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) + # if the commit ID is provided use it to point to it + if self.ranCommitID != '': + mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) + # if the branch is not develop, then it is a merge request and we need to do + # the potential merge. Note that merge conflicts should already been checked earlier + if (self.ranAllowMerge): + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) + else: + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + mySSH.command('source oaienv', '\$', 5) + mySSH.command('cd cmake_targets', '\$', 5) + mySSH.command('mkdir -p log', '\$', 5) + mySSH.command('chmod 777 log', '\$', 5) + # no need to remove in log (git clean did the trick) + if self.backgroundBuild: + mySSH.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) + mySSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) + mySSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) + mySSH.close() + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id + return + mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) + + + + def WaitBuildeNBisFinished(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + count = 40 + buildOAIprocess = True + while (count > 0) and buildOAIprocess: + mySSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) + result = re.search('build_oai', mySSH.getBefore()) + if result is None: + buildOAIprocess = False + else: + count -= 1 + time.sleep(30) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) + + def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): + mySSH = SSH.SSHConnection() + mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) + mySSH.command('ls ran_build/build', '\$', 3) + mySSH.command('ls ran_build/build', '\$', 3) + if self.air_interface == 'nr': + nodeB_prefix = 'g' + else: + nodeB_prefix = 'e' + buildStatus = True + result = re.search(self.air_interface + '-softmodem', mySSH.getBefore()) + if result is None: + buildStatus = False + else: + # Generating a BUILD INFO file + mySSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + mySSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (self.ranAllowMerge): + mySSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if self.ranTargetBranch == '': + mySSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + mySSH.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + else: + mySSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) + mySSH.command('mkdir -p build_log_' + testcaseId, '\$', 5) + mySSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) + mySSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) + if self.eNB_serverId != '0': + mySSH.command('cd cmake_targets', '\$', 5) + mySSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) + mySSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) + mySSH.close() + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + os.remove('./tmp_build' + testcaseId + '.zip') + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') + if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): + mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') + os.remove('./tmp_build' + testcaseId + '.zip') + mySSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + mySSH.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) + mySSH.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) + mySSH.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) + mySSH.close() + else: + mySSH.close() + + if buildStatus: + logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') + self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + else: + logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') + self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) + self.CreateHtmlTabFooter(False) + sys.exit(1) + + + def InitializeeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + mySSH = SSH.SSHConnection() + check_eNB = False + check_OAI_UE = False + pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (pStatus < 0): + self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) + self.CreateHtmlTabFooter(False) + sys.exit(1) + # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + mySSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) + result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', mySSH.getBefore()) + if result is not None: + eth_interface = result.group('eth_interface') + logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') + EPC.Get_PcapFileName() = 'enb_' + self.testCase_id + '_s1log.pcap' + mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.Get_PcapFileName() + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) + mySSH.close() + mySSH.open(lIpAddr, lUserName, lPassWord) + mySSH.command('cd ' + lSourcePath, '\$', 5) + # Initialize_eNB_args usually start with -O and followed by the location in repository + full_config_file = self.Initialize_eNB_args.replace('-O ','') + extra_options = '' + extIdx = full_config_file.find('.conf') + if (extIdx > 0): + extra_options = full_config_file[extIdx + 5:] + # if tracer options is on, compiling and running T Tracer + result = re.search('T_stdout', str(extra_options)) + if result is not None: + logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') + mySSH.command('cd common/utils/T/tracer', '\$', 5) + mySSH.command('make', '\$', 10) + mySSH.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) + mySSH.command('cd ' + lSourcePath, '\$', 5) + full_config_file = full_config_file[:extIdx + 5] + config_path, config_file = os.path.split(full_config_file) + else: + sys.exit('Insufficient Parameter') + ci_full_config_file = config_path + '/ci-' + config_file + rruCheck = False + result = re.search('^rru|^rcc|^du.band', str(config_file)) + if result is not None: + rruCheck = True + # do not reset board twice in IF4.5 case + result = re.search('^rru|^enb|^du.band', str(config_file)) + if result is not None: + mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) + result = re.search('type: b200', mySSH.getBefore()) + if result is not None: + logging.debug('Found a B2xx device --> resetting it') + mySSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + # Reloading FGPA bin firmware + mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) + # Make a copy and adapt to EPC / eNB IP addresses + mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) + mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.GetIPAddress() + '/\' ' + ci_full_config_file, '\$', 2); + mySSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); + mySSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + mySSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + mySSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); + if self.flexranCtrlInstalled and self.flexranCtrlStarted: + mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); + else: + mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); + self.eNBmbmsEnables[int(self.eNB_instance)] = False + mySSH.command('grep enable_enb_m2 ' + ci_full_config_file, '\$', 2); + result = re.search('yes', mySSH.getBefore()) + if result is not None: + self.eNBmbmsEnables[int(self.eNB_instance)] = True + logging.debug('\u001B[1m MBMS is enabled on this eNB\u001B[0m') + result = re.search('noS1', str(self.Initialize_eNB_args)) + eNBinNoS1 = False + if result is not None: + eNBinNoS1 = True + logging.debug('\u001B[1m eNB is in noS1 configuration \u001B[0m') + # Launch eNB with the modified config file + mySSH.command('source oaienv', '\$', 5) + mySSH.command('cd cmake_targets', '\$', 5) + mySSH.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface + '-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + mySSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) + mySSH.command('hostnamectl','\$', 5) + result = re.search('CentOS Linux 7', mySSH.getBefore()) + if result is not None: + mySSH.command('echo $USER; nohup sudo ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log 2>&1 &', lUserName, 10) + else: + mySSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' + if extra_options != '': + self.eNBOptions[int(self.eNB_instance)] = extra_options + time.sleep(6) + doLoop = True + loopCounter = 20 + enbDidSync = False + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # In case of T tracer recording, we may need to kill it + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + mySSH.command('killall --signal SIGKILL record', '\$', 5) + mySSH.close() + doLoop = False + logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) + # In case of T tracer recording, we need to kill tshark on EPC side + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + mySSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if EPC.Get_PcapFileName() != '': + time.sleep(0.5) + mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.close() + time.sleep(1) + if EPC.Get_PcapFileName() != '': + copyin_res = mySSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.Get_PcapFileName() , '.') + if (copyin_res == 0): + mySSH.copyout(lIpAddr, lUserName, lPassWord, EPC.Get_PcapFileName() , lSourcePath + '/cmake_targets/.') + self.prematureExit = True + return + else: + mySSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) + if rruCheck: + result = re.search('wait RUs', mySSH.getBefore()) + else: + result = re.search('got sync|Starting F1AP at CU', mySSH.getBefore()) + if result is None: + time.sleep(6) + else: + doLoop = False + enbDidSync = True + time.sleep(10) + + if enbDidSync and eNBinNoS1: + mySSH.command('ifconfig oaitun_enb1', '\$', 4) + mySSH.command('ifconfig oaitun_enb1', '\$', 4) + result = re.search('inet addr:1|inet 1', mySSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m oaitun_enb1 interface is mounted and configured\u001B[0m') + else: + logging.error('\u001B[1m oaitun_enb1 interface is either NOT mounted or NOT configured\u001B[0m') + if self.eNBmbmsEnables[int(self.eNB_instance)]: + mySSH.command('ifconfig oaitun_enm1', '\$', 4) + result = re.search('inet addr', mySSH.getBefore()) + if result is not None: + logging.debug('\u001B[1m oaitun_enm1 interface is mounted and configured\u001B[0m') + else: + logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m') + if enbDidSync: + self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) + + mySSH.close() + self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') + + + + def CheckeNBProcess(self, status_queue): + try: + # At least the instance 0 SHALL be on! + if self.eNBstatuses[0] == 0: + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + elif self.eNBstatuses[0] == 1: + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + elif self.eNBstatuses[0] == 2: + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + else: + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + mySSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-softmodem | grep -v grep', '\$', 5) + result = re.search(self.air_interface + '-softmodem', mySSH.getBefore()) + if result is None: + logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') + status_queue.put(ENB_PROCESS_FAILED) + else: + status_queue.put(ENB_PROCESS_OK) + mySSH.close() + except: + os.kill(os.getppid(),signal.SIGUSR1) + + + + def TerminateeNB(self): + if self.eNB_serverId == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + GenericHelp(Version) + sys.exit('Insufficient Parameter') + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + if self.air_interface == 'lte': + nodeB_prefix = 'e' + else: + nodeB_prefix = 'g' + mySSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('-softmodem', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) + mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5) + time.sleep(10) + mySSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) + result = re.search('-softmodem', mySSH.getBefore()) + if result is not None: + mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5) + time.sleep(5) + mySSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + mySSH.close() + # If tracer options is on, stopping tshark on EPC side + result = re.search('T_stdout', str(self.Initialize_eNB_args)) + if result is not None: + mySSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + logging.debug('\u001B[1m Stopping tshark \u001B[0m') + mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + time.sleep(1) + if EPC.Get_PcapFileName() != '': + mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.Get_PcapFileName() , '.') + mySSH.copyout(lIpAddr, lUserName, lPassWord, EPC.Get_PcapFileName() , lSourcePath + '/cmake_targets/.') + mySSH.close() + logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') + mySSH.open(lIpAddr, lUserName, lPassWord) + mySSH.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) + enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] + raw_record_file = enbLogFile.replace('.log', '_record.raw') + replay_log_file = enbLogFile.replace('.log', '_replay.log') + extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') + extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') + mySSH.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) + mySSH.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) + mySSH.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) + mySSH.close() + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') + logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') + logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBLogFiles[int(self.eNB_instance)] = '' + else: + analyzeFile = False + if self.eNBLogFiles[int(self.eNB_instance)] != '': + analyzeFile = True + fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] + self.eNBLogFiles[int(self.eNB_instance)] = '' + if analyzeFile: + copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') + if (copyin_res == -1): + logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') + self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' + self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + self.eNBmbmsEnables[int(self.eNB_instance)] = False + return + if self.eNB_serverId != '0': + mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') + logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) + logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) + if (logStatus < 0): + self.CreateHtmlTestRow('N/A', 'KO', logStatus) + self.preamtureExit = True + self.eNBmbmsEnables[int(self.eNB_instance)] = False + return + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + else: + self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + self.eNBmbmsEnables[int(self.eNB_instance)] = False + self.eNBstatuses[int(self.eNB_instance)] = -1 + + + def LogCollecteNB(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + mySSH.command('cd ' + self.eNBSourceCodePath, '\$', 5) + mySSH.command('cd cmake_targets', '\$', 5) + mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) + mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) + mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) + mySSH.close() diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index d10edf360b..6103bf4f0f 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -68,7 +68,8 @@ class SSHConnection(): elif self.sshresponse == 1: logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) + logging.debug(str(self.ssh.before)) + sys.exit(self.sshresponse) elif self.sshresponse == 2: logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') logging.debug('Expected Line : ' + expectedline) From 0a2e033253d8c5035931245db27f5794404ce491 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Thu, 13 Feb 2020 17:18:20 +0100 Subject: [PATCH 099/175] max ack bits in mac_proto.h --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 4f675fecc4..9d0365d5ff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1350,7 +1350,7 @@ void nr_update_pucch_scheduling(int Mod_idP, } else { // to be tested curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch; - if (curr_pucch->dai_c<11) { // we are scheduling at most 11 harq-ack in the same pucch + if (curr_pucch->dai_cul_slot % slots_per_tdd)-(slotP % slots_per_tdd)) found = 1; @@ -1362,7 +1362,7 @@ void nr_update_pucch_scheduling(int Mod_idP, sched_pucch->timing_indicator = pdsch_to_harq_feedback[i]; } } - if (curr_pucch->dai_c==11 || found == 0) { // if current pucch is full or no timing indicator allowed + if (curr_pucch->dai_c==MAX_ACK_BITS || found == 0) { // if current pucch is full or no timing indicator allowed // look for pucch occasions in other UL of mixed slots for (k=scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; kul_slot % slots_per_tdd)) { // skip current scheduled slot (already checked) @@ -1396,7 +1396,7 @@ void nr_update_pucch_scheduling(int Mod_idP, curr_pucch->next_sched_pucch = sched_pucch; } else { - if (curr_pucch->dai_c==11) + if (curr_pucch->dai_c==MAX_ACK_BITS) found = 0; // if pucch at index k is already full we have to find a new one in a following occasion else { // scheduling this harq-ack in current pucch sched_pucch = curr_pucch; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index cbbac3a55a..657de416a9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -34,6 +34,8 @@ #include "nr_mac_gNB.h" #include "PHY/defs_gNB.h" +#define MAX_ACK_BITS 2 //only format 0 is available for now + void set_cset_offset(uint16_t); void mac_top_init_gNB(void); From 53db39b8a02dfdcf2564a2fce11d4650f494a775 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 2 Mar 2020 15:41:21 +0100 Subject: [PATCH 100/175] split 7.3 ready for merge --- SystemX-tutorial-design.odt | Bin 55501 -> 0 bytes cmake_targets/CMakeLists.txt | 8 - common/utils/system.c | 6 +- .../SystemX-tutorial-design.md | 21 +- enb.fs6.example.conf | 290 ------- executables/main-fs6.c | 126 +-- executables/main-ocp.c | 789 +++++++++++++----- executables/nr-gnb.c | 137 ++- executables/nr-ru.c | 40 +- executables/nr-softmodem.c | 130 +-- executables/nr-ue.c | 128 +-- executables/nr-uesoftmodem.c | 56 +- executables/softmodem-common.c | 44 +- executables/softmodem-common.h | 9 + executables/split_headers.h | 5 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 8 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 24 +- openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c | 2 +- openair1/PHY/LTE_TRANSPORT/transport_eNB.h | 6 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 54 +- .../PHY/LTE_UE_TRANSPORT/dlsch_decoding.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 23 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 9 +- openair1/SIMULATION/LTE_PHY/ulsim.c | 9 +- openair2/PHY_INTERFACE/IF_Module.h | 6 +- targets/ARCH/rfsimulator/simulator.c | 6 +- targets/COMMON/create_tasks.c | 15 +- targets/RT/USER/lte-softmodem.c | 31 +- 29 files changed, 1032 insertions(+), 954 deletions(-) delete mode 100644 SystemX-tutorial-design.odt rename SystemX-tutorial-design.md => doc/SystemX-tutorial-design.md (93%) delete mode 100644 enb.fs6.example.conf diff --git a/SystemX-tutorial-design.odt b/SystemX-tutorial-design.odt deleted file mode 100644 index 42e195ac112b370ff7d48cfbb5e083d9cfaecf6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55501 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
YnRIhBz$ZI{0_ZI3>?OH0uus+P7A)eI|s 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 U6A%AvGbQ$Q5gQ0mG $d/cpufreq/scaling_min_freq; done")) - LOG_W(HW,"Can't set cpu frequency\n"); - + LOG_E(HW,"Can't set cpu frequency\n"); + + mlockall(MCL_CURRENT | MCL_FUTURE); + } diff --git a/SystemX-tutorial-design.md b/doc/SystemX-tutorial-design.md similarity index 93% rename from SystemX-tutorial-design.md rename to doc/SystemX-tutorial-design.md index c5d1f77704..371cb33a75 100644 --- a/SystemX-tutorial-design.md +++ b/doc/SystemX-tutorial-design.md @@ -258,26 +258,22 @@ lte-softmodem. The functionality and parameters is the same, enhanced with FS6 mode. -The environment variable “fs6” enables the fs6 mode and decided to be cu -or du from the fs6 variable content. - -A example configuration file is: $OPENAIR_DIR/enb.fs6.example.conf -The IP addresses in this file should be updated for each network. +The end line option “--split73” enables the fs6 (also called split 7.3) mode and decided to be cu or du. Example: -`fs6=cu ./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug +./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 cu:127.0.0.1 ` +Run the CU init of the split 6 eNB, that will call du on 127.0.0.1 address -Run the CU init of the split 6 eNB. +./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 du:127.0.0.1 -`fs6=du ./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug +will run the du, calling the cu on 127.0.0.1 ` If the CU and the DU are not on the same machine, the remote address of each side need to be specified as per this example -`fs6=du FS6_REMOTE_IP=192.168.2.211 ./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug +./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 du:192.168.1.55 ` - runs the functional split 6 DU `./lte-uesoftmodem -C 2685000000 -r 50 --rfsim --rfsimulator.serveraddr 192.168.1.1 -d @@ -285,10 +281,7 @@ runs the functional split 6 DU Runs the UE (to have the UE signal scope, compile it with make uescope) -CU and DU IP address and port are configurable in the eNB configuration -file (as X2, GTP, … interfaces). - -CU+DU+UE can run with option --noS1 to avoid to use a EPC. +CU+DU+UE can run with option --noS1 to avoid to use a EPC and/or with --rfsim to simulate RF board ##5G and F1 diff --git a/enb.fs6.example.conf b/enb.fs6.example.conf deleted file mode 100644 index 6102f91756..0000000000 --- a/enb.fs6.example.conf +++ /dev/null @@ -1,290 +0,0 @@ -Active_eNBs = ( "eNB-Eurecom-LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB-Eurecom-LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = 1; - plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } ); - - tr_s_preference = "local_mac" - - ////////// Physical parameters: - - component_carriers = ( - { - node_function = "3GPP_eNODEB"; - node_timing = "synch_to_ext_device"; - node_synch_ref = 0; - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2685000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 50; - Nid_cell_mbsfn = 0; - nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 125; - pbch_repetition = "FALSE"; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 0; - pucch_nCS_AN = 0; - pucch_n1_AN = 0; - pdsch_referenceSignalPower = -27; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -96; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -104; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - drx_Config_present = "prSetup"; //"prSetup" "prRelease" - drx_onDurationTimer = "psf1"; // "psfX": X=1,2,3,4,5,6,8,10,20,30,40,50,60,80,100 - drx_InactivityTimer = "psf1"; // "psfX": X=1,2,3,4,5,6,8,10,20,30,40,50,60,80,100,200,300,500,750,1280,1920,2560 - drx_RetransmissionTimer = "psf1"; // "psfX": X=1,2,4,6,8,16,24,33 - drx_longDrx_CycleStartOffset_present = "prSf128"; // "psfX": X=10,20,32,40,64,80,128,160,256,320,512,640,1024,1280,2048,2560 - drx_longDrx_CycleStartOffset = 0; // X >= 0 && X < drx_longDrx_CycleStartOffset_present - drx_shortDrx_Cycle = "sf16"; // "sfX": X=2,5,8,10,16,20,32,40,64,80,128,160,256,320,512,640 - drx_shortDrx_ShortCycleTimer = 3; // 1..16 integer. Total duration in short cycle = drx_shortDrx_Cycle*drx_shortDrx_ShortCycleTimer [subframe] - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - ue_TransmissionMode = 1; - - //Parameters for SIB18 - rxPool_sc_CP_Len = "normal"; - rxPool_sc_Period = "sf40"; - rxPool_data_CP_Len = "normal"; - rxPool_ResourceConfig_prb_Num = 20; - rxPool_ResourceConfig_prb_Start = 5; - rxPool_ResourceConfig_prb_End = 44; - rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; - rxPool_ResourceConfig_offsetIndicator_choice = 0; - rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; - rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; - rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; - rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; -/* rxPool_dataHoppingConfig_hoppingParameter = 0; - rxPool_dataHoppingConfig_numSubbands = "ns1"; - rxPool_dataHoppingConfig_rbOffset = 0; - rxPool_commTxResourceUC-ReqAllowed = "TRUE"; -*/ - // Parameters for SIB19 - discRxPool_cp_Len = "normal" - discRxPool_discPeriod = "rf32" - discRxPool_numRetx = 1; - discRxPool_numRepetition = 2; - discRxPool_ResourceConfig_prb_Num = 5; - discRxPool_ResourceConfig_prb_Start = 3; - discRxPool_ResourceConfig_prb_End = 21; - discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; - discRxPool_ResourceConfig_offsetIndicator_choice = 0; - discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; - discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; - discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; - discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; - - } - ); - - - srb1_parameters : - { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] - timer_poll_retransmit = 80; - - # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] - timer_reordering = 35; - - # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] - timer_status_prohibit = 0; - - # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] - poll_pdu = 4; - - # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] - poll_byte = 99999; - - # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] - max_retx_threshold = 4; - } - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "127.0.0.20"; - ipv6 = "192:168:30::17"; - active = "yes"; - preference = "ipv4"; - } - ); - - enable_measurement_reports = "no"; - ///X2 - enable_x2 = "no"; - t_reloc_prep = 1000; /* unit: millisecond */ - tx2_reloc_overall = 2000; /* unit: millisecond */ - - NETWORK_INTERFACES : - { - - ENB_INTERFACE_NAME_FOR_S1_MME = "lo"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.0.10"; - ENB_INTERFACE_NAME_FOR_S1U = "lo"; - ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.10"; - ENB_PORT_FOR_S1U = 2152; # Spec 2152 - - ENB_IPV4_ADDRESS_FOR_X2C = "127.0.0.1"; - ENB_PORT_FOR_X2C = 36422; # Spec 36422 - }; - } -); - -MACRLCs = ( - { - num_cc = 1; - tr_s_preference = "local_L1"; - tr_n_preference = "local_RRC"; - //scheduler_mode = "fairRR"; - phy_test_mode = 0; - puSch10xSnr = 160; - puCch10xSnr = 160; - } -); - -L1s = ( - { - num_cc = 1; - tr_n_preference = "local_mac"; - } -); - -RUs = ( - { - local_rf = "yes" - nb_tx = 1 - nb_rx = 1 - att_tx = 0 - att_rx = 0; - bands = [7]; - max_pdschReferenceSignalPower = -27; - max_rxgain = 108; - eNB_instances = [0]; - - } -); - -NETWORK_CONTROLLER : -{ - FLEXRAN_ENABLED = "no"; - FLEXRAN_INTERFACE_NAME = "lo"; - FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; - FLEXRAN_PORT = 2210; - FLEXRAN_CACHE = "/mnt/oai_agent_cache"; - FLEXRAN_AWAIT_RECONF = "no"; -}; - -THREAD_STRUCT = ( - { - #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" - parallel_config = "PARALLEL_SINGLE_THREAD"; - #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" - worker_config = "WORKER_DISABLE"; - } -); - -#example config for rfsimulator -rfsimulator : -{ - serveraddr = "enb"; - serverport = "4043"; - options = (); #("saviq"); - modelname = "AWGN"; - IQfile = "/tmp/rfsimulator.iqs"; -}; - - log_config : - { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="info"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - diff --git a/executables/main-fs6.c b/executables/main-fs6.c index 727f80a72b..c20777a5d6 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -165,16 +165,16 @@ void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_r } ocp_rx_prach(eNB, - proc, - eNB->RU_list[0], - header->max_preamble, - header->max_preamble_energy, - header->max_preamble_delay, - header->avg_preamble_energy, - proc->frame_prach, - 0, - false - ); + proc, + eNB->RU_list[0], + header->max_preamble, + header->max_preamble_energy, + header->max_preamble_delay, + header->avg_preamble_energy, + proc->frame_prach, + 0, + false + ); // run PRACH detection for CE-level 0 only for now when br_flag is set /* fixme: seems not operational and may overwrite regular LTE prach detection * OAI code can call is sequence @@ -513,15 +513,12 @@ void fill_rx_indication_from_split(uint8_t *bufferZone, PHY_VARS_eNB *eNB,int UE nfapi_rx_indication_pdu_t *pdu; int timing_advance_update; uint32_t harq_pid; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - if (eNB->ulsch[UE_id]->ue_type > 0) harq_pid = 0; + if (eNB->ulsch[UE_id]->ue_type > 0) + harq_pid = 0; else -#endif - { harq_pid = subframe2harq_pid (&eNB->frame_parms, frame, subframe); - } pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rx_ind.sfn_sf = frame<<4| subframe; @@ -533,7 +530,7 @@ void fill_rx_indication_from_split(uint8_t *bufferZone, PHY_VARS_eNB *eNB,int UE pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation - pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; + pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->decodedBytes; // estimate timing advance for MAC timing_advance_update = ul_propa[UE_id].ta; @@ -662,7 +659,7 @@ void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB * } // for (i=0; inbDecode > 0) { - notifiedFIFO_elt_t *req=pullTpool(&proc->respDecode, &proc->threadPool); + notifiedFIFO_elt_t *req=pullTpool(proc->respDecode, proc->threadPool); postDecode(proc, req); delNotifiedFIFO_elt(req); } @@ -678,7 +675,7 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagat if ( type == fs6ULsch) { LTE_eNB_ULSCH_t *ulsch =eNB->ulsch[hULUE(bufPtr)->UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hULUE(bufPtr)->harq_id]; - memcpy(ulsch_harq->e+hULUE(bufPtr)->r_offset, + memcpy(ulsch_harq->eUL+hULUE(bufPtr)->r_offset, hULUE(bufPtr)+1, hULUE(bufPtr)->segLen); memcpy(eNB->pusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power, @@ -691,7 +688,7 @@ void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagat sizeof(ulsch_harq->o_ACK)); memcpy(ulsch_harq->o,hULUE(bufPtr)->o, sizeof(ulsch_harq->o)); ul_propa[hULUE(bufPtr)->UE_id].ta=hULUE(bufPtr)->ta; - LOG_D(PHY,"Received ulsch data for: rnti:%x, cqi_crc_status %d O_ACK: %di, segment: %di, seglen: %d \n", + LOG_D(PHY,"Received ulsch data for: rnti:%x, cqi_crc_status %d O_ACK: %d, segment: %d, seglen: %d \n", ulsch->rnti, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment, hULUE(bufPtr)->segLen); } else if ( type == fs6ULcch ) { int nb_uci=hULUEuci(bufPtr)->nb_active_ue; @@ -771,10 +768,10 @@ void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, i dlsch0->i0=hDLUE(bufPtr)->i0; dlsch0->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag; #endif - fs6Dlunpack(dlsch_harq->e, + fs6Dlunpack(dlsch_harq->eDL, hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen); LOG_D(PHY,"received %d bits, in harq id: %di fsf: %d.%d, sum %d\n", - hDLUE(bufPtr)->dataLen, hDLUE(bufPtr)->harq_pid, frame, subframe, sum(dlsch_harq->e, hDLUE(bufPtr)->dataLen)); + hDLUE(bufPtr)->dataLen, hDLUE(bufPtr)->harq_pid, frame, subframe, sum(dlsch_harq->eDL, hDLUE(bufPtr)->dataLen)); } else if (type == fs6UlConfig) { int nbUE=(((commonUDP_t *)bufPtr)->contentBytes - sizeof(fs6_dl_t)) / sizeof( fs6_dl_ulsched_t ) ; #define cpyVal(a) memcpy(&ulsch_harq->a,&hTxULUE(bufPtr)->a, sizeof(ulsch_harq->a)) @@ -1103,9 +1100,9 @@ void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_ hDLUE(newUDPheader)->sib1_br_flag=dlsch0->sib1_br_flag; #endif hDLUE(newUDPheader)->dataLen=UEdataLen; - fs6Dlpack(hDLUE(newUDPheader)+1, harqData->e, UEdataLen); + fs6Dlpack(hDLUE(newUDPheader)+1, harqData->eDL, UEdataLen); LOG_D(PHY,"sending %d bits, in harq id: %di fsf: %d.%d, sum %d\n", - UEdataLen, harq_pid, frame, subframe, sum(harqData->e, UEdataLen)); + UEdataLen, harq_pid, frame, subframe, sum(harqData->eDL, UEdataLen)); //for (int i=0; i < UEdataLen; i++) //LOG_D(PHY,"buffer ei[%d]:%hhx\n", i, ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]); } @@ -1322,7 +1319,11 @@ void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx void *DL_du_fs6(void *arg) { RU_t *ru=(RU_t *)arg; static uint64_t lastTS; - L1_rxtx_proc_t L1_proc= {0}; + L1_rxtx_proc_t L1proc= {0}; + // We pick the global thread pool from the legacy code global vars + L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool; + L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode; + L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode; initStaticTime(begingWait); initStaticTime(begingProcessing); initRefTimes(fullLoop); @@ -1338,27 +1339,31 @@ void *DL_du_fs6(void *arg) { updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU"); if (nb_blocks > 0) { - if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti != hUDP(bufferZone)->timestamp) { + if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti < hUDP(bufferZone)->timestamp) { LOG_E(HW,"Missed a subframe: expecting: %lu, received %lu\n", lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, hUDP(bufferZone)->timestamp); + } else if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti > hUDP(bufferZone)->timestamp) { + LOG_E(HW,"Received a subframe in past time from CU (dropping it): expecting: %lu, received %lu\n", + lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti, + hUDP(bufferZone)->timestamp); } pickStaticTime(begingProcessing); lastTS=hUDP(bufferZone)->timestamp; - setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1_proc); + setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1proc); measTransportTime(hDL(bufferZone)->DuClock, hDL(bufferZone)->CuSpentMicroSec, &transportTime, 1000, false, "Transport time, to CU + from CU for one subframe"); - phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1_proc, 1); + phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1proc, 1); updateTimesReset(begingProcessing, &DuHigh, 1000, false, "DU high layer1 processing for DL"); } else LOG_E(PHY,"DL not received for subframe\n"); } pickStaticTime(begingProcessing); - feptx_prec(ru, L1_proc.frame_tx,L1_proc.subframe_tx ); - feptx_ofdm(ru, L1_proc.frame_tx,L1_proc.subframe_tx ); - ocp_tx_rf(ru, &L1_proc); + feptx_prec(ru, L1proc.frame_tx,L1proc.subframe_tx ); + feptx_ofdm(ru, L1proc.frame_tx,L1proc.subframe_tx ); + ocp_tx_rf(ru, &L1proc); updateTimesReset(begingProcessing, &DuLow, 1000, false, "DU low layer1 processing for DL"); if ( IS_SOFTMODEM_RFSIM ) @@ -1374,7 +1379,6 @@ void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc) { pickStaticTime(begingWait); rx_rf(ru, proc); updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait USRP"); - setAllfromTS(proc->timestamp_rx, proc); // front end processing: convert from time domain to frequency domain // fills rxdataF buffer fep_full(ru, proc->subframe_rx); @@ -1480,23 +1484,22 @@ void *cu_fs6(void *arg) { init_frame_parms(ru->frame_parms,1); phy_init_RU(ru); wait_sync("ru_thread"); - char *remoteIP; - - if ( getenv("FS6_REMOTE_IP") ) - remoteIP=getenv("FS6_REMOTE_IP"); - else - remoteIP=DU_IP; - - AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, DU_PORT, &sockFS6), ""); + char remoteIP[1024]; + strncpy(remoteIP,get_softmodem_params()->split73+3, 1023); //three first char should be cu: or du: + char port_def[256]=DU_PORT; + for (int i=0; i <1000; i++) + if (remoteIP[i]==':') { + strncpy(port_def,remoteIP+i+1,255); + remoteIP[i]=0; + break; + } + + AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, port_def, &sockFS6), ""); L1_rxtx_proc_t L1proc= {0}; - - if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) - initTpool(get_softmodem_params()->threadPoolConfig, &L1proc.threadPool, true); - else - initTpool("n", &L1proc.threadPool, true); - - initNotifiedFIFO(&L1proc.respEncode); - initNotifiedFIFO(&L1proc.respDecode); + // We pick the global thread pool from the legacy code global vars + L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool; + L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode; + L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode; uint64_t timeStamp=0; initStaticTime(begingWait); initStaticTime(begingWait2); @@ -1529,14 +1532,16 @@ void *du_fs6(void *arg) { phy_init_RU(ru); init_rf(ru); wait_sync("ru_thread"); - char *remoteIP; - - if ( getenv("FS6_REMOTE_IP") ) - remoteIP=getenv("FS6_REMOTE_IP"); - else - remoteIP=CU_IP; - - AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, CU_PORT, &sockFS6), ""); + char remoteIP[1024]; + strncpy(remoteIP,get_softmodem_params()->split73+3,1023); //three first char should be cu: or du: + char port_def[256]=CU_PORT; + for (int i=0; i <1000; i++) + if (remoteIP[i]==':') { + strncpy(port_def,remoteIP+i+1,255); + remoteIP[i]=0; + break; + } + AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, port_def, &sockFS6), ""); if (ru->rfdevice.trx_start_func(&ru->rfdevice) != 0) LOG_E(HW,"Could not start the RF device\n"); @@ -1551,8 +1556,13 @@ void *du_fs6(void *arg) { if ( !IS_SOFTMODEM_RFSIM ) threadCreate(&t, DL_du_fs6, (void *)ru, "MainDuTx", -1, OAI_PRIORITY_RT_MAX); - while(oai_exit) { - L1_rxtx_proc_t L1proc; + L1_rxtx_proc_t L1proc= {0}; + // We pick the global thread pool from the legacy code global vars + L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool; + L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode; + L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode; + + while(!oai_exit) { updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)"); pickStaticTime(begingWait); UL_du_fs6(ru, &L1proc); @@ -1562,7 +1572,7 @@ void *du_fs6(void *arg) { updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing"); } - + ru->rfdevice.trx_end_func(&ru->rfdevice); LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); return NULL; diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 97939846fd..50cd1f2714 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -5,8 +5,11 @@ /* * This file replaces + * targets/RT/USER/lte-softmodem.c + * targets/RT/USER/rt_wrapper.c * targets/RT/USER/lte-ru.c * targets/RT/USER/lte-enb.c + * targets/RT/USER/ru_control.c * openair1/SCHED/prach_procedures.c * The merger of OpenAir central code to this branch * should check if these 3 files are modified and analyze if code code has to be copied in here @@ -16,6 +19,7 @@ #include #include +#include static int DEFBANDS[] = {7}; static int DEFENBS[] = {0}; #include @@ -30,8 +34,33 @@ static int DEFENBS[] = {0}; #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -extern uint16_t sf_ahead; +pthread_cond_t nfapi_sync_cond; +pthread_mutex_t nfapi_sync_mutex; +int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. +int config_sync_var=-1; +volatile int oai_exit = 0; +double cpuf; +uint16_t sf_ahead=4; +int otg_enabled; +uint32_t downlink_frequency[MAX_NUM_CCs][4]; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; +int split73; +char * split73_config; +int split73; static void *ru_thread( void *param ); void kill_RU_proc(RU_t *ru) { @@ -42,6 +71,34 @@ void free_transport(PHY_VARS_eNB *eNB) { } void reset_opp_meas(void) { } +extern void phy_free_RU(RU_t *); + +void exit_function(const char *file, const char *function, const int line, const char *s) { + if (s != NULL) { + printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s); + } + + close_log_mem(); + oai_exit = 1; + + if (RC.ru == NULL) + exit(-1); // likely init not completed, prevent crash or hang, exit now... + + for (int ru_id=0; ru_idrfdevice.trx_end_func) { + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + RC.ru[ru_id]->rfdevice.trx_end_func = NULL; + } + + if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) { + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + RC.ru[ru_id]->ifdevice.trx_end_func = NULL; + } + } + + sleep(1); //allow lte-softmodem threads to exit first + exit(1); +} // Fixme: there are many mistakes in the datamodel and in redondant variables // TDD is also mode complex @@ -67,92 +124,47 @@ void setAllfromTS(uint64_t TS, L1_rxtx_proc_t *proc) { return; } - -void init_eNB_proc(int inst) { - /*int i=0;*/ - int CC_id; - PHY_VARS_eNB *eNB; - - for (CC_id=0; CC_idUL_INFO_mutex, NULL); - } - - //for multiple CCs: setup master and slaves - /* - for (CC_id=0; CC_idnode_timing == synch_to_ext_device) { //master - proc->num_slaves = MAX_NUM_CCs-1; - proc->slave_proc = (L1_proc_t**)malloc(proc->num_slaves*sizeof(L1_proc_t*)); - - for (i=0; i< eNB->proc.num_slaves; i++) { - if (i < CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc); - if (i >= CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc); - } - } - } - */ -} - void init_RU_proc(RU_t *ru) { pthread_t t; - char *fs6=getenv("fs6"); - if (fs6) { - if ( strncasecmp(fs6,"cu", 2) == 0 ) - threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); - else if ( strncasecmp(fs6,"du", 2) == 0 ) { - threadCreate(&t, du_fs6, (void *)ru, "MainDuRx", -1, OAI_PRIORITY_RT_MAX); - } else - AssertFatal(false, "environement variable fs6 is not cu or du"); - } else + switch(split73) { + case SPLIT73_CU: + threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX); + break; + case SPLIT73_DU: + threadCreate(&t, du_fs6, (void *)ru, "MainDuRx", -1, OAI_PRIORITY_RT_MAX); + break; + default: threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX); + } } +// Create per UE structures void init_transport(PHY_VARS_eNB *eNB) { - int i; - int j; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; LOG_I(PHY, "Initialise transport\n"); - for (i=0; idlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp); - - if (!eNB->dlsch[i][j]) { - LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i); - exit(-1); - } else { - eNB->dlsch[i][j]->rnti=0; - LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,eNB->dlsch[i][j], eNB->dlsch[i][j]->rnti); - } + for (int j=0; j<2; j++) { + AssertFatal( (eNB->dlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp)) != NULL, + "Can't get eNB dlsch structures for UE %d \n", i); + eNB->dlsch[i][j]->rnti=0; + LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,eNB->dlsch[i][j], eNB->dlsch[i][j]->rnti); } LOG_D(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i); - eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0); - - if (!eNB->ulsch[1+i]) { - LOG_E(PHY,"Can't get eNB ulsch structures\n"); - exit(-1); - } - + AssertFatal((eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0)) != NULL, + "Can't get eNB ulsch structures\n"); // this is the transmission mode for the signalling channels // this will be overwritten with the real transmission mode by the RRC once the UE is connected eNB->transmission_mode[i] = fp->nb_antenna_ports_eNB==1 ? 1 : 2; } // ULSCH for RA - eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0); - - if (!eNB->ulsch[0]) { - LOG_E(PHY,"Can't get eNB ulsch structures\n"); - exit(-1); - } - + AssertFatal( (eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0)) !=NULL, + "Can't get eNB ulsch structures\n"); eNB->dlsch_SI = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); LOG_D(PHY,"eNB %d.%d : SI %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_SI); eNB->dlsch_ra = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); @@ -161,7 +173,7 @@ void init_transport(PHY_VARS_eNB *eNB) { LOG_D(PHY,"eNB %d.%d : MCH %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_MCH); eNB->rx_total_gain_dB=130; - for(i=0; imu_mimo_mode[i].dl_pow_off = 2; eNB->check_for_total_transmissions = 0; @@ -172,23 +184,19 @@ void init_transport(PHY_VARS_eNB *eNB) { } void init_eNB_afterRU(void) { - int inst,CC_id,ru_id,i,aa; - PHY_VARS_eNB *eNB; - - for (inst=0; instframe_parms.nb_antennas_rx = 0; eNB->frame_parms.nb_antennas_tx = 0; eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *)); for (int ce_level=0; ce_level<4; ce_level++) { - LOG_I(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); eNB->prach_vars_br.rxsigF[ce_level] = (int16_t **)malloc16(64*sizeof(int16_t *)); } - for (ru_id=0,aa=0; ru_idnum_RU; ru_id++) { + for (int ru_id=0,aa=0; ru_idnum_RU; ru_id++) { eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx; eNB->frame_parms.nb_antennas_tx += eNB->RU_list[ru_id]->nb_tx; AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL, @@ -198,7 +206,7 @@ void init_eNB_afterRU(void) { "RU %d : prach_rxsigF is NULL\n", eNB->RU_list[ru_id]->idx); - for (i=0; iRU_list[ru_id]->nb_rx; aa++,i++) { + for (int i=0; iRU_list[ru_id]->nb_rx; aa++,i++) { LOG_I(PHY,"Attaching RU %d antenna %d to eNB antenna %d\n",eNB->RU_list[ru_id]->idx,i,aa); eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[ru_id]->prach_rxsigF[i]; @@ -209,35 +217,24 @@ void init_eNB_afterRU(void) { } } - /* TODO: review this code, there is something wrong. - * In monolithic mode, we come here with nb_antennas_rx == 0 - * (not tested in other modes). - */ AssertFatal( eNB->frame_parms.nb_antennas_rx > 0 && eNB->frame_parms.nb_antennas_rx < 4, ""); AssertFatal( eNB->frame_parms.nb_antennas_tx > 0 && eNB->frame_parms.nb_antennas_rx < 4, ""); LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); init_transport(eNB); //init_precoding_weights(RC.eNB[inst][CC_id]); } - - init_eNB_proc(inst); } } void init_eNB(int single_thread_flag,int wait_for_sync) { - int CC_id; - int inst; - PHY_VARS_eNB *eNB; + AssertFatal(RC.eNB != NULL,"RC.eNB must have been allocated\n"); - if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB ** *) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **)); + for (int inst=0; instabstraction_flag = 0; eNB->single_thread_flag = single_thread_flag; AssertFatal((eNB->if_inst = IF_Module_init(inst))!=NULL,"Cannot register interface"); @@ -245,6 +242,7 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { eNB->if_inst->PHY_config_req = phy_config_request; memset((void *)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO)); memset((void *)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO)); + pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); LOG_I(PHY,"Setting indication lists\n"); eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = eNB->rx_pdu_list; eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list; @@ -381,7 +379,6 @@ int setup_RU_buffers(RU_t *ru) { return(0); } - void init_precoding_weights(PHY_VARS_eNB *eNB) { int layer,ru_id,aa,re,ue,tb; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; @@ -416,21 +413,21 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) { } void ocp_rx_prach(PHY_VARS_eNB *eNB, - L1_rxtx_proc_t *proc, - RU_t *ru, - uint16_t *max_preamble, - uint16_t *max_preamble_energy, - uint16_t *max_preamble_delay, - uint16_t *avg_preamble_energy, - uint16_t Nf, - uint8_t tdd_mapindex, - uint8_t br_flag) { + L1_rxtx_proc_t *proc, + RU_t *ru, + uint16_t *max_preamble, + uint16_t *max_preamble_energy, + uint16_t *max_preamble_delay, + uint16_t *avg_preamble_energy, + uint16_t Nf, + uint8_t tdd_mapindex, + uint8_t br_flag) { int i; int prach_mask=0; - + if (br_flag == 0) { rx_prach0(eNB,ru,proc->frame_prach, proc->subframe_prach, - max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,0,0); + max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,0,0); } else { // This is procedure for eMTC, basically handling the repetitions prach_mask = is_prach_subframe(&eNB->frame_parms,proc->frame_prach_br,proc->subframe_prach_br); @@ -445,7 +442,7 @@ void ocp_rx_prach(PHY_VARS_eNB *eNB, eNB->prach_vars_br.repetition_number[i]++; // do basic PRACH reception rx_prach0(eNB,ru,proc->frame_prach, proc->subframe_prach_br, - max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,1,i); + max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,1,i); // if last repetition, clear counter if (eNB->prach_vars_br.repetition_number[i] == eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[i]) { @@ -477,16 +474,16 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int br_flag) // run PRACH detection for CE-level 0 only for now when br_flag is set ocp_rx_prach(eNB, - proc, - eNB->RU_list[0], - &max_preamble[0], - &max_preamble_energy[0], - &max_preamble_delay[0], - &avg_preamble_energy[0], - proc->frame_prach, - 0 - ,br_flag - ); + proc, + eNB->RU_list[0], + &max_preamble[0], + &max_preamble_energy[0], + &max_preamble_delay[0], + &avg_preamble_energy[0], + proc->frame_prach, + 0 + ,br_flag + ); LOG_D(PHY,"RACH detection index 0: max preamble: %u, energy: %u, delay: %u, avg energy: %u\n", max_preamble[0], max_preamble_energy[0], @@ -531,7 +528,7 @@ void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int br_flag) /* ind++; } - } */// ce_level + } */// ce_level } else if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) { LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", @@ -616,13 +613,6 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name return(0); } -void eNB_top(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int dummy1, int dummy2, char *string,RU_t *ru) { - if (!oai_exit) { - if (rxtx(eNB,proc,string) < 0) - LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - } -} - void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp = ru->frame_parms; void *rxp[ru->nb_rx]; @@ -728,42 +718,36 @@ void ocp_tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) { static void *ru_thread( void *param ) { setbuf(stdout, NULL); setbuf(stderr, NULL); - RU_t *ru = (RU_t *)param; + RU_t *ru = (RU_t *)param; L1_rxtx_proc_t L1proc= {0}; - L1_rxtx_proc_t *proc=&L1proc; - - if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) - initTpool(get_softmodem_params()->threadPoolConfig, &L1proc.threadPool, true); - else - initTpool("n", &L1proc.threadPool, true); - - initNotifiedFIFO(&L1proc.respEncode); - initNotifiedFIFO(&L1proc.respDecode); - + // We pick the global thread pool from the legacy code global vars + L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool; + L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode; + L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode; + if (ru->if_south == LOCAL_RF) { // configure RF parameters only fill_rf_config(ru,ru->rf_config_file); init_frame_parms(ru->frame_parms,1); phy_init_RU(ru); init_rf(ru); } - + AssertFatal(setup_RU_buffers(ru)==0, "Exiting, cannot initialize RU Buffers\n"); LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); wait_sync("ru_thread"); - + // Start RF device if any if (ru->rfdevice.trx_start_func(&ru->rfdevice) != 0) LOG_E(HW,"Could not start the RF device\n"); else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); - + // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { // synchronization on input FH interface, acquire signals/data and block - rx_rf(ru, proc); - + rx_rf(ru, &L1proc); // do RX front-end processing (frequency-shift, dft) if needed - fep_full(ru, proc->subframe_rx); - + fep_full(ru, L1proc.subframe_rx); + // At this point, all information for subframe has been received on FH interface // If this proc is to provide synchronization, do so // Fixme: not used @@ -771,24 +755,23 @@ static void *ru_thread( void *param ) { for (int i=0; inum_eNB; i++) { char string[20]; sprintf(string,"Incoming RU %d",ru->idx); - eNB_top(ru->eNB_list[i],proc, proc->frame_rx,proc->subframe_rx,string,ru); + + if (rxtx(ru->eNB_list[i],&L1proc,string) < 0) + LOG_E(PHY,"eNB %d CC_id %d failed during execution\n", + ru->eNB_list[i]->Mod_id,ru->eNB_list[i]->CC_id); } - + // do TX front-end processing if needed (precoding and/or IDFTs) - feptx_prec(ru, proc->frame_tx, proc->subframe_tx); - + feptx_prec(ru, L1proc.frame_tx, L1proc.subframe_tx); // do OFDM if needed - feptx_ofdm(ru, proc->frame_tx, proc->subframe_tx); - + feptx_ofdm(ru, L1proc.frame_tx, L1proc.subframe_tx); // do outgoing fronthaul (south) if needed - ocp_tx_rf(ru, proc); + ocp_tx_rf(ru, &L1proc); } - + LOG_W(PHY,"Exiting ru_thread \n"); - ru->rfdevice.trx_end_func(&ru->rfdevice); LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); - return NULL; } @@ -801,34 +784,24 @@ int init_rf(RU_t *ru) { return ret; } - -void set_function_spec_param(RU_t *ru) { -} - -//extern void RCconfig_RU(void); - void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t time_source,int send_dmrssync) { - int ru_id; RU_t *ru; PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; int i; int CC_id; - // create status mask - pthread_mutex_init(&RC.ru_mutex,NULL); - pthread_cond_init(&RC.ru_cond,NULL); // read in configuration file) LOG_I(PHY,"configuring RU from file\n"); - RCconfig_RU(); LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n", RC.nb_L1_inst,RC.nb_RU,get_nprocs()); if (RC.nb_CC != 0) for (i=0; inum_RU=0; + for (CC_id=0; CC_idnum_RU=0; LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); - for (ru_id=0; ru_idrf_config_file = rf_config_file; @@ -862,43 +835,23 @@ void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t ti if (ru->num_eNB > 0) { LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); - - if (ru->eNB_list[0] == 0) { - LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", - __FUNCTION__); - ru->eNB_list[0] = RC.eNB[0][0]; - ru->num_eNB=1; - // - // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU - // - } else { - LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); - } + AssertFatal(ru->eNB_list[0], "ru->eNB_list is not initialized\n"); + } else { + LOG_E(PHY,"Wrong data model, assigning eNB 0, carrier 0 to RU 0\n"); + ru->eNB_list[0] = RC.eNB[0][0]; + ru->num_eNB=1; } eNB0 = ru->eNB_list[0]; - LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); - LOG_D(PHY, "eNB0:%p\n", eNB0); + // datamodel error in regular OAI: a RU uses one single eNB carrier parameters! + ru->frame_parms = &eNB0->frame_parms; - if (eNB0) { - LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); - ru->frame_parms=&eNB0->frame_parms; - - for (i=0; inum_eNB; i++) { - eNB0 = ru->eNB_list[i]; - eNB0->RU_list[eNB0->num_RU++] = ru; - } + for (i=0; inum_eNB; i++) { + eNB0 = ru->eNB_list[i]; + int ruIndex=eNB0->num_RU++; + eNB0->RU_list[ruIndex] = ru; } - - LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n", - ru_id,ru_if_types[ru->if_south],NB_timing[ru->if_timing],ru->function); - set_function_spec_param(ru); - LOG_I(PHY,"Starting ru_thread %d\n",ru_id); - init_RU_proc(ru); } // for ru_id - - // sleep(1); - LOG_D(HW,"[lte-softmodem.c] RU threads created\n"); } void stop_RU(int nb_ru) { @@ -912,20 +865,25 @@ void stop_RU(int nb_ru) { /* from here function to use configuration module */ static int DEFBFW[] = {0x00007fff}; void RCconfig_RU(void) { - int j = 0; - int i = 0; paramdef_t RUParams[] = RUPARAMS_DESC; paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); - if ( RUParamList.numelt == 0 ) { + if ( RUParamList.numelt == 0 ) { + LOG_W(PHY, "Calling RCconfig_RU while no ru\n"); RC.nb_RU = 0; return; } // setting != NULL + if ( RC.ru != NULL ) { + LOG_W(PHY, "Calling RCconfig_RU twice (nb ru=%d), ignoring the second call data structure is %p\n", + RUParamList.numelt,RC.ru); + return; + } + RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); - for (j = 0; j < RC.nb_RU; j++) { + for (int j = 0; j < RC.nb_RU; j++) { RC.ru[j] = (RU_t *)calloc(sizeof(RU_t), 1); RC.ru[j]->idx = j; LOG_I(PHY,"Creating RC.ru[%d]:%p\n", j, RC.ru[j]); @@ -937,7 +895,7 @@ void RCconfig_RU(void) { else RC.ru[j]->num_eNB = 0; - for (i=0; inum_eNB; i++) + for (int i=0; inum_eNB; i++) RC.ru[j]->eNB_list[i] = RC.eNB[vals[RU_ENB_LIST_IDX].iptr[i]][0]; if (config_isparamset(vals, RU_SDR_ADDRS)) { @@ -981,7 +939,7 @@ void RCconfig_RU(void) { RC.ru[j]->sf_extension = *(vals[RU_SF_EXTENSION_IDX].uptr); RC.ru[j]->end_of_burst_delay = *(vals[RU_END_OF_BURST_DELAY_IDX].uptr); - for (i=0; inum_bands; i++) RC.ru[j]->band[i] = vals[RU_BAND_LIST_IDX].iptr[i]; + for (int i=0; inum_bands; i++) RC.ru[j]->band[i] = vals[RU_BAND_LIST_IDX].iptr[i]; } else { LOG_I(PHY,"RU %d: Transport %s\n",j,*(vals[RU_TRANSPORT_PREFERENCE_IDX].strptr)); RC.ru[j]->eth_params.local_if_name = strdup(*(vals[RU_LOCAL_IF_NAME_IDX].strptr)); @@ -1001,3 +959,430 @@ void RCconfig_RU(void) { return; } + + +static void get_options(void) { + CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); + get_common_options(); + CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP); + + if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) { + memset((void *)&RC,0,sizeof(RC)); + /* Read RC configuration file */ + RCConfig(); + NB_eNB_INST = RC.nb_inst; + printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU); + + if (!IS_SOFTMODEM_NONBIOT) { + load_NB_IoT(); + printf(" nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n", + RC.nb_nb_iot_rrc_inst, RC.nb_nb_iot_L1_inst, RC.nb_nb_iot_macrlc_inst); + } else { + printf("All Nb-IoT instances disabled\n"); + RC.nb_nb_iot_rrc_inst=RC.nb_nb_iot_L1_inst=RC.nb_nb_iot_macrlc_inst=0; + } + } +} + +void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { + int CC_id; + + for (CC_id=0; CC_idframe_type = FDD; + frame_parms[CC_id]->tdd_config = 3; + frame_parms[CC_id]->tdd_config_S = 0; + frame_parms[CC_id]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = 0; + frame_parms[CC_id]->num_MBSFN_config = 0; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; + frame_parms[CC_id]->nb_antennas_tx = 1; + frame_parms[CC_id]->nb_antennas_rx = 1; + frame_parms[CC_id]->nushift = 0; + frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth; + frame_parms[CC_id]->phich_config_common.phich_duration = normal; + // UL RS Config + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0 + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0; + frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; + // downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. + // downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; + // downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; + // downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; + //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); + frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0]; + } +} + +void init_pdcp(void) { + if (!NODE_IS_DU(RC.rrc[0]->node_type)) { + pdcp_layer_init(); + uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ? + (PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT) : LINK_ENB_PDCP_TO_GTPV1U_BIT; + + if (IS_SOFTMODEM_NOS1) + pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT ; + + pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_W_MBMS_BIT; + + if ( split73!=SPLIT73_DU) + pdcp_module_init(pdcp_initmask); + + if (NODE_IS_CU(RC.rrc[0]->node_type)) { + pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t)proto_agent_send_rlc_data_req); + } else { + pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t) rlc_data_req); + pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind); + } + } else { + pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) proto_agent_send_pdcp_data_ind); + } +} + +static void wait_nfapi_init(char *thread_name) { + printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name); + pthread_mutex_lock( &nfapi_sync_mutex ); + + while (nfapi_sync_var<0) + pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex ); + + pthread_mutex_unlock(&nfapi_sync_mutex); + printf( "NFAPI: got sync (%s)\n", thread_name); +} + +void terminate_task(module_id_t mod_id, task_id_t from, task_id_t to) { + LOG_I(ENB_APP, "sending TERMINATE_MESSAGE from task %s (%d) to task %s (%d)\n", + itti_get_task_name(from), from, itti_get_task_name(to), to); + MessageDef *msg; + msg = itti_alloc_new_message (from, TERMINATE_MESSAGE); + itti_send_msg_to_task (to, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); +} + +int stop_L1L2(module_id_t enb_id) { + LOG_W(ENB_APP, "stopping lte-softmodem\n"); + + if (!RC.ru) { + LOG_UI(ENB_APP, "no RU configured\n"); + return -1; + } + + /* these tasks need to pick up new configuration */ + terminate_task(enb_id, TASK_ENB_APP, TASK_RRC_ENB); + oai_exit = 1; + LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", enb_id); + kill_RU_proc(RC.ru[enb_id]); + LOG_I(ENB_APP, "calling kill_eNB_proc() for instance %d\n", enb_id); + kill_eNB_proc(enb_id); + oai_exit = 0; + + for (int cc_id = 0; cc_id < RC.nb_CC[enb_id]; cc_id++) { + free_transport(RC.eNB[enb_id][cc_id]); + phy_free_lte_eNB(RC.eNB[enb_id][cc_id]); + } + + phy_free_RU(RC.ru[enb_id]); + free_lte_top(); + return 0; +} + +/* + * Restart the lte-softmodem after it has been soft-stopped with stop_L1L2() + */ +int restart_L1L2(module_id_t enb_id) { + RU_t *ru = RC.ru[enb_id]; + MessageDef *msg_p = NULL; + LOG_W(ENB_APP, "restarting lte-softmodem\n"); + /* block threads */ + pthread_mutex_lock(&sync_mutex); + sync_var = -1; + pthread_mutex_unlock(&sync_mutex); + RC.ru_mask |= (1 << ru->idx); + /* copy the changed frame parameters to the RU */ + /* TODO this should be done for all RUs associated to this eNB */ + memcpy(&ru->frame_parms, &RC.eNB[enb_id][0]->frame_parms, sizeof(LTE_DL_FRAME_PARMS)); + /* reset the list of connected UEs in the MAC, since in this process with + * loose all UEs (have to reconnect) */ + init_UE_list(&RC.mac[enb_id]->UE_list); + LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); + // No more rrc thread, as many race conditions are hidden behind + rrc_enb_init(); + itti_mark_task_ready(TASK_RRC_ENB); + /* pass a reconfiguration request which will configure everything down to + * RC.eNB[i][j]->frame_parms, too */ + msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + /* TODO XForms might need to be restarted, but it is currently (09/02/18) + * broken, so we cannot test it */ + init_RU_proc(ru); + ru->rf_map.card = 0; + ru->rf_map.chain = 0; /* CC_id + chain_offset;*/ + init_eNB_afterRU(); + printf("Sending sync to all threads\n"); + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + return 0; +} + +int main ( int argc, char **argv ) { + int i; + int CC_id = 0; + int node_type = ngran_eNB; + AssertFatal(load_configmodule(argc,argv,0), "[SOFTMODEM] Error, configuration module init failed\n"); + logInit(); + printf("Reading in command-line options\n"); + get_options (); + AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n"); + EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1; +#if T_TRACER + T_Config_Init(); +#endif + configure_linux(); + cpuf=get_cpu_freq_GHz(); + set_taus_seed (0); + + if (opp_enabled ==1) + reset_opp_meas(); + + itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); + init_opt(); +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); + + /* Read configuration */ + if (RC.nb_inst > 0) { + // Allocate memory from RC variable + read_config_and_init(); + } else { + printf("RC.nb_inst = 0, Initializing L1\n"); + RCconfig_L1(); + } + + /* We need to read RU configuration before FlexRAN starts so it knows what + * splits to report. Actual RU start comes later. */ + if (RC.nb_RU > 0 && NFAPI_MODE != NFAPI_MODE_VNF) { + RCconfig_RU(); + LOG_I(PHY, + "number of L1 instances %d, number of RU %d, number of CPU cores %d\n", + RC.nb_L1_inst, RC.nb_RU, get_nprocs()); + } + + if ( strlen(get_softmodem_params()->split73) > 0 ) { + char tmp[1024]={0}; + strncpy(tmp,get_softmodem_params()->split73, 1023); + tmp[2]=0; + if ( strncasecmp(tmp,"cu", 2)==0 ) + split73=SPLIT73_CU; + else if ( strncasecmp(tmp,"du", 2)==0 ) + split73=SPLIT73_DU; + else + AssertFatal(false,"split73 syntax: :[:] (string found: %s) \n",get_softmodem_params()->split73); + } + + if (RC.nb_inst > 0) { + /* Start the agent. If it is turned off in the configuration, it won't start */ + for (i = 0; i < RC.nb_inst; i++) { + flexran_agent_start(i); + } + + /* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks + * for monolithic/F1 modes */ + init_pdcp(); + AssertFatal(create_tasks(1)==0,"cannot create ITTI tasks\n"); + + for (int enb_id = 0; enb_id < RC.nb_inst; enb_id++) { + MessageDef *msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; + itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + } + + node_type = RC.rrc[0]->node_type; + } + + if (RC.nb_inst > 0 && NODE_IS_CU(node_type)) { + protocol_ctxt_t ctxt; + ctxt.module_id = 0 ; + ctxt.instance = 0; + ctxt.rnti = 0; + ctxt.enb_flag = 1; + ctxt.frame = 0; + ctxt.subframe = 0; + pdcp_run(&ctxt); + } + + /* start threads if only L1 or not a CU */ + if (RC.nb_inst == 0 || !NODE_IS_CU(node_type) || NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MODE_VNF) { + // init UE_PF_PO and mutex lock + pthread_mutex_init(&ue_pf_po_mutex, NULL); + memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*MAX_MOBILES_PER_ENB*MAX_NUM_CCs); + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + + if (NFAPI_MODE!=NFAPI_MONOLITHIC) { + LOG_I(ENB_APP,"NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + } + + if (NFAPI_MODE==NFAPI_MODE_VNF) {// VNF +#if defined(PRE_SCD_THREAD) + init_ru_vnf(); // ru pointer is necessary for pre_scd. +#endif + wait_nfapi_init("main?"); + } + + LOG_I(ENB_APP,"START MAIN THREADS\n"); + // start the main threads + number_of_cards = 1; + printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst); + + if (RC.nb_L1_inst > 0) { + printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", + get_softmodem_params()->single_thread_flag, + get_softmodem_params()->wait_for_sync); + init_eNB(get_softmodem_params()->single_thread_flag, + get_softmodem_params()->wait_for_sync); + } + + for (int x=0; x < RC.nb_L1_inst; x++) + for (int CC_id=0; CC_idproc.L1_proc; + L1proc->threadPool=(tpool_t *)malloc(sizeof(tpool_t)); + L1proc->respEncode=(notifiedFIFO_t *) malloc(sizeof(notifiedFIFO_t)); + L1proc->respDecode=(notifiedFIFO_t *) malloc(sizeof(notifiedFIFO_t)); + + if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) + initTpool(get_softmodem_params()->threadPoolConfig, L1proc->threadPool, true); + else + initTpool("n", L1proc->threadPool, true); + + initNotifiedFIFO(L1proc->respEncode); + initNotifiedFIFO(L1proc->respDecode); + } + } + + printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); + + // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator. + // but RU thread deals with pre_scd and this is necessary in VNF and simulator. + // some initialization is necessary and init_ru_vnf do this. + if (RC.nb_RU >0 && NFAPI_MODE!=NFAPI_MODE_VNF) { + printf("Initializing RU threads\n"); + init_RU(get_softmodem_params()->rf_config_file, + get_softmodem_params()->clock_source, + get_softmodem_params()->timing_source, + get_softmodem_params()->send_dmrs_sync); + + for (int ru_id=0; ru_idrf_map.card=0; + RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset); + LOG_I(PHY,"Starting ru_thread %d\n",ru_id); + init_RU_proc(RC.ru[ru_id]); + } + + config_sync_var=0; + + if (NFAPI_MODE==NFAPI_MODE_PNF) { // PNF + wait_nfapi_init("main?"); + } + + LOG_I(ENB_APP,"RC.nb_RU:%d\n", RC.nb_RU); + // once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration) + printf("ALL RUs ready - init eNBs\n"); + + if (NFAPI_MODE!=NFAPI_MODE_PNF && NFAPI_MODE!=NFAPI_MODE_VNF) { + LOG_I(ENB_APP,"Not NFAPI mode - call init_eNB_afterRU()\n"); + init_eNB_afterRU(); + } else { + LOG_I(ENB_APP,"NFAPI mode - DO NOT call init_eNB_afterRU()\n"); + } + + LOG_UI(ENB_APP,"ALL RUs ready - ALL eNBs ready\n"); + // connect the TX/RX buffers + sleep(1); /* wait for thread activation */ + LOG_I(ENB_APP,"Sending sync to all threads\n"); + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS); + } + + create_tasks_mbms(1); + // wait for end of program + LOG_UI(ENB_APP,"TYPE TO TERMINATE\n"); + // CI -- Flushing the std outputs for the previous marker to show on the eNB / DU / CU log file + fflush(stdout); + fflush(stderr); + + // end of CI modifications + //getchar(); + if(IS_SOFTMODEM_DOFORMS) + load_softscope("enb"); + + itti_wait_tasks_end(); + oai_exit=1; + LOG_I(ENB_APP,"oai_exit=%d\n",oai_exit); + // stop threads + + if (RC.nb_inst == 0 || !NODE_IS_CU(node_type)) { + if(IS_SOFTMODEM_DOFORMS) + end_forms(); + + LOG_I(ENB_APP,"stopping MODEM threads\n"); + stop_eNB(NB_eNB_INST); + stop_RU(RC.nb_RU); + + /* release memory used by the RU/eNB threads (incomplete), after all + * threads have been stopped (they partially use the same memory) */ + for (int inst = 0; inst < NB_eNB_INST; inst++) { + for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) { + free_transport(RC.eNB[inst][cc_id]); + phy_free_lte_eNB(RC.eNB[inst][cc_id]); + } + } + + for (int inst = 0; inst < RC.nb_RU; inst++) { + phy_free_RU(RC.ru[inst]); + } + + free_lte_top(); + end_configmodule(); + pthread_cond_destroy(&sync_cond); + pthread_mutex_destroy(&sync_mutex); + pthread_cond_destroy(&nfapi_sync_cond); + pthread_mutex_destroy(&nfapi_sync_mutex); + pthread_mutex_destroy(&ue_pf_po_mutex); + + for(int ru_id=0; ru_idrfdevice.trx_end_func) { + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + RC.ru[ru_id]->rfdevice.trx_end_func = NULL; + } + + if (RC.ru[ru_id]->ifdevice.trx_end_func) { + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + RC.ru[ru_id]->ifdevice.trx_end_func = NULL; + } + } + } + + terminate_opt(); + logClean(); + printf("Bye.\n"); + return 0; +} diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 46689b137a..43407de19b 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -180,14 +180,14 @@ static inline int rxtx(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int frame_t // **************************************** // Common RX procedures subframe n T(T_GNB_PHY_DL_TICK, T_INT(gNB->Mod_id), T_INT(frame_tx), T_INT(slot_tx)); -/* - // if this is IF5 or 3GPP_gNB - if (gNB && gNB->RU_list && gNB->RU_list[0] && gNB->RU_list[0]->function < NGFI_RAU_IF4p5) { - wakeup_prach_gNB(gNB,NULL,proc->frame_rx,proc->slot_rx); - } + /* + // if this is IF5 or 3GPP_gNB + if (gNB && gNB->RU_list && gNB->RU_list[0] && gNB->RU_list[0]->function < NGFI_RAU_IF4p5) { + wakeup_prach_gNB(gNB,NULL,proc->frame_rx,proc->slot_rx); + } - // UE-specific RX processing for subframe n - if (nfapi_mode == 0 || nfapi_mode == 1) */ + // UE-specific RX processing for subframe n + if (nfapi_mode == 0 || nfapi_mode == 1) */ pthread_mutex_lock(&gNB->UL_INFO_mutex); gNB->UL_INFO.frame = frame_rx; @@ -207,8 +207,8 @@ static inline int rxtx(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int frame_t if (oai_exit) return(-1); - //if (slot_rx == NR_UPLINK_SLOT || gNB->frame_parms.frame_type == FDD) - phy_procedures_gNB_uespec_RX(gNB, frame_rx, slot_rx); + //if (slot_rx == NR_UPLINK_SLOT || gNB->frame_parms.frame_type == FDD) + phy_procedures_gNB_uespec_RX(gNB, frame_rx, slot_rx); if(get_thread_parallel_conf() != PARALLEL_RU_L1_TRX_SPLIT) { phy_procedures_gNB_TX(gNB, frame_tx,slot_tx, 1); @@ -318,7 +318,7 @@ static void *gNB_L1_thread( void *param ) { gNB_L1_rxtx_proc_t *L1_proc = &gNB_proc->L1_proc; //PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id]; char thread_name[100]; - + // set default return value // set default return value gNB_thread_rxtx_status = 0; @@ -327,16 +327,15 @@ static void *gNB_L1_thread( void *param ) { while (!oai_exit) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 0 ); - if (wait_on_condition(&L1_proc->mutex,&L1_proc->cond,&L1_proc->instance_cnt,thread_name)<0) break; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 1 ); + if (wait_on_condition(&L1_proc->mutex,&L1_proc->cond,&L1_proc->instance_cnt,thread_name)<0) break; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 1 ); int frame_rx = L1_proc->frame_rx; int slot_rx = L1_proc->slot_rx; int frame_tx = L1_proc->frame_tx; int slot_tx = L1_proc->slot_tx; uint64_t timestamp_tx = L1_proc->timestamp_tx; - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX0_GNB,slot_tx); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_RX0_GNB,slot_rx); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_GNB,frame_tx); @@ -408,17 +407,15 @@ void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, char *string, struct } int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot_tx,uint64_t timestamp_tx) { - RU_t *ru; RU_proc_t *ru_proc; - int waitret = 0, ret = 0, time_ns = 1000*1000; struct timespec now, abstime; - // note this should depend on the numerology used by the TX L1 thread, set here for 500us slot time VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL,1); time_ns = time_ns/gNB->frame_parms.slots_per_subframe; AssertFatal((ret = pthread_mutex_lock(&proc->mutex_RUs_tx))==0,"mutex_lock returns %d\n",ret); + while (proc->instance_cnt_RUs < 0) { clock_gettime(CLOCK_REALTIME, &now); abstime.tv_sec = now.tv_sec; @@ -428,35 +425,32 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot abstime.tv_nsec -= 1000*1000*1000; abstime.tv_sec += 1; } + if((waitret = pthread_cond_timedwait(&proc->cond_RUs,&proc->mutex_RUs_tx,&abstime)) == 0) break; // this unlocks mutex_rxtx while waiting and then locks it again } + proc->instance_cnt_RUs = -1; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); AssertFatal((ret = pthread_mutex_unlock(&proc->mutex_RUs_tx))==0,"mutex_unlock returns %d\n",ret); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL,0); if (waitret == ETIMEDOUT) { - LOG_W(PHY,"Dropping TX slot (%d.%d) because FH is blocked more than 1 slot times (500us)\n",frame_tx,slot_tx); + LOG_W(PHY,"Dropping TX slot (%d.%d) because FH is blocked more than 1 slot times (500us)\n",frame_tx,slot_tx); + AssertFatal((ret=pthread_mutex_lock(&gNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); + gNB->proc.RU_mask_tx = 0; + AssertFatal((ret=pthread_mutex_unlock(&gNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RUs_tx))==0,"mutex_lock returns %d\n",ret); + proc->instance_cnt_RUs = 0; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RUs_tx))==0,"mutex_unlock returns %d\n",ret); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,1); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,0); + return(-1); + } - AssertFatal((ret=pthread_mutex_lock(&gNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); - gNB->proc.RU_mask_tx = 0; - AssertFatal((ret=pthread_mutex_unlock(&gNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RUs_tx))==0,"mutex_lock returns %d\n",ret); - proc->instance_cnt_RUs = 0; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RUs_tx))==0,"mutex_unlock returns %d\n",ret); - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,1); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,0); - - return(-1); - } - - for(int i=0; inum_RU; i++) - { + for(int i=0; inum_RU; i++) { ru = gNB->RU_list[i]; ru_proc = &ru->proc; - if (ru_proc->instance_cnt_gNBs == 0) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE, 1); @@ -464,62 +458,46 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot AssertFatal((ret=pthread_mutex_lock(&gNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); gNB->proc.RU_mask_tx = 0; AssertFatal((ret=pthread_mutex_unlock(&gNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE, 0); return(-1); } - AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_gNBs))==0,"ERROR pthread_mutex_lock failed on mutex_gNBs L1_thread_tx with ret=%d\n",ret); + AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_gNBs))==0,"ERROR pthread_mutex_lock failed on mutex_gNBs L1_thread_tx with ret=%d\n",ret); ru_proc->instance_cnt_gNBs = 0; ru_proc->timestamp_tx = timestamp_tx; ru_proc->tti_tx = slot_tx; ru_proc->frame_tx = frame_tx; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_UE, ru_proc->instance_cnt_gNBs); - - LOG_D(PHY,"Signaling tx_thread_fh for %d.%d\n",frame_tx,slot_tx); + LOG_D(PHY,"Signaling tx_thread_fh for %d.%d\n",frame_tx,slot_tx); // the thread can now be woken up AssertFatal(pthread_cond_signal(&ru_proc->cond_gNBs) == 0, - "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); + "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); AssertFatal((ret=pthread_mutex_unlock(&ru_proc->mutex_gNBs))==0,"mutex_unlock returned %d\n",ret); - } + return(0); } int wakeup_tx(PHY_VARS_gNB *gNB,int frame_rx,int slot_rx,int frame_tx,int slot_tx,uint64_t timestamp_tx) { - - gNB_L1_rxtx_proc_t *L1_proc_tx = &gNB->proc.L1_proc_tx; - int ret; - - AssertFatal((ret = pthread_mutex_lock(&L1_proc_tx->mutex))==0,"mutex_lock returns %d\n",ret); - - while(L1_proc_tx->instance_cnt == 0){ + while(L1_proc_tx->instance_cnt == 0) { pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex); } L1_proc_tx->instance_cnt = 0; - - L1_proc_tx->slot_rx = slot_rx; L1_proc_tx->frame_rx = frame_rx; L1_proc_tx->slot_tx = slot_tx; L1_proc_tx->frame_tx = frame_tx; L1_proc_tx->timestamp_tx = timestamp_tx; - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_UE,1); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_UE,0); - // the thread can now be woken up AssertFatal(pthread_cond_signal(&L1_proc_tx->cond) == 0, "ERROR pthread_cond_signal for gNB L1 thread\n"); - AssertFatal((ret=pthread_mutex_unlock(&L1_proc_tx->mutex))==0,"mutex_unlock returns %d\n",ret); - return(0); } @@ -532,22 +510,23 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { int i; struct timespec abstime; int time_ns = 50000; - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RU))==0,"mutex_lock returns %d\n",ret); - for (i=0;inum_RU;i++) { + + for (i=0; inum_RU; i++) { if (ru == gNB->RU_list[i]) { if ((proc->RU_mask&(1< 0) - LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", - gNB->Mod_id,proc->frame_rx,proc->slot_rx,ru->idx,gNB->num_RU,proc->RU_mask); + LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", + gNB->Mod_id,proc->frame_rx,proc->slot_rx,ru->idx,gNB->num_RU,proc->RU_mask); + proc->RU_mask |= (1<RU_mask != (1<num_RU)-1) { // not all RUs have provided their information so return LOG_E(PHY,"Not all RUs have provided their info\n"); AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU))==0,"mutex_unlock returns %d\n",ret); return(0); - } - else { // all RUs have provided their information so continue on and wakeup gNB processing + } else { // all RUs have provided their information so continue on and wakeup gNB processing proc->RU_mask = 0; AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU))==0,"muex_unlock returns %d\n",ret); } @@ -565,17 +544,16 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { AssertFatal((ret=pthread_mutex_timedlock(&L1_proc->mutex, &abstime)) == 0,"mutex_lock returns %d\n", ret); if (L1_proc->instance_cnt == 0) { // L1_thread is busy so abort the subframe - AssertFatal((ret=pthread_mutex_unlock( &L1_proc->mutex))==0,"muex_unlock return %d\n",ret); - LOG_W(PHY,"L1_thread isn't ready in %d.%d, aborting RX processing\n",ru_proc->frame_rx,ru_proc->tti_rx); - return(-1); + AssertFatal((ret=pthread_mutex_unlock( &L1_proc->mutex))==0,"muex_unlock return %d\n",ret); + LOG_W(PHY,"L1_thread isn't ready in %d.%d, aborting RX processing\n",ru_proc->frame_rx,ru_proc->tti_rx); + return(-1); } - + ++L1_proc->instance_cnt; - - // We have just received and processed the common part of a subframe, say n. - // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired // transmitted timestamp of the next TX slot (first). - // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, // we want to generate subframe (n+sl_ahead), so TS_tx = TX_rx+sl_ahead*samples_per_tti, // and proc->slot_tx = proc->slot_rx+sl_ahead L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot); @@ -583,9 +561,7 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { L1_proc->slot_rx = ru_proc->tti_rx; L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame; - LOG_D(PHY,"wakeupL1: passing parameter IC = %d, RX: %d.%d, TX: %d.%d to L1 sl_ahead = %d\n", L1_proc->instance_cnt, L1_proc->frame_rx, L1_proc->slot_rx, L1_proc->frame_tx, L1_proc->slot_tx, sl_ahead); - pthread_mutex_unlock( &L1_proc->mutex ); // the thread can now be woken up @@ -594,7 +570,7 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { exit_fun( "ERROR pthread_cond_signal" ); return(-1); } - + return(0); } /* @@ -698,23 +674,20 @@ static void* gNB_thread_prach( void* param ) { extern void init_td_thread(PHY_VARS_gNB *); extern void init_te_thread(PHY_VARS_gNB *); -static void* process_stats_thread(void* param) { - - PHY_VARS_gNB *gNB = (PHY_VARS_gNB*)param; - +static void *process_stats_thread(void *param) { + PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param; reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->dlsch_scrambling_stats); reset_meas(&gNB->dlsch_modulation_stats); - wait_sync("process_stats_thread"); - while(!oai_exit) - { + while(!oai_exit) { sleep(1); print_meas(&gNB->dlsch_encoding_stats, "pdsch_encoding", NULL, NULL); print_meas(&gNB->dlsch_scrambling_stats, "pdsch_scrambling", NULL, NULL); print_meas(&gNB->dlsch_modulation_stats, "pdsch_modulation", NULL, NULL); } + return(NULL); } @@ -767,6 +740,7 @@ void init_gNB_proc(int inst) { } if(opp_enabled == 1) threadCreate(&proc->L1_stats_thread, process_stats_thread,(void *)gNB, "time_meas", -1, OAI_PRIORITY_RT_LOW); + //pthread_create( &proc->pthread_prach, attr_prach, gNB_thread_prach, gNB ); char name[16]; @@ -904,7 +878,7 @@ void init_eNB_afterRU(void) { for (i=0; iRU_list[ru_id]->nb_rx; aa++,i++) { LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n",gNB->RU_list[ru_id]->idx,i,aa); - // gNB->prach_vars.rxsigF[0][aa] = gNB->RU_list[ru_id]->prach_rxsigF[i]; + // gNB->prach_vars.rxsigF[0][aa] = gNB->RU_list[ru_id]->prach_rxsigF[i]; gNB->common_vars.rxdataF[aa] = gNB->RU_list[ru_id]->common.rxdataF[i]; } } @@ -968,7 +942,6 @@ void init_gNB(int single_thread_flag,int wait_for_sync) { gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list; gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list; gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list; - gNB->prach_energy_counter = 0; } } diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 0003cf770d..05ae216d00 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -92,7 +92,7 @@ unsigned short config_frames[4] = {2,9,11,13}; static int DEFBANDS[] = {7}; static int DEFENBS[] = {0}; static int DEFBFW[] = {0x00007fff}; - + //static int DEFNRBANDS[] = {7}; //static int DEFGNBS[] = {0}; @@ -712,7 +712,7 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { } -void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { +void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; //nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config; @@ -758,7 +758,7 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot ); - for (i=0; inb_tx; i++){ + for (i=0; inb_tx; i++) { txp[i] = (void *)&ru->common.txdata[i][(slot*fp->samples_per_slot)-sf_extension]; } @@ -870,7 +870,7 @@ static void *ru_thread_prach( void *param ) { 0,0 ); } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );*/ + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );*/ if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; } @@ -1097,16 +1097,16 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { } } else if(N_RB == 106) { if (fp->threequarter_fs) { - cfg->sample_rate=46.08e6; - cfg->samples_per_frame = 460800; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; + cfg->sample_rate=46.08e6; + cfg->samples_per_frame = 460800; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; } else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; + cfg->sample_rate=61.44e6; + cfg->samples_per_frame = 614400; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; } } else { AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); @@ -1210,7 +1210,7 @@ static void *ru_stats_thread(void *param) { if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL); - if (ru->feptx_ofdm){ + if (ru->feptx_ofdm) { print_meas(&ru->precoding_stats,"feptx_prec",NULL,NULL); print_meas(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL); print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL); @@ -1219,7 +1219,7 @@ static void *ru_stats_thread(void *param) { if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); - print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); + print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); if (ru->fh_north_out) { print_meas(&ru->compression,"compression",NULL,NULL); print_meas(&ru->transport,"transport",NULL,NULL); @@ -1346,7 +1346,7 @@ static void *ru_thread_tx( void *param ) { if (L1_proc->instance_cnt_RUs == -1) { L1_proc->instance_cnt_RUs = 0; AssertFatal(pthread_cond_signal(&L1_proc->cond_RUs) == 0, - "ERROR pthread_cond_signal for gNB_L1_thread\n"); + "ERROR pthread_cond_signal for gNB_L1_thread\n"); } //else AssertFatal(1==0,"gNB TX thread is not ready\n"); ret = pthread_mutex_unlock(&L1_proc->mutex_RUs_tx); AssertFatal(ret == 0,"mutex_unlock returns %d\n",ret); @@ -1371,7 +1371,7 @@ static void *ru_thread( void *param ) { int print_frame = 8; int i = 0; int aa; - + // set default return value // set default return value ru_thread_status = 0; // set default return value @@ -1499,9 +1499,9 @@ static void *ru_thread( void *param ) { LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx); LOG_D(PHY,"Copying rxdataF from RU to gNB\n"); - for (aa=0;aanb_rx;aa++) - memcpy((void*)RC.gNB[0][0]->common_vars.rxdataF[aa], - (void*)ru->common.rxdataF[aa], fp->symbols_per_slot*fp->ofdm_symbol_size*sizeof(int32_t)); + for (aa=0; aanb_rx; aa++) + memcpy((void *)RC.gNB[0][0]->common_vars.rxdataF[aa], + (void *)ru->common.rxdataF[aa], fp->symbols_per_slot*fp->ofdm_symbol_size*sizeof(int32_t)); // At this point, all information for subframe has been received on FH interface @@ -2260,7 +2260,7 @@ void RCconfig_RU(void) } } else { - RC.ru[j]->openair0_cfg.clock_source = unset; + RC.ru[j]->openair0_cfg.clock_source = unset; } if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 6b72562033..60931f7674 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -176,6 +176,10 @@ uint32_t target_ul_mcs = 20; uint32_t timing_advance = 0; uint64_t num_missed_slots=0; // counter for the number of missed slots +int split73=0; +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) { + AssertFatal(false, "Must not be called in this context\n"); +} extern void reset_opp_meas(void); extern void print_opp_meas(void); @@ -721,13 +725,9 @@ int restart_L1L2(module_id_t gnb_id) { memcpy(&ru->nr_frame_parms, &RC.gNB[gnb_id][0]->frame_parms, sizeof(NR_DL_FRAME_PARMS)); set_function_spec_param(RC.ru[gnb_id]); LOG_I(GNB_APP, "attempting to create ITTI tasks\n"); - - if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { - LOG_E(RRC, "Create task for RRC eNB failed\n"); - return -1; - } else { - LOG_I(RRC, "Re-created task for RRC gNB successfully\n"); - } + // No more rrc thread, as many race conditions are hidden behind + rrc_enb_init(); + itti_mark_task_ready(TASK_RRC_ENB); if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { LOG_E(PDCP, "Create task for L2L1 failed\n"); @@ -771,23 +771,23 @@ static void wait_nfapi_init(char *thread_name) { void init_pdcp(void) { //if (!NODE_IS_DU(RC.rrc[0]->node_type)) { - pdcp_layer_init(); - uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ? - (PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT) : LINK_ENB_PDCP_TO_GTPV1U_BIT; + pdcp_layer_init(); + uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ? + (PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT) : LINK_ENB_PDCP_TO_GTPV1U_BIT; - if (IS_SOFTMODEM_NOS1){ - printf("IS_SOFTMODEM_NOS1 option enabled \n"); - pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT ; - } + if (IS_SOFTMODEM_NOS1) { + printf("IS_SOFTMODEM_NOS1 option enabled \n"); + pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT ; + } - pdcp_module_init(pdcp_initmask); + pdcp_module_init(pdcp_initmask); - /*if (NODE_IS_CU(RC.rrc[0]->node_type)) { - pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t)proto_agent_send_rlc_data_req); - } else {*/ - pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t) rlc_data_req); - pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind); - //} + /*if (NODE_IS_CU(RC.rrc[0]->node_type)) { + pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t)proto_agent_send_rlc_data_req); + } else {*/ + pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t) rlc_data_req); + pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind); + //} /*} else { pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) proto_agent_send_pdcp_data_ind); }*/ @@ -841,7 +841,7 @@ int main( int argc, char **argv ) MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); #endif -init_opt(); + init_opt(); #ifdef PDCP_USE_NETLINK @@ -857,7 +857,7 @@ init_opt(); LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); if(IS_SOFTMODEM_NOS1) - init_pdcp(); + init_pdcp(); #if defined(ENABLE_ITTI) @@ -883,37 +883,37 @@ init_opt(); mlockall(MCL_CURRENT | MCL_FUTURE); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); -/*#ifdef XFORMS - int UE_id; + /*#ifdef XFORMS + int UE_id; - if (do_forms==1) { - fl_initialize (&argc, argv, NULL, 0, 0); - form_stats_l2 = create_form_stats_form(); - fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); - form_stats = create_form_stats_form(); - fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + if (do_forms==1) { + fl_initialize (&argc, argv, NULL, 0, 0); + form_stats_l2 = create_form_stats_form(); + fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); - for(UE_id=0; UE_idphy_scope_gnb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + for(UE_id=0; UE_idphy_scope_gnb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - if (otg_enabled) { - fl_set_button(form_gnb[CC_id][UE_id]->button_0,1); - fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic ON"); - } else { - fl_set_button(form_gnb[CC_id][UE_id]->button_0,0); - fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic OFF"); - } - } // CC_id - } // UE_id + if (otg_enabled) { + fl_set_button(form_gnb[CC_id][UE_id]->button_0,1); + fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic ON"); + } else { + fl_set_button(form_gnb[CC_id][UE_id]->button_0,0); + fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic OFF"); + } + } // CC_id + } // UE_id - threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW); - printf("Scope thread created, ret=%d\n",ret); - } + threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW); + printf("Scope thread created, ret=%d\n",ret); + } -#endif*/ + #endif*/ usleep(10*1000); if (nfapi_mode) { @@ -1018,27 +1018,27 @@ init_opt(); printf("Terminating application - oai_exit=%d\n",oai_exit); #endif // stop threads -/*#ifdef XFORMS + /*#ifdef XFORMS - printf("waiting for XFORMS thread\n"); + printf("waiting for XFORMS thread\n"); - if (do_forms==1) { - pthread_join(forms_thread,&status); - fl_hide_form(form_stats->stats_form); - fl_free_form(form_stats->stats_form); + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); - fl_hide_form(form_stats_l2->stats_form); - fl_free_form(form_stats_l2->stats_form); + fl_hide_form(form_stats_l2->stats_form); + fl_free_form(form_stats_l2->stats_form); - for(UE_id=0; UE_idphy_scope_gNB); - fl_free_form(form_enb[CC_id][UE_id]->phy_scope_gNB); - } - } - } + for(UE_id=0; UE_idphy_scope_gNB); + fl_free_form(form_enb[CC_id][UE_id]->phy_scope_gNB); + } + } + } -#endif*/ + #endif*/ printf("stopping MODEM threads\n"); // cleanup stop_gNB(NB_gNB_INST); diff --git a/executables/nr-ue.c b/executables/nr-ue.c index c6e3873f18..f390e40cb5 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -148,7 +148,7 @@ PHY_VARS_NR_UE *init_nr_ue_vars(NR_DL_FRAME_PARMS *frame_parms, ue->Mod_id = UE_id; ue->mac_enabled = 1; - + // initialize all signal buffers // initialize all signal buffers init_nr_ue_signal(ue,1,abstraction_flag); // intialize transport @@ -380,7 +380,7 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { scheduled_response.CC_id = 0; scheduled_response.frame = proc->frame_rx; scheduled_response.slot = proc->nr_tti_rx; - + //--------------------------Temporary configuration-----------------------------// //--------------------------Temporary configuration-----------------------------// n_rnti = 0x1234; nb_rb = 50; @@ -391,7 +391,7 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { mcs = 9; harq_pid = 0; rvidx = 0; - //------------------------------------------------------------------------------// + //------------------------------------------------------------------------------// scheduled_response.ul_config->sfn_slot = NR_UPLINK_SLOT; scheduled_response.ul_config->number_pdus = 1; @@ -416,18 +416,18 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { LOG_D(PHY,"phy_procedures_nrUE_RX: slot:%d, time %lu\n", proc->nr_tti_rx, (rdtsc()-a)/3500); //printf(">>> nr_ue_pdcch_procedures ended\n"); #endif - if(IS_SOFTMODEM_NOS1){ //&& proc->nr_tti_rx==1 - //Hardcoded rnti value - protocol_ctxt_t ctxt; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE->Mod_id, ENB_FLAG_NO, - 0x1234, proc->frame_rx, - proc->nr_tti_rx, 0); - pdcp_run(&ctxt); - pdcp_fifo_flush_sdus(&ctxt); - } + if(IS_SOFTMODEM_NOS1) { //&& proc->nr_tti_rx==1 + //Hardcoded rnti value + protocol_ctxt_t ctxt; + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE->Mod_id, ENB_FLAG_NO, + 0x1234, proc->frame_rx, + proc->nr_tti_rx, 0); + pdcp_run(&ctxt); + pdcp_fifo_flush_sdus(&ctxt); + } } - + // no UL for now // no UL for now /* if (UE->mac_enabled==1) { @@ -465,7 +465,7 @@ void UE_processing(void *arg) { PHY_VARS_NR_UE *UE = rxtxD->UE; processSlotRX(UE, proc); uint8_t gNB_id = 0; - + // params for UL time alignment procedure // params for UL time alignment procedure NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id]; uint8_t numerology = UE->frame_parms.numerology_index; @@ -475,24 +475,24 @@ void UE_processing(void *arg) { //printf(">>> mac ended\n"); // Prepare the future Tx data -/* -#ifndef NO_RAT_NR + /* + #ifndef NO_RAT_NR - if (slot_select_nr(&UE->frame_parms, proc->frame_tx, proc->nr_tti_tx) & NR_UPLINK_SLOT) -#else - if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || - (UE->frame_parms.frame_type == FDD) ) -#endif -*/ + if (slot_select_nr(&UE->frame_parms, proc->frame_tx, proc->nr_tti_tx) & NR_UPLINK_SLOT) + #else + if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || + (UE->frame_parms.frame_type == FDD) ) + #endif + */ /* UL time alignment // If the current tx frame and slot match the TA configuration in ul_time_alignment // then timing advance is processed and set to be applied in the next UL transmission */ if (UE->mac_enabled == 1) { - if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot){ + if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot) { LOG_D(PHY,"Applying timing advance -- frame %d -- slot %d\n", frame_tx, slot_tx); - + //if (nfapi_mode!=3){ //if (nfapi_mode!=3){ nr_process_timing_advance(UE->Mod_id, UE->CC_id, ul_time_alignment->ta_command, numerology, bwp_ul_NB_RB); ul_time_alignment->ta_frame = -1; @@ -501,7 +501,7 @@ void UE_processing(void *arg) { } } - if (proc->nr_tti_tx == NR_UPLINK_SLOT || UE->frame_parms.frame_type == FDD){ + if (proc->nr_tti_tx == NR_UPLINK_SLOT || UE->frame_parms.frame_type == FDD) { thread_id = PHY_vars_UE_g[UE->Mod_id][0]->current_thread_id[proc->nr_tti_tx]; @@ -566,7 +566,7 @@ void trashFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { UE->frame_parms.samples_per_subframe, UE->frame_parms.nb_antennas_rx); if (IS_SOFTMODEM_RFSIM ) { - usleep(1000); // slow down, as would do actual rf to let cpu for the synchro thread + usleep(1000); // slow down, as would do actual rf to let cpu for the synchro thread } } @@ -579,24 +579,24 @@ void trashFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) { - LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); - void *dummy_tx[UE->frame_parms.nb_antennas_tx]; + LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); + void *dummy_tx[UE->frame_parms.nb_antennas_tx]; - for (int i=0; iframe_parms.nb_antennas_tx; i++) - dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4); + for (int i=0; iframe_parms.nb_antennas_tx; i++) + dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4); - for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) { - int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ; - AssertFatal(unitTransfer == - UE->rfdevice.trx_read_func(&UE->rfdevice, - timestamp, - (void **)UE->common_vars.rxdata, - unitTransfer, - UE->frame_parms.nb_antennas_rx),""); - } + for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) { + int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ; + AssertFatal(unitTransfer == + UE->rfdevice.trx_read_func(&UE->rfdevice, + timestamp, + (void **)UE->common_vars.rxdata, + unitTransfer, + UE->frame_parms.nb_antennas_rx),""); + } - for (int i=0; iframe_parms.nb_antennas_tx; i++) - free(dummy_tx[i]); + for (int i=0; iframe_parms.nb_antennas_tx; i++) + free(dummy_tx[i]); } @@ -727,7 +727,7 @@ void *UE_thread(void *arg) { #ifdef OAI_ADRV9371_ZC706 /*uint32_t total_gain_dB_prev = 0; if (total_gain_dB_prev != UE->rx_total_gain_dB) { - total_gain_dB_prev = UE->rx_total_gain_dB; + total_gain_dB_prev = UE->rx_total_gain_dB; openair0_cfg[0].rx_gain[0] = UE->rx_total_gain_dB; UE->rfdevice.trx_set_gains_func(&UE->rfdevice,&openair0_cfg[0]); }*/ @@ -763,29 +763,29 @@ void *UE_thread(void *arg) { readBlockSize, UE->frame_parms.nb_antennas_rx),""); -if (slot_nr == (20+NR_UPLINK_SLOT-DURATION_RX_TO_TX - 1)%20) - AssertFatal( writeBlockSize == - UE->rfdevice.trx_write_func(&UE->rfdevice, - timestamp+ - (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot) - - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - - openair0_cfg[0].tx_sample_advance, - txp, - writeBlockSize, - UE->frame_parms.nb_antennas_tx, - 2),""); + if (slot_nr == (20+NR_UPLINK_SLOT-DURATION_RX_TO_TX - 1)%20) + AssertFatal( writeBlockSize == + UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp+ + (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot) - + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - + openair0_cfg[0].tx_sample_advance, + txp, + writeBlockSize, + UE->frame_parms.nb_antennas_tx, + 2),""); -if (slot_nr == (20+NR_UPLINK_SLOT-DURATION_RX_TO_TX)%20) - AssertFatal( writeBlockSize == - UE->rfdevice.trx_write_func(&UE->rfdevice, - timestamp+ - (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot) - - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - - openair0_cfg[0].tx_sample_advance, - txp, - writeBlockSize, - UE->frame_parms.nb_antennas_tx, - 3),""); + if (slot_nr == (20+NR_UPLINK_SLOT-DURATION_RX_TO_TX)%20) + AssertFatal( writeBlockSize == + UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp+ + (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot) - + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - + openair0_cfg[0].tx_sample_advance, + txp, + writeBlockSize, + UE->frame_parms.nb_antennas_tx, + 3),""); if( slot_nr==(nb_slot_frame-1)) { // read in first symbol of next frame and adjust for timing drift diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 6bcbec3790..eb57d9a5de 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -214,7 +214,7 @@ int emulate_rf = 0; tpool_t *Tpool; #ifdef UE_DLSCH_PARALLELISATION -tpool_t *Tpool_dl; + tpool_t *Tpool_dl; #endif @@ -308,8 +308,8 @@ static void *scope_thread(void *arg) { while (!oai_exit) { phy_scope_nrUE(form_nrue[0], - PHY_vars_UE_g[0][0], - 0,0,1); + PHY_vars_UE_g[0][0], + 0,0,1); usleep(100*1000); } @@ -382,9 +382,9 @@ static void get_options(void) { int tddflag=0, nonbiotflag, vcdflag=0; char *loopfile=NULL; int dumpframe=0; - //uint32_t noS1; //uint32_t nokrnmod; + //uint32_t nokrnmod; paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC_UE ; config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); @@ -511,12 +511,12 @@ void init_openair0(void) { else { openair0_cfg[card].sample_rate=122.88e6; openair0_cfg[card].samples_per_frame = 1228800; - } + } } else { LOG_E(PHY,"Unsupported numerology!\n"); exit(-1); } - }else if(frame_parms[0]->N_RB_DL == 273) { + } else if(frame_parms[0]->N_RB_DL == 273) { if (numerology==1) { if (frame_parms[0]->threequarter_fs) { AssertFatal(0 == 1,"three quarter sampling not supported for N_RB 273\n"); @@ -524,12 +524,12 @@ void init_openair0(void) { else { openair0_cfg[card].sample_rate=122.88e6; openair0_cfg[card].samples_per_frame = 1228800; - } + } } else { LOG_E(PHY,"Unsupported numerology!\n"); exit(-1); } - }else if(frame_parms[0]->N_RB_DL == 106) { + } else if(frame_parms[0]->N_RB_DL == 106) { if (numerology==0) { if (frame_parms[0]->threequarter_fs) { openair0_cfg[card].sample_rate=23.04e6; @@ -538,15 +538,15 @@ void init_openair0(void) { openair0_cfg[card].sample_rate=30.72e6; openair0_cfg[card].samples_per_frame = 307200; } - } else if (numerology==1) { + } else if (numerology==1) { if (frame_parms[0]->threequarter_fs) { - openair0_cfg[card].sample_rate=46.08e6; - openair0_cfg[card].samples_per_frame = 460800; + openair0_cfg[card].sample_rate=46.08e6; + openair0_cfg[card].samples_per_frame = 460800; } else { - openair0_cfg[card].sample_rate=61.44e6; - openair0_cfg[card].samples_per_frame = 614400; - } + openair0_cfg[card].sample_rate=61.44e6; + openair0_cfg[card].samples_per_frame = 614400; + } } else if (numerology==2) { openair0_cfg[card].sample_rate=122.88e6; openair0_cfg[card].samples_per_frame = 1228800; @@ -621,7 +621,7 @@ void init_pdcp(void) { pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; /*if (rlc_module_init() != 0) { - LOG_I(RLC, "Problem at RLC initiation \n"); + LOG_I(RLC, "Problem at RLC initiation \n"); } pdcp_layer_init(); nr_ip_over_LTE_DRB_preconfiguration();*/ @@ -633,7 +633,7 @@ void init_pdcp(void) { // Stupid function addition because UE itti messages queues definition is common with eNB void *rrc_enb_process_itti_msg(void *notUsed) { - return NULL; + return NULL; } @@ -663,12 +663,12 @@ int main( int argc, char **argv ) { set_taus_seed (0); tpool_t pool; Tpool = &pool; - char params[]="-1,-1"; + char params[]="-1,-1"; initTpool(params, Tpool, false); #ifdef UE_DLSCH_PARALLELISATION tpool_t pool_dl; Tpool_dl = &pool_dl; - char params_dl[]="-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1"; + char params_dl[]="-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"; initTpool(params_dl, Tpool_dl, false); #endif cpuf=get_cpu_freq_GHz(); @@ -676,21 +676,21 @@ int main( int argc, char **argv ) { init_opt() ; if(IS_SOFTMODEM_NOS1) - init_pdcp(); + init_pdcp(); if (ouput_vcd) { vcd_signal_dumper_init("/tmp/openair_dump_nrUE.vcd"); } -/* -#ifdef PDCP_USE_NETLINK - netlink_init(); -#if defined(PDCP_USE_NETLINK_QUEUES) - pdcp_netlink_init(); -#endif -#endif -*/ - #ifndef PACKAGE_VERSION + /* + #ifdef PDCP_USE_NETLINK + netlink_init(); + #if defined(PDCP_USE_NETLINK_QUEUES) + pdcp_netlink_init(); + #endif + #endif + */ +#ifndef PACKAGE_VERSION # define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" #endif LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); diff --git a/executables/softmodem-common.c b/executables/softmodem-common.c index 78d0d01ef9..de5009eccc 100644 --- a/executables/softmodem-common.c +++ b/executables/softmodem-common.c @@ -125,27 +125,27 @@ void get_common_options(void) { } void softmodem_printresources(int sig, telnet_printfunc_t pf) { - struct rusage usage; - struct timespec stop; + struct rusage usage; + struct timespec stop; - clock_gettime(CLOCK_BOOTTIME, &stop); + clock_gettime(CLOCK_BOOTTIME, &stop); - uint64_t elapse = (stop.tv_sec - start.tv_sec) ; // in seconds + uint64_t elapse = (stop.tv_sec - start.tv_sec) ; // in seconds - int st = getrusage(RUSAGE_SELF,&usage); - if (!st) { - pf("\nRun time: %lluh %llus\n",(unsigned long long)elapse/3600,(unsigned long long)(elapse - (elapse/3600))); - pf("\tTime executing user inst.: %lds %ldus\n",(long)usage.ru_utime.tv_sec,(long)usage.ru_utime.tv_usec); - pf("\tTime executing system inst.: %lds %ldus\n",(long)usage.ru_stime.tv_sec,(long)usage.ru_stime.tv_usec); - pf("\tMax. Phy. memory usage: %ldkB\n",(long)usage.ru_maxrss); - pf("\tPage fault number (no io): %ld\n",(long)usage.ru_minflt); - pf("\tPage fault number (requiring io): %ld\n",(long)usage.ru_majflt); - pf("\tNumber of file system read: %ld\n",(long)usage.ru_inblock); - pf("\tNumber of filesystem write: %ld\n",(long)usage.ru_oublock); - pf("\tNumber of context switch (process origin, io...): %ld\n",(long)usage.ru_nvcsw); - pf("\tNumber of context switch (os origin, priority...): %ld\n",(long)usage.ru_nivcsw); - } + int st = getrusage(RUSAGE_SELF,&usage); + if (!st) { + pf("\nRun time: %lluh %llus\n",(unsigned long long)elapse/3600,(unsigned long long)(elapse - (elapse/3600))); + pf("\tTime executing user inst.: %lds %ldus\n",(long)usage.ru_utime.tv_sec,(long)usage.ru_utime.tv_usec); + pf("\tTime executing system inst.: %lds %ldus\n",(long)usage.ru_stime.tv_sec,(long)usage.ru_stime.tv_usec); + pf("\tMax. Phy. memory usage: %ldkB\n",(long)usage.ru_maxrss); + pf("\tPage fault number (no io): %ld\n",(long)usage.ru_minflt); + pf("\tPage fault number (requiring io): %ld\n",(long)usage.ru_majflt); + pf("\tNumber of file system read: %ld\n",(long)usage.ru_inblock); + pf("\tNumber of filesystem write: %ld\n",(long)usage.ru_oublock); + pf("\tNumber of context switch (process origin, io...): %ld\n",(long)usage.ru_nvcsw); + pf("\tNumber of context switch (os origin, priority...): %ld\n",(long)usage.ru_nivcsw); + } } void signal_handler(int sig) { @@ -160,9 +160,9 @@ void signal_handler(int sig) { backtrace_symbols_fd(array, size, 2); exit(-1); } else { - if(sig==SIGINT ||sig==SOFTMODEM_RTSIGNAL) - softmodem_printresources(sig,(telnet_printfunc_t)printf); - if (sig != SOFTMODEM_RTSIGNAL) { + if(sig==SIGINT ||sig==SOFTMODEM_RTSIGNAL) + softmodem_printresources(sig,(telnet_printfunc_t)printf); + if (sig != SOFTMODEM_RTSIGNAL) { printf("Linux signal %s...\n",strsignal(sig)); exit_function(__FILE__, __FUNCTION__, __LINE__,"softmodem starting exit procedure\n"); } @@ -172,7 +172,7 @@ void signal_handler(int sig) { void set_softmodem_sighandler(void) { - struct sigaction act,oldact; + struct sigaction act,oldact; clock_gettime(CLOCK_BOOTTIME, &start); memset(&act,0,sizeof(act)); act.sa_handler=signal_handler; @@ -181,5 +181,5 @@ void set_softmodem_sighandler(void) { signal(SIGSEGV, signal_handler); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); - signal(SIGABRT, signal_handler); + signal(SIGABRT, signal_handler); } diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 8fedb74949..a356ec50a4 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -37,6 +37,11 @@ extern "C" #endif /* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ #define CONFIG_HLP_RFCFGF "Configuration file for front-end (e.g. LMS7002M)\n" +#define CONFIG_HLP_SPLIT73 "Split 7.3 (below rate matching) option: ::" +#define CONFIG_HLP_TPOOL "Thread pool configuration: \n\ + default no pool (runs in calling thread),\n\ + list of cores, comma separated (negative value is no core affinity)\n\ + example: -1,3 launches two working threads one floating, the second set on core 3" #define CONFIG_HLP_ULMAXE "set the eNodeB max ULSCH erros\n" #define CONFIG_HLP_CALUER "set UE RX calibration\n" #define CONFIG_HLP_CALUERM "" @@ -87,6 +92,7 @@ extern "C" /* optname helpstr paramflags XXXptr defXXXval type numelt */ /*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ #define RF_CONFIG_FILE softmodem_params.rf_config_file +#define SPLIT73 softmodem_params.split73 #define TP_CONFIG softmodem_params.threadPoolConfig #define PHY_TEST softmodem_params.phy_test #define WAIT_FOR_SYNC softmodem_params.wait_for_sync @@ -103,6 +109,8 @@ extern "C" #define CMDLINE_PARAMS_DESC { \ {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, sizeof(RF_CONFIG_FILE)},\ + {"split73", CONFIG_HLP_SPLIT73, 0, strptr:(char **)&SPLIT73, defstrval:NULL, TYPE_STRING, sizeof(SPLIT73)},\ + {"thread-pool", CONFIG_HLP_TPOOL, 0, strptr:(char **)&TP_CONFIG, defstrval:"n", TYPE_STRING, sizeof(TP_CONFIG)}, \ {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \ {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&USIM_TEST, defintval:0, TYPE_UINT8, 0}, \ {"clock", CONFIG_HLP_CLK, 0, uptr:&CLOCK_SOURCE, defintval:0, TYPE_UINT, 0}, \ @@ -179,6 +187,7 @@ typedef struct { uint64_t optmask; THREAD_STRUCT thread_struct; char rf_config_file[1024]; + char split73[1024]; char threadPoolConfig[1024]; int phy_test; uint8_t usim_test; diff --git a/executables/split_headers.h b/executables/split_headers.h index 3e8fe23b14..54b9930250 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -5,10 +5,11 @@ #include #include -#define CU_IP "127.0.0.1" #define CU_PORT "7878" -#define DU_IP "127.0.0.1" #define DU_PORT "8787" +#define SPLIT73_CU 1 +#define SPLIT73_DU 2 +extern int split73; #define MTU 65536 #define UDP_TIMEOUT 900000L // in micro second (struct timeval, NOT struct timespec) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index 75d572c2fc..15eb5206a1 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -310,7 +310,7 @@ static void TPencode(void * arg) { lte_rate_matching_turbo(hadlsch->RTC[rdata->r], rdata->G, //G hadlsch->w[rdata->r], - hadlsch->e+rdata->r_offset, + hadlsch->eDL+rdata->r_offset, hadlsch->C, // C rdata->dlsch->Nsoft, // Nsoft, rdata->dlsch->Mdlharq, @@ -389,7 +389,7 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, for (int r=0, r_offset=0; rC; r++) { union turboReqUnion id= {.s={dlsch->rnti,frame,subframe,r,0}}; - notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboEncode_t), id.p, &proc->respEncode, TPencode); + notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboEncode_t), id.p, proc->respEncode, TPencode); turboEncode_t * rdata=(turboEncode_t *) NotifiedFifoData(req); rdata->input=hadlsch->c[r]; rdata->Kr_bytes= ( rCminus ? hadlsch->Kminus : hadlsch->Kplus) >>3; @@ -404,8 +404,8 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, rdata->r_offset=r_offset; rdata->G=G; - if ( proc->threadPool.activated) { - pushTpool(&proc->threadPool,req); + if ( proc->threadPool->activated ) { + pushTpool(proc->threadPool,req); proc->nbEncode++; } else { TPencode(rdata); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 04a49d062a..475c8bd521 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -158,7 +158,7 @@ int allocate_REs_in_RB_no_pilots_QPSK_siso(PHY_VARS_eNB* phy_vars_eNB, { LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->frame_parms; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint32_t qpsk_table_offset_re = 0; uint32_t qpsk_table_offset_im = 0; @@ -248,7 +248,7 @@ int allocate_REs_in_RB_pilots_QPSK_siso(PHY_VARS_eNB* phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms=&phy_vars_eNB->frame_parms; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint32_t qpsk_table_offset_re = 0; uint32_t qpsk_table_offset_im = 0; @@ -343,7 +343,7 @@ int allocate_REs_in_RB_no_pilots_16QAM_siso(PHY_VARS_eNB* phy_vars_eNB, { LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->frame_parms; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint32_t qam16_table_offset_re = 0; uint32_t qam16_table_offset_im = 0; @@ -439,7 +439,7 @@ int allocate_REs_in_RB_pilots_16QAM_siso(PHY_VARS_eNB* phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms=&phy_vars_eNB->frame_parms; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint32_t qam16_table_offset_re = 0; uint32_t qam16_table_offset_im = 0; @@ -542,7 +542,7 @@ int allocate_REs_in_RB_no_pilots_64QAM_siso(PHY_VARS_eNB* phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->frame_parms; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint32_t qam64_table_offset_re = 0; uint32_t qam64_table_offset_im = 0; @@ -699,7 +699,7 @@ int allocate_REs_in_RB_pilots_64QAM_siso(PHY_VARS_eNB* phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms=&phy_vars_eNB->frame_parms; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint32_t qam64_table_offset_re = 0; uint32_t qam64_table_offset_im = 0; @@ -866,12 +866,12 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, if ((dlsch0_harq != NULL) && (dlsch1_harq != NULL)) { //this is for TM3, TM4 - x0 = dlsch0_harq->e; + x0 = dlsch0_harq->eDL; mimo_mode = dlsch0_harq->mimo_mode; first_layer0 = dlsch0_harq->first_layer; Nlayers0 = dlsch0_harq->Nlayers; mod_order0 = dlsch0_harq->Qm; - x1 = dlsch1_harq->e; + x1 = dlsch1_harq->eDL; // Fill these in later for TM8-10 // Nlayers1 = dlsch1_harq->Nlayers; // first_layer1 = dlsch1_harq->first_layer; @@ -879,7 +879,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, } else if ((dlsch0_harq != NULL) && (dlsch1_harq == NULL)){ //This is for SIS0 TM1, TM6, etc - x0 = dlsch0_harq->e; + x0 = dlsch0_harq->eDL; mimo_mode = dlsch0_harq->mimo_mode; first_layer0 = dlsch0_harq->first_layer; Nlayers0 = dlsch0_harq->Nlayers; @@ -887,7 +887,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, } else if ((dlsch0_harq == NULL) && (dlsch1_harq != NULL)){ // This is for TM4 retransmission - x0 = dlsch1_harq->e; + x0 = dlsch1_harq->eDL; mimo_mode = dlsch1_harq->mimo_mode; first_layer0 = dlsch1_harq->first_layer; Nlayers0 = dlsch1_harq->Nlayers; @@ -2692,7 +2692,7 @@ int dlsch_modulation_SIC(int32_t **sic_buffer, LTE_DL_eNB_HARQ_t *dlsch0_harq = dlsch0->harq_processes[harq_pid]; uint32_t i,jj,re_allocated=0; uint8_t mod_order0 = dlsch0_harq->Qm; - uint8_t *x0 = dlsch0_harq->e; + uint8_t *x0 = dlsch0_harq->eDL; uint8_t qam64_table_offset_re = 0; uint8_t qam64_table_offset_im = 0; uint8_t qam16_table_offset_re = 0; @@ -2883,7 +2883,7 @@ int mch_modulation(int32_t **txdataF, &jj, re_offset, symbol_offset, - dlsch->harq_processes[0]->e, + dlsch->harq_processes[0]->eDL, l, mod_order, amp, diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c index 2e8ddde848..d48164e07d 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c @@ -52,7 +52,7 @@ void dlsch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, int n; // uint8_t reset; uint32_t x1, x2, s=0; - uint8_t *dlsch_e=dlsch->harq_processes[harq_pid]->e; + uint8_t *dlsch_e=dlsch->harq_processes[harq_pid]->eDL; uint8_t *e=dlsch_e; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_SCRAMBLING, VCD_FUNCTION_IN); // Rule for accumulation of subframes for BL/CE UEs diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h index 7dd4e46da4..5e446db5fd 100644 --- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h +++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h @@ -100,7 +100,7 @@ typedef struct { /// start symbold of pdsch uint8_t pdsch_start; /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) - uint8_t e[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); + uint8_t eDL[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); /// Turbo-code outputs (36-212 V8.6 2009-03, p.12 uint8_t *d[MAX_NUM_DLSCH_SEGMENTS];//[(96+3+(3*6144))]; /// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17) @@ -261,11 +261,11 @@ typedef struct { /// coded RI bits int16_t q_RI[MAX_RI_PAYLOAD]; /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) - int16_t e[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); + int16_t eUL[MAX_NUM_CHANNEL_BITS] __attribute__((aligned(32))); /// Temporary h sequence to flag PUSCH_x/PUSCH_y symbols which are not scrambled uint8_t h[MAX_NUM_CHANNEL_BITS]; /// Pointer to the payload - uint8_t *b; + uint8_t *decodedBytes; /// Pointers to transport block segments //TBD uint8_t *c[MAX_NUM_ULSCH_SEGMENTS]; diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 581f50494f..36a3cd9a5c 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -54,9 +54,9 @@ void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch) { if (ulsch) { for (i=0; i<8; i++) { if (ulsch->harq_processes[i]) { - if (ulsch->harq_processes[i]->b) { - free16(ulsch->harq_processes[i]->b,MAX_ULSCH_PAYLOAD_BYTES); - ulsch->harq_processes[i]->b = NULL; + if (ulsch->harq_processes[i]->decodedBytes) { + free16(ulsch->harq_processes[i]->decodedBytes,MAX_ULSCH_PAYLOAD_BYTES); + ulsch->harq_processes[i]->decodedBytes = NULL; } for (r=0; rharq_processes[i]) { memset(ulsch->harq_processes[i],0,sizeof(LTE_UL_eNB_HARQ_t)); - ulsch->harq_processes[i]->b = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); + ulsch->harq_processes[i]->decodedBytes = (uint8_t *)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); - if (ulsch->harq_processes[i]->b) - memset(ulsch->harq_processes[i]->b,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); + if (ulsch->harq_processes[i]->decodedBytes) + memset(ulsch->harq_processes[i]->decodedBytes,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); else exit_flag=3; @@ -229,7 +229,7 @@ void processULSegment(void * arg) { G, ulsch_harq->w[r], (uint8_t *) &dummy_w[0], - ulsch_harq->e+rdata->r_offset, + ulsch_harq->eUL+rdata->r_offset, ulsch_harq->C, NSOFT, 0, //Uplink @@ -327,19 +327,15 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, E = ulsch_harq->Qm * (Gp/ulsch_harq->C); else E = ulsch_harq->Qm * ((GpmodC==0?0:1) + (Gp/ulsch_harq->C)); -#ifdef FS6 - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { - - sendFs6Ul(eNB, UE_id, harq_pid, r, ulsch_harq->e+r_offset, E*sizeof(int16_t), r_offset); - + + if ( split73 == SPLIT73_DU ) { + sendFs6Ul(eNB, UE_id, harq_pid, r, ulsch_harq->eUL+r_offset, E*sizeof(int16_t), r_offset); r_offset += E; continue; } -#endif - union turboReqUnion id= {.s={ulsch->rnti,proc->frame_rx,proc->subframe_rx,0,0}}; - notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboDecode_t), id.p, &proc->respDecode, processULSegment); + notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboDecode_t), id.p, proc->respDecode, processULSegment); turboDecode_t * rdata=(turboDecode_t *) NotifiedFifoData(req); rdata->eNB=eNB; @@ -359,7 +355,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, rdata->function=td; int Fbytes=(r==0) ? rdata->Fbits>>3 : 0; int sz=Kr_bytes - Fbytes - ((ulsch_harq->C>1)?3:0); - pushTpool(&proc->threadPool,req); + pushTpool(proc->threadPool,req); proc->nbDecode++; LOG_D(PHY,"Added a block to decode, in pipe: %d\n",proc->nbDecode); r_offset+=E; @@ -892,8 +888,8 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB, j2+=2; } - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; } break; @@ -905,10 +901,10 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB, j2+=4; } - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; } break; @@ -920,12 +916,12 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB, j2+=6; } - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; - ulsch_harq->e[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; + ulsch_harq->eUL[iprime++] = y[j2++]; } break; @@ -963,7 +959,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB, */ int16_t *yp,*ep; - for (iprime=0,yp=&y[j2],ep=&ulsch_harq->e[0]; + for (iprime=0,yp=&y[j2],ep=&ulsch_harq->eUL[0]; iprimeharq_processes[harq_pid]->RTC[r], G, //G dlsch->harq_processes[harq_pid]->w[r], - dlsch->harq_processes[harq_pid]->e+r_offset, + dlsch->harq_processes[harq_pid]->eDL+r_offset, dlsch->harq_processes[harq_pid]->C, // C dlsch->Nsoft, // Nsoft, dlsch->Mdlharq, diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 0fabf8c639..e59c651713 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -2032,7 +2032,7 @@ uint16_t nr_dci_format_size (PHY_VARS_NR_UE *ue, ul_res_alloc_type_1 = 1; } - uint8_t n_bits_freq_dom_res_assign_ul=0,n_ul_RGB_tmp; + uint8_t n_bits_freq_dom_res_assign_ul=0,n_ul_RGB_tmp=0; if (ul_res_alloc_type_0 == 1) { // implementation of Table 6.1.2.2.1-1 TC 38.214 subclause 6.1.2.2.1 // config1: PUSCH-Config IE contains rbg-Size ENUMERATED {config1 config2} diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 6e34a71e0c..1ada594725 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -320,10 +320,10 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, &eNB->dlsch_interleaving_stats); stop_meas(&eNB->dlsch_encoding_stats); - if ( proc->threadPool.activated ) { + if ( proc->threadPool->activated ) { // Wait all other threads finish to process while (proc->nbEncode) { - delNotifiedFIFO_elt(pullTpool(&proc->respEncode, &proc->threadPool)); + delNotifiedFIFO_elt(pullTpool(proc->respEncode, proc->threadPool)); proc->nbEncode--; } } @@ -604,12 +604,11 @@ void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { } void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { - #ifdef FS6 - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + if ( split73 == SPLIT73_DU ) { sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, NULL, frame, subframe, NULL,0,0, rnti, stat); return; } - #endif + pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_sr_indication_t *sr_ind = &eNB->UL_INFO.sr_ind; nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body; @@ -1175,13 +1174,13 @@ void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req) { if (decodeSucess) { int Fbytes=(rdata->segment_r==0) ? rdata->Fbits>>3 : 0; int sz=(rdata->Kr>>3) - Fbytes - ((ulsch_harq->C>1)?3:0); - memcpy(ulsch_harq->b+rdata->offset, + memcpy(ulsch_harq->decodedBytes+rdata->offset, rdata->decoded_bytes+Fbytes, sz); } else { if ( rdata->nbSegments != ulsch_harq->processedSegments ) { - int nb=abortTpool(&proc->threadPool, req->key); - nb+=abortNotifiedFIFO(&proc->respDecode, req->key); + int nb=abortTpool(proc->threadPool, req->key); + nb+=abortNotifiedFIFO(proc->respDecode, req->key); proc->nbDecode-=nb; LOG_I(PHY,"uplink segment error %d/%d, aborted %d segments\n",rdata->segment_r,rdata->nbSegments, nb); AssertFatal(ulsch_harq->processedSegments+nb == rdata->nbSegments,"processed: %d, aborted: %d, total %d\n", @@ -1329,7 +1328,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) { } // for (i=0; inbDecode > 0) { - notifiedFIFO_elt_t *req=pullTpool(&proc->respDecode, &proc->threadPool); + notifiedFIFO_elt_t *req=pullTpool(proc->respDecode, proc->threadPool); postDecode(proc, req); delNotifiedFIFO_elt(req); } @@ -1415,7 +1414,7 @@ void fill_rx_indication(PHY_VARS_eNB *eNB, pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation - pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; + pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->decodedBytes; // estimate timing advance for MAC sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check @@ -1749,12 +1748,10 @@ void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_har } void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { - #ifdef FS6 - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) { + if ( split73 == SPLIT73_DU ) { sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, uci, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0); return; } - #endif int UE_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index d8ac505d14..6a12831e2d 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1266,9 +1266,12 @@ int main(int argc, char **argv) { } L1_rxtx_proc_t *proc_eNB = &eNB->proc.L1_proc; - initTpool("n", &proc_eNB->threadPool, true); - initNotifiedFIFO(&proc_eNB->respEncode); - initNotifiedFIFO(&proc_eNB->respDecode); + proc_eNB->threadPool=(tpool_t*)malloc(sizeof(tpool_t)); + proc_eNB->respEncode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + proc_eNB->respDecode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + initTpool("n", proc_eNB->threadPool, true); + initNotifiedFIFO(proc_eNB->respEncode); + initNotifiedFIFO(proc_eNB->respDecode); proc_eNB->frame_tx=0; diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 34237771aa..6c04d6edf7 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -793,9 +793,12 @@ int main(int argc, char **argv) { proc_rxtx_ue->frame_rx = (subframe<4)?(proc_rxtx->frame_tx-1):(proc_rxtx->frame_tx); proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; proc_rxtx_ue->subframe_rx = (proc_rxtx->subframe_tx+6)%10; - initTpool("n", &proc_rxtx->threadPool, true); - initNotifiedFIFO(&proc_rxtx->respEncode); - initNotifiedFIFO(&proc_rxtx->respDecode); + proc_rxtx->threadPool=(tpool_t*)malloc(sizeof(tpool_t)); + proc_rxtx->respEncode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + proc_rxtx->respDecode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + initTpool("n",proc_rxtx->threadPool, true); + initNotifiedFIFO(proc_rxtx->respEncode); + initNotifiedFIFO(proc_rxtx->respDecode); printf("Init UL hopping UE\n"); init_ul_hopping(&UE->frame_parms); diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h index 5bcbc2420d..42a4459732 100644 --- a/openair2/PHY_INTERFACE/IF_Module.h +++ b/openair2/PHY_INTERFACE/IF_Module.h @@ -176,11 +176,11 @@ typedef struct { pthread_cond_t cond_RUs; /// mutex for RXn-TXnp4 processing thread pthread_mutex_t mutex_RUs; - tpool_t threadPool; + tpool_t *threadPool; int nbEncode; int nbDecode; - notifiedFIFO_t respEncode; - notifiedFIFO_t respDecode; + notifiedFIFO_t *respEncode; + notifiedFIFO_t *respDecode; pthread_mutex_t mutex_emulateRF; int instance_cnt_emulateRF; pthread_t pthread_emulateRF; diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index 94f8f2e938..01a78213ca 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -346,7 +346,7 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp if ( t->lastWroteTS != 0 && abs((double)t->lastWroteTS-timestamp) > (double)CirSize) LOG_E(HW,"Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); - if (t->lastWroteTS >= timestamp+1) + if (t->lastWroteTS > timestamp+nsamps) LOG_E(HW,"Not supported to send Tx out of order (same in USRP) %lu, %lu\n", t->lastWroteTS, timestamp); t->lastWroteTS=timestamp+nsamps; @@ -468,8 +468,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi } else if ( b->lastReceivedTS == b->th.timestamp ) { // normal case } else { - abort(); - AssertFatal(false, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); + LOG_E(HW, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); + b->trashingPacket=true; } pthread_mutex_lock(&Sockmutex); diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 1f2e8fa8f1..10691d2db8 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -41,6 +41,7 @@ # include "f1ap_du_task.h" # include "enb_app.h" # include "openair2/LAYER2/MAC/mac_proto.h" +#include extern RAN_CONTEXT_t RC; @@ -50,25 +51,21 @@ int create_tasks(uint32_t enb_nb) { int rc; if (enb_nb == 0) return 0; - bool fs6Du=false; - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) - fs6Du=true; LOG_I(ENB_APP, "Creating ENB_APP eNB Task\n"); rc = itti_create_task (TASK_ENB_APP, eNB_app_task, NULL); AssertFatal(rc >= 0, "Create task for eNB APP failed\n"); - LOG_I(RRC,"Creating RRC eNB Task\n"); - rc = itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL); - AssertFatal(rc >= 0, "Create task for RRC eNB failed\n"); + // No more rrc thread, as many race conditions are hidden behind + rrc_enb_init(); + itti_mark_task_ready(TASK_RRC_ENB); - if (EPC_MODE_ENABLED && !fs6Du ) { + if (EPC_MODE_ENABLED && ! ( split73==SPLIT73_DU ) ) { rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); AssertFatal(rc >= 0, "Create task for SCTP failed\n"); } - - if (EPC_MODE_ENABLED && !NODE_IS_DU(type) && !fs6Du ) { + if (EPC_MODE_ENABLED && !NODE_IS_DU(type) && ! ( split73==SPLIT73_DU ) ) { rc = itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL); AssertFatal(rc >= 0, "Create task for S1AP failed\n"); if (!(get_softmodem_params()->emulate_rf)){ diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 8e85ae11c6..67f9c62256 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -93,6 +93,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "lte-softmodem.h" #include "NB_IoT_interface.h" +#include pthread_cond_t nfapi_sync_cond; @@ -152,6 +153,13 @@ int otg_enabled; uint64_t num_missed_slots=0; // counter for the number of missed slots +int split73=0; +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) { + AssertFatal(false, "Must not be called in this context\n"); +} +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) { + AssertFatal(false, "Must not be called in this context\n"); +} extern void reset_opp_meas(void); extern void print_opp_meas(void); @@ -438,12 +446,9 @@ int restart_L1L2(module_id_t enb_id) { init_UE_list(&RC.mac[enb_id]->UE_list); LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); - if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { - LOG_E(RRC, "Create task for RRC eNB failed\n"); - return -1; - } else { - LOG_I(RRC, "Re-created task for RRC eNB successfully\n"); - } + // No more rrc thread, as many race conditions are hidden behind + rrc_enb_init(); + itti_mark_task_ready(TASK_RRC_ENB); /* pass a reconfiguration request which will configure everything down to * RC.eNB[i][j]->frame_parms, too */ @@ -477,8 +482,7 @@ void init_pdcp(void) { pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_W_MBMS_BIT; - if ( getenv("fs6") != NULL && strncasecmp( getenv("fs6"), "du", 2) == 0 ) - pdcp_module_init(pdcp_initmask); + pdcp_module_init(pdcp_initmask); if (NODE_IS_CU(RC.rrc[0]->node_type)) { pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t)proto_agent_send_rlc_data_req); @@ -643,12 +647,15 @@ int main ( int argc, char **argv ) for (int x=0; x < RC.nb_L1_inst; x++) for (int CC_id=0; CC_idproc.L1_proc; + L1proc->threadPool=(tpool_t*)malloc(sizeof(tpool_t)); + L1proc->respEncode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + L1proc->respDecode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) - initTpool(get_softmodem_params()->threadPoolConfig, &L1proc->threadPool, true); + initTpool(get_softmodem_params()->threadPoolConfig, L1proc->threadPool, true); else - initTpool("n", &L1proc->threadPool, true); - initNotifiedFIFO(&L1proc->respEncode); - initNotifiedFIFO(&L1proc->respDecode); + initTpool("n", L1proc->threadPool, true); + initNotifiedFIFO(L1proc->respEncode); + initNotifiedFIFO(L1proc->respDecode); } From 7ad4efb37a22f469efdd5216fc3ae1c311e8690d Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 2 Mar 2020 17:39:44 +0100 Subject: [PATCH 101/175] fix warnings, reduce formating differences with develop branch --- executables/main-fs6.c | 4 + executables/main-ocp.c | 7 +- executables/nr-gnb.c | 57 +++++++++--- executables/split_headers.h | 4 + executables/transport_split.c | 4 + nfapi/oai_integration/nfapi_vnf.c | 2 +- .../PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c | 4 + .../lte_dl_bf_channel_estimation.c | 92 +++++++++---------- openair1/PHY/LTE_TRANSPORT/if5_tools.c | 2 +- openair1/PHY/LTE_TRANSPORT/phich.c | 2 +- .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 1 - openair1/SCHED/phy_procedures_lte_eNb.c | 3 +- openair1/SCHED/prach_procedures.c | 9 ++ openair1/SCHED/sched_eNB.h | 2 + openair1/SCHED_UE/phy_procedures_lte_ue.c | 2 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 7 +- openair2/RRC/LTE/rrc_eNB.c | 3 + targets/RT/USER/lte-softmodem.h | 1 + 18 files changed, 127 insertions(+), 79 deletions(-) diff --git a/executables/main-fs6.c b/executables/main-fs6.c index c20777a5d6..0a5988c802 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1,3 +1,7 @@ +/* + Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX + copyleft: OpenAirInterface Software Alliance and it's licence +*/ #include #include #include diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 50cd1f2714..0635df2bef 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -1,9 +1,6 @@ /* - * Author: Laurent Thomas - * Copyright: Open Cells Project company - */ - -/* + Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX + copyleft: OpenAirInterface Software Alliance and it's licence * This file replaces * targets/RT/USER/lte-softmodem.c * targets/RT/USER/rt_wrapper.c diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 43407de19b..3a5916c577 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -327,15 +327,16 @@ static void *gNB_L1_thread( void *param ) { while (!oai_exit) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 0 ); - if (wait_on_condition(&L1_proc->mutex,&L1_proc->cond,&L1_proc->instance_cnt,thread_name)<0) break; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 1 ); + int frame_rx = L1_proc->frame_rx; int slot_rx = L1_proc->slot_rx; int frame_tx = L1_proc->frame_tx; int slot_tx = L1_proc->slot_tx; uint64_t timestamp_tx = L1_proc->timestamp_tx; + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX0_GNB,slot_tx); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_RX0_GNB,slot_rx); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_GNB,frame_tx); @@ -407,15 +408,17 @@ void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, char *string, struct } int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot_tx,uint64_t timestamp_tx) { + RU_t *ru; RU_proc_t *ru_proc; + int waitret = 0, ret = 0, time_ns = 1000*1000; struct timespec now, abstime; // note this should depend on the numerology used by the TX L1 thread, set here for 500us slot time + // note this should depend on the numerology used by the TX L1 thread, set here for 500us slot time VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL,1); time_ns = time_ns/gNB->frame_parms.slots_per_subframe; AssertFatal((ret = pthread_mutex_lock(&proc->mutex_RUs_tx))==0,"mutex_lock returns %d\n",ret); - while (proc->instance_cnt_RUs < 0) { clock_gettime(CLOCK_REALTIME, &now); abstime.tv_sec = now.tv_sec; @@ -425,10 +428,8 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot abstime.tv_nsec -= 1000*1000*1000; abstime.tv_sec += 1; } - if((waitret = pthread_cond_timedwait(&proc->cond_RUs,&proc->mutex_RUs_tx,&abstime)) == 0) break; // this unlocks mutex_rxtx while waiting and then locks it again } - proc->instance_cnt_RUs = -1; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); AssertFatal((ret = pthread_mutex_unlock(&proc->mutex_RUs_tx))==0,"mutex_unlock returns %d\n",ret); @@ -436,6 +437,7 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot if (waitret == ETIMEDOUT) { LOG_W(PHY,"Dropping TX slot (%d.%d) because FH is blocked more than 1 slot times (500us)\n",frame_tx,slot_tx); + AssertFatal((ret=pthread_mutex_lock(&gNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); gNB->proc.RU_mask_tx = 0; AssertFatal((ret=pthread_mutex_unlock(&gNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); @@ -443,61 +445,81 @@ int wakeup_txfh(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc,int frame_tx,int slot proc->instance_cnt_RUs = 0; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RUs_tx))==0,"mutex_unlock returns %d\n",ret); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,1); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE,0); + return(-1); } - for(int i=0; inum_RU; i++) { + for(int i=0; inum_RU; i++) + { ru = gNB->RU_list[i]; ru_proc = &ru->proc; + if (ru_proc->instance_cnt_gNBs == 0) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE, 1); LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->tti_tx, proc->frame_rx, proc->slot_rx); AssertFatal((ret=pthread_mutex_lock(&gNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); gNB->proc.RU_mask_tx = 0; AssertFatal((ret=pthread_mutex_unlock(&gNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST_UE, 0); return(-1); } - AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_gNBs))==0,"ERROR pthread_mutex_lock failed on mutex_gNBs L1_thread_tx with ret=%d\n",ret); + ru_proc->instance_cnt_gNBs = 0; ru_proc->timestamp_tx = timestamp_tx; ru_proc->tti_tx = slot_tx; ru_proc->frame_tx = frame_tx; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_UE, ru_proc->instance_cnt_gNBs); + LOG_D(PHY,"Signaling tx_thread_fh for %d.%d\n",frame_tx,slot_tx); // the thread can now be woken up AssertFatal(pthread_cond_signal(&ru_proc->cond_gNBs) == 0, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); AssertFatal((ret=pthread_mutex_unlock(&ru_proc->mutex_gNBs))==0,"mutex_unlock returned %d\n",ret); - } + } return(0); } int wakeup_tx(PHY_VARS_gNB *gNB,int frame_rx,int slot_rx,int frame_tx,int slot_tx,uint64_t timestamp_tx) { + + gNB_L1_rxtx_proc_t *L1_proc_tx = &gNB->proc.L1_proc_tx; + int ret; + + AssertFatal((ret = pthread_mutex_lock(&L1_proc_tx->mutex))==0,"mutex_lock returns %d\n",ret); + while(L1_proc_tx->instance_cnt == 0) { pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex); } L1_proc_tx->instance_cnt = 0; + + L1_proc_tx->slot_rx = slot_rx; L1_proc_tx->frame_rx = frame_rx; L1_proc_tx->slot_tx = slot_tx; L1_proc_tx->frame_tx = frame_tx; L1_proc_tx->timestamp_tx = timestamp_tx; + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_UE,1); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_UE,0); // the thread can now be woken up + // the thread can now be woken up AssertFatal(pthread_cond_signal(&L1_proc_tx->cond) == 0, "ERROR pthread_cond_signal for gNB L1 thread\n"); + AssertFatal((ret=pthread_mutex_unlock(&L1_proc_tx->mutex))==0,"mutex_unlock returns %d\n",ret); + return(0); } @@ -510,23 +532,22 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { int i; struct timespec abstime; int time_ns = 50000; + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RU))==0,"mutex_lock returns %d\n",ret); - for (i=0; inum_RU; i++) { if (ru == gNB->RU_list[i]) { if ((proc->RU_mask&(1< 0) LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", gNB->Mod_id,proc->frame_rx,proc->slot_rx,ru->idx,gNB->num_RU,proc->RU_mask); - proc->RU_mask |= (1<RU_mask != (1<num_RU)-1) { // not all RUs have provided their information so return LOG_E(PHY,"Not all RUs have provided their info\n"); AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU))==0,"mutex_unlock returns %d\n",ret); return(0); - } else { // all RUs have provided their information so continue on and wakeup gNB processing + } + else { // all RUs have provided their information so continue on and wakeup gNB processing proc->RU_mask = 0; AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU))==0,"muex_unlock returns %d\n",ret); } @@ -556,12 +577,15 @@ int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, // we want to generate subframe (n+sl_ahead), so TS_tx = TX_rx+sl_ahead*samples_per_tti, // and proc->slot_tx = proc->slot_rx+sl_ahead + // and proc->slot_tx = proc->slot_rx+sl_ahead L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot); L1_proc->frame_rx = ru_proc->frame_rx; L1_proc->slot_rx = ru_proc->tti_rx; L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame; + LOG_D(PHY,"wakeupL1: passing parameter IC = %d, RX: %d.%d, TX: %d.%d to L1 sl_ahead = %d\n", L1_proc->instance_cnt, L1_proc->frame_rx, L1_proc->slot_rx, L1_proc->frame_tx, L1_proc->slot_tx, sl_ahead); + pthread_mutex_unlock( &L1_proc->mutex ); // the thread can now be woken up @@ -675,19 +699,22 @@ extern void init_td_thread(PHY_VARS_gNB *); extern void init_te_thread(PHY_VARS_gNB *); static void *process_stats_thread(void *param) { + PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param; + reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->dlsch_scrambling_stats); reset_meas(&gNB->dlsch_modulation_stats); + wait_sync("process_stats_thread"); - while(!oai_exit) { + while(!oai_exit) + { sleep(1); print_meas(&gNB->dlsch_encoding_stats, "pdsch_encoding", NULL, NULL); print_meas(&gNB->dlsch_scrambling_stats, "pdsch_scrambling", NULL, NULL); print_meas(&gNB->dlsch_modulation_stats, "pdsch_modulation", NULL, NULL); } - return(NULL); } @@ -740,7 +767,6 @@ void init_gNB_proc(int inst) { } if(opp_enabled == 1) threadCreate(&proc->L1_stats_thread, process_stats_thread,(void *)gNB, "time_meas", -1, OAI_PRIORITY_RT_LOW); - //pthread_create( &proc->pthread_prach, attr_prach, gNB_thread_prach, gNB ); char name[16]; @@ -942,6 +968,7 @@ void init_gNB(int single_thread_flag,int wait_for_sync) { gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list; gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list; gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list; + gNB->prach_energy_counter = 0; } } diff --git a/executables/split_headers.h b/executables/split_headers.h index 54b9930250..62293c7369 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -1,3 +1,7 @@ +/* + Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX + copyleft: OpenAirInterface Software Alliance and it's licence +*/ #ifndef __SPLIT_HEADERS_H #define __SPLIT_HEADERS_H diff --git a/executables/transport_split.c b/executables/transport_split.c index 1ed95db7a0..7a1ee3e85e 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -1,3 +1,7 @@ +/* + Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX + copyleft: OpenAirInterface Software Alliance and it's licence +*/ #include #include /* See NOTES */ #include diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index c1f69574fd..a0574221f5 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -398,7 +398,7 @@ int phy_sync_indication(struct nfapi_vnf_p7_config *config, uint8_t sync) { return(0); } -int phy_subframe_indication(L1_rxtx_proc_t * proc, struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn_sf) { +int phy_subframe_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn_sf) { static uint8_t first_time = 1; if (first_time) { diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c index 294169b75d..04fe19ecbc 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c @@ -148,5 +148,9 @@ int lte_est_timing_advance_pusch(PHY_VARS_eNB *eNB, if (max_pos>frame_parms->ofdm_symbol_size/2) max_pos = max_pos-frame_parms->ofdm_symbol_size; + //#ifdef DEBUG_PHY + LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); + //#endif //DEBUG_PHY + return max_pos - sync_pos; } diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 43c0350efb..2331e253d5 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -43,7 +43,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, uint8_t pilot0,pilot1,pilot2,pilot3; short ch[2], *pil, *rxF, *dl_bf_ch, *dl_bf_ch_prev; - short *fl, *fm, *fr, *fl_dc, *fm_dc, *fr_dc, *f1, *f2l, *f2r; + short *fl=NULL, *fm=NULL, *fr=NULL, *fl_dc=NULL, *fm_dc=NULL, *fr_dc=NULL, *f1, *f2l=NULL, *f2r=NULL; unsigned int *rballoc; int **rxdataF; @@ -58,10 +58,10 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; if (((frame_parms->Ncp == NORMAL) && (symbol>=7)) || - ((frame_parms->Ncp == EXTENDED) && (symbol>=6))) - rballoc = dlsch0_harq->rb_alloc_odd; + ((frame_parms->Ncp == EXTENDED) && (symbol>=6))) + rballoc = dlsch0_harq->rb_alloc_odd; else - rballoc = dlsch0_harq->rb_alloc_even; + rballoc = dlsch0_harq->rb_alloc_even; rxdataF = phy_vars_ue->common_vars.common_vars_rx_data_per_thread[phy_vars_ue->current_thread_id[Ns>>1]].rxdataF; @@ -69,56 +69,56 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, beamforming_mode = phy_vars_ue->transmission_mode[eNB_id]>6 ? phy_vars_ue->transmission_mode[eNB_id] : 0; if (phy_vars_ue->high_speed_flag == 0) // use second channel estimate position for temporary storage - ch_offset = frame_parms->ofdm_symbol_size; + ch_offset = frame_parms->ofdm_symbol_size; else - ch_offset = frame_parms->ofdm_symbol_size*symbol; + ch_offset = frame_parms->ofdm_symbol_size*symbol; + - uespec_nushift = frame_parms->Nid_cell%3; subframe = Ns>>1; - - //generate ue specific pilots - lprime = symbol/3-1; - lte_dl_ue_spec_rx(phy_vars_ue,uespec_pilot,Ns,5,lprime,0,dlsch0_harq->nb_rb); - //LOG_M("uespec_pilot_rx.m","uespec_pilot",uespec_pilot,300,1,1); - if (frame_parms->Ncp==0){ - if (symbol==3 || symbol==6 || symbol==9 || symbol==12) - uespec_pilots = 1; - } else{ - if (symbol==4 || symbol==7 || symbol==10) - uespec_pilots = 1; - } - - if ((frame_parms->Ncp==0 && (symbol==6 ||symbol ==12)) || (frame_parms->Ncp==1 && symbol==7)) - uespec_poffset = 2; + //generate ue specific pilots + lprime = symbol/3-1; + lte_dl_ue_spec_rx(phy_vars_ue,uespec_pilot,Ns,5,lprime,0,dlsch0_harq->nb_rb); + //LOG_M("uespec_pilot_rx.m","uespec_pilot",uespec_pilot,300,1,1); - if (phy_vars_ue->frame_parms.Ncp == 0) { // normal prefix - pilot0 = 3; - pilot1 = 6; - pilot2 = 9; - pilot3 = 12; - } else { // extended prefix - pilot0 = 4; - pilot1 = 7; - pilot2 = 10; - } + if (frame_parms->Ncp==0){ + if (symbol==3 || symbol==6 || symbol==9 || symbol==12) + uespec_pilots = 1; + } else{ + if (symbol==4 || symbol==7 || symbol==10) + uespec_pilots = 1; + } - //define the filter - pil_offset = (uespec_nushift+uespec_poffset)%3; - // printf("symbol=%d,pil_offset=%d\n",symbol,pil_offset); - switch (pil_offset) { - case 0: - fl = filt16_l0; - fm = filt16_m0; - fr = filt16_r0; - fl_dc = filt16_l0; - fm_dc = filt16_m0; - fr_dc = filt16_r0; - f1 = filt16_1; - f2l = filt16_2l0; - f2r = filt16_2r0; + if ((frame_parms->Ncp==0 && (symbol==6 ||symbol ==12)) || (frame_parms->Ncp==1 && symbol==7)) + uespec_poffset = 2; + + if (phy_vars_ue->frame_parms.Ncp == 0) { // normal prefix + pilot0 = 3; + pilot1 = 6; + pilot2 = 9; + pilot3 = 12; + } else { // extended prefix + pilot0 = 4; + pilot1 = 7; + pilot2 = 10; + } + + //define the filter + pil_offset = (uespec_nushift+uespec_poffset)%3; + // printf("symbol=%d,pil_offset=%d\n",symbol,pil_offset); + switch (pil_offset) { + case 0: + fl = filt16_l0; + fm = filt16_m0; + fr = filt16_r0; + fl_dc = filt16_l0; + fm_dc = filt16_m0; + fr_dc = filt16_r0; + f1 = filt16_1; + f2l = filt16_2l0; + f2r = filt16_2r0; break; case 1: diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index 0e383fa04f..1e0dd9db1b 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -1504,7 +1504,7 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 rxp[0] = (void*)&ru->common.rxdata[0][subframe*ru->frame_parms->samples_per_tti]; rxp128 = (__m128i *) (rxp[0]); - RU_proc_t *proc = NULL; //&ru->eNB_list[0]->proc.L1_proc; + RU_proc_t *proc = &ru->proc; /* // while(packet_idsamples_per_tti/db_fulllength) { data_block = data_block_head; diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index ab2fe2d743..6d8b58818b 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -714,7 +714,7 @@ void generate_phich_top(PHY_VARS_eNB *eNB, int32_t **txdataF = eNB->common_vars.txdataF; uint8_t Ngroup_PHICH,ngroup_PHICH,nseq_PHICH; uint8_t NSF_PHICH = 4; - uint8_t pusch_subframe; + uint8_t pusch_subframe=-1; uint8_t i; int subframe = proc->subframe_tx; phich_config_t *phich; diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 9351cf0adc..1b0d7feaf5 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1199,7 +1199,6 @@ void dump_ulsch(PHY_VARS_eNB *eNB,int frame,int subframe,uint8_t UE_id,int round eNB->ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch); sprintf(fname,"/tmp/ulsch_r%d_d",round); sprintf(vname,"/tmp/ulsch_r%d_dseq",round); - LOG_UM(fname,vname,&eNB->ulsch[UE_id]->harq_processes[harq_pid]->d[0][96], eNB->ulsch[UE_id]->harq_processes[harq_pid]->Kplus*3,1,0); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 1ada594725..daa9039236 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -175,7 +175,7 @@ void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int **txdataF = eNB->common_vars.txdataF; uint8_t *pbch_pdu=&eNB->pbch_pdu[0]; - LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?"); + //LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?"); // generate Cell-Specific Reference Signals for both slots VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1); @@ -291,7 +291,6 @@ bool dlsch_procedures(PHY_VARS_eNB *eNB, if (dlsch->rnti!=0xffff) LOG_D(PHY,"Generating DLSCH/PDSCH pdu:%p pdsch_start:%d frame:%d subframe:%d nb_rb:%d rb_alloc:%d Qm:%d Nl:%d round:%d\n", - dlsch_harq->pdu,dlsch_harq->pdsch_start,frame,subframe,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0], dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round); diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index 4f2d05ef50..f1e7589a66 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -108,6 +108,15 @@ void prach_procedures(PHY_VARS_eNB *eNB, eNB->prach_energy_counter, eNB->measurements.prach_I0+eNB->prach_DTX_threshold, eNB->measurements.prach_I0); + if (max_preamble_energy[0] > 100 && br_flag==0) + LOG_W(PHY,"[RAPROC] Frame %d, subframe %d : BR %d Most likely preamble %d, energy %d dB delay %d (prach_energy counter %d), threshold %d, I0 %d\n", + frame,subframe,br_flag, + max_preamble[0], + max_preamble_energy[0]/10, + max_preamble_delay[0], + eNB->prach_energy_counter, + eNB->measurements.prach_I0+eNB->prach_DTX_threshold, + eNB->measurements.prach_I0); if (br_flag==1) { int prach_mask; diff --git a/openair1/SCHED/sched_eNB.h b/openair1/SCHED/sched_eNB.h index da0106226e..f04bec2e5c 100644 --- a/openair1/SCHED/sched_eNB.h +++ b/openair1/SCHED/sched_eNB.h @@ -127,9 +127,11 @@ void phy_procedures_eNB_S_RX(PHY_VARS_eNB *phy_vars_eNB,L1_rxtx_proc_t *proc); @param phy_vars_eNB Pointer to eNB variables on which to act @param br_flag indicator for eMTC PRACH */ + void prach_procedures(PHY_VARS_eNB *eNB, int br_flag); + /*! \brief Function to compute timing of Msg3 transmission on UL-SCH (first UE transmission in RA procedure). This implements the timing in paragraph a) from Section 6.1.1 in 36.213 (p. 17 in version 8.6). Used by eNB upon transmission of random-access response (RA_RNTI) to program corresponding ULSCH reception procedure. Used by UE upon reception of random-access response (RA_RNTI) to program corresponding ULSCH transmission procedure. This does not support the UL_delay field in RAR (always assumed to be 0). @param frame_parms Pointer to DL frame parameter descriptor @param current_subframe Index of subframe where RA_RNTI was received diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index c64a8ef177..8ca533c146 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -3467,7 +3467,7 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, frame_rx%1024, subframe_rx,(ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]].p_time)/(cpuf*1000.0)); } - LOG_D(PHY," ------ end turbo decoder for AbsSubframe %d.%d ------ iter %d \n", frame_rx, subframe_rx,ret1); + LOG_D(PHY," ------ end turbo decoder for AbsSubframe %d.%d ------ \n", frame_rx, subframe_rx); // Check CRC for CW 0 if (ret == (1+dlsch0->max_turbo_iterations)) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 4aef7ce771..5189e76975 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -4982,12 +4982,7 @@ cqi_indication(module_id_t mod_idP, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); -/* - int sum=0; - for (int i=0; i length; i++) - sum+=pdu[i]; - LOG_D(MAC, "pdu for channel: %d, checksum: %d\n", ul_cqi_information->channel, sum); -*/ + if (ul_cqi_information->channel == 0) { // PUCCH // extract pucch csi information before changing RI information extract_pucch_csi(mod_idP, diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index b77ac07729..baf4d82465 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -8604,6 +8604,8 @@ void *rrc_enb_process_itti_msg(void *notUsed) { return NULL; } +// as there are race conditions, no rrc thread +#if 0 //----------------------------------------------------------------------------- void * rrc_enb_task( @@ -8620,6 +8622,7 @@ rrc_enb_task( //} return NULL; } +#endif /*------------------------------------------------------------------------------*/ void diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index b67a54e4a0..7b896b2817 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -135,6 +135,7 @@ #define DEFAULT_DLF 2680000000 + uint64_t get_pdcp_optmask(void); extern pthread_cond_t sync_cond; extern pthread_mutex_t sync_mutex; From 44167f0119ac175d4ae3c4409cdd93cad8d573c3 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 2 Mar 2020 19:15:44 +0100 Subject: [PATCH 102/175] Fix phy simulators --- openair1/SIMULATION/LTE_PHY/dlsim.c | 16 ++++++++++++---- openair1/SIMULATION/LTE_PHY/ulsim.c | 9 +++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 6a12831e2d..f65e1f9633 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -59,6 +59,7 @@ #include "unitary_defs.h" #include "dummy_functions.c" #include "executables/thread-common.h" +#include "executables/split_headers.h" void feptx_ofdm(RU_t *ru, int frame, int subframe); void feptx_prec(RU_t *ru, int frame, int subframe); @@ -78,6 +79,13 @@ int n_tx_dropped = 0; /*!< \brief initial max process time for tx */ int n_rx_dropped = 0; /*!< \brief initial max process time for rx */ int emulate_rf = 0; +int split73=0; +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) { + AssertFatal(false, "Must not be called in this context\n"); +} +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) { + AssertFatal(false, "Must not be called in this context\n"); +} void handler(int sig) { void *array[10]; @@ -1590,11 +1598,11 @@ int main(int argc, char **argv) { subframe<<1); for (i=0; idlsch[0][0]->harq_processes[0]->e[i]==1 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] > 0)|| - (eNB->dlsch[0][0]->harq_processes[0]->e[i]==0 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] < 0)) { + if ((eNB->dlsch[0][0]->harq_processes[0]->eDL[i]==1 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] > 0)|| + (eNB->dlsch[0][0]->harq_processes[0]->eDL[i]==0 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] < 0)) { uncoded_ber_bit[bit_errors++] = 1; printf("error in pos %d : %d => %d\n",i, - eNB->dlsch[0][0]->harq_processes[0]->e[i], + eNB->dlsch[0][0]->harq_processes[0]->eDL[i], UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i]); } else { /* @@ -1641,7 +1649,7 @@ int main(int argc, char **argv) { //pdsch_vars printf("coded_bits_per_codeword %u\n",coded_bits_per_codeword); dump_dlsch2(UE,eNB_id,subframe,&coded_bits_per_codeword,round, UE->dlsch[UE->current_thread_id[subframe]][0][0]->current_harq_pid); - LOG_M("dlsch_e.m","e",eNB->dlsch[0][0]->harq_processes[0]->e,coded_bits_per_codeword,1,4); + LOG_M("dlsch_e.m","e",eNB->dlsch[0][0]->harq_processes[0]->eDL,coded_bits_per_codeword,1,4); //pdcch_vars LOG_M("pdcchF0_ext.m","pdcchF_ext", UE->pdcch_vars[0][eNB_id]->rxdataF_ext[0],2*3*UE->frame_parms.ofdm_symbol_size,1,1); LOG_M("pdcch00_ch0_ext.m","pdcch00_ch0_ext",UE->pdcch_vars[0][eNB_id]->dl_ch_estimates_ext[0],300*3,1,1); diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 6c04d6edf7..064066801d 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -54,6 +54,7 @@ #include "common/config/config_load_configmodule.h" #include "executables/thread-common.h" #include "targets/RT/USER/lte-softmodem.h" +#include "executables/split_headers.h" double cpuf; #define inMicroS(a) (((double)(a))/(cpu_freq_GHz*1000.0)) @@ -81,6 +82,14 @@ int n_tx_dropped = 0; /*!< \brief initial max process time for tx */ int n_rx_dropped = 0; /*!< \brief initial max process time for rx */ +int split73=0; +void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) { + AssertFatal(false, "Must not be called in this context\n"); +} +void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) { + AssertFatal(false, "Must not be called in this context\n"); +} + extern void fep_full(RU_t *ru, int subframe); extern void ru_fep_full_2thread(RU_t *ru, int subframe); //extern void eNB_fep_full(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc); From 9afdaf02444106dd8855554a1f9227a3aa84faf9 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Wed, 4 Mar 2020 15:13:07 +0100 Subject: [PATCH 103/175] pushing for debugging --- ci-scripts/constants.py | 2 +- ci-scripts/epc.py | 15 +- ci-scripts/html.py | 528 ++++++ ci-scripts/main_enb.py | 1582 +++-------------- ci-scripts/ran.py | 376 +++- ci-scripts/sshconnection.py | 5 +- .../enb_usrp210_band13_test_10mhz_tm1.xml | 2 +- .../x2ho_enb_usrp210_band13_simple_test.xml | 189 ++ 8 files changed, 1352 insertions(+), 1347 deletions(-) create mode 100644 ci-scripts/html.py create mode 100644 ci-scripts/xml_files/x2ho_enb_usrp210_band13_simple_test.xml diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py index f07fd81b43..65fca7193b 100644 --- a/ci-scripts/constants.py +++ b/ci-scripts/constants.py @@ -56,6 +56,7 @@ OAI_UE_PROCESS_COULD_NOT_SYNC = -21 OAI_UE_PROCESS_ASSERTION = -22 OAI_UE_PROCESS_FAILED = -23 OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 +OAI_UE_PROCESS_SEG_FAULT = -25 OAI_UE_PROCESS_OK = +6 UE_STATUS_DETACHED = 0 @@ -68,4 +69,3 @@ X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 - diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 91d722a72f..4f283f530e 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -6,6 +6,8 @@ import re # reg import logging import os import time +import signal + from multiprocessing import Process, Lock, SimpleQueue #----------------------------------------------------------- @@ -49,23 +51,22 @@ class EPCManagement(): def GetType(self): return self.EPCType def Set_PcapFileName(self, pcapfn): - self.PcapFileName = pcapfn + self.EPC_PcapFileName = pcapfn def Get_PcapFileName(self): - return self.PcapFileName + return self.EPC_PcapFileName def InitializeHSS(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': HELP.GenericHelp(Version) HELP.EPCSrvHelp(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath, self.EPCType) sys.exit('Insufficient EPC Parameters') - #mySSH = SSH() mySSH = SSH.SSHConnection() mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') mySSH.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') - EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' + self.EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + self.EPC_PcapFileName, '\$', 5) mySSH.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) @@ -85,7 +86,8 @@ class EPCManagement(): mySSH.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) mySSH.command('cd /opt/hss_sim0609', '\$', 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + #mySSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo su -c "screen -dm -S simulated_hss ./starthss"', '\$', 5) else: logging.error('This option should not occur!') mySSH.close() @@ -248,7 +250,8 @@ class EPCManagement(): mySSH.command('cd scripts', '\$', 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) time.sleep(1) - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) + #mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo killall hss_sim', '\$', 5) else: logging.error('This should not happen!') mySSH.close() diff --git a/ci-scripts/html.py b/ci-scripts/html.py new file mode 100644 index 0000000000..80ad46f51e --- /dev/null +++ b/ci-scripts/html.py @@ -0,0 +1,528 @@ + +#----------------------------------------------------------- +# Import +#----------------------------------------------------------- +import sys # arg +import re # reg +import logging +import os +import time +import subprocess +from multiprocessing import Process, Lock, SimpleQueue + +#----------------------------------------------------------- +# OAI Testing modules +#----------------------------------------------------------- +#import main_enb +#MAIN = main_enb.OaiCiTest() + + +#----------------------------------------------------------- +# Class Declaration +#----------------------------------------------------------- +class HTMLManagement(): + def __init__(self): + # self.FailReportCnt = 0 + # self.prematureExit = False + self.ranRepository = '' + self.ranBranch = '' + self.ranAllowMerge = False + self.ranCommitID = '' + self.ranTargetBranch = '' + #self.eNBIPAddress = '' + #self.eNBUserName = '' + #self.eNBPassword = '' + #self.eNBSourceCodePath = '' + #self.eNB1IPAddress = '' + #self.eNB1UserName = '' + #self.eNB1Password = '' + #self.eNB1SourceCodePath = '' + #self.eNB2IPAddress = '' + #self.eNB2UserName = '' + #self.eNB2Password = '' + #self.eNB2SourceCodePath = '' + #self.ADBIPAddress = '' + #self.ADBUserName = '' + #self.ADBPassword = '' + #self.ADBCentralized = True + #self.testCase_id = '' + self.testXMLfiles = [] + self.nbTestXMLfiles = 0 + #self.desc = '' + #self.Build_eNB_args = '' + #self.backgroundBuild = False + #self.backgroundBuildTestId = ['', '', ''] + #self.Build_eNB_forced_workspace_cleanup = False + #self.Initialize_eNB_args = '' + #self.air_interface = 'lte' + #self.eNB_instance = '' + #self.eNB_serverId = '' + #self.eNBLogFiles = ['', '', ''] + #self.eNBOptions = ['', '', ''] + #self.eNBmbmsEnables = [False, False, False] + #self.eNBstatuses = [-1, -1, -1] + #self.ping_args = '' + #self.ping_packetloss_threshold = '' + #self.iperf_args = '' + #self.iperf_packetloss_threshold = '' + #self.iperf_profile = '' + #self.iperf_options = '' + #self.nbMaxUEtoAttach = -1 + #self.UEDevices = [] + #self.UEDevicesStatus = [] + #self.UEDevicesRemoteServer = [] + #self.UEDevicesRemoteUser = [] + #self.UEDevicesOffCmd = [] + #self.UEDevicesOnCmd = [] + #self.UEDevicesRebootCmd = [] + #self.CatMDevices = [] + #self.UEIPAddresses = [] + self.htmlFile = '' + self.htmlHeaderCreated = False + self.htmlFooterCreated = False + self.htmlUEConnected = -1 + self.htmlNb_Smartphones = 0 + self.htmlNb_CATM_Modules = 0 + self.htmleNBFailureMsg = '' + self.htmlUEFailureMsg = '' + #self.picocom_closure = False + #self.idle_sleep_time = 0 + #self.x2_ho_options = 'network' + #self.x2NbENBs = 0 + #self.x2ENBBsIds = [] + #self.x2ENBConnectedUEs = [] + self.htmlTabRefs = [] + self.htmlTabNames = [] + self.htmlTabIcons = [] + #self.repeatCounts = [] + #self.finalStatus = False + #self.OsVersion = '' + #self.KernelVersion = '' + #self.UhdVersion = '' + #self.UsrpBoard = '' + #self.CpuNb = '' + #self.CpuModel = '' + #self.CpuMHz = '' + #self.UEIPAddress = '' + #self.UEUserName = '' + #self.UEPassword = '' + #self.UE_instance = '' + #self.UESourceCodePath = '' + #self.UELogFile = '' + #self.Build_OAI_UE_args = '' + #self.Initialize_OAI_UE_args = '' + #self.clean_repository = True + #self.flexranCtrlInstalled = False + #self.flexranCtrlStarted = False + #self.expectedNbOfConnectedUEs = 0 + #self.startTime = 0 + + +#----------------------------------------------------------- +# HTML Reporting.... +#----------------------------------------------------------- + + def Setdesc(self, dsc): + self.desc = dsc + + def SetstartTime(self, sttime): + self.startTime = sttime + + def SettestCase_id(self, tcid): + self.testCase_id = tcid + + + def SetranRepository(self, repository): + self.ranRepository = repository + def GetranRepository(self): + return self.ranRepository + + def SetranAllowMerge(self, merge): + self.ranAllowMerge = merge + def GetranAllowMerge(self): + return self.ranAllowMerge + + + def SetranBranch(self, branch): + self.ranBranch = branch + def GetranBranch(self): + return self.ranBranch + + def SetranCommitID(self, commitid): + self.ranCommitID = commitid + def GetranCommitID(self): + return self.ranCommitID + + def SetranTargetBranch(self, tbranch): + self.ranTargetBranch = tbranch + def GetranTargetBranch(self): + return self.ranTargetBranch + +# def SetADBIPAddress(self, adbip): +# self.ADBIPAddress = adbip +# def GetADBIPAddress(self): +# return self.ADBIPAddress + + def SethtmlUEConnected(self, nbUEs): + self.htmlUEConnected = nbUEs + + def SethtmlNb_Smartphones(self, nbUEs): + self.htmlNb_Smartphones = nbUEs + + def SethtmlNb_CATM_Modules(self, nbUEs): + self.htmlNb_CATM_Modules = nbUEs + + def SetnbTestXMLfiles(self, nb): + self.nbTestXMLfiles = nb + + def SettestXMLfiles(self, xmlFile): + self.testXMLfiles.append(xmlFile) + + def SethtmlTabRefs(self, tabRef): + self.htmlTabRefs.append(tabRef) + + def SethtmlTabNames(self, tabName): + self.htmlTabNames.append(tabName) + + def SethtmlTabIcons(self, tabIcon): + self.htmlTabIcons.append(tabIcon) + + def CreateHtmlHeader(self, ADBIPAddress): + if (not self.htmlHeaderCreated): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML header \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + self.htmlFile = open('test_results.html', 'w') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write('\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') + self.htmlFile.write('\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if self.ranAllowMerge != '': + commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + self.ranCommitID, shell=True, universal_newlines=True) + commit_message = commit_message.strip() + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranAllowMerge): + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if (self.ranTargetBranch == ''): + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + self.ranRepository + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + self.ranBranch + '
Source Commit ID Commit ID ' + self.ranCommitID + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + self.ranTargetBranch + '
\n') + + if (ADBIPAddress != 'none'): + #terminate_ue_flag = True + #MAIN.GetAllUEDevices(terminate_ue_flag) + #self.GetAllCatMDevices(terminate_ue_flag) + #self.htmlUEConnected = len(self.UEDevices) + self.htmlFile.write('

' + str(self.htmlNb_Smartphones) + ' UE(s) is(are) connected to ADB bench server

\n') + self.htmlFile.write('

' + str(self.htmlNb_CATM_Modules) + ' CAT-M UE(s) is(are) connected to bench server

\n') + else: + #self.UEDevices.append('OAI-UE') + #self.htmlUEConnected = len(self.UEDevices) + self.htmlUEConnected = 1 + self.htmlFile.write('

1 OAI UE(s) is(are) connected to CI bench

\n') + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write('
\n') + self.htmlFile.close() + + def CreateHtmlTabHeader(self): + if (not self.htmlHeaderCreated): + if (not os.path.isfile('test_results.html')): + self.CreateHtmlHeader('none') + self.htmlFile = open('test_results.html', 'a') + if (self.nbTestXMLfiles == 1): + self.htmlFile.write('
\n') + self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') + else: + self.htmlFile.write('
\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + #if (self.htmlUEConnected == -1): + # terminate_ue_flag = True + # if (self.ADBIPAddress != 'none'): + # self.GetAllUEDevices(terminate_ue_flag) + # self.GetAllCatMDevices(terminate_ue_flag) + # else: + # self.UEDevices.append('OAI-UE') + # self.htmlUEConnected = len(self.UEDevices) + + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' \n') + i += 1 + self.htmlFile.write(' \n') + self.htmlFile.close() + self.htmlHeaderCreated = True + + def CreateHtmlTabFooter(self, passStatus): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile = open('test_results.html', 'a') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') + self.htmlFile.write('
\n') + self.htmlFile.close() + time.sleep(1) + if passStatus: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" + subprocess.run(cmd, shell=True) + else: + cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" + subprocess.run(cmd, shell=True) + self.htmlFooterCreated = False + + def CreateHtmlFooter(self, passStatus): + if (os.path.isfile('test_results.html')): + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML footer \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + + self.htmlFile = open('test_results.html', 'a') + self.htmlFile.write('
\n') + self.htmlFile.write('

\n') + self.htmlFile.write(' \n') + + machines = [ 'eNB', 'UE' ] + for machine in machines: + #This needs to move back to main and be called before CreateHtmlFooter + res = self.RetrieveSystemVersion(machine) + if res == -1: + continue + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + if passStatus: + self.htmlFile.write(' \n') + else: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') + self.htmlFile.write('

\n') + self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') + self.htmlFile.write('
\n') + self.htmlFile.write('\n') + self.htmlFile.close() + + #FailReportCnt should be passed as a parameter of CreateHtmlRetrySeparator method + # no need for a setter and be a member of html class + def CreateHtmlRetrySeparator(self, cntnumfails): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile = open('test_results.html', 'a') + self.htmlFile.write(' \n') + self.htmlFile.write(' Try Run #' + str(cntnumfails) + '\n') + self.htmlFile.write(' \n') + self.htmlFile.close() + + def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile = open('test_results.html', 'a') + currentTime = int(round(time.time() * 1000)) - self.startTime + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + if (processesStatus == 0): + self.htmlFile.write(' ' + str(status) + '\n') + elif (processesStatus == ENB_PROCESS_FAILED): + self.htmlFile.write(' KO - eNB process not found\n') + elif (processesStatus == OAI_UE_PROCESS_FAILED): + self.htmlFile.write(' KO - OAI UE process not found\n') + elif (processesStatus == ENB_PROCESS_SEG_FAULT) or (processesStatus == OAI_UE_PROCESS_SEG_FAULT): + self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') + elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): + self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') + elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): + self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') + elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): + self.htmlFile.write(' OK?\n') + elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): + self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') + elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + self.htmlFile.write(' KO - UE could not sync\n') + elif (processesStatus == HSS_PROCESS_FAILED): + self.htmlFile.write(' KO - HSS process not found\n') + elif (processesStatus == MME_PROCESS_FAILED): + self.htmlFile.write(' KO - MME process not found\n') + elif (processesStatus == SPGW_PROCESS_FAILED): + self.htmlFile.write(' KO - SPGW process not found\n') + elif (processesStatus == UE_IP_ADDRESS_ISSUE): + self.htmlFile.write(' KO - Could not retrieve UE IP address\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + else: + self.htmlFile.write(' ' + str(status) + '\n') + if (len(str(self.htmleNBFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') + self.htmleNBFailureMsg = '' + elif (len(str(self.htmlUEFailureMsg)) > 2): + cellBgColor = 'white' + result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'red' + else: + result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) + if result is not None: + cellBgColor = 'orange' + self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') + self.htmlUEFailureMsg = '' + else: + i = 0 + while (i < self.htmlUEConnected): + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + self.htmlFile.close() + + def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): + if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): + self.htmlFile = open('test_results.html', 'a') + currentTime = int(round(time.time() * 1000)) - self.startTime + addOrangeBK = False + self.htmlFile.write(' \n') + self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') + self.htmlFile.write(' ' + self.testCase_id + '\n') + self.htmlFile.write(' ' + self.desc + '\n') + self.htmlFile.write(' ' + str(options) + '\n') + if (str(status) == 'OK'): + self.htmlFile.write(' ' + str(status) + '\n') + elif (str(status) == 'KO'): + self.htmlFile.write(' ' + str(status) + '\n') + else: + addOrangeBK = True + self.htmlFile.write(' ' + str(status) + '\n') + i = 0 + while (i < self.htmlUEConnected): + if (i < ue_status): + if (not ue_queue.empty()): + if (addOrangeBK): + self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') + else: + self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') + else: + self.htmlFile.write(' -\n') + else: + self.htmlFile.write(' -\n') + i += 1 + self.htmlFile.write(' \n') + self.htmlFile.close() + + diff --git a/ci-scripts/main_enb.py b/ci-scripts/main_enb.py index e8c530a70b..340aaed9b3 100644 --- a/ci-scripts/main_enb.py +++ b/ci-scripts/main_enb.py @@ -28,6 +28,8 @@ # pexpect #--------------------------------------------------------------------- +import constants as CONST + #----------------------------------------------------------- # Version #----------------------------------------------------------- @@ -36,39 +38,39 @@ Version = '0.1' #----------------------------------------------------------- # Constants #----------------------------------------------------------- -ALL_PROCESSES_OK = 0 -ENB_PROCESS_FAILED = -1 -ENB_PROCESS_OK = +1 -ENB_PROCESS_SEG_FAULT = -11 -ENB_PROCESS_ASSERTION = -12 -ENB_PROCESS_REALTIME_ISSUE = -13 -ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 -ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 -HSS_PROCESS_FAILED = -2 -HSS_PROCESS_OK = +2 -MME_PROCESS_FAILED = -3 -MME_PROCESS_OK = +3 -SPGW_PROCESS_FAILED = -4 -SPGW_PROCESS_OK = +4 -UE_IP_ADDRESS_ISSUE = -5 -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 -OAI_UE_PROCESS_COULD_NOT_SYNC = -21 -OAI_UE_PROCESS_ASSERTION = -22 -OAI_UE_PROCESS_FAILED = -23 -OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 -OAI_UE_PROCESS_SEG_FAULT = -25 -OAI_UE_PROCESS_OK = +6 +ALL_PROCESSES_OK = CONST.ALL_PROCESSES_OK +ENB_PROCESS_FAILED = CONST.ENB_PROCESS_FAILED +ENB_PROCESS_OK = CONST.ENB_PROCESS_OK +ENB_PROCESS_SEG_FAULT = CONST.ENB_PROCESS_SEG_FAULT +ENB_PROCESS_ASSERTION = CONST.ENB_PROCESS_ASSERTION +ENB_PROCESS_REALTIME_ISSUE = CONST.ENB_PROCESS_REALTIME_ISSUE +ENB_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE +ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED +HSS_PROCESS_FAILED = CONST.HSS_PROCESS_FAILED +HSS_PROCESS_OK = CONST.HSS_PROCESS_OK +MME_PROCESS_FAILED = CONST.MME_PROCESS_FAILED +MME_PROCESS_OK = CONST.MME_PROCESS_OK +SPGW_PROCESS_FAILED = CONST.SPGW_PROCESS_FAILED +SPGW_PROCESS_OK = CONST.SPGW_PROCESS_OK +UE_IP_ADDRESS_ISSUE = CONST.UE_IP_ADDRESS_ISSUE +OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE +OAI_UE_PROCESS_COULD_NOT_SYNC = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC +OAI_UE_PROCESS_ASSERTION = CONST.OAI_UE_PROCESS_ASSERTION +OAI_UE_PROCESS_FAILED = CONST.OAI_UE_PROCESS_FAILED +OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE +OAI_UE_PROCESS_SEG_FAULT = CONST.OAI_UE_PROCESS_SEG_FAULT +OAI_UE_PROCESS_OK = CONST.OAI_UE_PROCESS_OK -UE_STATUS_DETACHED = 0 -UE_STATUS_DETACHING = 1 -UE_STATUS_ATTACHING = 2 -UE_STATUS_ATTACHED = 3 +UE_STATUS_DETACHED = CONST.UE_STATUS_DETACHED +UE_STATUS_DETACHING = CONST.UE_STATUS_DETACHING +UE_STATUS_ATTACHING = CONST.UE_STATUS_ATTACHING +UE_STATUS_ATTACHED = CONST.UE_STATUS_ATTACHED -X2_HO_REQ_STATE__IDLE = 0 -X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 -X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 -X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 -X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 +X2_HO_REQ_STATE__IDLE = CONST.X2_HO_REQ_STATE__IDLE +X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ +X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE +X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ +X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK #----------------------------------------------------------- # Import @@ -167,9 +169,9 @@ class OaiCiTest(): self.x2NbENBs = 0 self.x2ENBBsIds = [] self.x2ENBConnectedUEs = [] - self.htmlTabRefs = [] - self.htmlTabNames = [] - self.htmlTabIcons = [] + #self.htmlTabRefs = [] + #self.htmlTabNames = [] + #self.htmlTabIcons = [] self.repeatCounts = [] self.finalStatus = False self.OsVersion = '' @@ -192,198 +194,8 @@ class OaiCiTest(): self.flexranCtrlStarted = False self.expectedNbOfConnectedUEs = 0 self.startTime = 0 -''' - def BuildeNB(self): - if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = RAN.GeteNBSourceCodePath() - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(lIpAddr, lUserName, lPassWord) - # Check if we build an 5G-NR gNB or an LTE eNB - result = re.search('--gNB', RAN.GetBuild_eNB_args()) - if result is not None: - self.air_interface = 'nr' - else: - self.air_interface = 'lte' - # Worakround for some servers, we need to erase completely the workspace - if self.Build_eNB_forced_workspace_cleanup: - SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) - # on RedHat/CentOS .git extension is mandatory - result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) - if result is not None: - full_ran_repo_name = self.ranRepository - else: - full_ran_repo_name = self.ranRepository + '.git' - SSH.command('mkdir -p ' + lSourcePath, '\$', 5) - SSH.command('cd ' + lSourcePath, '\$', 5) - SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) - # Raphael: here add a check if git clone or git fetch went smoothly - SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - SSH.command('git config user.name "OAI Jenkins"', '\$', 5) - # Checking the BUILD INFO file - if not self.backgroundBuild: - SSH.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', SSH.getBefore()) - if result is not None: - mismatch = False - SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, SSH.getBefore()) - if result is None: - mismatch = True - SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge()): - result = re.search('YES', SSH.getBefore()) - if result is None: - mismatch = True - SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if RAN.GetranTargetBranch() == '': - result = re.search('develop', SSH.getBefore()) - else: - result = re.search(RAN.GetranTargetBranch(), SSH.getBefore()) - if result is None: - mismatch = True - else: - result = re.search('NO', SSH.getBefore()) - if result is None: - mismatch = True - if not mismatch: - SSH.close() - self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) - return - SSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) - # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (RAN.GetranAllowMerge()): - if RAN.GetranTargetBranch() == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + RAN.GetranTargetBranch()) - SSH.command('git merge --ff origin/' + RAN.GetranTargetBranch() + ' -m "Temporary merge for CI"', '\$', 5) - SSH.command('source oaienv', '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('mkdir -p log', '\$', 5) - SSH.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - if self.backgroundBuild: - SSH.command('echo "./build_oai ' + RAN.GetBuild_eNB_args() + '" > ./my-lte-softmodem-build.sh', '\$', 5) - SSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) - SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) - SSH.close() - self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) - self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id - return - SSH.command('stdbuf -o0 ./build_oai ' + RAN.GetBuild_eNB_args() + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) - def WaitBuildeNBisFinished(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = RAN.GeteNBSourceCodePath() - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(lIpAddr, lUserName, lPassWord) - count = 40 - buildOAIprocess = True - while (count > 0) and buildOAIprocess: - SSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) - result = re.search('build_oai', SSH.getBefore()) - if result is None: - buildOAIprocess = False - else: - count -= 1 - time.sleep(30) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) - - def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): - SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) - SSH.command('ls ran_build/build', '\$', 3) - SSH.command('ls ran_build/build', '\$', 3) - if self.air_interface == 'nr': - nodeB_prefix = 'g' - else: - nodeB_prefix = 'e' - buildStatus = True - result = re.search(self.air_interface + '-softmodem', SSH.getBefore()) - if result is None: - buildStatus = False - else: - # Generating a BUILD INFO file - SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge()): - SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if RAN.GetranTargetBranch() == '': - SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - SSH.command('echo "TGT_BRANCH: ' + RAN.GetranTargetBranch() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('mkdir -p build_log_' + testcaseId, '\$', 5) - SSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) - SSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) - if self.eNB_serverId != '0': - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) - SSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) - SSH.close() - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - os.remove('./tmp_build' + testcaseId + '.zip') - SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', RAN.GeteNBSourceCodePath() + '/cmake_targets/.') - os.remove('./tmp_build' + testcaseId + '.zip') - SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - SSH.command('cd ' + RAN.GeteNBSourceCodePath() + '/cmake_targets', '\$', 5) - SSH.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) - SSH.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) - SSH.close() - else: - SSH.close() - - if buildStatus: - logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') - self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) - else: - logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') - self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'KO', ALL_PROCESSES_OK) - self.CreateHtmlTabFooter(False) - sys.exit(1) -''' def BuildOAIUE(self): if self.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': GenericHelp(Version) @@ -391,10 +203,10 @@ class OaiCiTest(): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) result = re.search('--nrUE', self.Build_OAI_UE_args) if result is not None: - RAN.Setair_interface() = 'nr' + RAN.Setair_interface('nr') ue_prefix = 'NR ' else: - RAN.Setair_interface() = 'lte' + RAN.Setair_interface('lte') ue_prefix = '' result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', RAN.GetranRepository()) if result is not None: @@ -434,7 +246,7 @@ class OaiCiTest(): mismatch = True if not mismatch: SSH.close() - self.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) return SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) @@ -470,7 +282,7 @@ class OaiCiTest(): # Generating a BUILD INFO file SSH.command('echo "SRC_BRANCH: ' + RAN.GetranBranch() + '" > ../LAST_BUILD_INFO.txt', '\$', 2) SSH.command('echo "SRC_COMMIT: ' + RAN.GetranCommitID() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge): + if (RAN.GetranAllowMerge()): SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) if RAN.GetranTargetBranch() == '': SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) @@ -479,12 +291,12 @@ class OaiCiTest(): else: SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) SSH.close() - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') else: SSH.close() logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTabFooter(False) sys.exit(1) def CheckFlexranCtrlInstallation(self): @@ -495,6 +307,7 @@ class OaiCiTest(): result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) if result is not None: self.flexranCtrlInstalled = True + RAN.SetflexranCtrlInstalled(True) logging.debug('Flexran Controller is installed') SSH.close() @@ -515,187 +328,10 @@ class OaiCiTest(): if result is not None: logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') self.flexranCtrlStarted = True + RAN.SetflexranCtrlStarted(True) SSH.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) -''' - def InitializeeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = RAN.GeteNBSourceCodePath() - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = False - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(RAN.GetInitialize_eNB_args(), 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB - result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) - if result is not None: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', SSH.getBefore()) - if result is not None: - eth_interface = result.group('eth_interface') - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - EPC.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) - SSH.close() - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('cd ' + lSourcePath, '\$', 5) - # Initialize_eNB_args usually start with -O and followed by the location in repository - full_config_file = RAN.GetInitialize_eNB_args().replace('-O ','') - extra_options = '' - extIdx = full_config_file.find('.conf') - if (extIdx > 0): - extra_options = full_config_file[extIdx + 5:] - # if tracer options is on, compiling and running T Tracer - result = re.search('T_stdout', str(extra_options)) - if result is not None: - logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') - SSH.command('cd common/utils/T/tracer', '\$', 5) - SSH.command('make', '\$', 10) - SSH.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) - SSH.command('cd ' + lSourcePath, '\$', 5) - full_config_file = full_config_file[:extIdx + 5] - config_path, config_file = os.path.split(full_config_file) - else: - sys.exit('Insufficient Parameter') - ci_full_config_file = config_path + '/ci-' + config_file - rruCheck = False - result = re.search('^rru|^rcc|^du.band', str(config_file)) - if result is not None: - rruCheck = True - # do not reset board twice in IF4.5 case - result = re.search('^rru|^enb|^du.band', str(config_file)) - if result is not None: - SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) - result = re.search('type: b200', SSH.getBefore()) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - SSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) - # Make a copy and adapt to EPC / eNB IP addresses - SSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.GetIPAddress() + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); - else: - SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); - self.eNBmbmsEnables[int(self.eNB_instance)] = False - SSH.command('grep enable_enb_m2 ' + ci_full_config_file, '\$', 2); - result = re.search('yes', SSH.getBefore()) - if result is not None: - self.eNBmbmsEnables[int(self.eNB_instance)] = True - logging.debug('\u001B[1m MBMS is enabled on this eNB\u001B[0m') - result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) - eNBinNoS1 = False - if result is not None: - eNBinNoS1 = True - logging.debug('\u001B[1m eNB is in noS1 configuration \u001B[0m') - # Launch eNB with the modified config file - SSH.command('source oaienv', '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface + '-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - SSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - SSH.command('hostnamectl','\$', 5) - result = re.search('CentOS Linux 7', SSH.getBefore()) - if result is not None: - SSH.command('echo $USER; nohup sudo ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log 2>&1 &', lUserName, 10) - else: - SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' - if extra_options != '': - self.eNBOptions[int(self.eNB_instance)] = extra_options - time.sleep(6) - doLoop = True - loopCounter = 20 - enbDidSync = False - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # In case of T tracer recording, we may need to kill it - result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) - if result is not None: - SSH.command('killall --signal SIGKILL record', '\$', 5) - SSH.close() - doLoop = False - logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) - # In case of T tracer recording, we need to kill tshark on EPC side - result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) - if result is not None: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if EPC.EPC_PcapFileName != '': - time.sleep(0.5) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.close() - time.sleep(1) - if EPC.EPC_PcapFileName != '': - copyin_res = SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') - if (copyin_res == 0): - SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') - self.prematureExit = True - return - else: - SSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) - if rruCheck: - result = re.search('wait RUs', SSH.getBefore()) - else: - result = re.search('got sync|Starting F1AP at CU', SSH.getBefore()) - if result is None: - time.sleep(6) - else: - doLoop = False - enbDidSync = True - time.sleep(10) - - if enbDidSync and eNBinNoS1: - SSH.command('ifconfig oaitun_enb1', '\$', 4) - SSH.command('ifconfig oaitun_enb1', '\$', 4) - result = re.search('inet addr:1|inet 1', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_enb1 interface is mounted and configured\u001B[0m') - else: - logging.error('\u001B[1m oaitun_enb1 interface is either NOT mounted or NOT configured\u001B[0m') - if self.eNBmbmsEnables[int(self.eNB_instance)]: - SSH.command('ifconfig oaitun_enm1', '\$', 4) - result = re.search('inet addr', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_enm1 interface is mounted and configured\u001B[0m') - else: - logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m') - if enbDidSync: - self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) - - SSH.close() - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) - logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') -''' + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + def InitializeUE_common(self, device_id, idx): try: SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -757,7 +393,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def InitializeOAIUE(self): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': @@ -770,8 +406,8 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) UE_prefix = '' else: @@ -915,7 +551,7 @@ class OaiCiTest(): SSH.close() if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') if (self.ADBIPAddress != 'none'): self.UEDevices = [] @@ -928,10 +564,10 @@ class OaiCiTest(): self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' else: self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') else: self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') logging.error('\033[91mInitialize OAI UE Failed! \033[0m') self.AutoTerminateUEandeNB() @@ -961,11 +597,11 @@ class OaiCiTest(): # Calling twice AT to clear all buffers SSH.command('AT', 'OK|ERROR', 5) SSH.command('AT', 'OK', 5) - # Doing a power cycle - self.command('AT^RESET', 'SIMSTORE,READY', 15) - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - self.command('ATE1', 'OK', 5) + # Doing a power cycle + self.command('AT^RESET', 'SIMSTORE,READY', 15) + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + self.command('ATE1', 'OK', 5) # Disabling the Radio SSH.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') @@ -984,7 +620,7 @@ class OaiCiTest(): # Force closure of picocom but device might still be locked SSH.close() self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() def TerminateCatM(self): @@ -1005,7 +641,7 @@ class OaiCiTest(): logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') SSH.close() self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() def AttachCatM(self): @@ -1074,12 +710,12 @@ class OaiCiTest(): else: html_cell += '' html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) else: logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') html_cell = '
CAT-M module Attachment Failed
' html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) self.AutoTerminateUEandeNB() def PingCatM(self): @@ -1090,7 +726,7 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return try: @@ -1101,8 +737,8 @@ class OaiCiTest(): SSH.command('cd scripts', '\$', 5) if re.match('OAI', EPC.GetType(), re.IGNORECASE): logging.debug('Using the OAI EPC HSS: not implemented yet') - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) else: SSH.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) @@ -1110,7 +746,7 @@ class OaiCiTest(): if result is not None: moduleIPAddr = result.group('ipaddr') else: - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ping_time = re.findall("-c (\d+)",str(self.ping_args)) @@ -1172,9 +808,9 @@ class OaiCiTest(): html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' statusQueue.put(html_cell) if (packetLossOK): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) self.AutoTerminateUEandeNB() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1198,6 +834,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) + print('#GP: in SSH.getBefore() K=0 (it was K=2 in main.py)') result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') @@ -1256,7 +893,7 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) self.AutoTerminateUEandeNB() return multi_jobs = [] @@ -1275,7 +912,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() return else: @@ -1298,13 +935,13 @@ class OaiCiTest(): if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED cnt += 1 - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) if result is not None: logging.debug('Waiting 5 seconds to fill up record file') time.sleep(5) else: - self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def DetachUE_common(self, device_id, idx): @@ -1330,7 +967,7 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) self.AutoTerminateUEandeNB() return multi_jobs = [] @@ -1344,7 +981,7 @@ class OaiCiTest(): cnt += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) if result is not None: logging.debug('Waiting 5 seconds to fill up record file') @@ -1401,8 +1038,8 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) multi_jobs = [] for device_id in self.UEDevices: @@ -1412,7 +1049,7 @@ class OaiCiTest(): multi_jobs.append(p) for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def DataDisableUE_common(self, device_id, idx): try: @@ -1441,7 +1078,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def DataEnableUE_common(self, device_id, idx): try: @@ -1470,7 +1107,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def GetAllUEDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': @@ -1506,11 +1143,13 @@ class OaiCiTest(): self.UEDevicesRebootCmd.append(comma_split[5]) phone_list_file.close() - if terminate_ue_flag == False: + if terminate_ue_flag == True: + print('terminate_ue_flag == True') if len(self.UEDevices) == 0: logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') sys.exit(1) if len(self.UEDevicesStatus) == 0: + print('len(self.UEDevicesStatus) == 0') cnt = 0 while cnt < len(self.UEDevices): self.UEDevicesStatus.append(UE_STATUS_DETACHED) @@ -1533,7 +1172,7 @@ class OaiCiTest(): SSH.close() if result is not None: logging.debug('Found a module list file on ADB server') - if terminate_ue_flag == False: + if terminate_ue_flag == True: if len(self.CatMDevices) == 0: logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') sys.exit(1) @@ -1596,8 +1235,8 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) multi_jobs = [] lock = Lock() @@ -1633,7 +1272,7 @@ class OaiCiTest(): htmlOptions = 'N/A' if (status_queue.empty()): - self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: check_status = True @@ -1647,9 +1286,9 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\n' + message + '
' html_queue.put(html_cell) if check_status and passStatus: - self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def GetAllUEIPAddresses(self): @@ -1680,6 +1319,7 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) idx = 0 for device_id in self.UEDevices: + print('UE status attched'+UE_STATUS_ATTACHED) if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: idx += 1 continue @@ -1809,14 +1449,14 @@ class OaiCiTest(): html_queue = SimpleQueue() html_cell = '
OAI UE ping result\n' + qMsg + '
' html_queue.put(html_cell) - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) def PingNoS1(self): check_eNB = True check_OAI_UE = True pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) @@ -1889,13 +1529,13 @@ class OaiCiTest(): html_cell = '
OAI UE ping result\n' + qMsg + '
' html_queue.put(html_cell) if packetLossOK: - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) # copying on the EPC server for logCollection if ping_from_eNB is not None: - copyin_res = SSH.copyin(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword, RAN.GeteNBSourceCodePath() + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + copyin_res = SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') else: copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') if (copyin_res == 0): @@ -1918,12 +1558,12 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return multi_jobs = [] @@ -1941,7 +1581,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: ping_status = True @@ -1956,9 +1596,9 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' html_queue.put(html_cell) if (ping_status): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def Iperf_ComputeTime(self): @@ -2347,6 +1987,7 @@ class OaiCiTest(): def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): try: + logging.debug('entring Iperf_common') # Single-UE profile -- iperf only on one UE if self.iperf_profile == 'single-ue' and idx != 0: return @@ -2520,9 +2161,9 @@ class OaiCiTest(): SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) # fromdos has to be called on the python executor not on ADB server - cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log' - subprocess.run(cmd, shell=True) - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) + cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log' + subprocess.run(cmd, shell=True) + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI UE: if (device_id == 'OAI-UE'): @@ -2543,14 +2184,14 @@ class OaiCiTest(): check_OAI_UE = True pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return server_on_enb = re.search('-R', str(self.iperf_args)) if server_on_enb is not None: - iServerIPAddr = RAN.GeteNBIPAddress - iServerUser = RAN.GeteNBUserName - iServerPasswd = RAN.GeteNBPassword + iServerIPAddr = RAN.GeteNBIPAddress() + iServerUser = RAN.GeteNBUserName() + iServerPasswd = RAN.GeteNBPassword() iClientIPAddr = self.UEIPAddress iClientUser = self.UEUserName iClientPasswd = self.UEPassword @@ -2558,9 +2199,9 @@ class OaiCiTest(): iServerIPAddr = self.UEIPAddress iServerUser = self.UEUserName iServerPasswd = self.UEPassword - iClientIPAddr = RAN.GeteNBIPAddress - iClientUser = RAN.GeteNBUserName - iClientPasswd = RAN.GeteNBPassword + iClientIPAddr = RAN.GeteNBIPAddress() + iClientUser = RAN.GeteNBUserName() + iClientPasswd = RAN.GeteNBPassword() if self.iperf_options != 'sink': # Starting the iperf server SSH.open(iServerIPAddr, iServerUser, iServerPasswd) @@ -2637,11 +2278,11 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' html_queue.put(html_cell) if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def Iperf(self): @@ -2659,12 +2300,13 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) + logging.debug('going here') + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return @@ -2684,9 +2326,10 @@ class OaiCiTest(): ue_num = len(self.UEIPAddresses) lock = Lock() status_queue = SimpleQueue() + logging.debug('ue_num = ' + str(ue_num)) for UE_IPAddress in self.UEIPAddresses: device_id = self.UEDevices[i] - p = Process(target = CiTestObj.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) + p = Process(target = self.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2695,7 +2338,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: iperf_status = True @@ -2713,11 +2356,11 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' html_queue.put(html_cell) if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def CheckProcessExist(self, check_eNB, check_OAI_UE): @@ -2743,12 +2386,12 @@ class OaiCiTest(): if (check_eNB == False) and (check_OAI_UE == False): return 0 if check_eNB: - p = Process(target = CiTestObj.CheckeNBProcess, args = (status_queue,)) + p = Process(target = RAN.CheckeNBProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) if check_OAI_UE: - p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) + p = Process(target = self.CheckOAIUEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2766,7 +2409,7 @@ class OaiCiTest(): if result == ENB_PROCESS_FAILED: fileCheck = re.search('enb_', str(RAN.GeteNBLogFiles[0])) if fileCheck is not None: - SSH.copyin(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword, RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') + SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') logStatus = self.AnalyzeLogFile_eNB(RAN.GeteNBLogFiles[0]) if logStatus < 0: result = logStatus @@ -2779,7 +2422,7 @@ class OaiCiTest(): multi_jobs = [] status_queue = SimpleQueue() if initialize_OAI_UE_flag == False: - p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) + p = Process(target = self.CheckOAIUEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2816,293 +2459,10 @@ class OaiCiTest(): SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) -''' - def CheckeNBProcess(self, status_queue): - try: - # At least the instance 0 SHALL be on! - if self.eNBstatuses[0] == 0: - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - elif self.eNBstatuses[0] == 1: - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - elif self.eNBstatuses[0] == 2: - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - else: - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-softmodem | grep -v grep', '\$', 5) - result = re.search(self.air_interface + '-softmodem', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') - status_queue.put(ENB_PROCESS_FAILED) - else: - status_queue.put(ENB_PROCESS_OK) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) -''' - def AnalyzeLogFile_eNB(self, eNBlogFile): - if (not os.path.isfile('./' + eNBlogFile)): - return -1 - enb_log_file = open('./' + eNBlogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - rrcSetupComplete = 0 - rrcReleaseRequest = 0 - rrcReconfigRequest = 0 - rrcReconfigComplete = 0 - rrcReestablishRequest = 0 - rrcReestablishComplete = 0 - rrcReestablishReject = 0 - rlcDiscardBuffer = 0 - rachCanceledProcedure = 0 - uciStatMsgCount = 0 - pdcpFailure = 0 - ulschFailure = 0 - cdrxActivationMessageCount = 0 - dropNotEnoughRBs = 0 - mbmsRequestMsg = 0 - self.htmleNBFailureMsg = '' - isRRU = False - isSlave = False - slaveReceivesFrameResyncCmd = False - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures = 0 - X2HO_outNbProcedures = 0 - for line in enb_log_file.readlines(): - if X2HO_state == X2_HO_REQ_STATE__IDLE: - result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ - result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK - if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: - result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE - if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: - result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ - if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: - result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures += 1 - if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: - result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_outNbProcedures += 1 - if RAN.SeteNBOptions[int(RAN.GeteNB_instance())] != '': - res1 = re.search('max_rxgain (?P[0-9]+)', RAN.GeteNBOptions[int(RAN.GeteNB_instance())]) - res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) - if res1 is not None and res2 is not None: - requested_option = int(res1.group('requested_option')) - applied_option = int(res2.group('applied_option')) - if requested_option == applied_option: - self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + RAN.GeteNBOptions[int(RAN.GeteNB_instance())] + '\n\n' - else: - self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + RAN.GeteNBOptions[int(RAN.GeteNB_instance())] + '\n\n' - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('[Ss]egmentation [Ff]ault', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./ran_build/build/lte-softmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('Setting function for RU', str(line)) - if result is not None: - isRRU = True - if isRRU: - result = re.search('RU 0 is_slave=yes', str(line)) - if result is not None: - isSlave = True - if isSlave: - result = re.search('Received RRU_frame_resynch command', str(line)) - if result is not None: - slaveReceivesFrameResyncCmd = True - result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) - if result is not None: - rrcSetupComplete += 1 - result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) - if result is not None: - rrcReleaseRequest += 1 - result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) - if result is not None: - rrcReconfigRequest += 1 - result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) - if result is not None: - rrcReconfigComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) - if result is not None: - rrcReestablishRequest += 1 - result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) - if result is not None: - rrcReestablishComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) - if result is not None: - rrcReestablishReject += 1 - result = re.search('CDRX configuration activated after RRC Connection', str(line)) - if result is not None: - cdrxActivationMessageCount += 1 - result = re.search('uci->stat', str(line)) - if result is not None: - uciStatMsgCount += 1 - result = re.search('PDCP.*Out of Resources.*reason', str(line)) - if result is not None: - pdcpFailure += 1 - result = re.search('ULSCH in error in round', str(line)) - if result is not None: - ulschFailure += 1 - result = re.search('BAD all_segments_received', str(line)) - if result is not None: - rlcDiscardBuffer += 1 - result = re.search('Canceled RA procedure for UE rnti', str(line)) - if result is not None: - rachCanceledProcedure += 1 - result = re.search('dropping, not enough RBs', str(line)) - if result is not None: - dropNotEnoughRBs += 1 - if RAN.GeteNBmbmsEnables[int(RAN.GeteNB_instance())]: - result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line)) - if result is not None: - mbmsRequestMsg += 1 - enb_log_file.close() - logging.debug(' File analysis completed') - self.htmleNBFailureMsg = '' - if RAN.Getair_interface() == 'lte': - nodeB_prefix = 'e' - else: - nodeB_prefix = 'g' - if uciStatMsgCount > 0: - statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if pdcpFailure > 0: - statMsg = nodeB_prefix + 'NB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if ulschFailure > 0: - statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if dropNotEnoughRBs > 0: - statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if rrcSetupComplete > 0: - rrcMsg = nodeB_prefix + 'NB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcSetupComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReleaseRequest > 0: - rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: - rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: - rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if RAN.GeteNBmbmsEnables[int(RAN.GeteNB_instance())]: - if mbmsRequestMsg > 0: - rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_inNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_outNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if RAN.SeteNBOptions[int(RAN.GeteNB_instance())] != '': - res1 = re.search('drx_Config_present prSetup', RAN.GeteNBOptions[int(RAN.GeteNB_instance())]) - if res1 is not None: - if cdrxActivationMessageCount > 0: - rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - else: - rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' - logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rachCanceledProcedure > 0: - rachMsg = nodeB_prefix + 'NB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' - logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rachMsg + '\n' - if isRRU: - if isSlave: - if slaveReceivesFrameResyncCmd: - rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - else: - rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - self.prematureExit = True - return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED - if foundSegFault: - logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m') - self.htmleNBFailureMsg += msgAssertion - return ENB_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') - self.htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE - if rlcDiscardBuffer > 0: - rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' - logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rlcMsg + '\n' - return ENB_PROCESS_REALTIME_ISSUE - return 0 + +# def AnalyzeLogFile_eNB(self, eNBlogFile): +# ... def AnalyzeLogFile_UE(self, UElogFile): if (not os.path.isfile('./' + UElogFile)): @@ -3354,104 +2714,8 @@ class OaiCiTest(): self.htmlUEFailureMsg += 'UE could not synchronize!\n' return OAI_UE_PROCESS_COULD_NOT_SYNC return 0 -''' - def TerminateeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = RAN.GeteNBSourceCodePath() - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) - if self.air_interface == 'lte': - nodeB_prefix = 'e' - else: - nodeB_prefix = 'g' - SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('-softmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) - SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5) - time.sleep(10) - SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('-softmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5) - time.sleep(5) - SSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - SSH.close() - # If tracer options is on, stopping tshark on EPC side - result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) - if result is not None: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - time.sleep(1) - if EPC.EPC_PcapFileName != '': - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') - SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') - SSH.close() - logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) - enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] - raw_record_file = enbLogFile.replace('.log', '_record.raw') - replay_log_file = enbLogFile.replace('.log', '_replay.log') - extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') - extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') - SSH.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) - SSH.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) - SSH.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) - SSH.close() - SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') - logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.eNBLogFiles[int(self.eNB_instance)] = '' - else: - analyzeFile = False - if self.eNBLogFiles[int(self.eNB_instance)] != '': - analyzeFile = True - fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] - self.eNBLogFiles[int(self.eNB_instance)] = '' - if analyzeFile: - copyin_res = SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') - self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - return - if self.eNB_serverId != '0': - SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, RAN.GeteNBSourceCodePath() + '/cmake_targets/') - logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) - logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) - if (logStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', logStatus) - self.preamtureExit = True - self.eNBmbmsEnables[int(self.eNB_instance)] = False - return - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - self.eNBstatuses[int(self.eNB_instance)] = -1 -''' + + def TerminateFlexranCtrl(self): if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: return @@ -3465,7 +2729,7 @@ class OaiCiTest(): time.sleep(1) SSH.close() self.flexranCtrlStarted = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateUE_common(self, device_id, idx): try: @@ -3496,19 +2760,19 @@ class OaiCiTest(): os.kill(os.getppid(),signal.SIGUSR1) def TerminateUE(self): - terminate_ue_flag = True + terminate_ue_flag = False self.GetAllUEDevices(terminate_ue_flag) multi_jobs = [] i = 0 for device_id in self.UEDevices: - p = Process(target= CiTestObj.TerminateUE_common, args = (device_id,i,)) + p = Process(target= self.TerminateUE_common, args = (device_id,i,)) p.daemon = True p.start() multi_jobs.append(p) i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateOAIUE(self): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) @@ -3531,7 +2795,7 @@ class OaiCiTest(): if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + HTML.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') self.UELogFile = '' return logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') @@ -3544,7 +2808,7 @@ class OaiCiTest(): if (logStatus < 0): logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') + HTML.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') if RAN.Getair_interface() == 'lte': # In case of sniffing on commercial eNBs we have random results # Not an error then @@ -3558,38 +2822,42 @@ class OaiCiTest(): else: logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.UELogFile = '' else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def AutoTerminateUEandeNB(self): if (self.ADBIPAddress != 'none'): self.testCase_id = 'AUTO-KILL-UE' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' self.ShowTestID() self.TerminateUE() if (self.Initialize_OAI_UE_args != ''): self.testCase_id = 'AUTO-KILL-UE' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' self.ShowTestID() self.TerminateOAIUE() if (RAN.GetInitialize_eNB_args() != ''): self.testCase_id = 'AUTO-KILL-eNB' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of eNB' self.ShowTestID() - RAN.SeteNB_instance() = '0' - self.TerminateeNB() + RAN.SeteNB_instance('0') + RAN.TerminateeNB() if self.flexranCtrlInstalled and self.flexranCtrlStarted: self.testCase_id = 'AUTO-KILL-flexran-ctl' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of FlexRan CTL' self.ShowTestID() self.TerminateFlexranCtrl() - self.prematureExit = True + RAN.SetprematureExit(True) def IdleSleep(self): time.sleep(self.idle_sleep_time) - self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) def X2_Status(self, idx, fileName): cmd = "curl --silent http://" + EPC.GetIPAddress() + ":9999/stats | jq '.' > " + fileName @@ -3691,21 +2959,21 @@ class OaiCiTest(): logging.debug(msg) fullMessage += msg + '' html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) else: msg = "X2 Handover FAILED" logging.error(msg) fullMessage += msg + '' html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) def LogCollectBuild(self): if (RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != ''): - IPAddress = RAN.GeteNBIPAddress - UserName = RAN.GeteNBUserName - Password = RAN.GeteNBPassword + IPAddress = RAN.GeteNBIPAddress() + UserName = RAN.GeteNBUserName() + Password = RAN.GeteNBPassword() SourceCodePath = RAN.GeteNBSourceCodePath() elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): IPAddress = self.UEIPAddress @@ -3720,16 +2988,6 @@ class OaiCiTest(): SSH.command('rm -f build.log.zip', '\$', 5) SSH.command('zip build.log.zip build_log_*/*', '\$', 60) SSH.close() -''' - def LogCollecteNB(self): - SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - SSH.command('cd ' + RAN.GeteNBSourceCodePath(), '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - SSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) - SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) - SSH.close() -''' def LogCollectPing(self): SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) @@ -3769,9 +3027,9 @@ class OaiCiTest(): return 0 if machine == 'eNB': if RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != '': - IPAddress = RAN.GeteNBIPAddress - UserName = RAN.GeteNBUserName - Password = RAN.GeteNBPassword + IPAddress = RAN.GeteNBIPAddress() + UserName = RAN.GeteNBUserName() + Password = RAN.GeteNBPassword() else: return -1 if machine == 'UE': @@ -3837,335 +3095,6 @@ class OaiCiTest(): logging.debug('cpu_mhz: ' + self.CpuMHz) SSH.close() -#----------------------------------------------------------- -# HTML Reporting.... -#----------------------------------------------------------- - def CreateHtmlHeader(self): - if (not self.htmlHeaderCreated): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML header \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - self.htmlFile = open('test_results.html', 'w') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') - self.htmlFile.write('\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (RAN.GetranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (RAN.GetranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (RAN.GetranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if RAN.GetranAllowMerge() != '': - commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + RAN.GetranCommitID, shell=True, universal_newlines=True) - commit_message = commit_message.strip() - self.htmlFile.write(' \n') - if (RAN.GetranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (RAN.GetranAllowMerge): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (RAN.GetranTargetBranch() == ''): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + RAN.GetranRepository() + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + RAN.GetranBranch() + '
Source Commit ID Commit ID ' + RAN.GetranCommitID() + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + RAN.GetranTargetBranch() + '
\n') - - if (self.ADBIPAddress != 'none'): - terminate_ue_flag = True - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') - self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.close() - - def CreateHtmlTabHeader(self): - if (not self.htmlHeaderCreated): - if (not os.path.isfile('test_results.html')): - self.CreateHtmlHeader() - self.htmlFile = open('test_results.html', 'a') - if (self.nbTestXMLfiles == 1): - self.htmlFile.write('
\n') - self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') - else: - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.htmlUEConnected == -1): - terminate_ue_flag = True - if (self.ADBIPAddress != 'none'): - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' \n') - i += 1 - self.htmlFile.write(' \n') - self.htmlHeaderCreated = True - - def CreateHtmlTabFooter(self, passStatus): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') - self.htmlFile.write('
\n') - self.htmlFile.close() - time.sleep(1) - if passStatus: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" - subprocess.run(cmd, shell=True) - else: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" - subprocess.run(cmd, shell=True) - self.htmlFooterCreated = False - - def CreateHtmlFooter(self, passStatus): - if (os.path.isfile('test_results.html')): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML footer \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - - self.htmlFile = open('test_results.html', 'a') - self.htmlFile.write('
\n') - self.htmlFile.write('

\n') - self.htmlFile.write(' \n') - - machines = [ 'eNB', 'UE' ] - for machine in machines: - res = self.RetrieveSystemVersion(machine) - if res == -1: - continue - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') - self.htmlFile.write('

\n') - self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('\n') - self.htmlFile.close() - - def CreateHtmlRetrySeparator(self): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - self.htmlFile.write(' \n') - self.htmlFile.write(' Try Run #' + str(self.FailReportCnt) + '\n') - self.htmlFile.write(' \n') - - def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - if (processesStatus == 0): - self.htmlFile.write(' ' + str(status) + '\n') - elif (processesStatus == ENB_PROCESS_FAILED): - self.htmlFile.write(' KO - eNB process not found\n') - elif (processesStatus == OAI_UE_PROCESS_FAILED): - self.htmlFile.write(' KO - OAI UE process not found\n') - elif (processesStatus == ENB_PROCESS_SEG_FAULT) or (processesStatus == OAI_UE_PROCESS_SEG_FAULT): - self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') - elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): - self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') - elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): - self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') - elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): - self.htmlFile.write(' OK?\n') - elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): - self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') - elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): - self.htmlFile.write(' KO - UE could not sync\n') - elif (processesStatus == HSS_PROCESS_FAILED): - self.htmlFile.write(' KO - HSS process not found\n') - elif (processesStatus == MME_PROCESS_FAILED): - self.htmlFile.write(' KO - MME process not found\n') - elif (processesStatus == SPGW_PROCESS_FAILED): - self.htmlFile.write(' KO - SPGW process not found\n') - elif (processesStatus == UE_IP_ADDRESS_ISSUE): - self.htmlFile.write(' KO - Could not retrieve UE IP address\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - if (len(str(self.htmleNBFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') - self.htmleNBFailureMsg = '' - elif (len(str(self.htmlUEFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') - self.htmlUEFailureMsg = '' - else: - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - - def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - addOrangeBK = False - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - self.htmlFile.write(' ' + str(status) + '\n') - else: - addOrangeBK = True - self.htmlFile.write(' ' + str(status) + '\n') - i = 0 - while (i < self.htmlUEConnected): - if (i < ue_status): - if (not ue_queue.empty()): - if (addOrangeBK): - self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') - else: - self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') - else: - self.htmlFile.write(' -\n') - else: - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - #----------------------------------------------------------- # ShowTestID() #----------------------------------------------------------- @@ -4183,47 +3112,47 @@ def CheckClassValidity(action,id): def GetParametersFromXML(action): if action == 'Build_eNB': - RAN.SetBuild_eNB_args() = test.findtext('Build_eNB_args') + RAN.SetBuild_eNB_args(test.findtext('Build_eNB_args')) forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') if (forced_workspace_cleanup is None): - RAN.SetBuild_eNB_forced_workspace_cleanup() = False + RAN.SetBuild_eNB_forced_workspace_cleanup(False) else: if re.match('true', forced_workspace_cleanup, re.IGNORECASE): - RAN.SetBuild_eNB_forced_workspace_cleanup() = True + RAN.SetBuild_eNB_forced_workspace_cleanup(True) else: - RAN.SetBuild_eNB_forced_workspace_cleanup() = False - RAN.SeteNB_instance() = test.findtext('eNB_instance') + RAN.SetBuild_eNB_forced_workspace_cleanup(False) + RAN.SeteNB_instance(test.findtext('eNB_instance')) if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance() = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') xmlBgBuildField = test.findtext('backgroundBuild') if (xmlBgBuildField is None): - RAN.SetbackgroundBuild() = False + RAN.SetbackgroundBuild(False) else: if re.match('true', xmlBgBuildField, re.IGNORECASE): - RAN.SetbackgroundBuild() = True + RAN.SetbackgroundBuild(True) else: - RAN.SetbackgroundBuild() = False + RAN.SetbackgroundBuild(False) if action == 'WaitEndBuild_eNB': - RAN.SetBuild_eNB_args() = test.findtext('Build_eNB_args') - RAN.SeteNB_instance() = test.findtext('eNB_instance') + RAN.SetBuild_eNB_args(test.findtext('Build_eNB_args')) + RAN.SeteNB_instance(test.findtext('eNB_instance')) if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance() = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') if action == 'Initialize_eNB': - RAN.SetInitialize_eNB_args() = test.findtext('Initialize_eNB_args') - RAN.SeteNB_instance() = test.findtext('eNB_instance') + RAN.SetInitialize_eNB_args(test.findtext('Initialize_eNB_args')) + RAN.SeteNB_instance(test.findtext('eNB_instance')) if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') CiTestObj.air_interface = test.findtext('air_interface') if (CiTestObj.air_interface is None): CiTestObj.air_interface = 'lte' @@ -4231,12 +3160,12 @@ def GetParametersFromXML(action): CiTestObj.air_interface = CiTestObj.air_interface.lower() if action == 'Terminate_eNB': - RAN.SeteNB_instance() = test.findtext('eNB_instance') + RAN.SeteNB_instance(test.findtext('eNB_instance')) if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance() = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') CiTestObj.air_interface = test.findtext('air_interface') if (CiTestObj.air_interface is None): CiTestObj.air_interface = 'lte' @@ -4277,7 +3206,7 @@ def GetParametersFromXML(action): CiTestObj.air_interface = SSH.air_interface.lower() if action == 'Terminate_OAI_UE': - RAN.SeteNB_instance = test.findtext('UE_instance') + RAN.SeteNB_instance(test.findtext('UE_instance')) if (CiTestObj.UE_instance is None): CiTestObj.UE_instance = '0' @@ -4340,15 +3269,18 @@ def receive_signal(signum, frame): mode = '' CiTestObj = OaiCiTest() -from sshconnection import * -from epc import * -from helpreadme import * -from enb import * -SSH = SSHConnection() -EPC = EPCManagement() -RAN = RANManagement() -#HELP = HelpReadme() -#HELP.GenericHelp() +import sshconnection +import epc +import helpreadme +import ran +import html +import constants + +SSH = sshconnection.SSHConnection() +EPC = epc.EPCManagement() +RAN = ran.RANManagement() +HTML = html.HTMLManagement() + argvs = sys.argv argc = len(argvs) @@ -4356,6 +3288,7 @@ cwd = os.getcwd() while len(argvs) > 1: myArgv = argvs.pop(1) # 0th is this file's name + if re.match('^\-\-help$', myArgv, re.IGNORECASE): GenericHelp(Version) sys.exit(0) @@ -4367,7 +3300,8 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) - RAN.SetranRepository() = matchReg.group(1) + RAN.SetranRepository(matchReg.group(1)) + HTML.SetranRepository(matchReg.group(1)) elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) @@ -4375,68 +3309,72 @@ while len(argvs) > 1: matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) doMerge = matchReg.group(1) if ((doMerge == 'true') or (doMerge == 'True')): - RAN.SetranAllowMerge() = True + RAN.SetranAllowMerge(True) + HTML.SetranAllowMerge(True) elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) - RAN.SetranBranch() = matchReg.group(1) + RAN.SetranBranch(matchReg.group(1)) + HTML.SetranBranch(matchReg.group(1)) elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) - RAN.SetranCommitID() = matchReg.group(1) + RAN.SetranCommitID(matchReg.group(1)) + HTML.SetranCommitID(matchReg.group(1)) elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) - RAN.SetranTargetBranch() = matchReg.group(1) + RAN.SetranTargetBranch(matchReg.group(1)) elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBIPAddress() = matchReg.group(1) + RAN.SeteNBIPAddress(matchReg.group(1)) elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1IPAddress() = matchReg.group(1) + RAN.SeteNB1IPAddress(matchReg.group(1)) elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2IPAddress() = matchReg.group(1) + RAN.SeteNB2IPAddress(matchReg.group(1)) elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBUserName() = matchReg.group(1) + RAN.SeteNBUserName(matchReg.group(1)) elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1UserName() = matchReg.group(1) + RAN.SeteNB1UserName(matchReg.group(1)) elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2UserName() = matchReg.group(1) + RAN.SeteNB2UserName(matchReg.group(1)) elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBPassword() = matchReg.group(1) + RAN.SeteNBPassword(matchReg.group(1)) elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1Password() = matchReg.group(1) + RAN.SeteNB1Password(matchReg.group(1)) elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2Password() = matchReg.group(1) + RAN.SeteNB2Password(matchReg.group(1)) elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBSourceCodePath() = matchReg.group(1) + RAN.SeteNBSourceCodePath(matchReg.group(1)) elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1SourceCodePath() = matchReg.group(1) + RAN.SeteNB1SourceCodePath(matchReg.group(1)) elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2SourceCodePath() = matchReg.group(1) + RAN.SeteNB2SourceCodePath(matchReg.group(1)) elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) EPC.SetIPAddress(matchReg.group(1)) +#GP250220: do we still need EPCBranch? it's not used anywhere elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) CiTestObj.EPCBranch = matchReg.group(1) @@ -4476,6 +3414,7 @@ while len(argvs) > 1: elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) CiTestObj.testXMLfiles.append(matchReg.group(1)) + HTML.SettestXMLfiles(matchReg.group(1)) CiTestObj.nbTestXMLfiles += 1 elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) @@ -4502,9 +3441,9 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE): if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - CiTestObj.eNB_serverId = '0' - RAN.SeteNB_instance = '0' - RAN.GeteNBSourceCodePath() = '/tmp/' + RAN.SeteNB_serverId('0') + RAN.SeteNB_instance('0') + RAN.SeteNBSourceCodePath('/tmp/') CiTestObj.TerminateeNB() elif re.match('^TerminateUE$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): @@ -4588,23 +3527,38 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): except: print("Error while parsing file: " + xml_test_file) xmlRoot = xmlTree.getroot() - CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + HTML.SethtmlTabIcons(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) + #CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) foundCount += 1 count += 1 if foundCount != CiTestObj.nbTestXMLfiles: CiTestObj.nbTestXMLfiles = foundCount - CiTestObj.CreateHtmlHeader() + HTML.SetnbTestXMLfiles(CiTestObj.nbTestXMLfiles) + + if (CiTestObj.ADBIPAddress != 'none'): + terminate_ue_flag = False + CiTestObj.GetAllUEDevices(terminate_ue_flag) + CiTestObj.GetAllCatMDevices(terminate_ue_flag) + HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices)) + HTML.SethtmlNb_Smartphones(len(CiTestObj.UEDevices)) + HTML.SethtmlNb_CATM_Modules(len(CiTestObj.CatMDevices)) + HTML.CreateHtmlHeader(CiTestObj.ADBIPAddress) elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - CiTestObj.CreateHtmlFooter(CiTestObj.finalStatus) + HTML.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): if RAN.GeteNBIPAddress() == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': GenericHelp(Version) if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or EPC.GetType() == '': EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) - # Gabriele: other if conditions relevant to eNB etc. to be added + if RAN.GetranRepository() == '': + GitSrvHelp(RAN.GetranRepository(),RAN.GetranBranch(),RAN.GetranCommitID(),RAN.GetranAllowMerge(),RAN.GetranTargetBranch()) + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': + eNBSrvHelp(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath()) sys.exit('Insufficient Parameter') if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): @@ -4628,8 +3582,10 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') if (CiTestObj.nbTestXMLfiles == 1): - CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) + HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabName',default='Test-0')) + #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) repeatCount = xmlRoot.findtext('repeatCount',default='1') CiTestObj.repeatCounts.append(int(repeatCount)) all_tests=xmlRoot.findall('testCase') @@ -4671,26 +3627,38 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re signal.signal(signal.SIGUSR1, receive_signal) - CiTestObj.CreateHtmlTabHeader() + if (CiTestObj.ADBIPAddress != 'none'): + terminate_ue_flag = False + CiTestObj.GetAllUEDevices(terminate_ue_flag) + CiTestObj.GetAllCatMDevices(terminate_ue_flag) + else: + CiTestObj.UEDevices.append('OAI-UE') + HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices)) + HTML.CreateHtmlTabHeader() CiTestObj.FailReportCnt = 0 - CiTestObj.prematureExit = True + RAN.SetprematureExit(True) CiTestObj.startTime = int(round(time.time() * 1000)) - while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: - CiTestObj.prematureExit = False + HTML.SetstartTime(CiTestObj.startTime) + while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): + RAN.SetprematureExit(False) # At every iteratin of the retry loop, a separator will be added - CiTestObj.CreateHtmlRetrySeparator() + # pass CiTestObj.FailReportCnt as parameter of HTML.CreateHtmlRetrySeparator + HTML.CreateHtmlRetrySeparator(CiTestObj.FailReportCnt) for test_case_id in todo_tests: - if CiTestObj.prematureExit: + if RAN.GetprematureExit(): break for test in all_tests: - if CiTestObj.prematureExit: + if RAN.GetprematureExit(): break id = test.get('id') if test_case_id != id: continue CiTestObj.testCase_id = id + RAN.SettestCase_id(CiTestObj.testCase_id) + HTML.SettestCase_id(CiTestObj.testCase_id) CiTestObj.desc = test.findtext('desc') + HTML.Setdesc(CiTestObj.desc) action = test.findtext('class') if (CheckClassValidity(action, id) == False): continue @@ -4705,6 +3673,10 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re elif action == 'WaitEndBuild_eNB': RAN.WaitBuildeNBisFinished() elif action == 'Initialize_eNB': + check_eNB = False + check_OAI_UE = False + RAN.SetpStatus(CiTestObj.CheckProcessExist(check_eNB, check_OAI_UE)) + RAN.InitializeeNB() elif action == 'Terminate_eNB': RAN.TerminateeNB() @@ -4767,13 +3739,13 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re else: sys.exit('Invalid action') CiTestObj.FailReportCnt += 1 - if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: + if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)') - CiTestObj.CreateHtmlTabFooter(False) + HTML.CreateHtmlTabFooter(False) sys.exit('Failed Scenario') else: logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') - CiTestObj.CreateHtmlTabFooter(True) + HTML.CreateHtmlTabFooter(True) else: GenericHelp(Version) sys.exit('Invalid mode') diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 2145557343..17461884e9 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -11,11 +11,47 @@ from multiprocessing import Process, Lock, SimpleQueue #----------------------------------------------------------- # OAI Testing modules #----------------------------------------------------------- -import sshconnection as mySSH -#from sshconnection import mySSHConnection as mySSH +import sshconnection as SSH +import epc import helpreadme as HELP import constants as CONST +import html as HTML +EPC = epc.EPCManagement() + +ALL_PROCESSES_OK = CONST.ALL_PROCESSES_OK +ENB_PROCESS_FAILED = CONST.ENB_PROCESS_FAILED +ENB_PROCESS_OK = CONST.ENB_PROCESS_OK +ENB_PROCESS_SEG_FAULT = CONST.ENB_PROCESS_SEG_FAULT +ENB_PROCESS_ASSERTION = CONST.ENB_PROCESS_ASSERTION +ENB_PROCESS_REALTIME_ISSUE = CONST.ENB_PROCESS_REALTIME_ISSUE +ENB_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE +ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED +HSS_PROCESS_FAILED = CONST.HSS_PROCESS_FAILED +HSS_PROCESS_OK = CONST.HSS_PROCESS_OK +MME_PROCESS_FAILED = CONST.MME_PROCESS_FAILED +MME_PROCESS_OK = CONST.MME_PROCESS_OK +SPGW_PROCESS_FAILED = CONST.SPGW_PROCESS_FAILED +SPGW_PROCESS_OK = CONST.SPGW_PROCESS_OK +UE_IP_ADDRESS_ISSUE = CONST.UE_IP_ADDRESS_ISSUE +OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE +OAI_UE_PROCESS_COULD_NOT_SYNC = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC +OAI_UE_PROCESS_ASSERTION = CONST.OAI_UE_PROCESS_ASSERTION +OAI_UE_PROCESS_FAILED = CONST.OAI_UE_PROCESS_FAILED +OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE +OAI_UE_PROCESS_SEG_FAULT = CONST.OAI_UE_PROCESS_SEG_FAULT +OAI_UE_PROCESS_OK = CONST.OAI_UE_PROCESS_OK + +UE_STATUS_DETACHED = CONST.UE_STATUS_DETACHED +UE_STATUS_DETACHING = CONST.UE_STATUS_DETACHING +UE_STATUS_ATTACHING = CONST.UE_STATUS_ATTACHING +UE_STATUS_ATTACHED = CONST.UE_STATUS_ATTACHED + +X2_HO_REQ_STATE__IDLE = CONST.X2_HO_REQ_STATE__IDLE +X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ +X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE +X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ +X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK #----------------------------------------------------------- # Class Declaration @@ -45,7 +81,7 @@ class RANManagement(): #self.ADBUserName = '' #self.ADBPassword = '' #self.ADBCentralized = True - #self.testCase_id = '' + self.testCase_id = '' #self.testXMLfiles = [] #self.nbTestXMLfiles = 0 #self.desc = '' @@ -110,12 +146,19 @@ class RANManagement(): #self.Build_OAI_UE_args = '' #self.Initialize_OAI_UE_args = '' #self.clean_repository = True - #self.flexranCtrlInstalled = False - #self.flexranCtrlStarted = False + self.flexranCtrlInstalled = False + self.flexranCtrlStarted = False #self.expectedNbOfConnectedUEs = 0 #self.startTime = 0 - + def SettestCase_id(self,tcid): + self.testCase_id = tcid + def SetflexranCtrlInstalled(self,fxrctin): + self.flexranCtrlInstalled = fxrctin + def SetflexranCtrlStarted(self,fxrctst): + self.flexranCtrlStarted = fxrctst + def SetpStatus(self, pSt): + self.pStatus = pSt def SetranRepository(self, repository): self.ranRepository = repository def GetranRepository(self): @@ -241,14 +284,22 @@ class RANManagement(): def GeteNB2SourceCodePath(self): return self.eNB2SourceCodePath + def SetprematureExit(self, premex): + self.prematureExit = premex + def GetprematureExit(self): + return self.prematureExit def BuildeNB(self): + myHTML = HTML.HTMLManagement() if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': GenericHelp(Version) sys.exit('Insufficient Parameter') if self.eNB_serverId == '0': + #checkpoint enB_serverId lIpAddr = self.eNBIPAddress + print(self.eNBIPAddress + 'self.eNBIPAddress') + print(lIpAddr + 'lIpAddr') lUserName = self.eNBUserName lPassWord = self.eNBPassword lSourcePath = self.eNBSourceCodePath @@ -262,11 +313,12 @@ class RANManagement(): lUserName = self.eNB2UserName lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath + print(lIpAddr + 'just before the error') if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') mySSH = SSH.SSHConnection() - mySSH.open(lIpAddr, lUserName, lPassWord) + mySSH.open(lIpAddr, lUserName, lPassWord) # Check if we build an 5G-NR gNB or an LTE eNB result = re.search('--gNB', self.Build_eNB_args) if result is not None: @@ -316,7 +368,7 @@ class RANManagement(): mismatch = True if not mismatch: mySSH.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) return mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) @@ -342,7 +394,7 @@ class RANManagement(): mySSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) mySSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) mySSH.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id return mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) @@ -369,7 +421,7 @@ class RANManagement(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - mySSH = SSH.SSHConnection() + mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) count = 40 buildOAIprocess = True @@ -384,8 +436,9 @@ class RANManagement(): self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): + myHTML = HTML.HTMLManagement() mySSH = SSH.SSHConnection() - mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) + mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) mySSH.command('ls ran_build/build', '\$', 3) mySSH.command('ls ran_build/build', '\$', 3) if self.air_interface == 'nr': @@ -432,15 +485,16 @@ class RANManagement(): if buildStatus: logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) else: logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) - self.CreateHtmlTabFooter(False) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) + myHTML.CreateHtmlTabFooter(False) sys.exit(1) def InitializeeNB(self): + myHTML = HTML.HTMLManagement() if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress lUserName = self.eNBUserName @@ -459,13 +513,13 @@ class RANManagement(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - mySSH = SSH.SSHConnection() - check_eNB = False - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) + mySSH = SSH.SSHConnection() + #check_eNB = False + #check_OAI_UE = False + #pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (self.pStatus < 0): + myHTML.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', self.pStatus) + myHTML.CreateHtmlTabFooter(False) sys.exit(1) # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB result = re.search('T_stdout', str(self.Initialize_eNB_args)) @@ -476,7 +530,7 @@ class RANManagement(): if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - EPC.Get_PcapFileName() = 'enb_' + self.testCase_id + '_s1log.pcap' + EPC.Set_PcapFileName('enb_' + self.testCase_id + '_s1log.pcap') mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.Get_PcapFileName() , '\$', 5) mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.Get_PcapFileName() + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) mySSH.close() @@ -566,7 +620,7 @@ class RANManagement(): mySSH.close() doLoop = False logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: @@ -616,7 +670,7 @@ class RANManagement(): self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) mySSH.close() - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') @@ -640,7 +694,7 @@ class RANManagement(): lIpAddr = self.eNBIPAddress lUserName = self.eNBUserName lPassWord = self.eNBPassword - mySSH = SSH.SSHConnection() + mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-softmodem | grep -v grep', '\$', 5) result = re.search(self.air_interface + '-softmodem', mySSH.getBefore()) @@ -656,6 +710,7 @@ class RANManagement(): def TerminateeNB(self): + myHTML = HTML.HTMLManagement() if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress lUserName = self.eNBUserName @@ -674,7 +729,7 @@ class RANManagement(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - mySSH = SSH.SSHConnection() + mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) if self.air_interface == 'lte': @@ -721,7 +776,7 @@ class RANManagement(): mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.eNBLogFiles[int(self.eNB_instance)] = '' else: analyzeFile = False @@ -734,7 +789,7 @@ class RANManagement(): if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + myHTML.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) self.eNBmbmsEnables[int(self.eNB_instance)] = False return if self.eNB_serverId != '0': @@ -742,20 +797,20 @@ class RANManagement(): logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) if (logStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', logStatus) + myHTML.CreateHtmlTestRow('N/A', 'KO', logStatus) self.preamtureExit = True self.eNBmbmsEnables[int(self.eNB_instance)] = False return else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBstatuses[int(self.eNB_instance)] = -1 def LogCollecteNB(self): - mySSH = SSH.SSHConnection() + mySSH = SSH.SSHConnection() mySSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) mySSH.command('cd ' + self.eNBSourceCodePath, '\$', 5) mySSH.command('cd cmake_targets', '\$', 5) @@ -763,3 +818,260 @@ class RANManagement(): mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) mySSH.close() + + + def AnalyzeLogFile_eNB(self, eNBlogFile): + if (not os.path.isfile('./' + eNBlogFile)): + return -1 + enb_log_file = open('./' + eNBlogFile, 'r') + exitSignalReceived = False + foundAssertion = False + msgAssertion = '' + msgLine = 0 + foundSegFault = False + foundRealTimeIssue = False + rrcSetupComplete = 0 + rrcReleaseRequest = 0 + rrcReconfigRequest = 0 + rrcReconfigComplete = 0 + rrcReestablishRequest = 0 + rrcReestablishComplete = 0 + rrcReestablishReject = 0 + rlcDiscardBuffer = 0 + rachCanceledProcedure = 0 + uciStatMsgCount = 0 + pdcpFailure = 0 + ulschFailure = 0 + cdrxActivationMessageCount = 0 + dropNotEnoughRBs = 0 + mbmsRequestMsg = 0 + self.htmleNBFailureMsg = '' + isRRU = False + isSlave = False + slaveReceivesFrameResyncCmd = False + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures = 0 + X2HO_outNbProcedures = 0 + for line in enb_log_file.readlines(): + if X2HO_state == X2_HO_REQ_STATE__IDLE: + result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ + result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK + if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: + result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE + if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: + result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ + if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: + result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_inNbProcedures += 1 + if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: + result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) + if result is not None: + X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_outNbProcedures += 1 + + if self.eNBOptions[int(self.eNB_instance)] != '': + res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) + res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) + if res1 is not None and res2 is not None: + requested_option = int(res1.group('requested_option')) + applied_option = int(res2.group('applied_option')) + if requested_option == applied_option: + self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + else: + self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + result = re.search('Exiting OAI softmodem', str(line)) + if result is not None: + exitSignalReceived = True + result = re.search('[Ss]egmentation [Ff]ault', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('./ran_build/build/lte-softmodem', str(line)) + if result is not None and not exitSignalReceived: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None and not exitSignalReceived: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None and not exitSignalReceived: + foundRealTimeIssue = True + if foundAssertion and (msgLine < 3): + msgLine += 1 + msgAssertion += str(line) + result = re.search('Setting function for RU', str(line)) + if result is not None: + isRRU = True + if isRRU: + result = re.search('RU 0 is_slave=yes', str(line)) + if result is not None: + isSlave = True + if isSlave: + result = re.search('Received RRU_frame_resynch command', str(line)) + if result is not None: + slaveReceivesFrameResyncCmd = True + result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) + if result is not None: + rrcSetupComplete += 1 + result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) + if result is not None: + rrcReleaseRequest += 1 + result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) + if result is not None: + rrcReconfigRequest += 1 + result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) + if result is not None: + rrcReconfigComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) + if result is not None: + rrcReestablishRequest += 1 + result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) + if result is not None: + rrcReestablishComplete += 1 + result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) + if result is not None: + rrcReestablishReject += 1 + result = re.search('CDRX configuration activated after RRC Connection', str(line)) + if result is not None: + cdrxActivationMessageCount += 1 + result = re.search('uci->stat', str(line)) + if result is not None: + uciStatMsgCount += 1 + result = re.search('PDCP.*Out of Resources.*reason', str(line)) + if result is not None: + pdcpFailure += 1 + result = re.search('ULSCH in error in round', str(line)) + if result is not None: + ulschFailure += 1 + result = re.search('BAD all_segments_received', str(line)) + if result is not None: + rlcDiscardBuffer += 1 + result = re.search('Canceled RA procedure for UE rnti', str(line)) + if result is not None: + rachCanceledProcedure += 1 + result = re.search('dropping, not enough RBs', str(line)) + if result is not None: + dropNotEnoughRBs += 1 + if self.eNBmbmsEnables[int(self.eNB_instance)]: + result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line)) + if result is not None: + mbmsRequestMsg += 1 + enb_log_file.close() + logging.debug(' File analysis completed') + self.htmleNBFailureMsg = '' + if self.air_interface() == 'lte': + nodeB_prefix = 'e' + else: + nodeB_prefix = 'g' + if uciStatMsgCount > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if pdcpFailure > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if ulschFailure > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if dropNotEnoughRBs > 0: + statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmleNBFailureMsg += statMsg + '\n' + if rrcSetupComplete > 0: + rrcMsg = nodeB_prefix + 'NB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcSetupComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReleaseRequest > 0: + rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: + rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: + rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if self.eNBmbmsEnables[int(self.eNB_instance)]: + if mbmsRequestMsg > 0: + rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_inNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if X2HO_outNbProcedures > 0: + rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if self.eNBOptions[int(self.eNB_instance)] != '': + res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) + if res1 is not None: + if cdrxActivationMessageCount > 0: + rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' + logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + else: + rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' + logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rrcMsg + '\n' + if rachCanceledProcedure > 0: + rachMsg = nodeB_prefix + 'NB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' + logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rachMsg + '\n' + if isRRU: + if isSlave: + if slaveReceivesFrameResyncCmd: + rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + else: + rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' + logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rruMsg + '\n' + self.prematureExit(True) + return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED + if foundSegFault: + logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m') + return ENB_PROCESS_SEG_FAULT + if foundAssertion: + logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m') + self.htmleNBFailureMsg += msgAssertion + return ENB_PROCESS_ASSERTION + if foundRealTimeIssue: + logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') + self.htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' + #return ENB_PROCESS_REALTIME_ISSUE + if rlcDiscardBuffer > 0: + rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' + logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') + self.htmleNBFailureMsg += rlcMsg + '\n' + return ENB_PROCESS_REALTIME_ISSUE + return 0 diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index 6103bf4f0f..df1ada4834 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -3,7 +3,8 @@ #----------------------------------------------------------- import pexpect # pexpect import logging - +import time # sleep +import re #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- @@ -69,7 +70,7 @@ class SSHConnection(): logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') logging.debug('Expected Line : ' + expectedline) logging.debug(str(self.ssh.before)) - sys.exit(self.sshresponse) + sys.exit(self.sshresponse) elif self.sshresponse == 2: logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') logging.debug('Expected Line : ' + expectedline) diff --git a/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml index 680f09c435..611492b0bc 100644 --- a/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml +++ b/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml @@ -24,7 +24,7 @@ test-lte-m-10-tm1 Test-LTE-M-10MHz-TM1 tasks - 2 + 1 030201 040102 diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_simple_test.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_simple_test.xml new file mode 100644 index 0000000000..8d813a8e2c --- /dev/null +++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_simple_test.xml @@ -0,0 +1,189 @@ + + + test-x2-ho-05-tm1 + Test-X2-HO-FDD-05MHz-TM1 + tasks + 1 + + 030201 + 040101 + 030101 040301 040501 040401 040201 030201 + + + + + IdleSleep + Waiting for 60 seconds + 60 + + + + IdleSleep + Waiting for 10 seconds + 10 + + + + Initialize_FlexranCtrl + Starting Flexran Controller + + + + Terminate_FlexranCtrl + Stopping Flexran Controller + + + + Initialize_eNB + Initialize Master eNB (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf --eNBs.[0].enable_x2 no + 0 + 0 + + + + Initialize_eNB + Initialize Slave eNB (FDD/Band7/5MHz) + -O ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf + 1 + 1 + + + + Terminate_eNB + Terminate Master eNB + 0 + 0 + + + + Terminate_eNB + Terminate Slave eNB + 1 + 1 + + + + Initialize_UE + Initialize UE + + + + Terminate_UE + Terminate UE + + + + Attach_UE + Attach UE + + + + Detach_UE + Detach UE + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Ping + ping (5MHz - 20 sec) + -c 20 + 5 + + + + Iperf + iperf (5MHz - DL/8Mbps/UDP)(30 sec) + -u -b 8M -t 30 -i 1 + 50 + single-ue + + + + Iperf + iperf (5MHz - DL/8Mbps/UDP)(30 sec) + -u -b 8M -t 30 -i 1 + 50 + single-ue + + + + Iperf + iperf (5MHz - DL/8Mbps/UDP)(30 sec) + -u -b 8M -t 30 -i 1 + 50 + single-ue + + + + Iperf + iperf (5MHz - UL/5Mbps/UDP)(30 sec) + -u -b 5M -t 30 -i 1 -R + 50 + single-ue + + + + Iperf + iperf (5MHz - UL/5Mbps/UDP)(30 sec) + -u -b 5M -t 30 -i 1 -R + 50 + single-ue + + + + Iperf + iperf (5MHz - UL/5Mbps/UDP)(30 sec) + -u -b 5M -t 30 -i 1 -R + 50 + single-ue + + + + Perform_X2_Handover + Doing a Flexran-Controlled X2 Handover + network + + + + Perform_X2_Handover + Doing a Flexran-Controlled X2 Handover + network + + + From 6aa64bd2864af9af9c67b85295946d3f7dd313a7 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 17 Mar 2020 08:24:13 +0100 Subject: [PATCH 104/175] to switch to develop --- ci-scripts/epc.py | 64 +++++++++-- ci-scripts/helpreadme.py | 30 +++++ ci-scripts/html.py | 206 +++++++++++++--------------------- ci-scripts/main_enb.py | 180 +++++++++--------------------- ci-scripts/ran.py | 213 +++++++++++++----------------------- ci-scripts/sshconnection.py | 31 ++++++ 6 files changed, 320 insertions(+), 404 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 4f283f530e..4d88a69e75 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -1,3 +1,33 @@ +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + + #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -14,22 +44,28 @@ from multiprocessing import Process, Lock, SimpleQueue # OAI Testing modules #----------------------------------------------------------- import sshconnection as SSH -#from sshconnection import SSHConnection as SSH import helpreadme as HELP import constants as CONST +import html as HTML #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class EPCManagement(): + def __init__(self): - self.EPCIPAddress = '' - self.EPCUserName = '' - self.EPCPassword = '' - self.EPCSourceCodePath = '' - self.EPCType = '' + + self.IPAddress = '' + self.UserName = '' + self.Password = '' + self.SourceCodePath = '' + self.Type = '' self.EPC_PcapFileName = '' +#----------------------------------------------------------- +# Setter and Getters +#----------------------------------------------------------- + def SetIPAddress(self, ipaddress): self.EPCIPAddress = ipaddress def GetIPAddress(self): @@ -55,6 +91,10 @@ class EPCManagement(): def Get_PcapFileName(self): return self.EPC_PcapFileName +#----------------------------------------------------------- +# EPC management functions +#----------------------------------------------------------- + def InitializeHSS(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': HELP.GenericHelp(Version) @@ -91,7 +131,7 @@ class EPCManagement(): else: logging.error('This option should not occur!') mySSH.close() - #self.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) def InitializeMME(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': @@ -124,7 +164,7 @@ class EPCManagement(): else: logging.error('This option should not occur!') mySSH.close() - #self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def InitializeSPGW(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': @@ -155,7 +195,7 @@ class EPCManagement(): else: logging.error('This option should not occur!') mySSH.close() - #self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) def CheckHSSProcess(self, status_queue): @@ -255,7 +295,7 @@ class EPCManagement(): else: logging.error('This should not happen!') mySSH.close() - #self.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateMME(self): mySSH = SSH.SSHConnection() @@ -274,7 +314,7 @@ class EPCManagement(): else: logging.error('This should not happen!') mySSH.close() - #self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) def TerminateSPGW(self): mySSH = SSH.SSHConnection() @@ -305,7 +345,7 @@ class EPCManagement(): else: logging.error('This should not happen!') mySSH.close() - #self.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def LogCollectHSS(self): diff --git a/ci-scripts/helpreadme.py b/ci-scripts/helpreadme.py index 294454e270..307ab4ff31 100644 --- a/ci-scripts/helpreadme.py +++ b/ci-scripts/helpreadme.py @@ -1,3 +1,33 @@ +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + + #----------------------------------------------------------- # Functions Declaration #----------------------------------------------------------- diff --git a/ci-scripts/html.py b/ci-scripts/html.py index 80ad46f51e..e8930f6e2c 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -1,3 +1,32 @@ +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + #----------------------------------------------------------- # Import @@ -10,117 +39,24 @@ import time import subprocess from multiprocessing import Process, Lock, SimpleQueue -#----------------------------------------------------------- -# OAI Testing modules -#----------------------------------------------------------- -#import main_enb -#MAIN = main_enb.OaiCiTest() - - #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class HTMLManagement(): + def __init__(self): - # self.FailReportCnt = 0 - # self.prematureExit = False - self.ranRepository = '' - self.ranBranch = '' - self.ranAllowMerge = False - self.ranCommitID = '' - self.ranTargetBranch = '' - #self.eNBIPAddress = '' - #self.eNBUserName = '' - #self.eNBPassword = '' - #self.eNBSourceCodePath = '' - #self.eNB1IPAddress = '' - #self.eNB1UserName = '' - #self.eNB1Password = '' - #self.eNB1SourceCodePath = '' - #self.eNB2IPAddress = '' - #self.eNB2UserName = '' - #self.eNB2Password = '' - #self.eNB2SourceCodePath = '' - #self.ADBIPAddress = '' - #self.ADBUserName = '' - #self.ADBPassword = '' - #self.ADBCentralized = True - #self.testCase_id = '' - self.testXMLfiles = [] - self.nbTestXMLfiles = 0 - #self.desc = '' - #self.Build_eNB_args = '' - #self.backgroundBuild = False - #self.backgroundBuildTestId = ['', '', ''] - #self.Build_eNB_forced_workspace_cleanup = False - #self.Initialize_eNB_args = '' - #self.air_interface = 'lte' - #self.eNB_instance = '' - #self.eNB_serverId = '' - #self.eNBLogFiles = ['', '', ''] - #self.eNBOptions = ['', '', ''] - #self.eNBmbmsEnables = [False, False, False] - #self.eNBstatuses = [-1, -1, -1] - #self.ping_args = '' - #self.ping_packetloss_threshold = '' - #self.iperf_args = '' - #self.iperf_packetloss_threshold = '' - #self.iperf_profile = '' - #self.iperf_options = '' - #self.nbMaxUEtoAttach = -1 - #self.UEDevices = [] - #self.UEDevicesStatus = [] - #self.UEDevicesRemoteServer = [] - #self.UEDevicesRemoteUser = [] - #self.UEDevicesOffCmd = [] - #self.UEDevicesOnCmd = [] - #self.UEDevicesRebootCmd = [] - #self.CatMDevices = [] - #self.UEIPAddresses = [] - self.htmlFile = '' - self.htmlHeaderCreated = False - self.htmlFooterCreated = False - self.htmlUEConnected = -1 - self.htmlNb_Smartphones = 0 - self.htmlNb_CATM_Modules = 0 - self.htmleNBFailureMsg = '' - self.htmlUEFailureMsg = '' - #self.picocom_closure = False - #self.idle_sleep_time = 0 - #self.x2_ho_options = 'network' - #self.x2NbENBs = 0 - #self.x2ENBBsIds = [] - #self.x2ENBConnectedUEs = [] + self.htmlTabRefs = [] self.htmlTabNames = [] self.htmlTabIcons = [] - #self.repeatCounts = [] - #self.finalStatus = False - #self.OsVersion = '' - #self.KernelVersion = '' - #self.UhdVersion = '' - #self.UsrpBoard = '' - #self.CpuNb = '' - #self.CpuModel = '' - #self.CpuMHz = '' - #self.UEIPAddress = '' - #self.UEUserName = '' - #self.UEPassword = '' - #self.UE_instance = '' - #self.UESourceCodePath = '' - #self.UELogFile = '' - #self.Build_OAI_UE_args = '' - #self.Initialize_OAI_UE_args = '' - #self.clean_repository = True - #self.flexranCtrlInstalled = False - #self.flexranCtrlStarted = False - #self.expectedNbOfConnectedUEs = 0 - #self.startTime = 0 - - + self.testXMLfiles = [] #----------------------------------------------------------- -# HTML Reporting.... +# Setters and Getters #----------------------------------------------------------- + def SetreseNB(self,rsenb): + self.reseNB = rsenb + def SetresUE(self,rsue): + self.resUE = rsue def Setdesc(self, dsc): self.desc = dsc @@ -157,11 +93,6 @@ class HTMLManagement(): self.ranTargetBranch = tbranch def GetranTargetBranch(self): return self.ranTargetBranch - -# def SetADBIPAddress(self, adbip): -# self.ADBIPAddress = adbip -# def GetADBIPAddress(self): -# return self.ADBIPAddress def SethtmlUEConnected(self, nbUEs): self.htmlUEConnected = nbUEs @@ -187,6 +118,12 @@ class HTMLManagement(): def SethtmlTabIcons(self, tabIcon): self.htmlTabIcons.append(tabIcon) + +#----------------------------------------------------------- +# HTML structure creation functions +#----------------------------------------------------------- + + def CreateHtmlHeader(self, ADBIPAddress): if (not self.htmlHeaderCreated): logging.debug('\u001B[1m----------------------------------------\u001B[0m') @@ -270,15 +207,9 @@ class HTMLManagement(): self.htmlFile.write(' \n') if (ADBIPAddress != 'none'): - #terminate_ue_flag = True - #MAIN.GetAllUEDevices(terminate_ue_flag) - #self.GetAllCatMDevices(terminate_ue_flag) - #self.htmlUEConnected = len(self.UEDevices) self.htmlFile.write('

' + str(self.htmlNb_Smartphones) + ' UE(s) is(are) connected to ADB bench server

\n') self.htmlFile.write('

' + str(self.htmlNb_CATM_Modules) + ' CAT-M UE(s) is(are) connected to bench server

\n') else: - #self.UEDevices.append('OAI-UE') - #self.htmlUEConnected = len(self.UEDevices) self.htmlUEConnected = 1 self.htmlFile.write('

1 OAI UE(s) is(are) connected to CI bench

\n') self.htmlFile.write('
\n') @@ -316,14 +247,6 @@ class HTMLManagement(): self.htmlFile.write(' Test Desc\n') self.htmlFile.write(' Test Options\n') self.htmlFile.write(' Test Status\n') - #if (self.htmlUEConnected == -1): - # terminate_ue_flag = True - # if (self.ADBIPAddress != 'none'): - # self.GetAllUEDevices(terminate_ue_flag) - # self.GetAllCatMDevices(terminate_ue_flag) - # else: - # self.UEDevices.append('OAI-UE') - # self.htmlUEConnected = len(self.UEDevices) i = 0 while (i < self.htmlUEConnected): @@ -366,14 +289,41 @@ class HTMLManagement(): self.htmlFile.write('

\n') self.htmlFile.write(' \n') - machines = [ 'eNB', 'UE' ] - for machine in machines: - #This needs to move back to main and be called before CreateHtmlFooter - res = self.RetrieveSystemVersion(machine) - if res == -1: - continue + # GP machines = [ 'eNB', 'UE' ] + # GP for machine in machines: + #GP This needs to move back to main and be called before CreateHtmlFooter + + res = self.reseNB + if res != -1: self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') + + + res = self.resUE + if res != -1: + self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') @@ -410,8 +360,6 @@ class HTMLManagement(): self.htmlFile.write('\n') self.htmlFile.close() - #FailReportCnt should be passed as a parameter of CreateHtmlRetrySeparator method - # no need for a setter and be a member of html class def CreateHtmlRetrySeparator(self, cntnumfails): if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): self.htmlFile = open('test_results.html', 'a') diff --git a/ci-scripts/main_enb.py b/ci-scripts/main_enb.py index 340aaed9b3..a42aba76e2 100644 --- a/ci-scripts/main_enb.py +++ b/ci-scripts/main_enb.py @@ -35,43 +35,6 @@ import constants as CONST #----------------------------------------------------------- Version = '0.1' -#----------------------------------------------------------- -# Constants -#----------------------------------------------------------- -ALL_PROCESSES_OK = CONST.ALL_PROCESSES_OK -ENB_PROCESS_FAILED = CONST.ENB_PROCESS_FAILED -ENB_PROCESS_OK = CONST.ENB_PROCESS_OK -ENB_PROCESS_SEG_FAULT = CONST.ENB_PROCESS_SEG_FAULT -ENB_PROCESS_ASSERTION = CONST.ENB_PROCESS_ASSERTION -ENB_PROCESS_REALTIME_ISSUE = CONST.ENB_PROCESS_REALTIME_ISSUE -ENB_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE -ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED -HSS_PROCESS_FAILED = CONST.HSS_PROCESS_FAILED -HSS_PROCESS_OK = CONST.HSS_PROCESS_OK -MME_PROCESS_FAILED = CONST.MME_PROCESS_FAILED -MME_PROCESS_OK = CONST.MME_PROCESS_OK -SPGW_PROCESS_FAILED = CONST.SPGW_PROCESS_FAILED -SPGW_PROCESS_OK = CONST.SPGW_PROCESS_OK -UE_IP_ADDRESS_ISSUE = CONST.UE_IP_ADDRESS_ISSUE -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE -OAI_UE_PROCESS_COULD_NOT_SYNC = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC -OAI_UE_PROCESS_ASSERTION = CONST.OAI_UE_PROCESS_ASSERTION -OAI_UE_PROCESS_FAILED = CONST.OAI_UE_PROCESS_FAILED -OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE -OAI_UE_PROCESS_SEG_FAULT = CONST.OAI_UE_PROCESS_SEG_FAULT -OAI_UE_PROCESS_OK = CONST.OAI_UE_PROCESS_OK - -UE_STATUS_DETACHED = CONST.UE_STATUS_DETACHED -UE_STATUS_DETACHING = CONST.UE_STATUS_DETACHING -UE_STATUS_ATTACHING = CONST.UE_STATUS_ATTACHING -UE_STATUS_ATTACHED = CONST.UE_STATUS_ATTACHED - -X2_HO_REQ_STATE__IDLE = CONST.X2_HO_REQ_STATE__IDLE -X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ -X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE -X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ -X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -91,36 +54,14 @@ logging.basicConfig( format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" ) + #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class OaiCiTest(): + def __init__(self): self.FailReportCnt = 0 - self.prematureExit = False - #self.ranRepository = '' - #self.ranBranch = '' - #RAN.GetranAllowMerge() = False - #self.ranCommitID = '' - #RAN.GetranTargetBranch() = '' - #self.eNBIPAddress = '' - #self.eNBUserName = '' - #self.eNBPassword = '' - #RAN.GeteNBSourceCodePath() = '' - #self.EPCIPAddress = '' - #self.EPCUserName = '' - #self.EPCPassword = '' - #self.eNB1IPAddress = '' - #self.eNB1UserName = '' - #self.eNB1Password = '' - #self.eNB1SourceCodePath = '' - #self.eNB2IPAddress = '' - #self.eNB2UserName = '' - #self.eNB2Password = '' - #self.eNB2SourceCodePath = '' - #self.EPCSourceCodePath = '' - #self.EPCType = '' - #self.EPC_PcapFileName = '' self.ADBIPAddress = '' self.ADBUserName = '' self.ADBPassword = '' @@ -129,18 +70,6 @@ class OaiCiTest(): self.testXMLfiles = [] self.nbTestXMLfiles = 0 self.desc = '' - #RAN.GetBuild_eNB_args() = '' - #self.backgroundBuild = False - #self.backgroundBuildTestId = ['', '', ''] - #self.Build_eNB_forced_workspace_cleanup = False - #RAN.GetInitialize_eNB_args() = '' - self.air_interface = 'lte' - #self.eNB_instance = '' - #self.eNB_serverId = '' - #self.eNBLogFiles = ['', '', ''] - #self.eNBOptions = ['', '', ''] - #self.eNBmbmsEnables = [False, False, False] - #self.eNBstatuses = [-1, -1, -1] self.ping_args = '' self.ping_packetloss_threshold = '' self.iperf_args = '' @@ -169,9 +98,6 @@ class OaiCiTest(): self.x2NbENBs = 0 self.x2ENBBsIds = [] self.x2ENBConnectedUEs = [] - #self.htmlTabRefs = [] - #self.htmlTabNames = [] - #self.htmlTabIcons = [] self.repeatCounts = [] self.finalStatus = False self.OsVersion = '' @@ -246,7 +172,7 @@ class OaiCiTest(): mismatch = True if not mismatch: SSH.close() - HTML.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', CONST.ALL_PROCESSES_OK) return SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) @@ -291,11 +217,11 @@ class OaiCiTest(): else: SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) SSH.close() - HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', CONST.ALL_PROCESSES_OK, 'OAI UE') else: SSH.close() logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') - HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', CONST.ALL_PROCESSES_OK, 'OAI UE') HTML.CreateHtmlTabFooter(False) sys.exit(1) @@ -330,7 +256,7 @@ class OaiCiTest(): self.flexranCtrlStarted = True RAN.SetflexranCtrlStarted(True) SSH.close() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def InitializeUE_common(self, device_id, idx): try: @@ -393,7 +319,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def InitializeOAIUE(self): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': @@ -551,23 +477,23 @@ class OaiCiTest(): SSH.close() if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', CONST.ALL_PROCESSES_OK, 'OAI UE') logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') if (self.ADBIPAddress != 'none'): self.UEDevices = [] self.UEDevices.append('OAI-UE') self.UEDevicesStatus = [] - self.UEDevicesStatus.append(UE_STATUS_DETACHED) + self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) else: if RAN.Getair_interface() == 'lte': if RAN.GeteNBmbmsEnables[0]: self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' else: self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') else: self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') logging.error('\033[91mInitialize OAI UE Failed! \033[0m') self.AutoTerminateUEandeNB() @@ -620,7 +546,7 @@ class OaiCiTest(): # Force closure of picocom but device might still be locked SSH.close() self.picocom_closure = False - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() def TerminateCatM(self): @@ -641,7 +567,7 @@ class OaiCiTest(): logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') SSH.close() self.picocom_closure = False - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() def AttachCatM(self): @@ -902,7 +828,7 @@ class OaiCiTest(): nb_ue_to_connect = 0 for device_id in self.UEDevices: if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): - self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING + self.UEDevicesStatus[nb_ue_to_connect] = CONST.UE_STATUS_ATTACHING p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) p.daemon = True p.start() @@ -912,7 +838,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - HTML.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() return else: @@ -932,8 +858,8 @@ class OaiCiTest(): if (attach_status): cnt = 0 while cnt < len(self.UEDevices): - if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: - self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED + if self.UEDevicesStatus[cnt] == CONST.UE_STATUS_ATTACHING: + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_ATTACHED cnt += 1 HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) @@ -973,7 +899,7 @@ class OaiCiTest(): multi_jobs = [] cnt = 0 for device_id in self.UEDevices: - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHING p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) p.daemon = True p.start() @@ -981,14 +907,14 @@ class OaiCiTest(): cnt += 1 for job in multi_jobs: job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) if result is not None: logging.debug('Waiting 5 seconds to fill up record file') time.sleep(5) cnt = 0 while cnt < len(self.UEDevices): - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHED cnt += 1 def RebootUE_common(self, device_id): @@ -1049,7 +975,7 @@ class OaiCiTest(): multi_jobs.append(p) for job in multi_jobs: job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def DataDisableUE_common(self, device_id, idx): try: @@ -1078,7 +1004,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def DataEnableUE_common(self, device_id, idx): try: @@ -1107,7 +1033,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def GetAllUEDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': @@ -1152,7 +1078,7 @@ class OaiCiTest(): print('len(self.UEDevicesStatus) == 0') cnt = 0 while cnt < len(self.UEDevices): - self.UEDevicesStatus.append(UE_STATUS_DETACHED) + self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) cnt += 1 def GetAllCatMDevices(self, terminate_ue_flag): @@ -1272,7 +1198,7 @@ class OaiCiTest(): htmlOptions = 'N/A' if (status_queue.empty()): - HTML.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(htmlOptions, 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: check_status = True @@ -1319,8 +1245,8 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) idx = 0 for device_id in self.UEDevices: - print('UE status attched'+UE_STATUS_ATTACHED) - if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: + print('UE status attched'+CONST.UE_STATUS_ATTACHED) + if self.UEDevicesStatus[idx] != CONST.UE_STATUS_ATTACHED: idx += 1 continue count = 0 @@ -1563,7 +1489,7 @@ class OaiCiTest(): return ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return multi_jobs = [] @@ -1581,7 +1507,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: ping_status = True @@ -1998,7 +1924,7 @@ class OaiCiTest(): if (device_id != 'OAI-UE'): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + EPC.GetSourceCodePath() + '/scripts ; fi', '\$', 5) SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) # Checking if iperf / iperf3 are installed if self.ADBCentralized: @@ -2306,7 +2232,7 @@ class OaiCiTest(): ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): logging.debug('going here') - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return @@ -2338,7 +2264,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: iperf_status = True @@ -2406,7 +2332,7 @@ class OaiCiTest(): status = status_queue.get() if (status < 0): result = status - if result == ENB_PROCESS_FAILED: + if result == CONST.ENB_PROCESS_FAILED: fileCheck = re.search('enb_', str(RAN.GeteNBLogFiles[0])) if fileCheck is not None: SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') @@ -2437,7 +2363,7 @@ class OaiCiTest(): status = status_queue.get() if (status < 0): result = status - if result == OAI_UE_PROCESS_FAILED: + if result == CONST.OAI_UE_PROCESS_FAILED: fileCheck = re.search('ue_', str(self.UELogFile)) if fileCheck is not None: SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') @@ -2453,9 +2379,9 @@ class OaiCiTest(): result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') - status_queue.put(OAI_UE_PROCESS_FAILED) + status_queue.put(CONST.OAI_UE_PROCESS_FAILED) else: - status_queue.put(OAI_UE_PROCESS_OK) + status_queue.put(CONST.OAI_UE_PROCESS_OK) SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -2688,31 +2614,31 @@ class OaiCiTest(): if foundSegFault: logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') if not nrUEFlag: - return OAI_UE_PROCESS_SEG_FAULT + return CONST.OAI_UE_PROCESS_SEG_FAULT else: if not frequency_found: - return OAI_UE_PROCESS_SEG_FAULT + return CONST.OAI_UE_PROCESS_SEG_FAULT if foundAssertion: logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') self.htmlUEFailureMsg += 'UE showed an assertion!\n' if not nrUEFlag: if not mib_found or not frequency_found: - return OAI_UE_PROCESS_ASSERTION + return CONST.OAI_UE_PROCESS_ASSERTION else: if not frequency_found: - return OAI_UE_PROCESS_ASSERTION + return CONST.OAI_UE_PROCESS_ASSERTION if foundRealTimeIssue: logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') self.htmlUEFailureMsg += 'UE faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE + #return CONST.ENB_PROCESS_REALTIME_ISSUE if nrUEFlag: if not frequency_found: - return OAI_UE_PROCESS_COULD_NOT_SYNC + return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC else: if no_cell_sync_found and not mib_found: logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') self.htmlUEFailureMsg += 'UE could not synchronize!\n' - return OAI_UE_PROCESS_COULD_NOT_SYNC + return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC return 0 @@ -2729,7 +2655,7 @@ class OaiCiTest(): time.sleep(1) SSH.close() self.flexranCtrlStarted = False - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateUE_common(self, device_id, idx): try: @@ -2772,7 +2698,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateOAIUE(self): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) @@ -2795,7 +2721,7 @@ class OaiCiTest(): if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - HTML.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') self.UELogFile = '' return logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') @@ -2812,20 +2738,20 @@ class OaiCiTest(): if RAN.Getair_interface() == 'lte': # In case of sniffing on commercial eNBs we have random results # Not an error then - if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): + if (logStatus != CONST.OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): self.Initialize_OAI_UE_args = '' self.AutoTerminateUEandeNB() else: - if (logStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + if (logStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC): self.Initialize_OAI_UE_args = '' self.AutoTerminateUEandeNB() else: logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.UELogFile = '' else: - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def AutoTerminateUEandeNB(self): if (self.ADBIPAddress != 'none'): @@ -2857,7 +2783,7 @@ class OaiCiTest(): def IdleSleep(self): time.sleep(self.idle_sleep_time) - HTML.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', CONST.ALL_PROCESSES_OK) def X2_Status(self, idx, fileName): cmd = "curl --silent http://" + EPC.GetIPAddress() + ":9999/stats | jq '.' > " + fileName @@ -2967,7 +2893,7 @@ class OaiCiTest(): html_queue.put(fullMessage) HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) else: - HTML.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', CONST.ALL_PROCESSES_OK) def LogCollectBuild(self): if (RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != ''): @@ -3548,6 +3474,8 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): HTML.SethtmlNb_CATM_Modules(len(CiTestObj.CatMDevices)) HTML.CreateHtmlHeader(CiTestObj.ADBIPAddress) elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): + HTML.SetreseNB(RetrieveSystemVersion('eNB')) + HTML.SetresUE(RetrieveSystemVersion('UE')) HTML.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 17461884e9..04c2e71c5f 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -1,3 +1,34 @@ + +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + + #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -19,47 +50,15 @@ import html as HTML EPC = epc.EPCManagement() -ALL_PROCESSES_OK = CONST.ALL_PROCESSES_OK -ENB_PROCESS_FAILED = CONST.ENB_PROCESS_FAILED -ENB_PROCESS_OK = CONST.ENB_PROCESS_OK -ENB_PROCESS_SEG_FAULT = CONST.ENB_PROCESS_SEG_FAULT -ENB_PROCESS_ASSERTION = CONST.ENB_PROCESS_ASSERTION -ENB_PROCESS_REALTIME_ISSUE = CONST.ENB_PROCESS_REALTIME_ISSUE -ENB_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE -ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED -HSS_PROCESS_FAILED = CONST.HSS_PROCESS_FAILED -HSS_PROCESS_OK = CONST.HSS_PROCESS_OK -MME_PROCESS_FAILED = CONST.MME_PROCESS_FAILED -MME_PROCESS_OK = CONST.MME_PROCESS_OK -SPGW_PROCESS_FAILED = CONST.SPGW_PROCESS_FAILED -SPGW_PROCESS_OK = CONST.SPGW_PROCESS_OK -UE_IP_ADDRESS_ISSUE = CONST.UE_IP_ADDRESS_ISSUE -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE -OAI_UE_PROCESS_COULD_NOT_SYNC = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC -OAI_UE_PROCESS_ASSERTION = CONST.OAI_UE_PROCESS_ASSERTION -OAI_UE_PROCESS_FAILED = CONST.OAI_UE_PROCESS_FAILED -OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE -OAI_UE_PROCESS_SEG_FAULT = CONST.OAI_UE_PROCESS_SEG_FAULT -OAI_UE_PROCESS_OK = CONST.OAI_UE_PROCESS_OK - -UE_STATUS_DETACHED = CONST.UE_STATUS_DETACHED -UE_STATUS_DETACHING = CONST.UE_STATUS_DETACHING -UE_STATUS_ATTACHING = CONST.UE_STATUS_ATTACHING -UE_STATUS_ATTACHED = CONST.UE_STATUS_ATTACHED - -X2_HO_REQ_STATE__IDLE = CONST.X2_HO_REQ_STATE__IDLE -X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ -X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE -X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ -X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class RANManagement(): + def __init__(self): - # self.FailReportCnt = 0 - # self.prematureExit = False + + self.prematureExit = False self.ranRepository = '' self.ranBranch = '' self.ranAllowMerge = False @@ -77,14 +76,6 @@ class RANManagement(): self.eNB2UserName = '' self.eNB2Password = '' self.eNB2SourceCodePath = '' - #self.ADBIPAddress = '' - #self.ADBUserName = '' - #self.ADBPassword = '' - #self.ADBCentralized = True - self.testCase_id = '' - #self.testXMLfiles = [] - #self.nbTestXMLfiles = 0 - #self.desc = '' self.Build_eNB_args = '' self.backgroundBuild = False self.backgroundBuildTestId = ['', '', ''] @@ -96,60 +87,11 @@ class RANManagement(): self.eNBLogFiles = ['', '', ''] self.eNBOptions = ['', '', ''] self.eNBmbmsEnables = [False, False, False] - self.eNBstatuses = [-1, -1, -1] - #self.ping_args = '' - #self.ping_packetloss_threshold = '' - #self.iperf_args = '' - #self.iperf_packetloss_threshold = '' - #self.iperf_profile = '' - #self.iperf_options = '' - #self.nbMaxUEtoAttach = -1 - #self.UEDevices = [] - #self.UEDevicesStatus = [] - #self.UEDevicesRemoteServer = [] - #self.UEDevicesRemoteUser = [] - #self.UEDevicesOffCmd = [] - #self.UEDevicesOnCmd = [] - #self.UEDevicesRebootCmd = [] - #self.CatMDevices = [] - #self.UEIPAddresses = [] - #self.htmlFile = '' - #self.htmlHeaderCreated = False - #self.htmlFooterCreated = False - #self.htmlUEConnected = -1 - #self.htmleNBFailureMsg = '' - #self.htmlUEFailureMsg = '' - #self.picocom_closure = False - #self.idle_sleep_time = 0 - #self.x2_ho_options = 'network' - #self.x2NbENBs = 0 - #self.x2ENBBsIds = [] - #self.x2ENBConnectedUEs = [] - #self.htmlTabRefs = [] - #self.htmlTabNames = [] - #self.htmlTabIcons = [] - #self.repeatCounts = [] - #self.finalStatus = False - #self.OsVersion = '' - #self.KernelVersion = '' - #self.UhdVersion = '' - #self.UsrpBoard = '' - #self.CpuNb = '' - #self.CpuModel = '' - #self.CpuMHz = '' - #self.UEIPAddress = '' - #self.UEUserName = '' - #self.UEPassword = '' - #self.UE_instance = '' - #self.UESourceCodePath = '' - #self.UELogFile = '' - #self.Build_OAI_UE_args = '' - #self.Initialize_OAI_UE_args = '' - #self.clean_repository = True - self.flexranCtrlInstalled = False - self.flexranCtrlStarted = False - #self.expectedNbOfConnectedUEs = 0 - #self.startTime = 0 + +#----------------------------------------------------------- +# Setters and Getters +#----------------------------------------------------------- + def SettestCase_id(self,tcid): self.testCase_id = tcid @@ -247,10 +189,8 @@ class RANManagement(): self.eNBstatuses = enbstatus def GeteNBstatuses(self): return self.eNBstatuses - - - - def SeteNB1IPAddress(self, enb1ip): + self.eNB1IPAddress = enb1ip + def SeteNB1IPAddress(self,enb1ip): self.eNB1IPAddress = enb1ip def GeteNB1IPAddress(self): return self.eNB1IPAddress @@ -267,7 +207,7 @@ class RANManagement(): def GeteNB1SourceCodePath(self): return self.eNB1SourceCodePath - def SeteNB2IPAddress(self, enbip): + def SeteNB2IPAddress(self, enb2ip): self.eNB2IPAddress = enb2ip def GeteNB2IPAddress(self): return self.eNB2IPAddress @@ -289,6 +229,11 @@ class RANManagement(): def GetprematureExit(self): return self.prematureExit +#----------------------------------------------------------- +# RAN management functions +#----------------------------------------------------------- + + def BuildeNB(self): myHTML = HTML.HTMLManagement() @@ -296,10 +241,7 @@ class RANManagement(): GenericHelp(Version) sys.exit('Insufficient Parameter') if self.eNB_serverId == '0': - #checkpoint enB_serverId lIpAddr = self.eNBIPAddress - print(self.eNBIPAddress + 'self.eNBIPAddress') - print(lIpAddr + 'lIpAddr') lUserName = self.eNBUserName lPassWord = self.eNBPassword lSourcePath = self.eNBSourceCodePath @@ -313,7 +255,6 @@ class RANManagement(): lUserName = self.eNB2UserName lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath - print(lIpAddr + 'just before the error') if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') @@ -368,7 +309,7 @@ class RANManagement(): mismatch = True if not mismatch: mySSH.close() - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) return mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) @@ -394,7 +335,7 @@ class RANManagement(): mySSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) mySSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) mySSH.close() - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id return mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) @@ -485,10 +426,10 @@ class RANManagement(): if buildStatus: logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) else: logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK) myHTML.CreateHtmlTabFooter(False) sys.exit(1) @@ -514,9 +455,7 @@ class RANManagement(): GenericHelp(Version) sys.exit('Insufficient Parameter') mySSH = SSH.SSHConnection() - #check_eNB = False - #check_OAI_UE = False - #pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) + if (self.pStatus < 0): myHTML.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', self.pStatus) myHTML.CreateHtmlTabFooter(False) @@ -620,7 +559,7 @@ class RANManagement(): mySSH.close() doLoop = False logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK) # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: @@ -670,7 +609,7 @@ class RANManagement(): self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) mySSH.close() - myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK) logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') @@ -700,9 +639,9 @@ class RANManagement(): result = re.search(self.air_interface + '-softmodem', mySSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') - status_queue.put(ENB_PROCESS_FAILED) + status_queue.put(CONST.ENB_PROCESS_FAILED) else: - status_queue.put(ENB_PROCESS_OK) + status_queue.put(CONST.ENB_PROCESS_OK) mySSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -776,7 +715,7 @@ class RANManagement(): mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - myHTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.eNBLogFiles[int(self.eNB_instance)] = '' else: analyzeFile = False @@ -789,7 +728,7 @@ class RANManagement(): if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' - myHTML.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + myHTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) self.eNBmbmsEnables[int(self.eNB_instance)] = False return if self.eNB_serverId != '0': @@ -802,9 +741,9 @@ class RANManagement(): self.eNBmbmsEnables[int(self.eNB_instance)] = False return else: - myHTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) else: - myHTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBstatuses[int(self.eNB_instance)] = -1 @@ -849,34 +788,34 @@ class RANManagement(): isRRU = False isSlave = False slaveReceivesFrameResyncCmd = False - X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_state = CONST.X2_HO_REQ_STATE__IDLE X2HO_inNbProcedures = 0 X2HO_outNbProcedures = 0 for line in enb_log_file.readlines(): - if X2HO_state == X2_HO_REQ_STATE__IDLE: + if X2HO_state == CONST.X2_HO_REQ_STATE__IDLE: result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ + X2HO_state = CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) if result is not None: - X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK - if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: + X2HO_state = CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK + if X2HO_state == CONST.X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE - if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: + X2HO_state = CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE + if X2HO_state == CONST.X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ - if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: + X2HO_state = CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ + if X2HO_state == CONST.X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_state = CONST.X2_HO_REQ_STATE__IDLE X2HO_inNbProcedures += 1 - if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: + if X2HO_state == CONST.X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE + X2HO_state = CONST.X2_HO_REQ_STATE__IDLE X2HO_outNbProcedures += 1 if self.eNBOptions[int(self.eNB_instance)] != '': @@ -1057,14 +996,14 @@ class RANManagement(): logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') self.htmleNBFailureMsg += rruMsg + '\n' self.prematureExit(True) - return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED + return CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED if foundSegFault: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT + return CONST.ENB_PROCESS_SEG_FAULT if foundAssertion: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m') self.htmleNBFailureMsg += msgAssertion - return ENB_PROCESS_ASSERTION + return CONST.ENB_PROCESS_ASSERTION if foundRealTimeIssue: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') self.htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' @@ -1073,5 +1012,5 @@ class RANManagement(): rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') self.htmleNBFailureMsg += rlcMsg + '\n' - return ENB_PROCESS_REALTIME_ISSUE + return CONST.ENB_PROCESS_REALTIME_ISSUE return 0 diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index df1ada4834..ecaf8f4116 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -1,3 +1,34 @@ + +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# Python for CI of OAI-eNB + COTS-UE +# +# Required Python Version +# Python 3.x +# +# Required Python Package +# pexpect +#--------------------------------------------------------------------- + + #----------------------------------------------------------- # Import #----------------------------------------------------------- From e9c6872bb91c8e48d7006f3b14e011e1414aca6e Mon Sep 17 00:00:00 2001 From: OAI Jenkins Date: Fri, 20 Mar 2020 14:09:51 +0100 Subject: [PATCH 105/175] minor modifications during a lease on inria fit14 to keep on debugging main, html, ran.py etc. --- ci-scripts/html.py | 3 +++ ci-scripts/main_enb.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ci-scripts/html.py b/ci-scripts/html.py index e8930f6e2c..3c0544c3cf 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -50,6 +50,9 @@ class HTMLManagement(): self.htmlTabNames = [] self.htmlTabIcons = [] self.testXMLfiles = [] + self.htmlHeaderCreated = False + self.htmlFooterCreated = False + #----------------------------------------------------------- # Setters and Getters #----------------------------------------------------------- diff --git a/ci-scripts/main_enb.py b/ci-scripts/main_enb.py index a42aba76e2..3b3428eec4 100644 --- a/ci-scripts/main_enb.py +++ b/ci-scripts/main_enb.py @@ -87,8 +87,8 @@ class OaiCiTest(): self.CatMDevices = [] self.UEIPAddresses = [] self.htmlFile = '' - self.htmlHeaderCreated = False - self.htmlFooterCreated = False + # self.htmlHeaderCreated = False + # self.htmlFooterCreated = False self.htmlUEConnected = -1 self.htmleNBFailureMsg = '' self.htmlUEFailureMsg = '' From 6bbf9011ba0fb003ef11182251e531a0516f88bd Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 24 Mar 2020 19:16:13 +0100 Subject: [PATCH 106/175] compilation ok --- common/utils/ocp_itti/intertask_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 89e19074bf..5e86a69958 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -7,6 +7,7 @@ #include +extern "C" { #include #include @@ -35,7 +36,6 @@ typedef struct task_list_s { int timer_expired(int fd); task_list_t tasks[TASK_MAX]; -extern "C" { void *pool_buffer_init (void) { return 0; } From 34694363e296104c138eb34ac9b86785231347c7 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 30 Mar 2020 17:34:23 +0200 Subject: [PATCH 107/175] clean up the HSS termination procedure using the screen command --- ci-scripts/epc.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 4d88a69e75..6c48dcd15d 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -126,7 +126,6 @@ class EPCManagement(): mySSH.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) mySSH.command('cd /opt/hss_sim0609', '\$', 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - #mySSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) mySSH.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo su -c "screen -dm -S simulated_hss ./starthss"', '\$', 5) else: logging.error('This option should not occur!') @@ -288,10 +287,10 @@ class EPCManagement(): elif re.match('ltebox', self.EPCType, re.IGNORECASE): mySSH.command('cd ' + self.EPCSourceCodePath, '\$', 5) mySSH.command('cd scripts', '\$', 5) - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) + #mySSH.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) time.sleep(1) #mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) - mySSH.command('echo ' + self.EPCPassword + ' | sudo killall hss_sim', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo screen -X -S simulated_hss quit', '\$', 5) else: logging.error('This should not happen!') mySSH.close() From ddfaa9af5e4dbb7f2b130b91433d02c641bf768a Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 30 Mar 2020 17:47:08 +0200 Subject: [PATCH 108/175] editorial on html.py --- ci-scripts/html.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci-scripts/html.py b/ci-scripts/html.py index e8930f6e2c..1a2ae10dc0 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -46,6 +46,8 @@ class HTMLManagement(): def __init__(self): + self.htmlHeaderCreated = False + self.htmlFooterCreated = False self.htmlTabRefs = [] self.htmlTabNames = [] self.htmlTabIcons = [] From 72d76c75856307d7b45d7bc6efa82d40ea3390cc Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 1 Apr 2020 16:52:56 +0200 Subject: [PATCH 109/175] dft-based pucch0 receiver --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 88 +++++++++++++++++++++------ openair1/PHY/TOOLS/lte_dfts.c | 4 ++ openair1/PHY/TOOLS/tools_defs.h | 2 + openair1/SIMULATION/NR_PHY/pucchsim.c | 30 ++++++--- 4 files changed, 98 insertions(+), 26 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index c1e202994b..3cd5f251af 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -17,6 +17,7 @@ #include "T.h" +#define DEBUG_NR_PUCCH_RX 1 void nr_decode_pucch0(int32_t **rxdataF, NR_DL_FRAME_PARMS *frame_parms, @@ -79,28 +80,32 @@ void nr_decode_pucch0(int32_t **rxdataF, nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,n_hop,slot,&u,&v); // calculating u and v value alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id,pucch_pdu->initial_cyclic_shift,mcs[i],l,pucch_pdu->start_symbol_index,slot); - #ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d)\n",u,v,alpha,l); - #endif +#ifdef DEBUG_NR_PUCCH_RX + printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d/%d,mcs %d)\n",u,v,alpha,l,l+pucch_pdu->start_symbol_index,mcs[i]); +#endif for (n=0; n<12; n++){ x_n_re[i][(12*l)+n] = (int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)))>>15); // Re part of base sequence shifted by alpha + - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15)))); // Re part of base sequence shifted by alpha x_n_im[i][(12*l)+n] =(int16_t)((int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) - + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)))>>15); // Im part of base sequence shifted by alpha - #ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \tx_n(l=%d,n=%d)=(%d,%d)\n", - u,v,alpha,l,n,x_n_re[(12*l)+n],x_n_im[(12*l)+n]); - #endif + + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15)))); // Im part of base sequence shifted by alpha +#ifdef DEBUG_NR_PUCCH_RX + printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \tx_n(l=%d,n=%d)=(%d,%d) %d,%d\n", + u,v,alpha,l,n,x_n_re[i][(12*l)+n],x_n_im[i][(12*l)+n], + (int32_t)(round(32767*cos(alpha*n))), + (int32_t)(round(32767*sin(alpha*n)))); +#endif } } } - int16_t r_re[24],r_im[24]; /* * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources */ uint32_t re_offset=0; uint8_t l2; +#ifdef OLD_IMPL + int16_t r_re[24],r_im[24]; + for (l=0; lnr_of_symbols; l++) { l2 = l+pucch_pdu->start_symbol_index; @@ -122,7 +127,7 @@ void nr_decode_pucch0(int32_t **rxdataF, if (re_offset>= frame_parms->ofdm_symbol_size) re_offset-=frame_parms->ofdm_symbol_size; } - } + } double corr[nr_sequences],corr_re[nr_sequences],corr_im[nr_sequences]; memset(corr,0,nr_sequences*sizeof(double)); memset(corr_re,0,nr_sequences*sizeof(double)); @@ -144,7 +149,55 @@ void nr_decode_pucch0(int32_t **rxdataF, max_corr=corr[i]; } } +#else + int16_t *x_re = x_n_re[0],*x_im = x_n_im[0]; + int16_t xr[32] __attribute__((aligned(32))); + int16_t xrt[32] __attribute__((aligned(32))); + int32_t xrtmag=0; + int maxpos=0; + int n2=0; + uint8_t index=0; + memset((void*)xr,0,32*sizeof(int16_t)); + + for (l=0; lnr_of_symbols; l++) { + + l2 = l+pucch_pdu->start_symbol_index; + re_offset = (12*pucch_pdu->prb_start) + frame_parms->first_carrier_offset; + if (re_offset>= frame_parms->ofdm_symbol_size) + re_offset-=frame_parms->ofdm_symbol_size; + + AssertFatal(re_offset+12 < frame_parms->ofdm_symbol_size,"pucch straddles DC carrier, handle this!\n"); + + n2=0; + int16_t *r=(int16_t*)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size+re_offset)]; + if (l==0) for (n=0;n<12;n++,n2+=2) { + xr[n2] =((int32_t)x_re[n]*r[n2]+(int32_t)x_im[n]*r[n2+1])>>15; + xr[n2+1]=((int32_t)x_re[n]*r[n2+1]-(int32_t)x_im[n]*r[n2])>>15; + printf("x (%d,%d), r (%d,%d), xr (%d,%d)\n", + x_re[n],x_im[n],r[n2],r[n2+1],xr[n2],xr[n2+1]); + } + else for (n=0;n<12;n++,n2+=2) { + xr[n2] +=((int32_t)x_re[n]*r[n2]+(int32_t)x_im[n]*r[n2+1])>>15; + xr[n2+1]+=((int32_t)x_re[n]*r[n2+1]-(int32_t)x_im[n]*r[n2])>>15; + } + x_re+=12; + x_im+=12; + } + idft16f(xr,xrt); + n2=0; + int32_t temp; + for (n=0;n<16;n++,n2+=2) { +#ifdef DEBUG_NR_PUCCH_RX + printf("PUCCH IDFT[%d] = (%d,%d)\n",n,xrt[n2],xrt[n2+1]); +#endif + if ((temp=(int32_t)xrt[n2]*xrt[n2]+(int32_t)xrt[n2+1]*xrt[n2+1])pdu_bit_map = pucch_pdu->sr_flag | ((pucch_pdu->bit_len_harq>0)<<1); uci_pdu->pucch_format = 0; // format 0 @@ -281,7 +334,6 @@ void nr_decode_pucch1( int32_t **rxdataF, re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; } - //txptr = &txdataF[0][re_offset]; for (int n=0; n<12; n++) { if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB) @@ -294,7 +346,7 @@ void nr_decode_pucch1( int32_t **rxdataF, #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset, - l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]); + l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]); #endif } @@ -305,7 +357,7 @@ void nr_decode_pucch1( int32_t **rxdataF, #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset, - l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]); + l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]); #endif // printf("l=%d\ti=%d\tre_offset=%d\treceived dmrs re=%d\tim=%d\n",l,i,re_offset,z_dmrs_re_rx[i+n],z_dmrs_im_rx[i+n]); } @@ -416,7 +468,7 @@ void nr_decode_pucch1( int32_t **rxdataF, mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n], table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n], - z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); + z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); #endif // multiplying with conjugate of low papr sequence z_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) @@ -450,7 +502,7 @@ void nr_decode_pucch1( int32_t **rxdataF, mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n], table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n], - z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); + z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); #endif //finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and z_dmrs_im_rx arrays z_dmrs_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) @@ -501,7 +553,7 @@ void nr_decode_pucch1( int32_t **rxdataF, mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n], table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n], - z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); + z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); #endif z_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) + (((int32_t)(r_u_v_alpha_delta_im[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); @@ -529,7 +581,7 @@ void nr_decode_pucch1( int32_t **rxdataF, mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n], table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n], - z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); + z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); #endif //finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and z_dmrs_im_rx arrays z_dmrs_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) diff --git a/openair1/PHY/TOOLS/lte_dfts.c b/openair1/PHY/TOOLS/lte_dfts.c index 2de8653ab3..4147ba6dc6 100644 --- a/openair1/PHY/TOOLS/lte_dfts.c +++ b/openair1/PHY/TOOLS/lte_dfts.c @@ -2437,6 +2437,10 @@ static inline void idft16(int16_t *x,int16_t *y) #endif } +void idft16f(int16_t *x,int16_t *y) { + idft16(x,y); +} + #if defined(__x86_64__) || defined(__i386__) #ifdef __AVX2__ // Does two 16-point IDFTS (x[0 .. 15] is 128 LSBs of input vector, x[16..31] is in 128 MSBs) diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 4253eb28d3..8a2310378e 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -171,6 +171,8 @@ This function performs optimized fixed-point radix-2 FFT/IFFT. ); */ +void idft16f(int16_t *x,int16_t *y); + void idft1536(int16_t *sigF,int16_t *sig,int scale); void idft6144(int16_t *sigF,int16_t *sig,int scale); diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 35e9713b27..33023eaeeb 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -454,8 +454,6 @@ int main(int argc, char **argv) for(SNR=snr0;SNR<=snr1;SNR=SNR+1){ ack_nack_errors=0; n_errors = 0; - sigma2_dB = 20*log10((double)amp/32767)-SNR; - sigma2 = pow(10,sigma2_dB/10); for (trial=0; trialpucch_config_dedicated,actual_payload,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,0,nr_bit); } - for(i=0; isamples_per_slot; i<(nr_tti_tx+1)*frame_parms->samples_per_slot; i++) { r_re[aa][i]=((double)(((int16_t *)txdata[0])[(i<<1)])/32767 + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); r_im[aa][i]=((double)(((int16_t *)txdata[0])[(i<<1)+1])/32767+ sqrt(sigma2/2)*gaussdouble(0.0,1.0)); r_re[aa][i]=r_re[0][i]/(sqrt(sigma2/2)+1); @@ -481,13 +483,26 @@ int main(int argc, char **argv) ((int16_t *)txdata[aa])[(i<<1)+1] =(int16_t)round(r_im[aa][i]*32767); } if(format==0){ - nr_decode_pucch0(txdata,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,nr_bit); + nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu; + nfapi_nr_pucch_pdu_t pucch_pdu; + pucch_pdu.group_hop_flag = PUCCH_GroupHopping&1; + pucch_pdu.sequence_hop_flag = (PUCCH_GroupHopping>>1)&1; + pucch_pdu.bit_len_harq = nr_bit; + pucch_pdu.sr_flag = 0; + pucch_pdu.nr_of_symbols = nrofSymbols; + pucch_pdu.hopping_id = n_id; + pucch_pdu.initial_cyclic_shift = 0; + pucch_pdu.start_symbol_index = startingSymbolIndex; + pucch_pdu.prb_start = startingPRB; + nr_decode_pucch0(txdata,frame_parms,nr_tti_tx,&uci_pdu,&pucch_pdu); if(nr_bit==1) - ack_nack_errors+=(((actual_payload^payload_received)&2)>>1); + ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value); else - ack_nack_errors+=(((actual_payload^payload_received)&2)>>1) + (((actual_payload^payload_received)&4)>>2); + ack_nack_errors+=((actual_payload^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value)); + free(uci_pdu.harq->harq_list); } else{ + nr_decode_pucch1(txdata,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit); if(nr_bit==1) ack_nack_errors+=((actual_payload^payload_received)&1); @@ -496,8 +511,7 @@ int main(int argc, char **argv) } n_errors=((actual_payload^payload_received)&1)+(((actual_payload^payload_received)&2)>>1)+(((actual_payload^payload_received)&4)>>2)+n_errors; } - printf("Decoded payload is %ld\n",payload_received); - printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,n_errors); + printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,ack_nack_errors); if((float)ack_nack_errors/(float)(nr_bit*n_trials)<=target_error_rate){ printf("PUCCH test OK\n"); break; From 236b17ce81c32785b3caaf1bfc36970260f502c2 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Wed, 1 Apr 2020 18:27:34 +0200 Subject: [PATCH 110/175] cleanup of main*.py names and push of minor changes on main.py and html.py --- ci-scripts/html.py | 7 +- ci-scripts/main-cnt-mod.py | 4927 ----------------------------- ci-scripts/main-index-to-class.py | 4921 ---------------------------- ci-scripts/main.py | 1769 ++--------- ci-scripts/main_enb.py | 3680 --------------------- 5 files changed, 344 insertions(+), 14960 deletions(-) delete mode 100644 ci-scripts/main-cnt-mod.py delete mode 100644 ci-scripts/main-index-to-class.py delete mode 100644 ci-scripts/main_enb.py diff --git a/ci-scripts/html.py b/ci-scripts/html.py index 3a520d30e3..ccd89eb577 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -48,12 +48,12 @@ class HTMLManagement(): self.htmlHeaderCreated = False self.htmlFooterCreated = False + self.ranAllowMerge = False + self.nbTestXMLfiles = 0 self.htmlTabRefs = [] self.htmlTabNames = [] self.htmlTabIcons = [] self.testXMLfiles = [] - self.htmlHeaderCreated = False - self.htmlFooterCreated = False #----------------------------------------------------------- # Setters and Getters @@ -110,6 +110,9 @@ class HTMLManagement(): def SetnbTestXMLfiles(self, nb): self.nbTestXMLfiles = nb + def GetnbTestXMLfiles(self): + return self.nbTestXMLfiles + def SettestXMLfiles(self, xmlFile): self.testXMLfiles.append(xmlFile) diff --git a/ci-scripts/main-cnt-mod.py b/ci-scripts/main-cnt-mod.py deleted file mode 100644 index 439dc0cfe4..0000000000 --- a/ci-scripts/main-cnt-mod.py +++ /dev/null @@ -1,4927 +0,0 @@ -# /* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (the "License"); you may not use this file -# * except in compliance with the License. -# * You may obtain a copy of the License at -# * -# * http://www.openairinterface.org/?page_id=698 -# * -# * Unless required by applicable law or agreed to in writing, software -# * distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# Python for CI of OAI-eNB + COTS-UE -# -# Required Python Version -# Python 3.x -# -# Required Python Package -# pexpect -#--------------------------------------------------------------------- - -#----------------------------------------------------------- -# Version -#----------------------------------------------------------- -Version = '0.1' - -#----------------------------------------------------------- -# Constants -#----------------------------------------------------------- -ALL_PROCESSES_OK = 0 -ENB_PROCESS_FAILED = -1 -ENB_PROCESS_OK = +1 -ENB_PROCESS_SEG_FAULT = -11 -ENB_PROCESS_ASSERTION = -12 -ENB_PROCESS_REALTIME_ISSUE = -13 -ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 -ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 -HSS_PROCESS_FAILED = -2 -HSS_PROCESS_OK = +2 -MME_PROCESS_FAILED = -3 -MME_PROCESS_OK = +3 -SPGW_PROCESS_FAILED = -4 -SPGW_PROCESS_OK = +4 -UE_IP_ADDRESS_ISSUE = -5 -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 -OAI_UE_PROCESS_COULD_NOT_SYNC = -21 -OAI_UE_PROCESS_ASSERTION = -22 -OAI_UE_PROCESS_FAILED = -23 -OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 -OAI_UE_PROCESS_OK = +6 - -UE_STATUS_DETACHED = 0 -UE_STATUS_DETACHING = 1 -UE_STATUS_ATTACHING = 2 -UE_STATUS_ATTACHED = 3 - -X2_HO_REQ_STATE__IDLE = 0 -X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 -X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 -X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 -X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 - -#----------------------------------------------------------- -# Import -#----------------------------------------------------------- -import sys # arg -import re # reg -import pexpect # pexpect -import time # sleep -import os -import subprocess -import xml.etree.ElementTree as ET -import logging -import datetime -import signal -from multiprocessing import Process, Lock, SimpleQueue -logging.basicConfig( - level=logging.DEBUG, - format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" -) - -#----------------------------------------------------------- -# Class Declaration -#----------------------------------------------------------- -class SSHConnection(): - def __init__(self): - self.prematureExit = False - self.ranRepository = '' - self.ranBranch = '' - self.ranAllowMerge = False - self.ranCommitID = '' - self.ranTargetBranch = '' - self.eNBIPAddress = '' - self.eNBUserName = '' - self.eNBPassword = '' - self.eNBSourceCodePath = '' - self.EPCIPAddress = '' - self.EPCUserName = '' - self.EPCPassword = '' - self.eNB1IPAddress = '' - self.eNB1UserName = '' - self.eNB1Password = '' - self.eNB1SourceCodePath = '' - self.eNB2IPAddress = '' - self.eNB2UserName = '' - self.eNB2Password = '' - self.eNB2SourceCodePath = '' - self.EPCSourceCodePath = '' - self.EPCType = '' - self.EPC_PcapFileName = '' - self.ADBIPAddress = '' - self.ADBUserName = '' - self.ADBPassword = '' - self.ADBCentralized = True - self.testCase_id = '' - self.testXMLfiles = [] - self.nbTestXMLfiles = 0 - self.desc = '' - self.Build_eNB_args = '' - self.backgroundBuild = False - self.backgroundBuildTestId = ['', '', ''] - self.Initialize_eNB_args = '' - self.eNB_instance = '' - self.eNB_serverId = '' - self.eNBLogFiles = ['', '', ''] - self.eNBOptions = ['', '', ''] - self.ping_args = '' - self.ping_packetloss_threshold = '' - self.iperf_args = '' - self.iperf_packetloss_threshold = '' - self.iperf_profile = '' - self.nbMaxUEtoAttach = -1 - self.UEDevices = [] - self.UEDevicesStatus = [] - self.UEDevicesRemoteServer = [] - self.UEDevicesRemoteUser = [] - self.UEDevicesOffCmd = [] - self.UEDevicesOnCmd = [] - self.UEDevicesRebootCmd = [] - self.CatMDevices = [] - self.UEIPAddresses = [] - self.htmlFile = '' - self.htmlHeaderCreated = False - self.htmlFooterCreated = False - self.htmlUEConnected = -1 - self.htmleNBFailureMsg = '' - self.htmlUEFailureMsg = '' - self.picocom_closure = False - self.idle_sleep_time = 0 - self.x2_ho_options = 'network' - self.x2NbENBs = 0 - self.x2ENBBsIds = [] - self.x2ENBConnectedUEs = [] - self.htmlTabRefs = [] - self.htmlTabNames = [] - self.htmlTabIcons = [] - # repeatCounts was a list --> becomes an integer - self.repeatCounts = 1 - self.finalStatus = False - self.OsVersion = '' - self.KernelVersion = '' - self.UhdVersion = '' - self.UsrpBoard = '' - self.CpuNb = '' - self.CpuModel = '' - self.CpuMHz = '' - self.UEIPAddress = '' - self.UEUserName = '' - self.UEPassword = '' - self.UE_instance = '' - self.UESourceCodePath = '' - self.UELogFile = '' - self.Build_OAI_UE_args = '' - self.Initialize_OAI_UE_args = '' - self.flexranCtrlInstalled = False - self.flexranCtrlStarted = False - self.expectedNbOfConnectedUEs = 0 - self.startTime = 0 - - def open(self, ipaddress, username, password): - count = 0 - connect_status = False - while count < 4: - self.ssh = pexpect.spawn('ssh', [username + '@' + ipaddress], timeout = 5) - self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - self.ssh.sendline('yes') - self.ssh.expect('password:') - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 1: - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 2: - # Checking if we are really on the remote client defined by its IP address - self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) - result = re.search(str(ipaddress), str(self.ssh.before)) - if result is None: - self.close() - else: - count = 10 - connect_status = True - else: - # debug output - logging.debug(str(self.ssh.before)) - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - # adding a tempo when failure - if not connect_status: - time.sleep(1) - count += 1 - if connect_status: - pass - else: - sys.exit('SSH Connection Failed') - - def command(self, commandline, expectedline, timeout): - logging.debug(commandline) - self.ssh.timeout = timeout - self.ssh.sendline(commandline) - self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - return 0 - elif self.sshresponse == 1: - logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) - elif self.sshresponse == 2: - logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - result = re.search('ping |iperf |picocom', str(commandline)) - if result is None: - logging.debug(str(self.ssh.before)) - sys.exit(self.sshresponse) - else: - return -1 - else: - logging.debug('\u001B[1;37;41m Unexpected Others \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) - - def close(self): - self.ssh.timeout = 5 - self.ssh.sendline('exit') - self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - pass - elif self.sshresponse == 1: - if not self.picocom_closure: - logging.debug('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') - else: - logging.debug('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') - - def copyin(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.debug('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination) - while count < 10: - scp_spawn = pexpect.spawn('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.debug('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.debug('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.debug('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - return 0 - else: - return -1 - - def copyout(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.debug('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination) - while count < 4: - scp_spawn = pexpect.spawn('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.debug('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.debug('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.debug('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - pass - else: - sys.exit('SCP failed') - - def BuildeNB(self): - if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - Usage() - sys.exit('Insufficient Parameter') - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - self.command('mkdir -p ' + lSourcePath, '\$', 5) - self.command('cd ' + lSourcePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) - # Raphael: here add a check if git clone or git fetch went smoothly - self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - self.command('git config user.name "OAI Jenkins"', '\$', 5) - # Checking the BUILD INFO file - if not self.backgroundBuild: - self.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) - if result is not None: - mismatch = False - self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - result = re.search('YES', str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - result = re.search('develop', str(self.ssh.before)) - else: - result = re.search(self.ranTargetBranch, str(self.ssh.before)) - if result is None: - mismatch = True - else: - result = re.search('NO', str(self.ssh.before)) - if result is None: - mismatch = True - if not mismatch: - self.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - return - - self.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) - # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - self.command('git checkout -f ' + self.ranCommitID, '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (self.ranAllowMerge): - if self.ranTargetBranch == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('mkdir -p log', '\$', 5) - self.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - if self.backgroundBuild: - self.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) - self.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id - return - self.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) - - def WaitBuildeNBisFinished(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - count = 40 - buildOAIprocess = True - while (count > 0) and buildOAIprocess: - self.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) - result = re.search('build_oai', str(self.ssh.before)) - if result is None: - buildOAIprocess = False - else: - count -= 1 - time.sleep(30) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) - - def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): - self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - buildStatus = True - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is None: - buildStatus = False - else: - # Generating a BUILD INFO file - self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('mkdir -p build_log_' + testcaseId, '\$', 5) - self.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) - self.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) - if self.eNB_serverId != '0': - self.command('cd cmake_targets', '\$', 5) - self.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) - self.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) - self.close() - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - os.remove('./tmp_build' + testcaseId + '.zip') - self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') - os.remove('./tmp_build' + testcaseId + '.zip') - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) - self.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) - self.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) - self.close() - else: - self.close() - - if buildStatus: - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - else: - logging.error('\u001B[1m Building OAI eNB Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) - self.CreateHtmlTabFooter(False) - sys.exit(1) - - def BuildOAIUE(self): - if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) - # here add a check if git clone or git fetch went smoothly - self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - self.command('git config user.name "OAI Jenkins"', '\$', 5) - self.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) - if result is not None: - mismatch = False - self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - result = re.search('YES', str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - result = re.search('develop', str(self.ssh.before)) - else: - result = re.search(self.ranTargetBranch, str(self.ssh.before)) - if result is None: - mismatch = True - else: - result = re.search('NO', str(self.ssh.before)) - if result is None: - mismatch = True - if not mismatch: - self.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - return - - self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) - # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - self.command('git checkout -f ' + self.ranCommitID, '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (self.ranAllowMerge): - if self.ranTargetBranch == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('mkdir -p log', '\$', 5) - self.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) - self.command('ls lte_build_oai/build', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - buildStatus = True - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is None: - buildStatus = False - self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) - self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) - self.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) - if buildStatus: - # Generating a BUILD INFO file - self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - self.close() - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') - else: - self.close() - logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') - self.CreateHtmlTabFooter(False) - sys.exit(1) - - def InitializeHSS(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') - EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) - self.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) - self.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) - self.command('chmod 755 ./my-hss.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC HSS') - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - logging.debug('Using the ltebox simulated HSS') - self.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - self.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('cd /opt/hss_sim0609', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) - else: - logging.error('This option should not occur!') - self.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def InitializeMME(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 MME') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) - self.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) - self.command('chmod 755 ./my-mme.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('stdbuf -o0 hostname', '\$', 5) - result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') - sys.exit(1) - host_name = result.group('host_name') - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) - else: - logging.error('This option should not occur!') - self.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def InitializeSPGW(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) - self.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) - self.command('chmod 755 ./my-spgwc.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) - time.sleep(5) - self.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) - self.command('chmod 755 ./my-spgwu.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) - else: - logging.error('This option should not occur!') - self.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def CheckFlexranCtrlInstallation(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': - return - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) - result = re.search('/opt/flexran_rtc/build/rt_controller', str(self.ssh.before)) - if result is not None: - self.flexranCtrlInstalled = True - logging.debug('Flexran Controller is installed') - self.close() - - def InitializeFlexranCtrl(self): - if self.flexranCtrlInstalled == False: - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd /opt/flexran_rtc', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) - self.command('ps -aux | grep --color=never rt_controller', '\$', 5) - result = re.search('rt_controller -c ', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') - self.flexranCtrlStarted = True - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def InitializeeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = False - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', str(self.ssh.before)) - if result is not None: - eth_interface = result.group('eth_interface') - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - self.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - self.close() - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath, '\$', 5) - # Initialize_eNB_args usually start with -O and followed by the location in repository - full_config_file = self.Initialize_eNB_args.replace('-O ','') - extra_options = '' - extIdx = full_config_file.find('.conf') - if (extIdx > 0): - extra_options = full_config_file[extIdx + 5:] - # if tracer options is on, compiling and running T Tracer - result = re.search('T_stdout', str(extra_options)) - if result is not None: - logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') - self.command('cd common/utils/T/tracer', '\$', 5) - self.command('make', '\$', 10) - self.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) - self.command('cd ' + lSourcePath, '\$', 5) - full_config_file = full_config_file[:extIdx + 5] - config_path, config_file = os.path.split(full_config_file) - else: - sys.exit('Insufficient Parameter') - ci_full_config_file = config_path + '/ci-' + config_file - rruCheck = False - result = re.search('^rru|^rcc|^du.band', str(config_file)) - if result is not None: - rruCheck = True - # do not reset board twice in IF4.5 case - result = re.search('^rru|^enb|^du.band', str(config_file)) - if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 15) - # Make a copy and adapt to EPC / eNB IP addresses - self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); - else: - self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); - # Launch eNB with the modified config file - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' - if extra_options != '': - self.eNBOptions[int(self.eNB_instance)] = extra_options - time.sleep(6) - doLoop = True - loopCounter = 10 - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # In case of T tracer recording, we may need to kill it - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.command('killall --signal SIGKILL record', '\$', 5) - self.close() - doLoop = False - logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) - # In case of T tracer recording, we need to kill tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if self.EPC_PcapFileName != '': - time.sleep(0.5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.close() - time.sleep(1) - if self.EPC_PcapFileName != '': - copyin_res = self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') - if (copyin_res == 0): - self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') - self.prematureExit = True - return - else: - self.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) - if rruCheck: - result = re.search('wait RUs', str(self.ssh.before)) - else: - result = re.search('got sync|Starting F1AP at CU', str(self.ssh.before)) - if result is None: - time.sleep(6) - else: - doLoop = False - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) - logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') - time.sleep(10) - - self.close() - - def InitializeUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if not self.ADBCentralized: - # Reboot UE - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) - # Wait - #time.sleep(60) - # Put in LTE-Mode only - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) - # enable data service - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - # we need to do radio on/off cycle to make sure of above changes - # airplane mode off // radio on - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - #time.sleep(10) - # airplane mode on // radio off - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - - # normal procedure without reboot - # enable data service - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - # airplane mode on // radio off - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - self.close() - return - # enable data service - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) - - # The following commands are deprecated since we no longer work on Android 7+ - # self.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) - # self.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) - # a dedicated script has to be installed inside the UE - # airplane mode on means call /data/local/tmp/off - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - #airplane mode off means call /data/local/tmp/on - logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def InitializeUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.InitializeUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def InitializeOAIUE(self): - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - # b2xx_fx3_utils reset procedure - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) - else: - logging.debug('Did not find any B2xx device') - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets/lte_build_oai/build', '\$', 5) - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - # We may have to regenerate the .u* files - if result is None: - self.command('ls /tmp/*.sed', '\$', 5) - result = re.search('adapt_usim_parameters', str(self.ssh.before)) - if result is not None: - self.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - else: - self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - # Launch UE with the modified config file - self.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.UELogFile = 'ue_' + self.testCase_id + '.log' - - # We are now looping several times to hope we really sync w/ an eNB - doOutterLoop = True - outterLoopCounter = 5 - gotSyncStatus = True - fullSyncStatus = True - while (doOutterLoop): - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - time.sleep(6) - self.command('cd ../..', '\$', 5) - doLoop = True - loopCounter = 10 - gotSyncStatus = True - # the 'got sync' message is for the UE threads synchronization - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here should never occur - logging.error('"got sync" message never showed!') - gotSyncStatus = False - doLoop = False - continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('got sync', str(self.ssh.before)) - if result is None: - time.sleep(6) - else: - doLoop = False - logging.debug('Found "got sync" message!') - if gotSyncStatus == False: - # we certainly need to stop the lte-uesoftmodem process if it is still running! - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - time.sleep(3) - # We are now checking if sync w/ eNB DOES NOT OCCUR - # Usually during the cell synchronization stage, the UE returns with No cell synchronization message - doLoop = True - loopCounter = 10 - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here we do have a great chance that the UE did cell-sync w/ eNB - doLoop = False - doOutterLoop = False - fullSyncStatus = True - continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('No cell synchronization found', str(self.ssh.before)) - if result is None: - time.sleep(6) - else: - doLoop = False - fullSyncStatus = False - logging.debug('Found: "No cell synchronization" message! --> try again') - time.sleep(6) - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - outterLoopCounter = outterLoopCounter - 1 - if (outterLoopCounter == 0): - doOutterLoop = False - - if fullSyncStatus and gotSyncStatus: - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - self.command('ifconfig oaitun_ue1', '\$', 4) - # ifconfig output is different between ubuntu 16 and ubuntu 18 - result = re.search('inet addr:1|inet 1', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') - tunnelInterfaceStatus = True - else: - logging.debug(str(self.ssh.before)) - logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') - tunnelInterfaceStatus = False - else: - tunnelInterfaceStatus = True - - self.close() - if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') - logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') - if (self.ADBIPAddress != 'none'): - self.UEDevices = [] - self.UEDevices.append('OAI-UE') - self.UEDevicesStatus = [] - self.UEDevicesStatus.append(UE_STATUS_DETACHED) - else: - self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') - logging.error('\033[91mInitialize OAI UE Failed! \033[0m') - self.AutoTerminateUEandeNB() - - def checkDevTTYisUnlocked(self): - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - count = 0 - while count < 5: - self.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) - result = re.search('picocom', str(self.ssh.before)) - if result is None: - count = 10 - else: - time.sleep(5) - count = count + 1 - self.close() - - def InitializeCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - # Disabling the Radio - self.command('AT+CFUN=0', 'OK', 5) - logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - # Checking if auto-attach is enabled - self.command('AT^AUTOATT?', 'OK', 5) - result = re.search('AUTOATT: (?P[0-9\-]+)', str(self.ssh.before)) - if result is not None: - if result.group('state') is not None: - autoAttachState = int(result.group('state')) - if autoAttachState is not None: - if autoAttachState == 0: - self.command('AT^AUTOATT=1', 'OK', 5) - logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') - else: - logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') - # Force closure of picocom but device might still be locked - self.close() - self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.checkDevTTYisUnlocked() - - def TerminateCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - # Disabling the Radio - self.command('AT+CFUN=0', 'OK', 5) - logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - self.close() - self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.checkDevTTYisUnlocked() - - def AttachCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - # Enabling the Radio - self.command('AT+CFUN=1', 'SIMSTORE,READY', 5) - logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') - time.sleep(4) - # We should check if we register - count = 0 - attach_cnt = 0 - attach_status = False - while count < 5: - self.command('AT+CEREG?', 'OK', 5) - result = re.search('CEREG: 2,(?P[0-9\-]+),', str(self.ssh.before)) - if result is not None: - mDataConnectionState = int(result.group('state')) - if mDataConnectionState is not None: - if mDataConnectionState == 1: - count = 10 - attach_status = True - result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', str(self.ssh.before)) - if result is not None: - networky = result.group('networky') - networkz = result.group('networkz') - logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m') - else: - logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m') - else: - logging.debug('+CEREG: 2,' + str(mDataConnectionState)) - attach_cnt = attach_cnt + 1 - else: - logging.debug(str(self.ssh.before)) - attach_cnt = attach_cnt + 1 - count = count + 1 - time.sleep(1) - if attach_status: - self.command('AT+CESQ', 'OK', 5) - result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', str(self.ssh.before)) - if result is not None: - nRSRQ = int(result.group('rsrq')) - nRSRP = int(result.group('rsrp')) - if (nRSRQ is not None) and (nRSRP is not None): - logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') - logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') - self.close() - self.picocom_closure = False - html_queue = SimpleQueue() - self.checkDevTTYisUnlocked() - if attach_status: - html_cell = '
CAT-M module Attachment Completed in ' + str(attach_cnt+4) + ' seconds'
-			if (nRSRQ is not None) and (nRSRP is not None):
-				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
-				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm
' - else: - html_cell += '' - html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) - else: - logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') - html_cell = '
CAT-M module Attachment Failed
' - html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) - self.AutoTerminateUEandeNB() - - def PingCatM(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - try: - statusQueue = SimpleQueue() - lock = Lock() - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC HSS: not implemented yet') - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - else: - self.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) - result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', str(self.ssh.before)) - if result is not None: - moduleIPAddr = result.group('ipaddr') - else: - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - device_id = 'catm' - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - lock.acquire() - logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - lock.release() - self.close() - html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' - statusQueue.put(html_cell) - if (packetLossOK): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) - else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) - self.AutoTerminateUEandeNB() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AttachUE_common(self, device_id, statusQueue, lock, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) - else: - # airplane mode off // radio on - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(2) - max_count = 45 - count = max_count - while count > 0: - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put('mDataConnectionState Not Found!') - lock.release() - break - mDataConnectionState = int(result.group('state')) - if mDataConnectionState == 2: - logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') - lock.acquire() - statusQueue.put(max_count - count) - statusQueue.put(device_id) - statusQueue.put('Attach Completed') - lock.release() - break - count = count - 1 - if count == 15 or count == 30: - logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - time.sleep(0.5) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(0.5) - logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') - time.sleep(1) - if count == 0: - logging.debug('\u001B[1;37;41m UE (' + device_id + ') Attach Failed \u001B[0m') - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put('Attach Failed') - lock.release() - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AttachUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - status_queue = SimpleQueue() - lock = Lock() - nb_ue_to_connect = 0 - for device_id in self.UEDevices: - if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): - self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING - p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) - p.daemon = True - p.start() - multi_jobs.append(p) - nb_ue_to_connect = nb_ue_to_connect + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - return - else: - attach_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - attach_status = False - device_id = status_queue.get() - message = status_queue.get() - if (count < 0): - html_cell = '
UE (' + device_id + ')\n' + message + '
' - else: - html_cell = '
UE (' + device_id + ')\n' + message + ' in ' + str(count + 2) + ' seconds
' - html_queue.put(html_cell) - if (attach_status): - cnt = 0 - while cnt < len(self.UEDevices): - if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: - self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED - cnt += 1 - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - else: - self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def DetachUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DetachUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - cnt = 0 - for device_id in self.UEDevices: - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING - p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) - p.daemon = True - p.start() - multi_jobs.append(p) - cnt += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED - cnt += 1 - - def RebootUE_common(self, device_id): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - previousmDataConnectionStates = [] - # Save mDataConnectionState - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') - sys.exit(1) - previousmDataConnectionStates.append(int(result.group('state'))) - # Reboot UE - self.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) - time.sleep(60) - previousmDataConnectionState = previousmDataConnectionStates.pop(0) - count = 180 - while count > 0: - count = count - 1 - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) - if result is None: - mDataConnectionState = None - else: - mDataConnectionState = int(result.group('state')) - logging.debug('mDataConnectionState = ' + result.group('state')) - if mDataConnectionState is None or (previousmDataConnectionState == 2 and mDataConnectionState != 2): - logging.debug('\u001B[1mWait UE (' + device_id + ') a second until reboot completion (' + str(180-count) + ' times)\u001B[0m') - time.sleep(1) - else: - logging.debug('\u001B[1mUE (' + device_id + ') Reboot Completed\u001B[0m') - break - if count == 0: - logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') - sys.exit(1) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def RebootUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - multi_jobs = [] - for device_id in self.UEDevices: - p = Process(target = self.RebootUE_common, args = (device_id,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def DataDisableUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # disable data service - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DataDisableUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.DataDisableUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def DataEnableUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # enable data service - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DataEnableUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.DataEnableUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def GetAllUEDevices(self, terminate_ue_flag): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('adb devices', '\$', 15) - self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",str(self.ssh.before)) - self.close() - else: - if (os.path.isfile('./phones_list.txt')): - os.remove('./phones_list.txt') - self.command('ls /etc/*/phones*.txt', '\$', 5) - result = re.search('/etc/ci/phones_list.txt', str(self.ssh.before)) - self.close() - if (result is not None) and (len(self.UEDevices) == 0): - self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') - if (os.path.isfile('./phones_list.txt')): - phone_list_file = open('./phones_list.txt', 'r') - for line in phone_list_file.readlines(): - line = line.strip() - result = re.search('^#', line) - if result is not None: - continue - comma_split = line.split(",") - self.UEDevices.append(comma_split[0]) - self.UEDevicesRemoteServer.append(comma_split[1]) - self.UEDevicesRemoteUser.append(comma_split[2]) - self.UEDevicesOffCmd.append(comma_split[3]) - self.UEDevicesOnCmd.append(comma_split[4]) - self.UEDevicesRebootCmd.append(comma_split[5]) - phone_list_file.close() - - if terminate_ue_flag == False: - if len(self.UEDevices) == 0: - logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') - sys.exit(1) - if len(self.UEDevicesStatus) == 0: - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus.append(UE_STATUS_DETACHED) - cnt += 1 - - def GetAllCatMDevices(self, terminate_ue_flag): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) - self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",str(self.ssh.before)) - else: - if (os.path.isfile('./modules_list.txt')): - os.remove('./modules_list.txt') - self.command('ls /etc/*/modules*.txt', '\$', 5) - result = re.search('/etc/ci/modules_list.txt', str(self.ssh.before)) - self.close() - if result is not None: - logging.debug('Found a module list file on ADB server') - if terminate_ue_flag == False: - if len(self.CatMDevices) == 0: - logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') - sys.exit(1) - self.close() - - def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) - result = re.search('mServiceState=(?P[0-9]+)', str(self.ssh.before)) - serviceState = 'Service State: UNKNOWN' - if result is not None: - lServiceState = int(result.group('serviceState')) - if lServiceState == 3: - serviceState = 'Service State: RADIO_POWERED_OFF' - if lServiceState == 1: - serviceState = 'Service State: OUT_OF_SERVICE' - if lServiceState == 0: - serviceState = 'Service State: IN_SERVICE' - if lServiceState == 2: - serviceState = 'Service State: EMERGENCY_ONLY' - result = re.search('mDataConnectionState=(?P[0-9]+)', str(self.ssh.before)) - dataConnectionState = 'Data State: UNKNOWN' - if result is not None: - lDataConnectionState = int(result.group('dataConnectionState')) - if lDataConnectionState == 0: - dataConnectionState = 'Data State: DISCONNECTED' - if lDataConnectionState == 1: - dataConnectionState = 'Data State: CONNECTING' - if lDataConnectionState == 2: - dataConnectionState = 'Data State: CONNECTED' - if lDataConnectionState == 3: - dataConnectionState = 'Data State: SUSPENDED' - result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', str(self.ssh.before)) - dataConnectionReason = 'Data Reason: UNKNOWN' - if result is not None: - dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') - lock.acquire() - logging.debug('\u001B[1;37;44m Status Check (' + str(device_id) + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + serviceState + '\u001B[0m') - logging.debug('\u001B[1;34m ' + dataConnectionState + '\u001B[0m') - logging.debug('\u001B[1;34m ' + dataConnectionReason + '\u001B[0m') - statusQueue.put(0) - statusQueue.put(device_id) - qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason - statusQueue.put(qMsg) - lock.release() - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckStatusUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - multi_jobs = [] - lock = Lock() - status_queue = SimpleQueue() - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.CheckUEStatus_common, args = (lock,device_id,status_queue,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd /opt/flexran_rtc', '\$', 5) - self.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) - self.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) - result = re.search('Nb Connected UE = (?P[0-9]+)', str(self.ssh.before)) - passStatus = True - if result is not None: - nb_ues = int(result.group('nb_ues')) - htmlOptions = 'Nb Connected UE(s) to eNB = ' + str(nb_ues) - logging.debug('\u001B[1;37;44m ' + htmlOptions + ' \u001B[0m') - if self.expectedNbOfConnectedUEs > -1: - if nb_ues != self.expectedNbOfConnectedUEs: - passStatus = False - else: - htmlOptions = 'N/A' - self.close() - else: - passStatus = True - htmlOptions = 'N/A' - - if (status_queue.empty()): - self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - check_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - check_status = False - device_id = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\n' + message + '
' - html_queue.put(html_cell) - if check_status and passStatus: - self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def GetAllUEIPAddresses(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - ue_ip_status = 0 - self.UEIPAddresses = [] - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('ifconfig oaitun_ue1', '\$', 4) - result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', str(self.ssh.before)) - if result is not None: - if result.group('ueipaddress') is not None: - UE_IPAddress = result.group('ueipaddress') - else: - UE_IPAddress = result.group('ueipaddress2') - logging.debug('\u001B[1mUE (' + self.UEDevices[0] + ') IP Address is ' + UE_IPAddress + '\u001B[0m') - self.UEIPAddresses.append(UE_IPAddress) - else: - logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') - ue_ip_status -= 1 - self.close() - return ue_ip_status - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - idx = 0 - for device_id in self.UEDevices: - if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: - idx += 1 - continue - count = 0 - while count < 4: - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) - result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') - time.sleep(1) - count += 1 - else: - count = 10 - if count < 9: - ue_ip_status -= 1 - continue - UE_IPAddress = result.group('ueipaddress') - logging.debug('\u001B[1mUE (' + device_id + ') IP Address is ' + UE_IPAddress + '\u001B[0m') - for ueipaddress in self.UEIPAddresses: - if ueipaddress == UE_IPAddress: - logging.debug('\u001B[1mUE (' + device_id + ') IP Address ' + UE_IPAddress + ': has already been allocated to another device !' + '\u001B[0m') - ue_ip_status -= 1 - continue - self.UEIPAddresses.append(UE_IPAddress) - idx += 1 - self.close() - return ue_ip_status - - def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(message) - lock.release() - - def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): - try: - # Launch ping on the EPC side (true for ltebox and old open-air-cn) - # But for OAI-Rel14-CUPS, we launch from python executor - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - launchFromEpc = False - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) - else: - cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - ping_status = ret.returncode - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - lock.acquire() - logging.debug('\u001B[1;37;44m ping result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - if (packetLossOK): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(qMsg) - lock.release() - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def PingNoS1_wrong_exit(self, qMsg): - html_queue = SimpleQueue() - html_cell = '
OAI UE ping result\n' + qMsg + '
' - html_queue.put(html_cell) - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - - def PingNoS1(self): - check_eNB = True - check_OAI_UE = True - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) - if ping_from_eNB is not None: - if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - else: - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - Usage() - sys.exit('Insufficient Parameter') - try: - if ping_from_eNB is not None: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) - else: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with OAI UE crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - logging.debug('\u001B[1;37;44m OAI UE ping result \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - self.close() - html_queue = SimpleQueue() - ip_addr = 'TBD' - html_cell = '
OAI UE ping result\n' + qMsg + '
' - html_queue.put(html_cell) - if packetLossOK: - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - - # copying on the EPC server for logCollection - if ping_from_eNB is not None: - copyin_res = self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') - else: - copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def Ping(self): - result = re.search('noS1', str(self.Initialize_eNB_args)) - if result is not None: - self.PingNoS1() - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - check_OAI_UE = True - else: - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - i = 0 - lock = Lock() - status_queue = SimpleQueue() - for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - ping_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - ping_status = False - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (ping_status): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def Iperf_ComputeTime(self): - result = re.search('-t (?P\d+)', str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Iperf time Not Found! \u001B[0m') - sys.exit(1) - return result.group('iperf_time') - - def Iperf_ComputeModifiedBW(self, idx, ue_num): - result = re.search('-b (?P[0-9\.]+)[KMG]', str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Iperf bandwidth Not Found! \u001B[0m') - sys.exit(1) - iperf_bandwidth = result.group('iperf_bandwidth') - if self.iperf_profile == 'balanced': - iperf_bandwidth_new = float(iperf_bandwidth)/ue_num - if self.iperf_profile == 'single-ue': - iperf_bandwidth_new = float(iperf_bandwidth) - if self.iperf_profile == 'unbalanced': - # residual is 2% of max bw - residualBW = float(iperf_bandwidth) / 50 - if idx == 0: - iperf_bandwidth_new = float(iperf_bandwidth) - ((ue_num - 1) * residualBW) - else: - iperf_bandwidth_new = residualBW - iperf_bandwidth_str = '-b ' + iperf_bandwidth - iperf_bandwidth_str_new = '-b ' + ('%.2f' % iperf_bandwidth_new) - result = re.sub(iperf_bandwidth_str, iperf_bandwidth_str_new, str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Calculate Iperf bandwidth Failed! \u001B[0m') - sys.exit(1) - return result - - def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - self.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', str(self.ssh.before)) - if result is not None: - avgbitrate = result.group('average') - maxbitrate = result.group('maximum') - minbitrate = result.group('minimum') - lock.acquire() - logging.debug('\u001B[1;37;44m TCP iperf result (' + UE_IPAddress + ') \u001B[0m') - msg = 'TCP Stats :\n' - if avgbitrate is not None: - logging.debug('\u001B[1;34m Avg Bitrate : ' + avgbitrate + '\u001B[0m') - msg += 'Avg Bitrate : ' + avgbitrate + '\n' - if maxbitrate is not None: - logging.debug('\u001B[1;34m Max Bitrate : ' + maxbitrate + '\u001B[0m') - msg += 'Max Bitrate : ' + maxbitrate + '\n' - if minbitrate is not None: - logging.debug('\u001B[1;34m Min Bitrate : ' + minbitrate + '\u001B[0m') - msg += 'Min Bitrate : ' + minbitrate + '\n' - statusQueue.put(0) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - return 0 - - def Iperf_analyzeV2Output(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - result = re.search('-u', str(iperf_real_options)) - if result is None: - return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) - - result = re.search('Server Report:', str(self.ssh.before)) - if result is None: - result = re.search('read failed: Connection refused', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') - else: - logging.debug('\u001B[1;37;41m Server Report and Connection refused Not Found! \u001B[0m') - return -1 - # Computing the requested bandwidth in float - result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) - if result is not None: - req_bandwidth = result.group('iperf_bandwidth') - req_bw = float(req_bandwidth) - result = re.search('-b [0-9\.]+K', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Kbits/sec' % req_bw - req_bw = req_bw * 1000 - result = re.search('-b [0-9\.]+M', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Mbits/sec' % req_bw - req_bw = req_bw * 1000000 - result = re.search('-b [0-9\.]+G', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Gbits/sec' % req_bw - req_bw = req_bw * 1000000000 - - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) - if result is not None: - bitrate = result.group('bitrate') - packetloss = result.group('packetloss') - jitter = result.group('jitter') - lock.acquire() - logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') - iperfStatus = True - msg = 'Req Bitrate : ' + req_bandwidth + '\n' - logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m') - if bitrate is not None: - msg += 'Bitrate : ' + bitrate + '\n' - logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') - result = re.search('(?P[0-9\.]+) [KMG]bits/sec', str(bitrate)) - if result is not None: - actual_bw = float(str(result.group('real_bw'))) - result = re.search('[0-9\.]+ K', bitrate) - if result is not None: - actual_bw = actual_bw * 1000 - result = re.search('[0-9\.]+ M', bitrate) - if result is not None: - actual_bw = actual_bw * 1000000 - result = re.search('[0-9\.]+ G', bitrate) - if result is not None: - actual_bw = actual_bw * 1000000000 - br_loss = 100 * actual_bw / req_bw - bitperf = '%.2f ' % br_loss - msg += 'Bitrate Perf: ' + bitperf + '%\n' - logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m') - if packetloss is not None: - msg += 'Packet Loss : ' + packetloss + '%\n' - logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') - if float(packetloss) > float(self.iperf_packetloss_threshold): - msg += 'Packet Loss too high!\n' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - iperfStatus = False - if jitter is not None: - msg += 'Jitter : ' + jitter + '\n' - logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m') - if (iperfStatus): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - return 0 - else: - return -2 - - def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') - return - # Computing the requested bandwidth in float - result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) - if result is None: - logging.debug('Iperf bandwidth Not Found!') - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not compute Iperf bandwidth!') - return - else: - req_bandwidth = result.group('iperf_bandwidth') - req_bw = float(req_bandwidth) - result = re.search('-b [0-9\.]+K', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Kbits/sec' % req_bw - req_bw = req_bw * 1000 - result = re.search('-b [0-9\.]+M', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Mbits/sec' % req_bw - req_bw = req_bw * 1000000 - result = re.search('-b [0-9\.]+G', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Gbits/sec' % req_bw - req_bw = req_bw * 1000000000 - - server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') - br_sum = 0.0 - ji_sum = 0.0 - pl_sum = 0 - ps_sum = 0 - row_idx = 0 - for line in server_file.readlines(): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) - if result is not None: - bitrate = result.group('bitrate') - jitter = result.group('jitter') - packetlost = result.group('lostPack') - packetsent = result.group('sentPack') - br = bitrate.split(' ') - ji = jitter.split(' ') - row_idx = row_idx + 1 - curr_br = float(br[0]) - pl_sum = pl_sum + int(packetlost) - ps_sum = ps_sum + int(packetsent) - if (br[1] == 'Kbits/sec'): - curr_br = curr_br * 1000 - if (br[1] == 'Mbits/sec'): - curr_br = curr_br * 1000 * 1000 - br_sum = curr_br + br_sum - ji_sum = float(ji[0]) + ji_sum - if (row_idx > 0): - br_sum = br_sum / row_idx - ji_sum = ji_sum / row_idx - br_loss = 100 * br_sum / req_bw - if (br_sum > 1000): - br_sum = br_sum / 1000 - if (br_sum > 1000): - br_sum = br_sum / 1000 - bitrate = '%.2f Mbits/sec' % br_sum - else: - bitrate = '%.2f Kbits/sec' % br_sum - else: - bitrate = '%.2f bits/sec' % br_sum - bitperf = '%.2f ' % br_loss - bitperf += '%' - jitter = '%.2f ms' % (ji_sum) - if (ps_sum > 0): - pl = float(100 * pl_sum / ps_sum) - packetloss = '%2.1f ' % (pl) - packetloss += '%' - else: - packetloss = 'unknown' - lock.acquire() - if (br_loss < 90): - statusQueue.put(1) - else: - statusQueue.put(0) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - req_msg = 'Req Bitrate : ' + req_bandwidth - bir_msg = 'Bitrate : ' + bitrate - brl_msg = 'Bitrate Perf: ' + bitperf - jit_msg = 'Jitter : ' + jitter - pal_msg = 'Packet Loss : ' + packetloss - statusQueue.put(req_msg + '\n' + bir_msg + '\n' + brl_msg + '\n' + jit_msg + '\n' + pal_msg + '\n') - logging.debug('\u001B[1;37;45m iperf result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;35m ' + req_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + bir_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + brl_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + jit_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + pal_msg + '\u001B[0m') - lock.release() - else: - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') - - server_file.close() - - - def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', str(self.ssh.before)) - if result is None: - result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', str(self.ssh.before)) - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - if result is not None: - logging.debug('\u001B[1;37;41m ' + result.group('error') + ' \u001B[0m') - statusQueue.put(result.group('error')) - else: - logging.debug('\u001B[1;37;41m Bitrate and/or Packet Loss Not Found! \u001B[0m') - statusQueue.put('Bitrate and/or Packet Loss Not Found!') - lock.release() - - bitrate = result.group('bitrate') - packetloss = result.group('packetloss') - lock.acquire() - logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') - msg = 'Bitrate : ' + bitrate + '\n' - iperfStatus = True - if packetloss is not None: - logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') - msg += 'Packet Loss : ' + packetloss + '%\n' - if float(packetloss) > float(self.iperf_packetloss_threshold): - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - msg += 'Packet Loss too high!\n' - iperfStatus = False - if (iperfStatus): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - - def Iperf_UL_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): - udpIperf = True - result = re.search('-u', str(self.iperf_args)) - if result is None: - udpIperf = False - ipnumbers = UE_IPAddress.split('.') - if (len(ipnumbers) == 4): - ipnumbers[3] = '1' - EPC_Iperf_UE_IPAddress = ipnumbers[0] + '.' + ipnumbers[1] + '.' + ipnumbers[2] + '.' + ipnumbers[3] - - # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 - # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - launchFromEpc = False - cmd = 'hostname -I' - ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - if ret.stdout is not None: - EPC_Iperf_UE_IPAddress = ret.stdout.strip() - port = 5001 + idx - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if udpIperf: - self.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) - else: - self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) - self.close() - else: - if self.ueIperfVersion == self.dummyIperfVersion: - prefix = '' - else: - prefix = '' - if self.ueIperfVersion == '2.0.5': - prefix = '/opt/iperf-2.0.5/bin/' - if udpIperf: - cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - else: - cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - logging.debug(cmd) - subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - time.sleep(0.5) - - # Launch iperf client on UE - if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - iperf_time = self.Iperf_ComputeTime() - time.sleep(0.5) - - if udpIperf: - modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) - else: - modified_options = str(self.iperf_args) - modified_options = modified_options.replace('-R','') - time.sleep(0.5) - - self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if (device_id == 'OAI-UE'): - iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - if self.ADBCentralized: - iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # TIMEOUT Case - if iperf_status < 0: - self.close() - message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - self.close() - - # Kill iperf server on EPC side - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) - self.close() - else: - cmd = 'killall --signal SIGKILL iperf' - logging.debug(cmd) - subprocess.run(cmd, shell=True) - time.sleep(1) - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - # in case of failure, retrieve server log - if (clientStatus == -1) or (clientStatus == -2): - if launchFromEpc: - time.sleep(1) - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) - # in case of OAI-UE - if (device_id == 'OAI-UE'): - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - - def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): - try: - # Single-UE profile -- iperf only on one UE - if self.iperf_profile == 'single-ue' and idx != 0: - return - useIperf3 = False - udpIperf = True - - self.ueIperfVersion = '2.0.5' - if (device_id != 'OAI-UE'): - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - self.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - # Checking if iperf / iperf3 are installed - if self.ADBCentralized: - self.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) - result = re.search('iperf3', str(self.ssh.before)) - if result is None: - result = re.search('iperf', str(self.ssh.before)) - if result is None: - message = 'Neither iperf nor iperf3 installed on UE!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - else: - if self.ADBCentralized: - self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) - result = re.search('iperf version 2.0.5', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.10' - else: - useIperf3 = True - self.close() - else: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('iperf --version', '\$', 5) - result = re.search('iperf version 2.0.5', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.10' - self.close() - # in case of iperf, UL has its own function - if (not useIperf3): - result = re.search('-R', str(self.iperf_args)) - if result is not None: - self.Iperf_UL_common(lock, UE_IPAddress, device_id, idx, ue_num, statusQueue) - return - - # Launch the IPERF server on the UE side for DL - if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('-u', str(self.iperf_args)) - if result is None: - self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) - udpIperf = False - else: - self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) - else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - if self.ADBCentralized: - if (useIperf3): - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) - else: - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('-u', str(self.iperf_args)) - if result is None: - self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) - udpIperf = False - else: - self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) - else: - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) - - time.sleep(0.5) - self.close() - - # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn - # But for OAI-Rel14-CUPS, we launch from python executor - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - launchFromEpc = False - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - iperf_time = self.Iperf_ComputeTime() - time.sleep(0.5) - - if udpIperf: - modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) - else: - modified_options = str(self.iperf_args) - time.sleep(0.5) - - if launchFromEpc: - self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - else: - if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') - if (useIperf3): - self.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - - clientStatus = 0 - self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) - else: - if launchFromEpc: - iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - if self.ueIperfVersion == self.dummyIperfVersion: - prefix = '' - else: - prefix = '' - if self.ueIperfVersion == '2.0.5': - prefix = '/opt/iperf-2.0.5/bin/' - cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - iperf_status = ret.returncode - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if iperf_status < 0: - if launchFromEpc: - self.close() - message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - self.close() - - # Kill the IPERF server that runs in background - if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('killall iperf', '\$', 5) - else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) - result = re.search('shell +(?P\d+)', str(self.ssh.before)) - if result is not None: - pid_iperf = result.group('pid') - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - self.close() - # if the client report is absent, try to analyze the server log file - if (clientStatus == -1): - time.sleep(1) - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - if (device_id == 'OAI-UE'): - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - else: - self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) - - # in case of OAI UE: - if (device_id == 'OAI-UE'): - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - if not launchFromEpc: - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - else: - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def IperfNoS1(self): - if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = True - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - server_on_enb = re.search('-R', str(self.iperf_args)) - if server_on_enb is not None: - iServerIPAddr = self.eNBIPAddress - iServerUser = self.eNBUserName - iServerPasswd = self.eNBPassword - iClientIPAddr = self.UEIPAddress - iClientUser = self.UEUserName - iClientPasswd = self.UEPassword - else: - iServerIPAddr = self.UEIPAddress - iServerUser = self.UEUserName - iServerPasswd = self.UEPassword - iClientIPAddr = self.eNBIPAddress - iClientUser = self.eNBUserName - iClientPasswd = self.eNBPassword - # Starting the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - # args SHALL be "-c client -u any" - # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 - # -B 10.0.1.1 -u -s -i 1 -fm - server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) - server_options = server_options.replace('-c','-B') - self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) - self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) - time.sleep(0.5) - self.close() - - # Starting the iperf client - modified_options = self.Iperf_ComputeModifiedBW(0, 1) - modified_options = modified_options.replace('-R','') - iperf_time = self.Iperf_ComputeTime() - self.open(iClientIPAddr, iClientUser, iClientPasswd) - self.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) - iperf_status = self.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) - status_queue = SimpleQueue() - lock = Lock() - if iperf_status < 0: - message = 'iperf on OAI UE crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - clientStatus = -2 - else: - clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - self.close() - - # Stopping the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - self.command('killall --signal SIGKILL iperf', '\$', 5) - time.sleep(0.5) - self.close() - if (clientStatus == -1): - if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '.log') - self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - - # copying on the EPC server for logCollection - copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') - copyin_res = self.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') - iperf_noperf = False - if status_queue.empty(): - iperf_status = False - else: - iperf_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - iperf_status = False - if (count > 0): - iperf_noperf = True - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) - elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def Iperf(self): - result = re.search('noS1', str(self.Initialize_eNB_args)) - if result is not None: - self.IperfNoS1() - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - check_OAI_UE = True - else: - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB() - return - - self.dummyIperfVersion = '2.0.10' - #cmd = 'iperf --version' - #logging.debug(cmd + '\n') - #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) - #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) - #if result is not None: - # dummyIperfVersion = '2.0.5' - #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) - #if result is not None: - # dummyIperfVersion = '2.0.10' - - multi_jobs = [] - i = 0 - ue_num = len(self.UEIPAddresses) - lock = Lock() - status_queue = SimpleQueue() - for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = SSH.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - iperf_status = True - iperf_noperf = False - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - iperf_status = False - if (count > 0): - iperf_noperf = True - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) - elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def CheckProcessExist(self, check_eNB, check_OAI_UE): - multi_jobs = [] - status_queue = SimpleQueue() - # in noS1 config, no need to check status from EPC - result = re.search('noS1', str(self.Initialize_eNB_args)) - if result is None: - p = Process(target = SSH.CheckHSSProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - p = Process(target = SSH.CheckMMEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - p = Process(target = SSH.CheckSPGWProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - else: - if (check_eNB == False) and (check_OAI_UE == False): - return 0 - if check_eNB: - p = Process(target = SSH.CheckeNBProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - if check_OAI_UE: - p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - return -15 - else: - result = 0 - while (not status_queue.empty()): - status = status_queue.get() - if (status < 0): - result = status - if result == ENB_PROCESS_FAILED: - fileCheck = re.search('enb_', str(self.eNBLogFiles[0])) - if fileCheck is not None: - self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') - logStatus = self.AnalyzeLogFile_eNB(self.eNBLogFiles[0]) - if logStatus < 0: - result = logStatus - self.eNBLogFiles[0] = '' - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.TerminateFlexranCtrl() - return result - - def CheckOAIUEProcessExist(self, initialize_OAI_UE_flag): - multi_jobs = [] - status_queue = SimpleQueue() - if initialize_OAI_UE_flag == False: - p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - return -15 - else: - result = 0 - while (not status_queue.empty()): - status = status_queue.get() - if (status < 0): - result = status - if result == OAI_UE_PROCESS_FAILED: - fileCheck = re.search('ue_', str(self.UELogFile)) - if fileCheck is not None: - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') - logStatus = self.AnalyzeLogFile_UE(self.UELogFile) - if logStatus < 0: - result = logStatus - return result - - def CheckOAIUEProcess(self, status_queue): - try: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') - status_queue.put(OAI_UE_PROCESS_FAILED) - else: - status_queue.put(OAI_UE_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckeNBProcess(self, status_queue): - try: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') - status_queue.put(ENB_PROCESS_FAILED) - else: - status_queue.put(ENB_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckHSSProcess(self, status_queue): - try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('oai_hss -j', str(self.ssh.before)) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('hss_sim s6as diam_hss', str(self.ssh.before)) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m HSS Process Not Found! \u001B[0m') - status_queue.put(HSS_PROCESS_FAILED) - else: - status_queue.put(HSS_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckMMEProcess(self, status_queue): - try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('mme -c', str(self.ssh.before)) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('mme', str(self.ssh.before)) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m MME Process Not Found! \u001B[0m') - status_queue.put(MME_PROCESS_FAILED) - else: - status_queue.put(MME_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckSPGWProcess(self, status_queue): - try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('spgwu -c ', str(self.ssh.before)) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) - result = re.search('xGw', str(self.ssh.before)) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m SPGW Process Not Found! \u001B[0m') - status_queue.put(SPGW_PROCESS_FAILED) - else: - status_queue.put(SPGW_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AnalyzeLogFile_eNB(self, eNBlogFile): - if (not os.path.isfile('./' + eNBlogFile)): - return -1 - enb_log_file = open('./' + eNBlogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - rrcSetupComplete = 0 - rrcReleaseRequest = 0 - rrcReconfigRequest = 0 - rrcReconfigComplete = 0 - rrcReestablishRequest = 0 - rrcReestablishComplete = 0 - rrcReestablishReject = 0 - rlcDiscardBuffer = 0 - rachCanceledProcedure = 0 - uciStatMsgCount = 0 - pdcpFailure = 0 - ulschFailure = 0 - cdrxActivationMessageCount = 0 - dropNotEnoughRBs = 0 - self.htmleNBFailureMsg = '' - isRRU = False - isSlave = False - slaveReceivesFrameResyncCmd = False - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures = 0 - X2HO_outNbProcedures = 0 - for line in enb_log_file.readlines(): - if X2HO_state == X2_HO_REQ_STATE__IDLE: - result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ - result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK - if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: - result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE - if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: - result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ - if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: - result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures += 1 - if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: - result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_outNbProcedures += 1 - - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) - res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) - if res1 is not None and res2 is not None: - requested_option = int(res1.group('requested_option')) - applied_option = int(res2.group('applied_option')) - if requested_option == applied_option: - self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' - else: - self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('[Ss]egmentation [Ff]ault', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./lte_build_oai/build/lte-softmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('Setting function for RU', str(line)) - if result is not None: - isRRU = True - if isRRU: - result = re.search('RU 0 is_slave=yes', str(line)) - if result is not None: - isSlave = True - if isSlave: - result = re.search('Received RRU_frame_resynch command', str(line)) - if result is not None: - slaveReceivesFrameResyncCmd = True - result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) - if result is not None: - rrcSetupComplete += 1 - result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) - if result is not None: - rrcReleaseRequest += 1 - result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) - if result is not None: - rrcReconfigRequest += 1 - result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) - if result is not None: - rrcReconfigComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) - if result is not None: - rrcReestablishRequest += 1 - result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) - if result is not None: - rrcReestablishComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) - if result is not None: - rrcReestablishReject += 1 - result = re.search('CDRX configuration activated after RRC Connection', str(line)) - if result is not None: - cdrxActivationMessageCount += 1 - result = re.search('uci->stat', str(line)) - if result is not None: - uciStatMsgCount += 1 - result = re.search('PDCP.*Out of Resources.*reason', str(line)) - if result is not None: - pdcpFailure += 1 - result = re.search('ULSCH in error in round', str(line)) - if result is not None: - ulschFailure += 1 - result = re.search('BAD all_segments_received', str(line)) - if result is not None: - rlcDiscardBuffer += 1 - result = re.search('Canceled RA procedure for UE rnti', str(line)) - if result is not None: - rachCanceledProcedure += 1 - result = re.search('dropping, not enough RBs', str(line)) - if result is not None: - dropNotEnoughRBs += 1 - enb_log_file.close() - logging.debug(' File analysis completed') - if uciStatMsgCount > 0: - statMsg = 'eNB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if pdcpFailure > 0: - statMsg = 'eNB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if ulschFailure > 0: - statMsg = 'eNB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if dropNotEnoughRBs > 0: - statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if rrcSetupComplete > 0: - rrcMsg = 'eNB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReleaseRequest > 0: - rrcMsg = 'eNB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: - rrcMsg = 'eNB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: - rrcMsg = 'eNB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_inNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_outNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) - if res1 is not None: - if cdrxActivationMessageCount > 0: - rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - else: - rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' - logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rachCanceledProcedure > 0: - rachMsg = 'eNB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' - logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rachMsg + '\n' - if isRRU: - if isSlave: - if slaveReceivesFrameResyncCmd: - rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - else: - rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - self.prematureExit = True - return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED - if foundSegFault: - logging.debug('\u001B[1;37;41m eNB ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;37;41m eNB ended with an assertion! \u001B[0m') - self.htmleNBFailureMsg += msgAssertion - return ENB_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m eNB faced real time issues! \u001B[0m') - self.htmleNBFailureMsg += 'eNB faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE - if rlcDiscardBuffer > 0: - rlcMsg = 'eNB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' - logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rlcMsg + '\n' - return ENB_PROCESS_REALTIME_ISSUE - return 0 - - def AnalyzeLogFile_UE(self, UElogFile): - if (not os.path.isfile('./' + UElogFile)): - return -1 - ue_log_file = open('./' + UElogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - uciStatMsgCount = 0 - pdcpDataReqFailedCount = 0 - badDciCount = 0 - rrcConnectionRecfgComplete = 0 - no_cell_sync_found = False - mib_found = False - frequency_found = False - plmn_found = False - self.htmlUEFailureMsg = '' - for line in ue_log_file.readlines(): - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./lte-uesoftmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('uci->stat', str(line)) - if result is not None and not exitSignalReceived: - uciStatMsgCount += 1 - result = re.search('PDCP data request failed', str(line)) - if result is not None and not exitSignalReceived: - pdcpDataReqFailedCount += 1 - result = re.search('bad DCI 1A', str(line)) - if result is not None and not exitSignalReceived: - badDciCount += 1 - result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) - if result is not None: - rrcConnectionRecfgComplete += 1 - # No cell synchronization found, abandoning - result = re.search('No cell synchronization found, abandoning', str(line)) - if result is not None: - no_cell_sync_found = True - result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) - if result is not None and (not mib_found): - try: - mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " nidcell = " + result.group('nidcell') - self.htmlUEFailureMsg += mibMsg - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " n_rb_dl = " + result.group('n_rb_dl') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " phich_duration = " + result.group('phich_duration') - self.htmlUEFailureMsg += mibMsg - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " phich_resource = " + result.group('phich_resource') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " tx_ant = " + result.group('tx_ant') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mib_found = True - except Exception as e: - logging.error('\033[91m' + "MIB marker was not found" + '\033[0m') - result = re.search("Measured Carrier Frequency (?P\d{1,15}) Hz", str(line)) - if result is not None and (not frequency_found): - try: - mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - frequency_found = True - except Exception as e: - logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') - result = re.search("PLMN MCC (?P\d{1,3}), MNC (?P\d{1,3}), TAC", str(line)) - if result is not None and (not plmn_found): - try: - mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - plmn_found = True - except Exception as e: - logging.error('\033[91m' + "PLMN not found" + '\033[0m') - result = re.search("Found (?P[\w,\s]{1,15}) \(name from internal table\)", str(line)) - if result is not None: - try: - mibMsg = "The operator is: " + result.group('operator') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - except Exception as e: - logging.error('\033[91m' + "Operator name not found" + '\033[0m') - result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line)) - if result is not None: - try: - mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) - self.htmlUEFailureMsg += mibMsg + ' -> ' - logging.debug('\033[94m' + mibMsg + '\033[0m') - except Exception as e: - logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') - result = re.search("DL Carrier Frequency/ARFCN : (?P\d{1,15}/\d{1,4})", str(line)) - if result is not None: - try: - freq = result.group('carrier_frequency') - new_freq = re.sub('/[0-9]+','',freq) - float_freq = float(new_freq) / 1000000 - self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' - logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') - except Exception as e: - logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') - result = re.search("AllowedMeasBandwidth : (?P\d{1,7})", str(line)) - if result is not None: - try: - prb = result.group('allowed_bandwidth') - self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' - logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') - except Exception as e: - logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') - ue_log_file.close() - if rrcConnectionRecfgComplete > 0: - statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' - logging.debug('\033[94m' + statMsg + '\033[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if uciStatMsgCount > 0: - statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if pdcpDataReqFailedCount > 0: - statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if badDciCount > 0: - statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1A" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if foundSegFault: - logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') - self.htmlUEFailureMsg += 'UE showed an assertion!\n' - if not mib_found or not frequency_found: - return OAI_UE_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') - self.htmlUEFailureMsg += 'UE faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE - if no_cell_sync_found and not mib_found: - logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') - self.htmlUEFailureMsg += 'UE could not synchronize!\n' - return OAI_UE_PROCESS_COULD_NOT_SYNC - return 0 - - def TerminateeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) - time.sleep(10) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) - time.sleep(5) - self.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.close() - # If tracer options is on, stopping tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - time.sleep(1) - if self.EPC_PcapFileName != '': - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') - self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') - self.close() - logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) - enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] - raw_record_file = enbLogFile.replace('.log', '_record.raw') - replay_log_file = enbLogFile.replace('.log', '_replay.log') - extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') - extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') - self.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) - self.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) - self.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) - self.close() - self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') - logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.eNBLogFiles[int(self.eNB_instance)] = '' - else: - analyzeFile = False - if self.eNBLogFiles[int(self.eNB_instance)] != '': - analyzeFile = True - fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] - self.eNBLogFiles[int(self.eNB_instance)] = '' - if analyzeFile: - copyin_res = self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy eNB logfile to analyze it! \u001B[0m') - self.htmleNBFailureMsg = 'Could not copy eNB logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) - return - if self.eNB_serverId != '0': - self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') - logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m ' + fileToAnalyze) - logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) - if (logStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', logStatus) - self.preamtureExit = True - return - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateHSS(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('oai_hss -j', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) - time.sleep(1) - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) - else: - logging.error('This should not happen!') - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateMME(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) - result = re.search('mme -c', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) - else: - logging.error('This should not happen!') - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateSPGW(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('spgwc -c |spgwu -c ', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) - self.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) - result = re.search('-w ', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) - else: - logging.error('This should not happen!') - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateFlexranCtrl(self): - if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) - time.sleep(1) - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) - time.sleep(1) - self.close() - self.flexranCtrlStarted = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # back in airplane mode on (ie radio off) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) - result = re.search('shell +(?P\d+)', str(self.ssh.before)) - if result is not None: - pid_iperf = result.group('pid') - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def TerminateUE(self): - terminate_ue_flag = True - self.GetAllUEDevices(terminate_ue_flag) - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target= SSH.TerminateUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateOAIUE(self): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) - time.sleep(10) - self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) - time.sleep(5) - self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.close() - result = re.search('ue_', str(self.UELogFile)) - if result is not None: - copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') - self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') - self.UELogFile = '' - return - logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_UE(self.UELogFile) - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is not None: - ueAction = 'Sniffing' - else: - ueAction = 'Connection' - if (logStatus < 0): - logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') - # In case of sniffing on commercial eNBs we have random results - # Not an error then - if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): - self.Initialize_OAI_UE_args = '' - self.AutoTerminateUEandeNB() - else: - logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.UELogFile = '' - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def AutoTerminateUEandeNB(self): - if (self.ADBIPAddress != 'none'): - self.testCase_id = 'AUTO-KILL-UE' - self.desc = 'Automatic Termination of UE' - self.ShowTestID() - self.TerminateUE() - if (self.Initialize_OAI_UE_args != ''): - self.testCase_id = 'AUTO-KILL-UE' - self.desc = 'Automatic Termination of UE' - self.ShowTestID() - self.TerminateOAIUE() - if (self.Initialize_eNB_args != ''): - self.testCase_id = 'AUTO-KILL-eNB' - self.desc = 'Automatic Termination of eNB' - self.ShowTestID() - self.eNB_instance = '0' - self.TerminateeNB() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.testCase_id = 'AUTO-KILL-flexran-ctl' - self.desc = 'Automatic Termination of FlexRan CTL' - self.ShowTestID() - self.TerminateFlexranCtrl() - self.prematureExit = True - - def IdleSleep(self): - time.sleep(self.idle_sleep_time) - self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) - - def X2_Status(self, idx, fileName): - cmd = "curl --silent http://" + self.EPCIPAddress + ":9999/stats | jq '.' > " + fileName - message = cmd + '\n' - logging.debug(cmd) - subprocess.run(cmd, shell=True) - if idx == 0: - cmd = "jq '.mac_stats | length' " + fileName - strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2NbENBs = int(strNbEnbs.strip()) - cnt = 0 - while cnt < self.x2NbENBs: - cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName - bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBBsIds[idx].append(bs_id.strip()) - cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName - stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) - nbUEs = int(stNbUEs.strip()) - ueIdx = 0 - self.x2ENBConnectedUEs[idx].append([]) - while ueIdx < nbUEs: - cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName - rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip()) - ueIdx += 1 - cnt += 1 - - msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" - logging.debug(msg) - message += msg + '\n' - cnt = 0 - while cnt < self.x2NbENBs: - msg = " -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][cnt])) + " UE(s)" - logging.debug(msg) - message += msg + '\n' - ueIdx = 0 - while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]): - msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx]) - logging.debug(msg) - message += msg + '\n' - ueIdx += 1 - cnt += 1 - return message - - def Perform_X2_Handover(self): - html_queue = SimpleQueue() - fullMessage = '
'
-		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
-		logging.debug(msg)
-		fullMessage += msg + '\n'
-		if self.x2_ho_options == 'network':
-			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
-				self.x2ENBBsIds = []
-				self.x2ENBConnectedUEs = []
-				self.x2ENBBsIds.append([])
-				self.x2ENBBsIds.append([])
-				self.x2ENBConnectedUEs.append([])
-				self.x2ENBConnectedUEs.append([])
-				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
-
-				msg = "Activating the X2 Net control on each eNB"
-				logging.debug(msg)
-				fullMessage += msg + '\n'
-				eNB_cnt = self.x2NbENBs
-				cnt = 0
-				while cnt < eNB_cnt:
-					cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1"
-					logging.debug(cmd)
-					fullMessage += cmd + '\n'
-					subprocess.run(cmd, shell=True)
-					cnt += 1
-				# Waiting for the activation to be active
-				time.sleep(10)
-				msg = "Switching UE(s) from eNB to eNB"
-				logging.debug(msg)
-				fullMessage += msg + '\n'
-				cnt = 0
-				while cnt < eNB_cnt:
-					ueIdx = 0
-					while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]):
-						cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
-						logging.debug(cmd)
-						fullMessage += cmd + '\n'
-						subprocess.run(cmd, shell=True)
-						ueIdx += 1
-					cnt += 1
-				time.sleep(10)
-				# check
-				logging.debug("Checking the Status after X2 Handover")
-				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
-				cnt = 0
-				x2Status = True
-				while cnt < eNB_cnt:
-					if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
-						x2Status = False
-					cnt += 1
-				if x2Status:
-					msg = "X2 Handover was successful"
-					logging.debug(msg)
-					fullMessage += msg + '
' - html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - else: - msg = "X2 Handover FAILED" - logging.error(msg) - fullMessage += msg + '' - html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) - - def LogCollectBuild(self): - if (self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != ''): - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword - SourceCodePath = self.eNBSourceCodePath - elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - SourceCodePath = self.UESourceCodePath - else: - sys.exit('Insufficient Parameter') - self.open(IPAddress, UserName, Password) - self.command('cd ' + SourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('rm -f build.log.zip', '\$', 5) - self.command('zip build.log.zip build_log_*/*', '\$', 60) - self.close() - - def LogCollecteNB(self): - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) - self.close() - - def LogCollectPing(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('rm -f ping.log.zip', '\$', 5) - self.command('zip ping.log.zip ping*.log', '\$', 60) - self.command('rm ping*.log', '\$', 5) - self.close() - - def LogCollectIperf(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('rm -f iperf.log.zip', '\$', 5) - self.command('zip iperf.log.zip iperf*.log', '\$', 60) - self.command('rm iperf*.log', '\$', 5) - self.close() - - def LogCollectHSS(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f hss.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip hss.log.zip hss*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) - self.command('zip hss.log.zip hss.log', '\$', 60) - else: - logging.error('This option should not occur!') - self.close() - - def LogCollectMME(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f mme.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip mme.log.zip mme*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) - self.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) - else: - logging.error('This option should not occur!') - self.close() - - def LogCollectSPGW(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f spgw.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip spgw.log.zip spgw*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) - self.command('zip spgw.log.zip xGwLog.0', '\$', 60) - else: - logging.error('This option should not occur!') - self.close() - - def LogCollectOAIUE(self): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) - self.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) - self.close() - - def RetrieveSystemVersion(self, machine): - if self.eNBIPAddress == 'none' or self.UEIPAddress == 'none': - self.OsVersion = 'Ubuntu 16.04.5 LTS' - self.KernelVersion = '4.15.0-45-generic' - self.UhdVersion = '3.13.0.1-0' - self.UsrpBoard = 'B210' - self.CpuNb = '4' - self.CpuModel = 'Intel(R) Core(TM) i5-6200U' - self.CpuMHz = '2399.996 MHz' - return 0 - if machine == 'eNB': - if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword - else: - return -1 - if machine == 'UE': - if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - else: - return -1 - - self.open(IPAddress, UserName, Password) - self.command('lsb_release -a', '\$', 5) - result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) - if result is not None: - self.OsVersion = result.group('os_type') - logging.debug('OS is: ' + self.OsVersion) - self.command('uname -r', '\$', 5) - result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', str(self.ssh.before)) - if result is not None: - self.KernelVersion = result.group('kernel_version') - logging.debug('Kernel Version is: ' + self.KernelVersion) - self.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) - result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', str(self.ssh.before)) - if result is not None: - self.UhdVersion = result.group('uhd_version') - logging.debug('UHD Version is: ' + self.UhdVersion) - self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) - result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) - if result is not None: - self.UsrpBoard = result.group('usrp_board') - logging.debug('USRP Board is: ' + self.UsrpBoard) - self.command('lscpu', '\$', 5) - result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', str(self.ssh.before)) - if result is not None: - self.CpuNb = result.group('nb_cpus') - logging.debug('nb_cpus: ' + self.CpuNb) - self.CpuModel = result.group('model') - logging.debug('model: ' + self.CpuModel) - self.CpuMHz = result.group('cpu_mhz') + ' MHz' - logging.debug('cpu_mhz: ' + self.CpuMHz) - self.close() - -#----------------------------------------------------------- -# HTML Reporting.... -#----------------------------------------------------------- - def CreateHtmlHeader(self): - if (not self.htmlHeaderCreated): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML header \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - self.htmlFile = open('test_results.html', 'w') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') - self.htmlFile.write('\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
' + str(machine) + ' Server Characteristics' + str('eNB') + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
' + str('UE') + ' Server Characteristics
OS Version
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if self.ranAllowMerge != '': - commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + self.ranCommitID, shell=True, universal_newlines=True) - commit_message = commit_message.strip() - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranTargetBranch == ''): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + self.ranRepository + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + self.ranBranch + '
Source Commit ID Commit ID ' + self.ranCommitID + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + self.ranTargetBranch + '
\n') - - if (self.ADBIPAddress != 'none'): - terminate_ue_flag = True - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') - self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.close() - - def CreateHtmlTabHeader(self): - if (not self.htmlHeaderCreated): - if (not os.path.isfile('test_results.html')): - self.CreateHtmlHeader() - self.htmlFile = open('test_results.html', 'a') - if (self.nbTestXMLfiles == 1): - self.htmlFile.write('
\n') - self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') - else: - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.htmlUEConnected == -1): - terminate_ue_flag = True - if (self.ADBIPAddress != 'none'): - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' \n') - i += 1 - self.htmlFile.write(' \n') - self.htmlHeaderCreated = True - - def CreateHtmlTabFooter(self, passStatus): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') - self.htmlFile.write('
\n') - self.htmlFile.close() - time.sleep(1) - if passStatus: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" - subprocess.run(cmd, shell=True) - else: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" - subprocess.run(cmd, shell=True) - self.htmlFooterCreated = False - - def CreateHtmlFooter(self, passStatus): - if (os.path.isfile('test_results.html')): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML footer \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - - self.htmlFile = open('test_results.html', 'a') - self.htmlFile.write('
\n') - self.htmlFile.write('

\n') - self.htmlFile.write(' \n') - - machines = [ 'eNB', 'UE' ] - for machine in machines: - res = self.RetrieveSystemVersion(machine) - if res == -1: - continue - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') - self.htmlFile.write('

\n') - self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('\n') - self.htmlFile.close() - - def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - if (processesStatus == 0): - self.htmlFile.write(' ' + str(status) + '\n') - elif (processesStatus == ENB_PROCESS_FAILED): - self.htmlFile.write(' KO - eNB process not found\n') - elif (processesStatus == OAI_UE_PROCESS_FAILED): - self.htmlFile.write(' KO - OAI UE process not found\n') - elif (processesStatus == ENB_PROCESS_SEG_FAULT): - self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') - elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): - self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') - elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): - self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') - elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): - self.htmlFile.write(' OK?\n') - elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): - self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') - elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): - self.htmlFile.write(' KO - UE could not sync\n') - elif (processesStatus == HSS_PROCESS_FAILED): - self.htmlFile.write(' KO - HSS process not found\n') - elif (processesStatus == MME_PROCESS_FAILED): - self.htmlFile.write(' KO - MME process not found\n') - elif (processesStatus == SPGW_PROCESS_FAILED): - self.htmlFile.write(' KO - SPGW process not found\n') - elif (processesStatus == UE_IP_ADDRESS_ISSUE): - self.htmlFile.write(' KO - Could not retrieve UE IP address\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - if (len(str(self.htmleNBFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') - self.htmleNBFailureMsg = '' - elif (len(str(self.htmlUEFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') - self.htmlUEFailureMsg = '' - else: - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - - def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - addOrangeBK = False - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - self.htmlFile.write(' ' + str(status) + '\n') - else: - addOrangeBK = True - self.htmlFile.write(' ' + str(status) + '\n') - i = 0 - while (i < self.htmlUEConnected): - if (i < ue_status): - if (not ue_queue.empty()): - if (addOrangeBK): - self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') - else: - self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') - else: - self.htmlFile.write(' -\n') - else: - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - -#----------------------------------------------------------- -# ShowTestID() -#----------------------------------------------------------- - def ShowTestID(self): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1mTest ID:' + self.testCase_id + '\u001B[0m') - logging.debug('\u001B[1m' + self.desc + '\u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - -#----------------------------------------------------------- -# Usage() -#----------------------------------------------------------- -def Usage(): - print('----------------------------------------------------------------------------------------------------------------------') - print('main.py Ver:' + Version) - print('----------------------------------------------------------------------------------------------------------------------') - print('Usage: python main.py [options]') - print(' --help Show this help.') - print(' --mode=[Mode]') - print(' TesteNB') - print(' InitiateHtml, FinalizeHtml') - print(' TerminateeNB, TerminateUE, TerminateHSS, TerminateMME, TerminateSPGW') - print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf') - print('---------------------------------------------------------------------------------------------------- Git Options --') - print(' --ranRepository=[OAI RAN Repository URL]') - print(' --ranBranch=[OAI RAN Repository Branch]') - print(' --ranCommitID=[OAI RAN Repository Commit SHA-1]') - print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)]') - print(' --ranTargetBranch=[Target Branch in case of a Merge Request]') - print('--------------------------------------------------------------------------------------------- eNB Server Options --') - print(' --eNBIPAddress=[eNB\'s IP Address]') - print(' --eNBUserName=[eNB\'s Login User Name]') - print(' --eNBPassword=[eNB\'s Login Password]') - print(' --eNBSourceCodePath=[eNB\'s Source Code Path]') - print('------------------------------------------------------------------------------------------ OAI UE Server Options --') - print(' --UEIPAddress=[UE\'s IP Address]') - print(' --UEUserName=[UE\'s Login User Name]') - print(' --UEPassword=[UE\'s Login Password]') - print(' --UESourceCodePath=[UE\'s Source Code Path]') - print('--------------------------------------------------------------------------------------------- EPC Server Options --') - print(' --EPCIPAddress=[EPC\'s IP Address]') - print(' --EPCUserName=[EPC\'s Login User Name]') - print(' --EPCPassword=[EPC\'s Login Password]') - print(' --EPCSourceCodePath=[EPC\'s Source Code Path]') - print(' --EPCType=[EPC\'s Type: OAI or ltebox or OAI-Rel14-CUPS]') - print('--------------------------------------------------------------------------------------------- ABD Server Options --') - print(' --ADBIPAddress=[ADB\'s IP Address]') - print(' --ADBUserName=[ADB\'s Login User Name]') - print(' --ADBPassword=[ADB\'s Login Password]') - print('----------------------------------------------------------------------------------------------------------------------') - print(' --XMLTestFile=[XML Test File to be run]') - print('----------------------------------------------------------------------------------------------------------------------') - -def CheckClassValidity(action,id): - if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': - logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) - return False - return True - -def GetParametersFromXML(action): - if action == 'Build_eNB': - SSH.Build_eNB_args = test.findtext('Build_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - xmlBgBuildField = test.findtext('backgroundBuild') - if (xmlBgBuildField is None): - SSH.backgroundBuild = False - else: - if re.match('true', xmlBgBuildField, re.IGNORECASE): - SSH.backgroundBuild = True - else: - SSH.backgroundBuild = False - - if action == 'WaitEndBuild_eNB': - SSH.Build_eNB_args = test.findtext('Build_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - - if action == 'Initialize_eNB': - SSH.Initialize_eNB_args = test.findtext('Initialize_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - - if action == 'Terminate_eNB': - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - - if action == 'Attach_UE': - nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') - if (nbMaxUEtoAttach is None): - SSH.nbMaxUEtoAttach = -1 - else: - SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach) - - if action == 'CheckStatusUE': - expectedNBUE = test.findtext('expectedNbOfConnectedUEs') - if (expectedNBUE is None): - SSH.expectedNbOfConnectedUEs = -1 - else: - SSH.expectedNbOfConnectedUEs = int(expectedNBUE) - - if action == 'Build_OAI_UE': - SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') - - if action == 'Initialize_OAI_UE': - SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') - SSH.UE_instance = test.findtext('UE_instance') - if (SSH.UE_instance is None): - SSH.UE_instance = '0' - - if action == 'Terminate_OAI_UE': - SSH.eNB_instance = test.findtext('UE_instance') - if (SSH.UE_instance is None): - SSH.UE_instance = '0' - - if action == 'Ping' or action == 'Ping_CatM_module': - SSH.ping_args = test.findtext('ping_args') - SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') - - if action == 'Iperf': - SSH.iperf_args = test.findtext('iperf_args') - SSH.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') - SSH.iperf_profile = test.findtext('iperf_profile') - if (SSH.iperf_profile is None): - SSH.iperf_profile = 'balanced' - else: - if SSH.iperf_profile != 'balanced' and SSH.iperf_profile != 'unbalanced' and SSH.iperf_profile != 'single-ue': - logging.debug('ERROR: test-case has wrong profile ' + SSH.iperf_profile) - SSH.iperf_profile = 'balanced' - - if action == 'IdleSleep': - string_field = test.findtext('idle_sleep_time_in_sec') - if (string_field is None): - SSH.idle_sleep_time = 5 - else: - SSH.idle_sleep_time = int(string_field) - - if action == 'Perform_X2_Handover': - string_field = test.findtext('x2_ho_options') - if (string_field is None): - SSH.x2_ho_options = 'network' - else: - if string_field != 'network': - logging.error('ERROR: test-case has wrong option ' + string_field) - SSH.x2_ho_options = 'network' - else: - SSH.x2_ho_options = string_field - - -#check if given test is in list -#it is in list if one of the strings in 'list' is at the beginning of 'test' -def test_in_list(test, list): - for check in list: - check=check.replace('+','') - if (test.startswith(check)): - return True - return False - -def receive_signal(signum, frame): - sys.exit(1) - -#----------------------------------------------------------- -# Parameter Check -#----------------------------------------------------------- -mode = '' -SSH = SSHConnection() - -argvs = sys.argv -argc = len(argvs) -cwd = os.getcwd() - -while len(argvs) > 1: - myArgv = argvs.pop(1) # 0th is this file's name - if re.match('^\-\-help$', myArgv, re.IGNORECASE): - Usage() - sys.exit(0) - elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) - mode = matchReg.group(1) - elif re.match('^\-\-eNBRepository=(.+)$|^\-\-ranRepository(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) - SSH.ranRepository = matchReg.group(1) - elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) - doMerge = matchReg.group(1) - if ((doMerge == 'true') or (doMerge == 'True')): - SSH.ranAllowMerge = True - elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) - SSH.ranBranch = matchReg.group(1) - elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) - SSH.ranCommitID = matchReg.group(1) - elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) - SSH.ranTargetBranch = matchReg.group(1) - elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBIPAddress = matchReg.group(1) - elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1IPAddress = matchReg.group(1) - elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2IPAddress = matchReg.group(1) - elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBUserName = matchReg.group(1) - elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1UserName = matchReg.group(1) - elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2UserName = matchReg.group(1) - elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBPassword = matchReg.group(1) - elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1Password = matchReg.group(1) - elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2Password = matchReg.group(1) - elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBSourceCodePath = matchReg.group(1) - elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1SourceCodePath = matchReg.group(1) - elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2SourceCodePath = matchReg.group(1) - elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCIPAddress = matchReg.group(1) - elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCBranch = matchReg.group(1) - elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCUserName = matchReg.group(1) - elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCPassword = matchReg.group(1) - elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCSourceCodePath = matchReg.group(1) - elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) - if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): - SSH.EPCType = matchReg.group(1) - else: - sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') - elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBIPAddress = matchReg.group(1) - elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBUserName = matchReg.group(1) - elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) - if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): - if re.match('distributed', matchReg.group(1), re.IGNORECASE): - SSH.ADBCentralized = False - else: - SSH.ADBCentralized = True - else: - sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') - elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBPassword = matchReg.group(1) - elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) - SSH.testXMLfiles.append(matchReg.group(1)) - SSH.nbTestXMLfiles += 1 - elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.UEIPAddress = matchReg.group(1) - elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.UEUserName = matchReg.group(1) - elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.UEPassword = matchReg.group(1) - elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.UESourceCodePath = matchReg.group(1) -# reading repeatCounts from command line - elif re.match('^\-\-repeatCounts=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-repeatCounts=(.+)$', myArgv, re.IGNORECASE) - SSH.repeatCounts = int(matchReg.group(1)) - elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) - finalStatus = matchReg.group(1) - if ((finalStatus == 'true') or (finalStatus == 'True')): - SSH.finalStatus = True - else: - Usage() - sys.exit('Invalid Parameter: ' + myArgv) - -if re.match('^TerminateeNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.eNB_serverId = '0' - SSH.eNB_instance = '0' - SSH.eNBSourceCodePath = '/tmp/' - SSH.TerminateeNB() -elif re.match('^TerminateUE$', mode, re.IGNORECASE): - if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): - Usage() - sys.exit('Insufficient Parameter') - signal.signal(signal.SIGUSR1, receive_signal) - SSH.TerminateUE() -elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '': - Usage() - sys.exit('Insufficient Parameter') - signal.signal(signal.SIGUSR1, receive_signal) - SSH.TerminateOAIUE() -elif re.match('^TerminateHSS$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.TerminateHSS() -elif re.match('^TerminateMME$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.TerminateMME() -elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.TerminateSPGW() -elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): - if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == ''): - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectBuild() -elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollecteNB() -elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectHSS() -elif re.match('^LogCollectMME$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectMME() -elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectSPGW() -elif re.match('^LogCollectPing$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectPing() -elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectIperf() -elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectOAIUE() -elif re.match('^InitiateHtml$', mode, re.IGNORECASE): - if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): - Usage() - sys.exit('Insufficient Parameter') - count = 0 - foundCount = 0 - while (count < SSH.nbTestXMLfiles): - xml_test_file = cwd + "/" + SSH.testXMLfiles[count] - xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count] - if (os.path.isfile(xml_test_file)): - xmlTree = ET.parse(xml_test_file) - xmlRoot = xmlTree.getroot() - SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) - foundCount += 1 - count += 1 - if foundCount != SSH.nbTestXMLfiles: - SSH.nbTestXMLfiles = foundCount - SSH.CreateHtmlHeader() -elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - SSH.CreateHtmlFooter(SSH.finalStatus) -elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): - if re.match('^TesteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - - if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): - SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") - SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") - else: - if SSH.UEIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': - Usage() - sys.exit('UE: Insufficient Parameter') - - #read test_case_list.xml file - # if no parameters for XML file, use default value - if (SSH.nbTestXMLfiles != 1): - xml_test_file = cwd + "/test_case_list.xml" - else: - xml_test_file = cwd + "/" + SSH.testXMLfiles[0] - - xmlTree = ET.parse(xml_test_file) - xmlRoot = xmlTree.getroot() - - exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') - requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') - if (SSH.nbTestXMLfiles == 1): - SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) -# repeatCounts not read from the xml file -# repeatCount = xmlRoot.findtext('repeatCount',default='1') -# SSH.repeatCounts.append(int(repeatCount)) - all_tests=xmlRoot.findall('testCase') - - exclusion_tests=exclusion_tests.split() - requested_tests=requested_tests.split() - - #check that exclusion tests are well formatted - #(6 digits or less than 6 digits followed by +) - for test in exclusion_tests: - if (not re.match('^[0-9]{6}$', test) and - not re.match('^[0-9]{1,5}\+$', test)): - logging.debug('ERROR: exclusion test is invalidly formatted: ' + test) - sys.exit(1) - else: - logging.debug(test) - - #check that requested tests are well formatted - #(6 digits or less than 6 digits followed by +) - #be verbose - for test in requested_tests: - if (re.match('^[0-9]{6}$', test) or - re.match('^[0-9]{1,5}\+$', test)): - logging.debug('INFO: test group/case requested: ' + test) - else: - logging.debug('ERROR: requested test is invalidly formatted: ' + test) - sys.exit(1) - if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): - SSH.CheckFlexranCtrlInstallation() - - #get the list of tests to be done - todo_tests=[] - for test in requested_tests: - if (test_in_list(test, exclusion_tests)): - logging.debug('INFO: test will be skipped: ' + test) - else: - #logging.debug('INFO: test will be run: ' + test) - todo_tests.append(test) - - signal.signal(signal.SIGUSR1, receive_signal) - - SSH.CreateHtmlTabHeader() - - cnt = 0 - SSH.prematureExit = True - SSH.startTime = int(round(time.time() * 1000)) -# repeatCounts becomes an integer (was SSH.repeatCounts[0] --> becomes SSH.repeatCounts) - while cnt < SSH.repeatCounts and SSH.prematureExit: - SSH.prematureExit = False - for test_case_id in todo_tests: - if SSH.prematureExit: - break - for test in all_tests: - if SSH.prematureExit: - break - id = test.get('id') - if test_case_id != id: - continue - SSH.testCase_id = id - SSH.desc = test.findtext('desc') - action = test.findtext('class') - if (CheckClassValidity(action, id) == False): - continue - SSH.ShowTestID() - GetParametersFromXML(action) - if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': - if (SSH.ADBIPAddress != 'none'): - terminate_ue_flag = False - SSH.GetAllUEDevices(terminate_ue_flag) - if action == 'Build_eNB': - SSH.BuildeNB() - elif action == 'WaitEndBuild_eNB': - SSH.WaitBuildeNBisFinished() - elif action == 'Initialize_eNB': - SSH.InitializeeNB() - elif action == 'Terminate_eNB': - SSH.TerminateeNB() - elif action == 'Initialize_UE': - SSH.InitializeUE() - elif action == 'Terminate_UE': - SSH.TerminateUE() - elif action == 'Attach_UE': - SSH.AttachUE() - elif action == 'Detach_UE': - SSH.DetachUE() - elif action == 'DataDisable_UE': - SSH.DataDisableUE() - elif action == 'DataEnable_UE': - SSH.DataEnableUE() - elif action == 'CheckStatusUE': - SSH.CheckStatusUE() - elif action == 'Build_OAI_UE': - SSH.BuildOAIUE() - elif action == 'Initialize_OAI_UE': - SSH.InitializeOAIUE() - elif action == 'Terminate_OAI_UE': - SSH.TerminateOAIUE() - elif action == 'Initialize_CatM_module': - SSH.InitializeCatM() - elif action == 'Terminate_CatM_module': - SSH.TerminateCatM() - elif action == 'Attach_CatM_module': - SSH.AttachCatM() - elif action == 'Detach_CatM_module': - SSH.TerminateCatM() - elif action == 'Ping_CatM_module': - SSH.PingCatM() - elif action == 'Ping': - SSH.Ping() - elif action == 'Iperf': - SSH.Iperf() - elif action == 'Reboot_UE': - SSH.RebootUE() - elif action == 'Initialize_HSS': - SSH.InitializeHSS() - elif action == 'Terminate_HSS': - SSH.TerminateHSS() - elif action == 'Initialize_MME': - SSH.InitializeMME() - elif action == 'Terminate_MME': - SSH.TerminateMME() - elif action == 'Initialize_SPGW': - SSH.InitializeSPGW() - elif action == 'Terminate_SPGW': - SSH.TerminateSPGW() - elif action == 'Initialize_FlexranCtrl': - SSH.InitializeFlexranCtrl() - elif action == 'Terminate_FlexranCtrl': - SSH.TerminateFlexranCtrl() - elif action == 'IdleSleep': - SSH.IdleSleep() - elif action == 'Perform_X2_Handover': - SSH.Perform_X2_Handover() - else: - sys.exit('Invalid action') - cnt += 1 -# repeatCounts becomes an integer (was SSH.repeatCounts[0] --> becomes SSH.repeatCounts) - if cnt == SSH.repeatCounts and SSH.prematureExit: - logging.debug('Testsuite failed ' + str(cnt) + ' time(s)') - SSH.CreateHtmlTabFooter(False) - sys.exit('Failed Scenario') - else: - logging.info('Testsuite passed after ' + str(cnt) + ' time(s)') - SSH.CreateHtmlTabFooter(True) -else: - Usage() - sys.exit('Invalid mode') -sys.exit(0) diff --git a/ci-scripts/main-index-to-class.py b/ci-scripts/main-index-to-class.py deleted file mode 100644 index 68b9558740..0000000000 --- a/ci-scripts/main-index-to-class.py +++ /dev/null @@ -1,4921 +0,0 @@ -# /* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (the "License"); you may not use this file -# * except in compliance with the License. -# * You may obtain a copy of the License at -# * -# * http://www.openairinterface.org/?page_id=698 -# * -# * Unless required by applicable law or agreed to in writing, software -# * distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# Python for CI of OAI-eNB + COTS-UE -# -# Required Python Version -# Python 3.x -# -# Required Python Package -# pexpect -#--------------------------------------------------------------------- - -#----------------------------------------------------------- -# Version -#----------------------------------------------------------- -Version = '0.1' - -#----------------------------------------------------------- -# Constants -#----------------------------------------------------------- -ALL_PROCESSES_OK = 0 -ENB_PROCESS_FAILED = -1 -ENB_PROCESS_OK = +1 -ENB_PROCESS_SEG_FAULT = -11 -ENB_PROCESS_ASSERTION = -12 -ENB_PROCESS_REALTIME_ISSUE = -13 -ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 -ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 -HSS_PROCESS_FAILED = -2 -HSS_PROCESS_OK = +2 -MME_PROCESS_FAILED = -3 -MME_PROCESS_OK = +3 -SPGW_PROCESS_FAILED = -4 -SPGW_PROCESS_OK = +4 -UE_IP_ADDRESS_ISSUE = -5 -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 -OAI_UE_PROCESS_COULD_NOT_SYNC = -21 -OAI_UE_PROCESS_ASSERTION = -22 -OAI_UE_PROCESS_FAILED = -23 -OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 -OAI_UE_PROCESS_OK = +6 - -UE_STATUS_DETACHED = 0 -UE_STATUS_DETACHING = 1 -UE_STATUS_ATTACHING = 2 -UE_STATUS_ATTACHED = 3 - -X2_HO_REQ_STATE__IDLE = 0 -X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 -X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 -X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 -X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 - -#----------------------------------------------------------- -# Import -#----------------------------------------------------------- -import sys # arg -import re # reg -import pexpect # pexpect -import time # sleep -import os -import subprocess -import xml.etree.ElementTree as ET -import logging -import datetime -import signal -from multiprocessing import Process, Lock, SimpleQueue -logging.basicConfig( - level=logging.DEBUG, - format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" -) - -#----------------------------------------------------------- -# Class Declaration -#----------------------------------------------------------- -class SSHConnection(): - def __init__(self): - self.FailReportCnt = 0 # FailReportCnt was an index inside the SSH instantiation (called "cnt"), now it becomes an object - self.prematureExit = False - self.ranRepository = '' - self.ranBranch = '' - self.ranAllowMerge = False - self.ranCommitID = '' - self.ranTargetBranch = '' - self.eNBIPAddress = '' - self.eNBUserName = '' - self.eNBPassword = '' - self.eNBSourceCodePath = '' - self.EPCIPAddress = '' - self.EPCUserName = '' - self.EPCPassword = '' - self.eNB1IPAddress = '' - self.eNB1UserName = '' - self.eNB1Password = '' - self.eNB1SourceCodePath = '' - self.eNB2IPAddress = '' - self.eNB2UserName = '' - self.eNB2Password = '' - self.eNB2SourceCodePath = '' - self.EPCSourceCodePath = '' - self.EPCType = '' - self.EPC_PcapFileName = '' - self.ADBIPAddress = '' - self.ADBUserName = '' - self.ADBPassword = '' - self.ADBCentralized = True - self.testCase_id = '' - self.testXMLfiles = [] - self.nbTestXMLfiles = 0 - self.desc = '' - self.Build_eNB_args = '' - self.backgroundBuild = False - self.backgroundBuildTestId = ['', '', ''] - self.Initialize_eNB_args = '' - self.eNB_instance = '' - self.eNB_serverId = '' - self.eNBLogFiles = ['', '', ''] - self.eNBOptions = ['', '', ''] - self.ping_args = '' - self.ping_packetloss_threshold = '' - self.iperf_args = '' - self.iperf_packetloss_threshold = '' - self.iperf_profile = '' - self.nbMaxUEtoAttach = -1 - self.UEDevices = [] - self.UEDevicesStatus = [] - self.UEDevicesRemoteServer = [] - self.UEDevicesRemoteUser = [] - self.UEDevicesOffCmd = [] - self.UEDevicesOnCmd = [] - self.UEDevicesRebootCmd = [] - self.CatMDevices = [] - self.UEIPAddresses = [] - self.htmlFile = '' - self.htmlHeaderCreated = False - self.htmlFooterCreated = False - self.htmlUEConnected = -1 - self.htmleNBFailureMsg = '' - self.htmlUEFailureMsg = '' - self.picocom_closure = False - self.idle_sleep_time = 0 - self.x2_ho_options = 'network' - self.x2NbENBs = 0 - self.x2ENBBsIds = [] - self.x2ENBConnectedUEs = [] - self.htmlTabRefs = [] - self.htmlTabNames = [] - self.htmlTabIcons = [] - self.repeatCounts = [] - self.finalStatus = False - self.OsVersion = '' - self.KernelVersion = '' - self.UhdVersion = '' - self.UsrpBoard = '' - self.CpuNb = '' - self.CpuModel = '' - self.CpuMHz = '' - self.UEIPAddress = '' - self.UEUserName = '' - self.UEPassword = '' - self.UE_instance = '' - self.UESourceCodePath = '' - self.UELogFile = '' - self.Build_OAI_UE_args = '' - self.Initialize_OAI_UE_args = '' - self.flexranCtrlInstalled = False - self.flexranCtrlStarted = False - self.expectedNbOfConnectedUEs = 0 - self.startTime = 0 - - def open(self, ipaddress, username, password): - count = 0 - connect_status = False - while count < 4: - self.ssh = pexpect.spawn('ssh', [username + '@' + ipaddress], timeout = 5) - self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - self.ssh.sendline('yes') - self.ssh.expect('password:') - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 1: - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 2: - # Checking if we are really on the remote client defined by its IP address - self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', '\$', 5) - result = re.search(str(ipaddress), str(self.ssh.before)) - if result is None: - self.close() - else: - count = 10 - connect_status = True - else: - # debug output - logging.debug(str(self.ssh.before)) - logging.debug('self.sshresponse = ' + str(self.sshresponse)) - # adding a tempo when failure - if not connect_status: - time.sleep(1) - count += 1 - if connect_status: - pass - else: - sys.exit('SSH Connection Failed') - - def command(self, commandline, expectedline, timeout): - logging.debug(commandline) - self.ssh.timeout = timeout - self.ssh.sendline(commandline) - self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - return 0 - elif self.sshresponse == 1: - logging.debug('\u001B[1;37;41m Unexpected EOF \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) - elif self.sshresponse == 2: - logging.debug('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - result = re.search('ping |iperf |picocom', str(commandline)) - if result is None: - logging.debug(str(self.ssh.before)) - sys.exit(self.sshresponse) - else: - return -1 - else: - logging.debug('\u001B[1;37;41m Unexpected Others \u001B[0m') - logging.debug('Expected Line : ' + expectedline) - sys.exit(self.sshresponse) - - def close(self): - self.ssh.timeout = 5 - self.ssh.sendline('exit') - self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - pass - elif self.sshresponse == 1: - if not self.picocom_closure: - logging.debug('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') - else: - logging.debug('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') - - def copyin(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.debug('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination) - while count < 10: - scp_spawn = pexpect.spawn('scp '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.debug('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.debug('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.debug('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - return 0 - else: - return -1 - - def copyout(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.debug('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination) - while count < 4: - scp_spawn = pexpect.spawn('scp ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.debug('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.debug('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.debug('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - pass - else: - sys.exit('SCP failed') - - def BuildeNB(self): - if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - Usage() - sys.exit('Insufficient Parameter') - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - self.command('mkdir -p ' + lSourcePath, '\$', 5) - self.command('cd ' + lSourcePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) - # Raphael: here add a check if git clone or git fetch went smoothly - self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - self.command('git config user.name "OAI Jenkins"', '\$', 5) - # Checking the BUILD INFO file - if not self.backgroundBuild: - self.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) - if result is not None: - mismatch = False - self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - result = re.search('YES', str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - result = re.search('develop', str(self.ssh.before)) - else: - result = re.search(self.ranTargetBranch, str(self.ssh.before)) - if result is None: - mismatch = True - else: - result = re.search('NO', str(self.ssh.before)) - if result is None: - mismatch = True - if not mismatch: - self.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - return - - self.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) - # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - self.command('git checkout -f ' + self.ranCommitID, '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (self.ranAllowMerge): - if self.ranTargetBranch == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('mkdir -p log', '\$', 5) - self.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - if self.backgroundBuild: - self.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) - self.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id - return - self.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) - - def WaitBuildeNBisFinished(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - count = 40 - buildOAIprocess = True - while (count > 0) and buildOAIprocess: - self.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) - result = re.search('build_oai', str(self.ssh.before)) - if result is None: - buildOAIprocess = False - else: - count -= 1 - time.sleep(30) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) - - def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): - self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - buildStatus = True - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is None: - buildStatus = False - else: - # Generating a BUILD INFO file - self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('mkdir -p build_log_' + testcaseId, '\$', 5) - self.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) - self.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) - if self.eNB_serverId != '0': - self.command('cd cmake_targets', '\$', 5) - self.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) - self.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) - self.close() - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - os.remove('./tmp_build' + testcaseId + '.zip') - self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') - os.remove('./tmp_build' + testcaseId + '.zip') - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) - self.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) - self.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) - self.close() - else: - self.close() - - if buildStatus: - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - else: - logging.error('\u001B[1m Building OAI eNB Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) - self.CreateHtmlTabFooter(False) - sys.exit(1) - - def BuildOAIUE(self): - if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + self.ranRepository + ' .; else stdbuf -o0 git fetch; fi', '\$', 600) - # here add a check if git clone or git fetch went smoothly - self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - self.command('git config user.name "OAI Jenkins"', '\$', 5) - self.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', str(self.ssh.before)) - if result is not None: - mismatch = False - self.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - result = re.search('YES', str(self.ssh.before)) - if result is None: - mismatch = True - self.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - result = re.search('develop', str(self.ssh.before)) - else: - result = re.search(self.ranTargetBranch, str(self.ssh.before)) - if result is None: - mismatch = True - else: - result = re.search('NO', str(self.ssh.before)) - if result is None: - mismatch = True - if not mismatch: - self.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - return - - self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) - # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - self.command('git checkout -f ' + self.ranCommitID, '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (self.ranAllowMerge): - if self.ranTargetBranch == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - self.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - self.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('mkdir -p log', '\$', 5) - self.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) - self.command('ls lte_build_oai/build', '\$', 3) - self.command('ls lte_build_oai/build', '\$', 3) - buildStatus = True - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is None: - buildStatus = False - self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) - self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) - self.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) - if buildStatus: - # Generating a BUILD INFO file - self.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - self.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - self.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - self.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - self.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - self.close() - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') - else: - self.close() - logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') - self.CreateHtmlTabFooter(False) - sys.exit(1) - - def InitializeHSS(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 Cassandra-based HSS') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - logging.debug('\u001B[1m Launching tshark on all interfaces \u001B[0m') - EPC_PcapFileName = 'epc_' + self.testCase_id + '.pcap' - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f ' + EPC_PcapFileName, '\$', 5) - self.command('echo $USER; nohup sudo tshark -f "tcp port not 22 and port not 53" -i any -w ' + self.EPCSourceCodePath + '/scripts/' + EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S mkdir -p logs', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss_' + self.testCase_id + '.log logs/hss*.*', '\$', 5) - self.command('echo "oai_hss -j /usr/local/etc/oai/hss_rel14.json" > ./my-hss.sh', '\$', 5) - self.command('chmod 755 ./my-hss.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=hss_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/hss_' + self.testCase_id + '.log ./my-hss.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC HSS') - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_hss 2>&1 | stdbuf -o0 awk \'{ print strftime("[%Y/%m/%d %H:%M:%S] ",systime()) $0 }\' | stdbuf -o0 tee -a hss_' + self.testCase_id + '.log &', 'Core state: 2 -> 3', 35) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - logging.debug('Using the ltebox simulated HSS') - self.command('if [ -d ' + self.EPCSourceCodePath + '/scripts ]; then echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - self.command('mkdir -p ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('cd /opt/hss_sim0609', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "Starting sudo session" && sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real ', '\$', 5) - else: - logging.error('This option should not occur!') - self.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def InitializeMME(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 MME') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f mme_' + self.testCase_id + '.log', '\$', 5) - self.command('echo "./run_mme --config-file /usr/local/etc/oai/mme.conf --set-virt-if" > ./my-mme.sh', '\$', 5) - self.command('chmod 755 ./my-mme.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=mme_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/mme_' + self.testCase_id + '.log ./my-mme.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('stdbuf -o0 hostname', '\$', 5) - result = re.search('hostname\\\\r\\\\n(?P[a-zA-Z0-9\-\_]+)\\\\r\\\\n', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m Hostname Not Found! \u001B[0m') - sys.exit(1) - host_name = result.group('host_name') - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_mme 2>&1 | stdbuf -o0 tee -a mme_' + self.testCase_id + '.log &', 'MME app initialization complete', 100) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_mme', '\$', 5) - else: - logging.error('This option should not occur!') - self.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def InitializeSPGW(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC Release 14 SPGW-CUPS') - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f spgwc_' + self.testCase_id + '.log spgwu_' + self.testCase_id + '.log', '\$', 5) - self.command('echo "spgwc -c /usr/local/etc/oai/spgw_c.conf" > ./my-spgwc.sh', '\$', 5) - self.command('chmod 755 ./my-spgwc.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=spgwc_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwc_' + self.testCase_id + '.log ./my-spgwc.sh', '\$', 5) - time.sleep(5) - self.command('echo "spgwu -c /usr/local/etc/oai/spgw_u.conf" > ./my-spgwu.sh', '\$', 5) - self.command('chmod 755 ./my-spgwu.sh', '\$', 5) - self.command('sudo daemon --unsafe --name=spgwu_daemon --chdir=' + self.EPCSourceCodePath + '/scripts -o ' + self.EPCSourceCodePath + '/scripts/spgwu_' + self.testCase_id + '.log ./my-spgwu.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./run_spgw 2>&1 | stdbuf -o0 tee -a spgw_' + self.testCase_id + '.log &', 'Initializing SPGW-APP task interface: DONE', 30) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./start_xGw', '\$', 5) - else: - logging.error('This option should not occur!') - self.close() - self.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) - - def CheckFlexranCtrlInstallation(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': - return - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) - result = re.search('/opt/flexran_rtc/build/rt_controller', str(self.ssh.before)) - if result is not None: - self.flexranCtrlInstalled = True - logging.debug('Flexran Controller is installed') - self.close() - - def InitializeFlexranCtrl(self): - if self.flexranCtrlInstalled == False: - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd /opt/flexran_rtc', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f log/*.log', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) - self.command('ps -aux | grep --color=never rt_controller', '\$', 5) - result = re.search('rt_controller -c ', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') - self.flexranCtrlStarted = True - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def InitializeeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = False - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', str(self.ssh.before)) - if result is not None: - eth_interface = result.group('eth_interface') - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - self.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) - self.close() - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath, '\$', 5) - # Initialize_eNB_args usually start with -O and followed by the location in repository - full_config_file = self.Initialize_eNB_args.replace('-O ','') - extra_options = '' - extIdx = full_config_file.find('.conf') - if (extIdx > 0): - extra_options = full_config_file[extIdx + 5:] - # if tracer options is on, compiling and running T Tracer - result = re.search('T_stdout', str(extra_options)) - if result is not None: - logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') - self.command('cd common/utils/T/tracer', '\$', 5) - self.command('make', '\$', 10) - self.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) - self.command('cd ' + lSourcePath, '\$', 5) - full_config_file = full_config_file[:extIdx + 5] - config_path, config_file = os.path.split(full_config_file) - else: - sys.exit('Insufficient Parameter') - ci_full_config_file = config_path + '/ci-' + config_file - rruCheck = False - result = re.search('^rru|^rcc|^du.band', str(config_file)) - if result is not None: - rruCheck = True - # do not reset board twice in IF4.5 case - result = re.search('^rru|^enb|^du.band', str(config_file)) - if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - self.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 15) - # Make a copy and adapt to EPC / eNB IP addresses - self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); - else: - self.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); - # Launch eNB with the modified config file - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' - if extra_options != '': - self.eNBOptions[int(self.eNB_instance)] = extra_options - time.sleep(6) - doLoop = True - loopCounter = 10 - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # In case of T tracer recording, we may need to kill it - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.command('killall --signal SIGKILL record', '\$', 5) - self.close() - doLoop = False - logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) - # In case of T tracer recording, we need to kill tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if self.EPC_PcapFileName != '': - time.sleep(0.5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.close() - time.sleep(1) - if self.EPC_PcapFileName != '': - copyin_res = self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') - if (copyin_res == 0): - self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') - self.prematureExit = True - return - else: - self.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) - if rruCheck: - result = re.search('wait RUs', str(self.ssh.before)) - else: - result = re.search('got sync|Starting F1AP at CU', str(self.ssh.before)) - if result is None: - time.sleep(6) - else: - doLoop = False - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) - logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') - time.sleep(10) - - self.close() - - def InitializeUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if not self.ADBCentralized: - # Reboot UE - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) - # Wait - #time.sleep(60) - # Put in LTE-Mode only - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) - # enable data service - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - # we need to do radio on/off cycle to make sure of above changes - # airplane mode off // radio on - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - #time.sleep(10) - # airplane mode on // radio off - #self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - - # normal procedure without reboot - # enable data service - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - # airplane mode on // radio off - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - self.close() - return - # enable data service - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) - - # The following commands are deprecated since we no longer work on Android 7+ - # self.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) - # self.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) - # a dedicated script has to be installed inside the UE - # airplane mode on means call /data/local/tmp/off - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - #airplane mode off means call /data/local/tmp/on - logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def InitializeUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.InitializeUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def InitializeOAIUE(self): - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - # b2xx_fx3_utils reset procedure - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) - else: - logging.debug('Did not find any B2xx device') - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets/lte_build_oai/build', '\$', 5) - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - # We may have to regenerate the .u* files - if result is None: - self.command('ls /tmp/*.sed', '\$', 5) - result = re.search('adapt_usim_parameters', str(self.ssh.before)) - if result is not None: - self.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - else: - self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - # Launch UE with the modified config file - self.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.UELogFile = 'ue_' + self.testCase_id + '.log' - - # We are now looping several times to hope we really sync w/ an eNB - doOutterLoop = True - outterLoopCounter = 5 - gotSyncStatus = True - fullSyncStatus = True - while (doOutterLoop): - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - time.sleep(6) - self.command('cd ../..', '\$', 5) - doLoop = True - loopCounter = 10 - gotSyncStatus = True - # the 'got sync' message is for the UE threads synchronization - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here should never occur - logging.error('"got sync" message never showed!') - gotSyncStatus = False - doLoop = False - continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('got sync', str(self.ssh.before)) - if result is None: - time.sleep(6) - else: - doLoop = False - logging.debug('Found "got sync" message!') - if gotSyncStatus == False: - # we certainly need to stop the lte-uesoftmodem process if it is still running! - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - time.sleep(3) - # We are now checking if sync w/ eNB DOES NOT OCCUR - # Usually during the cell synchronization stage, the UE returns with No cell synchronization message - doLoop = True - loopCounter = 10 - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here we do have a great chance that the UE did cell-sync w/ eNB - doLoop = False - doOutterLoop = False - fullSyncStatus = True - continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('No cell synchronization found', str(self.ssh.before)) - if result is None: - time.sleep(6) - else: - doLoop = False - fullSyncStatus = False - logging.debug('Found: "No cell synchronization" message! --> try again') - time.sleep(6) - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - outterLoopCounter = outterLoopCounter - 1 - if (outterLoopCounter == 0): - doOutterLoop = False - - if fullSyncStatus and gotSyncStatus: - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - self.command('ifconfig oaitun_ue1', '\$', 4) - # ifconfig output is different between ubuntu 16 and ubuntu 18 - result = re.search('inet addr:1|inet 1', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') - tunnelInterfaceStatus = True - else: - logging.debug(str(self.ssh.before)) - logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') - tunnelInterfaceStatus = False - else: - tunnelInterfaceStatus = True - - self.close() - if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') - logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') - if (self.ADBIPAddress != 'none'): - self.UEDevices = [] - self.UEDevices.append('OAI-UE') - self.UEDevicesStatus = [] - self.UEDevicesStatus.append(UE_STATUS_DETACHED) - else: - self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') - logging.error('\033[91mInitialize OAI UE Failed! \033[0m') - self.AutoTerminateUEandeNB() - - def checkDevTTYisUnlocked(self): - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - count = 0 - while count < 5: - self.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) - result = re.search('picocom', str(self.ssh.before)) - if result is None: - count = 10 - else: - time.sleep(5) - count = count + 1 - self.close() - - def InitializeCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - # Disabling the Radio - self.command('AT+CFUN=0', 'OK', 5) - logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - # Checking if auto-attach is enabled - self.command('AT^AUTOATT?', 'OK', 5) - result = re.search('AUTOATT: (?P[0-9\-]+)', str(self.ssh.before)) - if result is not None: - if result.group('state') is not None: - autoAttachState = int(result.group('state')) - if autoAttachState is not None: - if autoAttachState == 0: - self.command('AT^AUTOATT=1', 'OK', 5) - logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') - else: - logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') - # Force closure of picocom but device might still be locked - self.close() - self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.checkDevTTYisUnlocked() - - def TerminateCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - # Disabling the Radio - self.command('AT+CFUN=0', 'OK', 5) - logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - self.close() - self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.checkDevTTYisUnlocked() - - def AttachCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.picocom_closure = True - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - self.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - self.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - # Enabling the Radio - self.command('AT+CFUN=1', 'SIMSTORE,READY', 5) - logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') - time.sleep(4) - # We should check if we register - count = 0 - attach_cnt = 0 - attach_status = False - while count < 5: - self.command('AT+CEREG?', 'OK', 5) - result = re.search('CEREG: 2,(?P[0-9\-]+),', str(self.ssh.before)) - if result is not None: - mDataConnectionState = int(result.group('state')) - if mDataConnectionState is not None: - if mDataConnectionState == 1: - count = 10 - attach_status = True - result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', str(self.ssh.before)) - if result is not None: - networky = result.group('networky') - networkz = result.group('networkz') - logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m') - else: - logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m') - else: - logging.debug('+CEREG: 2,' + str(mDataConnectionState)) - attach_cnt = attach_cnt + 1 - else: - logging.debug(str(self.ssh.before)) - attach_cnt = attach_cnt + 1 - count = count + 1 - time.sleep(1) - if attach_status: - self.command('AT+CESQ', 'OK', 5) - result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', str(self.ssh.before)) - if result is not None: - nRSRQ = int(result.group('rsrq')) - nRSRP = int(result.group('rsrp')) - if (nRSRQ is not None) and (nRSRP is not None): - logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') - logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') - self.close() - self.picocom_closure = False - html_queue = SimpleQueue() - self.checkDevTTYisUnlocked() - if attach_status: - html_cell = '
CAT-M module Attachment Completed in ' + str(attach_cnt+4) + ' seconds'
-			if (nRSRQ is not None) and (nRSRP is not None):
-				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
-				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm
' - else: - html_cell += '' - html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) - else: - logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') - html_cell = '
CAT-M module Attachment Failed
' - html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) - self.AutoTerminateUEandeNB() - - def PingCatM(self): - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - try: - statusQueue = SimpleQueue() - lock = Lock() - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE): - logging.debug('Using the OAI EPC HSS: not implemented yet') - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - else: - self.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) - result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', str(self.ssh.before)) - if result is not None: - moduleIPAddr = result.group('ipaddr') - else: - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - device_id = 'catm' - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - lock.acquire() - logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - lock.release() - self.close() - html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' - statusQueue.put(html_cell) - if (packetLossOK): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) - else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) - self.AutoTerminateUEandeNB() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AttachUE_common(self, device_id, statusQueue, lock, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) - else: - # airplane mode off // radio on - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(2) - max_count = 45 - count = max_count - while count > 0: - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put('mDataConnectionState Not Found!') - lock.release() - break - mDataConnectionState = int(result.group('state')) - if mDataConnectionState == 2: - logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') - lock.acquire() - statusQueue.put(max_count - count) - statusQueue.put(device_id) - statusQueue.put('Attach Completed') - lock.release() - break - count = count - 1 - if count == 15 or count == 30: - logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - time.sleep(0.5) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(0.5) - logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') - time.sleep(1) - if count == 0: - logging.debug('\u001B[1;37;41m UE (' + device_id + ') Attach Failed \u001B[0m') - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put('Attach Failed') - lock.release() - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AttachUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - status_queue = SimpleQueue() - lock = Lock() - nb_ue_to_connect = 0 - for device_id in self.UEDevices: - if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): - self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING - p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) - p.daemon = True - p.start() - multi_jobs.append(p) - nb_ue_to_connect = nb_ue_to_connect + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - return - else: - attach_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - attach_status = False - device_id = status_queue.get() - message = status_queue.get() - if (count < 0): - html_cell = '
UE (' + device_id + ')\n' + message + '
' - else: - html_cell = '
UE (' + device_id + ')\n' + message + ' in ' + str(count + 2) + ' seconds
' - html_queue.put(html_cell) - if (attach_status): - # cnt from index to object of a class - cnt = 0 - while cnt < len(self.UEDevices): - if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: - self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED - cnt += 1 - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - else: - self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def DetachUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DetachUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - cnt = 0 - for device_id in self.UEDevices: - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING - p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) - p.daemon = True - p.start() - multi_jobs.append(p) - cnt += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED - cnt += 1 - - def RebootUE_common(self, device_id): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - previousmDataConnectionStates = [] - # Save mDataConnectionState - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') - sys.exit(1) - previousmDataConnectionStates.append(int(result.group('state'))) - # Reboot UE - self.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) - time.sleep(60) - previousmDataConnectionState = previousmDataConnectionStates.pop(0) - count = 180 - while count > 0: - count = count - 1 - self.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', str(self.ssh.before)) - if result is None: - mDataConnectionState = None - else: - mDataConnectionState = int(result.group('state')) - logging.debug('mDataConnectionState = ' + result.group('state')) - if mDataConnectionState is None or (previousmDataConnectionState == 2 and mDataConnectionState != 2): - logging.debug('\u001B[1mWait UE (' + device_id + ') a second until reboot completion (' + str(180-count) + ' times)\u001B[0m') - time.sleep(1) - else: - logging.debug('\u001B[1mUE (' + device_id + ') Reboot Completed\u001B[0m') - break - if count == 0: - logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') - sys.exit(1) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def RebootUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - multi_jobs = [] - for device_id in self.UEDevices: - p = Process(target = self.RebootUE_common, args = (device_id,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def DataDisableUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # disable data service - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DataDisableUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.DataDisableUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def DataEnableUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # enable data service - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DataEnableUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.DataEnableUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def GetAllUEDevices(self, terminate_ue_flag): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('adb devices', '\$', 15) - self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",str(self.ssh.before)) - self.close() - else: - if (os.path.isfile('./phones_list.txt')): - os.remove('./phones_list.txt') - self.command('ls /etc/*/phones*.txt', '\$', 5) - result = re.search('/etc/ci/phones_list.txt', str(self.ssh.before)) - self.close() - if (result is not None) and (len(self.UEDevices) == 0): - self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') - if (os.path.isfile('./phones_list.txt')): - phone_list_file = open('./phones_list.txt', 'r') - for line in phone_list_file.readlines(): - line = line.strip() - result = re.search('^#', line) - if result is not None: - continue - comma_split = line.split(",") - self.UEDevices.append(comma_split[0]) - self.UEDevicesRemoteServer.append(comma_split[1]) - self.UEDevicesRemoteUser.append(comma_split[2]) - self.UEDevicesOffCmd.append(comma_split[3]) - self.UEDevicesOnCmd.append(comma_split[4]) - self.UEDevicesRebootCmd.append(comma_split[5]) - phone_list_file.close() - - if terminate_ue_flag == False: - if len(self.UEDevices) == 0: - logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') - sys.exit(1) - if len(self.UEDevicesStatus) == 0: - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus.append(UE_STATUS_DETACHED) - cnt += 1 - - def GetAllCatMDevices(self, terminate_ue_flag): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) - self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",str(self.ssh.before)) - else: - if (os.path.isfile('./modules_list.txt')): - os.remove('./modules_list.txt') - self.command('ls /etc/*/modules*.txt', '\$', 5) - result = re.search('/etc/ci/modules_list.txt', str(self.ssh.before)) - self.close() - if result is not None: - logging.debug('Found a module list file on ADB server') - if terminate_ue_flag == False: - if len(self.CatMDevices) == 0: - logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') - sys.exit(1) - self.close() - - def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) - result = re.search('mServiceState=(?P[0-9]+)', str(self.ssh.before)) - serviceState = 'Service State: UNKNOWN' - if result is not None: - lServiceState = int(result.group('serviceState')) - if lServiceState == 3: - serviceState = 'Service State: RADIO_POWERED_OFF' - if lServiceState == 1: - serviceState = 'Service State: OUT_OF_SERVICE' - if lServiceState == 0: - serviceState = 'Service State: IN_SERVICE' - if lServiceState == 2: - serviceState = 'Service State: EMERGENCY_ONLY' - result = re.search('mDataConnectionState=(?P[0-9]+)', str(self.ssh.before)) - dataConnectionState = 'Data State: UNKNOWN' - if result is not None: - lDataConnectionState = int(result.group('dataConnectionState')) - if lDataConnectionState == 0: - dataConnectionState = 'Data State: DISCONNECTED' - if lDataConnectionState == 1: - dataConnectionState = 'Data State: CONNECTING' - if lDataConnectionState == 2: - dataConnectionState = 'Data State: CONNECTED' - if lDataConnectionState == 3: - dataConnectionState = 'Data State: SUSPENDED' - result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', str(self.ssh.before)) - dataConnectionReason = 'Data Reason: UNKNOWN' - if result is not None: - dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') - lock.acquire() - logging.debug('\u001B[1;37;44m Status Check (' + str(device_id) + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + serviceState + '\u001B[0m') - logging.debug('\u001B[1;34m ' + dataConnectionState + '\u001B[0m') - logging.debug('\u001B[1;34m ' + dataConnectionReason + '\u001B[0m') - statusQueue.put(0) - statusQueue.put(device_id) - qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason - statusQueue.put(qMsg) - lock.release() - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckStatusUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - multi_jobs = [] - lock = Lock() - status_queue = SimpleQueue() - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.CheckUEStatus_common, args = (lock,device_id,status_queue,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd /opt/flexran_rtc', '\$', 5) - self.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) - self.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) - result = re.search('Nb Connected UE = (?P[0-9]+)', str(self.ssh.before)) - passStatus = True - if result is not None: - nb_ues = int(result.group('nb_ues')) - htmlOptions = 'Nb Connected UE(s) to eNB = ' + str(nb_ues) - logging.debug('\u001B[1;37;44m ' + htmlOptions + ' \u001B[0m') - if self.expectedNbOfConnectedUEs > -1: - if nb_ues != self.expectedNbOfConnectedUEs: - passStatus = False - else: - htmlOptions = 'N/A' - self.close() - else: - passStatus = True - htmlOptions = 'N/A' - - if (status_queue.empty()): - self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - check_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - check_status = False - device_id = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\n' + message + '
' - html_queue.put(html_cell) - if check_status and passStatus: - self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def GetAllUEIPAddresses(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - ue_ip_status = 0 - self.UEIPAddresses = [] - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('ifconfig oaitun_ue1', '\$', 4) - result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', str(self.ssh.before)) - if result is not None: - if result.group('ueipaddress') is not None: - UE_IPAddress = result.group('ueipaddress') - else: - UE_IPAddress = result.group('ueipaddress2') - logging.debug('\u001B[1mUE (' + self.UEDevices[0] + ') IP Address is ' + UE_IPAddress + '\u001B[0m') - self.UEIPAddresses.append(UE_IPAddress) - else: - logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') - ue_ip_status -= 1 - self.close() - return ue_ip_status - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - idx = 0 - for device_id in self.UEDevices: - if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: - idx += 1 - continue - count = 0 - while count < 4: - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) - result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') - time.sleep(1) - count += 1 - else: - count = 10 - if count < 9: - ue_ip_status -= 1 - continue - UE_IPAddress = result.group('ueipaddress') - logging.debug('\u001B[1mUE (' + device_id + ') IP Address is ' + UE_IPAddress + '\u001B[0m') - for ueipaddress in self.UEIPAddresses: - if ueipaddress == UE_IPAddress: - logging.debug('\u001B[1mUE (' + device_id + ') IP Address ' + UE_IPAddress + ': has already been allocated to another device !' + '\u001B[0m') - ue_ip_status -= 1 - continue - self.UEIPAddresses.append(UE_IPAddress) - idx += 1 - self.close() - return ue_ip_status - - def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(message) - lock.release() - - def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): - try: - # Launch ping on the EPC side (true for ltebox and old open-air-cn) - # But for OAI-Rel14-CUPS, we launch from python executor - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - launchFromEpc = False - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) - else: - cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - ping_status = ret.returncode - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cat ' + self.EPCSourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - lock.acquire() - logging.debug('\u001B[1;37;44m ping result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - if (packetLossOK): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(qMsg) - lock.release() - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def PingNoS1_wrong_exit(self, qMsg): - html_queue = SimpleQueue() - html_cell = '
OAI UE ping result\n' + qMsg + '
' - html_queue.put(html_cell) - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - - def PingNoS1(self): - check_eNB = True - check_OAI_UE = True - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) - if ping_from_eNB is not None: - if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - else: - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - Usage() - sys.exit('Insufficient Parameter') - try: - if ping_from_eNB is not None: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) - else: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) - self.command('cd cmake_targets', '\$', 5) - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with OAI UE crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before)) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before)) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - logging.debug('\u001B[1;37;44m OAI UE ping result \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - self.close() - html_queue = SimpleQueue() - ip_addr = 'TBD' - html_cell = '
OAI UE ping result\n' + qMsg + '
' - html_queue.put(html_cell) - if packetLossOK: - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - - # copying on the EPC server for logCollection - if ping_from_eNB is not None: - copyin_res = self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') - else: - copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'ping_' + self.testCase_id + '.log', self.EPCSourceCodePath + '/scripts') - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def Ping(self): - result = re.search('noS1', str(self.Initialize_eNB_args)) - if result is not None: - self.PingNoS1() - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - check_OAI_UE = True - else: - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - i = 0 - lock = Lock() - status_queue = SimpleQueue() - for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - ping_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - ping_status = False - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (ping_status): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def Iperf_ComputeTime(self): - result = re.search('-t (?P\d+)', str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Iperf time Not Found! \u001B[0m') - sys.exit(1) - return result.group('iperf_time') - - def Iperf_ComputeModifiedBW(self, idx, ue_num): - result = re.search('-b (?P[0-9\.]+)[KMG]', str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Iperf bandwidth Not Found! \u001B[0m') - sys.exit(1) - iperf_bandwidth = result.group('iperf_bandwidth') - if self.iperf_profile == 'balanced': - iperf_bandwidth_new = float(iperf_bandwidth)/ue_num - if self.iperf_profile == 'single-ue': - iperf_bandwidth_new = float(iperf_bandwidth) - if self.iperf_profile == 'unbalanced': - # residual is 2% of max bw - residualBW = float(iperf_bandwidth) / 50 - if idx == 0: - iperf_bandwidth_new = float(iperf_bandwidth) - ((ue_num - 1) * residualBW) - else: - iperf_bandwidth_new = residualBW - iperf_bandwidth_str = '-b ' + iperf_bandwidth - iperf_bandwidth_str_new = '-b ' + ('%.2f' % iperf_bandwidth_new) - result = re.sub(iperf_bandwidth_str, iperf_bandwidth_str_new, str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Calculate Iperf bandwidth Failed! \u001B[0m') - sys.exit(1) - return result - - def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - self.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', str(self.ssh.before)) - if result is not None: - avgbitrate = result.group('average') - maxbitrate = result.group('maximum') - minbitrate = result.group('minimum') - lock.acquire() - logging.debug('\u001B[1;37;44m TCP iperf result (' + UE_IPAddress + ') \u001B[0m') - msg = 'TCP Stats :\n' - if avgbitrate is not None: - logging.debug('\u001B[1;34m Avg Bitrate : ' + avgbitrate + '\u001B[0m') - msg += 'Avg Bitrate : ' + avgbitrate + '\n' - if maxbitrate is not None: - logging.debug('\u001B[1;34m Max Bitrate : ' + maxbitrate + '\u001B[0m') - msg += 'Max Bitrate : ' + maxbitrate + '\n' - if minbitrate is not None: - logging.debug('\u001B[1;34m Min Bitrate : ' + minbitrate + '\u001B[0m') - msg += 'Min Bitrate : ' + minbitrate + '\n' - statusQueue.put(0) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - return 0 - - def Iperf_analyzeV2Output(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - result = re.search('-u', str(iperf_real_options)) - if result is None: - return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) - - result = re.search('Server Report:', str(self.ssh.before)) - if result is None: - result = re.search('read failed: Connection refused', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') - else: - logging.debug('\u001B[1;37;41m Server Report and Connection refused Not Found! \u001B[0m') - return -1 - # Computing the requested bandwidth in float - result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) - if result is not None: - req_bandwidth = result.group('iperf_bandwidth') - req_bw = float(req_bandwidth) - result = re.search('-b [0-9\.]+K', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Kbits/sec' % req_bw - req_bw = req_bw * 1000 - result = re.search('-b [0-9\.]+M', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Mbits/sec' % req_bw - req_bw = req_bw * 1000000 - result = re.search('-b [0-9\.]+G', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Gbits/sec' % req_bw - req_bw = req_bw * 1000000000 - - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', str(self.ssh.before)) - if result is not None: - bitrate = result.group('bitrate') - packetloss = result.group('packetloss') - jitter = result.group('jitter') - lock.acquire() - logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') - iperfStatus = True - msg = 'Req Bitrate : ' + req_bandwidth + '\n' - logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m') - if bitrate is not None: - msg += 'Bitrate : ' + bitrate + '\n' - logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') - result = re.search('(?P[0-9\.]+) [KMG]bits/sec', str(bitrate)) - if result is not None: - actual_bw = float(str(result.group('real_bw'))) - result = re.search('[0-9\.]+ K', bitrate) - if result is not None: - actual_bw = actual_bw * 1000 - result = re.search('[0-9\.]+ M', bitrate) - if result is not None: - actual_bw = actual_bw * 1000000 - result = re.search('[0-9\.]+ G', bitrate) - if result is not None: - actual_bw = actual_bw * 1000000000 - br_loss = 100 * actual_bw / req_bw - bitperf = '%.2f ' % br_loss - msg += 'Bitrate Perf: ' + bitperf + '%\n' - logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m') - if packetloss is not None: - msg += 'Packet Loss : ' + packetloss + '%\n' - logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') - if float(packetloss) > float(self.iperf_packetloss_threshold): - msg += 'Packet Loss too high!\n' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - iperfStatus = False - if jitter is not None: - msg += 'Jitter : ' + jitter + '\n' - logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m') - if (iperfStatus): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - return 0 - else: - return -2 - - def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') - return - # Computing the requested bandwidth in float - result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) - if result is None: - logging.debug('Iperf bandwidth Not Found!') - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not compute Iperf bandwidth!') - return - else: - req_bandwidth = result.group('iperf_bandwidth') - req_bw = float(req_bandwidth) - result = re.search('-b [0-9\.]+K', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Kbits/sec' % req_bw - req_bw = req_bw * 1000 - result = re.search('-b [0-9\.]+M', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Mbits/sec' % req_bw - req_bw = req_bw * 1000000 - result = re.search('-b [0-9\.]+G', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Gbits/sec' % req_bw - req_bw = req_bw * 1000000000 - - server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') - br_sum = 0.0 - ji_sum = 0.0 - pl_sum = 0 - ps_sum = 0 - row_idx = 0 - for line in server_file.readlines(): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) - if result is not None: - bitrate = result.group('bitrate') - jitter = result.group('jitter') - packetlost = result.group('lostPack') - packetsent = result.group('sentPack') - br = bitrate.split(' ') - ji = jitter.split(' ') - row_idx = row_idx + 1 - curr_br = float(br[0]) - pl_sum = pl_sum + int(packetlost) - ps_sum = ps_sum + int(packetsent) - if (br[1] == 'Kbits/sec'): - curr_br = curr_br * 1000 - if (br[1] == 'Mbits/sec'): - curr_br = curr_br * 1000 * 1000 - br_sum = curr_br + br_sum - ji_sum = float(ji[0]) + ji_sum - if (row_idx > 0): - br_sum = br_sum / row_idx - ji_sum = ji_sum / row_idx - br_loss = 100 * br_sum / req_bw - if (br_sum > 1000): - br_sum = br_sum / 1000 - if (br_sum > 1000): - br_sum = br_sum / 1000 - bitrate = '%.2f Mbits/sec' % br_sum - else: - bitrate = '%.2f Kbits/sec' % br_sum - else: - bitrate = '%.2f bits/sec' % br_sum - bitperf = '%.2f ' % br_loss - bitperf += '%' - jitter = '%.2f ms' % (ji_sum) - if (ps_sum > 0): - pl = float(100 * pl_sum / ps_sum) - packetloss = '%2.1f ' % (pl) - packetloss += '%' - else: - packetloss = 'unknown' - lock.acquire() - if (br_loss < 90): - statusQueue.put(1) - else: - statusQueue.put(0) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - req_msg = 'Req Bitrate : ' + req_bandwidth - bir_msg = 'Bitrate : ' + bitrate - brl_msg = 'Bitrate Perf: ' + bitperf - jit_msg = 'Jitter : ' + jitter - pal_msg = 'Packet Loss : ' + packetloss - statusQueue.put(req_msg + '\n' + bir_msg + '\n' + brl_msg + '\n' + jit_msg + '\n' + pal_msg + '\n') - logging.debug('\u001B[1;37;45m iperf result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;35m ' + req_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + bir_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + brl_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + jit_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + pal_msg + '\u001B[0m') - lock.release() - else: - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') - - server_file.close() - - - def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', str(self.ssh.before)) - if result is None: - result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', str(self.ssh.before)) - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - if result is not None: - logging.debug('\u001B[1;37;41m ' + result.group('error') + ' \u001B[0m') - statusQueue.put(result.group('error')) - else: - logging.debug('\u001B[1;37;41m Bitrate and/or Packet Loss Not Found! \u001B[0m') - statusQueue.put('Bitrate and/or Packet Loss Not Found!') - lock.release() - - bitrate = result.group('bitrate') - packetloss = result.group('packetloss') - lock.acquire() - logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') - msg = 'Bitrate : ' + bitrate + '\n' - iperfStatus = True - if packetloss is not None: - logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') - msg += 'Packet Loss : ' + packetloss + '%\n' - if float(packetloss) > float(self.iperf_packetloss_threshold): - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - msg += 'Packet Loss too high!\n' - iperfStatus = False - if (iperfStatus): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - - def Iperf_UL_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): - udpIperf = True - result = re.search('-u', str(self.iperf_args)) - if result is None: - udpIperf = False - ipnumbers = UE_IPAddress.split('.') - if (len(ipnumbers) == 4): - ipnumbers[3] = '1' - EPC_Iperf_UE_IPAddress = ipnumbers[0] + '.' + ipnumbers[1] + '.' + ipnumbers[2] + '.' + ipnumbers[3] - - # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 - # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - launchFromEpc = False - cmd = 'hostname -I' - ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - if ret.stdout is not None: - EPC_Iperf_UE_IPAddress = ret.stdout.strip() - port = 5001 + idx - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if udpIperf: - self.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) - else: - self.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.EPCUserName, 5) - self.close() - else: - if self.ueIperfVersion == self.dummyIperfVersion: - prefix = '' - else: - prefix = '' - if self.ueIperfVersion == '2.0.5': - prefix = '/opt/iperf-2.0.5/bin/' - if udpIperf: - cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - else: - cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - logging.debug(cmd) - subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - time.sleep(0.5) - - # Launch iperf client on UE - if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - iperf_time = self.Iperf_ComputeTime() - time.sleep(0.5) - - if udpIperf: - modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) - else: - modified_options = str(self.iperf_args) - modified_options = modified_options.replace('-R','') - time.sleep(0.5) - - self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if (device_id == 'OAI-UE'): - iperf_status = self.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - if self.ADBCentralized: - iperf_status = self.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - iperf_status = self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - self.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # TIMEOUT Case - if iperf_status < 0: - self.close() - message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - self.close() - - # Kill iperf server on EPC side - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('killall --signal SIGKILL iperf', self.EPCUserName, 5) - self.close() - else: - cmd = 'killall --signal SIGKILL iperf' - logging.debug(cmd) - subprocess.run(cmd, shell=True) - time.sleep(1) - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - # in case of failure, retrieve server log - if (clientStatus == -1) or (clientStatus == -2): - if launchFromEpc: - time.sleep(1) - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) - # in case of OAI-UE - if (device_id == 'OAI-UE'): - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - - def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): - try: - # Single-UE profile -- iperf only on one UE - if self.iperf_profile == 'single-ue' and idx != 0: - return - useIperf3 = False - udpIperf = True - - self.ueIperfVersion = '2.0.5' - if (device_id != 'OAI-UE'): - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - self.command('if [ ! -d ' + self.EPCSourceCodePath + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - # Checking if iperf / iperf3 are installed - if self.ADBCentralized: - self.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) - result = re.search('iperf3', str(self.ssh.before)) - if result is None: - result = re.search('iperf', str(self.ssh.before)) - if result is None: - message = 'Neither iperf nor iperf3 installed on UE!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - else: - if self.ADBCentralized: - self.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) - result = re.search('iperf version 2.0.5', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.10' - else: - useIperf3 = True - self.close() - else: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('iperf --version', '\$', 5) - result = re.search('iperf version 2.0.5', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', str(self.ssh.before)) - if result is not None: - self.ueIperfVersion = '2.0.10' - self.close() - # in case of iperf, UL has its own function - if (not useIperf3): - result = re.search('-R', str(self.iperf_args)) - if result is not None: - self.Iperf_UL_common(lock, UE_IPAddress, device_id, idx, ue_num, statusQueue) - return - - # Launch the IPERF server on the UE side for DL - if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('-u', str(self.iperf_args)) - if result is None: - self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) - udpIperf = False - else: - self.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) - else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - if self.ADBCentralized: - if (useIperf3): - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) - else: - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('-u', str(self.iperf_args)) - if result is None: - self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) - udpIperf = False - else: - self.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) - else: - self.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) - - time.sleep(0.5) - self.close() - - # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn - # But for OAI-Rel14-CUPS, we launch from python executor - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - launchFromEpc = False - if launchFromEpc: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - iperf_time = self.Iperf_ComputeTime() - time.sleep(0.5) - - if udpIperf: - modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) - else: - modified_options = str(self.iperf_args) - time.sleep(0.5) - - if launchFromEpc: - self.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - else: - if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') - if (useIperf3): - self.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - - clientStatus = 0 - self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) - else: - if launchFromEpc: - iperf_status = self.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - if self.ueIperfVersion == self.dummyIperfVersion: - prefix = '' - else: - prefix = '' - if self.ueIperfVersion == '2.0.5': - prefix = '/opt/iperf-2.0.5/bin/' - cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - iperf_status = ret.returncode - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cat ' + self.EPCSourceCodePath + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if iperf_status < 0: - if launchFromEpc: - self.close() - message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - self.close() - - # Kill the IPERF server that runs in background - if (device_id == 'OAI-UE'): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('killall iperf', '\$', 5) - else: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) - result = re.search('shell +(?P\d+)', str(self.ssh.before)) - if result is not None: - pid_iperf = result.group('pid') - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - self.close() - # if the client report is absent, try to analyze the server log file - if (clientStatus == -1): - time.sleep(1) - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - if (device_id == 'OAI-UE'): - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - else: - self.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, self.EPCSourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) - - # in case of OAI UE: - if (device_id == 'OAI-UE'): - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - if not launchFromEpc: - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - else: - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', self.EPCSourceCodePath + '/scripts') - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def IperfNoS1(self): - if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = True - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - server_on_enb = re.search('-R', str(self.iperf_args)) - if server_on_enb is not None: - iServerIPAddr = self.eNBIPAddress - iServerUser = self.eNBUserName - iServerPasswd = self.eNBPassword - iClientIPAddr = self.UEIPAddress - iClientUser = self.UEUserName - iClientPasswd = self.UEPassword - else: - iServerIPAddr = self.UEIPAddress - iServerUser = self.UEUserName - iServerPasswd = self.UEPassword - iClientIPAddr = self.eNBIPAddress - iClientUser = self.eNBUserName - iClientPasswd = self.eNBPassword - # Starting the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - # args SHALL be "-c client -u any" - # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 - # -B 10.0.1.1 -u -s -i 1 -fm - server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) - server_options = server_options.replace('-c','-B') - self.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) - self.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) - time.sleep(0.5) - self.close() - - # Starting the iperf client - modified_options = self.Iperf_ComputeModifiedBW(0, 1) - modified_options = modified_options.replace('-R','') - iperf_time = self.Iperf_ComputeTime() - self.open(iClientIPAddr, iClientUser, iClientPasswd) - self.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) - iperf_status = self.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) - status_queue = SimpleQueue() - lock = Lock() - if iperf_status < 0: - message = 'iperf on OAI UE crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - clientStatus = -2 - else: - clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - self.close() - - # Stopping the iperf server - self.open(iServerIPAddr, iServerUser, iServerPasswd) - self.command('killall --signal SIGKILL iperf', '\$', 5) - time.sleep(0.5) - self.close() - if (clientStatus == -1): - if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '.log') - self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - - # copying on the EPC server for logCollection - copyin_res = self.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_server_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') - copyin_res = self.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - self.copyout(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, 'iperf_' + self.testCase_id + '_OAI-UE.log', self.EPCSourceCodePath + '/scripts') - iperf_noperf = False - if status_queue.empty(): - iperf_status = False - else: - iperf_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - iperf_status = False - if (count > 0): - iperf_noperf = True - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) - elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def Iperf(self): - result = re.search('noS1', str(self.Initialize_eNB_args)) - if result is not None: - self.IperfNoS1() - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - check_eNB = True - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - check_OAI_UE = True - else: - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB() - return - - self.dummyIperfVersion = '2.0.10' - #cmd = 'iperf --version' - #logging.debug(cmd + '\n') - #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) - #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) - #if result is not None: - # dummyIperfVersion = '2.0.5' - #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) - #if result is not None: - # dummyIperfVersion = '2.0.10' - - multi_jobs = [] - i = 0 - ue_num = len(self.UEIPAddresses) - lock = Lock() - status_queue = SimpleQueue() - for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = SSH.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - iperf_status = True - iperf_noperf = False - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - iperf_status = False - if (count > 0): - iperf_noperf = True - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) - elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def CheckProcessExist(self, check_eNB, check_OAI_UE): - multi_jobs = [] - status_queue = SimpleQueue() - # in noS1 config, no need to check status from EPC - result = re.search('noS1', str(self.Initialize_eNB_args)) - if result is None: - p = Process(target = SSH.CheckHSSProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - p = Process(target = SSH.CheckMMEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - p = Process(target = SSH.CheckSPGWProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - else: - if (check_eNB == False) and (check_OAI_UE == False): - return 0 - if check_eNB: - p = Process(target = SSH.CheckeNBProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - if check_OAI_UE: - p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - return -15 - else: - result = 0 - while (not status_queue.empty()): - status = status_queue.get() - if (status < 0): - result = status - if result == ENB_PROCESS_FAILED: - fileCheck = re.search('enb_', str(self.eNBLogFiles[0])) - if fileCheck is not None: - self.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') - logStatus = self.AnalyzeLogFile_eNB(self.eNBLogFiles[0]) - if logStatus < 0: - result = logStatus - self.eNBLogFiles[0] = '' - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.TerminateFlexranCtrl() - return result - - def CheckOAIUEProcessExist(self, initialize_OAI_UE_flag): - multi_jobs = [] - status_queue = SimpleQueue() - if initialize_OAI_UE_flag == False: - p = Process(target = SSH.CheckOAIUEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - return -15 - else: - result = 0 - while (not status_queue.empty()): - status = status_queue.get() - if (status < 0): - result = status - if result == OAI_UE_PROCESS_FAILED: - fileCheck = re.search('ue_', str(self.UELogFile)) - if fileCheck is not None: - self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') - logStatus = self.AnalyzeLogFile_UE(self.UELogFile) - if logStatus < 0: - result = logStatus - return result - - def CheckOAIUEProcess(self, status_queue): - try: - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') - status_queue.put(OAI_UE_PROCESS_FAILED) - else: - status_queue.put(OAI_UE_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckeNBProcess(self, status_queue): - try: - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is None: - logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') - status_queue.put(ENB_PROCESS_FAILED) - else: - status_queue.put(ENB_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckHSSProcess(self, status_queue): - try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('oai_hss -j', str(self.ssh.before)) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('hss_sim s6as diam_hss', str(self.ssh.before)) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m HSS Process Not Found! \u001B[0m') - status_queue.put(HSS_PROCESS_FAILED) - else: - status_queue.put(HSS_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckMMEProcess(self, status_queue): - try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - result = re.search('mme -c', str(self.ssh.before)) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - result = re.search('mme', str(self.ssh.before)) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m MME Process Not Found! \u001B[0m') - status_queue.put(MME_PROCESS_FAILED) - else: - status_queue.put(MME_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckSPGWProcess(self, status_queue): - try: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('spgwu -c ', str(self.ssh.before)) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('stdbuf -o0 ps -aux | grep --color=never xGw | grep -v grep', '\$', 5) - result = re.search('xGw', str(self.ssh.before)) - else: - logging.error('This should not happen!') - if result is None: - logging.debug('\u001B[1;37;41m SPGW Process Not Found! \u001B[0m') - status_queue.put(SPGW_PROCESS_FAILED) - else: - status_queue.put(SPGW_PROCESS_OK) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AnalyzeLogFile_eNB(self, eNBlogFile): - if (not os.path.isfile('./' + eNBlogFile)): - return -1 - enb_log_file = open('./' + eNBlogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - rrcSetupComplete = 0 - rrcReleaseRequest = 0 - rrcReconfigRequest = 0 - rrcReconfigComplete = 0 - rrcReestablishRequest = 0 - rrcReestablishComplete = 0 - rrcReestablishReject = 0 - rlcDiscardBuffer = 0 - rachCanceledProcedure = 0 - uciStatMsgCount = 0 - pdcpFailure = 0 - ulschFailure = 0 - cdrxActivationMessageCount = 0 - dropNotEnoughRBs = 0 - self.htmleNBFailureMsg = '' - isRRU = False - isSlave = False - slaveReceivesFrameResyncCmd = False - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures = 0 - X2HO_outNbProcedures = 0 - for line in enb_log_file.readlines(): - if X2HO_state == X2_HO_REQ_STATE__IDLE: - result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ - result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK - if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: - result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE - if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: - result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ - if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: - result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures += 1 - if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: - result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_outNbProcedures += 1 - - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) - res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) - if res1 is not None and res2 is not None: - requested_option = int(res1.group('requested_option')) - applied_option = int(res2.group('applied_option')) - if requested_option == applied_option: - self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' - else: - self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('[Ss]egmentation [Ff]ault', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./lte_build_oai/build/lte-softmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('Setting function for RU', str(line)) - if result is not None: - isRRU = True - if isRRU: - result = re.search('RU 0 is_slave=yes', str(line)) - if result is not None: - isSlave = True - if isSlave: - result = re.search('Received RRU_frame_resynch command', str(line)) - if result is not None: - slaveReceivesFrameResyncCmd = True - result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) - if result is not None: - rrcSetupComplete += 1 - result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) - if result is not None: - rrcReleaseRequest += 1 - result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) - if result is not None: - rrcReconfigRequest += 1 - result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) - if result is not None: - rrcReconfigComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) - if result is not None: - rrcReestablishRequest += 1 - result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) - if result is not None: - rrcReestablishComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) - if result is not None: - rrcReestablishReject += 1 - result = re.search('CDRX configuration activated after RRC Connection', str(line)) - if result is not None: - cdrxActivationMessageCount += 1 - result = re.search('uci->stat', str(line)) - if result is not None: - uciStatMsgCount += 1 - result = re.search('PDCP.*Out of Resources.*reason', str(line)) - if result is not None: - pdcpFailure += 1 - result = re.search('ULSCH in error in round', str(line)) - if result is not None: - ulschFailure += 1 - result = re.search('BAD all_segments_received', str(line)) - if result is not None: - rlcDiscardBuffer += 1 - result = re.search('Canceled RA procedure for UE rnti', str(line)) - if result is not None: - rachCanceledProcedure += 1 - result = re.search('dropping, not enough RBs', str(line)) - if result is not None: - dropNotEnoughRBs += 1 - enb_log_file.close() - logging.debug(' File analysis completed') - if uciStatMsgCount > 0: - statMsg = 'eNB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if pdcpFailure > 0: - statMsg = 'eNB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if ulschFailure > 0: - statMsg = 'eNB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if dropNotEnoughRBs > 0: - statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if rrcSetupComplete > 0: - rrcMsg = 'eNB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReleaseRequest > 0: - rrcMsg = 'eNB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: - rrcMsg = 'eNB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: - rrcMsg = 'eNB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_inNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_outNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) - if res1 is not None: - if cdrxActivationMessageCount > 0: - rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - else: - rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' - logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rachCanceledProcedure > 0: - rachMsg = 'eNB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' - logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rachMsg + '\n' - if isRRU: - if isSlave: - if slaveReceivesFrameResyncCmd: - rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - else: - rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - self.prematureExit = True - return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED - if foundSegFault: - logging.debug('\u001B[1;37;41m eNB ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;37;41m eNB ended with an assertion! \u001B[0m') - self.htmleNBFailureMsg += msgAssertion - return ENB_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m eNB faced real time issues! \u001B[0m') - self.htmleNBFailureMsg += 'eNB faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE - if rlcDiscardBuffer > 0: - rlcMsg = 'eNB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' - logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rlcMsg + '\n' - return ENB_PROCESS_REALTIME_ISSUE - return 0 - - def AnalyzeLogFile_UE(self, UElogFile): - if (not os.path.isfile('./' + UElogFile)): - return -1 - ue_log_file = open('./' + UElogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - uciStatMsgCount = 0 - pdcpDataReqFailedCount = 0 - badDciCount = 0 - rrcConnectionRecfgComplete = 0 - no_cell_sync_found = False - mib_found = False - frequency_found = False - plmn_found = False - self.htmlUEFailureMsg = '' - for line in ue_log_file.readlines(): - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./lte-uesoftmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('uci->stat', str(line)) - if result is not None and not exitSignalReceived: - uciStatMsgCount += 1 - result = re.search('PDCP data request failed', str(line)) - if result is not None and not exitSignalReceived: - pdcpDataReqFailedCount += 1 - result = re.search('bad DCI 1A', str(line)) - if result is not None and not exitSignalReceived: - badDciCount += 1 - result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) - if result is not None: - rrcConnectionRecfgComplete += 1 - # No cell synchronization found, abandoning - result = re.search('No cell synchronization found, abandoning', str(line)) - if result is not None: - no_cell_sync_found = True - result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) - if result is not None and (not mib_found): - try: - mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " nidcell = " + result.group('nidcell') - self.htmlUEFailureMsg += mibMsg - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " n_rb_dl = " + result.group('n_rb_dl') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " phich_duration = " + result.group('phich_duration') - self.htmlUEFailureMsg += mibMsg - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " phich_resource = " + result.group('phich_resource') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " tx_ant = " + result.group('tx_ant') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mib_found = True - except Exception as e: - logging.error('\033[91m' + "MIB marker was not found" + '\033[0m') - result = re.search("Measured Carrier Frequency (?P\d{1,15}) Hz", str(line)) - if result is not None and (not frequency_found): - try: - mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - frequency_found = True - except Exception as e: - logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') - result = re.search("PLMN MCC (?P\d{1,3}), MNC (?P\d{1,3}), TAC", str(line)) - if result is not None and (not plmn_found): - try: - mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - plmn_found = True - except Exception as e: - logging.error('\033[91m' + "PLMN not found" + '\033[0m') - result = re.search("Found (?P[\w,\s]{1,15}) \(name from internal table\)", str(line)) - if result is not None: - try: - mibMsg = "The operator is: " + result.group('operator') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - except Exception as e: - logging.error('\033[91m' + "Operator name not found" + '\033[0m') - result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line)) - if result is not None: - try: - mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) - self.htmlUEFailureMsg += mibMsg + ' -> ' - logging.debug('\033[94m' + mibMsg + '\033[0m') - except Exception as e: - logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') - result = re.search("DL Carrier Frequency/ARFCN : (?P\d{1,15}/\d{1,4})", str(line)) - if result is not None: - try: - freq = result.group('carrier_frequency') - new_freq = re.sub('/[0-9]+','',freq) - float_freq = float(new_freq) / 1000000 - self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' - logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') - except Exception as e: - logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') - result = re.search("AllowedMeasBandwidth : (?P\d{1,7})", str(line)) - if result is not None: - try: - prb = result.group('allowed_bandwidth') - self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' - logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') - except Exception as e: - logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') - ue_log_file.close() - if rrcConnectionRecfgComplete > 0: - statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' - logging.debug('\033[94m' + statMsg + '\033[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if uciStatMsgCount > 0: - statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if pdcpDataReqFailedCount > 0: - statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if badDciCount > 0: - statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1A" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if foundSegFault: - logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') - self.htmlUEFailureMsg += 'UE showed an assertion!\n' - if not mib_found or not frequency_found: - return OAI_UE_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') - self.htmlUEFailureMsg += 'UE faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE - if no_cell_sync_found and not mib_found: - logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') - self.htmlUEFailureMsg += 'UE could not synchronize!\n' - return OAI_UE_PROCESS_COULD_NOT_SYNC - return 0 - - def TerminateeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) - self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) - time.sleep(10) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL lte-softmodem || true', '\$', 5) - time.sleep(5) - self.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.close() - # If tracer options is on, stopping tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - time.sleep(1) - if self.EPC_PcapFileName != '': - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + self.EPC_PcapFileName, '\$', 5) - self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + self.EPC_PcapFileName, '.') - self.copyout(lIpAddr, lUserName, lPassWord, self.EPC_PcapFileName, lSourcePath + '/cmake_targets/.') - self.close() - logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') - self.open(lIpAddr, lUserName, lPassWord) - self.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) - enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] - raw_record_file = enbLogFile.replace('.log', '_record.raw') - replay_log_file = enbLogFile.replace('.log', '_replay.log') - extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') - extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') - self.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) - self.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) - self.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) - self.close() - self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') - logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.eNBLogFiles[int(self.eNB_instance)] = '' - else: - analyzeFile = False - if self.eNBLogFiles[int(self.eNB_instance)] != '': - analyzeFile = True - fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] - self.eNBLogFiles[int(self.eNB_instance)] = '' - if analyzeFile: - copyin_res = self.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy eNB logfile to analyze it! \u001B[0m') - self.htmleNBFailureMsg = 'Could not copy eNB logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) - return - if self.eNB_serverId != '0': - self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') - logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m ' + fileToAnalyze) - logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) - if (logStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', logStatus) - self.preamtureExit = True - return - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateHSS(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT oai_hss || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('oai_hss -j', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL oai_hss || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-hss.sh', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_hss oai_hss || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep hss | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_hss oai_hss || true', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) - time.sleep(1) - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) - else: - logging.error('This should not happen!') - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateMME(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_mme mme || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep mme | grep -v grep', '\$', 5) - result = re.search('mme -c', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_mme mme || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-mme.sh', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_mme', '\$', 5) - else: - logging.error('This should not happen!') - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateSPGW(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT spgwc spgwu || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('spgwc -c |spgwu -c ', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL spgwc spgwu || true', '\$', 5) - self.command('rm -f ' + self.EPCSourceCodePath + '/scripts/my-spgw*.sh', '\$', 5) - self.command('stdbuf -o0 ps -aux | grep tshark | grep -v grep', '\$', 5) - result = re.search('-w ', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT tshark || true', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 ' + self.EPCSourceCodePath + '/scripts/*.pcap', '\$', 5) - elif re.match('OAI', self.EPCType, re.IGNORECASE): - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGINT run_spgw spgw || true', '\$', 5) - time.sleep(2) - self.command('stdbuf -o0 ps -aux | grep spgw | grep -v grep', '\$', 5) - result = re.search('\/bin\/bash .\/run_', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL run_spgw spgw || true', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cd /opt/ltebox/tools', '\$', 5) - self.command('echo ' + self.EPCPassword + ' | sudo -S ./stop_xGw', '\$', 5) - else: - logging.error('This should not happen!') - self.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateFlexranCtrl(self): - if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: - return - if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '': - Usage() - sys.exit('Insufficient Parameter') - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) - time.sleep(1) - self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) - time.sleep(1) - self.close() - self.flexranCtrlStarted = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateUE_common(self, device_id, idx): - try: - self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # back in airplane mode on (ie radio off) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) - result = re.search('shell +(?P\d+)', str(self.ssh.before)) - if result is not None: - pid_iperf = result.group('pid') - if self.ADBCentralized: - self.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) - else: - self.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - self.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def TerminateUE(self): - terminate_ue_flag = True - self.GetAllUEDevices(terminate_ue_flag) - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target= SSH.TerminateUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def TerminateOAIUE(self): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT lte-uesoftmodem || true', '\$', 5) - time.sleep(10) - self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) - time.sleep(5) - self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - self.close() - result = re.search('ue_', str(self.UELogFile)) - if result is not None: - copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') - self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') - self.UELogFile = '' - return - logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_UE(self.UELogFile) - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is not None: - ueAction = 'Sniffing' - else: - ueAction = 'Connection' - if (logStatus < 0): - logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') - # In case of sniffing on commercial eNBs we have random results - # Not an error then - if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): - self.Initialize_OAI_UE_args = '' - self.AutoTerminateUEandeNB() - else: - logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.UELogFile = '' - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def AutoTerminateUEandeNB(self): - if (self.ADBIPAddress != 'none'): - self.testCase_id = 'AUTO-KILL-UE' - self.desc = 'Automatic Termination of UE' - self.ShowTestID() - self.TerminateUE() - if (self.Initialize_OAI_UE_args != ''): - self.testCase_id = 'AUTO-KILL-UE' - self.desc = 'Automatic Termination of UE' - self.ShowTestID() - self.TerminateOAIUE() - if (self.Initialize_eNB_args != ''): - self.testCase_id = 'AUTO-KILL-eNB' - self.desc = 'Automatic Termination of eNB' - self.ShowTestID() - self.eNB_instance = '0' - self.TerminateeNB() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.testCase_id = 'AUTO-KILL-flexran-ctl' - self.desc = 'Automatic Termination of FlexRan CTL' - self.ShowTestID() - self.TerminateFlexranCtrl() - self.prematureExit = True - - def IdleSleep(self): - time.sleep(self.idle_sleep_time) - self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) - - def X2_Status(self, idx, fileName): - cmd = "curl --silent http://" + self.EPCIPAddress + ":9999/stats | jq '.' > " + fileName - message = cmd + '\n' - logging.debug(cmd) - subprocess.run(cmd, shell=True) - if idx == 0: - cmd = "jq '.mac_stats | length' " + fileName - strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2NbENBs = int(strNbEnbs.strip()) - cnt = 0 - while cnt < self.x2NbENBs: - cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName - bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBBsIds[idx].append(bs_id.strip()) - cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName - stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) - nbUEs = int(stNbUEs.strip()) - ueIdx = 0 - self.x2ENBConnectedUEs[idx].append([]) - while ueIdx < nbUEs: - cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName - rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip()) - ueIdx += 1 - cnt += 1 - - msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" - logging.debug(msg) - message += msg + '\n' - cnt = 0 - while cnt < self.x2NbENBs: - msg = " -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][self.cnt])) + " UE(s)" - logging.debug(msg) - message += msg + '\n' - ueIdx = 0 - while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]): - msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx]) - logging.debug(msg) - message += msg + '\n' - ueIdx += 1 - cnt += 1 - return message - - def Perform_X2_Handover(self): - html_queue = SimpleQueue() - fullMessage = '
'
-		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
-		logging.debug(msg)
-		fullMessage += msg + '\n'
-		if self.x2_ho_options == 'network':
-			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
-				self.x2ENBBsIds = []
-				self.x2ENBConnectedUEs = []
-				self.x2ENBBsIds.append([])
-				self.x2ENBBsIds.append([])
-				self.x2ENBConnectedUEs.append([])
-				self.x2ENBConnectedUEs.append([])
-				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
-
-				msg = "Activating the X2 Net control on each eNB"
-				logging.debug(msg)
-				fullMessage += msg + '\n'
-				eNB_cnt = self.x2NbENBs
-				cnt = 0
-				while cnt < eNB_cnt:
-					cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1"
-					logging.debug(cmd)
-					fullMessage += cmd + '\n'
-					subprocess.run(cmd, shell=True)
-					cnt += 1
-				# Waiting for the activation to be active
-				time.sleep(10)
-				msg = "Switching UE(s) from eNB to eNB"
-				logging.debug(msg)
-				fullMessage += msg + '\n'
-				cnt = 0
-				while cnt < eNB_cnt:
-					ueIdx = 0
-					while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]):
-						cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
-						logging.debug(cmd)
-						fullMessage += cmd + '\n'
-						subprocess.run(cmd, shell=True)
-						ueIdx += 1
-					cnt += 1
-				time.sleep(10)
-				# check
-				logging.debug("Checking the Status after X2 Handover")
-				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
-				cnt = 0
-				x2Status = True
-				while cnt < eNB_cnt:
-					if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
-						x2Status = False
-					cnt += 1
-				if x2Status:
-					msg = "X2 Handover was successful"
-					logging.debug(msg)
-					fullMessage += msg + '
' - html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - else: - msg = "X2 Handover FAILED" - logging.error(msg) - fullMessage += msg + '' - html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - else: - self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) - - def LogCollectBuild(self): - if (self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != ''): - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword - SourceCodePath = self.eNBSourceCodePath - elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - SourceCodePath = self.UESourceCodePath - else: - sys.exit('Insufficient Parameter') - self.open(IPAddress, UserName, Password) - self.command('cd ' + SourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('rm -f build.log.zip', '\$', 5) - self.command('zip build.log.zip build_log_*/*', '\$', 60) - self.close() - - def LogCollecteNB(self): - self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('cd ' + self.eNBSourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) - self.close() - - def LogCollectPing(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('rm -f ping.log.zip', '\$', 5) - self.command('zip ping.log.zip ping*.log', '\$', 60) - self.command('rm ping*.log', '\$', 5) - self.close() - - def LogCollectIperf(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath, '\$', 5) - self.command('cd scripts', '\$', 5) - self.command('rm -f iperf.log.zip', '\$', 5) - self.command('zip iperf.log.zip iperf*.log', '\$', 60) - self.command('rm iperf*.log', '\$', 5) - self.close() - - def LogCollectHSS(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f hss.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip hss.log.zip hss*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm hss*.log', '\$', 5) - if re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip hss.log.zip logs/hss*.* *.pcap', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm -f logs/hss*.* *.pcap', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/hss_sim0609/hss.log .', '\$', 60) - self.command('zip hss.log.zip hss.log', '\$', 60) - else: - logging.error('This option should not occur!') - self.close() - - def LogCollectMME(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f mme.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip mme.log.zip mme*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm mme*.log', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/ltebox/var/log/*Log.0 .', '\$', 5) - self.command('zip mme.log.zip mmeLog.0 s1apcLog.0 s1apsLog.0 s11cLog.0 libLog.0 s1apCodecLog.0', '\$', 60) - else: - logging.error('This option should not occur!') - self.close() - - def LogCollectSPGW(self): - self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) - self.command('cd ' + self.EPCSourceCodePath + '/scripts', '\$', 5) - self.command('rm -f spgw.log.zip', '\$', 5) - if re.match('OAI', self.EPCType, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.EPCType, re.IGNORECASE): - self.command('zip spgw.log.zip spgw*.log', '\$', 60) - self.command('echo ' + self.EPCPassword + ' | sudo -S rm spgw*.log', '\$', 5) - elif re.match('ltebox', self.EPCType, re.IGNORECASE): - self.command('cp /opt/ltebox/var/log/xGwLog.0 .', '\$', 5) - self.command('zip spgw.log.zip xGwLog.0', '\$', 60) - else: - logging.error('This option should not occur!') - self.close() - - def LogCollectOAIUE(self): - self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('cd ' + self.UESourceCodePath, '\$', 5) - self.command('cd cmake_targets', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) - self.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) - self.close() - - def RetrieveSystemVersion(self, machine): - if self.eNBIPAddress == 'none' or self.UEIPAddress == 'none': - self.OsVersion = 'Ubuntu 16.04.5 LTS' - self.KernelVersion = '4.15.0-45-generic' - self.UhdVersion = '3.13.0.1-0' - self.UsrpBoard = 'B210' - self.CpuNb = '4' - self.CpuModel = 'Intel(R) Core(TM) i5-6200U' - self.CpuMHz = '2399.996 MHz' - return 0 - if machine == 'eNB': - if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword - else: - return -1 - if machine == 'UE': - if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - else: - return -1 - - self.open(IPAddress, UserName, Password) - self.command('lsb_release -a', '\$', 5) - result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) - if result is not None: - self.OsVersion = result.group('os_type') - logging.debug('OS is: ' + self.OsVersion) - self.command('uname -r', '\$', 5) - result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', str(self.ssh.before)) - if result is not None: - self.KernelVersion = result.group('kernel_version') - logging.debug('Kernel Version is: ' + self.KernelVersion) - self.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) - result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', str(self.ssh.before)) - if result is not None: - self.UhdVersion = result.group('uhd_version') - logging.debug('UHD Version is: ' + self.UhdVersion) - self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) - result = re.search('product: (?P[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) - if result is not None: - self.UsrpBoard = result.group('usrp_board') - logging.debug('USRP Board is: ' + self.UsrpBoard) - self.command('lscpu', '\$', 5) - result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', str(self.ssh.before)) - if result is not None: - self.CpuNb = result.group('nb_cpus') - logging.debug('nb_cpus: ' + self.CpuNb) - self.CpuModel = result.group('model') - logging.debug('model: ' + self.CpuModel) - self.CpuMHz = result.group('cpu_mhz') + ' MHz' - logging.debug('cpu_mhz: ' + self.CpuMHz) - self.close() - -#----------------------------------------------------------- -# HTML Reporting.... -#----------------------------------------------------------- - def CreateHtmlHeader(self): - if (not self.htmlHeaderCreated): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML header \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - self.htmlFile = open('test_results.html', 'w') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') - self.htmlFile.write('\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if self.ranAllowMerge != '': - commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + self.ranCommitID, shell=True, universal_newlines=True) - commit_message = commit_message.strip() - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranTargetBranch == ''): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + self.ranRepository + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + self.ranBranch + '
Source Commit ID Commit ID ' + self.ranCommitID + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + self.ranTargetBranch + '
\n') - - if (self.ADBIPAddress != 'none'): - terminate_ue_flag = True - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') - self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.close() - - def CreateHtmlTabHeader(self): - if (not self.htmlHeaderCreated): - if (not os.path.isfile('test_results.html')): - self.CreateHtmlHeader() - self.htmlFile = open('test_results.html', 'a') - if (self.nbTestXMLfiles == 1): - self.htmlFile.write('
\n') - self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') - else: - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.htmlUEConnected == -1): - terminate_ue_flag = True - if (self.ADBIPAddress != 'none'): - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' \n') - i += 1 - self.htmlFile.write(' \n') - self.htmlHeaderCreated = True - - def CreateHtmlTabFooter(self, passStatus): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') - self.htmlFile.write('
\n') - self.htmlFile.close() - time.sleep(1) - if passStatus: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" - subprocess.run(cmd, shell=True) - else: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" - subprocess.run(cmd, shell=True) - self.htmlFooterCreated = False - - def CreateHtmlFooter(self, passStatus): - if (os.path.isfile('test_results.html')): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML footer \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - - self.htmlFile = open('test_results.html', 'a') - self.htmlFile.write('
\n') - self.htmlFile.write('

\n') - self.htmlFile.write(' \n') - - machines = [ 'eNB', 'UE' ] - for machine in machines: - res = self.RetrieveSystemVersion(machine) - if res == -1: - continue - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') - self.htmlFile.write('

\n') - self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('\n') - self.htmlFile.close() - - def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - if (processesStatus == 0): - self.htmlFile.write(' ' + str(status) + '\n') - elif (processesStatus == ENB_PROCESS_FAILED): - self.htmlFile.write(' KO - eNB process not found\n') - elif (processesStatus == OAI_UE_PROCESS_FAILED): - self.htmlFile.write(' KO - OAI UE process not found\n') - elif (processesStatus == ENB_PROCESS_SEG_FAULT): - self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') - elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): - self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') - elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): - self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') - elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): - self.htmlFile.write(' OK?\n') - elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): - self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') - elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): - self.htmlFile.write(' KO - UE could not sync\n') - elif (processesStatus == HSS_PROCESS_FAILED): - self.htmlFile.write(' KO - HSS process not found\n') - elif (processesStatus == MME_PROCESS_FAILED): - self.htmlFile.write(' KO - MME process not found\n') - elif (processesStatus == SPGW_PROCESS_FAILED): - self.htmlFile.write(' KO - SPGW process not found\n') - elif (processesStatus == UE_IP_ADDRESS_ISSUE): - self.htmlFile.write(' KO - Could not retrieve UE IP address\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - if (len(str(self.htmleNBFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') - self.htmleNBFailureMsg = '' - elif (len(str(self.htmlUEFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') - self.htmlUEFailureMsg = '' - else: - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - - def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - addOrangeBK = False - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - self.htmlFile.write(' ' + str(status) + '\n') - else: - addOrangeBK = True - self.htmlFile.write(' ' + str(status) + '\n') - i = 0 - while (i < self.htmlUEConnected): - if (i < ue_status): - if (not ue_queue.empty()): - if (addOrangeBK): - self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') - else: - self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') - else: - self.htmlFile.write(' -\n') - else: - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - -#----------------------------------------------------------- -# ShowTestID() -#----------------------------------------------------------- - def ShowTestID(self): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1mTest ID:' + self.testCase_id + '\u001B[0m') - logging.debug('\u001B[1m' + self.desc + '\u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - -#----------------------------------------------------------- -# Usage() -#----------------------------------------------------------- -def Usage(): - print('----------------------------------------------------------------------------------------------------------------------') - print('main.py Ver:' + Version) - print('----------------------------------------------------------------------------------------------------------------------') - print('Usage: python main.py [options]') - print(' --help Show this help.') - print(' --mode=[Mode]') - print(' TesteNB') - print(' InitiateHtml, FinalizeHtml') - print(' TerminateeNB, TerminateUE, TerminateHSS, TerminateMME, TerminateSPGW') - print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf') - print('---------------------------------------------------------------------------------------------------- Git Options --') - print(' --ranRepository=[OAI RAN Repository URL]') - print(' --ranBranch=[OAI RAN Repository Branch]') - print(' --ranCommitID=[OAI RAN Repository Commit SHA-1]') - print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)]') - print(' --ranTargetBranch=[Target Branch in case of a Merge Request]') - print('--------------------------------------------------------------------------------------------- eNB Server Options --') - print(' --eNBIPAddress=[eNB\'s IP Address]') - print(' --eNBUserName=[eNB\'s Login User Name]') - print(' --eNBPassword=[eNB\'s Login Password]') - print(' --eNBSourceCodePath=[eNB\'s Source Code Path]') - print('------------------------------------------------------------------------------------------ OAI UE Server Options --') - print(' --UEIPAddress=[UE\'s IP Address]') - print(' --UEUserName=[UE\'s Login User Name]') - print(' --UEPassword=[UE\'s Login Password]') - print(' --UESourceCodePath=[UE\'s Source Code Path]') - print('--------------------------------------------------------------------------------------------- EPC Server Options --') - print(' --EPCIPAddress=[EPC\'s IP Address]') - print(' --EPCUserName=[EPC\'s Login User Name]') - print(' --EPCPassword=[EPC\'s Login Password]') - print(' --EPCSourceCodePath=[EPC\'s Source Code Path]') - print(' --EPCType=[EPC\'s Type: OAI or ltebox or OAI-Rel14-CUPS]') - print('--------------------------------------------------------------------------------------------- ABD Server Options --') - print(' --ADBIPAddress=[ADB\'s IP Address]') - print(' --ADBUserName=[ADB\'s Login User Name]') - print(' --ADBPassword=[ADB\'s Login Password]') - print('----------------------------------------------------------------------------------------------------------------------') - print(' --XMLTestFile=[XML Test File to be run]') - print('----------------------------------------------------------------------------------------------------------------------') - -def CheckClassValidity(action,id): - if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': - logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) - return False - return True - -def GetParametersFromXML(action): - if action == 'Build_eNB': - SSH.Build_eNB_args = test.findtext('Build_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - xmlBgBuildField = test.findtext('backgroundBuild') - if (xmlBgBuildField is None): - SSH.backgroundBuild = False - else: - if re.match('true', xmlBgBuildField, re.IGNORECASE): - SSH.backgroundBuild = True - else: - SSH.backgroundBuild = False - - if action == 'WaitEndBuild_eNB': - SSH.Build_eNB_args = test.findtext('Build_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - - if action == 'Initialize_eNB': - SSH.Initialize_eNB_args = test.findtext('Initialize_eNB_args') - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - - if action == 'Terminate_eNB': - SSH.eNB_instance = test.findtext('eNB_instance') - if (SSH.eNB_instance is None): - SSH.eNB_instance = '0' - SSH.eNB_serverId = test.findtext('eNB_serverId') - if (SSH.eNB_serverId is None): - SSH.eNB_serverId = '0' - - if action == 'Attach_UE': - nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') - if (nbMaxUEtoAttach is None): - SSH.nbMaxUEtoAttach = -1 - else: - SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach) - - if action == 'CheckStatusUE': - expectedNBUE = test.findtext('expectedNbOfConnectedUEs') - if (expectedNBUE is None): - SSH.expectedNbOfConnectedUEs = -1 - else: - SSH.expectedNbOfConnectedUEs = int(expectedNBUE) - - if action == 'Build_OAI_UE': - SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') - - if action == 'Initialize_OAI_UE': - SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') - SSH.UE_instance = test.findtext('UE_instance') - if (SSH.UE_instance is None): - SSH.UE_instance = '0' - - if action == 'Terminate_OAI_UE': - SSH.eNB_instance = test.findtext('UE_instance') - if (SSH.UE_instance is None): - SSH.UE_instance = '0' - - if action == 'Ping' or action == 'Ping_CatM_module': - SSH.ping_args = test.findtext('ping_args') - SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') - - if action == 'Iperf': - SSH.iperf_args = test.findtext('iperf_args') - SSH.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') - SSH.iperf_profile = test.findtext('iperf_profile') - if (SSH.iperf_profile is None): - SSH.iperf_profile = 'balanced' - else: - if SSH.iperf_profile != 'balanced' and SSH.iperf_profile != 'unbalanced' and SSH.iperf_profile != 'single-ue': - logging.debug('ERROR: test-case has wrong profile ' + SSH.iperf_profile) - SSH.iperf_profile = 'balanced' - - if action == 'IdleSleep': - string_field = test.findtext('idle_sleep_time_in_sec') - if (string_field is None): - SSH.idle_sleep_time = 5 - else: - SSH.idle_sleep_time = int(string_field) - - if action == 'Perform_X2_Handover': - string_field = test.findtext('x2_ho_options') - if (string_field is None): - SSH.x2_ho_options = 'network' - else: - if string_field != 'network': - logging.error('ERROR: test-case has wrong option ' + string_field) - SSH.x2_ho_options = 'network' - else: - SSH.x2_ho_options = string_field - - -#check if given test is in list -#it is in list if one of the strings in 'list' is at the beginning of 'test' -def test_in_list(test, list): - for check in list: - check=check.replace('+','') - if (test.startswith(check)): - return True - return False - -def receive_signal(signum, frame): - sys.exit(1) - -#----------------------------------------------------------- -# Parameter Check -#----------------------------------------------------------- -mode = '' -SSH = SSHConnection() - -argvs = sys.argv -argc = len(argvs) -cwd = os.getcwd() - -while len(argvs) > 1: - myArgv = argvs.pop(1) # 0th is this file's name - if re.match('^\-\-help$', myArgv, re.IGNORECASE): - Usage() - sys.exit(0) - elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) - mode = matchReg.group(1) - elif re.match('^\-\-eNBRepository=(.+)$|^\-\-ranRepository(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) - SSH.ranRepository = matchReg.group(1) - elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) - doMerge = matchReg.group(1) - if ((doMerge == 'true') or (doMerge == 'True')): - SSH.ranAllowMerge = True - elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) - SSH.ranBranch = matchReg.group(1) - elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) - SSH.ranCommitID = matchReg.group(1) - elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) - SSH.ranTargetBranch = matchReg.group(1) - elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBIPAddress = matchReg.group(1) - elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1IPAddress = matchReg.group(1) - elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2IPAddress = matchReg.group(1) - elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBUserName = matchReg.group(1) - elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1UserName = matchReg.group(1) - elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2UserName = matchReg.group(1) - elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBPassword = matchReg.group(1) - elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1Password = matchReg.group(1) - elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2Password = matchReg.group(1) - elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNBSourceCodePath = matchReg.group(1) - elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB1SourceCodePath = matchReg.group(1) - elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.eNB2SourceCodePath = matchReg.group(1) - elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCIPAddress = matchReg.group(1) - elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCBranch = matchReg.group(1) - elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCUserName = matchReg.group(1) - elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCPassword = matchReg.group(1) - elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.EPCSourceCodePath = matchReg.group(1) - elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) - if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): - SSH.EPCType = matchReg.group(1) - else: - sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') - elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBIPAddress = matchReg.group(1) - elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBUserName = matchReg.group(1) - elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) - if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): - if re.match('distributed', matchReg.group(1), re.IGNORECASE): - SSH.ADBCentralized = False - else: - SSH.ADBCentralized = True - else: - sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') - elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.ADBPassword = matchReg.group(1) - elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) - SSH.testXMLfiles.append(matchReg.group(1)) - SSH.nbTestXMLfiles += 1 - elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) - SSH.UEIPAddress = matchReg.group(1) - elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) - SSH.UEUserName = matchReg.group(1) - elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) - SSH.UEPassword = matchReg.group(1) - elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) - SSH.UESourceCodePath = matchReg.group(1) - elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) - finalStatus = matchReg.group(1) - if ((finalStatus == 'true') or (finalStatus == 'True')): - SSH.finalStatus = True - else: - Usage() - sys.exit('Invalid Parameter: ' + myArgv) - -if re.match('^TerminateeNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.eNB_serverId = '0' - SSH.eNB_instance = '0' - SSH.eNBSourceCodePath = '/tmp/' - SSH.TerminateeNB() -elif re.match('^TerminateUE$', mode, re.IGNORECASE): - if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): - Usage() - sys.exit('Insufficient Parameter') - signal.signal(signal.SIGUSR1, receive_signal) - SSH.TerminateUE() -elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '': - Usage() - sys.exit('Insufficient Parameter') - signal.signal(signal.SIGUSR1, receive_signal) - SSH.TerminateOAIUE() -elif re.match('^TerminateHSS$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.TerminateHSS() -elif re.match('^TerminateMME$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.TerminateMME() -elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.TerminateSPGW() -elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): - if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == ''): - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectBuild() -elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollecteNB() -elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectHSS() -elif re.match('^LogCollectMME$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectMME() -elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectSPGW() -elif re.match('^LogCollectPing$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectPing() -elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): - if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCSourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectIperf() -elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectOAIUE() -elif re.match('^InitiateHtml$', mode, re.IGNORECASE): - if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): - Usage() - sys.exit('Insufficient Parameter') - count = 0 - foundCount = 0 - while (count < SSH.nbTestXMLfiles): - xml_test_file = cwd + "/" + SSH.testXMLfiles[count] - xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count] - if (os.path.isfile(xml_test_file)): - xmlTree = ET.parse(xml_test_file) - xmlRoot = xmlTree.getroot() - SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) - foundCount += 1 - count += 1 - if foundCount != SSH.nbTestXMLfiles: - SSH.nbTestXMLfiles = foundCount - SSH.CreateHtmlHeader() -elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - SSH.CreateHtmlFooter(SSH.finalStatus) -elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): - if re.match('^TesteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': - Usage() - sys.exit('Insufficient Parameter') - - if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): - SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") - SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") - else: - if SSH.UEIPAddress == '' or SSH.ranRepository == '' or SSH.ranBranch == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': - Usage() - sys.exit('UE: Insufficient Parameter') - - #read test_case_list.xml file - # if no parameters for XML file, use default value - if (SSH.nbTestXMLfiles != 1): - xml_test_file = cwd + "/test_case_list.xml" - else: - xml_test_file = cwd + "/" + SSH.testXMLfiles[0] - - xmlTree = ET.parse(xml_test_file) - xmlRoot = xmlTree.getroot() - - exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') - requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') - if (SSH.nbTestXMLfiles == 1): - SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) - repeatCount = xmlRoot.findtext('repeatCount',default='1') - SSH.repeatCounts.append(int(repeatCount)) - all_tests=xmlRoot.findall('testCase') - - exclusion_tests=exclusion_tests.split() - requested_tests=requested_tests.split() - - #check that exclusion tests are well formatted - #(6 digits or less than 6 digits followed by +) - for test in exclusion_tests: - if (not re.match('^[0-9]{6}$', test) and - not re.match('^[0-9]{1,5}\+$', test)): - logging.debug('ERROR: exclusion test is invalidly formatted: ' + test) - sys.exit(1) - else: - logging.debug(test) - - #check that requested tests are well formatted - #(6 digits or less than 6 digits followed by +) - #be verbose - for test in requested_tests: - if (re.match('^[0-9]{6}$', test) or - re.match('^[0-9]{1,5}\+$', test)): - logging.debug('INFO: test group/case requested: ' + test) - else: - logging.debug('ERROR: requested test is invalidly formatted: ' + test) - sys.exit(1) - if (SSH.EPCIPAddress != '') and (SSH.EPCIPAddress != 'none'): - SSH.CheckFlexranCtrlInstallation() - - #get the list of tests to be done - todo_tests=[] - for test in requested_tests: - if (test_in_list(test, exclusion_tests)): - logging.debug('INFO: test will be skipped: ' + test) - else: - #logging.debug('INFO: test will be run: ' + test) - todo_tests.append(test) - - signal.signal(signal.SIGUSR1, receive_signal) - - SSH.CreateHtmlTabHeader() - - SSH.FailReportCnt = 0 - SSH.prematureExit = True - SSH.startTime = int(round(time.time() * 1000)) - while SSH.FailReportCnt < SSH.repeatCounts[0] and SSH.prematureExit: - SSH.prematureExit = False - for test_case_id in todo_tests: - if SSH.prematureExit: - break - for test in all_tests: - if SSH.prematureExit: - break - id = test.get('id') - if test_case_id != id: - continue - SSH.testCase_id = id - SSH.desc = test.findtext('desc') - action = test.findtext('class') - if (CheckClassValidity(action, id) == False): - continue - SSH.ShowTestID() - GetParametersFromXML(action) - if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': - if (SSH.ADBIPAddress != 'none'): - terminate_ue_flag = False - SSH.GetAllUEDevices(terminate_ue_flag) - if action == 'Build_eNB': - SSH.BuildeNB() - elif action == 'WaitEndBuild_eNB': - SSH.WaitBuildeNBisFinished() - elif action == 'Initialize_eNB': - SSH.InitializeeNB() - elif action == 'Terminate_eNB': - SSH.TerminateeNB() - elif action == 'Initialize_UE': - SSH.InitializeUE() - elif action == 'Terminate_UE': - SSH.TerminateUE() - elif action == 'Attach_UE': - SSH.AttachUE() - elif action == 'Detach_UE': - SSH.DetachUE() - elif action == 'DataDisable_UE': - SSH.DataDisableUE() - elif action == 'DataEnable_UE': - SSH.DataEnableUE() - elif action == 'CheckStatusUE': - SSH.CheckStatusUE() - elif action == 'Build_OAI_UE': - SSH.BuildOAIUE() - elif action == 'Initialize_OAI_UE': - SSH.InitializeOAIUE() - elif action == 'Terminate_OAI_UE': - SSH.TerminateOAIUE() - elif action == 'Initialize_CatM_module': - SSH.InitializeCatM() - elif action == 'Terminate_CatM_module': - SSH.TerminateCatM() - elif action == 'Attach_CatM_module': - SSH.AttachCatM() - elif action == 'Detach_CatM_module': - SSH.TerminateCatM() - elif action == 'Ping_CatM_module': - SSH.PingCatM() - elif action == 'Ping': - SSH.Ping() - elif action == 'Iperf': - SSH.Iperf() - elif action == 'Reboot_UE': - SSH.RebootUE() - elif action == 'Initialize_HSS': - SSH.InitializeHSS() - elif action == 'Terminate_HSS': - SSH.TerminateHSS() - elif action == 'Initialize_MME': - SSH.InitializeMME() - elif action == 'Terminate_MME': - SSH.TerminateMME() - elif action == 'Initialize_SPGW': - SSH.InitializeSPGW() - elif action == 'Terminate_SPGW': - SSH.TerminateSPGW() - elif action == 'Initialize_FlexranCtrl': - SSH.InitializeFlexranCtrl() - elif action == 'Terminate_FlexranCtrl': - SSH.TerminateFlexranCtrl() - elif action == 'IdleSleep': - SSH.IdleSleep() - elif action == 'Perform_X2_Handover': - SSH.Perform_X2_Handover() - else: - sys.exit('Invalid action') - SSH.FailReportCnt += 1 - if SSH.FailReportCnt == SSH.repeatCounts[0] and SSH.prematureExit: - logging.debug('Testsuite failed ' + str(SSH.FailReportCnt) + ' time(s)') - SSH.CreateHtmlTabFooter(False) - sys.exit('Failed Scenario') - else: - logging.info('Testsuite passed after ' + str(SSH.FailReportCnt) + ' time(s)') - SSH.CreateHtmlTabFooter(True) -else: - Usage() - sys.exit('Invalid mode') -sys.exit(0) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index c9da55041c..1dd8402250 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -28,48 +28,13 @@ # pexpect #--------------------------------------------------------------------- +import constants as CONST + #----------------------------------------------------------- # Version #----------------------------------------------------------- Version = '0.1' -#----------------------------------------------------------- -# Constants -#----------------------------------------------------------- -ALL_PROCESSES_OK = 0 -ENB_PROCESS_FAILED = -1 -ENB_PROCESS_OK = +1 -ENB_PROCESS_SEG_FAULT = -11 -ENB_PROCESS_ASSERTION = -12 -ENB_PROCESS_REALTIME_ISSUE = -13 -ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 -ENB_PROCESS_SLAVE_RRU_NOT_SYNCED = -15 -HSS_PROCESS_FAILED = -2 -HSS_PROCESS_OK = +2 -MME_PROCESS_FAILED = -3 -MME_PROCESS_OK = +3 -SPGW_PROCESS_FAILED = -4 -SPGW_PROCESS_OK = +4 -UE_IP_ADDRESS_ISSUE = -5 -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 -OAI_UE_PROCESS_COULD_NOT_SYNC = -21 -OAI_UE_PROCESS_ASSERTION = -22 -OAI_UE_PROCESS_FAILED = -23 -OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24 -OAI_UE_PROCESS_SEG_FAULT = -25 -OAI_UE_PROCESS_OK = +6 - -UE_STATUS_DETACHED = 0 -UE_STATUS_DETACHING = 1 -UE_STATUS_ATTACHING = 2 -UE_STATUS_ATTACHED = 3 - -X2_HO_REQ_STATE__IDLE = 0 -X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1 -X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2 -X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3 -X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10 - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -89,56 +54,22 @@ logging.basicConfig( format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" ) + #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class OaiCiTest(): + def __init__(self): self.FailReportCnt = 0 - self.prematureExit = False - self.ranRepository = '' - self.ranBranch = '' - self.ranAllowMerge = False - self.ranCommitID = '' - self.ranTargetBranch = '' - self.eNBIPAddress = '' - self.eNBUserName = '' - self.eNBPassword = '' - self.eNBSourceCodePath = '' - #self.EPCIPAddress = '' - #self.EPCUserName = '' - #self.EPCPassword = '' - self.eNB1IPAddress = '' - self.eNB1UserName = '' - self.eNB1Password = '' - self.eNB1SourceCodePath = '' - self.eNB2IPAddress = '' - self.eNB2UserName = '' - self.eNB2Password = '' - self.eNB2SourceCodePath = '' - #self.EPCSourceCodePath = '' - #self.EPCType = '' - #self.EPC_PcapFileName = '' self.ADBIPAddress = '' self.ADBUserName = '' self.ADBPassword = '' self.ADBCentralized = True self.testCase_id = '' self.testXMLfiles = [] - self.nbTestXMLfiles = 0 + #self.nbTestXMLfiles = 0 self.desc = '' - self.Build_eNB_args = '' - self.backgroundBuild = False - self.backgroundBuildTestId = ['', '', ''] - self.Build_eNB_forced_workspace_cleanup = False - self.Initialize_eNB_args = '' - self.air_interface = 'lte' - self.eNB_instance = '' - self.eNB_serverId = '' - self.eNBLogFiles = ['', '', ''] - self.eNBOptions = ['', '', ''] - self.eNBmbmsEnables = [False, False, False] - self.eNBstatuses = [-1, -1, -1] self.ping_args = '' self.ping_packetloss_threshold = '' self.iperf_args = '' @@ -156,8 +87,8 @@ class OaiCiTest(): self.CatMDevices = [] self.UEIPAddresses = [] self.htmlFile = '' - self.htmlHeaderCreated = False - self.htmlFooterCreated = False + # self.htmlHeaderCreated = False + # self.htmlFooterCreated = False self.htmlUEConnected = -1 self.htmleNBFailureMsg = '' self.htmlUEFailureMsg = '' @@ -167,9 +98,6 @@ class OaiCiTest(): self.x2NbENBs = 0 self.x2ENBBsIds = [] self.x2ENBConnectedUEs = [] - self.htmlTabRefs = [] - self.htmlTabNames = [] - self.htmlTabIcons = [] self.repeatCounts = [] self.finalStatus = False self.OsVersion = '' @@ -193,214 +121,24 @@ class OaiCiTest(): self.expectedNbOfConnectedUEs = 0 self.startTime = 0 - def BuildeNB(self): - if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(lIpAddr, lUserName, lPassWord) - # Check if we build an 5G-NR gNB or an LTE eNB - result = re.search('--gNB', self.Build_eNB_args) - if result is not None: - self.air_interface = 'nr' - else: - self.air_interface = 'lte' - # Worakround for some servers, we need to erase completely the workspace - if self.Build_eNB_forced_workspace_cleanup: - SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) - # on RedHat/CentOS .git extension is mandatory - result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) - if result is not None: - full_ran_repo_name = self.ranRepository - else: - full_ran_repo_name = self.ranRepository + '.git' - SSH.command('mkdir -p ' + lSourcePath, '\$', 5) - SSH.command('cd ' + lSourcePath, '\$', 5) - SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) - # Raphael: here add a check if git clone or git fetch went smoothly - SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - SSH.command('git config user.name "OAI Jenkins"', '\$', 5) - # Checking the BUILD INFO file - if not self.backgroundBuild: - SSH.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', SSH.getBefore()) - if result is not None: - mismatch = False - SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, SSH.getBefore()) - if result is None: - mismatch = True - SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - result = re.search('YES', SSH.getBefore()) - if result is None: - mismatch = True - SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - result = re.search('develop', SSH.getBefore()) - else: - result = re.search(self.ranTargetBranch, SSH.getBefore()) - if result is None: - mismatch = True - else: - result = re.search('NO', SSH.getBefore()) - if result is None: - mismatch = True - if not mismatch: - SSH.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - return - - SSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) - # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (self.ranAllowMerge): - if self.ranTargetBranch == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): - SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - SSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) - SSH.command('source oaienv', '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('mkdir -p log', '\$', 5) - SSH.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - if self.backgroundBuild: - SSH.command('echo "./build_oai ' + self.Build_eNB_args + '" > ./my-lte-softmodem-build.sh', '\$', 5) - SSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) - SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) - SSH.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id - return - SSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) - - def WaitBuildeNBisFinished(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(lIpAddr, lUserName, lPassWord) - count = 40 - buildOAIprocess = True - while (count > 0) and buildOAIprocess: - SSH.command('ps aux | grep --color=never build_ | grep -v grep', '\$', 3) - result = re.search('build_oai', SSH.getBefore()) - if result is None: - buildOAIprocess = False - else: - count -= 1 - time.sleep(30) - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) - - def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): - SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) - SSH.command('ls ran_build/build', '\$', 3) - SSH.command('ls ran_build/build', '\$', 3) - if self.air_interface == 'nr': - nodeB_prefix = 'g' - else: - nodeB_prefix = 'e' - buildStatus = True - result = re.search(self.air_interface + '-softmodem', SSH.getBefore()) - if result is None: - buildStatus = False - else: - # Generating a BUILD INFO file - SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): - SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': - SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - SSH.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('mkdir -p build_log_' + testcaseId, '\$', 5) - SSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5) - SSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5) - if self.eNB_serverId != '0': - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5) - SSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5) - SSH.close() - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - os.remove('./tmp_build' + testcaseId + '.zip') - SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/tmp_build' + testcaseId + '.zip', '.') - if (os.path.isfile('./tmp_build' + testcaseId + '.zip')): - SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './tmp_build' + testcaseId + '.zip', self.eNBSourceCodePath + '/cmake_targets/.') - os.remove('./tmp_build' + testcaseId + '.zip') - SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - SSH.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) - SSH.command('unzip -qq -DD tmp_build' + testcaseId + '.zip', '\$', 5) - SSH.command('rm -f tmp_build' + testcaseId + '.zip', '\$', 5) - SSH.close() - else: - SSH.close() - - if buildStatus: - logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) - else: - logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_eNB_args, 'KO', ALL_PROCESSES_OK) - self.CreateHtmlTabFooter(False) - sys.exit(1) def BuildOAIUE(self): - if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + if self.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) result = re.search('--nrUE', self.Build_OAI_UE_args) if result is not None: - self.air_interface = 'nr' + RAN.Setair_interface('nr') ue_prefix = 'NR ' else: - self.air_interface = 'lte' + RAN.Setair_interface('lte') ue_prefix = '' - result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', RAN.GetranRepository()) if result is not None: - full_ran_repo_name = self.ranRepository + full_ran_repo_name = RAN.GetranRepository() else: - full_ran_repo_name = self.ranRepository + '.git' + full_ran_repo_name = RAN.GetranRepository() + '.git' SSH.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) SSH.command('cd ' + self.UESourceCodePath, '\$', 5) SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) @@ -413,19 +151,19 @@ class OaiCiTest(): if result is not None: mismatch = False SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(self.ranCommitID, SSH.getBefore()) + result = re.search(RAN.GetranCommitID(), SSH.getBefore()) if result is None: mismatch = True SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): + if (RAN.GetranAllowMerge()): result = re.search('YES', SSH.getBefore()) if result is None: mismatch = True SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': + if RAN.GetranTargetBranch() == '': result = re.search('develop', SSH.getBefore()) else: - result = re.search(self.ranTargetBranch, SSH.getBefore()) + result = re.search(RAN.GetranTargetBranch(), SSH.getBefore()) if result is None: mismatch = True else: @@ -434,23 +172,23 @@ class OaiCiTest(): mismatch = True if not mismatch: SSH.close() - self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', CONST.ALL_PROCESSES_OK) return SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) # if the commit ID is provided use it to point to it - if self.ranCommitID != '': - SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) + if RAN.GetranCommitID() != '': + SSH.command('git checkout -f ' + RAN.GetranCommitID(), '\$', 5) # if the branch is not develop, then it is a merge request and we need to do # the potential merge. Note that merge conflicts should already been checked earlier - if (self.ranAllowMerge): - if self.ranTargetBranch == '': - if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): + if (RAN.GetranAllowMerge()): + if RAN.GetranTargetBranch() == '': + if (RAN.GetranBranch() != 'develop') and (RAN.GetranBranch() != 'origin/develop'): SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) else: - logging.debug('Merging with the target branch: ' + self.ranTargetBranch) - SSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + logging.debug('Merging with the target branch: ' + RAN.GetranTargetBranch()) + SSH.command('git merge --ff origin/' + RAN.GetranTargetBranch() + ' -m "Temporary merge for CI"', '\$', 5) SSH.command('source oaienv', '\$', 5) SSH.command('cd cmake_targets', '\$', 5) SSH.command('mkdir -p log', '\$', 5) @@ -460,7 +198,7 @@ class OaiCiTest(): SSH.command('ls ran_build/build', '\$', 3) SSH.command('ls ran_build/build', '\$', 3) buildStatus = True - result = re.search(self.air_interface + '-uesoftmodem', SSH.getBefore()) + result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) if result is None: buildStatus = False SSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) @@ -468,23 +206,23 @@ class OaiCiTest(): SSH.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) if buildStatus: # Generating a BUILD INFO file - SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (self.ranAllowMerge): + SSH.command('echo "SRC_BRANCH: ' + RAN.GetranBranch() + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_COMMIT: ' + RAN.GetranCommitID() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if (RAN.GetranAllowMerge()): SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if self.ranTargetBranch == '': + if RAN.GetranTargetBranch() == '': SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: - SSH.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "TGT_BRANCH: ' + RAN.GetranTargetBranch() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) SSH.close() - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', CONST.ALL_PROCESSES_OK, 'OAI UE') else: SSH.close() logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') - self.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', CONST.ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTabFooter(False) sys.exit(1) def CheckFlexranCtrlInstallation(self): @@ -495,6 +233,7 @@ class OaiCiTest(): result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) if result is not None: self.flexranCtrlInstalled = True + RAN.SetflexranCtrlInstalled(True) logging.debug('Flexran Controller is installed') SSH.close() @@ -515,187 +254,10 @@ class OaiCiTest(): if result is not None: logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') self.flexranCtrlStarted = True + RAN.SetflexranCtrlStarted(True) SSH.close() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - - def InitializeeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = False - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) - # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) - result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', SSH.getBefore()) - if result is not None: - eth_interface = result.group('eth_interface') - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - EPC.EPC_PcapFileName = 'enb_' + self.testCase_id + '_s1log.pcap' - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.EPC_PcapFileName + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) - SSH.close() - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('cd ' + lSourcePath, '\$', 5) - # Initialize_eNB_args usually start with -O and followed by the location in repository - full_config_file = self.Initialize_eNB_args.replace('-O ','') - extra_options = '' - extIdx = full_config_file.find('.conf') - if (extIdx > 0): - extra_options = full_config_file[extIdx + 5:] - # if tracer options is on, compiling and running T Tracer - result = re.search('T_stdout', str(extra_options)) - if result is not None: - logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') - SSH.command('cd common/utils/T/tracer', '\$', 5) - SSH.command('make', '\$', 10) - SSH.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) - SSH.command('cd ' + lSourcePath, '\$', 5) - full_config_file = full_config_file[:extIdx + 5] - config_path, config_file = os.path.split(full_config_file) - else: - sys.exit('Insufficient Parameter') - ci_full_config_file = config_path + '/ci-' + config_file - rruCheck = False - result = re.search('^rru|^rcc|^du.band', str(config_file)) - if result is not None: - rruCheck = True - # do not reset board twice in IF4.5 case - result = re.search('^rru|^enb|^du.band', str(config_file)) - if result is not None: - SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) - result = re.search('type: b200', SSH.getBefore()) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - SSH.command('echo ' + lPassWord + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - SSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) - # Make a copy and adapt to EPC / eNB IP addresses - SSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - SSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.GetIPAddress() + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - SSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "yes";/\' ' + ci_full_config_file, '\$', 2); - else: - SSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED = "no";/\' ' + ci_full_config_file, '\$', 2); - self.eNBmbmsEnables[int(self.eNB_instance)] = False - SSH.command('grep enable_enb_m2 ' + ci_full_config_file, '\$', 2); - result = re.search('yes', SSH.getBefore()) - if result is not None: - self.eNBmbmsEnables[int(self.eNB_instance)] = True - logging.debug('\u001B[1m MBMS is enabled on this eNB\u001B[0m') - result = re.search('noS1', str(self.Initialize_eNB_args)) - eNBinNoS1 = False - if result is not None: - eNBinNoS1 = True - logging.debug('\u001B[1m eNB is in noS1 configuration \u001B[0m') - # Launch eNB with the modified config file - SSH.command('source oaienv', '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface + '-softmodem -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - SSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - SSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - SSH.command('hostnamectl','\$', 5) - result = re.search('CentOS Linux 7', SSH.getBefore()) - if result is not None: - SSH.command('echo $USER; nohup sudo ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log 2>&1 &', lUserName, 10) - else: - SSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' - if extra_options != '': - self.eNBOptions[int(self.eNB_instance)] = extra_options - time.sleep(6) - doLoop = True - loopCounter = 20 - enbDidSync = False - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # In case of T tracer recording, we may need to kill it - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - SSH.command('killall --signal SIGKILL record', '\$', 5) - SSH.close() - doLoop = False - logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', ALL_PROCESSES_OK) - # In case of T tracer recording, we need to kill tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if EPC.EPC_PcapFileName != '': - time.sleep(0.5) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.close() - time.sleep(1) - if EPC.EPC_PcapFileName != '': - copyin_res = SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') - if (copyin_res == 0): - SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') - self.prematureExit = True - return - else: - SSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync|Starting"', '\$', 4) - if rruCheck: - result = re.search('wait RUs', SSH.getBefore()) - else: - result = re.search('got sync|Starting F1AP at CU', SSH.getBefore()) - if result is None: - time.sleep(6) - else: - doLoop = False - enbDidSync = True - time.sleep(10) - - if enbDidSync and eNBinNoS1: - SSH.command('ifconfig oaitun_enb1', '\$', 4) - SSH.command('ifconfig oaitun_enb1', '\$', 4) - result = re.search('inet addr:1|inet 1', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_enb1 interface is mounted and configured\u001B[0m') - else: - logging.error('\u001B[1m oaitun_enb1 interface is either NOT mounted or NOT configured\u001B[0m') - if self.eNBmbmsEnables[int(self.eNB_instance)]: - SSH.command('ifconfig oaitun_enm1', '\$', 4) - result = re.search('inet addr', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_enm1 interface is mounted and configured\u001B[0m') - else: - logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m') - if enbDidSync: - self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) - - SSH.close() - self.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', ALL_PROCESSES_OK) - logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') - + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + def InitializeUE_common(self, device_id, idx): try: SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -757,21 +319,21 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def InitializeOAIUE(self): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - if self.air_interface == 'lte': + if RAN.Getair_interface() == 'lte': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) if result is None: check_eNB = True check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) UE_prefix = '' else: @@ -792,7 +354,7 @@ class OaiCiTest(): # Initialize_OAI_UE_args usually start with -C and followed by the location in repository SSH.command('source oaienv', '\$', 5) SSH.command('cd cmake_targets/ran_build/build', '\$', 5) - if self.air_interface == 'lte': + if RAN.Getair_interface() == 'lte': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) # We may have to regenerate the .u* files if result is None: @@ -804,7 +366,7 @@ class OaiCiTest(): SSH.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - SSH.command('echo "ulimit -c unlimited && ./'+ self.air_interface +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('echo "ulimit -c unlimited && ./'+ RAN.Getair_interface() +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) SSH.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) self.UELogFile = 'ue_' + self.testCase_id + '.log' @@ -835,7 +397,7 @@ class OaiCiTest(): doLoop = False continue SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - if self.air_interface == 'nr': + if RAN.Getair_interface() == 'nr': result = re.search('Starting sync detection', SSH.getBefore()) else: result = re.search('got sync', SSH.getBefore()) @@ -852,7 +414,7 @@ class OaiCiTest(): SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT -r *-uesoftmodem', '\$', 4) time.sleep(3) continue - if self.air_interface == 'nr': + if RAN.Getair_interface() == 'nr': fullSyncStatus = True doOutterLoop = False else: @@ -885,7 +447,7 @@ class OaiCiTest(): if (outterLoopCounter == 0): doOutterLoop = False - if fullSyncStatus and gotSyncStatus and self.air_interface == 'lte': + if fullSyncStatus and gotSyncStatus and RAN.Getair_interface() == 'lte': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) if result is None: SSH.command('ifconfig oaitun_ue1', '\$', 4) @@ -899,7 +461,7 @@ class OaiCiTest(): logging.debug(SSH.getBefore()) logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') tunnelInterfaceStatus = False - if self.eNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnables[0]: self.command('ifconfig oaitun_uem1', '\$', 4) result = re.search('inet addr', SSH.getBefore()) if result is not None: @@ -915,23 +477,23 @@ class OaiCiTest(): SSH.close() if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', CONST.ALL_PROCESSES_OK, 'OAI UE') logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') if (self.ADBIPAddress != 'none'): self.UEDevices = [] self.UEDevices.append('OAI-UE') self.UEDevicesStatus = [] - self.UEDevicesStatus.append(UE_STATUS_DETACHED) + self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) else: - if self.air_interface == 'lte': - if self.eNBmbmsEnables[0]: + if RAN.Getair_interface() == 'lte': + if RAN.GeteNBmbmsEnables[0]: self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' else: self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') else: self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') + HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') logging.error('\033[91mInitialize OAI UE Failed! \033[0m') self.AutoTerminateUEandeNB() @@ -961,6 +523,11 @@ class OaiCiTest(): # Calling twice AT to clear all buffers SSH.command('AT', 'OK|ERROR', 5) SSH.command('AT', 'OK', 5) + # Doing a power cycle + self.command('AT^RESET', 'SIMSTORE,READY', 15) + self.command('AT', 'OK|ERROR', 5) + self.command('AT', 'OK', 5) + self.command('ATE1', 'OK', 5) # Disabling the Radio SSH.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') @@ -979,7 +546,7 @@ class OaiCiTest(): # Force closure of picocom but device might still be locked SSH.close() self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() def TerminateCatM(self): @@ -1000,7 +567,7 @@ class OaiCiTest(): logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') SSH.close() self.picocom_closure = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() def AttachCatM(self): @@ -1069,12 +636,12 @@ class OaiCiTest(): else: html_cell += '' html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) else: logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') html_cell = '
CAT-M module Attachment Failed
' html_queue.put(html_cell) - self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) self.AutoTerminateUEandeNB() def PingCatM(self): @@ -1085,7 +652,7 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return try: @@ -1096,8 +663,8 @@ class OaiCiTest(): SSH.command('cd scripts', '\$', 5) if re.match('OAI', EPC.GetType(), re.IGNORECASE): logging.debug('Using the OAI EPC HSS: not implemented yet') - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) else: SSH.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) @@ -1105,7 +672,7 @@ class OaiCiTest(): if result is not None: moduleIPAddr = result.group('ipaddr') else: - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ping_time = re.findall("-c (\d+)",str(self.ping_args)) @@ -1167,9 +734,9 @@ class OaiCiTest(): html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' statusQueue.put(html_cell) if (packetLossOK): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) self.AutoTerminateUEandeNB() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -1193,6 +760,7 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) + print('#GP: in SSH.getBefore() K=0 (it was K=2 in main.py)') result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') @@ -1251,7 +819,7 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) self.AutoTerminateUEandeNB() return multi_jobs = [] @@ -1260,7 +828,7 @@ class OaiCiTest(): nb_ue_to_connect = 0 for device_id in self.UEDevices: if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): - self.UEDevicesStatus[nb_ue_to_connect] = UE_STATUS_ATTACHING + self.UEDevicesStatus[nb_ue_to_connect] = CONST.UE_STATUS_ATTACHING p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) p.daemon = True p.start() @@ -1270,7 +838,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - self.CreateHtmlTestRow('N/A', 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() return else: @@ -1290,16 +858,16 @@ class OaiCiTest(): if (attach_status): cnt = 0 while cnt < len(self.UEDevices): - if self.UEDevicesStatus[cnt] == UE_STATUS_ATTACHING: - self.UEDevicesStatus[cnt] = UE_STATUS_ATTACHED + if self.UEDevicesStatus[cnt] == CONST.UE_STATUS_ATTACHING: + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_ATTACHED cnt += 1 - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - result = re.search('T_stdout', str(self.Initialize_eNB_args)) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) if result is not None: logging.debug('Waiting 5 seconds to fill up record file') time.sleep(5) else: - self.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def DetachUE_common(self, device_id, idx): @@ -1325,13 +893,13 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) self.AutoTerminateUEandeNB() return multi_jobs = [] cnt = 0 for device_id in self.UEDevices: - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHING + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHING p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) p.daemon = True p.start() @@ -1339,14 +907,14 @@ class OaiCiTest(): cnt += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - result = re.search('T_stdout', str(self.Initialize_eNB_args)) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) if result is not None: logging.debug('Waiting 5 seconds to fill up record file') time.sleep(5) cnt = 0 while cnt < len(self.UEDevices): - self.UEDevicesStatus[cnt] = UE_STATUS_DETACHED + self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHED cnt += 1 def RebootUE_common(self, device_id): @@ -1396,8 +964,8 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) multi_jobs = [] for device_id in self.UEDevices: @@ -1407,7 +975,7 @@ class OaiCiTest(): multi_jobs.append(p) for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def DataDisableUE_common(self, device_id, idx): try: @@ -1436,7 +1004,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def DataEnableUE_common(self, device_id, idx): try: @@ -1465,7 +1033,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def GetAllUEDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': @@ -1501,14 +1069,16 @@ class OaiCiTest(): self.UEDevicesRebootCmd.append(comma_split[5]) phone_list_file.close() - if terminate_ue_flag == False: + if terminate_ue_flag == True: + print('terminate_ue_flag == True') if len(self.UEDevices) == 0: logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') sys.exit(1) if len(self.UEDevicesStatus) == 0: + print('len(self.UEDevicesStatus) == 0') cnt = 0 while cnt < len(self.UEDevices): - self.UEDevicesStatus.append(UE_STATUS_DETACHED) + self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) cnt += 1 def GetAllCatMDevices(self, terminate_ue_flag): @@ -1528,7 +1098,7 @@ class OaiCiTest(): SSH.close() if result is not None: logging.debug('Found a module list file on ADB server') - if terminate_ue_flag == False: + if terminate_ue_flag == True: if len(self.CatMDevices) == 0: logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') sys.exit(1) @@ -1591,8 +1161,8 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.CreateHtmlTabFooter(False) + HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) + HTML.CreateHtmlTabFooter(False) sys.exit(1) multi_jobs = [] lock = Lock() @@ -1628,7 +1198,7 @@ class OaiCiTest(): htmlOptions = 'N/A' if (status_queue.empty()): - self.CreateHtmlTestRow(htmlOptions, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(htmlOptions, 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: check_status = True @@ -1642,9 +1212,9 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\n' + message + '
' html_queue.put(html_cell) if check_status and passStatus: - self.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def GetAllUEIPAddresses(self): @@ -1675,7 +1245,8 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) idx = 0 for device_id in self.UEDevices: - if self.UEDevicesStatus[idx] != UE_STATUS_ATTACHED: + print('UE status attched'+CONST.UE_STATUS_ATTACHED) + if self.UEDevicesStatus[idx] != CONST.UE_STATUS_ATTACHED: idx += 1 continue count = 0 @@ -1804,19 +1375,19 @@ class OaiCiTest(): html_queue = SimpleQueue() html_cell = '
OAI UE ping result\n' + qMsg + '
' html_queue.put(html_cell) - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) def PingNoS1(self): check_eNB = True check_OAI_UE = True pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) if ping_from_eNB is not None: - if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '': + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') else: @@ -1825,8 +1396,8 @@ class OaiCiTest(): sys.exit('Insufficient Parameter') try: if ping_from_eNB is not None: - SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - SSH.command('cd ' + self.eNBSourceCodePath + '/cmake_targets/', '\$', 5) + SSH.open(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword) + SSH.command('cd ' + RAN.GeteNBSourceCodePath() + '/cmake_targets/', '\$', 5) else: SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) @@ -1884,13 +1455,13 @@ class OaiCiTest(): html_cell = '
OAI UE ping result\n' + qMsg + '
' html_queue.put(html_cell) if packetLossOK: - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) # copying on the EPC server for logCollection if ping_from_eNB is not None: - copyin_res = SSH.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') + copyin_res = SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') else: copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') if (copyin_res == 0): @@ -1899,7 +1470,7 @@ class OaiCiTest(): os.kill(os.getppid(),signal.SIGUSR1) def Ping(self): - result = re.search('noS1', str(self.Initialize_eNB_args)) + result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) if result is not None: self.PingNoS1() return @@ -1913,12 +1484,12 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.ping_args, 'KO', UE_IP_ADDRESS_ISSUE) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return multi_jobs = [] @@ -1936,7 +1507,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - self.CreateHtmlTestRow(self.ping_args, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: ping_status = True @@ -1951,9 +1522,9 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' html_queue.put(html_cell) if (ping_status): - self.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def Iperf_ComputeTime(self): @@ -2342,6 +1913,7 @@ class OaiCiTest(): def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): try: + logging.debug('entring Iperf_common') # Single-UE profile -- iperf only on one UE if self.iperf_profile == 'single-ue' and idx != 0: return @@ -2352,7 +1924,7 @@ class OaiCiTest(): if (device_id != 'OAI-UE'): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + self.EPCSourceCodePath + '/scripts ; fi', '\$', 5) + SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + EPC.GetSourceCodePath() + '/scripts ; fi', '\$', 5) SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) # Checking if iperf / iperf3 are installed if self.ADBCentralized: @@ -2514,6 +2086,9 @@ class OaiCiTest(): else: SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) + # fromdos has to be called on the python executor not on ADB server + cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log' + subprocess.run(cmd, shell=True) self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) # in case of OAI UE: @@ -2528,21 +2103,21 @@ class OaiCiTest(): os.kill(os.getppid(),signal.SIGUSR1) def IperfNoS1(self): - if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': GenericHelp(Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = True pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return server_on_enb = re.search('-R', str(self.iperf_args)) if server_on_enb is not None: - iServerIPAddr = self.eNBIPAddress - iServerUser = self.eNBUserName - iServerPasswd = self.eNBPassword + iServerIPAddr = RAN.GeteNBIPAddress() + iServerUser = RAN.GeteNBUserName() + iServerPasswd = RAN.GeteNBPassword() iClientIPAddr = self.UEIPAddress iClientUser = self.UEUserName iClientPasswd = self.UEPassword @@ -2550,9 +2125,9 @@ class OaiCiTest(): iServerIPAddr = self.UEIPAddress iServerUser = self.UEUserName iServerPasswd = self.UEPassword - iClientIPAddr = self.eNBIPAddress - iClientUser = self.eNBUserName - iClientPasswd = self.eNBPassword + iClientIPAddr = RAN.GeteNBIPAddress() + iClientUser = RAN.GeteNBUserName() + iClientPasswd = RAN.GeteNBPassword() if self.iperf_options != 'sink': # Starting the iperf server SSH.open(iServerIPAddr, iServerUser, iServerPasswd) @@ -2629,15 +2204,15 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' html_queue.put(html_cell) if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def Iperf(self): - result = re.search('noS1', str(self.Initialize_eNB_args)) + result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) if result is not None: self.IperfNoS1() return @@ -2651,12 +2226,13 @@ class OaiCiTest(): check_OAI_UE = False pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) if (pStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) self.AutoTerminateUEandeNB() return ueIpStatus = self.GetAllUEIPAddresses() if (ueIpStatus < 0): - self.CreateHtmlTestRow(self.iperf_args, 'KO', UE_IP_ADDRESS_ISSUE) + logging.debug('going here') + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB() return @@ -2676,9 +2252,10 @@ class OaiCiTest(): ue_num = len(self.UEIPAddresses) lock = Lock() status_queue = SimpleQueue() + logging.debug('ue_num = ' + str(ue_num)) for UE_IPAddress in self.UEIPAddresses: device_id = self.UEDevices[i] - p = Process(target = CiTestObj.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) + p = Process(target = self.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2687,7 +2264,7 @@ class OaiCiTest(): job.join() if (status_queue.empty()): - self.CreateHtmlTestRow(self.iperf_args, 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.ALL_PROCESSES_OK) self.AutoTerminateUEandeNB() else: iperf_status = True @@ -2705,11 +2282,11 @@ class OaiCiTest(): html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' html_queue.put(html_cell) if (iperf_noperf and iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) elif (iperf_status): - self.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) self.AutoTerminateUEandeNB() def CheckProcessExist(self, check_eNB, check_OAI_UE): @@ -2717,7 +2294,7 @@ class OaiCiTest(): status_queue = SimpleQueue() # in noS1 config, no need to check status from EPC # in gNB also currently no need to check - result = re.search('noS1|band78', str(self.Initialize_eNB_args)) + result = re.search('noS1|band78', str(RAN.GetInitialize_eNB_args())) if result is None: p = Process(target = EPC.CheckHSSProcess, args = (status_queue,)) p.daemon = True @@ -2735,12 +2312,12 @@ class OaiCiTest(): if (check_eNB == False) and (check_OAI_UE == False): return 0 if check_eNB: - p = Process(target = CiTestObj.CheckeNBProcess, args = (status_queue,)) + p = Process(target = RAN.CheckeNBProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) if check_OAI_UE: - p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) + p = Process(target = self.CheckOAIUEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2755,14 +2332,14 @@ class OaiCiTest(): status = status_queue.get() if (status < 0): result = status - if result == ENB_PROCESS_FAILED: - fileCheck = re.search('enb_', str(self.eNBLogFiles[0])) + if result == CONST.ENB_PROCESS_FAILED: + fileCheck = re.search('enb_', str(RAN.GeteNBLogFiles[0])) if fileCheck is not None: - SSH.copyin(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFiles[0], '.') - logStatus = self.AnalyzeLogFile_eNB(self.eNBLogFiles[0]) + SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') + logStatus = self.AnalyzeLogFile_eNB(RAN.GeteNBLogFiles[0]) if logStatus < 0: result = logStatus - self.eNBLogFiles[0] = '' + RAN.SeteNBLogFiles[0] = '' if self.flexranCtrlInstalled and self.flexranCtrlStarted: self.TerminateFlexranCtrl() return result @@ -2771,7 +2348,7 @@ class OaiCiTest(): multi_jobs = [] status_queue = SimpleQueue() if initialize_OAI_UE_flag == False: - p = Process(target = CiTestObj.CheckOAIUEProcess, args = (status_queue,)) + p = Process(target = self.CheckOAIUEProcess, args = (status_queue,)) p.daemon = True p.start() multi_jobs.append(p) @@ -2786,7 +2363,7 @@ class OaiCiTest(): status = status_queue.get() if (status < 0): result = status - if result == OAI_UE_PROCESS_FAILED: + if result == CONST.OAI_UE_PROCESS_FAILED: fileCheck = re.search('ue_', str(self.UELogFile)) if fileCheck is not None: SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') @@ -2798,303 +2375,20 @@ class OaiCiTest(): def CheckOAIUEProcess(self, status_queue): try: SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-uesoftmodem | grep -v grep', '\$', 5) - result = re.search(self.air_interface + '-uesoftmodem', SSH.getBefore()) + SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + RAN.Getair_interface() + '-uesoftmodem | grep -v grep', '\$', 5) + result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) if result is None: logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') - status_queue.put(OAI_UE_PROCESS_FAILED) + status_queue.put(CONST.OAI_UE_PROCESS_FAILED) else: - status_queue.put(OAI_UE_PROCESS_OK) + status_queue.put(CONST.OAI_UE_PROCESS_OK) SSH.close() except: os.kill(os.getppid(),signal.SIGUSR1) - def CheckeNBProcess(self, status_queue): - try: - # At least the instance 0 SHALL be on! - if self.eNBstatuses[0] == 0: - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - elif self.eNBstatuses[0] == 1: - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - elif self.eNBstatuses[0] == 2: - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - else: - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + self.air_interface + '-softmodem | grep -v grep', '\$', 5) - result = re.search(self.air_interface + '-softmodem', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') - status_queue.put(ENB_PROCESS_FAILED) - else: - status_queue.put(ENB_PROCESS_OK) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AnalyzeLogFile_eNB(self, eNBlogFile): - if (not os.path.isfile('./' + eNBlogFile)): - return -1 - enb_log_file = open('./' + eNBlogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - rrcSetupComplete = 0 - rrcReleaseRequest = 0 - rrcReconfigRequest = 0 - rrcReconfigComplete = 0 - rrcReestablishRequest = 0 - rrcReestablishComplete = 0 - rrcReestablishReject = 0 - rlcDiscardBuffer = 0 - rachCanceledProcedure = 0 - uciStatMsgCount = 0 - pdcpFailure = 0 - ulschFailure = 0 - cdrxActivationMessageCount = 0 - dropNotEnoughRBs = 0 - mbmsRequestMsg = 0 - self.htmleNBFailureMsg = '' - isRRU = False - isSlave = False - slaveReceivesFrameResyncCmd = False - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures = 0 - X2HO_outNbProcedures = 0 - for line in enb_log_file.readlines(): - if X2HO_state == X2_HO_REQ_STATE__IDLE: - result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ - result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK - if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ: - result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE - if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE: - result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ - if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ: - result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_inNbProcedures += 1 - if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK: - result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line)) - if result is not None: - X2HO_state = X2_HO_REQ_STATE__IDLE - X2HO_outNbProcedures += 1 - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) - res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) - if res1 is not None and res2 is not None: - requested_option = int(res1.group('requested_option')) - applied_option = int(res2.group('applied_option')) - if requested_option == applied_option: - self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' - else: - self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('[Ss]egmentation [Ff]ault', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./ran_build/build/lte-softmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('Setting function for RU', str(line)) - if result is not None: - isRRU = True - if isRRU: - result = re.search('RU 0 is_slave=yes', str(line)) - if result is not None: - isSlave = True - if isSlave: - result = re.search('Received RRU_frame_resynch command', str(line)) - if result is not None: - slaveReceivesFrameResyncCmd = True - result = re.search('LTE_RRCConnectionSetupComplete from UE', str(line)) - if result is not None: - rrcSetupComplete += 1 - result = re.search('Generate LTE_RRCConnectionRelease|Generate RRCConnectionRelease', str(line)) - if result is not None: - rrcReleaseRequest += 1 - result = re.search('Generate LTE_RRCConnectionReconfiguration', str(line)) - if result is not None: - rrcReconfigRequest += 1 - result = re.search('LTE_RRCConnectionReconfigurationComplete from UE rnti', str(line)) - if result is not None: - rrcReconfigComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentRequest', str(line)) - if result is not None: - rrcReestablishRequest += 1 - result = re.search('LTE_RRCConnectionReestablishmentComplete', str(line)) - if result is not None: - rrcReestablishComplete += 1 - result = re.search('LTE_RRCConnectionReestablishmentReject', str(line)) - if result is not None: - rrcReestablishReject += 1 - result = re.search('CDRX configuration activated after RRC Connection', str(line)) - if result is not None: - cdrxActivationMessageCount += 1 - result = re.search('uci->stat', str(line)) - if result is not None: - uciStatMsgCount += 1 - result = re.search('PDCP.*Out of Resources.*reason', str(line)) - if result is not None: - pdcpFailure += 1 - result = re.search('ULSCH in error in round', str(line)) - if result is not None: - ulschFailure += 1 - result = re.search('BAD all_segments_received', str(line)) - if result is not None: - rlcDiscardBuffer += 1 - result = re.search('Canceled RA procedure for UE rnti', str(line)) - if result is not None: - rachCanceledProcedure += 1 - result = re.search('dropping, not enough RBs', str(line)) - if result is not None: - dropNotEnoughRBs += 1 - if self.eNBmbmsEnables[int(self.eNB_instance)]: - result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line)) - if result is not None: - mbmsRequestMsg += 1 - enb_log_file.close() - logging.debug(' File analysis completed') - self.htmleNBFailureMsg = '' - if self.air_interface == 'lte': - nodeB_prefix = 'e' - else: - nodeB_prefix = 'g' - if uciStatMsgCount > 0: - statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if pdcpFailure > 0: - statMsg = nodeB_prefix + 'NB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if ulschFailure > 0: - statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if dropNotEnoughRBs > 0: - statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' - if rrcSetupComplete > 0: - rrcMsg = nodeB_prefix + 'NB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcSetupComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReleaseRequest > 0: - rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: - rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: - rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if self.eNBmbmsEnables[int(self.eNB_instance)]: - if mbmsRequestMsg > 0: - rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_inNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if X2HO_outNbProcedures > 0: - rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) - if res1 is not None: - if cdrxActivationMessageCount > 0: - rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' - logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - else: - rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' - logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' - if rachCanceledProcedure > 0: - rachMsg = nodeB_prefix + 'NB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' - logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rachMsg + '\n' - if isRRU: - if isSlave: - if slaveReceivesFrameResyncCmd: - rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - else: - rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' - logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' - self.prematureExit = True - return ENB_PROCESS_SLAVE_RRU_NOT_SYNCED - if foundSegFault: - logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m') - return ENB_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m') - self.htmleNBFailureMsg += msgAssertion - return ENB_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') - self.htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE - if rlcDiscardBuffer > 0: - rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' - logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rlcMsg + '\n' - return ENB_PROCESS_REALTIME_ISSUE - return 0 +# def AnalyzeLogFile_eNB(self, eNBlogFile): +# ... def AnalyzeLogFile_UE(self, UElogFile): if (not os.path.isfile('./' + UElogFile)): @@ -3183,7 +2477,7 @@ class OaiCiTest(): result = re.search('No cell synchronization found, abandoning', str(line)) if result is not None: no_cell_sync_found = True - if self.eNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnables[0]: result = re.search('TRIED TO PUSH MBMS DATA', str(line)) if result is not None: mbms_messages += 1 @@ -3309,7 +2603,7 @@ class OaiCiTest(): statMsg = 'UE showed ' + str(fatalErrorCount) + ' "MAC BSR Triggered ReTxBSR Timer expiry" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') self.htmlUEFailureMsg += statMsg + '\n' - if self.eNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnables[0]: if mbms_messages > 0: statMsg = 'UE showed ' + str(mbms_messages) + ' "TRIED TO PUSH MBMS DATA" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') @@ -3320,130 +2614,34 @@ class OaiCiTest(): if foundSegFault: logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') if not nrUEFlag: - return OAI_UE_PROCESS_SEG_FAULT + return CONST.OAI_UE_PROCESS_SEG_FAULT else: if not frequency_found: - return OAI_UE_PROCESS_SEG_FAULT + return CONST.OAI_UE_PROCESS_SEG_FAULT if foundAssertion: logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') self.htmlUEFailureMsg += 'UE showed an assertion!\n' if not nrUEFlag: if not mib_found or not frequency_found: - return OAI_UE_PROCESS_ASSERTION + return CONST.OAI_UE_PROCESS_ASSERTION else: if not frequency_found: - return OAI_UE_PROCESS_ASSERTION + return CONST.OAI_UE_PROCESS_ASSERTION if foundRealTimeIssue: logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') self.htmlUEFailureMsg += 'UE faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE + #return CONST.ENB_PROCESS_REALTIME_ISSUE if nrUEFlag: if not frequency_found: - return OAI_UE_PROCESS_COULD_NOT_SYNC + return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC else: if no_cell_sync_found and not mib_found: logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') self.htmlUEFailureMsg += 'UE could not synchronize!\n' - return OAI_UE_PROCESS_COULD_NOT_SYNC + return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC return 0 - def TerminateeNB(self): - if self.eNB_serverId == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) - if self.air_interface == 'lte': - nodeB_prefix = 'e' - else: - nodeB_prefix = 'g' - SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('-softmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + lPassWord + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) - SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5) - time.sleep(10) - SSH.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('-softmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5) - time.sleep(5) - SSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - SSH.close() - # If tracer options is on, stopping tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - time.sleep(1) - if EPC.EPC_PcapFileName != '': - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.EPC_PcapFileName , '\$', 5) - SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.EPC_PcapFileName , '.') - SSH.copyout(lIpAddr, lUserName, lPassWord, EPC.EPC_PcapFileName , lSourcePath + '/cmake_targets/.') - SSH.close() - logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') - SSH.open(lIpAddr, lUserName, lPassWord) - SSH.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) - enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] - raw_record_file = enbLogFile.replace('.log', '_record.raw') - replay_log_file = enbLogFile.replace('.log', '_replay.log') - extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') - extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') - SSH.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) - SSH.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) - SSH.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) - SSH.close() - SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') - logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.eNBLogFiles[int(self.eNB_instance)] = '' - else: - analyzeFile = False - if self.eNBLogFiles[int(self.eNB_instance)] != '': - analyzeFile = True - fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] - self.eNBLogFiles[int(self.eNB_instance)] = '' - if analyzeFile: - copyin_res = SSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') - self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - return - if self.eNB_serverId != '0': - SSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') - logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) - logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) - if (logStatus < 0): - self.CreateHtmlTestRow('N/A', 'KO', logStatus) - self.preamtureExit = True - self.eNBmbmsEnables[int(self.eNB_instance)] = False - return - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - self.eNBstatuses[int(self.eNB_instance)] = -1 - + def TerminateFlexranCtrl(self): if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: return @@ -3457,7 +2655,7 @@ class OaiCiTest(): time.sleep(1) SSH.close() self.flexranCtrlStarted = False - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateUE_common(self, device_id, idx): try: @@ -3488,19 +2686,19 @@ class OaiCiTest(): os.kill(os.getppid(),signal.SIGUSR1) def TerminateUE(self): - terminate_ue_flag = True + terminate_ue_flag = False self.GetAllUEDevices(terminate_ue_flag) multi_jobs = [] i = 0 for device_id in self.UEDevices: - p = Process(target= CiTestObj.TerminateUE_common, args = (device_id,i,)) + p = Process(target= self.TerminateUE_common, args = (device_id,i,)) p.daemon = True p.start() multi_jobs.append(p) i += 1 for job in multi_jobs: job.join() - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateOAIUE(self): SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) @@ -3523,7 +2721,7 @@ class OaiCiTest(): if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') self.UELogFile = '' return logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') @@ -3536,52 +2734,56 @@ class OaiCiTest(): if (logStatus < 0): logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') - if self.air_interface == 'lte': + HTML.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') + if RAN.Getair_interface() == 'lte': # In case of sniffing on commercial eNBs we have random results # Not an error then - if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): + if (logStatus != CONST.OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): self.Initialize_OAI_UE_args = '' self.AutoTerminateUEandeNB() else: - if (logStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + if (logStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC): self.Initialize_OAI_UE_args = '' self.AutoTerminateUEandeNB() else: logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.UELogFile = '' else: - self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def AutoTerminateUEandeNB(self): if (self.ADBIPAddress != 'none'): self.testCase_id = 'AUTO-KILL-UE' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' self.ShowTestID() self.TerminateUE() if (self.Initialize_OAI_UE_args != ''): self.testCase_id = 'AUTO-KILL-UE' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' self.ShowTestID() self.TerminateOAIUE() - if (self.Initialize_eNB_args != ''): + if (RAN.GetInitialize_eNB_args() != ''): self.testCase_id = 'AUTO-KILL-eNB' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of eNB' self.ShowTestID() - self.eNB_instance = '0' - self.TerminateeNB() + RAN.SeteNB_instance('0') + RAN.TerminateeNB() if self.flexranCtrlInstalled and self.flexranCtrlStarted: self.testCase_id = 'AUTO-KILL-flexran-ctl' + RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of FlexRan CTL' self.ShowTestID() self.TerminateFlexranCtrl() - self.prematureExit = True + RAN.SetprematureExit(True) def IdleSleep(self): time.sleep(self.idle_sleep_time) - self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', CONST.ALL_PROCESSES_OK) def X2_Status(self, idx, fileName): cmd = "curl --silent http://" + EPC.GetIPAddress() + ":9999/stats | jq '.' > " + fileName @@ -3683,22 +2885,22 @@ class OaiCiTest(): logging.debug(msg) fullMessage += msg + '' html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) else: msg = "X2 Handover FAILED" logging.error(msg) fullMessage += msg + '' html_queue.put(fullMessage) - self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) + HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) else: - self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK) + HTML.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', CONST.ALL_PROCESSES_OK) def LogCollectBuild(self): - if (self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != ''): - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword - SourceCodePath = self.eNBSourceCodePath + if (RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != ''): + IPAddress = RAN.GeteNBIPAddress() + UserName = RAN.GeteNBUserName() + Password = RAN.GeteNBPassword() + SourceCodePath = RAN.GeteNBSourceCodePath() elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): IPAddress = self.UEIPAddress UserName = self.UEUserName @@ -3712,16 +2914,6 @@ class OaiCiTest(): SSH.command('rm -f build.log.zip', '\$', 5) SSH.command('zip build.log.zip build_log_*/*', '\$', 60) SSH.close() - - def LogCollecteNB(self): - SSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - SSH.command('cd ' + self.eNBSourceCodePath, '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - SSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 60) - SSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) - SSH.close() - def LogCollectPing(self): SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) @@ -3750,7 +2942,7 @@ class OaiCiTest(): SSH.close() def RetrieveSystemVersion(self, machine): - if self.eNBIPAddress == 'none' or self.UEIPAddress == 'none': + if RAN.GeteNBIPAddress() == 'none' or self.UEIPAddress == 'none': self.OsVersion = 'Ubuntu 16.04.5 LTS' self.KernelVersion = '4.15.0-45-generic' self.UhdVersion = '3.13.0.1-0' @@ -3760,10 +2952,10 @@ class OaiCiTest(): self.CpuMHz = '2399.996 MHz' return 0 if machine == 'eNB': - if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword + if RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != '': + IPAddress = RAN.GeteNBIPAddress() + UserName = RAN.GeteNBUserName() + Password = RAN.GeteNBPassword() else: return -1 if machine == 'UE': @@ -3829,335 +3021,6 @@ class OaiCiTest(): logging.debug('cpu_mhz: ' + self.CpuMHz) SSH.close() -#----------------------------------------------------------- -# HTML Reporting.... -#----------------------------------------------------------- - def CreateHtmlHeader(self): - if (not self.htmlHeaderCreated): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML header \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - self.htmlFile = open('test_results.html', 'w') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write('\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Test Results for TEMPLATE_JOB_NAME job build #TEMPLATE_BUILD_ID\n') - self.htmlFile.write('\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('
TEMPLATE_STAGE_NAME
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if self.ranAllowMerge != '': - commit_message = subprocess.check_output("git log -n1 --pretty=format:\"%s\" " + self.ranCommitID, shell=True, universal_newlines=True) - commit_message = commit_message.strip() - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranAllowMerge): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.ranTargetBranch == ''): - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Build Start Time (UTC) TEMPLATE_BUILD_TIME
GIT Repository ' + self.ranRepository + '
Job Trigger Merge-RequestPush to Branch
Source Branch Branch' + self.ranBranch + '
Source Commit ID Commit ID ' + self.ranCommitID + '
Source Commit Message Commit Message ' + commit_message + '
Target Branch develop' + self.ranTargetBranch + '
\n') - - if (self.ADBIPAddress != 'none'): - terminate_ue_flag = True - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' UE(s) is(are) connected to ADB bench server

\n') - self.htmlFile.write('

' + str(len(self.CatMDevices)) + ' CAT-M UE(s) is(are) connected to bench server

\n') - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - self.htmlFile.write('

' + str(len(self.UEDevices)) + ' OAI UE(s) is(are) connected to CI bench

\n') - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write('
\n') - self.htmlFile.close() - - def CreateHtmlTabHeader(self): - if (not self.htmlHeaderCreated): - if (not os.path.isfile('test_results.html')): - self.CreateHtmlHeader() - self.htmlFile = open('test_results.html', 'a') - if (self.nbTestXMLfiles == 1): - self.htmlFile.write('
\n') - self.htmlFile.write('

Test Summary for ' + self.testXMLfiles[0] + '

\n') - else: - self.htmlFile.write('
\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if (self.htmlUEConnected == -1): - terminate_ue_flag = True - if (self.ADBIPAddress != 'none'): - self.GetAllUEDevices(terminate_ue_flag) - self.GetAllCatMDevices(terminate_ue_flag) - else: - self.UEDevices.append('OAI-UE') - self.htmlUEConnected = len(self.UEDevices) - - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' \n') - i += 1 - self.htmlFile.write(' \n') - self.htmlHeaderCreated = True - - def CreateHtmlTabFooter(self, passStatus): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
Relative Time (ms)Test IdTest DescTest OptionsTest StatusUE' + str(i) + ' Status
Final Tab StatusPASS FAIL
\n') - self.htmlFile.write('
\n') - self.htmlFile.close() - time.sleep(1) - if passStatus: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" - subprocess.run(cmd, shell=True) - else: - cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__/<\/span>/' test_results.html" - subprocess.run(cmd, shell=True) - self.htmlFooterCreated = False - - def CreateHtmlFooter(self, passStatus): - if (os.path.isfile('test_results.html')): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1m Creating HTML footer \u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - - self.htmlFile = open('test_results.html', 'a') - self.htmlFile.write('
\n') - self.htmlFile.write('

\n') - self.htmlFile.write(' \n') - - machines = [ 'eNB', 'UE' ] - for machine in machines: - res = self.RetrieveSystemVersion(machine) - if res == -1: - continue - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - if passStatus: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write('
' + str(machine) + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '
Final StatusPASS FAIL
\n') - self.htmlFile.write('

\n') - self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') - self.htmlFile.write('
\n') - self.htmlFile.write('\n') - self.htmlFile.close() - - def CreateHtmlRetrySeparator(self): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - self.htmlFile.write(' \n') - self.htmlFile.write(' Try Run #' + str(self.FailReportCnt) + '\n') - self.htmlFile.write(' \n') - - def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - if (processesStatus == 0): - self.htmlFile.write(' ' + str(status) + '\n') - elif (processesStatus == ENB_PROCESS_FAILED): - self.htmlFile.write(' KO - eNB process not found\n') - elif (processesStatus == OAI_UE_PROCESS_FAILED): - self.htmlFile.write(' KO - OAI UE process not found\n') - elif (processesStatus == ENB_PROCESS_SEG_FAULT) or (processesStatus == OAI_UE_PROCESS_SEG_FAULT): - self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault\n') - elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): - self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion\n') - elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): - self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s)\n') - elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): - self.htmlFile.write(' OK?\n') - elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): - self.htmlFile.write(' KO - ' + machine + ' Slave RRU could not synch\n') - elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): - self.htmlFile.write(' KO - UE could not sync\n') - elif (processesStatus == HSS_PROCESS_FAILED): - self.htmlFile.write(' KO - HSS process not found\n') - elif (processesStatus == MME_PROCESS_FAILED): - self.htmlFile.write(' KO - MME process not found\n') - elif (processesStatus == SPGW_PROCESS_FAILED): - self.htmlFile.write(' KO - SPGW process not found\n') - elif (processesStatus == UE_IP_ADDRESS_ISSUE): - self.htmlFile.write(' KO - Could not retrieve UE IP address\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - else: - self.htmlFile.write(' ' + str(status) + '\n') - if (len(str(self.htmleNBFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Reestablishment|Could not copy eNB logfile', self.htmleNBFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmleNBFailureMsg + '
\n') - self.htmleNBFailureMsg = '' - elif (len(str(self.htmlUEFailureMsg)) > 2): - cellBgColor = 'white' - result = re.search('ended with|faced real time issues', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'red' - else: - result = re.search('showed|Could not copy UE logfile|oaitun_ue1 interface is either NOT mounted or NOT configured', self.htmlUEFailureMsg) - if result is not None: - cellBgColor = 'orange' - self.htmlFile.write('
' + self.htmlUEFailureMsg + '
\n') - self.htmlUEFailureMsg = '' - else: - i = 0 - while (i < self.htmlUEConnected): - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - - def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): - if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): - currentTime = int(round(time.time() * 1000)) - self.startTime - addOrangeBK = False - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + format(currentTime / 1000, '.1f') + '\n') - self.htmlFile.write(' ' + self.testCase_id + '\n') - self.htmlFile.write(' ' + self.desc + '\n') - self.htmlFile.write(' ' + str(options) + '\n') - if (str(status) == 'OK'): - self.htmlFile.write(' ' + str(status) + '\n') - elif (str(status) == 'KO'): - self.htmlFile.write(' ' + str(status) + '\n') - else: - addOrangeBK = True - self.htmlFile.write(' ' + str(status) + '\n') - i = 0 - while (i < self.htmlUEConnected): - if (i < ue_status): - if (not ue_queue.empty()): - if (addOrangeBK): - self.htmlFile.write(' ' + str(ue_queue.get()).replace('white', 'orange') + '\n') - else: - self.htmlFile.write(' ' + str(ue_queue.get()) + '\n') - else: - self.htmlFile.write(' -\n') - else: - self.htmlFile.write(' -\n') - i += 1 - self.htmlFile.write(' \n') - #----------------------------------------------------------- # ShowTestID() #----------------------------------------------------------- @@ -4175,47 +3038,47 @@ def CheckClassValidity(action,id): def GetParametersFromXML(action): if action == 'Build_eNB': - CiTestObj.Build_eNB_args = test.findtext('Build_eNB_args') + RAN.SetBuild_eNB_args(test.findtext('Build_eNB_args')) forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') if (forced_workspace_cleanup is None): - CiTestObj.Build_eNB_forced_workspace_cleanup = False + RAN.SetBuild_eNB_forced_workspace_cleanup(False) else: if re.match('true', forced_workspace_cleanup, re.IGNORECASE): - CiTestObj.Build_eNB_forced_workspace_cleanup = True + RAN.SetBuild_eNB_forced_workspace_cleanup(True) else: - CiTestObj.Build_eNB_forced_workspace_cleanup = False - CiTestObj.eNB_instance = test.findtext('eNB_instance') - if (CiTestObj.eNB_instance is None): - CiTestObj.eNB_instance = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SetBuild_eNB_forced_workspace_cleanup(False) + RAN.SeteNB_instance(test.findtext('eNB_instance')) + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') xmlBgBuildField = test.findtext('backgroundBuild') if (xmlBgBuildField is None): - CiTestObj.backgroundBuild = False + RAN.SetbackgroundBuild(False) else: if re.match('true', xmlBgBuildField, re.IGNORECASE): - CiTestObj.backgroundBuild = True + RAN.SetbackgroundBuild(True) else: - CiTestObj.backgroundBuild = False + RAN.SetbackgroundBuild(False) if action == 'WaitEndBuild_eNB': - CiTestObj.Build_eNB_args = test.findtext('Build_eNB_args') - CiTestObj.eNB_instance = test.findtext('eNB_instance') - if (CiTestObj.eNB_instance is None): - CiTestObj.eNB_instance = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SetBuild_eNB_args(test.findtext('Build_eNB_args')) + RAN.SeteNB_instance(test.findtext('eNB_instance')) + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') if action == 'Initialize_eNB': - CiTestObj.Initialize_eNB_args = test.findtext('Initialize_eNB_args') - CiTestObj.eNB_instance = test.findtext('eNB_instance') - if (CiTestObj.eNB_instance is None): - CiTestObj.eNB_instance = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SetInitialize_eNB_args(test.findtext('Initialize_eNB_args')) + RAN.SeteNB_instance(test.findtext('eNB_instance')) + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') CiTestObj.air_interface = test.findtext('air_interface') if (CiTestObj.air_interface is None): CiTestObj.air_interface = 'lte' @@ -4223,12 +3086,12 @@ def GetParametersFromXML(action): CiTestObj.air_interface = CiTestObj.air_interface.lower() if action == 'Terminate_eNB': - CiTestObj.eNB_instance = test.findtext('eNB_instance') - if (CiTestObj.eNB_instance is None): - CiTestObj.eNB_instance = '0' - CiTestObj.eNB_serverId = test.findtext('eNB_serverId') - if (CiTestObj.eNB_serverId is None): - CiTestObj.eNB_serverId = '0' + RAN.SeteNB_instance(test.findtext('eNB_instance')) + if (RAN.GeteNB_instance() is None): + RAN.SeteNB_instance('0') + RAN.SeteNB_serverId(test.findtext('eNB_serverId')) + if (RAN.GeteNB_serverId() is None): + RAN.SeteNB_serverId('0') CiTestObj.air_interface = test.findtext('air_interface') if (CiTestObj.air_interface is None): CiTestObj.air_interface = 'lte' @@ -4269,7 +3132,7 @@ def GetParametersFromXML(action): CiTestObj.air_interface = SSH.air_interface.lower() if action == 'Terminate_OAI_UE': - CiTestObj.eNB_instance = test.findtext('UE_instance') + RAN.SeteNB_instance(test.findtext('UE_instance')) if (CiTestObj.UE_instance is None): CiTestObj.UE_instance = '0' @@ -4332,13 +3195,18 @@ def receive_signal(signum, frame): mode = '' CiTestObj = OaiCiTest() -from sshconnection import * -from epc import * -from helpreadme import * -SSH = SSHConnection() -EPC = EPCManagement() -#HELP = HelpReadme() -#HELP.GenericHelp() +import sshconnection +import epc +import helpreadme +import ran +import html +import constants + +SSH = sshconnection.SSHConnection() +EPC = epc.EPCManagement() +RAN = ran.RANManagement() +HTML = html.HTMLManagement() + argvs = sys.argv argc = len(argvs) @@ -4346,6 +3214,7 @@ cwd = os.getcwd() while len(argvs) > 1: myArgv = argvs.pop(1) # 0th is this file's name + if re.match('^\-\-help$', myArgv, re.IGNORECASE): GenericHelp(Version) sys.exit(0) @@ -4357,7 +3226,8 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.ranRepository = matchReg.group(1) + RAN.SetranRepository(matchReg.group(1)) + HTML.SetranRepository(matchReg.group(1)) elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) @@ -4365,68 +3235,72 @@ while len(argvs) > 1: matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) doMerge = matchReg.group(1) if ((doMerge == 'true') or (doMerge == 'True')): - CiTestObj.ranAllowMerge = True + RAN.SetranAllowMerge(True) + HTML.SetranAllowMerge(True) elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.ranBranch = matchReg.group(1) + RAN.SetranBranch(matchReg.group(1)) + HTML.SetranBranch(matchReg.group(1)) elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) - CiTestObj.ranCommitID = matchReg.group(1) + RAN.SetranCommitID(matchReg.group(1)) + HTML.SetranCommitID(matchReg.group(1)) elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) - CiTestObj.ranTargetBranch = matchReg.group(1) + RAN.SetranTargetBranch(matchReg.group(1)) elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNBIPAddress = matchReg.group(1) + RAN.SeteNBIPAddress(matchReg.group(1)) elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB1IPAddress = matchReg.group(1) + RAN.SeteNB1IPAddress(matchReg.group(1)) elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB2IPAddress = matchReg.group(1) + RAN.SeteNB2IPAddress(matchReg.group(1)) elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNBUserName = matchReg.group(1) + RAN.SeteNBUserName(matchReg.group(1)) elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB1UserName = matchReg.group(1) + RAN.SeteNB1UserName(matchReg.group(1)) elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB2UserName = matchReg.group(1) + RAN.SeteNB2UserName(matchReg.group(1)) elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNBPassword = matchReg.group(1) + RAN.SeteNBPassword(matchReg.group(1)) elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB1Password = matchReg.group(1) + RAN.SeteNB1Password(matchReg.group(1)) elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB2Password = matchReg.group(1) + RAN.SeteNB2Password(matchReg.group(1)) elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNBSourceCodePath = matchReg.group(1) + RAN.SeteNBSourceCodePath(matchReg.group(1)) elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB1SourceCodePath = matchReg.group(1) + RAN.SeteNB1SourceCodePath(matchReg.group(1)) elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.eNB2SourceCodePath = matchReg.group(1) + RAN.SeteNB2SourceCodePath(matchReg.group(1)) elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) EPC.SetIPAddress(matchReg.group(1)) +#GP250220: do we still need EPCBranch? it's not used anywhere elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) CiTestObj.EPCBranch = matchReg.group(1) @@ -4466,7 +3340,8 @@ while len(argvs) > 1: elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) CiTestObj.testXMLfiles.append(matchReg.group(1)) - CiTestObj.nbTestXMLfiles += 1 + HTML.SettestXMLfiles(matchReg.group(1)) + HTML.SetnbTestXMLfiles(HTML.GetnbTestXMLfiles()+1) elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) CiTestObj.UEIPAddress = matchReg.group(1) @@ -4489,12 +3364,12 @@ while len(argvs) > 1: sys.exit('Invalid Parameter: ' + myArgv) if re.match('^TerminateeNB$', mode, re.IGNORECASE): - if CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '': + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - CiTestObj.eNB_serverId = '0' - CiTestObj.eNB_instance = '0' - CiTestObj.eNBSourceCodePath = '/tmp/' + RAN.SeteNB_serverId('0') + RAN.SeteNB_instance('0') + RAN.SeteNBSourceCodePath('/tmp/') CiTestObj.TerminateeNB() elif re.match('^TerminateUE$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): @@ -4524,12 +3399,12 @@ elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): sys.exit('Insufficient Parameter') CiTestObj.TerminateSPGW() elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): - if (CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): + if (RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectBuild() elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): - if CiTestObj.eNBIPAddress == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '': + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollecteNB() @@ -4569,7 +3444,7 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): sys.exit('Insufficient Parameter') count = 0 foundCount = 0 - while (count < CiTestObj.nbTestXMLfiles): + while (count < HTML.GetnbTestXMLfiles()): #xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[count] xml_test_file = sys.path[0] + "/" + CiTestObj.testXMLfiles[count] if (os.path.isfile(xml_test_file)): @@ -4578,36 +3453,52 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): except: print("Error while parsing file: " + xml_test_file) xmlRoot = xmlTree.getroot() - CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + HTML.SethtmlTabIcons(xmlRoot.findtext('htmlTabIcon',default='info-sign')) + #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) + #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) + #CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) foundCount += 1 count += 1 - if foundCount != CiTestObj.nbTestXMLfiles: - CiTestObj.nbTestXMLfiles = foundCount - CiTestObj.CreateHtmlHeader() + if foundCount != HTML.GetnbTestXMLfiles(): + HTML.SetnbTestXMLfiles(foundcount) + + if (CiTestObj.ADBIPAddress != 'none'): + terminate_ue_flag = False + CiTestObj.GetAllUEDevices(terminate_ue_flag) + CiTestObj.GetAllCatMDevices(terminate_ue_flag) + HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices)) + HTML.SethtmlNb_Smartphones(len(CiTestObj.UEDevices)) + HTML.SethtmlNb_CATM_Modules(len(CiTestObj.CatMDevices)) + HTML.CreateHtmlHeader(CiTestObj.ADBIPAddress) elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - CiTestObj.CreateHtmlFooter(CiTestObj.finalStatus) + HTML.SetreseNB(RetrieveSystemVersion('eNB')) + HTML.SetresUE(RetrieveSystemVersion('UE')) + HTML.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): - if CiTestObj.eNBIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.eNBUserName == '' or CiTestObj.eNBPassword == '' or CiTestObj.eNBSourceCodePath == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': + if RAN.GeteNBIPAddress() == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': GenericHelp(Version) if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or EPC.GetType() == '': EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) - # Gabriele: other if conditions relevant to eNB etc. to be added + if RAN.GetranRepository() == '': + GitSrvHelp(RAN.GetranRepository(),RAN.GetranBranch(),RAN.GetranCommitID(),RAN.GetranAllowMerge(),RAN.GetranTargetBranch()) + if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': + eNBSrvHelp(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath()) sys.exit('Insufficient Parameter') if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/tcp_iperf_stats.awk", "/tmp") SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/active_net_interfaces.awk", "/tmp") else: - if CiTestObj.UEIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': + if CiTestObj.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': GenericHelp(Version) sys.exit('UE: Insufficient Parameter') #read test_case_list.xml file # if no parameters for XML file, use default value - if (CiTestObj.nbTestXMLfiles != 1): + if (HTML.GetnbTestXMLfiles() != 1): xml_test_file = cwd + "/test_case_list.xml" else: xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0] @@ -4617,9 +3508,11 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') - if (CiTestObj.nbTestXMLfiles == 1): - CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) + if (HTML.GetnbTestXMLfiles() == 1): + HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabName',default='Test-0')) + #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) + #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) repeatCount = xmlRoot.findtext('repeatCount',default='1') CiTestObj.repeatCounts.append(int(repeatCount)) all_tests=xmlRoot.findall('testCase') @@ -4661,26 +3554,38 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re signal.signal(signal.SIGUSR1, receive_signal) - CiTestObj.CreateHtmlTabHeader() + if (CiTestObj.ADBIPAddress != 'none'): + terminate_ue_flag = False + CiTestObj.GetAllUEDevices(terminate_ue_flag) + CiTestObj.GetAllCatMDevices(terminate_ue_flag) + else: + CiTestObj.UEDevices.append('OAI-UE') + HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices)) + HTML.CreateHtmlTabHeader() CiTestObj.FailReportCnt = 0 - CiTestObj.prematureExit = True + RAN.SetprematureExit(True) CiTestObj.startTime = int(round(time.time() * 1000)) - while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: - CiTestObj.prematureExit = False + HTML.SetstartTime(CiTestObj.startTime) + while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): + RAN.SetprematureExit(False) # At every iteratin of the retry loop, a separator will be added - CiTestObj.CreateHtmlRetrySeparator() + # pass CiTestObj.FailReportCnt as parameter of HTML.CreateHtmlRetrySeparator + HTML.CreateHtmlRetrySeparator(CiTestObj.FailReportCnt) for test_case_id in todo_tests: - if CiTestObj.prematureExit: + if RAN.GetprematureExit(): break for test in all_tests: - if CiTestObj.prematureExit: + if RAN.GetprematureExit(): break id = test.get('id') if test_case_id != id: continue CiTestObj.testCase_id = id + RAN.SettestCase_id(CiTestObj.testCase_id) + HTML.SettestCase_id(CiTestObj.testCase_id) CiTestObj.desc = test.findtext('desc') + HTML.Setdesc(CiTestObj.desc) action = test.findtext('class') if (CheckClassValidity(action, id) == False): continue @@ -4691,13 +3596,17 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re terminate_ue_flag = False CiTestObj.GetAllUEDevices(terminate_ue_flag) if action == 'Build_eNB': - CiTestObj.BuildeNB() + RAN.BuildeNB() elif action == 'WaitEndBuild_eNB': - CiTestObj.WaitBuildeNBisFinished() + RAN.WaitBuildeNBisFinished() elif action == 'Initialize_eNB': - CiTestObj.InitializeeNB() + check_eNB = False + check_OAI_UE = False + RAN.SetpStatus(CiTestObj.CheckProcessExist(check_eNB, check_OAI_UE)) + + RAN.InitializeeNB() elif action == 'Terminate_eNB': - CiTestObj.TerminateeNB() + RAN.TerminateeNB() elif action == 'Initialize_UE': CiTestObj.InitializeUE() elif action == 'Terminate_UE': @@ -4757,13 +3666,13 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re else: sys.exit('Invalid action') CiTestObj.FailReportCnt += 1 - if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and CiTestObj.prematureExit: + if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)') - CiTestObj.CreateHtmlTabFooter(False) + HTML.CreateHtmlTabFooter(False) sys.exit('Failed Scenario') else: logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') - CiTestObj.CreateHtmlTabFooter(True) + HTML.CreateHtmlTabFooter(True) else: GenericHelp(Version) sys.exit('Invalid mode') diff --git a/ci-scripts/main_enb.py b/ci-scripts/main_enb.py deleted file mode 100644 index 3b3428eec4..0000000000 --- a/ci-scripts/main_enb.py +++ /dev/null @@ -1,3680 +0,0 @@ - -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (the "License"); you may not use this file -# * except in compliance with the License. -# * You may obtain a copy of the License at -# * -# * http://www.openairinterface.org/?page_id=698 -# * -# * Unless required by applicable law or agreed to in writing, software -# * distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# Python for CI of OAI-eNB + COTS-UE -# -# Required Python Version -# Python 3.x -# -# Required Python Package -# pexpect -#--------------------------------------------------------------------- - -import constants as CONST - -#----------------------------------------------------------- -# Version -#----------------------------------------------------------- -Version = '0.1' - -#----------------------------------------------------------- -# Import -#----------------------------------------------------------- -import sys # arg -import re # reg -import pexpect # pexpect -import time # sleep -import os -import subprocess -import xml.etree.ElementTree as ET -import logging -import datetime -import signal -from multiprocessing import Process, Lock, SimpleQueue -logging.basicConfig( - level=logging.DEBUG, - format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s" -) - - -#----------------------------------------------------------- -# Class Declaration -#----------------------------------------------------------- -class OaiCiTest(): - - def __init__(self): - self.FailReportCnt = 0 - self.ADBIPAddress = '' - self.ADBUserName = '' - self.ADBPassword = '' - self.ADBCentralized = True - self.testCase_id = '' - self.testXMLfiles = [] - self.nbTestXMLfiles = 0 - self.desc = '' - self.ping_args = '' - self.ping_packetloss_threshold = '' - self.iperf_args = '' - self.iperf_packetloss_threshold = '' - self.iperf_profile = '' - self.iperf_options = '' - self.nbMaxUEtoAttach = -1 - self.UEDevices = [] - self.UEDevicesStatus = [] - self.UEDevicesRemoteServer = [] - self.UEDevicesRemoteUser = [] - self.UEDevicesOffCmd = [] - self.UEDevicesOnCmd = [] - self.UEDevicesRebootCmd = [] - self.CatMDevices = [] - self.UEIPAddresses = [] - self.htmlFile = '' - # self.htmlHeaderCreated = False - # self.htmlFooterCreated = False - self.htmlUEConnected = -1 - self.htmleNBFailureMsg = '' - self.htmlUEFailureMsg = '' - self.picocom_closure = False - self.idle_sleep_time = 0 - self.x2_ho_options = 'network' - self.x2NbENBs = 0 - self.x2ENBBsIds = [] - self.x2ENBConnectedUEs = [] - self.repeatCounts = [] - self.finalStatus = False - self.OsVersion = '' - self.KernelVersion = '' - self.UhdVersion = '' - self.UsrpBoard = '' - self.CpuNb = '' - self.CpuModel = '' - self.CpuMHz = '' - self.UEIPAddress = '' - self.UEUserName = '' - self.UEPassword = '' - self.UE_instance = '' - self.UESourceCodePath = '' - self.UELogFile = '' - self.Build_OAI_UE_args = '' - self.Initialize_OAI_UE_args = '' - self.clean_repository = True - self.flexranCtrlInstalled = False - self.flexranCtrlStarted = False - self.expectedNbOfConnectedUEs = 0 - self.startTime = 0 - - - def BuildOAIUE(self): - if self.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - result = re.search('--nrUE', self.Build_OAI_UE_args) - if result is not None: - RAN.Setair_interface('nr') - ue_prefix = 'NR ' - else: - RAN.Setair_interface('lte') - ue_prefix = '' - result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', RAN.GetranRepository()) - if result is not None: - full_ran_repo_name = RAN.GetranRepository() - else: - full_ran_repo_name = RAN.GetranRepository() + '.git' - SSH.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) - SSH.command('cd ' + self.UESourceCodePath, '\$', 5) - SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) - # here add a check if git clone or git fetch went smoothly - SSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) - SSH.command('git config user.name "OAI Jenkins"', '\$', 5) - if self.clean_repository: - SSH.command('ls *.txt', '\$', 5) - result = re.search('LAST_BUILD_INFO', SSH.getBefore()) - if result is not None: - mismatch = False - SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(RAN.GetranCommitID(), SSH.getBefore()) - if result is None: - mismatch = True - SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge()): - result = re.search('YES', SSH.getBefore()) - if result is None: - mismatch = True - SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if RAN.GetranTargetBranch() == '': - result = re.search('develop', SSH.getBefore()) - else: - result = re.search(RAN.GetranTargetBranch(), SSH.getBefore()) - if result is None: - mismatch = True - else: - result = re.search('NO', SSH.getBefore()) - if result is None: - mismatch = True - if not mismatch: - SSH.close() - HTML.CreateHtmlTestRow(RAN.GetBuild_eNB_args(), 'OK', CONST.ALL_PROCESSES_OK) - return - - SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) - - # if the commit ID is provided use it to point to it - if RAN.GetranCommitID() != '': - SSH.command('git checkout -f ' + RAN.GetranCommitID(), '\$', 5) - # if the branch is not develop, then it is a merge request and we need to do - # the potential merge. Note that merge conflicts should already been checked earlier - if (RAN.GetranAllowMerge()): - if RAN.GetranTargetBranch() == '': - if (RAN.GetranBranch() != 'develop') and (RAN.GetranBranch() != 'origin/develop'): - SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) - else: - logging.debug('Merging with the target branch: ' + RAN.GetranTargetBranch()) - SSH.command('git merge --ff origin/' + RAN.GetranTargetBranch() + ' -m "Temporary merge for CI"', '\$', 5) - SSH.command('source oaienv', '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('mkdir -p log', '\$', 5) - SSH.command('chmod 777 log', '\$', 5) - # no need to remove in log (git clean did the trick) - SSH.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests|build have failed', 600) - SSH.command('ls ran_build/build', '\$', 3) - SSH.command('ls ran_build/build', '\$', 3) - buildStatus = True - result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) - if result is None: - buildStatus = False - SSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) - SSH.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) - SSH.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) - if buildStatus: - # Generating a BUILD INFO file - SSH.command('echo "SRC_BRANCH: ' + RAN.GetranBranch() + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('echo "SRC_COMMIT: ' + RAN.GetranCommitID() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge()): - SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if RAN.GetranTargetBranch() == '': - SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - SSH.command('echo "TGT_BRANCH: ' + RAN.GetranTargetBranch() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - else: - SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.close() - HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'OK', CONST.ALL_PROCESSES_OK, 'OAI UE') - else: - SSH.close() - logging.error('\u001B[1m Building OAI UE Failed\u001B[0m') - HTML.CreateHtmlTestRow(self.Build_OAI_UE_args, 'KO', CONST.ALL_PROCESSES_OK, 'OAI UE') - HTML.CreateHtmlTabFooter(False) - sys.exit(1) - - def CheckFlexranCtrlInstallation(self): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': - return - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) - result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) - if result is not None: - self.flexranCtrlInstalled = True - RAN.SetflexranCtrlInstalled(True) - logging.debug('Flexran Controller is installed') - SSH.close() - - def InitializeFlexranCtrl(self): - if self.flexranCtrlInstalled == False: - return - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd /opt/flexran_rtc', '\$', 5) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f log/*.log', '\$', 5) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S echo "build/rt_controller -c log_config/basic_log" > ./my-flexran-ctl.sh', '\$', 5) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 755 ./my-flexran-ctl.sh', '\$', 5) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --unsafe --name=flexran_rtc_daemon --chdir=/opt/flexran_rtc -o /opt/flexran_rtc/log/flexranctl_' + self.testCase_id + '.log ././my-flexran-ctl.sh', '\$', 5) - SSH.command('ps -aux | grep --color=never rt_controller', '\$', 5) - result = re.search('rt_controller -c ', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') - self.flexranCtrlStarted = True - RAN.SetflexranCtrlStarted(True) - SSH.close() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def InitializeUE_common(self, device_id, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if not self.ADBCentralized: - # Reboot UE - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesRebootCmd[idx], '\$', 60) - # Wait - #time.sleep(60) - # Put in LTE-Mode only - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode 11"\'', '\$', 60) - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode1 11"\'', '\$', 60) - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode2 11"\'', '\$', 60) - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "settings put global preferred_network_mode3 11"\'', '\$', 60) - # enable data service - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - # we need to do radio on/off cycle to make sure of above changes - # airplane mode off // radio on - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - #time.sleep(10) - # airplane mode on // radio off - #SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - - # normal procedure without reboot - # enable data service - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - # airplane mode on // radio off - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - SSH.close() - return - # enable data service - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) - - # The following commands are deprecated since we no longer work on Android 7+ - # SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell settings put global airplane_mode_on 1', '\$', 10) - # SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60) - # a dedicated script has to be installed inside the UE - # airplane mode on means call /data/local/tmp/off - if device_id == '84B7N16418004022': - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - #airplane mode off means call /data/local/tmp/on - logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m') - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def InitializeUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.InitializeUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def InitializeOAIUE(self): - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - if RAN.Getair_interface() == 'lte': - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) - HTML.CreateHtmlTabFooter(False) - sys.exit(1) - UE_prefix = '' - else: - UE_prefix = 'NR ' - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - # b2xx_fx3_utils reset procedure - SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 60) - result = re.search('type: b200', SSH.getBefore()) - if result is not None: - logging.debug('Found a B2xx device --> resetting it') - SSH.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) - # Reloading FGPA bin firmware - SSH.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 30) - result = re.search('type: n3xx', SSH.getBefore()) - if result is not None: - logging.debug('Found a N3xx device --> resetting it') - SSH.command('cd ' + self.UESourceCodePath, '\$', 5) - # Initialize_OAI_UE_args usually start with -C and followed by the location in repository - SSH.command('source oaienv', '\$', 5) - SSH.command('cd cmake_targets/ran_build/build', '\$', 5) - if RAN.Getair_interface() == 'lte': - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - # We may have to regenerate the .u* files - if result is None: - SSH.command('ls /tmp/*.sed', '\$', 5) - result = re.search('adapt_usim_parameters', SSH.getBefore()) - if result is not None: - SSH.command('sed -f /tmp/adapt_usim_parameters.sed ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - else: - SSH.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) - SSH.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - SSH.command('echo "ulimit -c unlimited && ./'+ RAN.Getair_interface() +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - SSH.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) - self.UELogFile = 'ue_' + self.testCase_id + '.log' - - # We are now looping several times to hope we really sync w/ an eNB - doOutterLoop = True - outterLoopCounter = 5 - gotSyncStatus = True - fullSyncStatus = True - while (doOutterLoop): - SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/ran_build/build', '\$', 5) - SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) - #use nohup instead of daemon - #SSH.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/ran_build/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - SSH.command('echo $USER; nohup sudo ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh' + ' > ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ' + ' 2>&1 &', self.UEUserName, 5) - time.sleep(6) - SSH.command('cd ../..', '\$', 5) - doLoop = True - loopCounter = 10 - gotSyncStatus = True - # the 'got sync' message is for the UE threads synchronization - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here should never occur - logging.error('"got sync" message never showed!') - gotSyncStatus = False - doLoop = False - continue - SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - if RAN.Getair_interface() == 'nr': - result = re.search('Starting sync detection', SSH.getBefore()) - else: - result = re.search('got sync', SSH.getBefore()) - if result is None: - time.sleep(10) - else: - doLoop = False - logging.debug('Found "got sync" message!') - if gotSyncStatus == False: - # we certainly need to stop the lte-uesoftmodem process if it is still running! - SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('-uesoftmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT -r *-uesoftmodem', '\$', 4) - time.sleep(3) - continue - if RAN.Getair_interface() == 'nr': - fullSyncStatus = True - doOutterLoop = False - else: - # We are now checking if sync w/ eNB DOES NOT OCCUR - # Usually during the cell synchronization stage, the UE returns with No cell synchronization message - doLoop = True - loopCounter = 10 - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here we do have a great chance that the UE did cell-sync w/ eNB - doLoop = False - doOutterLoop = False - fullSyncStatus = True - continue - SSH.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('No cell synchronization found', SSH.getBefore()) - if result is None: - time.sleep(6) - else: - doLoop = False - fullSyncStatus = False - logging.debug('Found: "No cell synchronization" message! --> try again') - time.sleep(6) - SSH.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - outterLoopCounter = outterLoopCounter - 1 - if (outterLoopCounter == 0): - doOutterLoop = False - - if fullSyncStatus and gotSyncStatus and RAN.Getair_interface() == 'lte': - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - SSH.command('ifconfig oaitun_ue1', '\$', 4) - SSH.command('ifconfig oaitun_ue1', '\$', 4) - # ifconfig output is different between ubuntu 16 and ubuntu 18 - result = re.search('inet addr:1|inet 1', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') - tunnelInterfaceStatus = True - else: - logging.debug(SSH.getBefore()) - logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') - tunnelInterfaceStatus = False - if RAN.GeteNBmbmsEnables[0]: - self.command('ifconfig oaitun_uem1', '\$', 4) - result = re.search('inet addr', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_uem1 interface is mounted and configured\u001B[0m') - tunnelInterfaceStatus = tunnelInterfaceStatus and True - else: - logging.error('\u001B[1m oaitun_uem1 interface is either NOT mounted or NOT configured\u001B[0m') - tunnelInterfaceStatus = False - else: - tunnelInterfaceStatus = True - else: - tunnelInterfaceStatus = True - - SSH.close() - if fullSyncStatus and gotSyncStatus and tunnelInterfaceStatus: - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', CONST.ALL_PROCESSES_OK, 'OAI UE') - logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') - if (self.ADBIPAddress != 'none'): - self.UEDevices = [] - self.UEDevices.append('OAI-UE') - self.UEDevicesStatus = [] - self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) - else: - if RAN.Getair_interface() == 'lte': - if RAN.GeteNBmbmsEnables[0]: - self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' - else: - self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') - else: - self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' - HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') - logging.error('\033[91mInitialize OAI UE Failed! \033[0m') - self.AutoTerminateUEandeNB() - - def checkDevTTYisUnlocked(self): - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - count = 0 - while count < 5: - SSH.command('echo ' + self.ADBPassword + ' | sudo -S lsof | grep ttyUSB0', '\$', 10) - result = re.search('picocom', SSH.getBefore()) - if result is None: - count = 10 - else: - time.sleep(5) - count = count + 1 - SSH.close() - - def InitializeCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - self.picocom_closure = True - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - SSH.command('AT', 'OK|ERROR', 5) - SSH.command('AT', 'OK', 5) - # Doing a power cycle - self.command('AT^RESET', 'SIMSTORE,READY', 15) - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - self.command('ATE1', 'OK', 5) - # Disabling the Radio - SSH.command('AT+CFUN=0', 'OK', 5) - logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - # Checking if auto-attach is enabled - SSH.command('AT^AUTOATT?', 'OK', 5) - result = re.search('AUTOATT: (?P[0-9\-]+)', SSH.getBefore()) - if result is not None: - if result.group('state') is not None: - autoAttachState = int(result.group('state')) - if autoAttachState is not None: - if autoAttachState == 0: - SSH.command('AT^AUTOATT=1', 'OK', 5) - logging.debug('\u001B[1m Auto-Attach enabled\u001B[0m') - else: - logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') - # Force closure of picocom but device might still be locked - SSH.close() - self.picocom_closure = False - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - self.checkDevTTYisUnlocked() - - def TerminateCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - self.picocom_closure = True - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - SSH.command('AT', 'OK|ERROR', 5) - SSH.command('AT', 'OK', 5) - # Disabling the Radio - SSH.command('AT+CFUN=0', 'OK', 5) - logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') - SSH.close() - self.picocom_closure = False - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - self.checkDevTTYisUnlocked() - - def AttachCatM(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - self.picocom_closure = True - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` - SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) - SSH.command('sudo picocom --baud 921600 --flow n --databits 8 /dev/ttyUSB0', 'Terminal ready', 10) - time.sleep(1) - # Calling twice AT to clear all buffers - SSH.command('AT', 'OK|ERROR', 5) - SSH.command('AT', 'OK', 5) - # Enabling the Radio - SSH.command('AT+CFUN=1', 'SIMSTORE,READY', 5) - logging.debug('\u001B[1m Cellular Functionality enabled\u001B[0m') - time.sleep(4) - # We should check if we register - count = 0 - attach_cnt = 0 - attach_status = False - while count < 5: - SSH.command('AT+CEREG?', 'OK', 5) - result = re.search('CEREG: 2,(?P[0-9\-]+),', SSH.getBefore()) - if result is not None: - mDataConnectionState = int(result.group('state')) - if mDataConnectionState is not None: - if mDataConnectionState == 1: - count = 10 - attach_status = True - result = re.search('CEREG: 2,1,"(?P[0-9A-Z]+)","(?P[0-9A-Z]+)"', SSH.getBefore()) - if result is not None: - networky = result.group('networky') - networkz = result.group('networkz') - logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m') - else: - logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m') - else: - logging.debug('+CEREG: 2,' + str(mDataConnectionState)) - attach_cnt = attach_cnt + 1 - else: - logging.debug(SSH.getBefore()) - attach_cnt = attach_cnt + 1 - count = count + 1 - time.sleep(1) - if attach_status: - SSH.command('AT+CESQ', 'OK', 5) - result = re.search('CESQ: 99,99,255,255,(?P[0-9]+),(?P[0-9]+)', SSH.getBefore()) - if result is not None: - nRSRQ = int(result.group('rsrq')) - nRSRP = int(result.group('rsrp')) - if (nRSRQ is not None) and (nRSRP is not None): - logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') - logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') - SSH.close() - self.picocom_closure = False - html_queue = SimpleQueue() - self.checkDevTTYisUnlocked() - if attach_status: - html_cell = '
CAT-M module Attachment Completed in ' + str(attach_cnt+4) + ' seconds'
-			if (nRSRQ is not None) and (nRSRP is not None):
-				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
-				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm
' - else: - html_cell += '' - html_queue.put(html_cell) - HTML.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue) - else: - logging.error('\u001B[1m CAT-M module Attachment Failed\u001B[0m') - html_cell = '
CAT-M module Attachment Failed
' - html_queue.put(html_cell) - HTML.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue) - self.AutoTerminateUEandeNB() - - def PingCatM(self): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - try: - statusQueue = SimpleQueue() - lock = Lock() - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) - SSH.command('cd scripts', '\$', 5) - if re.match('OAI', EPC.GetType(), re.IGNORECASE): - logging.debug('Using the OAI EPC HSS: not implemented yet') - HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - HTML.CreateHtmlTabFooter(False) - sys.exit(1) - else: - SSH.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5) - result = re.search('Allocated ipv4 addr: (?P[0-9\.]+) from Pool', SSH.getBefore()) - if result is not None: - moduleIPAddr = result.group('ipaddr') - else: - HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - device_id = 'catm' - ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - lock.acquire() - logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - lock.release() - SSH.close() - html_cell = '
CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '
' - statusQueue.put(html_cell) - if (packetLossOK): - HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue) - else: - HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue) - self.AutoTerminateUEandeNB() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AttachUE_common(self, device_id, statusQueue, lock, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) - else: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) - else: - # airplane mode off // radio on - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(2) - max_count = 45 - count = max_count - while count > 0: - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) - print('#GP: in SSH.getBefore() K=0 (it was K=2 in main.py)') - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put('mDataConnectionState Not Found!') - lock.release() - break - mDataConnectionState = int(result.group('state')) - if mDataConnectionState == 2: - logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') - lock.acquire() - statusQueue.put(max_count - count) - statusQueue.put(device_id) - statusQueue.put('Attach Completed') - lock.release() - break - count = count - 1 - if count == 15 or count == 30: - logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m') - if self.ADBCentralized: - if device_id == '84B7N16418004022': - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - time.sleep(0.5) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60) - else: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOnCmd[idx], '\$', 60) - time.sleep(0.5) - logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m') - time.sleep(1) - if count == 0: - logging.debug('\u001B[1;37;41m UE (' + device_id + ') Attach Failed \u001B[0m') - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put('Attach Failed') - lock.release() - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def AttachUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - status_queue = SimpleQueue() - lock = Lock() - nb_ue_to_connect = 0 - for device_id in self.UEDevices: - if (self.nbMaxUEtoAttach == -1) or (nb_ue_to_connect < self.nbMaxUEtoAttach): - self.UEDevicesStatus[nb_ue_to_connect] = CONST.UE_STATUS_ATTACHING - p = Process(target = self.AttachUE_common, args = (device_id, status_queue, lock,nb_ue_to_connect,)) - p.daemon = True - p.start() - multi_jobs.append(p) - nb_ue_to_connect = nb_ue_to_connect + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - return - else: - attach_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - attach_status = False - device_id = status_queue.get() - message = status_queue.get() - if (count < 0): - html_cell = '
UE (' + device_id + ')\n' + message + '
' - else: - html_cell = '
UE (' + device_id + ')\n' + message + ' in ' + str(count + 2) + ' seconds
' - html_queue.put(html_cell) - if (attach_status): - cnt = 0 - while cnt < len(self.UEDevices): - if self.UEDevicesStatus[cnt] == CONST.UE_STATUS_ATTACHING: - self.UEDevicesStatus[cnt] = CONST.UE_STATUS_ATTACHED - cnt += 1 - HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - else: - HTML.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def DetachUE_common(self, device_id, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DetachUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - cnt = 0 - for device_id in self.UEDevices: - self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHING - p = Process(target = self.DetachUE_common, args = (device_id,cnt,)) - p.daemon = True - p.start() - multi_jobs.append(p) - cnt += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - result = re.search('T_stdout', str(RAN.GetInitialize_eNB_args())) - if result is not None: - logging.debug('Waiting 5 seconds to fill up record file') - time.sleep(5) - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus[cnt] = CONST.UE_STATUS_DETACHED - cnt += 1 - - def RebootUE_common(self, device_id): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - previousmDataConnectionStates = [] - # Save mDataConnectionState - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') - sys.exit(1) - previousmDataConnectionStates.append(int(result.group('state'))) - # Reboot UE - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell reboot', '\$', 10) - time.sleep(60) - previousmDataConnectionState = previousmDataConnectionStates.pop(0) - count = 180 - while count > 0: - count = count - 1 - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell dumpsys telephony.registry | grep mDataConnectionState', '\$', 15) - result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) - if result is None: - mDataConnectionState = None - else: - mDataConnectionState = int(result.group('state')) - logging.debug('mDataConnectionState = ' + result.group('state')) - if mDataConnectionState is None or (previousmDataConnectionState == 2 and mDataConnectionState != 2): - logging.debug('\u001B[1mWait UE (' + device_id + ') a second until reboot completion (' + str(180-count) + ' times)\u001B[0m') - time.sleep(1) - else: - logging.debug('\u001B[1mUE (' + device_id + ') Reboot Completed\u001B[0m') - break - if count == 0: - logging.debug('\u001B[1;37;41m UE (' + device_id + ') Reboot Failed \u001B[0m') - sys.exit(1) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def RebootUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) - HTML.CreateHtmlTabFooter(False) - sys.exit(1) - multi_jobs = [] - for device_id in self.UEDevices: - p = Process(target = self.RebootUE_common, args = (device_id,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def DataDisableUE_common(self, device_id, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # disable data service - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data disable"', '\$', 60) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data disable"\'', '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Disabled Data Service\u001B[0m') - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DataDisableUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.DataDisableUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def DataEnableUE_common(self, device_id, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # enable data service - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "svc data enable"', '\$', 60) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "svc data enable"\'', '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Enabled Data Service\u001B[0m') - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def DataEnableUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.DataEnableUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def GetAllUEDevices(self, terminate_ue_flag): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - SSH.command('adb devices', '\$', 15) - #self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) - self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) - SSH.close() - else: - if (os.path.isfile('./phones_list.txt')): - os.remove('./phones_list.txt') - SSH.command('ls /etc/*/phones*.txt', '\$', 5) - result = re.search('/etc/ci/phones_list.txt', SSH.getBefore()) - SSH.close() - if (result is not None) and (len(self.UEDevices) == 0): - SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, '/etc/ci/phones_list.txt', '.') - if (os.path.isfile('./phones_list.txt')): - phone_list_file = open('./phones_list.txt', 'r') - for line in phone_list_file.readlines(): - line = line.strip() - result = re.search('^#', line) - if result is not None: - continue - comma_split = line.split(",") - self.UEDevices.append(comma_split[0]) - self.UEDevicesRemoteServer.append(comma_split[1]) - self.UEDevicesRemoteUser.append(comma_split[2]) - self.UEDevicesOffCmd.append(comma_split[3]) - self.UEDevicesOnCmd.append(comma_split[4]) - self.UEDevicesRebootCmd.append(comma_split[5]) - phone_list_file.close() - - if terminate_ue_flag == True: - print('terminate_ue_flag == True') - if len(self.UEDevices) == 0: - logging.debug('\u001B[1;37;41m UE Not Found! \u001B[0m') - sys.exit(1) - if len(self.UEDevicesStatus) == 0: - print('len(self.UEDevicesStatus) == 0') - cnt = 0 - while cnt < len(self.UEDevices): - self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) - cnt += 1 - - def GetAllCatMDevices(self, terminate_ue_flag): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - SSH.command('lsusb | egrep "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) - #self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) - self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) - else: - if (os.path.isfile('./modules_list.txt')): - os.remove('./modules_list.txt') - SSH.command('ls /etc/*/modules*.txt', '\$', 5) - result = re.search('/etc/ci/modules_list.txt', SSH.getBefore()) - SSH.close() - if result is not None: - logging.debug('Found a module list file on ADB server') - if terminate_ue_flag == True: - if len(self.CatMDevices) == 0: - logging.debug('\u001B[1;37;41m CAT-M UE Not Found! \u001B[0m') - sys.exit(1) - SSH.close() - - def CheckUEStatus_common(self, lock, device_id, statusQueue, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry"', '\$', 15) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\'', '\$', 60) - result = re.search('mServiceState=(?P[0-9]+)', SSH.getBefore()) - serviceState = 'Service State: UNKNOWN' - if result is not None: - lServiceState = int(result.group('serviceState')) - if lServiceState == 3: - serviceState = 'Service State: RADIO_POWERED_OFF' - if lServiceState == 1: - serviceState = 'Service State: OUT_OF_SERVICE' - if lServiceState == 0: - serviceState = 'Service State: IN_SERVICE' - if lServiceState == 2: - serviceState = 'Service State: EMERGENCY_ONLY' - result = re.search('mDataConnectionState=(?P[0-9]+)', SSH.getBefore()) - dataConnectionState = 'Data State: UNKNOWN' - if result is not None: - lDataConnectionState = int(result.group('dataConnectionState')) - if lDataConnectionState == 0: - dataConnectionState = 'Data State: DISCONNECTED' - if lDataConnectionState == 1: - dataConnectionState = 'Data State: CONNECTING' - if lDataConnectionState == 2: - dataConnectionState = 'Data State: CONNECTED' - if lDataConnectionState == 3: - dataConnectionState = 'Data State: SUSPENDED' - result = re.search('mDataConnectionReason=(?P[0-9a-zA-Z_]+)', SSH.getBefore()) - dataConnectionReason = 'Data Reason: UNKNOWN' - if result is not None: - dataConnectionReason = 'Data Reason: ' + result.group('dataConnectionReason') - lock.acquire() - logging.debug('\u001B[1;37;44m Status Check (' + str(device_id) + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + serviceState + '\u001B[0m') - logging.debug('\u001B[1;34m ' + dataConnectionState + '\u001B[0m') - logging.debug('\u001B[1;34m ' + dataConnectionReason + '\u001B[0m') - statusQueue.put(0) - statusQueue.put(device_id) - qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason - statusQueue.put(qMsg) - lock.release() - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def CheckStatusUE(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', pStatus) - HTML.CreateHtmlTabFooter(False) - sys.exit(1) - multi_jobs = [] - lock = Lock() - status_queue = SimpleQueue() - i = 0 - for device_id in self.UEDevices: - p = Process(target = self.CheckUEStatus_common, args = (lock,device_id,status_queue,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd /opt/flexran_rtc', '\$', 5) - SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) - SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5) - result = re.search('Nb Connected UE = (?P[0-9]+)', SSH.getBefore()) - passStatus = True - if result is not None: - nb_ues = int(result.group('nb_ues')) - htmlOptions = 'Nb Connected UE(s) to eNB = ' + str(nb_ues) - logging.debug('\u001B[1;37;44m ' + htmlOptions + ' \u001B[0m') - if self.expectedNbOfConnectedUEs > -1: - if nb_ues != self.expectedNbOfConnectedUEs: - passStatus = False - else: - htmlOptions = 'N/A' - SSH.close() - else: - passStatus = True - htmlOptions = 'N/A' - - if (status_queue.empty()): - HTML.CreateHtmlTestRow(htmlOptions, 'KO', CONST.ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - check_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - check_status = False - device_id = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\n' + message + '
' - html_queue.put(html_cell) - if check_status and passStatus: - HTML.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue) - else: - HTML.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def GetAllUEIPAddresses(self): - if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - ue_ip_status = 0 - self.UEIPAddresses = [] - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('ifconfig oaitun_ue1', '\$', 4) - result = re.search('inet addr:(?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', SSH.getBefore()) - if result is not None: - if result.group('ueipaddress') is not None: - UE_IPAddress = result.group('ueipaddress') - else: - UE_IPAddress = result.group('ueipaddress2') - logging.debug('\u001B[1mUE (' + self.UEDevices[0] + ') IP Address is ' + UE_IPAddress + '\u001B[0m') - self.UEIPAddresses.append(UE_IPAddress) - else: - logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') - ue_ip_status -= 1 - SSH.close() - return ue_ip_status - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - idx = 0 - for device_id in self.UEDevices: - print('UE status attched'+CONST.UE_STATUS_ATTACHED) - if self.UEDevicesStatus[idx] != CONST.UE_STATUS_ATTACHED: - idx += 1 - continue - count = 0 - while count < 4: - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ip addr show | grep rmnet"', '\$', 15) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ip addr show | grep rmnet"\'', '\$', 60) - result = re.search('inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/[0-9]+[0-9a-zA-Z\.\s]+', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m UE IP Address Not Found! \u001B[0m') - time.sleep(1) - count += 1 - else: - count = 10 - if count < 9: - ue_ip_status -= 1 - continue - UE_IPAddress = result.group('ueipaddress') - logging.debug('\u001B[1mUE (' + device_id + ') IP Address is ' + UE_IPAddress + '\u001B[0m') - for ueipaddress in self.UEIPAddresses: - if ueipaddress == UE_IPAddress: - logging.debug('\u001B[1mUE (' + device_id + ') IP Address ' + UE_IPAddress + ': has already been allocated to another device !' + '\u001B[0m') - ue_ip_status -= 1 - continue - self.UEIPAddresses.append(UE_IPAddress) - idx += 1 - SSH.close() - return ue_ip_status - - def ping_iperf_wrong_exit(self, lock, UE_IPAddress, device_id, statusQueue, message): - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(message) - lock.release() - - def Ping_common(self, lock, UE_IPAddress, device_id, statusQueue): - try: - # Launch ping on the EPC side (true for ltebox and old open-air-cn) - # But for OAI-Rel14-CUPS, we launch from python executor - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): - launchFromEpc = False - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - - if launchFromEpc: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) - SSH.command('cd scripts', '\$', 5) - ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) - else: - cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - ping_status = ret.returncode - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cat ' + EPC.GetSourceCodePath() + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - lock.acquire() - logging.debug('\u001B[1;37;44m ping result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - if (packetLossOK): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(qMsg) - lock.release() - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def PingNoS1_wrong_exit(self, qMsg): - html_queue = SimpleQueue() - html_cell = '
OAI UE ping result\n' + qMsg + '
' - html_queue.put(html_cell) - HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - - def PingNoS1(self): - check_eNB = True - check_OAI_UE = True - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) - if ping_from_eNB is not None: - if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - else: - if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - try: - if ping_from_eNB is not None: - SSH.open(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword) - SSH.command('cd ' + RAN.GeteNBSourceCodePath() + '/cmake_targets/', '\$', 5) - else: - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets/', '\$', 5) - ping_time = re.findall("-c (\d+)",str(self.ping_args)) - ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '.log', '\$', int(ping_time[0])*1.5) - # TIMEOUT CASE - if ping_status < 0: - message = 'Ping with OAI UE crashed due to TIMEOUT!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - result = re.search(', (?P[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore()) - if result is None: - message = 'Packet Loss Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - packetloss = result.group('packetloss') - if float(packetloss) == 100: - message = 'Packet Loss is 100%' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - result = re.search('rtt min\/avg\/max\/mdev = (?P[0-9\.]+)\/(?P[0-9\.]+)\/(?P[0-9\.]+)\/[0-9\.]+ ms', SSH.getBefore()) - if result is None: - message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.PingNoS1_wrong_exit(message) - return - rtt_min = result.group('rtt_min') - rtt_avg = result.group('rtt_avg') - rtt_max = result.group('rtt_max') - pal_msg = 'Packet Loss : ' + packetloss + '%' - min_msg = 'RTT(Min) : ' + rtt_min + ' ms' - avg_msg = 'RTT(Avg) : ' + rtt_avg + ' ms' - max_msg = 'RTT(Max) : ' + rtt_max + ' ms' - logging.debug('\u001B[1;37;44m OAI UE ping result \u001B[0m') - logging.debug('\u001B[1;34m ' + pal_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + min_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + avg_msg + '\u001B[0m') - logging.debug('\u001B[1;34m ' + max_msg + '\u001B[0m') - qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg - packetLossOK = True - if packetloss is not None: - if float(packetloss) > float(self.ping_packetloss_threshold): - qMsg += '\nPacket Loss too high' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - packetLossOK = False - elif float(packetloss) > 0: - qMsg += '\nPacket Loss is not 0%' - logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m') - SSH.close() - html_queue = SimpleQueue() - ip_addr = 'TBD' - html_cell = '
OAI UE ping result\n' + qMsg + '
' - html_queue.put(html_cell) - if packetLossOK: - HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) - else: - HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - - # copying on the EPC server for logCollection - if ping_from_eNB is not None: - copyin_res = SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') - else: - copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/ping_' + self.testCase_id + '.log', '.') - if (copyin_res == 0): - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'ping_' + self.testCase_id + '.log', EPC.GetSourceCodePath() + '/scripts') - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def Ping(self): - result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) - if result is not None: - self.PingNoS1() - return - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - check_OAI_UE = True - else: - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB() - return - multi_jobs = [] - i = 0 - lock = Lock() - status_queue = SimpleQueue() - for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = self.Ping_common, args = (lock,UE_IPAddress,device_id,status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - ping_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - ping_status = False - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (ping_status): - HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue) - else: - HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def Iperf_ComputeTime(self): - result = re.search('-t (?P\d+)', str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Iperf time Not Found! \u001B[0m') - sys.exit(1) - return result.group('iperf_time') - - def Iperf_ComputeModifiedBW(self, idx, ue_num): - result = re.search('-b (?P[0-9\.]+)[KMG]', str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Iperf bandwidth Not Found! \u001B[0m') - sys.exit(1) - iperf_bandwidth = result.group('iperf_bandwidth') - if self.iperf_profile == 'balanced': - iperf_bandwidth_new = float(iperf_bandwidth)/ue_num - if self.iperf_profile == 'single-ue': - iperf_bandwidth_new = float(iperf_bandwidth) - if self.iperf_profile == 'unbalanced': - # residual is 2% of max bw - residualBW = float(iperf_bandwidth) / 50 - if idx == 0: - iperf_bandwidth_new = float(iperf_bandwidth) - ((ue_num - 1) * residualBW) - else: - iperf_bandwidth_new = residualBW - iperf_bandwidth_str = '-b ' + iperf_bandwidth - iperf_bandwidth_str_new = '-b ' + ('%.2f' % iperf_bandwidth_new) - result = re.sub(iperf_bandwidth_str, iperf_bandwidth_str_new, str(self.iperf_args)) - if result is None: - logging.debug('\u001B[1;37;41m Calculate Iperf bandwidth Failed! \u001B[0m') - sys.exit(1) - return result - - def Iperf_analyzeV2TCPOutput(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - SSH.command('awk -f /tmp/tcp_iperf_stats.awk /tmp/CI-eNB/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('Avg Bitrate : (?P[0-9\.]+ Mbits\/sec) Max Bitrate : (?P[0-9\.]+ Mbits\/sec) Min Bitrate : (?P[0-9\.]+ Mbits\/sec)', SSH.getBefore()) - if result is not None: - avgbitrate = result.group('average') - maxbitrate = result.group('maximum') - minbitrate = result.group('minimum') - lock.acquire() - logging.debug('\u001B[1;37;44m TCP iperf result (' + UE_IPAddress + ') \u001B[0m') - msg = 'TCP Stats :\n' - if avgbitrate is not None: - logging.debug('\u001B[1;34m Avg Bitrate : ' + avgbitrate + '\u001B[0m') - msg += 'Avg Bitrate : ' + avgbitrate + '\n' - if maxbitrate is not None: - logging.debug('\u001B[1;34m Max Bitrate : ' + maxbitrate + '\u001B[0m') - msg += 'Max Bitrate : ' + maxbitrate + '\n' - if minbitrate is not None: - logging.debug('\u001B[1;34m Min Bitrate : ' + minbitrate + '\u001B[0m') - msg += 'Min Bitrate : ' + minbitrate + '\n' - statusQueue.put(0) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - return 0 - - def Iperf_analyzeV2Output(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - result = re.search('-u', str(iperf_real_options)) - if result is None: - return self.Iperf_analyzeV2TCPOutput(lock, UE_IPAddress, device_id, statusQueue, iperf_real_options) - - result = re.search('Server Report:', SSH.getBefore()) - if result is None: - result = re.search('read failed: Connection refused', SSH.getBefore()) - if result is not None: - logging.debug('\u001B[1;37;41m Could not connect to iperf server! \u001B[0m') - else: - logging.debug('\u001B[1;37;41m Server Report and Connection refused Not Found! \u001B[0m') - return -1 - # Computing the requested bandwidth in float - result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) - if result is not None: - req_bandwidth = result.group('iperf_bandwidth') - req_bw = float(req_bandwidth) - result = re.search('-b [0-9\.]+K', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Kbits/sec' % req_bw - req_bw = req_bw * 1000 - result = re.search('-b [0-9\.]+M', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Mbits/sec' % req_bw - req_bw = req_bw * 1000000 - result = re.search('-b [0-9\.]+G', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Gbits/sec' % req_bw - req_bw = req_bw * 1000000000 - - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', SSH.getBefore()) - if result is not None: - bitrate = result.group('bitrate') - packetloss = result.group('packetloss') - jitter = result.group('jitter') - lock.acquire() - logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') - iperfStatus = True - msg = 'Req Bitrate : ' + req_bandwidth + '\n' - logging.debug('\u001B[1;34m Req Bitrate : ' + req_bandwidth + '\u001B[0m') - if bitrate is not None: - msg += 'Bitrate : ' + bitrate + '\n' - logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') - result = re.search('(?P[0-9\.]+) [KMG]bits/sec', str(bitrate)) - if result is not None: - actual_bw = float(str(result.group('real_bw'))) - result = re.search('[0-9\.]+ K', bitrate) - if result is not None: - actual_bw = actual_bw * 1000 - result = re.search('[0-9\.]+ M', bitrate) - if result is not None: - actual_bw = actual_bw * 1000000 - result = re.search('[0-9\.]+ G', bitrate) - if result is not None: - actual_bw = actual_bw * 1000000000 - br_loss = 100 * actual_bw / req_bw - bitperf = '%.2f ' % br_loss - msg += 'Bitrate Perf: ' + bitperf + '%\n' - logging.debug('\u001B[1;34m Bitrate Perf: ' + bitperf + '%\u001B[0m') - if packetloss is not None: - msg += 'Packet Loss : ' + packetloss + '%\n' - logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') - if float(packetloss) > float(self.iperf_packetloss_threshold): - msg += 'Packet Loss too high!\n' - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - iperfStatus = False - if jitter is not None: - msg += 'Jitter : ' + jitter + '\n' - logging.debug('\u001B[1;34m Jitter : ' + jitter + '\u001B[0m') - if (iperfStatus): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - return 0 - else: - return -2 - - def Iperf_analyzeV2Server(self, lock, UE_IPAddress, device_id, statusQueue, iperf_real_options): - if (not os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') - return - # Computing the requested bandwidth in float - result = re.search('-b (?P[0-9\.]+)[KMG]', str(iperf_real_options)) - if result is None: - logging.debug('Iperf bandwidth Not Found!') - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not compute Iperf bandwidth!') - return - else: - req_bandwidth = result.group('iperf_bandwidth') - req_bw = float(req_bandwidth) - result = re.search('-b [0-9\.]+K', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Kbits/sec' % req_bw - req_bw = req_bw * 1000 - result = re.search('-b [0-9\.]+M', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Mbits/sec' % req_bw - req_bw = req_bw * 1000000 - result = re.search('-b [0-9\.]+G', str(iperf_real_options)) - if result is not None: - req_bandwidth = '%.1f Gbits/sec' % req_bw - req_bw = req_bw * 1000000000 - - server_file = open('iperf_server_' + self.testCase_id + '_' + device_id + '.log', 'r') - br_sum = 0.0 - ji_sum = 0.0 - pl_sum = 0 - ps_sum = 0 - row_idx = 0 - for line in server_file.readlines(): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) - if result is not None: - bitrate = result.group('bitrate') - jitter = result.group('jitter') - packetlost = result.group('lostPack') - packetsent = result.group('sentPack') - br = bitrate.split(' ') - ji = jitter.split(' ') - row_idx = row_idx + 1 - curr_br = float(br[0]) - pl_sum = pl_sum + int(packetlost) - ps_sum = ps_sum + int(packetsent) - if (br[1] == 'Kbits/sec'): - curr_br = curr_br * 1000 - if (br[1] == 'Mbits/sec'): - curr_br = curr_br * 1000 * 1000 - br_sum = curr_br + br_sum - ji_sum = float(ji[0]) + ji_sum - if (row_idx > 0): - br_sum = br_sum / row_idx - ji_sum = ji_sum / row_idx - br_loss = 100 * br_sum / req_bw - if (br_sum > 1000): - br_sum = br_sum / 1000 - if (br_sum > 1000): - br_sum = br_sum / 1000 - bitrate = '%.2f Mbits/sec' % br_sum - else: - bitrate = '%.2f Kbits/sec' % br_sum - else: - bitrate = '%.2f bits/sec' % br_sum - bitperf = '%.2f ' % br_loss - bitperf += '%' - jitter = '%.2f ms' % (ji_sum) - if (ps_sum > 0): - pl = float(100 * pl_sum / ps_sum) - packetloss = '%2.1f ' % (pl) - packetloss += '%' - else: - packetloss = 'unknown' - lock.acquire() - if (br_loss < 90): - statusQueue.put(1) - else: - statusQueue.put(0) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - req_msg = 'Req Bitrate : ' + req_bandwidth - bir_msg = 'Bitrate : ' + bitrate - brl_msg = 'Bitrate Perf: ' + bitperf - jit_msg = 'Jitter : ' + jitter - pal_msg = 'Packet Loss : ' + packetloss - statusQueue.put(req_msg + '\n' + bir_msg + '\n' + brl_msg + '\n' + jit_msg + '\n' + pal_msg + '\n') - logging.debug('\u001B[1;37;45m iperf result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;35m ' + req_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + bir_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + brl_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + jit_msg + '\u001B[0m') - logging.debug('\u001B[1;35m ' + pal_msg + '\u001B[0m') - lock.release() - else: - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, 'Could not analyze from server log') - - server_file.close() - - - def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', SSH.getBefore()) - if result is None: - result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', SSH.getBefore()) - lock.acquire() - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - if result is not None: - logging.debug('\u001B[1;37;41m ' + result.group('error') + ' \u001B[0m') - statusQueue.put(result.group('error')) - else: - logging.debug('\u001B[1;37;41m Bitrate and/or Packet Loss Not Found! \u001B[0m') - statusQueue.put('Bitrate and/or Packet Loss Not Found!') - lock.release() - - bitrate = result.group('bitrate') - packetloss = result.group('packetloss') - lock.acquire() - logging.debug('\u001B[1;37;44m iperf result (' + UE_IPAddress + ') \u001B[0m') - logging.debug('\u001B[1;34m Bitrate : ' + bitrate + '\u001B[0m') - msg = 'Bitrate : ' + bitrate + '\n' - iperfStatus = True - if packetloss is not None: - logging.debug('\u001B[1;34m Packet Loss : ' + packetloss + '%\u001B[0m') - msg += 'Packet Loss : ' + packetloss + '%\n' - if float(packetloss) > float(self.iperf_packetloss_threshold): - logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m') - msg += 'Packet Loss too high!\n' - iperfStatus = False - if (iperfStatus): - statusQueue.put(0) - else: - statusQueue.put(-1) - statusQueue.put(device_id) - statusQueue.put(UE_IPAddress) - statusQueue.put(msg) - lock.release() - - def Iperf_UL_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): - udpIperf = True - result = re.search('-u', str(self.iperf_args)) - if result is None: - udpIperf = False - ipnumbers = UE_IPAddress.split('.') - if (len(ipnumbers) == 4): - ipnumbers[3] = '1' - EPC_Iperf_UE_IPAddress = ipnumbers[0] + '.' + ipnumbers[1] + '.' + ipnumbers[2] + '.' + ipnumbers[3] - - # Launch iperf server on EPC side (true for ltebox and old open-air-cn0 - # But for OAI-Rel14-CUPS, we launch from python executor and we are using its IP address as iperf client address - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): - launchFromEpc = False - cmd = 'hostname -I' - ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - if ret.stdout is not None: - EPC_Iperf_UE_IPAddress = ret.stdout.strip() - port = 5001 + idx - if launchFromEpc: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) - SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if udpIperf: - SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.GetUserName(), 5) - else: - SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.GetUserName(), 5) - SSH.close() - else: - if self.ueIperfVersion == self.dummyIperfVersion: - prefix = '' - else: - prefix = '' - if self.ueIperfVersion == '2.0.5': - prefix = '/opt/iperf-2.0.5/bin/' - if udpIperf: - cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - else: - cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &' - logging.debug(cmd) - subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - time.sleep(0.5) - - # Launch iperf client on UE - if (device_id == 'OAI-UE'): - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - else: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) - iperf_time = self.Iperf_ComputeTime() - time.sleep(0.5) - - if udpIperf: - modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) - else: - modified_options = str(self.iperf_args) - modified_options = modified_options.replace('-R','') - time.sleep(0.5) - - SSH.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if (device_id == 'OAI-UE'): - iperf_status = SSH.command('iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + ' -B ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - if self.ADBCentralized: - iperf_status = SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '" 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - iperf_status = SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -c ' + EPC_Iperf_UE_IPAddress + ' ' + modified_options + ' -p ' + str(port) + '"\' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - SSH.command('fromdos -o iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - SSH.command('cat iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # TIMEOUT Case - if iperf_status < 0: - SSH.close() - message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - SSH.close() - - # Kill iperf server on EPC side - if launchFromEpc: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('killall --signal SIGKILL iperf', EPC.GetUserName(), 5) - SSH.close() - else: - cmd = 'killall --signal SIGKILL iperf' - logging.debug(cmd) - subprocess.run(cmd, shell=True) - time.sleep(1) - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') - # in case of failure, retrieve server log - if (clientStatus == -1) or (clientStatus == -2): - if launchFromEpc: - time.sleep(1) - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - SSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) - # in case of OAI-UE - if (device_id == 'OAI-UE'): - SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') - - def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): - try: - logging.debug('entring Iperf_common') - # Single-UE profile -- iperf only on one UE - if self.iperf_profile == 'single-ue' and idx != 0: - return - useIperf3 = False - udpIperf = True - - self.ueIperfVersion = '2.0.5' - if (device_id != 'OAI-UE'): - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # if by chance ADB server and EPC are on the same remote host, at least log collection will take care of it - SSH.command('if [ ! -d ' + EPC.GetSourceCodePath() + '/scripts ]; then mkdir -p ' + EPC.GetSourceCodePath() + '/scripts ; fi', '\$', 5) - SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) - # Checking if iperf / iperf3 are installed - if self.ADBCentralized: - SSH.command('adb -s ' + device_id + ' shell "ls /data/local/tmp"', '\$', 5) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ls /data/local/tmp"\'', '\$', 60) - result = re.search('iperf3', SSH.getBefore()) - if result is None: - result = re.search('iperf', SSH.getBefore()) - if result is None: - message = 'Neither iperf nor iperf3 installed on UE!' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - SSH.close() - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - else: - if self.ADBCentralized: - SSH.command('adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"', '\$', 5) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf --version"\'', '\$', 60) - result = re.search('iperf version 2.0.5', SSH.getBefore()) - if result is not None: - self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', SSH.getBefore()) - if result is not None: - self.ueIperfVersion = '2.0.10' - else: - useIperf3 = True - SSH.close() - else: - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('iperf --version', '\$', 5) - result = re.search('iperf version 2.0.5', SSH.getBefore()) - if result is not None: - self.ueIperfVersion = '2.0.5' - result = re.search('iperf version 2.0.10', SSH.getBefore()) - if result is not None: - self.ueIperfVersion = '2.0.10' - SSH.close() - # in case of iperf, UL has its own function - if (not useIperf3): - result = re.search('-R', str(self.iperf_args)) - if result is not None: - self.Iperf_UL_common(lock, UE_IPAddress, device_id, idx, ue_num, statusQueue) - return - - # Launch the IPERF server on the UE side for DL - if (device_id == 'OAI-UE'): - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('-u', str(self.iperf_args)) - if result is None: - SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) - udpIperf = False - else: - SSH.command('echo $USER; nohup iperf -B ' + UE_IPAddress + ' -u -s -i 1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.UEUserName, 5) - else: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) - if self.ADBCentralized: - if (useIperf3): - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/iperf3 -s &', '\$', 5) - else: - SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - result = re.search('-u', str(self.iperf_args)) - if result is None: - SSH.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) - udpIperf = False - else: - SSH.command('echo $USER; nohup adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 5) - else: - SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - SSH.command('echo $USER; nohup ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "/data/local/tmp/iperf -u -s -i 1" \' 2>&1 > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', self.ADBUserName, 60) - - time.sleep(0.5) - SSH.close() - - # Launch the IPERF client on the EPC side for DL (true for ltebox and old open-air-cn - # But for OAI-Rel14-CUPS, we launch from python executor - launchFromEpc = True - if re.match('OAI-Rel14-CUPS', EPC.GetType(), re.IGNORECASE): - launchFromEpc = False - if launchFromEpc: - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd ' + EPC.GetSourceCodePath() + '/scripts', '\$', 5) - iperf_time = self.Iperf_ComputeTime() - time.sleep(0.5) - - if udpIperf: - modified_options = self.Iperf_ComputeModifiedBW(idx, ue_num) - else: - modified_options = str(self.iperf_args) - time.sleep(0.5) - - if launchFromEpc: - SSH.command('rm -f iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - else: - if (os.path.isfile('iperf_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_' + self.testCase_id + '_' + device_id + '.log') - if (useIperf3): - SSH.command('stdbuf -o0 iperf3 -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - - clientStatus = 0 - self.Iperf_analyzeV3Output(lock, UE_IPAddress, device_id, statusQueue) - else: - if launchFromEpc: - iperf_status = SSH.command('stdbuf -o0 iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 | stdbuf -o0 tee iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', int(iperf_time)*5.0) - else: - if self.ueIperfVersion == self.dummyIperfVersion: - prefix = '' - else: - prefix = '' - if self.ueIperfVersion == '2.0.5': - prefix = '/opt/iperf-2.0.5/bin/' - cmd = prefix + 'iperf -c ' + UE_IPAddress + ' ' + modified_options + ' 2>&1 > iperf_' + self.testCase_id + '_' + device_id + '.log' - message = cmd + '\n' - logging.debug(cmd) - ret = subprocess.run(cmd, shell=True) - iperf_status = ret.returncode - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cat ' + EPC.GetSourceCodePath() + '/scripts/iperf_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - if iperf_status < 0: - if launchFromEpc: - SSH.close() - message = 'iperf on UE (' + str(UE_IPAddress) + ') crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message) - return - clientStatus = self.Iperf_analyzeV2Output(lock, UE_IPAddress, device_id, statusQueue, modified_options) - SSH.close() - - # Kill the IPERF server that runs in background - if (device_id == 'OAI-UE'): - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('killall iperf', '\$', 5) - else: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell ps | grep --color=never iperf | grep -v grep', '\$', 5) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps" | grep --color=never iperf | grep -v grep\'', '\$', 60) - result = re.search('shell +(?P\d+)', SSH.getBefore()) - if result is not None: - pid_iperf = result.group('pid') - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell kill -KILL ' + pid_iperf, '\$', 5) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - SSH.close() - # if the client report is absent, try to analyze the server log file - if (clientStatus == -1): - time.sleep(1) - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log') - if (device_id == 'OAI-UE'): - SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - else: - SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.GetSourceCodePath() + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.command('fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5) - # fromdos has to be called on the python executor not on ADB server - cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log' - subprocess.run(cmd, shell=True) - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options) - - # in case of OAI UE: - if (device_id == 'OAI-UE'): - if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')): - if not launchFromEpc: - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') - else: - SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.') - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.GetSourceCodePath() + '/scripts') - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def IperfNoS1(self): - if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - check_OAI_UE = True - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - server_on_enb = re.search('-R', str(self.iperf_args)) - if server_on_enb is not None: - iServerIPAddr = RAN.GeteNBIPAddress() - iServerUser = RAN.GeteNBUserName() - iServerPasswd = RAN.GeteNBPassword() - iClientIPAddr = self.UEIPAddress - iClientUser = self.UEUserName - iClientPasswd = self.UEPassword - else: - iServerIPAddr = self.UEIPAddress - iServerUser = self.UEUserName - iServerPasswd = self.UEPassword - iClientIPAddr = RAN.GeteNBIPAddress() - iClientUser = RAN.GeteNBUserName() - iClientPasswd = RAN.GeteNBPassword() - if self.iperf_options != 'sink': - # Starting the iperf server - SSH.open(iServerIPAddr, iServerUser, iServerPasswd) - # args SHALL be "-c client -u any" - # -c 10.0.1.2 -u -b 1M -t 30 -i 1 -fm -B 10.0.1.1 - # -B 10.0.1.1 -u -s -i 1 -fm - server_options = re.sub('-u.*$', '-u -s -i 1 -fm', str(self.iperf_args)) - server_options = server_options.replace('-c','-B') - SSH.command('rm -f /tmp/tmp_iperf_server_' + self.testCase_id + '.log', '\$', 5) - SSH.command('echo $USER; nohup iperf ' + server_options + ' > /tmp/tmp_iperf_server_' + self.testCase_id + '.log 2>&1 &', iServerUser, 5) - time.sleep(0.5) - SSH.close() - - # Starting the iperf client - modified_options = self.Iperf_ComputeModifiedBW(0, 1) - modified_options = modified_options.replace('-R','') - iperf_time = self.Iperf_ComputeTime() - SSH.open(iClientIPAddr, iClientUser, iClientPasswd) - SSH.command('rm -f /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', 5) - iperf_status = SSH.command('stdbuf -o0 iperf ' + modified_options + ' 2>&1 | stdbuf -o0 tee /tmp/tmp_iperf_' + self.testCase_id + '.log', '\$', int(iperf_time)*5.0) - status_queue = SimpleQueue() - lock = Lock() - if iperf_status < 0: - message = 'iperf on OAI UE crashed due to TIMEOUT !' - logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m') - clientStatus = -2 - else: - if self.iperf_options == 'sink': - clientStatus = 0 - status_queue.put(0) - status_queue.put('OAI-UE') - status_queue.put('10.0.1.2') - status_queue.put('Sink Test : no check') - else: - clientStatus = self.Iperf_analyzeV2Output(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - SSH.close() - - # Stopping the iperf server - if self.iperf_options != 'sink': - SSH.open(iServerIPAddr, iServerUser, iServerPasswd) - SSH.command('killall --signal SIGKILL iperf', '\$', 5) - time.sleep(0.5) - SSH.close() - - if (clientStatus == -1): - if (os.path.isfile('iperf_server_' + self.testCase_id + '.log')): - os.remove('iperf_server_' + self.testCase_id + '.log') - SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - self.Iperf_analyzeV2Server(lock, '10.0.1.2', 'OAI-UE', status_queue, modified_options) - - # copying on the EPC server for logCollection - if (clientStatus == -1): - copyin_res = SSH.copyin(iServerIPAddr, iServerUser, iServerPasswd, '/tmp/tmp_iperf_server_' + self.testCase_id + '.log', 'iperf_server_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_server_' + self.testCase_id + '_OAI-UE.log', EPC.GetSourceCodePath() + '/scripts') - copyin_res = SSH.copyin(iClientIPAddr, iClientUser, iClientPasswd, '/tmp/tmp_iperf_' + self.testCase_id + '.log', 'iperf_' + self.testCase_id + '_OAI-UE.log') - if (copyin_res == 0): - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), 'iperf_' + self.testCase_id + '_OAI-UE.log', EPC.GetSourceCodePath() + '/scripts') - iperf_noperf = False - if status_queue.empty(): - iperf_status = False - else: - iperf_status = True - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - iperf_status = False - if (count > 0): - iperf_noperf = True - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (iperf_noperf and iperf_status): - HTML.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) - elif (iperf_status): - HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) - else: - HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def Iperf(self): - result = re.search('noS1', str(RAN.GetInitialize_eNB_args())) - if result is not None: - self.IperfNoS1() - return - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - check_eNB = True - if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): - check_OAI_UE = True - else: - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus) - self.AutoTerminateUEandeNB() - return - ueIpStatus = self.GetAllUEIPAddresses() - if (ueIpStatus < 0): - logging.debug('going here') - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE) - self.AutoTerminateUEandeNB() - return - - self.dummyIperfVersion = '2.0.10' - #cmd = 'iperf --version' - #logging.debug(cmd + '\n') - #iperfStdout = subprocess.check_output(cmd, shell=True, universal_newlines=True) - #result = re.search('iperf version 2.0.5', str(iperfStdout.strip())) - #if result is not None: - # dummyIperfVersion = '2.0.5' - #result = re.search('iperf version 2.0.10', str(iperfStdout.strip())) - #if result is not None: - # dummyIperfVersion = '2.0.10' - - multi_jobs = [] - i = 0 - ue_num = len(self.UEIPAddresses) - lock = Lock() - status_queue = SimpleQueue() - logging.debug('ue_num = ' + str(ue_num)) - for UE_IPAddress in self.UEIPAddresses: - device_id = self.UEDevices[i] - p = Process(target = self.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i = i + 1 - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.ALL_PROCESSES_OK) - self.AutoTerminateUEandeNB() - else: - iperf_status = True - iperf_noperf = False - html_queue = SimpleQueue() - while (not status_queue.empty()): - count = status_queue.get() - if (count < 0): - iperf_status = False - if (count > 0): - iperf_noperf = True - device_id = status_queue.get() - ip_addr = status_queue.get() - message = status_queue.get() - html_cell = '
UE (' + device_id + ')\nIP Address  : ' + ip_addr + '\n' + message + '
' - html_queue.put(html_cell) - if (iperf_noperf and iperf_status): - HTML.CreateHtmlTestRowQueue(self.iperf_args, 'PERF NOT MET', len(self.UEDevices), html_queue) - elif (iperf_status): - HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue) - else: - HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue) - self.AutoTerminateUEandeNB() - - def CheckProcessExist(self, check_eNB, check_OAI_UE): - multi_jobs = [] - status_queue = SimpleQueue() - # in noS1 config, no need to check status from EPC - # in gNB also currently no need to check - result = re.search('noS1|band78', str(RAN.GetInitialize_eNB_args())) - if result is None: - p = Process(target = EPC.CheckHSSProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - p = Process(target = EPC.CheckMMEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - p = Process(target = EPC.CheckSPGWProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - else: - if (check_eNB == False) and (check_OAI_UE == False): - return 0 - if check_eNB: - p = Process(target = RAN.CheckeNBProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - if check_OAI_UE: - p = Process(target = self.CheckOAIUEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - return -15 - else: - result = 0 - while (not status_queue.empty()): - status = status_queue.get() - if (status < 0): - result = status - if result == CONST.ENB_PROCESS_FAILED: - fileCheck = re.search('enb_', str(RAN.GeteNBLogFiles[0])) - if fileCheck is not None: - SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') - logStatus = self.AnalyzeLogFile_eNB(RAN.GeteNBLogFiles[0]) - if logStatus < 0: - result = logStatus - RAN.SeteNBLogFiles[0] = '' - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.TerminateFlexranCtrl() - return result - - def CheckOAIUEProcessExist(self, initialize_OAI_UE_flag): - multi_jobs = [] - status_queue = SimpleQueue() - if initialize_OAI_UE_flag == False: - p = Process(target = self.CheckOAIUEProcess, args = (status_queue,)) - p.daemon = True - p.start() - multi_jobs.append(p) - for job in multi_jobs: - job.join() - - if (status_queue.empty()): - return -15 - else: - result = 0 - while (not status_queue.empty()): - status = status_queue.get() - if (status < 0): - result = status - if result == CONST.OAI_UE_PROCESS_FAILED: - fileCheck = re.search('ue_', str(self.UELogFile)) - if fileCheck is not None: - SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') - logStatus = self.AnalyzeLogFile_UE(self.UELogFile) - if logStatus < 0: - result = logStatus - return result - - def CheckOAIUEProcess(self, status_queue): - try: - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('stdbuf -o0 ps -aux | grep --color=never ' + RAN.Getair_interface() + '-uesoftmodem | grep -v grep', '\$', 5) - result = re.search(RAN.Getair_interface() + '-uesoftmodem', SSH.getBefore()) - if result is None: - logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') - status_queue.put(CONST.OAI_UE_PROCESS_FAILED) - else: - status_queue.put(CONST.OAI_UE_PROCESS_OK) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - -# def AnalyzeLogFile_eNB(self, eNBlogFile): -# ... - - def AnalyzeLogFile_UE(self, UElogFile): - if (not os.path.isfile('./' + UElogFile)): - return -1 - ue_log_file = open('./' + UElogFile, 'r') - exitSignalReceived = False - foundAssertion = False - msgAssertion = '' - msgLine = 0 - foundSegFault = False - foundRealTimeIssue = False - uciStatMsgCount = 0 - pdcpDataReqFailedCount = 0 - badDciCount = 0 - f1aRetransmissionCount = 0 - fatalErrorCount = 0 - macBsrTimerExpiredCount = 0 - rrcConnectionRecfgComplete = 0 - no_cell_sync_found = False - mib_found = False - frequency_found = False - plmn_found = False - nrUEFlag = False - nrDecodeMib = 0 - nrFoundDCI = 0 - nrCRCOK = 0 - mbms_messages = 0 - self.htmlUEFailureMsg = '' - for line in ue_log_file.readlines(): - result = re.search('nr_synchro_time', str(line)) - if result is not None: - nrUEFlag = True - if nrUEFlag: - result = re.search('decode mib', str(line)) - if result is not None: - nrDecodeMib += 1 - result = re.search('found 1 DCIs', str(line)) - if result is not None: - nrFoundDCI += 1 - result = re.search('CRC OK', str(line)) - if result is not None: - nrCRCOK += 1 - result = re.search('Exiting OAI softmodem', str(line)) - if result is not None: - exitSignalReceived = True - result = re.search('System error|[Ss]egmentation [Ff]ault|======= Backtrace: =========|======= Memory map: ========', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Cc]ore [dD]ump', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('./lte-uesoftmodem', str(line)) - if result is not None and not exitSignalReceived: - foundSegFault = True - result = re.search('[Aa]ssertion', str(line)) - if result is not None and not exitSignalReceived: - foundAssertion = True - result = re.search('LLL', str(line)) - if result is not None and not exitSignalReceived: - foundRealTimeIssue = True - if foundAssertion and (msgLine < 3): - msgLine += 1 - msgAssertion += str(line) - result = re.search('uci->stat', str(line)) - if result is not None and not exitSignalReceived: - uciStatMsgCount += 1 - result = re.search('PDCP data request failed', str(line)) - if result is not None and not exitSignalReceived: - pdcpDataReqFailedCount += 1 - result = re.search('bad DCI 1', str(line)) - if result is not None and not exitSignalReceived: - badDciCount += 1 - result = re.search('Format1A Retransmission but TBS are different', str(line)) - if result is not None and not exitSignalReceived: - f1aRetransmissionCount += 1 - result = re.search('FATAL ERROR', str(line)) - if result is not None and not exitSignalReceived: - fatalErrorCount += 1 - result = re.search('MAC BSR Triggered ReTxBSR Timer expiry', str(line)) - if result is not None and not exitSignalReceived: - macBsrTimerExpiredCount += 1 - result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) - if result is not None: - rrcConnectionRecfgComplete += 1 - # No cell synchronization found, abandoning - result = re.search('No cell synchronization found, abandoning', str(line)) - if result is not None: - no_cell_sync_found = True - if RAN.GeteNBmbmsEnables[0]: - result = re.search('TRIED TO PUSH MBMS DATA', str(line)) - if result is not None: - mbms_messages += 1 - result = re.search("MIB Information => ([a-zA-Z]{1,10}), ([a-zA-Z]{1,10}), NidCell (?P\d{1,3}), N_RB_DL (?P\d{1,3}), PHICH DURATION (?P\d), PHICH RESOURCE (?P.{1,4}), TX_ANT (?P\d)", str(line)) - if result is not None and (not mib_found): - try: - mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " nidcell = " + result.group('nidcell') - self.htmlUEFailureMsg += mibMsg - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " n_rb_dl = " + result.group('n_rb_dl') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " phich_duration = " + result.group('phich_duration') - self.htmlUEFailureMsg += mibMsg - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " phich_resource = " + result.group('phich_resource') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mibMsg = " tx_ant = " + result.group('tx_ant') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - mib_found = True - except Exception as e: - logging.error('\033[91m' + "MIB marker was not found" + '\033[0m') - result = re.search("Measured Carrier Frequency (?P\d{1,15}) Hz", str(line)) - if result is not None and (not frequency_found): - try: - mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - frequency_found = True - except Exception as e: - logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') - result = re.search("PLMN MCC (?P\d{1,3}), MNC (?P\d{1,3}), TAC", str(line)) - if result is not None and (not plmn_found): - try: - mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - plmn_found = True - except Exception as e: - logging.error('\033[91m' + "PLMN not found" + '\033[0m') - result = re.search("Found (?P[\w,\s]{1,15}) \(name from internal table\)", str(line)) - if result is not None: - try: - mibMsg = "The operator is: " + result.group('operator') - self.htmlUEFailureMsg += mibMsg + '\n' - logging.debug('\033[94m' + mibMsg + '\033[0m') - except Exception as e: - logging.error('\033[91m' + "Operator name not found" + '\033[0m') - result = re.search("SIB5 InterFreqCarrierFreq element (.{1,4})/(.{1,4})", str(line)) - if result is not None: - try: - mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) - self.htmlUEFailureMsg += mibMsg + ' -> ' - logging.debug('\033[94m' + mibMsg + '\033[0m') - except Exception as e: - logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') - result = re.search("DL Carrier Frequency/ARFCN : (?P\d{1,15}/\d{1,4})", str(line)) - if result is not None: - try: - freq = result.group('carrier_frequency') - new_freq = re.sub('/[0-9]+','',freq) - float_freq = float(new_freq) / 1000000 - self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' - logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') - except Exception as e: - logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') - result = re.search("AllowedMeasBandwidth : (?P\d{1,7})", str(line)) - if result is not None: - try: - prb = result.group('allowed_bandwidth') - self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' - logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') - except Exception as e: - logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') - ue_log_file.close() - if rrcConnectionRecfgComplete > 0: - statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' - logging.debug('\033[94m' + statMsg + '\033[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if nrUEFlag: - if nrDecodeMib > 0: - statMsg = 'UE showed ' + str(nrDecodeMib) + ' MIB decode message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if nrFoundDCI > 0: - statMsg = 'UE showed ' + str(nrFoundDCI) + ' DCI found message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if nrCRCOK > 0: - statMsg = 'UE showed ' + str(nrCRCOK) + ' PDSCH decoding message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if not frequency_found: - statMsg = 'NR-UE could NOT synch!' - logging.error('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if uciStatMsgCount > 0: - statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if pdcpDataReqFailedCount > 0: - statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if badDciCount > 0: - statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1(A)" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if f1aRetransmissionCount > 0: - statMsg = 'UE showed ' + str(f1aRetransmissionCount) + ' "Format1A Retransmission but TBS are different" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if fatalErrorCount > 0: - statMsg = 'UE showed ' + str(fatalErrorCount) + ' "FATAL ERROR:" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if macBsrTimerExpiredCount > 0: - statMsg = 'UE showed ' + str(fatalErrorCount) + ' "MAC BSR Triggered ReTxBSR Timer expiry" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if RAN.GeteNBmbmsEnables[0]: - if mbms_messages > 0: - statMsg = 'UE showed ' + str(mbms_messages) + ' "TRIED TO PUSH MBMS DATA" message(s)' - logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - else: - statMsg = 'UE did NOT SHOW "TRIED TO PUSH MBMS DATA" message(s)' - logging.debug('\u001B[1;30;41m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' - if foundSegFault: - logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') - if not nrUEFlag: - return CONST.OAI_UE_PROCESS_SEG_FAULT - else: - if not frequency_found: - return CONST.OAI_UE_PROCESS_SEG_FAULT - if foundAssertion: - logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') - self.htmlUEFailureMsg += 'UE showed an assertion!\n' - if not nrUEFlag: - if not mib_found or not frequency_found: - return CONST.OAI_UE_PROCESS_ASSERTION - else: - if not frequency_found: - return CONST.OAI_UE_PROCESS_ASSERTION - if foundRealTimeIssue: - logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') - self.htmlUEFailureMsg += 'UE faced real time issues!\n' - #return CONST.ENB_PROCESS_REALTIME_ISSUE - if nrUEFlag: - if not frequency_found: - return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC - else: - if no_cell_sync_found and not mib_found: - logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') - self.htmlUEFailureMsg += 'UE could not synchronize!\n' - return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC - return 0 - - - def TerminateFlexranCtrl(self): - if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: - return - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) - time.sleep(1) - SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) - time.sleep(1) - SSH.close() - self.flexranCtrlStarted = False - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def TerminateUE_common(self, device_id, idx): - try: - SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) - # back in airplane mode on (ie radio off) - if self.ADBCentralized: - if device_id == '84B7N16418004022': - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60) - else: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' ' + self.UEDevicesOffCmd[idx], '\$', 60) - logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m') - - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"', '\$', 5) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "ps | grep --color=never iperf | grep -v grep"\'', '\$', 60) - result = re.search('shell +(?P\d+)', SSH.getBefore()) - if result is not None: - pid_iperf = result.group('pid') - if self.ADBCentralized: - SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"', '\$', 5) - else: - SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "kill -KILL ' + pid_iperf + '"\'', '\$', 60) - SSH.close() - except: - os.kill(os.getppid(),signal.SIGUSR1) - - def TerminateUE(self): - terminate_ue_flag = False - self.GetAllUEDevices(terminate_ue_flag) - multi_jobs = [] - i = 0 - for device_id in self.UEDevices: - p = Process(target= self.TerminateUE_common, args = (device_id,i,)) - p.daemon = True - p.start() - multi_jobs.append(p) - i += 1 - for job in multi_jobs: - job.join() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def TerminateOAIUE(self): - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) - SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('-uesoftmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT -r .*-uesoftmodem || true', '\$', 5) - time.sleep(10) - SSH.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('-uesoftmodem', SSH.getBefore()) - if result is not None: - SSH.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL -r .*-uesoftmodem || true', '\$', 5) - time.sleep(5) - SSH.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - SSH.close() - result = re.search('ue_', str(self.UELogFile)) - if result is not None: - copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') - self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') - self.UELogFile = '' - return - logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_UE(self.UELogFile) - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is not None: - ueAction = 'Sniffing' - else: - ueAction = 'Connection' - if (logStatus < 0): - logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg - HTML.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') - if RAN.Getair_interface() == 'lte': - # In case of sniffing on commercial eNBs we have random results - # Not an error then - if (logStatus != CONST.OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): - self.Initialize_OAI_UE_args = '' - self.AutoTerminateUEandeNB() - else: - if (logStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC): - self.Initialize_OAI_UE_args = '' - self.AutoTerminateUEandeNB() - else: - logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - self.UELogFile = '' - else: - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - - def AutoTerminateUEandeNB(self): - if (self.ADBIPAddress != 'none'): - self.testCase_id = 'AUTO-KILL-UE' - RAN.SettestCase_id(self.testCase_id) - self.desc = 'Automatic Termination of UE' - self.ShowTestID() - self.TerminateUE() - if (self.Initialize_OAI_UE_args != ''): - self.testCase_id = 'AUTO-KILL-UE' - RAN.SettestCase_id(self.testCase_id) - self.desc = 'Automatic Termination of UE' - self.ShowTestID() - self.TerminateOAIUE() - if (RAN.GetInitialize_eNB_args() != ''): - self.testCase_id = 'AUTO-KILL-eNB' - RAN.SettestCase_id(self.testCase_id) - self.desc = 'Automatic Termination of eNB' - self.ShowTestID() - RAN.SeteNB_instance('0') - RAN.TerminateeNB() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: - self.testCase_id = 'AUTO-KILL-flexran-ctl' - RAN.SettestCase_id(self.testCase_id) - self.desc = 'Automatic Termination of FlexRan CTL' - self.ShowTestID() - self.TerminateFlexranCtrl() - RAN.SetprematureExit(True) - - def IdleSleep(self): - time.sleep(self.idle_sleep_time) - HTML.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', CONST.ALL_PROCESSES_OK) - - def X2_Status(self, idx, fileName): - cmd = "curl --silent http://" + EPC.GetIPAddress() + ":9999/stats | jq '.' > " + fileName - message = cmd + '\n' - logging.debug(cmd) - subprocess.run(cmd, shell=True) - if idx == 0: - cmd = "jq '.mac_stats | length' " + fileName - strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2NbENBs = int(strNbEnbs.strip()) - cnt = 0 - while cnt < self.x2NbENBs: - cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName - bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBBsIds[idx].append(bs_id.strip()) - cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName - stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True) - nbUEs = int(stNbUEs.strip()) - ueIdx = 0 - self.x2ENBConnectedUEs[idx].append([]) - while ueIdx < nbUEs: - cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName - rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True) - self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip()) - ueIdx += 1 - cnt += 1 - - msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)" - logging.debug(msg) - message += msg + '\n' - cnt = 0 - while cnt < self.x2NbENBs: - msg = " -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][cnt])) + " UE(s)" - logging.debug(msg) - message += msg + '\n' - ueIdx = 0 - while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]): - msg = " -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx]) - logging.debug(msg) - message += msg + '\n' - ueIdx += 1 - cnt += 1 - return message - - def Perform_X2_Handover(self): - html_queue = SimpleQueue() - fullMessage = '
'
-		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
-		logging.debug(msg)
-		fullMessage += msg + '\n'
-		if self.x2_ho_options == 'network':
-			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
-				self.x2ENBBsIds = []
-				self.x2ENBConnectedUEs = []
-				self.x2ENBBsIds.append([])
-				self.x2ENBBsIds.append([])
-				self.x2ENBConnectedUEs.append([])
-				self.x2ENBConnectedUEs.append([])
-				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
-
-				msg = "Activating the X2 Net control on each eNB"
-				logging.debug(msg)
-				fullMessage += msg + '\n'
-				eNB_cnt = self.x2NbENBs
-				cnt = 0
-				while cnt < eNB_cnt:
-					cmd = "curl -XPOST http://" + EPC.GetIPAddress() + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1"
-					logging.debug(cmd)
-					fullMessage += cmd + '\n'
-					subprocess.run(cmd, shell=True)
-					cnt += 1
-				# Waiting for the activation to be active
-				time.sleep(10)
-				msg = "Switching UE(s) from eNB to eNB"
-				logging.debug(msg)
-				fullMessage += msg + '\n'
-				cnt = 0
-				while cnt < eNB_cnt:
-					ueIdx = 0
-					while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]):
-						cmd = "curl -XPOST http://" + EPC.GetIPAddress() + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
-						logging.debug(cmd)
-						fullMessage += cmd + '\n'
-						subprocess.run(cmd, shell=True)
-						ueIdx += 1
-					cnt += 1
-				time.sleep(10)
-				# check
-				logging.debug("Checking the Status after X2 Handover")
-				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
-				cnt = 0
-				x2Status = True
-				while cnt < eNB_cnt:
-					if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
-						x2Status = False
-					cnt += 1
-				if x2Status:
-					msg = "X2 Handover was successful"
-					logging.debug(msg)
-					fullMessage += msg + '
' - html_queue.put(fullMessage) - HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - else: - msg = "X2 Handover FAILED" - logging.error(msg) - fullMessage += msg + '' - html_queue.put(fullMessage) - HTML.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue) - else: - HTML.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', CONST.ALL_PROCESSES_OK) - - def LogCollectBuild(self): - if (RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != ''): - IPAddress = RAN.GeteNBIPAddress() - UserName = RAN.GeteNBUserName() - Password = RAN.GeteNBPassword() - SourceCodePath = RAN.GeteNBSourceCodePath() - elif (self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != ''): - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - SourceCodePath = self.UESourceCodePath - else: - sys.exit('Insufficient Parameter') - SSH.open(IPAddress, UserName, Password) - SSH.command('cd ' + SourceCodePath, '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('rm -f build.log.zip', '\$', 5) - SSH.command('zip build.log.zip build_log_*/*', '\$', 60) - SSH.close() - def LogCollectPing(self): - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) - SSH.command('cd scripts', '\$', 5) - SSH.command('rm -f ping.log.zip', '\$', 5) - SSH.command('zip ping.log.zip ping*.log', '\$', 60) - SSH.command('rm ping*.log', '\$', 5) - SSH.close() - - def LogCollectIperf(self): - SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) - SSH.command('cd ' + EPC.GetSourceCodePath(), '\$', 5) - SSH.command('cd scripts', '\$', 5) - SSH.command('rm -f iperf.log.zip', '\$', 5) - SSH.command('zip iperf.log.zip iperf*.log', '\$', 60) - SSH.command('rm iperf*.log', '\$', 5) - SSH.close() - - def LogCollectOAIUE(self): - SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - SSH.command('cd ' + self.UESourceCodePath, '\$', 5) - SSH.command('cd cmake_targets', '\$', 5) - SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -f ue.log.zip', '\$', 5) - SSH.command('echo ' + self.UEPassword + ' | sudo -S zip ue.log.zip ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 60) - SSH.command('echo ' + self.UEPassword + ' | sudo -S rm ue*.log core* ue_*record.raw ue_*.pcap ue_*txt', '\$', 5) - SSH.close() - - def RetrieveSystemVersion(self, machine): - if RAN.GeteNBIPAddress() == 'none' or self.UEIPAddress == 'none': - self.OsVersion = 'Ubuntu 16.04.5 LTS' - self.KernelVersion = '4.15.0-45-generic' - self.UhdVersion = '3.13.0.1-0' - self.UsrpBoard = 'B210' - self.CpuNb = '4' - self.CpuModel = 'Intel(R) Core(TM) i5-6200U' - self.CpuMHz = '2399.996 MHz' - return 0 - if machine == 'eNB': - if RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != '': - IPAddress = RAN.GeteNBIPAddress() - UserName = RAN.GeteNBUserName() - Password = RAN.GeteNBPassword() - else: - return -1 - if machine == 'UE': - if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - else: - return -1 - - SSH.open(IPAddress, UserName, Password) - SSH.command('lsb_release -a', '\$', 5) - result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) - if result is not None: - self.OsVersion = result.group('os_type') - logging.debug('OS is: ' + self.OsVersion) - else: - SSH.command('hostnamectl', '\$', 5) - result = re.search('Operating System: (?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) - if result is not None: - self.OsVersion = result.group('os_type') - if self.OsVersion == 'CentOS Linux 7 ': - SSH.command('cat /etc/redhat-release', '\$', 5) - result = re.search('CentOS Linux release (?P[0-9\.]+)', SSH.getBefore()) - if result is not None: - self.OsVersion = self.OsVersion.replace('7 ', result.group('os_version')) - logging.debug('OS is: ' + self.OsVersion) - SSH.command('uname -r', '\$', 5) - result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', SSH.getBefore()) - if result is not None: - self.KernelVersion = result.group('kernel_version') - logging.debug('Kernel Version is: ' + self.KernelVersion) - SSH.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) - result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', SSH.getBefore()) - if result is not None: - self.UhdVersion = result.group('uhd_version') - logging.debug('UHD Version is: ' + self.UhdVersion) - else: - SSH.command('uhd_config_info --version', '\$', 5) - result = re.search('UHD (?P[a-zA-Z0-9\.\-]+)', SSH.getBefore()) - if result is not None: - self.UhdVersion = result.group('uhd_version') - logging.debug('UHD Version is: ' + self.UhdVersion) - SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 30) - usrp_boards = re.findall('product: ([0-9A-Za-z]+)\\\\r\\\\n', SSH.getBefore()) - count = 0 - for board in usrp_boards: - if count == 0: - self.UsrpBoard = board - else: - self.UsrpBoard += ',' + board - count += 1 - if count > 0: - logging.debug('USRP Board(s) : ' + self.UsrpBoard) - SSH.command('lscpu', '\$', 5) - result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', SSH.getBefore()) - if result is not None: - self.CpuNb = result.group('nb_cpus') - logging.debug('nb_cpus: ' + self.CpuNb) - self.CpuModel = result.group('model') - logging.debug('model: ' + self.CpuModel) - self.CpuMHz = result.group('cpu_mhz') + ' MHz' - logging.debug('cpu_mhz: ' + self.CpuMHz) - SSH.close() - -#----------------------------------------------------------- -# ShowTestID() -#----------------------------------------------------------- - def ShowTestID(self): - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - logging.debug('\u001B[1mTest ID:' + self.testCase_id + '\u001B[0m') - logging.debug('\u001B[1m' + self.desc + '\u001B[0m') - logging.debug('\u001B[1m----------------------------------------\u001B[0m') - -def CheckClassValidity(action,id): - if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover': - logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) - return False - return True - -def GetParametersFromXML(action): - if action == 'Build_eNB': - RAN.SetBuild_eNB_args(test.findtext('Build_eNB_args')) - forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') - if (forced_workspace_cleanup is None): - RAN.SetBuild_eNB_forced_workspace_cleanup(False) - else: - if re.match('true', forced_workspace_cleanup, re.IGNORECASE): - RAN.SetBuild_eNB_forced_workspace_cleanup(True) - else: - RAN.SetBuild_eNB_forced_workspace_cleanup(False) - RAN.SeteNB_instance(test.findtext('eNB_instance')) - if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance('0') - RAN.SeteNB_serverId(test.findtext('eNB_serverId')) - if (RAN.GeteNB_serverId() is None): - RAN.SeteNB_serverId('0') - xmlBgBuildField = test.findtext('backgroundBuild') - if (xmlBgBuildField is None): - RAN.SetbackgroundBuild(False) - else: - if re.match('true', xmlBgBuildField, re.IGNORECASE): - RAN.SetbackgroundBuild(True) - else: - RAN.SetbackgroundBuild(False) - - if action == 'WaitEndBuild_eNB': - RAN.SetBuild_eNB_args(test.findtext('Build_eNB_args')) - RAN.SeteNB_instance(test.findtext('eNB_instance')) - if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance('0') - RAN.SeteNB_serverId(test.findtext('eNB_serverId')) - if (RAN.GeteNB_serverId() is None): - RAN.SeteNB_serverId('0') - - if action == 'Initialize_eNB': - RAN.SetInitialize_eNB_args(test.findtext('Initialize_eNB_args')) - RAN.SeteNB_instance(test.findtext('eNB_instance')) - if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance('0') - RAN.SeteNB_serverId(test.findtext('eNB_serverId')) - if (RAN.GeteNB_serverId() is None): - RAN.SeteNB_serverId('0') - CiTestObj.air_interface = test.findtext('air_interface') - if (CiTestObj.air_interface is None): - CiTestObj.air_interface = 'lte' - else: - CiTestObj.air_interface = CiTestObj.air_interface.lower() - - if action == 'Terminate_eNB': - RAN.SeteNB_instance(test.findtext('eNB_instance')) - if (RAN.GeteNB_instance() is None): - RAN.SeteNB_instance('0') - RAN.SeteNB_serverId(test.findtext('eNB_serverId')) - if (RAN.GeteNB_serverId() is None): - RAN.SeteNB_serverId('0') - CiTestObj.air_interface = test.findtext('air_interface') - if (CiTestObj.air_interface is None): - CiTestObj.air_interface = 'lte' - else: - CiTestObj.air_interface = CiTestObj.air_interface.lower() - - if action == 'Attach_UE': - nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') - if (nbMaxUEtoAttach is None): - CiTestObj.nbMaxUEtoAttach = -1 - else: - CiTestObj.nbMaxUEtoAttach = int(nbMaxUEtoAttach) - - if action == 'CheckStatusUE': - expectedNBUE = test.findtext('expectedNbOfConnectedUEs') - if (expectedNBUE is None): - CiTestObj.expectedNbOfConnectedUEs = -1 - else: - CiTestObj.expectedNbOfConnectedUEs = int(expectedNBUE) - - if action == 'Build_OAI_UE': - CiTestObj.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') - CiTestObj.clean_repository = test.findtext('clean_repository') - if (CiTestObj.clean_repository == 'false'): - CiTestObj.clean_repository = False - else: - CiTestObj.clean_repository = True - - if action == 'Initialize_OAI_UE': - CiTestObj.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') - CiTestObj.UE_instance = test.findtext('UE_instance') - if (CiTestObj.UE_instance is None): - CiTestObj.UE_instance = '0' - CiTestObj.air_interface = test.findtext('air_interface') - if (CiTestObj.air_interface is None): - CiTestObj.air_interface = 'lte' - else: - CiTestObj.air_interface = SSH.air_interface.lower() - - if action == 'Terminate_OAI_UE': - RAN.SeteNB_instance(test.findtext('UE_instance')) - if (CiTestObj.UE_instance is None): - CiTestObj.UE_instance = '0' - - if action == 'Ping' or action == 'Ping_CatM_module': - CiTestObj.ping_args = test.findtext('ping_args') - CiTestObj.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold') - - if action == 'Iperf': - CiTestObj.iperf_args = test.findtext('iperf_args') - CiTestObj.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold') - CiTestObj.iperf_profile = test.findtext('iperf_profile') - if (CiTestObj.iperf_profile is None): - CiTestObj.iperf_profile = 'balanced' - else: - if CiTestObj.iperf_profile != 'balanced' and CiTestObj.iperf_profile != 'unbalanced' and CiTestObj.iperf_profile != 'single-ue': - logging.debug('ERROR: test-case has wrong profile ' + CiTestObj.iperf_profile) - CiTestObj.iperf_profile = 'balanced' - CiTestObj.iperf_options = test.findtext('iperf_options') - if (CiTestObj.iperf_options is None): - CiTestObj.iperf_options = 'check' - else: - if CiTestObj.iperf_options != 'check' and CiTestObj.iperf_options != 'sink': - logging.debug('ERROR: test-case has wrong option ' + CiTestObj.iperf_options) - CiTestObj.iperf_options = 'check' - - if action == 'IdleSleep': - string_field = test.findtext('idle_sleep_time_in_sec') - if (string_field is None): - CiTestObj.idle_sleep_time = 5 - else: - CiTestObj.idle_sleep_time = int(string_field) - - if action == 'Perform_X2_Handover': - string_field = test.findtext('x2_ho_options') - if (string_field is None): - CiTestObj.x2_ho_options = 'network' - else: - if string_field != 'network': - logging.error('ERROR: test-case has wrong option ' + string_field) - CiTestObj.x2_ho_options = 'network' - else: - CiTestObj.x2_ho_options = string_field - - -#check if given test is in list -#it is in list if one of the strings in 'list' is at the beginning of 'test' -def test_in_list(test, list): - for check in list: - check=check.replace('+','') - if (test.startswith(check)): - return True - return False - -def receive_signal(signum, frame): - sys.exit(1) - -#----------------------------------------------------------- -# Parameter Check -#----------------------------------------------------------- -mode = '' -CiTestObj = OaiCiTest() - -import sshconnection -import epc -import helpreadme -import ran -import html -import constants - -SSH = sshconnection.SSHConnection() -EPC = epc.EPCManagement() -RAN = ran.RANManagement() -HTML = html.HTMLManagement() - - -argvs = sys.argv -argc = len(argvs) -cwd = os.getcwd() - -while len(argvs) > 1: - myArgv = argvs.pop(1) # 0th is this file's name - - if re.match('^\-\-help$', myArgv, re.IGNORECASE): - GenericHelp(Version) - sys.exit(0) - elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) - mode = matchReg.group(1) - elif re.match('^\-\-eNBRepository=(.+)$|^\-\-ranRepository(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) - RAN.SetranRepository(matchReg.group(1)) - HTML.SetranRepository(matchReg.group(1)) - elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) - doMerge = matchReg.group(1) - if ((doMerge == 'true') or (doMerge == 'True')): - RAN.SetranAllowMerge(True) - HTML.SetranAllowMerge(True) - elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) - RAN.SetranBranch(matchReg.group(1)) - HTML.SetranBranch(matchReg.group(1)) - elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) - RAN.SetranCommitID(matchReg.group(1)) - HTML.SetranCommitID(matchReg.group(1)) - elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) - else: - matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) - RAN.SetranTargetBranch(matchReg.group(1)) - elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBIPAddress(matchReg.group(1)) - elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1IPAddress(matchReg.group(1)) - elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2IPAddress(matchReg.group(1)) - elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBUserName(matchReg.group(1)) - elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1UserName(matchReg.group(1)) - elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2UserName(matchReg.group(1)) - elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBPassword(matchReg.group(1)) - elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1Password(matchReg.group(1)) - elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2Password(matchReg.group(1)) - elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNBSourceCodePath(matchReg.group(1)) - elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB1SourceCodePath(matchReg.group(1)) - elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.SeteNB2SourceCodePath(matchReg.group(1)) - elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) - EPC.SetIPAddress(matchReg.group(1)) -#GP250220: do we still need EPCBranch? it's not used anywhere - elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.EPCBranch = matchReg.group(1) - elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) - EPC.SetUserName(matchReg.group(1)) - elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) - EPC.SetPassword(matchReg.group(1)) - elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) - EPC.SetSourceCodePath(matchReg.group(1)) - elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) - if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): - EPC.SetType(matchReg.group(1)) - else: - sys.exit('Invalid EPC Type: ' + matchReg.group(1) + ' -- (should be OAI or ltebox or OAI-Rel14-CUPS)') - elif re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBIPAddress=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.ADBIPAddress = matchReg.group(1) - elif re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBUserName=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.ADBUserName = matchReg.group(1) - elif re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBType=(.+)$', myArgv, re.IGNORECASE) - if re.match('centralized', matchReg.group(1), re.IGNORECASE) or re.match('distributed', matchReg.group(1), re.IGNORECASE): - if re.match('distributed', matchReg.group(1), re.IGNORECASE): - CiTestObj.ADBCentralized = False - else: - CiTestObj.ADBCentralized = True - else: - sys.exit('Invalid ADB Type: ' + matchReg.group(1) + ' -- (should be centralized or distributed)') - elif re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-ADBPassword=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.ADBPassword = matchReg.group(1) - elif re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.testXMLfiles.append(matchReg.group(1)) - HTML.SettestXMLfiles(matchReg.group(1)) - CiTestObj.nbTestXMLfiles += 1 - elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.UEIPAddress = matchReg.group(1) - elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.UEUserName = matchReg.group(1) - elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.UEPassword = matchReg.group(1) - elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.UESourceCodePath = matchReg.group(1) - elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) - finalStatus = matchReg.group(1) - if ((finalStatus == 'true') or (finalStatus == 'True')): - CiTestObj.finalStatus = True - else: - GenericHelp(Version) - sys.exit('Invalid Parameter: ' + myArgv) - -if re.match('^TerminateeNB$', mode, re.IGNORECASE): - if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - RAN.SeteNB_serverId('0') - RAN.SeteNB_instance('0') - RAN.SeteNBSourceCodePath('/tmp/') - CiTestObj.TerminateeNB() -elif re.match('^TerminateUE$', mode, re.IGNORECASE): - if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): - GenericHelp(Version) - sys.exit('Insufficient Parameter') - signal.signal(signal.SIGUSR1, receive_signal) - CiTestObj.TerminateUE() -elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): - if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - signal.signal(signal.SIGUSR1, receive_signal) - CiTestObj.TerminateOAIUE() -elif re.match('^TerminateHSS$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.TerminateHSS() -elif re.match('^TerminateMME$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.TerminateMME() -elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.TerminateSPGW() -elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): - if (RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.LogCollectBuild() -elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): - if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.LogCollecteNB() -elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - EPC.LogCollectHSS() -elif re.match('^LogCollectMME$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - EPC.LogCollectMME() -elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - EPC.LogCollectSPGW() -elif re.match('^LogCollectPing$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.LogCollectPing() -elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.LogCollectIperf() -elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): - if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': - GenericHelp(Version) - sys.exit('Insufficient Parameter') - CiTestObj.LogCollectOAIUE() -elif re.match('^InitiateHtml$', mode, re.IGNORECASE): - if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): - GenericHelp(Version) - sys.exit('Insufficient Parameter') - count = 0 - foundCount = 0 - while (count < CiTestObj.nbTestXMLfiles): - #xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[count] - xml_test_file = sys.path[0] + "/" + CiTestObj.testXMLfiles[count] - if (os.path.isfile(xml_test_file)): - try: - xmlTree = ET.parse(xml_test_file) - except: - print("Error while parsing file: " + xml_test_file) - xmlRoot = xmlTree.getroot() - HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - HTML.SethtmlTabIcons(xmlRoot.findtext('htmlTabIcon',default='info-sign')) - #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - #CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) - foundCount += 1 - count += 1 - if foundCount != CiTestObj.nbTestXMLfiles: - CiTestObj.nbTestXMLfiles = foundCount - HTML.SetnbTestXMLfiles(CiTestObj.nbTestXMLfiles) - - if (CiTestObj.ADBIPAddress != 'none'): - terminate_ue_flag = False - CiTestObj.GetAllUEDevices(terminate_ue_flag) - CiTestObj.GetAllCatMDevices(terminate_ue_flag) - HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices)) - HTML.SethtmlNb_Smartphones(len(CiTestObj.UEDevices)) - HTML.SethtmlNb_CATM_Modules(len(CiTestObj.CatMDevices)) - HTML.CreateHtmlHeader(CiTestObj.ADBIPAddress) -elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - HTML.SetreseNB(RetrieveSystemVersion('eNB')) - HTML.SetresUE(RetrieveSystemVersion('UE')) - HTML.CreateHtmlFooter(CiTestObj.finalStatus) -elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): - if re.match('^TesteNB$', mode, re.IGNORECASE): - if RAN.GeteNBIPAddress() == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': - GenericHelp(Version) - if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or EPC.GetType() == '': - EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) - if RAN.GetranRepository() == '': - GitSrvHelp(RAN.GetranRepository(),RAN.GetranBranch(),RAN.GetranCommitID(),RAN.GetranAllowMerge(),RAN.GetranTargetBranch()) - if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': - eNBSrvHelp(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath()) - sys.exit('Insufficient Parameter') - - if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/tcp_iperf_stats.awk", "/tmp") - SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/active_net_interfaces.awk", "/tmp") - else: - if CiTestObj.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': - GenericHelp(Version) - sys.exit('UE: Insufficient Parameter') - - #read test_case_list.xml file - # if no parameters for XML file, use default value - if (CiTestObj.nbTestXMLfiles != 1): - xml_test_file = cwd + "/test_case_list.xml" - else: - xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0] - - xmlTree = ET.parse(xml_test_file) - xmlRoot = xmlTree.getroot() - - exclusion_tests=xmlRoot.findtext('TestCaseExclusionList',default='') - requested_tests=xmlRoot.findtext('TestCaseRequestedList',default='') - if (CiTestObj.nbTestXMLfiles == 1): - HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabName',default='Test-0')) - #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) - repeatCount = xmlRoot.findtext('repeatCount',default='1') - CiTestObj.repeatCounts.append(int(repeatCount)) - all_tests=xmlRoot.findall('testCase') - - exclusion_tests=exclusion_tests.split() - requested_tests=requested_tests.split() - - #check that exclusion tests are well formatted - #(6 digits or less than 6 digits followed by +) - for test in exclusion_tests: - if (not re.match('^[0-9]{6}$', test) and - not re.match('^[0-9]{1,5}\+$', test)): - logging.debug('ERROR: exclusion test is invalidly formatted: ' + test) - sys.exit(1) - else: - logging.debug(test) - - #check that requested tests are well formatted - #(6 digits or less than 6 digits followed by +) - #be verbose - for test in requested_tests: - if (re.match('^[0-9]{6}$', test) or - re.match('^[0-9]{1,5}\+$', test)): - logging.debug('INFO: test group/case requested: ' + test) - else: - logging.debug('ERROR: requested test is invalidly formatted: ' + test) - sys.exit(1) - if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): - CiTestObj.CheckFlexranCtrlInstallation() - - #get the list of tests to be done - todo_tests=[] - for test in requested_tests: - if (test_in_list(test, exclusion_tests)): - logging.debug('INFO: test will be skipped: ' + test) - else: - #logging.debug('INFO: test will be run: ' + test) - todo_tests.append(test) - - signal.signal(signal.SIGUSR1, receive_signal) - - if (CiTestObj.ADBIPAddress != 'none'): - terminate_ue_flag = False - CiTestObj.GetAllUEDevices(terminate_ue_flag) - CiTestObj.GetAllCatMDevices(terminate_ue_flag) - else: - CiTestObj.UEDevices.append('OAI-UE') - HTML.SethtmlUEConnected(len(CiTestObj.UEDevices) + len(CiTestObj.CatMDevices)) - HTML.CreateHtmlTabHeader() - - CiTestObj.FailReportCnt = 0 - RAN.SetprematureExit(True) - CiTestObj.startTime = int(round(time.time() * 1000)) - HTML.SetstartTime(CiTestObj.startTime) - while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): - RAN.SetprematureExit(False) - # At every iteratin of the retry loop, a separator will be added - # pass CiTestObj.FailReportCnt as parameter of HTML.CreateHtmlRetrySeparator - HTML.CreateHtmlRetrySeparator(CiTestObj.FailReportCnt) - for test_case_id in todo_tests: - if RAN.GetprematureExit(): - break - for test in all_tests: - if RAN.GetprematureExit(): - break - id = test.get('id') - if test_case_id != id: - continue - CiTestObj.testCase_id = id - RAN.SettestCase_id(CiTestObj.testCase_id) - HTML.SettestCase_id(CiTestObj.testCase_id) - CiTestObj.desc = test.findtext('desc') - HTML.Setdesc(CiTestObj.desc) - action = test.findtext('class') - if (CheckClassValidity(action, id) == False): - continue - CiTestObj.ShowTestID() - GetParametersFromXML(action) - if action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Ping' or action == 'Iperf' or action == 'Reboot_UE' or action == 'DataDisable_UE' or action == 'DataEnable_UE' or action == 'CheckStatusUE': - if (CiTestObj.ADBIPAddress != 'none'): - terminate_ue_flag = False - CiTestObj.GetAllUEDevices(terminate_ue_flag) - if action == 'Build_eNB': - RAN.BuildeNB() - elif action == 'WaitEndBuild_eNB': - RAN.WaitBuildeNBisFinished() - elif action == 'Initialize_eNB': - check_eNB = False - check_OAI_UE = False - RAN.SetpStatus(CiTestObj.CheckProcessExist(check_eNB, check_OAI_UE)) - - RAN.InitializeeNB() - elif action == 'Terminate_eNB': - RAN.TerminateeNB() - elif action == 'Initialize_UE': - CiTestObj.InitializeUE() - elif action == 'Terminate_UE': - CiTestObj.TerminateUE() - elif action == 'Attach_UE': - CiTestObj.AttachUE() - elif action == 'Detach_UE': - CiTestObj.DetachUE() - elif action == 'DataDisable_UE': - CiTestObj.DataDisableUE() - elif action == 'DataEnable_UE': - CiTestObj.DataEnableUE() - elif action == 'CheckStatusUE': - CiTestObj.CheckStatusUE() - elif action == 'Build_OAI_UE': - CiTestObj.BuildOAIUE() - elif action == 'Initialize_OAI_UE': - CiTestObj.InitializeOAIUE() - elif action == 'Terminate_OAI_UE': - CiTestObj.TerminateOAIUE() - elif action == 'Initialize_CatM_module': - CiTestObj.InitializeCatM() - elif action == 'Terminate_CatM_module': - CiTestObj.TerminateCatM() - elif action == 'Attach_CatM_module': - CiTestObj.AttachCatM() - elif action == 'Detach_CatM_module': - CiTestObj.TerminateCatM() - elif action == 'Ping_CatM_module': - CiTestObj.PingCatM() - elif action == 'Ping': - CiTestObj.Ping() - elif action == 'Iperf': - CiTestObj.Iperf() - elif action == 'Reboot_UE': - CiTestObj.RebootUE() - elif action == 'Initialize_HSS': - EPC.InitializeHSS() - elif action == 'Terminate_HSS': - EPC.TerminateHSS() - elif action == 'Initialize_MME': - EPC.InitializeMME() - elif action == 'Terminate_MME': - EPC.TerminateMME() - elif action == 'Initialize_SPGW': - EPC.InitializeSPGW() - elif action == 'Terminate_SPGW': - EPC.TerminateSPGW() - elif action == 'Initialize_FlexranCtrl': - CiTestObj.InitializeFlexranCtrl() - elif action == 'Terminate_FlexranCtrl': - CiTestObj.TerminateFlexranCtrl() - elif action == 'IdleSleep': - CiTestObj.IdleSleep() - elif action == 'Perform_X2_Handover': - CiTestObj.Perform_X2_Handover() - else: - sys.exit('Invalid action') - CiTestObj.FailReportCnt += 1 - if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): - logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)') - HTML.CreateHtmlTabFooter(False) - sys.exit('Failed Scenario') - else: - logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') - HTML.CreateHtmlTabFooter(True) -else: - GenericHelp(Version) - sys.exit('Invalid mode') -sys.exit(0) From 9eab72b2bf8a78a86cb1f93194ae8450047f0760 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 6 Apr 2020 09:18:42 +0200 Subject: [PATCH 111/175] aligning remote repository with local on starsky --- ci-scripts/epc.py | 20 ++++++---- ci-scripts/html.py | 11 +++++- ci-scripts/main.py | 99 ++++++++++++++++++++-------------------------- ci-scripts/ran.py | 22 +++++------ 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 6c48dcd15d..c297b3e3b7 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -55,7 +55,7 @@ class EPCManagement(): def __init__(self): - self.IPAddress = '' + self.EPCIPAddress = '' self.UserName = '' self.Password = '' self.SourceCodePath = '' @@ -130,7 +130,8 @@ class EPCManagement(): else: logging.error('This option should not occur!') mySSH.close() - HTML.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) + myHTML = HTML.HTMLManagement() + myHTML.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) def InitializeMME(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': @@ -163,7 +164,8 @@ class EPCManagement(): else: logging.error('This option should not occur!') mySSH.close() - HTML.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + myHTML = HTML.HTMLManagement() + myHTML.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) def InitializeSPGW(self): if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '' or self.EPCType == '': @@ -194,7 +196,8 @@ class EPCManagement(): else: logging.error('This option should not occur!') mySSH.close() - HTML.CreateHtmlTestRow(self.EPCType, 'OK', ALL_PROCESSES_OK) + myHTML = HTML.HTMLManagement() + myHTML.CreateHtmlTestRow(self.EPCType, 'OK', CONST.ALL_PROCESSES_OK) def CheckHSSProcess(self, status_queue): @@ -294,7 +297,8 @@ class EPCManagement(): else: logging.error('This should not happen!') mySSH.close() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + myHTML = HTML.HTMLManagement() + myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateMME(self): mySSH = SSH.SSHConnection() @@ -313,7 +317,8 @@ class EPCManagement(): else: logging.error('This should not happen!') mySSH.close() - HTML.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) + myHTML = HTML.HTMLManagement() + myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateSPGW(self): mySSH = SSH.SSHConnection() @@ -344,7 +349,8 @@ class EPCManagement(): else: logging.error('This should not happen!') mySSH.close() - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + myHTML = HTML.HTMLManagement() + myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def LogCollectHSS(self): diff --git a/ci-scripts/html.py b/ci-scripts/html.py index ccd89eb577..15acafd2ed 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -45,7 +45,8 @@ from multiprocessing import Process, Lock, SimpleQueue class HTMLManagement(): def __init__(self): - + + self.htmlFile = '' self.htmlHeaderCreated = False self.htmlFooterCreated = False self.ranAllowMerge = False @@ -54,10 +55,18 @@ class HTMLManagement(): self.htmlTabNames = [] self.htmlTabIcons = [] self.testXMLfiles = [] + self.htmleNBFailureMsg = '' + self.htmlUEFailureMsg = '' #----------------------------------------------------------- # Setters and Getters #----------------------------------------------------------- + def SethtmlUEFailureMsg(self,huefa): + self.htmlUEFailureMsg = huefa + def GethtmlUEFailureMsg(self): + return huefa + + def SetreseNB(self,rsenb): self.reseNB = rsenb def SetresUE(self,rsue): diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 1dd8402250..2c59b09f60 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -68,7 +68,6 @@ class OaiCiTest(): self.ADBCentralized = True self.testCase_id = '' self.testXMLfiles = [] - #self.nbTestXMLfiles = 0 self.desc = '' self.ping_args = '' self.ping_packetloss_threshold = '' @@ -86,12 +85,7 @@ class OaiCiTest(): self.UEDevicesRebootCmd = [] self.CatMDevices = [] self.UEIPAddresses = [] - self.htmlFile = '' - # self.htmlHeaderCreated = False - # self.htmlFooterCreated = False self.htmlUEConnected = -1 - self.htmleNBFailureMsg = '' - self.htmlUEFailureMsg = '' self.picocom_closure = False self.idle_sleep_time = 0 self.x2_ho_options = 'network' @@ -116,8 +110,6 @@ class OaiCiTest(): self.Build_OAI_UE_args = '' self.Initialize_OAI_UE_args = '' self.clean_repository = True - self.flexranCtrlInstalled = False - self.flexranCtrlStarted = False self.expectedNbOfConnectedUEs = 0 self.startTime = 0 @@ -232,13 +224,12 @@ class OaiCiTest(): SSH.command('ls -ls /opt/flexran_rtc/*/rt_controller', '\$', 5) result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore()) if result is not None: - self.flexranCtrlInstalled = True RAN.SetflexranCtrlInstalled(True) logging.debug('Flexran Controller is installed') SSH.close() def InitializeFlexranCtrl(self): - if self.flexranCtrlInstalled == False: + if RAN.GetflexranCtrlInstalled() == False: return if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': GenericHelp(Version) @@ -253,7 +244,6 @@ class OaiCiTest(): result = re.search('rt_controller -c ', SSH.getBefore()) if result is not None: logging.debug('\u001B[1m Initialize FlexRan Controller Completed\u001B[0m') - self.flexranCtrlStarted = True RAN.SetflexranCtrlStarted(True) SSH.close() HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) @@ -487,12 +477,12 @@ class OaiCiTest(): else: if RAN.Getair_interface() == 'lte': if RAN.GeteNBmbmsEnables[0]: - self.htmlUEFailureMsg = 'oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured' + HTML.SethtmlUEFailureMsg('oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured') else: - self.htmlUEFailureMsg = 'oaitun_ue1 interface is either NOT mounted or NOT configured' + HTML.SethtmlUEFailureMsg('oaitun_ue1 interface is either NOT mounted or NOT configured') HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_NO_TUNNEL_INTERFACE, 'OAI UE') else: - self.htmlUEFailureMsg = 'nr-uesoftmodem did NOT synced' + HTML.SethtmlUEFailureMsg('nr-uesoftmodem did NOT synced') HTML.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE') logging.error('\033[91mInitialize OAI UE Failed! \033[0m') self.AutoTerminateUEandeNB() @@ -1176,7 +1166,7 @@ class OaiCiTest(): i += 1 for job in multi_jobs: job.join() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: + if RAN.GetflexranCtrlInstalled() and RAN.GetflexranCtrlStarted(): SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('cd /opt/flexran_rtc', '\$', 5) SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5) @@ -2340,7 +2330,7 @@ class OaiCiTest(): if logStatus < 0: result = logStatus RAN.SeteNBLogFiles[0] = '' - if self.flexranCtrlInstalled and self.flexranCtrlStarted: + if RAN.GetflexranCtrlInstalled() and RAN.GetflexranCtrlStarted(): self.TerminateFlexranCtrl() return result @@ -2416,7 +2406,7 @@ class OaiCiTest(): nrFoundDCI = 0 nrCRCOK = 0 mbms_messages = 0 - self.htmlUEFailureMsg = '' + HTML.SethtmlUEFailureMsg('') for line in ue_log_file.readlines(): result = re.search('nr_synchro_time', str(line)) if result is not None: @@ -2485,22 +2475,22 @@ class OaiCiTest(): if result is not None and (not mib_found): try: mibMsg = "MIB Information: " + result.group(1) + ', ' + result.group(2) - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') mibMsg = " nidcell = " + result.group('nidcell') - self.htmlUEFailureMsg += mibMsg + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg) logging.debug('\033[94m' + mibMsg + '\033[0m') mibMsg = " n_rb_dl = " + result.group('n_rb_dl') - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') mibMsg = " phich_duration = " + result.group('phich_duration') - self.htmlUEFailureMsg += mibMsg + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg) logging.debug('\033[94m' + mibMsg + '\033[0m') mibMsg = " phich_resource = " + result.group('phich_resource') - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') mibMsg = " tx_ant = " + result.group('tx_ant') - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') mib_found = True except Exception as e: @@ -2509,7 +2499,7 @@ class OaiCiTest(): if result is not None and (not frequency_found): try: mibMsg = "Measured Carrier Frequency = " + result.group('measured_carrier_frequency') + ' Hz' - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') frequency_found = True except Exception as e: @@ -2518,7 +2508,7 @@ class OaiCiTest(): if result is not None and (not plmn_found): try: mibMsg = 'PLMN MCC = ' + result.group('mcc') + ' MNC = ' + result.group('mnc') - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') plmn_found = True except Exception as e: @@ -2527,7 +2517,7 @@ class OaiCiTest(): if result is not None: try: mibMsg = "The operator is: " + result.group('operator') - self.htmlUEFailureMsg += mibMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + '\n') logging.debug('\033[94m' + mibMsg + '\033[0m') except Exception as e: logging.error('\033[91m' + "Operator name not found" + '\033[0m') @@ -2535,7 +2525,7 @@ class OaiCiTest(): if result is not None: try: mibMsg = "SIB5 InterFreqCarrierFreq element " + result.group(1) + '/' + result.group(2) - self.htmlUEFailureMsg += mibMsg + ' -> ' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + mibMsg + ' -> ') logging.debug('\033[94m' + mibMsg + '\033[0m') except Exception as e: logging.error('\033[91m' + "SIB5 InterFreqCarrierFreq element not found" + '\033[0m') @@ -2545,7 +2535,7 @@ class OaiCiTest(): freq = result.group('carrier_frequency') new_freq = re.sub('/[0-9]+','',freq) float_freq = float(new_freq) / 1000000 - self.htmlUEFailureMsg += 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz' + HTMLSethtmlUEFailureMsg(HTMLGethtmlUEFailureMsg() + 'DL Freq: ' + ('%.1f' % float_freq) + ' MHz') logging.debug('\033[94m' + " DL Carrier Frequency is: " + freq + '\033[0m') except Exception as e: logging.error('\033[91m' + " DL Carrier Frequency not found" + '\033[0m') @@ -2553,7 +2543,7 @@ class OaiCiTest(): if result is not None: try: prb = result.group('allowed_bandwidth') - self.htmlUEFailureMsg += ' -- PRB: ' + prb + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + ' -- PRB: ' + prb + '\n') logging.debug('\033[94m' + " AllowedMeasBandwidth: " + prb + '\033[0m') except Exception as e: logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') @@ -2561,48 +2551,48 @@ class OaiCiTest(): if rrcConnectionRecfgComplete > 0: statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' logging.debug('\033[94m' + statMsg + '\033[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if nrUEFlag: if nrDecodeMib > 0: statMsg = 'UE showed ' + str(nrDecodeMib) + ' MIB decode message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if nrFoundDCI > 0: statMsg = 'UE showed ' + str(nrFoundDCI) + ' DCI found message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if nrCRCOK > 0: statMsg = 'UE showed ' + str(nrCRCOK) + ' PDSCH decoding message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if not frequency_found: statMsg = 'NR-UE could NOT synch!' logging.error('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if uciStatMsgCount > 0: statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if pdcpDataReqFailedCount > 0: statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if badDciCount > 0: statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1(A)" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if f1aRetransmissionCount > 0: statMsg = 'UE showed ' + str(f1aRetransmissionCount) + ' "Format1A Retransmission but TBS are different" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if fatalErrorCount > 0: statMsg = 'UE showed ' + str(fatalErrorCount) + ' "FATAL ERROR:" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if macBsrTimerExpiredCount > 0: statMsg = 'UE showed ' + str(fatalErrorCount) + ' "MAC BSR Triggered ReTxBSR Timer expiry" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if RAN.GeteNBmbmsEnables[0]: if mbms_messages > 0: statMsg = 'UE showed ' + str(mbms_messages) + ' "TRIED TO PUSH MBMS DATA" message(s)' @@ -2610,7 +2600,7 @@ class OaiCiTest(): else: statMsg = 'UE did NOT SHOW "TRIED TO PUSH MBMS DATA" message(s)' logging.debug('\u001B[1;30;41m ' + statMsg + ' \u001B[0m') - self.htmlUEFailureMsg += statMsg + '\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') if foundSegFault: logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') if not nrUEFlag: @@ -2620,7 +2610,7 @@ class OaiCiTest(): return CONST.OAI_UE_PROCESS_SEG_FAULT if foundAssertion: logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') - self.htmlUEFailureMsg += 'UE showed an assertion!\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + 'UE showed an assertion!\n') if not nrUEFlag: if not mib_found or not frequency_found: return CONST.OAI_UE_PROCESS_ASSERTION @@ -2629,7 +2619,7 @@ class OaiCiTest(): return CONST.OAI_UE_PROCESS_ASSERTION if foundRealTimeIssue: logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') - self.htmlUEFailureMsg += 'UE faced real time issues!\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + 'UE faced real time issues!\n') #return CONST.ENB_PROCESS_REALTIME_ISSUE if nrUEFlag: if not frequency_found: @@ -2637,13 +2627,13 @@ class OaiCiTest(): else: if no_cell_sync_found and not mib_found: logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') - self.htmlUEFailureMsg += 'UE could not synchronize!\n' + HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + 'UE could not synchronize!\n') return CONST.OAI_UE_PROCESS_COULD_NOT_SYNC return 0 def TerminateFlexranCtrl(self): - if self.flexranCtrlInstalled == False or self.flexranCtrlStarted == False: + if RAN.GetflexranCtrlInstalled() == False or RAN.GetflexranCtrlStarted() == False: return if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': GenericHelp(Version) @@ -2654,7 +2644,7 @@ class OaiCiTest(): SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL rt_controller', '\$', 5) time.sleep(1) SSH.close() - self.flexranCtrlStarted = False + RAN.SetflexranCtrlStarted(False) HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) def TerminateUE_common(self, device_id, idx): @@ -2720,7 +2710,7 @@ class OaiCiTest(): copyin_res = SSH.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') - self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' + HTML.SethtmlUEFailureMsg('Could not copy UE logfile to analyze it!') HTML.CreateHtmlTestRow('N/A', 'KO', CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') self.UELogFile = '' return @@ -2733,7 +2723,7 @@ class OaiCiTest(): ueAction = 'Connection' if (logStatus < 0): logging.debug('\u001B[1m' + ueAction + ' Failed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Failed\n' + self.htmlUEFailureMsg + HTML.SethtmlUEFailureMsg('' + ueAction + ' Failed\n' + HTML.GethtmlUEFailureMsg()) HTML.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') if RAN.Getair_interface() == 'lte': # In case of sniffing on commercial eNBs we have random results @@ -2747,7 +2737,7 @@ class OaiCiTest(): self.AutoTerminateUEandeNB() else: logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m') - self.htmlUEFailureMsg = '' + ueAction + ' Completed\n' + self.htmlUEFailureMsg + HTML.SethtmlUEFailureMsg('' + ueAction + ' Completed\n' + HTML.GethtmlUEFailureMsg()) HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.UELogFile = '' else: @@ -2773,7 +2763,7 @@ class OaiCiTest(): self.ShowTestID() RAN.SeteNB_instance('0') RAN.TerminateeNB() - if self.flexranCtrlInstalled and self.flexranCtrlStarted: + if RAN.GetflexranCtrlInstalled() and RAN.GetflexranCtrlStarted(): self.testCase_id = 'AUTO-KILL-flexran-ctl' RAN.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of FlexRan CTL' @@ -2835,7 +2825,7 @@ class OaiCiTest(): logging.debug(msg) fullMessage += msg + '\n' if self.x2_ho_options == 'network': - if self.flexranCtrlInstalled and self.flexranCtrlStarted: + if RAN.GetflexranCtrlInstalled() and RAN.GetflexranCtrlStarted(): self.x2ENBBsIds = [] self.x2ENBConnectedUEs = [] self.x2ENBBsIds.append([]) @@ -3207,7 +3197,6 @@ EPC = epc.EPCManagement() RAN = ran.RANManagement() HTML = html.HTMLManagement() - argvs = sys.argv argc = len(argvs) cwd = os.getcwd() @@ -3300,10 +3289,6 @@ while len(argvs) > 1: elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) EPC.SetIPAddress(matchReg.group(1)) -#GP250220: do we still need EPCBranch? it's not used anywhere - elif re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-EPCBranch=(.+)$', myArgv, re.IGNORECASE) - CiTestObj.EPCBranch = matchReg.group(1) elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) EPC.SetUserName(matchReg.group(1)) @@ -3370,7 +3355,7 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE): RAN.SeteNB_serverId('0') RAN.SeteNB_instance('0') RAN.SeteNBSourceCodePath('/tmp/') - CiTestObj.TerminateeNB() + RAN.TerminateeNB() elif re.match('^TerminateUE$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): GenericHelp(Version) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 04c2e71c5f..454fe5cf5e 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -87,6 +87,9 @@ class RANManagement(): self.eNBLogFiles = ['', '', ''] self.eNBOptions = ['', '', ''] self.eNBmbmsEnables = [False, False, False] + self.eNBstatuses = [-1, -1, -1] + self.flexranCtrlInstalled = False + self.flexranCtrlStarted = False #----------------------------------------------------------- # Setters and Getters @@ -97,8 +100,12 @@ class RANManagement(): self.testCase_id = tcid def SetflexranCtrlInstalled(self,fxrctin): self.flexranCtrlInstalled = fxrctin + def GetflexranCtrlInstalled(self): + return self.flexranCtrlInstalled def SetflexranCtrlStarted(self,fxrctst): self.flexranCtrlStarted = fxrctst + def GetflexranCtrlStarted(self): + return self.flexranCtrlStarted def SetpStatus(self, pSt): self.pStatus = pSt def SetranRepository(self, repository): @@ -175,21 +182,11 @@ class RANManagement(): def GeteNBLogFiles(self): return self.eNBLogFiles - def SeteNBOptions(self, enbopt): - self.eNBOptions = enbopt - def GeteNBOptions(self): - return self.eNBOptions - def SeteNBmbmsEnables(self, enbmbms): self.eNBmbmsEnables = enbmbms def GeteNBmbmsEnables(self): return self.eNBmbmsEnables - def SeteNBstatuses(self, enbstatus): - self.eNBstatuses = enbstatus - def GeteNBstatuses(self): - return self.eNBstatuses - self.eNB1IPAddress = enb1ip def SeteNB1IPAddress(self,enb1ip): self.eNB1IPAddress = enb1ip def GeteNB1IPAddress(self): @@ -339,6 +336,7 @@ class RANManagement(): self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id return mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) + mySSH.close() self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) @@ -374,11 +372,13 @@ class RANManagement(): else: count -= 1 time.sleep(30) + mySSH.close() self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): myHTML = HTML.HTMLManagement() mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) mySSH.command('ls ran_build/build', '\$', 3) mySSH.command('ls ran_build/build', '\$', 3) @@ -909,7 +909,7 @@ class RANManagement(): enb_log_file.close() logging.debug(' File analysis completed') self.htmleNBFailureMsg = '' - if self.air_interface() == 'lte': + if self.air_interface == 'lte': nodeB_prefix = 'e' else: nodeB_prefix = 'g' From 2ea0070d4d4e2b67d95124bbc9c62b90f56f4537 Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 6 Apr 2020 12:04:07 +0200 Subject: [PATCH 112/175] further cleanup --- ci-scripts/main.py | 4 ++++ ci-scripts/ran.py | 33 +++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 2c59b09f60..94a7a52dc6 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -3289,15 +3289,19 @@ while len(argvs) > 1: elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) EPC.SetIPAddress(matchReg.group(1)) + RAN.SetIPAddress(matchReg.group(1)) elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) EPC.SetUserName(matchReg.group(1)) + RAN.SetUserName(matchReg.group(1)) elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) EPC.SetPassword(matchReg.group(1)) + RAN.SetPassword(matchReg.group(1)) elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) EPC.SetSourceCodePath(matchReg.group(1)) + RAN.SetSourceCodePath(matchReg.group(1)) elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 454fe5cf5e..e7f27f7bc6 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -95,6 +95,15 @@ class RANManagement(): # Setters and Getters #----------------------------------------------------------- + def SetIPAddress(self, ipaddress): + self.EPCIPAddress = ipaddress + def SetUserName(self, username): + self.EPCUserName = username + def SetPassword(self, password): + self.EPCPassword = password + def SetSourceCodePath(self, sourcecodepath): + self.EPCSourceCodePath = sourcecodepath + def SettestCase_id(self,tcid): self.testCase_id = tcid @@ -463,15 +472,15 @@ class RANManagement(): # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - mySSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', mySSH.getBefore()) if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') EPC.Set_PcapFileName('enb_' + self.testCase_id + '_s1log.pcap') - mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S rm -f /tmp/' + EPC.Get_PcapFileName() , '\$', 5) - mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.Get_PcapFileName() + ' > /tmp/tshark.log 2>&1 &', EPC.GetUserName(), 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.Get_PcapFileName() + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) mySSH.close() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath, '\$', 5) @@ -510,7 +519,7 @@ class RANManagement(): mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) # Make a copy and adapt to EPC / eNB IP addresses mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + EPC.GetIPAddress() + '/\' ' + ci_full_config_file, '\$', 2); + mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); mySSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); mySSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); mySSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); @@ -563,16 +572,16 @@ class RANManagement(): # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - mySSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) if EPC.Get_PcapFileName() != '': time.sleep(0.5) - mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) mySSH.close() time.sleep(1) if EPC.Get_PcapFileName() != '': - copyin_res = mySSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.Get_PcapFileName() , '.') + copyin_res = mySSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + EPC.Get_PcapFileName() , '.') if (copyin_res == 0): mySSH.copyout(lIpAddr, lUserName, lPassWord, EPC.Get_PcapFileName() , lSourcePath + '/cmake_targets/.') self.prematureExit = True @@ -691,13 +700,13 @@ class RANManagement(): # If tracer options is on, stopping tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) if result is not None: - mySSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) + mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) if EPC.Get_PcapFileName() != '': - mySSH.command('echo ' + EPC.GetPassword() + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) - mySSH.copyin(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), '/tmp/' + EPC.Get_PcapFileName() , '.') + mySSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + EPC.Get_PcapFileName() , '.') mySSH.copyout(lIpAddr, lUserName, lPassWord, EPC.Get_PcapFileName() , lSourcePath + '/cmake_targets/.') mySSH.close() logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') From eff978af5d67e34f4e3527f4fbaf0ce38f82039b Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 6 Apr 2020 14:54:13 +0200 Subject: [PATCH 113/175] debugging --- ci-scripts/main.py | 8 +++++++- ci-scripts/sshconnection.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 94a7a52dc6..5d143eece6 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -750,8 +750,12 @@ class OaiCiTest(): SSH.command('stdbuf -o0 adb -s ' + device_id + ' shell "dumpsys telephony.registry" | grep -m 1 mDataConnectionState', '\$', 15) else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) - print('#GP: in SSH.getBefore() K=0 (it was K=2 in main.py)') result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) + print("\n") + print(SSH.getBefore()) + print("\n") + print(result) + print("\n") if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') lock.acquire() @@ -761,6 +765,8 @@ class OaiCiTest(): lock.release() break mDataConnectionState = int(result.group('state')) + print(mDataConnectionState) + print("\n") if mDataConnectionState == 2: logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') lock.acquire() diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index ecaf8f4116..6fad5065e2 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -87,7 +87,7 @@ class SSHConnection(): if connect_status: pass else: - sys.exit('CiTestObj.Connection Failed') + sys.exit('SSH Connection Failed') def command(self, commandline, expectedline, timeout): From 564db9c398c1ca0ea93ce5d4ecbb894c1bb33d3b Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Mon, 6 Apr 2020 15:20:02 +0200 Subject: [PATCH 114/175] debugging --- ci-scripts/main.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 5d143eece6..0501cd263e 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -751,11 +751,7 @@ class OaiCiTest(): else: SSH.command('ssh ' + self.UEDevicesRemoteUser[idx] + '@' + self.UEDevicesRemoteServer[idx] + ' \'adb -s ' + device_id + ' shell "dumpsys telephony.registry"\' | grep -m 1 mDataConnectionState', '\$', 60) result = re.search('mDataConnectionState.*=(?P[0-9\-]+)', SSH.getBefore()) - print("\n") - print(SSH.getBefore()) - print("\n") - print(result) - print("\n") + print(SSH.getBefore()) #GP debugging if result is None: logging.debug('\u001B[1;37;41m mDataConnectionState Not Found! \u001B[0m') lock.acquire() @@ -765,8 +761,6 @@ class OaiCiTest(): lock.release() break mDataConnectionState = int(result.group('state')) - print(mDataConnectionState) - print("\n") if mDataConnectionState == 2: logging.debug('\u001B[1mUE (' + device_id + ') Attach Completed\u001B[0m') lock.acquire() From 9a136695523d7525bf01c02404d9a790a6870145 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Mon, 6 Apr 2020 16:33:40 +0200 Subject: [PATCH 115/175] CI: adding a few checks before loading images in R2LAB Signed-off-by: Raphael Defosseux --- ci-scripts/Jenkinsfile-inria-r2lab | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci-scripts/Jenkinsfile-inria-r2lab b/ci-scripts/Jenkinsfile-inria-r2lab index 3c4dddae8b..7e797fdf14 100644 --- a/ci-scripts/Jenkinsfile-inria-r2lab +++ b/ci-scripts/Jenkinsfile-inria-r2lab @@ -142,6 +142,12 @@ pipeline { stage ("Load Images") { steps { script { + // Adding a tempo after booking leases + sh "sleep 10" + sh "ssh -t inria_oaici@faraday.inria.fr 'rleases --check'" + sh "ssh -t inria_oaici@faraday.inria.fr 'all-off'" + sh "sleep 10" + echo '\u2705 \u001B[32mLoad Image for Python Executor\u001B[0m' sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labPythonExeIdx} > /dev/null 2>&1'" sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labPythonExeIdx}'" From 8bef0d1d612b19591296420858a4895b4f5fad02 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 7 Apr 2020 12:24:08 +0200 Subject: [PATCH 116/175] CI: adding some try/catches and more debug to see what is going on --> failure to load images since 2 weeks Signed-off-by: Raphael Defosseux --- ci-scripts/Jenkinsfile-inria-r2lab | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/ci-scripts/Jenkinsfile-inria-r2lab b/ci-scripts/Jenkinsfile-inria-r2lab index 7e797fdf14..ca6893dc4f 100644 --- a/ci-scripts/Jenkinsfile-inria-r2lab +++ b/ci-scripts/Jenkinsfile-inria-r2lab @@ -149,12 +149,32 @@ pipeline { sh "sleep 10" echo '\u2705 \u001B[32mLoad Image for Python Executor\u001B[0m' - sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labPythonExeIdx} > /dev/null 2>&1'" - sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labPythonExeIdx}'" + try { + //sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labPythonExeIdx} > /dev/null 2>&1'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labPythonExeIdx}'" + } catch (Exception e) { + echo "Why is it wrong?" + } + try { + //sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labPythonExeIdx}'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rwait ${r2labPythonExeIdx}'" + } catch (Exception e) { + echo "Why is it wrong?" + } echo '\u2705 \u001B[32mLoad Image for two (2) eNBs\u001B[0m' - sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx},${r2labENB1Idx} > /dev/null 2>&1'" - sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labENB0Idx},${r2labENB1Idx}'" + try { + //sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx},${r2labENB1Idx} > /dev/null 2>&1'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rload -i oai-ci-cd-u18-lowlatency-enb-ue ${r2labENB0Idx},${r2labENB1Idx}" + } catch (Exception e) { + echo "Why is it wrong?" + } + try { + //sh "ssh -t inria_oaici@faraday.inria.fr 'rwait --silent ${r2labENB0Idx},${r2labENB1Idx}'" + sh "ssh -t inria_oaici@faraday.inria.fr 'rwait ${r2labENB0Idx},${r2labENB1Idx}'" + } catch (Exception e) { + echo "Why is it wrong?" + } sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx},${r2labENB1Idx}'" sh "sleep 5" sh "ssh -t inria_oaici@faraday.inria.fr 'uon ${r2labENB0Idx},${r2labENB1Idx}'" From be9d4e1b55c64a3a600576ddf17877c574821e0e Mon Sep 17 00:00:00 2001 From: Gabriele Perrone Date: Tue, 7 Apr 2020 16:10:58 +0200 Subject: [PATCH 117/175] after full run of enb_usrp210_band7_test_05mhz_tm1.xml commit the latest changes; then I will create an integration branch to run CI --- ci-scripts/main.py | 1 - ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 0501cd263e..11686601b4 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -1235,7 +1235,6 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) idx = 0 for device_id in self.UEDevices: - print('UE status attched'+CONST.UE_STATUS_ATTACHED) if self.UEDevicesStatus[idx] != CONST.UE_STATUS_ATTACHED: idx += 1 continue diff --git a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml index 6bc60b113a..3b07ed4950 100644 --- a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml +++ b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml @@ -108,7 +108,7 @@ Initialize_eNB Initialize eNB (FDD/Band7/5MHz) - -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].plmn_list.[0].mnc 93 + -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf From 1c16705355ac2450fdb282d5e10e685346ff7978 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 8 Apr 2020 00:03:44 +0200 Subject: [PATCH 118/175] pucch receiver for format 0 reworked without floating point and no generation of sequences for each decoding attempt, SR detection integrated --- cmake_targets/autotests/test_case_list.xml | 16 +++--- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 64 +++++++++++++++++----- openair1/PHY/defs_gNB.h | 17 +++--- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index b3954db1fd..b7222d0330 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1177,21 +1177,23 @@ execution - nr_pucchsim Test cases. (Test1: Format 0 ACK miss 106 PRB), - (Test2: Format 1 ACK miss 106 PRB), - (Test3: Format 1 ACK miss 273 PRB), - (Test4: Format 1 NACKtoACK 106 PRB) + nr_pucchsim Test cases. (Test1: Format 0 1-bit ACK miss 106 PRB), + (Test2: Format 0 2-bit ACK miss 106 PRB), + (Test3: Format 1 ACK miss 106 PRB), + (Test4: Format 1 ACK miss 273 PRB), + (Test5: Format 1 NACKtoACK 106 PRB) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/targets/bin/nr_pucchsim.Rel15 - -R 106 -i 1 -P 0 -b 1 -s3 -n100 - -R 106 -i 14 -P 1 -b 1 -s-6 -n100 + -R 106 -i 1 -P 0 -b 1 -s-7 -n1000 + -R 106 -i 1 -P 0 -b 2 -s-7 -n1000 + -R 106 -i 14 -P 1 -b 1 -s-6 -n100 -R 273 -i 14 -P 1 -b 1 -s-6 -n100 -R 106 -i 14 -P 1 -b 1 -s-6 -T 0.001 -n1000 - nr_pucchsim.test1 nr_pucchsim.test2 nr_pucchsim.test3 nr_pucchsim.test4 + nr_pucchsim.test1 nr_pucchsim.test2 PUCCH test OK segmentation fault|assertion|exiting|fatal 3 diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index bb087aad0d..ee3e247cb0 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -94,7 +94,15 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); - if(pucch_pdu->bit_len_harq==1){ + AssertFatal(pucch_pdu->bit_len_harq > 0 || pucch_pdu->sr_flag > 0, + "Either bit_len_harq (%d) or sr_flag (%d) must be > 0\n", + pucch_pdu->bit_len_harq,pucch_pdu->sr_flag); + + if(pucch_pdu->bit_len_harq==0){ + mcs=table1_mcs; + nr_sequences=1; + } + else if(pucch_pdu->bit_len_harq==1){ mcs=table1_mcs; nr_sequences=4>>(1-pucch_pdu->sr_flag); } @@ -275,6 +283,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, maxpos=i; } } + + uint8_t xrtmag_dB = dB_fixed(xrtmag); #ifdef DEBUG_NR_PUCCH_RX printf("PUCCH 0 : maxpos %d\n",maxpos); @@ -288,21 +298,45 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->ul_cqi = 0xff; // currently not valid uci_pdu->timing_advance = 0xffff; // currently not valid uci_pdu->rssi = 0xffff; // currently not valid - if (pucch_pdu->sr_flag) { - //currently not supported - } - else - uci_pdu->sr = NULL; - if (pucch_pdu->bit_len_harq>0) { - uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq)); - uci_pdu->harq->num_harq = pucch_pdu->bit_len_harq; - uci_pdu->harq->harq_confidence_level = 0xff; // currently not valid - uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(uci_pdu->harq->num_harq); - for (i=0; iharq->num_harq; i++) // FIXME for non present - uci_pdu->harq->harq_list[i].harq_value = (index>>i)&0x01; - } - else + + if (pucch_pdu->bit_len_harq==0) { uci_pdu->harq = NULL; + uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); + if (xrtmag_dB>(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres)) { + uci_pdu->sr->sr_indication = 1; + uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres); + } else { + uci_pdu->sr->sr_indication = 0; + uci_pdu->sr->sr_confidence_level = (gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres)-xrtmag_dB; + } + } + else if (pucch_pdu->bit_len_harq==1) { + uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq)); + uci_pdu->harq->num_harq = 1; + uci_pdu->harq->harq_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres); + uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); + uci_pdu->harq->harq_list[0].harq_value = index&0x01; + if (pucch_pdu->sr_flag == 1) { + uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); + uci_pdu->sr->sr_indication = (index>1) ? 1 : 0; + uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres); + } + } + else { + uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq)); + uci_pdu->harq->num_harq = 2; + uci_pdu->harq->harq_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres); + uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(2); + + uci_pdu->harq->harq_list[0].harq_value = index&0x01; + uci_pdu->harq->harq_list[1].harq_value = (index>>1)&0x01; + + if (pucch_pdu->sr_flag == 1) { + uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); + uci_pdu->sr->sr_indication = (index>3) ? 1 : 0; + uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres); + } + } } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index d64153414f..d39f0d4e0b 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -568,13 +568,13 @@ typedef struct { //! estimated avg noise power (dB) short n0_power_tot_dBm; //! estimated avg noise power per RB per RX ant (lin) - unsigned short n0_subband_power[MAX_NUM_RU_PER_gNB][100]; + unsigned short n0_subband_power[MAX_NUM_RU_PER_gNB][275]; //! estimated avg noise power per RB per RX ant (dB) - unsigned short n0_subband_power_dB[MAX_NUM_RU_PER_gNB][100]; + unsigned short n0_subband_power_dB[MAX_NUM_RU_PER_gNB][275]; //! estimated avg noise power per RB (dB) - short n0_subband_power_tot_dB[100]; + short n0_subband_power_tot_dB[275]; //! estimated avg noise power per RB (dBm) - short n0_subband_power_tot_dBm[100]; + short n0_subband_power_tot_dBm[275]; // gNB measurements (per user) //! estimated received spatial signal power (linear) unsigned int rx_spatial_power[NUMBER_OF_NR_DLSCH_MAX][2][2]; @@ -594,13 +594,13 @@ typedef struct { /// Wideband CQI (sum of all RX antennas, in dB) char wideband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX]; /// Subband CQI per RX antenna and RB (= SINR) - int subband_cqi[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][100]; + int subband_cqi[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][275]; /// Total Subband CQI and RB (= SINR) - int subband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX][100]; + int subband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX][275]; /// Subband CQI in dB and RB (= SINR dB) - int subband_cqi_dB[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][100]; + int subband_cqi_dB[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][275]; /// Total Subband CQI and RB - int subband_cqi_tot_dB[NUMBER_OF_NR_DLSCH_MAX][100]; + int subband_cqi_tot_dB[NUMBER_OF_NR_DLSCH_MAX][275]; /// PRACH background noise level int prach_I0; } PHY_MEASUREMENTS_gNB; @@ -707,6 +707,7 @@ typedef struct PHY_VARS_gNB_s { /// counter to average prach energh over first 100 prach opportunities int prach_energy_counter; + int pucch0_thres; /* time_stats_t phy_proc; */ From c8ac5d56bf49d7f6edc3eb2c7c5166d5b13f921d Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 8 Apr 2020 12:47:34 +0200 Subject: [PATCH 119/175] compilation of NR executables with MAC --- openair1/SIMULATION/NR_PHY/dlsim.c | 3 ++- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 3 ++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index ebcedbaeb0..1927f16d60 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -171,6 +171,7 @@ int main(int argc, char **argv) //int pbch_tx_ant; int N_RB_DL=106,mu=1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t dlsch_config; + NR_sched_pucch pucch_sched; //unsigned char frame_type = 0; @@ -706,7 +707,7 @@ int main(int argc, char **argv) memset(RC.nrmac[0]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int)); clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot); - if (css_flag == 0) nr_schedule_uss_dlsch_phytest(0,frame,slot,&dlsch_config); + if (css_flag == 0) nr_schedule_uss_dlsch_phytest(0,frame,slot,&pucch_sched,&dlsch_config); else nr_schedule_css_dlsch_phytest(0,frame,slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 304004ff8c..1665a9f612 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -541,7 +541,8 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP, TBS_bytes = configure_fapi_dl_pdu(module_idP, CCEIndices, - dl_req, + dl_req, + pucch_sched, dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL, dlsch_config!=NULL ? &dlsch_config->rbSize : NULL, dlsch_config!=NULL ? &dlsch_config->rbStart : NULL); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 75d2385412..86dac1e11f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -123,7 +123,7 @@ typedef struct { DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB]; /// scheduling control info - UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB]; + NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB]; int next[MAX_MOBILES_PER_GNB]; int head; int next_ul[MAX_MOBILES_PER_GNB]; From 786be88101ebd2d6ca0a57c29921a691c11411d4 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 9 Apr 2020 15:52:19 +0200 Subject: [PATCH 120/175] fixed unitary simulation issue for nr_ulsim and removed broken pucch1 tests --- cmake_targets/autotests/test_case_list.xml | 9 ++------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index b7222d0330..7908772bb6 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1178,10 +1178,7 @@ execution nr_pucchsim Test cases. (Test1: Format 0 1-bit ACK miss 106 PRB), - (Test2: Format 0 2-bit ACK miss 106 PRB), - (Test3: Format 1 ACK miss 106 PRB), - (Test4: Format 1 ACK miss 273 PRB), - (Test5: Format 1 NACKtoACK 106 PRB) + (Test2: Format 0 2-bit ACK miss 106 PRB) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c @@ -1190,9 +1187,7 @@ $OPENAIR_DIR/targets/bin/nr_pucchsim.Rel15 -R 106 -i 1 -P 0 -b 1 -s-7 -n1000 -R 106 -i 1 -P 0 -b 2 -s-7 -n1000 - -R 106 -i 14 -P 1 -b 1 -s-6 -n100 - -R 273 -i 14 -P 1 -b 1 -s-6 -n100 - -R 106 -i 14 -P 1 -b 1 -s-6 -T 0.001 -n1000 + nr_pucchsim.test1 nr_pucchsim.test2 PUCCH test OK segmentation fault|assertion|exiting|fatal diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 46f9a79460..76d35f7ae7 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -428,6 +428,7 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) nr_fill_rx_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid); // indicate SDU to MAC nr_fill_crc_indication(gNB, frame_rx, slot_rx, ULSCH_id, 0); } + break; case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE:{ LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE\n",frame_rx,slot_rx); From b568d5b01af488908a200c9d1c45d58278f6faba Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 9 Apr 2020 22:25:02 +0200 Subject: [PATCH 121/175] removed faulty entries in ci unitary simulators and SNR starting point for nr_ulsim tests --- cmake_targets/autotests/test_case_list.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 7908772bb6..085e5fb07b 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1104,8 +1104,7 @@ -n100 -R217 -a80 -s5 -n100 -R217 -a110 -s5 -b100 -n100 -e27 -s30 - -n100 -e16 -s10 - + -n100 -e16 -s10 nr_dlsim.test1 nr_dlsim.test2 nr_dlsim.test3 nr_dlsim.test4 nr_dlsim.test5 nr_dlsim.test6 nr_dlsim.test7 nr_dlsim.test8 nr_dlsim.test9 nr_dlsim.test10 PDSCH test OK segmentation fault|assertion|exiting|fatal @@ -1245,11 +1244,11 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/targets/bin/nr_ulsim.Rel15 - -n100 -m9 -r106 -s0 + -n100 -m9 -r106 -s5 -n100 -m16 -s10 -n100 -m28 -s20 - -n100 -m9 -R217 -r217 -s0 - -n100 -m9 -R273 -r273 -s0 + -n100 -m9 -R217 -r217 -s5 + -n100 -m9 -R273 -r273 -s5 nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 PUSCH test OK segmentation fault|assertion|exiting|fatal From 58e973409aaf2b31bbea6fcafabd02099a71a5e0 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 14 Apr 2020 11:25:59 +0200 Subject: [PATCH 122/175] small compilation details --- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 4 ++-- openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- openair2/RRC/NR/nr_rrc_extern.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 36a3cd9a5c..90492b9999 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -314,7 +314,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, unsigned int Kr_bytes = Kr>>3; #ifdef DEBUG_ULSCH_DECODING - printf("Rate Matching Segment %u (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, Nl %d, r_offset %d)...\n", + printf("Rate Matching Segment %d (coded bits (G) %d,unpunctured/repeated bits %u, Q_m %d, Nl %d, r_offset %u)...\n", r, G, Kr*3, ulsch_harq->Qm, @@ -572,7 +572,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB, G = G - Q_RI - Q_CQI; ulsch_harq->G = G; AssertFatal((int)G > 0, - "FATAL: ulsch_decoding.c G < 0 (%d) : Q_RI %d, Q_CQI %d\n",G,Q_RI,Q_CQI); + "FATAL: ulsch_decoding.c G < 0 (%u) : Q_RI %u, Q_CQI %u\n",G,Q_RI,Q_CQI); H = G + Q_CQI; Hprime = H/Q_m; // Demultiplexing/Deinterleaving of PUSCH/ACK/RI/CQI diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 064066801d..c950d6f4da 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -1286,7 +1286,7 @@ int main(int argc, char **argv) { LOG_UDUMPMSG(SIM,dataArray(table_rx),table_rx->size,LOG_DUMP_DOUBLE,"The receiver raw data: \n"); } - printf("\n**********rb: %d ***mcs : %d *********SNR = %f dB (%f): TX %u dB (gain %f dB), N0W %f dB, I0 %d dB, delta_IF %d [ (%d,%d) dB / (%d,%d) dB ]**************************\n", + printf("\n**********rb: %d ***mcs : %d *********SNR = %f dB (%f): TX %u dB (gain %f dB), N0W %f dB, I0 %u dB, delta_IF %d [ (%d,%d) dB / (%u,%u) dB ]**************************\n", nb_rb,mcs,SNR,SNR2, tx_lev_dB, 20*log10(tx_gain), diff --git a/openair2/RRC/NR/nr_rrc_extern.h b/openair2/RRC/NR/nr_rrc_extern.h index cb6adc8012..04e0392236 100644 --- a/openair2/RRC/NR/nr_rrc_extern.h +++ b/openair2/RRC/NR/nr_rrc_extern.h @@ -73,7 +73,7 @@ extern UE_PF_PO_t UE_PF_PO[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB]; extern pthread_mutex_t ue_pf_po_mutex; -extern uint16_t reestablish_rnti_map[NUMBER_OF_UE_MAX][2]; +extern uint16_t reestablish_rnti_map[MAX_MOBILES_PER_ENB][2]; char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigurationReq *configuration); #endif From 8a58359a1be513c6ac8f68f1dac38704fc79abd1 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 14 Apr 2020 19:51:00 +0200 Subject: [PATCH 123/175] rereremerge --- openair1/SCHED/fapi_l1.c | 1 - openair2/LAYER2/MAC/pre_processor.c | 319 +-------------------------- openair2/PHY_INTERFACE/phy_stub_UE.c | 2 - openair2/X2AP/x2ap_eNB_handler.c | 4 +- targets/RT/USER/lte-ue.c | 5 +- targets/RT/USER/lte-uesoftmodem.c | 1 - 6 files changed, 12 insertions(+), 320 deletions(-) diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index b55ad99386..96a073fbb8 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -381,7 +381,6 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro dlsch0_harq->TBS, dlsch0_harq->Qm, dlsch0_harq->codeword, dlsch0_harq->rb_alloc[0], rel8->length ); - dlsch0->active = 1; harq_pid = dlsch0->harq_ids[frame%2][proc->subframe_tx]; dlsch0->harq_mask |= (1<pre_first_nb_rb_ul + i] = UE_id + '0'; } } - - // step 3: assigne RBS - for (UE_id = UE_list->head_ul; UE_id >= 0; UE_id = UE_list->next_ul[UE_id]) { - // if (continueTable[UE_id]) continue; - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - harq_pid = subframe2harqpid(&RC.mac[module_idP]->common_channels[CC_id], - sched_frameP, sched_subframeP); - - // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); - - if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] > 0) { - nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; - } else { - nb_allocated_rbs[CC_id][UE_id] = - cmin(UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[slice_idx], average_rbs_per_user[CC_id]); - } - - total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d, nb_rb_ul %d, %d ,%d, slice %d, round ul %d\n", - nb_allocated_rbs[CC_id][UE_id], - UE_id, - rntiTable[UE_id], - CC_id, - harq_pid, - UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid], - UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[slice_idx], - average_rbs_per_user[CC_id], - slice_idx, - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid]); - } - } - - // step 4: assigne the remaining RBs and set the pre_allocated rbs accordingly - for (UE_id = UE_list->head_ul; UE_id >= 0; UE_id = UE_list->next_ul[UE_id]) { - // if (continueTable[UE_id]) continue; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - N_RB_UL = to_prb(eNB->common_channels[CC_id].ul_Bandwidth); - first_rb_offset = UE_list->first_rb_offset[CC_id][slice_idx]; - available_rbs = cmin(ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_idx], N_RB_UL - first_rb[CC_id] - first_rb_offset); - total_remaining_rbs[CC_id] = available_rbs - total_allocated_rbs[CC_id]; - - if (total_ue_count[CC_id] == 1) { - total_remaining_rbs[CC_id]++; - } - - while (UE_template->pre_allocated_nb_rb_ul[slice_idx] > 0 && - nb_allocated_rbs[CC_id][UE_id] < UE_template->pre_allocated_nb_rb_ul[slice_idx] && - total_remaining_rbs[CC_id] > 0) { - nb_allocated_rbs[CC_id][UE_id] = cmin(nb_allocated_rbs[CC_id][UE_id] + 1, UE_template->pre_allocated_nb_rb_ul[slice_idx]); - total_remaining_rbs[CC_id]--; - total_allocated_rbs[CC_id]++; - } - - UE_template->pre_allocated_nb_rb_ul[slice_idx] = nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, "******************UL Scheduling Information for UE%d CC_id %d ************************\n", - UE_id, - CC_id); - LOG_D(MAC, "[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", - module_idP, - UE_id, - CC_id, - UE_template->pre_allocated_nb_rb_ul[slice_idx]); - } - } - - return; -} - -void -assign_max_mcs_min_rb(module_id_t module_idP, - int slice_idx, - int frameP, - sub_frame_t subframeP, - uint16_t *first_rb) { - int i; - uint16_t n, UE_id; - uint8_t CC_id; - int mcs; - int rb_table_index = 0, tbs, tx_power; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - slice_info_t *sli = &eNB->slice_info; - UE_TEMPLATE *UE_template; - UE_sched_ctrl_t *ue_sched_ctl; - int Ncp; - int N_RB_UL; - int first_rb_offset, available_rbs; - - for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { - if (UE_list->UE_sched_ctrl[i].phr_received == 1) { - /* if we've received the power headroom information the UE, we can go to - * maximum mcs */ - mcs = cmin(20, sli->ul[slice_idx].maxmcs); - } else { - /* otherwise, limit to QPSK PUSCH */ - mcs = cmin(10, sli->ul[slice_idx].maxmcs); - } - - UE_id = i; - - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - AssertFatal(CC_id < RC.nb_mac_CC[module_idP], "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, - NFAPI_CC_MAX, - n, - UE_id, - UE_list->numactiveULCCs[UE_id]); - UE_template = &UE_list->UE_template[CC_id][UE_id]; - UE_template->pre_assigned_mcs_ul = mcs; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - Ncp = eNB->common_channels[CC_id].Ncp; - N_RB_UL = to_prb(eNB->common_channels[CC_id].ul_Bandwidth); - ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_idx] = nb_rbs_allowed_slice(sli->ul[slice_idx].pct, N_RB_UL); - int bytes_to_schedule = UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes; - - if (bytes_to_schedule < 0) bytes_to_schedule = 0; - - int bits_to_schedule = bytes_to_schedule * 8; - - // if this UE has UL traffic - if (bits_to_schedule > 0) { - tbs = get_TBS_UL(UE_template->pre_assigned_mcs_ul, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! - rb_table_index = 2; - // fixme: set use_srs flag - tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); - - while ((UE_template->phr_info - tx_power < 0 || tbs > bits_to_schedule) && UE_template->pre_assigned_mcs_ul > 3) { - // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); - UE_template->pre_assigned_mcs_ul--; - tbs = get_TBS_UL(UE_template->pre_assigned_mcs_ul, rb_table[rb_table_index]) << 3; - tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); // fixme: set use_srs - } - - first_rb_offset = UE_list->first_rb_offset[CC_id][slice_idx]; - available_rbs = - cmin(ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_idx], N_RB_UL - first_rb[CC_id] - first_rb_offset); - - while (tbs < bits_to_schedule && - rb_table[rb_table_index] < available_rbs && - UE_template->phr_info - tx_power > 0 && - rb_table_index < 32) { - rb_table_index++; - tbs = get_TBS_UL(UE_template->pre_assigned_mcs_ul, rb_table[rb_table_index]) << 3; - tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); - } - - if (rb_table[rb_table_index] > (available_rbs - 1)) { - rb_table_index--; - } - - // 1 or 2 PRB with cqi enabled does not work well - if (rb_table[rb_table_index] < 3) { - rb_table_index = 2; //3PRB - } - - UE_template->pre_allocated_rb_table_index_ul = rb_table_index; - UE_template->pre_allocated_nb_rb_ul[slice_idx] = rb_table[rb_table_index]; - LOG_D(MAC, "[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", - module_idP, - frameP, - subframeP, - UE_id, - CC_id, - UE_template->pre_assigned_mcs_ul, - UE_template->pre_allocated_rb_table_index_ul, - UE_template->pre_allocated_nb_rb_ul[slice_idx], - UE_template->phr_info, tx_power); - } else { - /* if UE has pending scheduling request then pre-allocate 3 RBs */ - //if (UE_template->ul_active == 1 && UE_template->ul_SR == 1) { - if (UE_is_to_be_scheduled(module_idP, CC_id, i)) { - /* use QPSK mcs */ - UE_template->pre_assigned_mcs_ul = 10; - UE_template->pre_allocated_rb_table_index_ul = 2; - UE_template->pre_allocated_nb_rb_ul[slice_idx] = 3; - } else { - UE_template->pre_assigned_mcs_ul = 0; - UE_template->pre_allocated_rb_table_index_ul = -1; - UE_template->pre_allocated_nb_rb_ul[slice_idx] = 0; - } - } - } - } -} - -struct sort_ue_ul_params { - int module_idP; - int sched_frameP; - int sched_subframeP; -}; - -static int ue_ul_compare(const void *_a, const void *_b, void *_params) { - struct sort_ue_ul_params *params = _params; - UE_list_t *UE_list = &RC.mac[params->module_idP]->UE_list; - int UE_id1 = *(const int *) _a; - int UE_id2 = *(const int *) _b; - int rnti1 = UE_RNTI(params->module_idP, UE_id1); - int pCCid1 = UE_PCCID(params->module_idP, UE_id1); - int round1 = maxround_ul(params->module_idP, rnti1, params->sched_frameP, - params->sched_subframeP); - int rnti2 = UE_RNTI(params->module_idP, UE_id2); - int pCCid2 = UE_PCCID(params->module_idP, UE_id2); - int round2 = maxround_ul(params->module_idP, rnti2, params->sched_frameP, - params->sched_subframeP); - - if (round1 > round2) - return -1; - - if (round1 < round2) - return 1; - - if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] > - UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) - return -1; - - if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < - UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) - return 1; - - int bytes_to_schedule1 = UE_list->UE_template[pCCid1][UE_id1].estimated_ul_buffer - UE_list->UE_template[pCCid1][UE_id1].scheduled_ul_bytes; - - if (bytes_to_schedule1 < 0) bytes_to_schedule1 = 0; - - int bytes_to_schedule2 = UE_list->UE_template[pCCid2][UE_id2].estimated_ul_buffer - UE_list->UE_template[pCCid2][UE_id2].scheduled_ul_bytes; - - if (bytes_to_schedule2 < 0) bytes_to_schedule2 = 0; - - if (bytes_to_schedule1 > bytes_to_schedule2) - return -1; - - if (bytes_to_schedule1 < bytes_to_schedule2) - return 1; - - if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul > - UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) - return -1; - - if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul < - UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) - return 1; - - if (UE_list->UE_sched_ctrl[UE_id1].cqi_req_timer > - UE_list->UE_sched_ctrl[UE_id2].cqi_req_timer) - return -1; - - if (UE_list->UE_sched_ctrl[UE_id1].cqi_req_timer < - UE_list->UE_sched_ctrl[UE_id2].cqi_req_timer) - return 1; - - return 0; -} - -//----------------------------------------------------------------------------- -/* - * This function sorts the UEs in order, depending on their ulsch buffer and CQI - */ -void sort_ue_ul(module_id_t module_idP, - int slice_idx, - int sched_frameP, - sub_frame_t sched_subframeP, - rnti_t *rntiTable) -//----------------------------------------------------------------------------- -{ - int list[MAX_MOBILES_PER_ENB]; - int list_size = 0; - struct sort_ue_ul_params params = { module_idP, sched_frameP, sched_subframeP }; - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - UE_sched_ctrl_t *UE_scheduling_control = NULL; - - for (int i = 0; i < MAX_MOBILES_PER_ENB; i++) { - UE_scheduling_control = &(UE_list->UE_sched_ctrl[i]); - - /* Check CDRX configuration and if UE is in active time for this subframe */ - if (UE_scheduling_control->cdrx_configured == TRUE) { - if (UE_scheduling_control->in_active_time == FALSE) { - continue; - } - } - - rntiTable[i] = UE_RNTI(module_idP, i); - - // Valid element and is not the actual CC_id in the list - if (UE_list->active[i] == TRUE && - rntiTable[i] != NOT_A_RNTI && - UE_list->UE_sched_ctrl[i].ul_out_of_sync != 1 && - ue_ul_slice_membership(module_idP, i, slice_idx)) { - list[list_size++] = i; // Add to list - } - } - - qsort_r(list, list_size, sizeof(int), ue_ul_compare, ¶ms); - - if (list_size) { // At mimimum one list element - for (int i = 0; i < list_size - 1; i++) { - UE_list->next_ul[list[i]] = list[i + 1]; - } - - UE_list->next_ul[list[list_size - 1]] = -1; - UE_list->head_ul = list[0]; - } else { // No element - UE_list->head_ul = -1; - } + if (print) + LOG_D(MAC, + "%4d.%d UL scheduler allocation list: %s\n", + sched_frameP, + sched_subframeP, + t); +#endif } diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c index 8bd172f79f..5c9b4b996e 100644 --- a/openair2/PHY_INTERFACE/phy_stub_UE.c +++ b/openair2/PHY_INTERFACE/phy_stub_UE.c @@ -863,7 +863,6 @@ int memcpy_dl_config_req(L1_rxtx_proc_t *proc, dl_config_req->dl_config_request_body.number_pdsch_rnti = req->dl_config_request_body.number_pdsch_rnti; dl_config_req->dl_config_request_body.number_pdu = req->dl_config_request_body.number_pdu; - dl_config_req->dl_config_request_body.tl.tag = req->dl_config_request_body.tl.tag; dl_config_req->dl_config_request_body.tl.length = req->dl_config_request_body.tl.length; @@ -1045,7 +1044,6 @@ void handle_nfapi_bch_pdu(PHY_VARS_eNB *eNB, uint8_t *sdu) { } - void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB, int frame, int subframe, diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c index df68746201..afaae1756d 100644 --- a/openair2/X2AP/x2ap_eNB_handler.c +++ b/openair2/X2AP/x2ap_eNB_handler.c @@ -1771,9 +1771,9 @@ int x2ap_gNB_handle_ENDC_sGNB_addition_request (instance_t instance, X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest, X2AP_ProtocolIE_ID_id_MeNBtoSgNBContainer, true); + X2AP_MeNBtoSgNBContainer_t *container = &ie->value.choice.MeNBtoSgNBContainer; //X2AP_MeNBtoSgNBContainer_t *container = &ie->value.choice.MeNBtoSgNBContainer; - - if (ie->value.choice.MeNBtoSgNBContainer.size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s + if (container->size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s { printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); } memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).rrc_buffer, ie->value.choice.MeNBtoSgNBContainer.buf, ie->value.choice.MeNBtoSgNBContainer.size); diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index d9465db425..006394eb78 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1617,14 +1617,14 @@ void *UE_thread(void *arg) if (is_synchronized == 0) { if (instance_cnt_synch < 0) { // we can invoke the synch // grab 10 ms of signal and wakeup synch thread + if (UE->mode != loop_through_memory) { if (IS_SOFTMODEM_RFSIM ) { for(int sf=0; sf<10; sf++) { for (int i=0; iframe_parms.nb_antennas_rx; i++) rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.samples_per_tti*sf]; - AssertFatal( UE->frame_parms.samples_per_tti == - UE->rfdevice.trx_read_func(&UE->rfdevice, + AssertFatal(UE->frame_parms.samples_per_tti == UE->rfdevice.trx_read_func(&UE->rfdevice, ×tamp, rxp, UE->frame_parms.samples_per_tti, @@ -1643,6 +1643,7 @@ void *UE_thread(void *arg) UE->frame_parms.nb_antennas_rx), ""); } } + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); instance_cnt_synch = ++UE->proc.instance_cnt_synch; diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 8afbbe5358..395e73bb66 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -605,7 +605,6 @@ int main( int argc, char **argv ) { pthread_mutex_init(&sync_mutex, NULL); printf("ITTI init\n"); -#define UE itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); // initialize mscgen log after ITTI From 71cbb7e894750504c2f9ad9b53c927d1847946c2 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 16 Apr 2020 10:40:33 +0200 Subject: [PATCH 124/175] dirty workaround if4p5 bug --- cmake_targets/CMakeLists.txt | 10 +++++----- openair2/MCE_APP/mce_app.c | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 05d32b74df..6382bbea51 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -185,7 +185,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${CMAKE_CU # set a flag for changes in the source code # these changes are related to hardcoded path to include .h files set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -Og") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -O2") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3") set(GIT_BRANCH "UNKNOWN") @@ -2519,7 +2519,7 @@ target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem ${T_LIB}) -add_executable(ocp-softmodem +add_executable(ocp-enb ${OPENAIR_DIR}/executables/main-ocp.c ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c ${OPENAIR_DIR}/executables/softmodem-common.c @@ -2545,15 +2545,15 @@ add_executable(ocp-softmodem ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} ) -add_dependencies(ocp-softmodem rrc_flag s1ap_flag x2_flag oai_iqplayer) +add_dependencies(ocp-enb rrc_flag s1ap_flag x2_flag oai_iqplayer) -target_link_libraries (ocp-softmodem +target_link_libraries (ocp-enb -Wl,--start-group RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP M2AP_LIB M2AP_ENB X2AP_LIB X2AP_ENB M3AP_LIB M3AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT MME_APP UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 L2_LTE NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} -Wl,--end-group z dl) -target_link_libraries (ocp-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) +target_link_libraries (ocp-enb ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB}) add_executable(cu_test ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c diff --git a/openair2/MCE_APP/mce_app.c b/openair2/MCE_APP/mce_app.c index 32dfa5cc42..6f7454c321 100644 --- a/openair2/MCE_APP/mce_app.c +++ b/openair2/MCE_APP/mce_app.c @@ -343,7 +343,9 @@ void *MCE_app_task(void *args_p) { /* Try to register each MCE */ // This assumes that node_type of all RRC instances is the same - if (EPC_MODE_ENABLED) { + if ( EPC_MODE_ENABLED && RC.rrc == NULL ) + LOG_E(RRC, "inconsistent global variables\n"); + if (EPC_MODE_ENABLED && RC.rrc ) { register_mce_pending = MCE_app_register(RC.rrc[0]->node_type, mce_id_start, mce_id_end); } From 3310f5c6b04f30720c783abe3b05e58113cfd170 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 25 Apr 2019 10:54:58 +0200 Subject: [PATCH 125/175] alternative RLC implementation This commit introduces an alternative RLC implementation based on 36.322 version 8. AM and UM done, TM not done. See openair2/LAYER2/rlc_v2/TODO for missing parts. --- cmake_targets/CMakeLists.txt | 21 +- common/utils/T/tracer/hacks/pilot_timeplot.sh | 15 + common/utils/T/tracer/hacks/time_meas.c | 10 +- common/utils/T/tracer/hacks/timeplot.c | 18 +- openair2/COMMON/rrc_messages_def.h | 3 + openair2/COMMON/rrc_messages_types.h | 10 + openair2/LAYER2/rlc_v2/TODO | 18 + openair2/LAYER2/rlc_v2/asn1_utils.c | 129 ++ openair2/LAYER2/rlc_v2/asn1_utils.h | 33 + openair2/LAYER2/rlc_v2/rlc_entity.c | 144 ++ openair2/LAYER2/rlc_v2/rlc_entity.h | 97 + openair2/LAYER2/rlc_v2/rlc_entity_am.c | 1694 +++++++++++++++++ openair2/LAYER2/rlc_v2/rlc_entity_am.h | 285 +++ openair2/LAYER2/rlc_v2/rlc_entity_um.c | 703 +++++++ openair2/LAYER2/rlc_v2/rlc_entity_um.h | 90 + openair2/LAYER2/rlc_v2/rlc_oai_api.c | 821 ++++++++ openair2/LAYER2/rlc_v2/rlc_pdu.c | 266 +++ openair2/LAYER2/rlc_v2/rlc_pdu.h | 109 ++ openair2/LAYER2/rlc_v2/rlc_sdu.c | 68 + openair2/LAYER2/rlc_v2/rlc_sdu.h | 39 + openair2/LAYER2/rlc_v2/rlc_ue_manager.c | 182 ++ openair2/LAYER2/rlc_v2/rlc_ue_manager.h | 58 + openair2/LAYER2/rlc_v2/tests/LOG/log.h | 10 + openair2/LAYER2/rlc_v2/tests/Makefile | 32 + openair2/LAYER2/rlc_v2/tests/README | 38 + openair2/LAYER2/rlc_v2/tests/make_pdu.c | 29 + openair2/LAYER2/rlc_v2/tests/run_tests.sh | 12 + openair2/LAYER2/rlc_v2/tests/test.c | 433 +++++ openair2/LAYER2/rlc_v2/tests/test1.h | 14 + openair2/LAYER2/rlc_v2/tests/test1.txt.gz | Bin 0 -> 238 bytes openair2/LAYER2/rlc_v2/tests/test10.h | 23 + openair2/LAYER2/rlc_v2/tests/test10.txt.gz | Bin 0 -> 361 bytes openair2/LAYER2/rlc_v2/tests/test11.h | 37 + openair2/LAYER2/rlc_v2/tests/test11.txt.gz | Bin 0 -> 430 bytes openair2/LAYER2/rlc_v2/tests/test12.h | 34 + openair2/LAYER2/rlc_v2/tests/test12.txt.gz | Bin 0 -> 415 bytes openair2/LAYER2/rlc_v2/tests/test13.h | 30 + openair2/LAYER2/rlc_v2/tests/test13.txt.gz | Bin 0 -> 351 bytes openair2/LAYER2/rlc_v2/tests/test14.h | 12 + openair2/LAYER2/rlc_v2/tests/test14.txt.gz | Bin 0 -> 180 bytes openair2/LAYER2/rlc_v2/tests/test15.h | 42 + openair2/LAYER2/rlc_v2/tests/test15.txt.gz | Bin 0 -> 360 bytes openair2/LAYER2/rlc_v2/tests/test16.h | 48 + openair2/LAYER2/rlc_v2/tests/test16.txt.gz | Bin 0 -> 353 bytes openair2/LAYER2/rlc_v2/tests/test17.h | 30 + openair2/LAYER2/rlc_v2/tests/test17.txt.gz | Bin 0 -> 298 bytes openair2/LAYER2/rlc_v2/tests/test18.h | 10 + openair2/LAYER2/rlc_v2/tests/test18.txt.gz | Bin 0 -> 207 bytes openair2/LAYER2/rlc_v2/tests/test19.h | 54 + openair2/LAYER2/rlc_v2/tests/test19.txt.gz | Bin 0 -> 101 bytes openair2/LAYER2/rlc_v2/tests/test2.h | 10 + openair2/LAYER2/rlc_v2/tests/test2.txt.gz | Bin 0 -> 1616 bytes openair2/LAYER2/rlc_v2/tests/test20.h | 28 + openair2/LAYER2/rlc_v2/tests/test20.txt.gz | Bin 0 -> 3931 bytes openair2/LAYER2/rlc_v2/tests/test21.h | 18 + openair2/LAYER2/rlc_v2/tests/test21.txt.gz | Bin 0 -> 970 bytes openair2/LAYER2/rlc_v2/tests/test22.h | 25 + openair2/LAYER2/rlc_v2/tests/test22.txt.gz | Bin 0 -> 392 bytes openair2/LAYER2/rlc_v2/tests/test23.h | 9 + openair2/LAYER2/rlc_v2/tests/test23.txt.gz | Bin 0 -> 266 bytes openair2/LAYER2/rlc_v2/tests/test24.h | 9 + openair2/LAYER2/rlc_v2/tests/test24.txt.gz | Bin 0 -> 324 bytes openair2/LAYER2/rlc_v2/tests/test25.h | 8 + openair2/LAYER2/rlc_v2/tests/test25.txt.gz | Bin 0 -> 161 bytes openair2/LAYER2/rlc_v2/tests/test26.h | 25 + openair2/LAYER2/rlc_v2/tests/test26.txt.gz | Bin 0 -> 374 bytes openair2/LAYER2/rlc_v2/tests/test27.h | 17 + openair2/LAYER2/rlc_v2/tests/test27.txt.gz | Bin 0 -> 243 bytes openair2/LAYER2/rlc_v2/tests/test28.h | 18 + openair2/LAYER2/rlc_v2/tests/test28.txt.gz | Bin 0 -> 282 bytes openair2/LAYER2/rlc_v2/tests/test29.h | 21 + openair2/LAYER2/rlc_v2/tests/test29.txt.gz | Bin 0 -> 349 bytes openair2/LAYER2/rlc_v2/tests/test3.h | 11 + openair2/LAYER2/rlc_v2/tests/test3.txt.gz | Bin 0 -> 757 bytes openair2/LAYER2/rlc_v2/tests/test30.h | 16 + openair2/LAYER2/rlc_v2/tests/test30.txt.gz | Bin 0 -> 395 bytes openair2/LAYER2/rlc_v2/tests/test31.h | 10 + openair2/LAYER2/rlc_v2/tests/test31.txt.gz | Bin 0 -> 267 bytes openair2/LAYER2/rlc_v2/tests/test32.h | 10 + openair2/LAYER2/rlc_v2/tests/test32.txt.gz | Bin 0 -> 268 bytes openair2/LAYER2/rlc_v2/tests/test33.h | 18 + openair2/LAYER2/rlc_v2/tests/test33.txt.gz | Bin 0 -> 421 bytes openair2/LAYER2/rlc_v2/tests/test34.h | 15 + openair2/LAYER2/rlc_v2/tests/test34.txt.gz | Bin 0 -> 434 bytes openair2/LAYER2/rlc_v2/tests/test35.h | 9 + openair2/LAYER2/rlc_v2/tests/test35.txt.gz | Bin 0 -> 170 bytes openair2/LAYER2/rlc_v2/tests/test36.h | 14 + openair2/LAYER2/rlc_v2/tests/test36.txt.gz | Bin 0 -> 379 bytes openair2/LAYER2/rlc_v2/tests/test37.h | 37 + openair2/LAYER2/rlc_v2/tests/test37.txt.gz | Bin 0 -> 92 bytes openair2/LAYER2/rlc_v2/tests/test38.h | 22 + openair2/LAYER2/rlc_v2/tests/test38.txt.gz | Bin 0 -> 1048 bytes openair2/LAYER2/rlc_v2/tests/test39.h | 9 + openair2/LAYER2/rlc_v2/tests/test39.txt.gz | Bin 0 -> 758 bytes openair2/LAYER2/rlc_v2/tests/test4.h | 13 + openair2/LAYER2/rlc_v2/tests/test4.txt.gz | Bin 0 -> 166 bytes openair2/LAYER2/rlc_v2/tests/test40.h | 9 + openair2/LAYER2/rlc_v2/tests/test40.txt.gz | Bin 0 -> 148 bytes openair2/LAYER2/rlc_v2/tests/test41.h | 45 + openair2/LAYER2/rlc_v2/tests/test41.txt.gz | Bin 0 -> 875 bytes openair2/LAYER2/rlc_v2/tests/test42.h | 39 + openair2/LAYER2/rlc_v2/tests/test42.txt.gz | Bin 0 -> 496 bytes openair2/LAYER2/rlc_v2/tests/test43.h | 39 + openair2/LAYER2/rlc_v2/tests/test43.txt.gz | Bin 0 -> 416 bytes openair2/LAYER2/rlc_v2/tests/test44.h | 20 + openair2/LAYER2/rlc_v2/tests/test44.txt.gz | Bin 0 -> 278 bytes openair2/LAYER2/rlc_v2/tests/test45.h | 30 + openair2/LAYER2/rlc_v2/tests/test45.txt.gz | Bin 0 -> 358 bytes openair2/LAYER2/rlc_v2/tests/test5.h | 13 + openair2/LAYER2/rlc_v2/tests/test5.txt.gz | Bin 0 -> 167 bytes openair2/LAYER2/rlc_v2/tests/test6.h | 27 + openair2/LAYER2/rlc_v2/tests/test6.txt.gz | Bin 0 -> 777 bytes openair2/LAYER2/rlc_v2/tests/test7.h | 26 + openair2/LAYER2/rlc_v2/tests/test7.txt.gz | Bin 0 -> 796 bytes openair2/LAYER2/rlc_v2/tests/test8.h | 19 + openair2/LAYER2/rlc_v2/tests/test8.txt.gz | Bin 0 -> 461 bytes openair2/LAYER2/rlc_v2/tests/test9.h | 34 + openair2/LAYER2/rlc_v2/tests/test9.txt.gz | Bin 0 -> 327 bytes openair2/RRC/LTE/rrc_eNB.c | 228 ++- 119 files changed, 6579 insertions(+), 23 deletions(-) create mode 100755 common/utils/T/tracer/hacks/pilot_timeplot.sh create mode 100644 openair2/LAYER2/rlc_v2/TODO create mode 100644 openair2/LAYER2/rlc_v2/asn1_utils.c create mode 100644 openair2/LAYER2/rlc_v2/asn1_utils.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_am.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_am.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_um.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_um.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_oai_api.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_pdu.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_pdu.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_sdu.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_sdu.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_ue_manager.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_ue_manager.h create mode 100644 openair2/LAYER2/rlc_v2/tests/LOG/log.h create mode 100644 openair2/LAYER2/rlc_v2/tests/Makefile create mode 100644 openair2/LAYER2/rlc_v2/tests/README create mode 100644 openair2/LAYER2/rlc_v2/tests/make_pdu.c create mode 100755 openair2/LAYER2/rlc_v2/tests/run_tests.sh create mode 100644 openair2/LAYER2/rlc_v2/tests/test.c create mode 100644 openair2/LAYER2/rlc_v2/tests/test1.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test1.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test10.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test10.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test11.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test11.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test12.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test12.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test13.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test13.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test14.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test14.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test15.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test15.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test16.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test16.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test17.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test17.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test18.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test18.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test19.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test19.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test2.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test2.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test20.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test20.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test21.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test21.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test22.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test22.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test23.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test23.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test24.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test24.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test25.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test25.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test26.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test26.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test27.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test27.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test28.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test28.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test29.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test29.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test3.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test3.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test30.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test30.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test31.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test31.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test32.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test32.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test33.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test33.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test34.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test34.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test35.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test35.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test36.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test36.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test37.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test37.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test38.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test38.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test39.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test39.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test4.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test4.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test40.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test40.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test41.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test41.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test42.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test42.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test43.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test43.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test44.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test44.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test45.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test45.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test5.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test5.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test6.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test6.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test7.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test7.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test8.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test8.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test9.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test9.txt.gz diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f155d3061d..68849c0191 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -727,7 +727,6 @@ Message("CPU_Affinity flag is ${CPU_AFFINITY}") ############################################################## add_boolean_option(NO_RRM True "DO WE HAVE A RADIO RESSOURCE MANAGER: NO") -add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "set the RLC mode to AM for the default bearer") add_boolean_option(OAI_NW_DRIVER_TYPE_ETHERNET False "????") add_boolean_option(DEADLINE_SCHEDULER True "Use the Linux scheduler SCHED_DEADLINE: kernel >= 3.14") @@ -828,7 +827,7 @@ add_boolean_option(TRACE_RLC_UM_TX_STATUS False "TRACE for RLC UM, TO BE CHANGE ########################## # RRC LAYER OPTIONS ########################## -add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "Otherwise it is UM, configure params are actually set in rrc_eNB.c:rrc_eNB_generate_defaultRRCConnectionReconfiguration(...)") +add_boolean_option(RRC_DEFAULT_RAB_IS_AM True "set the RLC mode to AM for the default bearer, otherwise it is UM.") ########################## @@ -1640,7 +1639,7 @@ set(NR_RRC_DIR ${OPENAIR2_DIR}/RRC/NR) set(NR_UE_RRC_DIR ${OPENAIR2_DIR}/RRC/NR_UE) set(PDCP_DIR ${OPENAIR2_DIR}/LAYER2/PDCP_v10.1.0) -set(LTE_RLC_SRC +set(RLC_ENB_V1 ${RLC_AM_DIR}/rlc_am.c ${RLC_AM_DIR}/rlc_am_init.c ${RLC_AM_DIR}/rlc_am_timer_poll_retransmit.c @@ -1670,6 +1669,17 @@ set(LTE_RLC_SRC ${RLC_DIR}/rlc_mpls.c ) +set(RLC_ENB_V2 + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_oai_api.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/asn1_utils.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_ue_manager.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_entity.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_entity_am.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_entity_um.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_pdu.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_sdu.c + ) + set(NR_RLC_SRC ${OPENAIR2_DIR}/LAYER2/nr_rlc/asn1_utils.c ${OPENAIR2_DIR}/LAYER2/nr_rlc/nr_rlc_entity.c @@ -1691,6 +1701,7 @@ set(L2_SRC ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c + ${RLC_ENB_V2} # ${RRC_DIR}/rrc_UE.c ${RRC_DIR}/rrc_eNB.c ${RRC_DIR}/rrc_eNB_endc.c @@ -1704,7 +1715,7 @@ set(L2_SRC ) set(L2_LTE_SRC - ${LTE_RLC_SRC} + ${RLC_ENB_V1} ) set(L2_NR_SRC @@ -1741,7 +1752,7 @@ set(LTE_NR_L2_SRC_UE ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c - ${LTE_RLC_SRC} + ${RLC_ENB_V1} ) set(NR_L2_SRC_UE diff --git a/common/utils/T/tracer/hacks/pilot_timeplot.sh b/common/utils/T/tracer/hacks/pilot_timeplot.sh new file mode 100755 index 0000000000..0d9c4694a6 --- /dev/null +++ b/common/utils/T/tracer/hacks/pilot_timeplot.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# use UP and DOWN arrow keys to scroll the view displayed by timeplot + +while read -n 1 key +do + case "$key" in + 'B' ) + kill -SIGUSR1 `ps aux|grep timeplot|grep -v grep|grep -v sh|tr -s ' ' :|cut -f 2 -d :` + ;; + 'A' ) + kill -SIGUSR2 `ps aux|grep timeplot|grep -v grep|grep -v sh|tr -s ' ' :|cut -f 2 -d :` + ;; + esac +done diff --git a/common/utils/T/tracer/hacks/time_meas.c b/common/utils/T/tracer/hacks/time_meas.c index 6bd2950301..408189cd80 100644 --- a/common/utils/T/tracer/hacks/time_meas.c +++ b/common/utils/T/tracer/hacks/time_meas.c @@ -13,7 +13,8 @@ void usage(void) "options:\n" " -d this option is mandatory\n" " -ip connect to given IP address (default %s)\n" -" -p connect to given port (default %d)\n", +" -p connect to given port (default %d)\n" +" -e event to trace (default VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER)\n", DEFAULT_REMOTE_IP, DEFAULT_REMOTE_PORT ); @@ -47,6 +48,7 @@ int main(int n, char **v) int ev_fun; int start_valid = 0; struct timespec start_time, stop_time, delta_time; + char *name = "VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER"; for (i = 1; i < n; i++) { if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); @@ -55,6 +57,7 @@ int main(int n, char **v) if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-e")) { if (i > n-2) usage(); name = v[++i]; continue; } usage(); } @@ -71,10 +74,9 @@ int main(int n, char **v) is_on = calloc(number_of_events, sizeof(int)); if (is_on == NULL) abort(); - on_off(database, "VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER", is_on, 1); + on_off(database, name, is_on, 1); - ev_fun = event_id_from_name(database, - "VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER"); + ev_fun = event_id_from_name(database, name); socket = connect_to(ip, port); diff --git a/common/utils/T/tracer/hacks/timeplot.c b/common/utils/T/tracer/hacks/timeplot.c index 79905d16f9..a1ddb2a1c9 100644 --- a/common/utils/T/tracer/hacks/timeplot.c +++ b/common/utils/T/tracer/hacks/timeplot.c @@ -28,6 +28,7 @@ int bins[50]; #define N 1000 int data[N]; +long start = 100; void plot(void) { @@ -45,7 +46,8 @@ void plot(void) if (data[i] < vmin) vmin = data[i]; if (data[i] > vmax) vmax = data[i]; vavg += data[i]; - int ms2 = data[i]/binsize_ns; + int ms2 = (data[i] - start * 1000)/binsize_ns; + if (ms2 < 0) ms2 = 0; if (ms2 > 49) ms2 = 49; bins[ms2]++; if (bins[ms2] > max) max = bins[ms2]; @@ -55,7 +57,7 @@ void plot(void) GOTO(1,1); for (i = 0; i < 50; i++) { - double binend = (i+1) * binsize_ns / 1000.; + double binend = (i+1) * binsize_ns / 1000. + start; int k; int width = bins[i] * 70 / max; /* force at least width of 1 if some point is there */ @@ -68,11 +70,23 @@ void plot(void) printf("min %d ns max %d ns avg %ld ns\n", vmin, vmax, vavg); } +void up(int x) +{ + start += 5; +} + +void down(int x) +{ + start -= 5; +} + int main(void) { int i; int pos = 0; signal(SIGINT, sig); + signal(SIGUSR1, up); + signal(SIGUSR2, down); RESET(); HIDE_CURSOR(); while (!feof(stdin)) { diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 1d0c2dfdb8..cde2497880 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -76,3 +76,6 @@ MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, NasDlDataInd // eNB: realtime -> RRC messages MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process) + +// eNB: RLC -> RRC messages +MESSAGE_DEF(RLC_SDU_INDICATION, MESSAGE_PRIORITY_MED, RlcSduIndication, rlc_sdu_indication) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 68e1753448..7582de65ba 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -87,6 +87,8 @@ #define RRC_SUBFRAME_PROCESS(mSGpTR) (mSGpTR)->ittiMsg.rrc_subframe_process +#define RLC_SDU_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.rlc_sdu_indication + //-------------------------------------------------------------------------------------------// typedef struct RrcStateInd_s { Rrc_State_t state; @@ -429,4 +431,12 @@ typedef struct rrc_subframe_process_s { int CC_id; } RrcSubframeProcess; +// eNB: RLC -> RRC messages +typedef struct rlc_sdu_indication_s { + int rnti; + int is_successful; + int srb_id; + int message_id; +} RlcSduIndication; + #endif /* RRC_MESSAGES_TYPES_H_ */ diff --git a/openair2/LAYER2/rlc_v2/TODO b/openair2/LAYER2/rlc_v2/TODO new file mode 100644 index 0000000000..0778d4320b --- /dev/null +++ b/openair2/LAYER2/rlc_v2/TODO @@ -0,0 +1,18 @@ +RLC AM +====== + +- 36.322 5.4 Re-establishment procedure + when possible, reassemble RLC SDUs from any byte segments of AMD PDUs + with SN < VR(MR) in the receiving side, remove RLC headers when doing + so and deliver all reassembled RLC SDUs to upper layer in ascending order + of the RLC SN, if not delivered before; + +- 36.322 5.2.3 Status reporting + delay triggering the STATUS report until x < VR(MS) or x >= VR(MR) + +- 36.322 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception + buffer + [...] and in-sequence byte segments of the AMD PDU with SN = VR(R) [...] + +- use SOstart/SOend in NACK reporting, do not NACK full PDU if + parts of it have been received diff --git a/openair2/LAYER2/rlc_v2/asn1_utils.c b/openair2/LAYER2/rlc_v2/asn1_utils.c new file mode 100644 index 0000000000..46f7d90da5 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/asn1_utils.c @@ -0,0 +1,129 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc.h" + +int decode_t_reordering(int v) +{ + static int tab[32] = { + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, + 90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 1600 + }; + + if (v < 0 || v > 31) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_t_status_prohibit(int v) +{ + static int tab[62] = { + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, + 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, + 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, + 245, 250, 300, 350, 400, 450, 500, 800, 1000, 1200, 1600, 2000, 2400 + }; + + if (v < 0 || v > 61) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_t_poll_retransmit(int v) +{ + static int tab[59] = { + 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, + 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, + 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 245, + 250, 300, 350, 400, 450, 500, 800, 1000, 2000, 4000 + }; + + if (v < 0 || v > 58) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_poll_pdu(int v) +{ + static int tab[8] = { + 4, 8, 16, 32, 64, 128, 256, -1 /* -1 means infinity */ + }; + + if (v < 0 || v > 7) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_poll_byte(int v) +{ + static int tab[15] = { + 25, 50, 75, 100, 125, 250, 375, 500, 750, 1000, 1250, 1500, 2000, 3000, + -1 /* -1 means infinity */ + }; + + if (v < 0 || v > 14) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (tab[v] == -1) return -1; + return tab[v] * 1024; +} + +int decode_max_retx_threshold(int v) +{ + static int tab[8] = { + 1, 2, 3, 4, 6, 8, 16, 32 + }; + + if (v < 0 || v > 7) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_sn_field_length(int v) +{ + static int tab[2] = { + 5, 10 + }; + + if (v < 0 || v > 1) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} diff --git a/openair2/LAYER2/rlc_v2/asn1_utils.h b/openair2/LAYER2/rlc_v2/asn1_utils.h new file mode 100644 index 0000000000..61394c9c69 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/asn1_utils.h @@ -0,0 +1,33 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _ASN1_UTILS_H_ +#define _ASN1_UTILS_H_ + +int decode_t_reordering(int v); +int decode_t_status_prohibit(int v); +int decode_t_poll_retransmit(int v); +int decode_poll_pdu(int v); +int decode_poll_byte(int v); +int decode_max_retx_threshold(int v); +int decode_sn_field_length(int v); + +#endif /* _ASN1_UTILS_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_entity.c b/openair2/LAYER2/rlc_v2/rlc_entity.c new file mode 100644 index 0000000000..d774e2b7e1 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity.c @@ -0,0 +1,144 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc_entity.h" + +#include + +#include "rlc_entity_am.h" +#include "rlc_entity_um.h" + +#include "LOG/log.h" + +rlc_entity_t *new_rlc_entity_am( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + void (*sdu_successful_delivery)(void *sdu_successful_delivery_data, + struct rlc_entity_t *entity, + int sdu_id), + void *sdu_successful_delivery_data, + void (*max_retx_reached)(void *max_retx_reached_data, + struct rlc_entity_t *entity), + void *max_retx_reached_data, + int t_reordering, + int t_status_prohibit, + int t_poll_retransmit, + int poll_pdu, + int poll_byte, + int max_retx_threshold) +{ + rlc_entity_am_t *ret; + + ret = calloc(1, sizeof(rlc_entity_am_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ret->common.recv_pdu = rlc_entity_am_recv_pdu; + ret->common.buffer_status = rlc_entity_am_buffer_status; + ret->common.generate_pdu = rlc_entity_am_generate_pdu; + + ret->common.recv_sdu = rlc_entity_am_recv_sdu; + + ret->common.set_time = rlc_entity_am_set_time; + + ret->common.discard_sdu = rlc_entity_am_discard_sdu; + + ret->common.reestablishment = rlc_entity_am_reestablishment; + + ret->common.delete = rlc_entity_am_delete; + + ret->common.deliver_sdu = deliver_sdu; + ret->common.deliver_sdu_data = deliver_sdu_data; + + ret->common.sdu_successful_delivery = sdu_successful_delivery; + ret->common.sdu_successful_delivery_data = sdu_successful_delivery_data; + + ret->common.max_retx_reached = max_retx_reached; + ret->common.max_retx_reached_data = max_retx_reached_data; + + ret->rx_maxsize = rx_maxsize; + ret->tx_maxsize = tx_maxsize; + ret->t_reordering = t_reordering; + ret->t_status_prohibit = t_status_prohibit; + ret->t_poll_retransmit = t_poll_retransmit; + ret->poll_pdu = poll_pdu; + ret->poll_byte = poll_byte; + ret->max_retx_threshold = max_retx_threshold; + + return (rlc_entity_t *)ret; +} + +rlc_entity_t *new_rlc_entity_um( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + int t_reordering, + int sn_field_length) +{ + rlc_entity_um_t *ret; + + ret = calloc(1, sizeof(rlc_entity_um_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ret->common.recv_pdu = rlc_entity_um_recv_pdu; + ret->common.buffer_status = rlc_entity_um_buffer_status; + ret->common.generate_pdu = rlc_entity_um_generate_pdu; + + ret->common.recv_sdu = rlc_entity_um_recv_sdu; + + ret->common.set_time = rlc_entity_um_set_time; + + ret->common.discard_sdu = rlc_entity_um_discard_sdu; + + ret->common.reestablishment = rlc_entity_um_reestablishment; + + ret->common.delete = rlc_entity_um_delete; + + ret->common.deliver_sdu = deliver_sdu; + ret->common.deliver_sdu_data = deliver_sdu_data; + + ret->sn_field_length = sn_field_length; + ret->rx_maxsize = rx_maxsize; + ret->tx_maxsize = tx_maxsize; + ret->t_reordering = t_reordering; + + if (sn_field_length == 5) + ret->sn_modulus = 32; + else if (sn_field_length == 10) + ret->sn_modulus = 1024; + else { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + ret->window_size = ret->sn_modulus / 2; + + return (rlc_entity_t *)ret; +} diff --git a/openair2/LAYER2/rlc_v2/rlc_entity.h b/openair2/LAYER2/rlc_v2/rlc_entity.h new file mode 100644 index 0000000000..c9b35204f0 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity.h @@ -0,0 +1,97 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_ENTITY_H_ +#define _RLC_ENTITY_H_ + +#include + +#define SDU_MAX 16000 /* maximum PDCP SDU size is 8188, let's take more */ + +typedef struct { + int status_size; + int tx_size; + int retx_size; +} rlc_entity_buffer_status_t; + +typedef struct rlc_entity_t { + /* functions provided by the RLC module */ + void (*recv_pdu)(struct rlc_entity_t *entity, char *buffer, int size); + rlc_entity_buffer_status_t (*buffer_status)( + struct rlc_entity_t *entity, int maxsize); + int (*generate_pdu)(struct rlc_entity_t *entity, char *buffer, int size); + + void (*recv_sdu)(struct rlc_entity_t *entity, char *buffer, int size, + int sdu_id); + + void (*set_time)(struct rlc_entity_t *entity, uint64_t now); + + void (*discard_sdu)(struct rlc_entity_t *entity, int sdu_id); + + void (*reestablishment)(struct rlc_entity_t *entity); + + void (*delete)(struct rlc_entity_t *entity); + + /* callbacks provided to the RLC module */ + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size); + void *deliver_sdu_data; + + void (*sdu_successful_delivery)(void *sdu_successful_delivery_data, + struct rlc_entity_t *entity, + int sdu_id); + void *sdu_successful_delivery_data; + + void (*max_retx_reached)(void *max_retx_reached_data, + struct rlc_entity_t *entity); + void *max_retx_reached_data; +} rlc_entity_t; + +rlc_entity_t *new_rlc_entity_am( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + void (*sdu_successful_delivery)(void *sdu_successful_delivery_data, + struct rlc_entity_t *entity, + int sdu_id), + void *sdu_successful_delivery_data, + void (*max_retx_reached)(void *max_retx_reached_data, + struct rlc_entity_t *entity), + void *max_retx_reached_data, + int t_reordering, + int t_status_prohibit, + int t_poll_retransmit, + int poll_pdu, + int poll_byte, + int max_retx_threshold); + +rlc_entity_t *new_rlc_entity_um( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + int t_reordering, + int sn_field_length); + +#endif /* _RLC_ENTITY_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_am.c b/openair2/LAYER2/rlc_v2/rlc_entity_am.c new file mode 100644 index 0000000000..5b3df3ec75 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_am.c @@ -0,0 +1,1694 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc_entity_am.h" +#include "rlc_pdu.h" + +#include +#include + +#include "LOG/log.h" + +/*************************************************************************/ +/* PDU RX functions */ +/*************************************************************************/ + +static int modulus_rx(rlc_entity_am_t *entity, int a) +{ + /* as per 36.322 7.1, modulus base is vr(r) and modulus is 1024 for rx */ + int r = a - entity->vr_r; + if (r < 0) r += 1024; + return r; +} + +/* used in both RX and TX processing */ +static int modulus_tx(rlc_entity_am_t *entity, int a) +{ + /* as per 36.322 7.1, modulus base is vt(a) and modulus is 1024 for tx */ + int r = a - entity->vt_a; + if (r < 0) r += 1024; + return r; +} + +static int sn_in_recv_window(void *_entity, int sn) +{ + rlc_entity_am_t *entity = _entity; + int mod_sn = modulus_rx(entity, sn); + /* we simplify vr(r)<=snrx_list; + + while (l != NULL) { + if (l->sn == sn && l->so <= so && + l->so + l->size - l->data_offset >= so + data_size) + return 1; + l = l->next; + } + + return 0; +} + +static int rlc_am_segment_full(rlc_entity_am_t *entity, int sn) +{ + rlc_rx_pdu_segment_t *l = entity->rx_list; + int last_byte; + int new_last_byte; + + last_byte = -1; + while (l != NULL) { + if (l->sn == sn) + break; + l = l->next; + } + while (l != NULL && l->sn == sn) { + if (l->so > last_byte + 1) + return 0; + if (l->is_last) + return 1; + new_last_byte = l->so + l->size - l->data_offset - 1; + if (new_last_byte > last_byte) + last_byte = new_last_byte; + l = l->next; + } + return 0; +} + +/* return 1 if the new segment has some data to consume, 0 if not */ +static int rlc_am_reassemble_next_segment(rlc_am_reassemble_t *r) +{ + int rf; + int sn; + + r->sdu_offset = r->start->data_offset; + + rlc_pdu_decoder_init(&r->dec, r->start->data, r->start->size); + + rlc_pdu_decoder_get_bits(&r->dec, 1); /* dc */ + rf = rlc_pdu_decoder_get_bits(&r->dec, 1); + rlc_pdu_decoder_get_bits(&r->dec, 1); /* p */ + r->fi = rlc_pdu_decoder_get_bits(&r->dec, 2); + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sn = rlc_pdu_decoder_get_bits(&r->dec, 10); + if (rf) { + rlc_pdu_decoder_get_bits(&r->dec, 1); /* lsf */ + r->so = rlc_pdu_decoder_get_bits(&r->dec, 15); + } else { + r->so = 0; + } + + if (r->e) { + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + r->sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + r->sdu_len = r->start->size - r->sdu_offset; + + /* new sn: read starts from PDU byte 0 */ + if (sn != r->sn) { + r->pdu_byte = 0; + r->sn = sn; + } + + r->data_pos = r->start->data_offset + r->pdu_byte - r->so; + + /* TODO: remove this check, it is useless, data has been validated before */ + if (r->pdu_byte < r->so) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + /* if pdu_byte is not in [so .. so+len-1] then all bytes from this segment + * have already been consumed + */ + if (r->pdu_byte >= r->so + r->start->size - r->start->data_offset) + return 0; + + /* go to correct SDU */ + while (r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset) + r->sdu_len) { + r->sdu_offset += r->sdu_len; + if (r->e) { + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + r->sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else { + r->sdu_len = r->start->size - r->sdu_offset; + } + } + + return 1; +} + +static void rlc_am_reassemble(rlc_entity_am_t *entity) +{ + rlc_am_reassemble_t *r = &entity->reassemble; + + while (r->start != NULL) { + if (r->sdu_pos >= SDU_MAX) { + /* TODO: proper error handling (discard PDUs with current sn from + * reassembly queue? something else?) + */ + LOG_E(RLC, "%s:%d:%s: bad RLC PDU\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + r->sdu[r->sdu_pos] = r->start->data[r->data_pos]; + r->sdu_pos++; + r->data_pos++; + r->pdu_byte++; + if (r->data_pos == r->sdu_offset + r->sdu_len) { + /* all bytes of SDU are consumed, check if SDU is fully there. + * It is if the data pointer is not at the end of the PDU segment + * or if 'fi' & 1 == 0 + */ + if (r->data_pos != r->start->size || + (r->fi & 1) == 0) { + /* SDU is full - deliver to higher layer */ + entity->common.deliver_sdu(entity->common.deliver_sdu_data, + (rlc_entity_t *)entity, + r->sdu, r->sdu_pos); + r->sdu_pos = 0; + } + if (r->data_pos != r->start->size) { + /* not at the end, process next SDU */ + r->sdu_offset += r->sdu_len; + if (r->e) { + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + r->sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + r->sdu_len = r->start->size - r->sdu_offset; + } else { + /* all bytes are consumend, go to next segment not already fully + * processed, if any + */ + do { + rlc_rx_pdu_segment_t *e = r->start; + entity->rx_size -= e->size; + r->start = r->start->next; + rlc_rx_free_pdu_segment(e); + } while (r->start != NULL && !rlc_am_reassemble_next_segment(r)); + } + } + } +} + +static void rlc_am_reception_actions(rlc_entity_am_t *entity, + rlc_rx_pdu_segment_t *pdu_segment) +{ + int x = pdu_segment->sn; + int vr_ms; + int vr_r; + + if (modulus_rx(entity, x) >= modulus_rx(entity, entity->vr_h)) + entity->vr_h = (x + 1) % 1024; + + vr_ms = entity->vr_ms; + while (rlc_am_segment_full(entity, vr_ms)) + vr_ms = (vr_ms + 1) % 1024; + entity->vr_ms = vr_ms; + + if (x == entity->vr_r) { + vr_r = entity->vr_r; + while (rlc_am_segment_full(entity, vr_r)) { + /* move segments with sn=vr(r) from rx list to end of reassembly list */ + while (entity->rx_list != NULL && entity->rx_list->sn == vr_r) { + rlc_rx_pdu_segment_t *e = entity->rx_list; + entity->rx_list = e->next; + e->next = NULL; + if (entity->reassemble.start == NULL) { + entity->reassemble.start = e; + /* the list was empty, we need to init decoder */ + entity->reassemble.sn = -1; + if (!rlc_am_reassemble_next_segment(&entity->reassemble)) { + /* TODO: proper error recovery (or remove the test, it should not happen) */ + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + } else { + entity->reassemble.end->next = e; + } + entity->reassemble.end = e; + } + + /* update vr_r */ + vr_r = (vr_r + 1) % 1024; + } + entity->vr_r = vr_r; + } + + rlc_am_reassemble(entity); + + if (entity->t_reordering_start) { + int vr_x = entity->vr_x; + if (vr_x < entity->vr_r) vr_x += 1024; + if (vr_x == entity->vr_r || vr_x > entity->vr_r + 512) + entity->t_reordering_start = 0; + } + + if (entity->t_reordering_start == 0) { + if (sn_compare_rx(entity, entity->vr_h, entity->vr_r) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_x = entity->vr_h; + } + } +} + +static void process_received_ack(rlc_entity_am_t *entity, int sn) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + /* put all PDUs from wait and retransmit lists with SN < 'sn' to ack_list */ + + /* process wait list */ + head.next = entity->wait_list; + prev = &head; + cur = entity->wait_list; + while (cur != NULL) { + if (sn_compare_tx(entity, cur->sn, sn) < 0) { + /* remove from wait list */ + prev->next = cur->next; + /* put the PDU in the ack list */ + entity->ack_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->ack_list, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->wait_list = head.next; + + /* process retransmit list */ + head.next = entity->retransmit_list; + prev = &head; + cur = entity->retransmit_list; + while (cur != NULL) { + if (sn_compare_tx(entity, cur->sn, sn) < 0) { + /* dec. retx_count in case we put this segment back in retransmit list + * in 'process_received_nack' + */ + cur->retx_count--; + /* remove from retransmit list */ + prev->next = cur->next; + /* put the PDU in the ack list */ + entity->ack_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->ack_list, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->retransmit_list = head.next; + +} + +static void consider_retransmission(rlc_entity_am_t *entity, + rlc_tx_pdu_segment_t *cur) +{ + cur->retx_count++; + + /* let's report max RETX reached for all retx_count >= max_retx_threshold + * (specs say to report if retx_count == max_retx_threshold). + * Upper layers should react (radio link failure), so no big deal actually. + */ + if (cur->retx_count >= entity->max_retx_threshold) { + entity->common.max_retx_reached(entity->common.max_retx_reached_data, + (rlc_entity_t *)entity); + } + + /* let's put in retransmit list even if we are over max_retx_threshold. + * upper layers should deal with this condition, internally it's better + * for the RLC code to keep going with this segment (we only remove + * a segment that was ACKed) + */ + entity->retransmit_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->retransmit_list, cur); +} + +static int so_overlap(int s1, int e1, int s2, int e2) +{ + if (s1 < s2) { + if (e1 == -1 || e1 >= s2) + return 1; + return 0; + } + if (e2 == -1 || s1 <= e2) + return 1; + return 0; +} + +static void process_received_nack(rlc_entity_am_t *entity, int sn, + int so_start, int so_end) +{ + /* put all PDU segments with SN == 'sn' and with an overlapping so start/end + * to the retransmit list + * source lists are ack list and wait list. + * Not sure if we should consider wait list, isn't the other end supposed + * to only NACK SNs lower than the ACK SN sent in the status PDU, in which + * case all potential PDU segments should all be in ack list when calling + * the current function? in doubt let's accept anything and thus process + * also wait list. + */ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + /* check that VT(A) <= sn < VT(S) */ + if (!(sn_compare_tx(entity, entity->vt_a, sn) <= 0 && + sn_compare_tx(entity, sn, entity->vt_s) < 0)) + return; + + /* process wait list */ + head.next = entity->wait_list; + prev = &head; + cur = entity->wait_list; + while (cur != NULL) { + if (cur->sn == sn && + so_overlap(so_start, so_end, cur->so, cur->so + cur->data_size - 1)) { + /* remove from wait list */ + prev->next = cur->next; + /* consider the PDU segment for retransmission */ + consider_retransmission(entity, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->wait_list = head.next; + + /* process ack list */ + head.next = entity->ack_list; + prev = &head; + cur = entity->ack_list; + while (cur != NULL) { + if (cur->sn == sn && + so_overlap(so_start, so_end, cur->so, cur->so + cur->data_size - 1)) { + /* remove from ack list */ + prev->next = cur->next; + /* consider the PDU segment for retransmission */ + consider_retransmission(entity, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->ack_list = head.next; +} + +int tx_pdu_in_ack_list_full(rlc_tx_pdu_segment_t *pdu) +{ + int sn = pdu->sn; + int last_byte = -1; + int new_last_byte; + int is_last_seen = 0; + + while (pdu != NULL && pdu->sn == sn) { + if (pdu->so > last_byte + 1) return 0; + if (pdu->is_last) + is_last_seen = 1; + new_last_byte = pdu->so + pdu->data_size - 1; + if (new_last_byte > last_byte) + last_byte = new_last_byte; + pdu = pdu->next; + } + + return is_last_seen == 1; +} + +int tx_pdu_in_ack_list_size(rlc_tx_pdu_segment_t *pdu) +{ + int sn = pdu->sn; + int ret = 0; + + while (pdu != NULL && pdu->sn == sn) { + ret += pdu->data_size; + pdu = pdu->next; + } + + return ret; +} + +void ack_sdu_bytes(rlc_sdu_t *start, int start_byte, int sdu_size) +{ + rlc_sdu_t *cur = start; + int remaining_size = sdu_size; + + while (remaining_size) { + int cursize = cur->size - start_byte; + if (cursize > remaining_size) + cursize = remaining_size; + cur->acked_bytes += cursize; + remaining_size -= cursize; + /* start_byte is only meaningful for the 1st SDU, then it is 0 */ + start_byte = 0; + cur = cur->next; + } +} + +rlc_tx_pdu_segment_t *tx_list_remove_sn(rlc_tx_pdu_segment_t *list, int sn) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + head.next = list; + cur = list; + prev = &head; + + while (cur != NULL) { + if (cur->sn == sn) { + prev->next = cur->next; + rlc_tx_free_pdu(cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + + return head.next; +} + +void cleanup_sdu_list(rlc_entity_am_t *entity) +{ + rlc_sdu_t head; + rlc_sdu_t *cur; + rlc_sdu_t *prev; + + /* remove fully acked SDUs, indicate successful delivery to upper layer */ + head.next = entity->tx_list; + cur = entity->tx_list; + prev = &head; + + while (cur != NULL) { + if (cur->acked_bytes == cur->size) { + prev->next = cur->next; + entity->tx_size -= cur->size; + entity->common.sdu_successful_delivery( + entity->common.sdu_successful_delivery_data, + (rlc_entity_t *)entity, cur->upper_layer_id); + rlc_free_sdu(cur); + entity->tx_end = prev; + cur = prev->next; + } else { + entity->tx_end = cur; + cur = cur->next; + } + } + + entity->tx_list = head.next; + + /* if tx_end == head then it means that the list is now empty */ + if (entity->tx_end == &head) + entity->tx_end = NULL; +} + +static void finalize_ack_nack_processing(rlc_entity_am_t *entity) +{ + int sn; + rlc_tx_pdu_segment_t *cur = entity->ack_list; + int pdu_size; + + if (cur == NULL) + return; + + /* Remove full PDUs and ack the SDU bytes they cover. Start from SN == VT(A) + * and process increasing SNs until end of list or missing ACK or PDU not + * fully ACKed. + */ + while (cur != NULL && cur->sn == entity->vt_a && + tx_pdu_in_ack_list_full(cur)) { + sn = cur->sn; + entity->vt_a = (entity->vt_a + 1) % 1024; + pdu_size = tx_pdu_in_ack_list_size(cur); + ack_sdu_bytes(cur->start_sdu, cur->sdu_start_byte, pdu_size); + while (cur != NULL && cur->sn == sn) + cur = cur->next; + entity->ack_list = tx_list_remove_sn(entity->ack_list, sn); + } + + cleanup_sdu_list(entity); +} + +void rlc_entity_am_recv_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ +#define R(d) do { if (rlc_pdu_decoder_in_error(&d)) goto err; } while (0) + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_pdu_decoder_t decoder; + rlc_pdu_decoder_t data_decoder; + rlc_pdu_decoder_t control_decoder; + + int dc; + int rf; + int p = 0; + int fi; + int e; + int sn; + int lsf; + int so; + + int cpt; + int e1; + int e2; + int ack_sn; + int nack_sn; + int so_start; + int so_end; + int control_e1; + int control_e2; + + int data_e; + int data_li; + + int packet_count; + int data_size; + int data_start; + int indicated_data_size; + + rlc_rx_pdu_segment_t *pdu_segment; + + rlc_pdu_decoder_init(&decoder, buffer, size); + dc = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + if (dc == 0) goto control; + + /* data PDU */ + rf = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + p = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + fi = rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); + e = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + sn = rlc_pdu_decoder_get_bits(&decoder, 10); R(decoder); + + /* dicard PDU if rx buffer is full */ + if (entity->rx_size + size > entity->rx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + goto discard; + } + + if (!sn_in_recv_window(entity, sn)) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, sn out of window (sn %d vr_r %d)\n", + __FILE__, __LINE__, __FUNCTION__, + sn, entity->vr_r); + goto discard; + } + + if (rf) { + lsf = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + so = rlc_pdu_decoder_get_bits(&decoder, 15); R(decoder); + } else { + lsf = 1; + so = 0; + } + + packet_count = 1; + + /* go to start of data */ + indicated_data_size = 0; + data_decoder = decoder; + data_e = e; + while (data_e) { + data_e = rlc_pdu_decoder_get_bits(&data_decoder, 1); R(data_decoder); + data_li = rlc_pdu_decoder_get_bits(&data_decoder, 11); R(data_decoder); + if (data_li == 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, li == 0\n", + __FILE__, __LINE__, __FUNCTION__); + goto discard; + } + indicated_data_size += data_li; + packet_count++; + } + rlc_pdu_decoder_align(&data_decoder); + + data_start = data_decoder.byte; + data_size = size - data_start; + + if (data_size <= 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, wrong data size (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + goto discard; + } + if (indicated_data_size >= data_size) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, bad LIs (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + goto discard; + } + + /* discard segment if all the bytes of the segment are already there */ + if (segment_already_received(entity, sn, so, data_size)) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, already received\n", + __FILE__, __LINE__, __FUNCTION__); + goto discard; + } + + char *fi_str[] = { + "first byte: YES last byte: YES", + "first byte: YES last byte: NO", + "first byte: NO last byte: YES", + "first byte: NO last byte: NO", + }; + + LOG_D(RLC, "found %d packets, data size %d data start %d [fi %d %s] (sn %d) (p %d)\n", + packet_count, data_size, data_decoder.byte, fi, fi_str[fi], sn, p); + + /* put in pdu reception list */ + entity->rx_size += size; + pdu_segment = rlc_rx_new_pdu_segment(sn, so, size, lsf, buffer, data_start); + entity->rx_list = rlc_rx_pdu_segment_list_add(sn_compare_rx, entity, + entity->rx_list, pdu_segment); + + /* do reception actions (36.322 5.1.3.2.3) */ + rlc_am_reception_actions(entity, pdu_segment); + + if (p) { + /* 36.322 5.2.3 says status triggering should be delayed + * until x < VR(MS) or x >= VR(MR). This is not clear (what + * is x then? we keep the same?). So let's trigger no matter what. + */ + int vr_mr = (entity->vr_r + 512) % 1024; + entity->status_triggered = 1; + if (!(sn_compare_rx(entity, sn, entity->vr_ms) < 0 || + sn_compare_rx(entity, sn, vr_mr) >= 0)) { + LOG_D(RLC, "%s:%d:%s: warning: STATUS trigger should be delayed, according to specs\n", + __FILE__, __LINE__, __FUNCTION__); + } + } + + return; + +control: + cpt = rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); + if (cpt != 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, CPT not 0 (%d)\n", + __FILE__, __LINE__, __FUNCTION__, cpt); + goto discard; + } + ack_sn = rlc_pdu_decoder_get_bits(&decoder, 10); R(decoder); + e1 = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + + /* let's try to parse the control PDU once to check consistency */ + control_decoder = decoder; + control_e1 = e1; + while (control_e1) { + rlc_pdu_decoder_get_bits(&control_decoder, 10); R(control_decoder); /* NACK_SN */ + control_e1 = rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); + control_e2 = rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); + if (control_e2) { + rlc_pdu_decoder_get_bits(&control_decoder, 15); R(control_decoder); /* SOstart */ + rlc_pdu_decoder_get_bits(&control_decoder, 15); R(control_decoder); /* SOend */ + } + } + + /* 36.322 5.2.2.2 says to stop t_poll_retransmit if a ACK or NACK is + * received for the SN 'poll_sn' + */ + if (sn_compare_tx(entity, entity->poll_sn, ack_sn) < 0) + entity->t_poll_retransmit_start = 0; + + /* at this point, accept the PDU even if the actual values + * may be incorrect (eg. if so_start > so_end) + */ + process_received_ack(entity, ack_sn); + + while (e1) { + nack_sn = rlc_pdu_decoder_get_bits(&decoder, 10); R(decoder); + e1 = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + e2 = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + if (e2) { + so_start = rlc_pdu_decoder_get_bits(&decoder, 15); R(decoder); + so_end = rlc_pdu_decoder_get_bits(&decoder, 15); R(decoder); + if (so_end < so_start) { + LOG_W(RLC, "%s:%d:%s: warning, bad so start/end, NACK the whole PDU (sn %d)\n", + __FILE__, __LINE__, __FUNCTION__, nack_sn); + so_start = 0; + so_end = -1; + } + /* special value 0x7fff indicates 'all bytes to the end' */ + if (so_end == 0x7fff) + so_end = -1; + } else { + so_start = 0; + so_end = -1; + } + process_received_nack(entity, nack_sn, so_start, so_end); + + /* 36.322 5.2.2.2 says to stop t_poll_retransmit if a ACK or NACK is + * received for the SN 'poll_sn' + */ + if (entity->poll_sn == nack_sn) + entity->t_poll_retransmit_start = 0; + } + + finalize_ack_nack_processing(entity); + + return; + +err: + LOG_W(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__); + goto discard; + +discard: + if (p) + entity->status_triggered = 1; + +#undef R +} + +/*************************************************************************/ +/* TX functions */ +/*************************************************************************/ + +static int pdu_size(rlc_entity_am_t *entity, rlc_tx_pdu_segment_t *pdu) +{ + int header_size; + int sdu_count; + int data_size; + int li_bits; + rlc_sdu_t *sdu; + + header_size = 2; + if (pdu->is_segment) + header_size += 2; + + data_size = pdu->data_size; + + sdu = pdu->start_sdu; + + sdu_count = 1; + data_size -= sdu->size - pdu->sdu_start_byte; + sdu = sdu->next; + + while (data_size > 0) { + sdu_count++; + data_size -= sdu->size; + sdu = sdu->next; + } + + li_bits = 12 * (sdu_count - 1); + header_size += (li_bits + 7) / 8; + + return header_size + pdu->data_size; +} + +static int header_size(int sdu_count) +{ + int bits = 16 + 12 * (sdu_count - 1); + /* padding if we have to */ + return (bits + 7) / 8; +} + +typedef struct { + int sdu_count; + int data_size; + int header_size; +} tx_pdu_size_t; + +static tx_pdu_size_t compute_new_pdu_size(rlc_entity_am_t *entity, int maxsize) +{ + tx_pdu_size_t ret; + int sdu_count; + int sdu_size; + int pdu_data_size; + rlc_sdu_t *sdu; + + int vt_ms = (entity->vt_a + 512) % 1024; + + ret.sdu_count = 0; + ret.data_size = 0; + ret.header_size = 0; + + /* sn out of window? nothing to do */ + if (!(sn_compare_tx(entity, entity->vt_s, entity->vt_a) >= 0 && + sn_compare_tx(entity, entity->vt_s, vt_ms) < 0)) + return ret; + + /* TX PDU - let's make the biggest PDU we can with the SDUs we have */ + sdu_count = 0; + pdu_data_size = 0; + sdu = entity->tx_list; + while (sdu != NULL) { + /* include SDU only if it has not been fully included in PDUs already */ + if (sdu->next_byte != sdu->size) { + int new_header_size = header_size(sdu_count + 1); + /* if we cannot put new header + at least 1 byte of data then over */ + if (new_header_size + pdu_data_size + 1 > maxsize) + break; + sdu_count++; + /* only include the bytes of this SDU not included in PDUs already */ + sdu_size = sdu->size - sdu->next_byte; + /* don't feed more than 'maxsize' bytes */ + if (new_header_size + pdu_data_size + sdu_size > maxsize) + sdu_size = maxsize - new_header_size - pdu_data_size; + pdu_data_size += sdu_size; + /* if we put more than 2^11-1 bytes then the LI field cannot be used, + * so this is the last SDU we can put + */ + if (sdu_size > 2047) + break; + } + sdu = sdu->next; + } + + if (sdu_count) { + ret.sdu_count = sdu_count; + ret.data_size = pdu_data_size; + ret.header_size = header_size(sdu_count); + } + + return ret; +} + +static int status_size(rlc_entity_am_t *entity, int maxsize) +{ + /* let's count bits */ + int bits = 15; /* minimum size is 15 (header+ack_sn+e1) */ + int sn; + + maxsize *= 8; + + if (bits > maxsize) { + LOG_W(RLC, "%s:%d:%s: warning: cannot generate status PDU, not enough room\n", + __FILE__, __LINE__, __FUNCTION__); + return 0; + } + + /* each NACK adds 12 bits */ + sn = entity->vr_r; + while (bits + 12 <= maxsize && sn_compare_rx(entity, sn, entity->vr_ms) < 0) { + if (!(rlc_am_segment_full(entity, sn))) + bits += 12; + sn = (sn + 1) % 1024; + } + + return (bits + 7) / 8; +} + +static int generate_status(rlc_entity_am_t *entity, char *buffer, int size) +{ + /* let's count bits */ + int bits = 15; /* minimum size is 15 (header+ack_sn+e1) */ + int sn; + rlc_pdu_encoder_t encoder; + int has_nack = 0; + int ack; + + rlc_pdu_encoder_init(&encoder, buffer, size); + + size *= 8; + + if (bits > size) { + LOG_W(RLC, "%s:%d:%s: warning: cannot generate status PDU, not enough room\n", + __FILE__, __LINE__, __FUNCTION__); + return 0; + } + + /* header */ + rlc_pdu_encoder_put_bits(&encoder, 0, 1); /* D/C */ + rlc_pdu_encoder_put_bits(&encoder, 0, 3); /* CPT */ + + /* reserve room for ACK (it will be set after putting the NACKs) */ + rlc_pdu_encoder_put_bits(&encoder, 0, 10); + + /* at this point, ACK is VR(R) */ + ack = entity->vr_r; + + /* each NACK adds 12 bits */ + sn = entity->vr_r; + while (bits + 12 <= size && sn_compare_rx(entity, sn, entity->vr_ms) < 0) { + if (!(rlc_am_segment_full(entity, sn))) { + /* put previous e1 (is 1) */ + rlc_pdu_encoder_put_bits(&encoder, 1, 1); + /* if previous was NACK, put previous e2 (0, we don't do 'so' thing) */ + if (has_nack) + rlc_pdu_encoder_put_bits(&encoder, 0, 1); + /* put NACKed sn */ + rlc_pdu_encoder_put_bits(&encoder, sn, 10); + has_nack = 1; + bits += 12; + } else { + /* this sn is full and we put all NACKs before it, use it for ACK */ + ack = (sn + 1) % 1024; + } + sn = (sn + 1) % 1024; + } + + /* go to highest full sn+1 for ACK, VR(MS) is the limit */ + while (sn_compare_rx(entity, sn, entity->vr_ms) < 0 && + rlc_am_segment_full(entity, sn)) { + ack = (sn + 1) % 1024; + sn = (sn + 1) % 1024; + } + + /* at this point, if last put was NACK then put 2 bits else put 1 bit */ + if (has_nack) + rlc_pdu_encoder_put_bits(&encoder, 0, 2); + else + rlc_pdu_encoder_put_bits(&encoder, 0, 1); + + rlc_pdu_encoder_align(&encoder); + + /* let's put the ACK */ + buffer[0] |= ack >> 6; + buffer[1] |= (ack & 0x3f) << 2; + + /* reset the trigger */ + entity->status_triggered = 0; + + /* start t_status_prohibit */ + entity->t_status_prohibit_start = entity->t_current; + + return encoder.byte; +} + +int transmission_buffer_empty(rlc_entity_am_t *entity) +{ + rlc_sdu_t *sdu; + + /* is transmission buffer empty? */ + sdu = entity->tx_list; + while (sdu != NULL) { + if (sdu->next_byte != sdu->size) + return 0; + sdu = sdu->next; + } + return 1; +} + +int check_poll_after_pdu_assembly(rlc_entity_am_t *entity) +{ + int retransmission_buffer_empty; + int window_stalling; + int vt_ms; + + /* is retransmission buffer empty? */ + if (entity->retransmit_list == NULL) + retransmission_buffer_empty = 1; + else + retransmission_buffer_empty = 0; + + /* is window stalling? */ + vt_ms = (entity->vt_a + 512) % 1024; + if (!(sn_compare_tx(entity, entity->vt_s, entity->vt_a) >= 0 && + sn_compare_tx(entity, entity->vt_s, vt_ms) < 0)) + window_stalling = 1; + else + window_stalling = 0; + + return (transmission_buffer_empty(entity) && retransmission_buffer_empty) || + window_stalling; +} + +void include_poll(rlc_entity_am_t *entity, char *buffer) +{ + /* set the P bit to 1 */ + buffer[0] |= 0x20; + + entity->pdu_without_poll = 0; + entity->byte_without_poll = 0; + + /* set POLL_SN to VT(S) - 1 */ + entity->poll_sn = (entity->vt_s + 1023) % 1024; + + /* start t_poll_retransmit */ + entity->t_poll_retransmit_start = entity->t_current; +} + +static int serialize_pdu(rlc_entity_am_t *entity, char *buffer, int bufsize, + rlc_tx_pdu_segment_t *pdu, int p) +{ + int first_sdu_full; + int last_sdu_full; + int sdu_next_byte; + rlc_sdu_t *sdu; + int i; + int cursize; + rlc_pdu_encoder_t encoder; + int fi; + int e; + int li; + char *out; + int outpos; + int sdu_count; + int header_size; + int sdu_start_byte; + + first_sdu_full = pdu->sdu_start_byte == 0; + + /* is last SDU full? (and also compute sdu_count) */ + last_sdu_full = 1; + sdu = pdu->start_sdu; + sdu_next_byte = pdu->sdu_start_byte; + cursize = 0; + sdu_count = 0; + while (cursize != pdu->data_size) { + int sdu_size = sdu->size - sdu_next_byte; + sdu_count++; + if (cursize + sdu_size > pdu->data_size) { + last_sdu_full = 0; + break; + } + cursize += sdu_size; + sdu = sdu->next; + sdu_next_byte = 0; + } + + /* generate header */ + rlc_pdu_encoder_init(&encoder, buffer, bufsize); + + rlc_pdu_encoder_put_bits(&encoder, 1, 1); /* D/C: 1 = data */ + rlc_pdu_encoder_put_bits(&encoder, pdu->is_segment, 1); /* RF */ + rlc_pdu_encoder_put_bits(&encoder, 0, 1); /* P: reserve, set later */ + + fi = 0; + if (!first_sdu_full) + fi |= 0x02; + if (!last_sdu_full) + fi |= 0x01; + rlc_pdu_encoder_put_bits(&encoder, fi, 2); /* FI */ + + /* to understand the logic for Es and LIs: + * If we have: + * 1 SDU: E=0 + * + * 2 SDUs: E=1 + * then: E=0 LI(sdu[0]) + * + * 3 SDUs: E=1 + * then: E=1 LI(sdu[0]) + * then: E=0 LI(sdu[1]) + * + * 4 SDUs: E=1 + * then: E=1 LI(sdu[0]) + * then: E=1 LI(sdu[1]) + * then: E=0 LI(sdu[2]) + */ + if (sdu_count >= 2) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + + rlc_pdu_encoder_put_bits(&encoder, pdu->sn, 10); /* SN */ + + if (pdu->is_segment) { + rlc_pdu_encoder_put_bits(&encoder, pdu->is_last, 1); /* LSF */ + rlc_pdu_encoder_put_bits(&encoder, pdu->so, 15); /* SO */ + } + + /* put LIs */ + sdu = pdu->start_sdu; + /* first SDU */ + li = sdu->size - pdu->sdu_start_byte; + /* put E+LI only if at least 2 SDUs */ + if (sdu_count >= 2) { + /* E is 1 if at least 3 SDUs */ + if (sdu_count >= 3) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + /* next SDUs, but not the last (no LI for the last) */ + sdu = sdu->next; + for (i = 2; i < sdu_count; i++, sdu = sdu->next) { + if (i != sdu_count - 1) + e = 1; + else + e = 0; + li = sdu->size; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + + rlc_pdu_encoder_align(&encoder); + + header_size = encoder.byte; + + /* generate data */ + out = buffer + header_size; + sdu = pdu->start_sdu; + sdu_start_byte = pdu->sdu_start_byte; + outpos = 0; + for (i = 0; i < sdu_count; i++, sdu = sdu->next) { + li = sdu->size - sdu_start_byte; + if (outpos + li >= pdu->data_size) + li = pdu->data_size - outpos; + memcpy(out+outpos, sdu->data + sdu_start_byte, li); + outpos += li; + sdu_start_byte = 0; + } + + if (p) + include_poll(entity, buffer); + + return header_size + pdu->data_size; +} + +static int generate_tx_pdu(rlc_entity_am_t *entity, char *buffer, int bufsize) +{ + int vt_ms; + tx_pdu_size_t pdu_size; + rlc_sdu_t *sdu; + int i; + int cursize; + int p; + rlc_tx_pdu_segment_t *pdu; + + /* sn out of window? do nothing */ + vt_ms = (entity->vt_a + 512) % 1024; + if (!(sn_compare_tx(entity, entity->vt_s, entity->vt_a) >= 0 && + sn_compare_tx(entity, entity->vt_s, vt_ms) < 0)) + return 0; + + pdu_size = compute_new_pdu_size(entity, bufsize); + if (pdu_size.sdu_count == 0) + return 0; + + pdu = rlc_tx_new_pdu(); + + pdu->sn = entity->vt_s; + entity->vt_s = (entity->vt_s + 1) % 1024; + + /* go to first SDU (skip those already fully processed) */ + sdu = entity->tx_list; + while (sdu->next_byte == sdu->size) + sdu = sdu->next; + + pdu->start_sdu = sdu; + + pdu->sdu_start_byte = sdu->next_byte; + + pdu->so = 0; + pdu->is_segment = 0; + pdu->is_last = 1; + /* to conform to specs' logic, put -1 (specs say "for 1st retransmission + * put 0 otherwise increase", let's put -1 and always increase when the + * segment goes to retransmit list) + */ + pdu->retx_count = -1; + + /* reserve SDU bytes */ + cursize = 0; + for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + int sdu_size = sdu->size - sdu->next_byte; + if (cursize + sdu_size > pdu_size.data_size) + sdu_size = pdu_size.data_size - cursize; + sdu->next_byte += sdu_size; + cursize += sdu_size; + } + + pdu->data_size = cursize; + + /* put PDU at the end of the wait list */ + entity->wait_list = rlc_tx_pdu_list_append(entity->wait_list, pdu); + + /* polling actions for a new PDU */ + entity->pdu_without_poll++; + entity->byte_without_poll += pdu_size.data_size; + if ((entity->poll_pdu != -1 && + entity->pdu_without_poll >= entity->poll_pdu) || + (entity->poll_byte != -1 && + entity->byte_without_poll >= entity->poll_byte)) + p = 1; + else + p = check_poll_after_pdu_assembly(entity); + + if (entity->force_poll) { + p = 1; + entity->force_poll = 0; + } + + return serialize_pdu(entity, buffer, bufsize, pdu, p); +} + +static void resegment(rlc_tx_pdu_segment_t *pdu, int size) +{ + rlc_tx_pdu_segment_t *new_pdu; + rlc_sdu_t *sdu; + int sdu_count; + int pdu_header_size; + int pdu_data_size; + int sdu_pos; + int sdu_bytes_to_take; + + /* PDU segment too big, cut in two parts so that first part fits into + * size bytes (including header) + */ + sdu = pdu->start_sdu; + pdu_data_size = 0; + sdu_pos = pdu->sdu_start_byte; + sdu_count = 0; + while (1) { + /* can we put a new header and at least one byte of data? */ + /* header has 2 more bytes for SO */ + pdu_header_size = 2 + header_size(sdu_count + 1); + if (pdu_header_size + pdu_data_size + 1 > size) { + /* no we can't, stop here */ + break; + } + /* yes we can, go ahead */ + sdu_count++; + sdu_bytes_to_take = sdu->size - sdu_pos; + if (pdu_header_size + pdu_data_size + sdu_bytes_to_take > size) { + sdu_bytes_to_take = size - (pdu_header_size + pdu_data_size); + } + sdu_pos += sdu_bytes_to_take; + if (sdu_pos == sdu->size) { + sdu = sdu->next; + sdu_pos = 0; + } + pdu_data_size += sdu_bytes_to_take; + } + + new_pdu = rlc_tx_new_pdu(); + pdu->is_segment = 1; + *new_pdu = *pdu; + + new_pdu->so = pdu->so + pdu_data_size; + new_pdu->data_size = pdu->data_size - pdu_data_size; + new_pdu->start_sdu = sdu; + new_pdu->sdu_start_byte = sdu_pos; + + pdu->is_last = 0; + pdu->data_size = pdu_data_size; + pdu->next = new_pdu; +} + +static int generate_retx_pdu(rlc_entity_am_t *entity, char *buffer, int size) +{ + rlc_tx_pdu_segment_t *pdu; + int orig_size; + int p; + + pdu = entity->retransmit_list; + orig_size = pdu_size(entity, pdu); + + if (orig_size > size) { + /* we can't resegment if size is less than 5 + * (4 bytes for header, 1 byte for data) + */ + if (size < 5) + return 0; + resegment(pdu, size); + } + + /* remove from retransmit list and put in wait list */ + entity->retransmit_list = pdu->next; + entity->wait_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->wait_list, pdu); + + p = check_poll_after_pdu_assembly(entity); + + if (entity->force_poll) { + p = 1; + entity->force_poll = 0; + } + + return serialize_pdu(entity, buffer, orig_size, pdu, p); +} + +static int status_to_report(rlc_entity_am_t *entity) +{ + return entity->status_triggered && + (entity->t_status_prohibit_start == 0 || + entity->t_current - entity->t_status_prohibit_start > + entity->t_status_prohibit); +} + +static int retx_pdu_size(rlc_entity_am_t *entity, int maxsize) +{ + int size; + + if (entity->retransmit_list == NULL) + return 0; + + size = pdu_size(entity, entity->retransmit_list); + if (size <= maxsize) + return size; + + /* we can segment head of retransmist list if maxsize is large enough + * to hold a PDU segment with at least 1 data byte (so 5 bytes: 4 bytes + * header + 1 byte data) + */ + if (maxsize < 5) + return 0; + + /* a later segmentation of the head of retransmit list will generate a pdu + * of maximum size 'maxsize' (can be less) + */ + return maxsize; +} + +rlc_entity_buffer_status_t rlc_entity_am_buffer_status( + rlc_entity_t *_entity, int maxsize) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_entity_buffer_status_t ret; + tx_pdu_size_t tx_size; + + /* status PDU, if we have to */ + if (status_to_report(entity)) + ret.status_size = status_size(entity, maxsize); + else + ret.status_size = 0; + + /* TX PDU */ + tx_size = compute_new_pdu_size(entity, maxsize); + ret.tx_size = tx_size.data_size + tx_size.header_size; + + /* reTX PDU */ + ret.retx_size = retx_pdu_size(entity, maxsize); + + return ret; +} + +int rlc_entity_am_generate_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + int ret; + + if (status_to_report(entity)) { + ret = generate_status(entity, buffer, size); + if (ret != 0) + return ret; + } + + if (entity->retransmit_list != NULL) { + ret = generate_retx_pdu(entity, buffer, size); + if (ret != 0) + return ret; + } + + return generate_tx_pdu(entity, buffer, size); +} + +/*************************************************************************/ +/* SDU RX functions */ +/*************************************************************************/ + +void rlc_entity_am_recv_sdu(rlc_entity_t *_entity, char *buffer, int size, + int sdu_id) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_sdu_t *sdu; + + if (size > SDU_MAX) { + LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", + __FILE__, __LINE__, __FUNCTION__, size); + exit(1); + } + + if (entity->tx_size + size > entity->tx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + entity->tx_size += size; + + sdu = rlc_new_sdu(buffer, size, sdu_id); + rlc_sdu_list_add(&entity->tx_list, &entity->tx_end, sdu); +} + +/*************************************************************************/ +/* time/timers */ +/*************************************************************************/ + +static void check_t_poll_retransmit(rlc_entity_am_t *entity) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + int sn; + + /* 36.322 5.2.2.3 */ + /* did t_poll_retransmit expire? */ + if (entity->t_poll_retransmit_start == 0 || + entity->t_current <= entity->t_poll_retransmit_start + + entity->t_poll_retransmit) + return; + + /* stop timer */ + entity->t_poll_retransmit_start = 0; + + /* 36.322 5.2.2.3 says: + * + * - include a poll in a RLC data PDU as described in section 5.2.2.1 + * + * That does not seem to be conditional. So we forcefully will send + * a poll as soon as we generate a PDU. + * Hopefully this interpretation is correct. In the worst case we generate + * more polling than necessary, but it's not a big deal. When + * 't_poll_retransmit' expires it means we didn't receive a status report, + * meaning a bad radio link, so things are quite bad at this point and + * asking again for a poll won't hurt much more. + */ + entity->force_poll = 1; + + LOG_D(RLC, "%s:%d:%s: warning: t_poll_retransmit expired\n", + __FILE__, __LINE__, __FUNCTION__); + + /* do we meet conditions of 36.322 5.2.2.3? */ + if (!check_poll_after_pdu_assembly(entity)) + return; + + /* search wait list for PDU with SN = VT(S)-1 */ + sn = (entity->vt_s + 1023) % 1024; + + head.next = entity->wait_list; + cur = entity->wait_list; + prev = &head; + + while (cur != NULL) { + if (cur->sn == sn) + break; + prev = cur; + cur = cur->next; + } + + /* PDU with SN = VT(S)-1 not found?, take the head of wait list */ + if (cur == NULL) { + cur = entity->wait_list; + prev = &head; + sn = cur->sn; + } + + /* 36.322 says "PDU", not "PDU segment", so let's retransmit all + * PDU segments with this SN + */ + while (cur != NULL && cur->sn == sn) { + prev->next = cur->next; + entity->wait_list = head.next; + /* put in retransmit list */ + consider_retransmission(entity, cur); + cur = prev->next; + } +} + +static void check_t_reordering(rlc_entity_am_t *entity) +{ + int sn; + + /* is t_reordering running and if yes has it expired? */ + if (entity->t_reordering_start == 0 || + entity->t_current <= entity->t_reordering_start + entity->t_reordering) + return; + + /* stop timer */ + entity->t_reordering_start = 0; + + LOG_D(RLC, "%s:%d:%s: t_reordering expired\n", __FILE__, __LINE__, __FUNCTION__); + + /* update VR(MS) to first SN >= VR(X) for which not all PDU segments + * have been received + */ + sn = entity->vr_x; + while (rlc_am_segment_full(entity, sn)) + sn = (sn + 1) % 1024; + entity->vr_ms = sn; + + if (sn_compare_rx(entity, entity->vr_h, entity->vr_ms) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_x = entity->vr_h; + } + + /* trigger STATUS report */ + entity->status_triggered = 1; +} + +void rlc_entity_am_set_time(rlc_entity_t *_entity, uint64_t now) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + + entity->t_current = now; + + check_t_poll_retransmit(entity); + + check_t_reordering(entity); + + /* t_status_prohibit is handled by generate_status */ +} + +/*************************************************************************/ +/* discard/re-establishment/delete */ +/*************************************************************************/ + +void rlc_entity_am_discard_sdu(rlc_entity_t *_entity, int sdu_id) +{ + /* implements 36.322 5.3 */ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_sdu_t head; + rlc_sdu_t *cur; + rlc_sdu_t *prev; + + head.next = entity->tx_list; + cur = entity->tx_list; + prev = &head; + + while (cur != NULL && cur->upper_layer_id != sdu_id) { + prev = cur; + cur = cur->next; + } + + /* if sdu_id not found or some bytes have already been 'PDU-ized' + * then do nothing + */ + if (cur == NULL || cur->next_byte != 0) + return; + + /* remove SDU from tx_list */ + prev->next = cur->next; + entity->tx_list = head.next; + if (entity->tx_end == cur) { + if (prev != &head) + entity->tx_end = prev; + else + entity->tx_end = NULL; + } + + rlc_free_sdu(cur); +} + +static void free_pdu_segment_list(rlc_tx_pdu_segment_t *l) +{ + rlc_tx_pdu_segment_t *cur; + + while (l != NULL) { + cur = l; + l = l->next; + rlc_tx_free_pdu(cur); + } +} + +static void clear_entity(rlc_entity_am_t *entity) +{ + rlc_rx_pdu_segment_t *cur_rx; + rlc_sdu_t *cur_tx; + + entity->vr_r = 0; + entity->vr_x = 0; + entity->vr_ms = 0; + entity->vr_h = 0; + + entity->status_triggered = 0; + + entity->vt_a = 0; + entity->vt_s = 0; + entity->poll_sn = 0; + entity->pdu_without_poll = 0; + entity->byte_without_poll = 0; + entity->force_poll = 0; + + entity->t_current = 0; + + entity->t_reordering_start = 0; + entity->t_status_prohibit_start = 0; + entity->t_poll_retransmit_start = 0; + + cur_rx = entity->rx_list; + while (cur_rx != NULL) { + rlc_rx_pdu_segment_t *p = cur_rx; + cur_rx = cur_rx->next; + rlc_rx_free_pdu_segment(p); + } + entity->rx_list = NULL; + entity->rx_size = 0; + + memset(&entity->reassemble, 0, sizeof(rlc_am_reassemble_t)); + + cur_tx = entity->tx_list; + while (cur_tx != NULL) { + rlc_sdu_t *p = cur_tx; + cur_tx = cur_tx->next; + rlc_free_sdu(p); + } + entity->tx_list = NULL; + entity->tx_end = NULL; + entity->tx_size = 0; + + free_pdu_segment_list(entity->wait_list); + free_pdu_segment_list(entity->retransmit_list); + free_pdu_segment_list(entity->ack_list); + entity->wait_list = NULL; + entity->retransmit_list = NULL; + entity->ack_list = NULL; +} + +void rlc_entity_am_reestablishment(rlc_entity_t *_entity) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + + /* 36.322 5.4 says to deliver SDUs if possible. + * Let's not do that, it makes the code simpler. + * TODO: change this behavior if wanted/needed. + */ + + clear_entity(entity); +} + +void rlc_entity_am_delete(rlc_entity_t *_entity) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + clear_entity(entity); + free(entity); +} diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_am.h b/openair2/LAYER2/rlc_v2/rlc_entity_am.h new file mode 100644 index 0000000000..0437f17ad8 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_am.h @@ -0,0 +1,285 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_ENTITY_AM_H_ +#define _RLC_ENTITY_AM_H_ + +#include + +#include "rlc_entity.h" +#include "rlc_pdu.h" +#include "rlc_sdu.h" + +/* + * Here comes some documentation to understand the reassembly + * logic in the code and the fields in the structure rlc_am_reassemble_t. + * + * Inside RLC, we deal with SDUs, PDUs and PDU segments. + * SDUs are packets coming from upper layer. + * A PDU is made of a header and a payload. + * In the payload there are SDUs. + * First SDU and last SDU in a PDU may be incomplete. + * PDU segments exist in case of retransmissions when the MAC + * layer asks for less data than previously, in which case + * only part of the previous PDU is sent. + * + * This is PDU data (just bytes): + * --------------------------------------------------------- + * | PDU data | + * --------------------------------------------------------- + * It contains SDUs, like: + * --------------------------------------------------------- + * | SDU 1 | SDU 2 | [...] | SDU n | + * --------------------------------------------------------- + * SDU 1 may be only the end of an SDU from which previous bytes were + * transmitted in previous PDUs. + * SDU n may be only the start of an SDU, that is more bytes from + * this SDU may be sent in successive PDUs. + * + * At front of the PDU data, we have a header: + * --------------- --------------------------------------------------------- + * | PDU header | | SDU 1 | SDU 2 | [...] | SDU n | + * --------------- --------------------------------------------------------- + * PDU header describes PDU data (most notably lengths). + * + * A PDU segment is a part of a PDU. For example, from this PDU data: + * --------------------------------------------------------- + * | SDU 1 | SDU 2 | [...] | SDU n | + * --------------------------------------------------------- + * We can extract the following PDU segment (data part only): + * ---------------------- + * | PDU segment data | + * ---------------------- + * This PDU segment would contain the end of SDU 2 above and some SDUs up to, + * let's say SDU x (x is 5 below). + * + * In front of a transmitted PDU segment, we have a header, + * containing the important variable 'so' (segment offset) that gives + * the index of the first byte of the segment in the original PDU. + * -------------- ---------------------- + * | seg. header| | PDU segment data | + * -------------- ---------------------- + * + * Let's now explain the data structure rlc_am_reassemble_t. + * + * In the structure rlc_am_reassemble_t, the fields fi, e, sn and so + * are coming from the PDU segment header and the semantics is the + * one of the RLC specs. + * + * The currently processed PDU segment is stored in 'start'. + * We have 'start->s->data_offset' and 'start->s->size'. + * start->s->data_offset is the index of the start of the data in the + * PDU segment. That is if the header is of length 3 bytes + * then start->s->data_offset is 3. + * start->s->size is the total length of the PDU segment, + * including header. + * The size of actual data bytes in the PDU segment is thus + * start->s->size - start->s->data_offset. + * + * The field sdu_len is the length of the current SDU being + * processed. + * + * The field sdu_offset is the starting point of the + * current SDU being processed (starting from beginning + * of PDU segment, including header). + * + * The field data_pos is the current read pointer. 0 points to + * the beginning of the PDU segment (including header). + * + * The field pdu_byte points to the current byte in the original + * PDU (not the PDU segment). It starts at 0 when we start + * processing a new PDU (when a new 'sn' is seen) and always + * increases after each byte processed. This is tha variable + * that is used to know if the next PDU segment will be used + * or not and if yes, starting from which data byte (see + * function rlc_am_reassemble_next_segment). + * + * 'so' is important and points to the byte in the original PDU + * that is the first byte of the PDU segment. + * + * For example, let's take this PDU segment data from above: + * ---------------------- + * | PDU segment data | + * ---------------------- + * Let's say it is decomposed as: + * ---------------------- + * |222|33|4444|55555555| + * ---------------------- + * It contains SDUs 2, 3, 4, and 5. + * SDU 2 is 3 bytes, SDU 3 is 2 bytes, SDU 4 is 4 bytes, SDU 5 is 8 bytes. + * + * Let's suppose that the original PDU starts with: + * ---------------- + * |1111111|222222| + * ---------------- + * + * (In this example, in the PDU segment, SDU 2 is not full, + * we only have its end.) + * + * Then 'so' is 13 (SDU 1 is 7 bytes, head of SDU 2 is 6 bytes). + * + * Let's continue with our PDU segment data. + * Let's say we are current processing SDU 4. + * Let's say the read pointer (variable 'data_pos') is there: + * ---------------------- + * |222|33|4444|55555555| + * ---------------------- + * ^ + * read pointer (data_pos) + * + * Then: + * - sdu_len is 4 + * - sdu_offset is 5 + [PDU segment header length] + * (it points to the beginning of SDU 4, starting + * from the head of the PDU segment, that is + * 3 bytes for SDU 2, 2 bytes for SDU 3, and the + * PDU segment header length) + * - start->s->data_offset is [PDU segment header length] + * - pdu_byte is 20 + * (13 bytes from beginning of original PDU, + * 3 bytes for SDU 2, 2 bytes for SDU 3, then 2 bytes for SDU 4) + * - data_pos = read pointer = 7 + [PDU segment header length] + * + * To finish this description, in the code, a PDU is simply + * seen as a PDU segment with 'so' = 0 (and is_last == 1 (lsf in the specs), + * but this variable is not used by the reassembly logic). + * + * And for [PDU segment header length] we use start->s->data_offset. + * + * To recap, here is an illustration of the various variables + * and what starting point they use. In the figures, the start + * of the variable name is aligned to the byte it refers to. + * + is used to show the starting point. + * + * Let's put the PDU segment back into the original PDU. + * And let's show the values for when the read pointer + * is on the second byte of SDU 4 (as above). + * + * +++++++++++++++ so + * +++++++++++++++++++++++ pdu_byte + * --------------------------------------------------------- + * | SDU 1| SDU 2..222|33|4444|55555555| [...] | SDU n | + * --------------------------------------------------------- + * + * And now the PDU segment with header. + * + * + * ++++ sdu_len + * ++++++++++++++++++++++ sdu_offset + * +++++++++++++++++++++++ data_pos + * +++++++++++++++ start->s->data_offset + * +++++++++++++++++++++++++++++++++++++ start->s->size + * -------------- ---------------------- + * | seg. header| |222|33|4444|55555555| + * -------------- ---------------------- + * + * We see three case for the starting point: + * - start of original PDU (without any header) + * - start of header of current PDU segment + * - start of current SDU (for sdu_len) + */ + +typedef struct { + rlc_rx_pdu_segment_t *start; /* start of list */ + rlc_rx_pdu_segment_t *end; /* end of list (last element) */ + int pos; /* byte to get from current buffer */ + char sdu[SDU_MAX]; /* sdu is reassembled here */ + int sdu_pos; /* next byte to put in sdu */ + + /* decoder of current PDU */ + rlc_pdu_decoder_t dec; + int fi; + int e; + int sn; + int so; + int sdu_len; + int sdu_offset; + int data_pos; + int pdu_byte; +} rlc_am_reassemble_t; + +typedef struct { + rlc_entity_t common; + + /* configuration */ + int t_reordering; + int t_status_prohibit; + int t_poll_retransmit; + int poll_pdu; /* -1 means infinity */ + int poll_byte; /* -1 means infinity */ + int max_retx_threshold; + + /* runtime rx */ + int vr_r; + int vr_x; + int vr_ms; + int vr_h; + + int status_triggered; + + /* runtime tx */ + int vt_a; + int vt_s; + int poll_sn; + int pdu_without_poll; + int byte_without_poll; + int force_poll; + + /* set to the latest know time by the user of the module. Unit: ms */ + uint64_t t_current; + + /* timers (stores the TTI of activation, 0 means not active) */ + uint64_t t_reordering_start; + uint64_t t_status_prohibit_start; + uint64_t t_poll_retransmit_start; + + /* rx management */ + rlc_rx_pdu_segment_t *rx_list; + int rx_size; + int rx_maxsize; + + /* reassembly management */ + rlc_am_reassemble_t reassemble; + + /* tx management */ + rlc_sdu_t *tx_list; + rlc_sdu_t *tx_end; + int tx_size; + int tx_maxsize; + + rlc_tx_pdu_segment_t *wait_list; + rlc_tx_pdu_segment_t *retransmit_list; + + rlc_tx_pdu_segment_t *ack_list; +} rlc_entity_am_t; + +void rlc_entity_am_recv_sdu(rlc_entity_t *entity, char *buffer, int size, + int sdu_id); +void rlc_entity_am_recv_pdu(rlc_entity_t *entity, char *buffer, int size); +rlc_entity_buffer_status_t rlc_entity_am_buffer_status( + rlc_entity_t *entity, int maxsize); +int rlc_entity_am_generate_pdu(rlc_entity_t *entity, char *buffer, int size); +void rlc_entity_am_set_time(rlc_entity_t *entity, uint64_t now); +void rlc_entity_am_discard_sdu(rlc_entity_t *entity, int sdu_id); +void rlc_entity_am_reestablishment(rlc_entity_t *entity); +void rlc_entity_am_delete(rlc_entity_t *entity); + +#endif /* _RLC_ENTITY_AM_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_um.c b/openair2/LAYER2/rlc_v2/rlc_entity_um.c new file mode 100644 index 0000000000..75692851cd --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_um.c @@ -0,0 +1,703 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc_entity_um.h" +#include "rlc_pdu.h" + +#include +#include + +#include "LOG/log.h" + +/*************************************************************************/ +/* PDU RX functions */ +/*************************************************************************/ + +static int modulus_rx(rlc_entity_um_t *entity, int a) +{ + /* as per 36.322 7.1, modulus base is vr(uh)-window_size and modulus is + * 2^sn_field_length (which is 'sn_modulus' in rlc_entity_um_t) + */ + int r = a - (entity->vr_uh - entity->window_size); + if (r < 0) r += entity->sn_modulus; + return r % entity->sn_modulus; +} + +static int sn_compare_rx(void *_entity, int a, int b) +{ + rlc_entity_um_t *entity = _entity; + return modulus_rx(entity, a) - modulus_rx(entity, b); +} + +static int sn_in_recv_window(void *_entity, int sn) +{ + rlc_entity_um_t *entity = _entity; + int mod_sn = modulus_rx(entity, sn); + /* we simplify (VR(UH) - UM_Window_Size) <= SN < VR(UH), base is + * (VR(UH) - UM_Window_Size) and VR(UH) = base + window_size + */ + return mod_sn < entity->window_size; +} + +/* return 1 if a PDU with SN == 'sn' is in the rx list, 0 otherwise */ +static int rlc_um_pdu_received(rlc_entity_um_t *entity, int sn) +{ + rlc_rx_pdu_segment_t *cur = entity->rx_list; + while (cur != NULL) { + if (cur->sn == sn) + return 1; + cur = cur->next; + } + return 0; +} + +static int less_than_vr_ur(rlc_entity_um_t *entity, int sn) +{ + return sn_compare_rx(entity, sn, entity->vr_ur) < 0; +} + +static int outside_of_reordering_window(rlc_entity_um_t *entity, int sn) +{ + return !sn_in_recv_window(entity, sn); +} + +static int less_than_vr_uh(rlc_entity_um_t *entity, int sn) +{ + return sn_compare_rx(entity, sn, entity->vr_uh) < 0; +} + +static void rlc_um_reassemble_pdu(rlc_entity_um_t *entity, + rlc_rx_pdu_segment_t *pdu) +{ + rlc_um_reassemble_t *r = &entity->reassemble; + + int fi; + int e; + int sn; + int data_pos; + int sdu_len; + int sdu_offset; + + sdu_offset = pdu->data_offset; + + rlc_pdu_decoder_init(&r->dec, pdu->data, pdu->size); + + if (entity->sn_field_length == 10) + rlc_pdu_decoder_get_bits(&r->dec, 3); + + fi = rlc_pdu_decoder_get_bits(&r->dec, 2); + e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sn = rlc_pdu_decoder_get_bits(&r->dec, entity->sn_field_length); + + if (e) { + e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + sdu_len = pdu->size - sdu_offset; + + /* discard current SDU being reassembled if bad SN or bad FI */ + if (sn != (r->sn + 1) % entity->sn_modulus || + !(fi & 0x02)) { + if (r->sdu_pos) + LOG_D(RLC, "%s:%d:%s: warning: discard partially reassembled SDU\n", + __FILE__, __LINE__, __FUNCTION__); + r->sdu_pos = 0; + } + + /* if the head of the SDU is missing, still process the PDU + * but remember to discard the reassembled SDU later on (the + * head has not been received). + * The head is missing if sdu_pos == 0 and fi says the PDU does not + * start an SDU. + */ + if (r->sdu_pos == 0 && (fi & 0x02)) + r->sdu_head_missing = 1; + + r->sn = sn; + data_pos = pdu->data_offset; + + while (1) { + if (r->sdu_pos >= SDU_MAX) { + /* TODO: proper error handling (discard PDUs with current sn from + * reassembly queue? something else?) + */ + LOG_E(RLC, "%s:%d:%s: bad RLC PDU\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + r->sdu[r->sdu_pos] = pdu->data[data_pos]; + r->sdu_pos++; + data_pos++; + if (data_pos == sdu_offset + sdu_len) { + /* all bytes of SDU are consumed, check if SDU is fully there. + * It is if the data pointer is not at the end of the PDU segment + * or if 'fi' & 1 == 0 + */ + if (data_pos != pdu->size || (fi & 1) == 0) { + /* time to discard the SDU if we didn't receive the head */ + if (r->sdu_head_missing) { + LOG_D(RLC, "%s:%d:%s: warning: discard SDU, head not received\n", + __FILE__, __LINE__, __FUNCTION__); + r->sdu_head_missing = 0; + } else { + /* SDU is full - deliver to higher layer */ + entity->common.deliver_sdu(entity->common.deliver_sdu_data, + (rlc_entity_t *)entity, + r->sdu, r->sdu_pos); + } + r->sdu_pos = 0; + } + /* done with PDU? */ + if (data_pos == pdu->size) + break; + /* not at the end of PDU, process next SDU */ + sdu_offset += sdu_len; + if (e) { + e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + sdu_len = pdu->size - sdu_offset; + } + } +} + +static void rlc_um_reassemble(rlc_entity_um_t *entity, + int (*check_sn)(rlc_entity_um_t *entity, int sn)) +{ + rlc_rx_pdu_segment_t *cur; + + /* process all PDUs from head of rx list until all is processed or + * the SN is not valid anymore with respect to 'check_sn' + */ + while (entity->rx_list != NULL && check_sn(entity, entity->rx_list->sn)) { + cur = entity->rx_list; + rlc_um_reassemble_pdu(entity, cur); + entity->rx_size -= cur->size; + entity->rx_list = cur->next; + rlc_rx_free_pdu_segment(cur); + } +} + +static void rlc_um_reception_actions(rlc_entity_um_t *entity, + rlc_rx_pdu_segment_t *pdu_segment) +{ + if (!sn_in_recv_window(entity, pdu_segment->sn)) { + entity->vr_uh = (pdu_segment->sn + 1) % entity->sn_modulus; + rlc_um_reassemble(entity, outside_of_reordering_window); + if (!sn_in_recv_window(entity, entity->vr_ur)) + entity->vr_ur = (entity->vr_uh - entity->window_size + + entity->sn_modulus) % entity->sn_modulus; + } + + if (rlc_um_pdu_received(entity, entity->vr_ur)) { + do { + entity->vr_ur = (entity->vr_ur + 1) % entity->sn_modulus; + } while (rlc_um_pdu_received(entity, entity->vr_ur)); + rlc_um_reassemble(entity, less_than_vr_ur); + } + + if (entity->t_reordering_start) { + if (sn_compare_rx(entity, entity->vr_ux, entity->vr_ur) <= 0 || + (!sn_in_recv_window(entity, entity->vr_ux) && + entity->vr_ux != entity->vr_uh)) + entity->t_reordering_start = 0; + } + + if (entity->t_reordering_start == 0) { + if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_ux = entity->vr_uh; + } + } +} + +void rlc_entity_um_recv_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ +#define R(d) do { if (rlc_pdu_decoder_in_error(&d)) goto err; } while (0) + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_pdu_decoder_t decoder; + rlc_pdu_decoder_t data_decoder; + + int e; + int sn; + + int data_e; + int data_li; + + int packet_count; + int data_size; + int data_start; + int indicated_data_size; + + rlc_rx_pdu_segment_t *pdu_segment; + + rlc_pdu_decoder_init(&decoder, buffer, size); + + if (entity->sn_field_length == 10) { + rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); /* R1 */ + } + + rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); /* FI */ + e = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + sn = rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder); + + /* dicard PDU if rx buffer is full */ + if (entity->rx_size + size > entity->rx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + /* discard according to 36.322 5.1.2.2.2 */ + if ((sn_compare_rx(entity, entity->vr_ur, sn) < 0 && + sn_compare_rx(entity, sn, entity->vr_uh) < 0 && + rlc_um_pdu_received(entity, sn)) || + (sn_compare_rx(entity, entity->vr_uh - entity->window_size, sn) <= 0 && + sn_compare_rx(entity, sn, entity->vr_ur) < 0)) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU (sn %d vr(ur) %d vr(uh) %d)\n", + __FILE__, __LINE__, __FUNCTION__, + sn, entity->vr_ur, entity->vr_uh); + return; + } + + packet_count = 1; + + /* go to start of data */ + indicated_data_size = 0; + data_decoder = decoder; + data_e = e; + while (data_e) { + data_e = rlc_pdu_decoder_get_bits(&data_decoder, 1); R(data_decoder); + data_li = rlc_pdu_decoder_get_bits(&data_decoder, 11); R(data_decoder); + if (data_li == 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, li == 0\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + indicated_data_size += data_li; + packet_count++; + } + rlc_pdu_decoder_align(&data_decoder); + + data_start = data_decoder.byte; + data_size = size - data_start; + + if (data_size <= 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, wrong data size (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + return; + } + if (indicated_data_size >= data_size) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, bad LIs (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + return; + } + + /* put in pdu reception list */ + entity->rx_size += size; + pdu_segment = rlc_rx_new_pdu_segment(sn, 0, size, 1, buffer, data_start); + entity->rx_list = rlc_rx_pdu_segment_list_add(sn_compare_rx, entity, + entity->rx_list, pdu_segment); + + /* do reception actions (36.322 5.1.2.2.3) */ + rlc_um_reception_actions(entity, pdu_segment); + + return; + +err: + LOG_D(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__); + +#undef R +} + +/*************************************************************************/ +/* TX functions */ +/*************************************************************************/ + +typedef struct { + int sdu_count; + int data_size; + int header_size; + int last_sdu_is_full; + int first_sdu_length; +} tx_pdu_size_t; + +static int header_size(int sn_field_length, int sdu_count) +{ + int bits = 8 + 8 * (sn_field_length == 10) + 12 * (sdu_count - 1); + /* padding if we have to */ + return (bits + 7) / 8; +} + +static tx_pdu_size_t tx_pdu_size(rlc_entity_um_t *entity, int maxsize) +{ + tx_pdu_size_t ret; + int sdu_count; + int sdu_size; + int pdu_data_size; + rlc_sdu_t *sdu; + + ret.sdu_count = 0; + ret.data_size = 0; + ret.header_size = 0; + ret.last_sdu_is_full = 1; + + /* TX PDU - let's make the biggest PDU we can with the SDUs we have */ + sdu_count = 0; + pdu_data_size = 0; + sdu = entity->tx_list; + while (sdu != NULL) { + int new_header_size = header_size(entity->sn_field_length, sdu_count+1); + /* if we cannot put new header + at least 1 byte of data then over */ + if (new_header_size + pdu_data_size >= maxsize) + break; + sdu_count++; + /* only include the bytes of this SDU not included in PDUs already */ + sdu_size = sdu->size - sdu->next_byte; + /* don't feed more than 'maxsize' bytes */ + if (new_header_size + pdu_data_size + sdu_size > maxsize) { + sdu_size = maxsize - new_header_size - pdu_data_size; + ret.last_sdu_is_full = 0; + } + if (sdu_count == 1) + ret.first_sdu_length = sdu_size; + pdu_data_size += sdu_size; + /* if we put more than 2^11-1 bytes then the LI field cannot be used, + * so this is the last SDU we can put + */ + if (sdu_size > 2047) + break; + sdu = sdu->next; + } + + if (sdu_count) { + ret.sdu_count = sdu_count; + ret.data_size = pdu_data_size; + ret.header_size = header_size(entity->sn_field_length, sdu_count); + } + + return ret; +} + +rlc_entity_buffer_status_t rlc_entity_um_buffer_status( + rlc_entity_t *_entity, int maxsize) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_entity_buffer_status_t ret; + tx_pdu_size_t tx_size; + + ret.status_size = 0; + + tx_size = tx_pdu_size(entity, maxsize); + ret.tx_size = tx_size.data_size + tx_size.header_size; + + ret.retx_size = 0; + + return ret; +} + +int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + tx_pdu_size_t pdu_size; + rlc_sdu_t *sdu; + int i; + int cursize; + int first_sdu_full; + int last_sdu_full; + rlc_pdu_encoder_t encoder; + int fi; + int e; + int li; + char *out; + int outpos; + int first_sdu_start_byte; + int sdu_start_byte; + + pdu_size = tx_pdu_size(entity, size); + if (pdu_size.sdu_count == 0) + return 0; + + sdu = entity->tx_list; + + first_sdu_start_byte = sdu->next_byte; + + /* reserve SDU bytes */ + cursize = 0; + for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + int sdu_size = sdu->size - sdu->next_byte; + if (cursize + sdu_size > pdu_size.data_size) + sdu_size = pdu_size.data_size - cursize; + sdu->next_byte += sdu_size; + cursize += sdu_size; + } + + first_sdu_full = first_sdu_start_byte == 0; + last_sdu_full = pdu_size.last_sdu_is_full; + + /* generate header */ + rlc_pdu_encoder_init(&encoder, buffer, size); + + if (entity->sn_field_length == 10) + rlc_pdu_encoder_put_bits(&encoder, 0, 3); /* R1 */ + + fi = 0; + if (!first_sdu_full) + fi |= 0x02; + if (!last_sdu_full) + fi |= 0x01; + rlc_pdu_encoder_put_bits(&encoder, fi, 2); /* FI */ + + /* see the AM code to understand the logic for Es and LIs */ + if (pdu_size.sdu_count >= 2) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + + if (entity->sn_field_length == 10) + rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 10); /* SN */ + else + rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 5); /* SN */ + + /* put LIs */ + sdu = entity->tx_list; + /* first SDU */ + li = pdu_size.first_sdu_length; + /* put E+LI only if at least 2 SDUs */ + if (pdu_size.sdu_count >= 2) { + /* E is 1 if at least 3 SDUs */ + if (pdu_size.sdu_count >= 3) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + /* next SDUs, but not the last (no LI for the last) */ + sdu = sdu->next; + for (i = 2; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + if (i != pdu_size.sdu_count - 1) + e = 1; + else + e = 0; + li = sdu->size; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + + rlc_pdu_encoder_align(&encoder); + + /* generate data */ + out = buffer + pdu_size.header_size; + sdu = entity->tx_list; + sdu_start_byte = first_sdu_start_byte; + outpos = 0; + for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + li = sdu->size - sdu_start_byte; + if (outpos + li >= pdu_size.data_size) + li = pdu_size.data_size - outpos; + memcpy(out+outpos, sdu->data + sdu_start_byte, li); + outpos += li; + sdu_start_byte = 0; + } + + /* cleanup sdu list */ + while (entity->tx_list != NULL && + entity->tx_list->size == entity->tx_list->next_byte) { + rlc_sdu_t *c = entity->tx_list; + /* release SDU bytes */ + entity->tx_size -= c->size; + entity->tx_list = c->next; + rlc_free_sdu(c); + } + if (entity->tx_list == NULL) + entity->tx_end = NULL; + + /* update VT(US) */ + entity->vt_us = (entity->vt_us + 1) % entity->sn_modulus; + + return pdu_size.header_size + pdu_size.data_size; +} + +/*************************************************************************/ +/* SDU RX functions */ +/*************************************************************************/ + +void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size, + int sdu_id) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_sdu_t *sdu; + + if (size > SDU_MAX) { + LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", + __FILE__, __LINE__, __FUNCTION__, size); + exit(1); + } + + if (entity->tx_size + size > entity->tx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + entity->tx_size += size; + + sdu = rlc_new_sdu(buffer, size, sdu_id); + rlc_sdu_list_add(&entity->tx_list, &entity->tx_end, sdu); +} + +/*************************************************************************/ +/* time/timers */ +/*************************************************************************/ + +static void check_t_reordering(rlc_entity_um_t *entity) +{ + int sn; + + /* is t_reordering running and if yes has it expired? */ + if (entity->t_reordering_start == 0 || + entity->t_current <= entity->t_reordering_start + entity->t_reordering) + return; + + /* stop timer */ + entity->t_reordering_start = 0; + + LOG_D(RLC, "%s:%d:%s: t_reordering expired\n", __FILE__, __LINE__, __FUNCTION__); + + /* update VR(UR) to first SN >= VR(UX) of PDU not received + */ + sn = entity->vr_ux; + while (rlc_um_pdu_received(entity, sn)) + sn = (sn + 1) % entity->sn_modulus; + entity->vr_ur = sn; + + rlc_um_reassemble(entity, less_than_vr_ur); + + if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_ux = entity->vr_uh; + } +} + +void rlc_entity_um_set_time(rlc_entity_t *_entity, uint64_t now) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + + entity->t_current = now; + + check_t_reordering(entity); +} + +/*************************************************************************/ +/* discard/re-establishment/delete */ +/*************************************************************************/ + +void rlc_entity_um_discard_sdu(rlc_entity_t *_entity, int sdu_id) +{ + /* implements 36.322 5.3 */ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_sdu_t head; + rlc_sdu_t *cur; + rlc_sdu_t *prev; + + head.next = entity->tx_list; + cur = entity->tx_list; + prev = &head; + + while (cur != NULL && cur->upper_layer_id != sdu_id) { + prev = cur; + cur = cur->next; + } + + /* if sdu_id not found or some bytes have already been 'PDU-ized' + * then do nothing + */ + if (cur == NULL || cur->next_byte != 0) + return; + + /* remove SDU from tx_list */ + prev->next = cur->next; + entity->tx_list = head.next; + if (entity->tx_end == cur) { + if (prev != &head) + entity->tx_end = prev; + else + entity->tx_end = NULL; + } + + rlc_free_sdu(cur); +} + +static void clear_entity(rlc_entity_um_t *entity) +{ + rlc_rx_pdu_segment_t *cur_rx; + rlc_sdu_t *cur_tx; + + entity->vr_ur = 0; + entity->vr_ux = 0; + entity->vr_uh = 0; + + entity->vt_us = 0; + + entity->t_current = 0; + + entity->t_reordering_start = 0; + + cur_rx = entity->rx_list; + while (cur_rx != NULL) { + rlc_rx_pdu_segment_t *p = cur_rx; + cur_rx = cur_rx->next; + rlc_rx_free_pdu_segment(p); + } + entity->rx_list = NULL; + entity->rx_size = 0; + + memset(&entity->reassemble, 0, sizeof(rlc_um_reassemble_t)); + + cur_tx = entity->tx_list; + while (cur_tx != NULL) { + rlc_sdu_t *p = cur_tx; + cur_tx = cur_tx->next; + rlc_free_sdu(p); + } + entity->tx_list = NULL; + entity->tx_end = NULL; + entity->tx_size = 0; +} + +void rlc_entity_um_reestablishment(rlc_entity_t *_entity) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + + rlc_um_reassemble(entity, less_than_vr_uh); + + clear_entity(entity); +} + +void rlc_entity_um_delete(rlc_entity_t *_entity) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + clear_entity(entity); + free(entity); +} diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_um.h b/openair2/LAYER2/rlc_v2/rlc_entity_um.h new file mode 100644 index 0000000000..02c5141a7a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_um.h @@ -0,0 +1,90 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_ENTITY_UM_H_ +#define _RLC_ENTITY_UM_H_ + +#include "rlc_entity.h" +#include "rlc_pdu.h" +#include "rlc_sdu.h" + +typedef struct { + char sdu[SDU_MAX]; /* sdu is reassembled here */ + int sdu_pos; /* next byte to put in sdu */ + + /* decoder of current PDU */ + rlc_pdu_decoder_t dec; + int sn; + + int sdu_head_missing; +} rlc_um_reassemble_t; + +typedef struct { + rlc_entity_t common; + + /* configuration */ + int t_reordering; + int sn_field_length; + + int sn_modulus; /* 1024 for sn_field_length == 10, 32 for 5 */ + int window_size; /* 512 for sn_field_length == 10, 16 for 5 */ + + /* runtime rx */ + int vr_ur; + int vr_ux; + int vr_uh; + + /* runtime tx */ + int vt_us; + + /* set to the latest know time by the user of the module. Unit: ms */ + uint64_t t_current; + + /* timers (stores the TTI of activation, 0 means not active) */ + uint64_t t_reordering_start; + + /* rx management */ + rlc_rx_pdu_segment_t *rx_list; + int rx_size; + int rx_maxsize; + + /* reassembly management */ + rlc_um_reassemble_t reassemble; + + /* tx management */ + rlc_sdu_t *tx_list; + rlc_sdu_t *tx_end; + int tx_size; + int tx_maxsize; +} rlc_entity_um_t; + +void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size, + int sdu_id); +void rlc_entity_um_recv_pdu(rlc_entity_t *entity, char *buffer, int size); +rlc_entity_buffer_status_t rlc_entity_um_buffer_status( + rlc_entity_t *entity, int maxsize); +int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size); +void rlc_entity_um_set_time(rlc_entity_t *entity, uint64_t now); +void rlc_entity_um_discard_sdu(rlc_entity_t *entity, int sdu_id); +void rlc_entity_um_reestablishment(rlc_entity_t *entity); +void rlc_entity_um_delete(rlc_entity_t *entity); + +#endif /* _RLC_ENTITY_UM_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_oai_api.c b/openair2/LAYER2/rlc_v2/rlc_oai_api.c new file mode 100644 index 0000000000..1be9c90a31 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_oai_api.c @@ -0,0 +1,821 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* from openair */ +#include "rlc.h" +#include "pdcp.h" + +/* from new rlc module */ +#include "asn1_utils.h" +#include "rlc_ue_manager.h" +#include "rlc_entity.h" + +#include + +static rlc_ue_manager_t *rlc_ue_manager; + +/* TODO: handle time a bit more properly */ +static uint64_t rlc_current_time; +static int rlc_current_time_last_frame; +static int rlc_current_time_last_subframe; + +void mac_rlc_data_ind ( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const eNB_flag_t enb_flagP, + const MBMS_flag_t MBMS_flagP, + const logical_chan_id_t channel_idP, + char *buffer_pP, + const tb_size_t tb_sizeP, + num_tb_t num_tbP, + crc_t *crcs_pP) +{ + rlc_ue_t *ue; + rlc_entity_t *rb; + + if (module_idP != 0 || eNB_index != 0 || enb_flagP != 1 || MBMS_flagP != 0) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (enb_flagP) + T(T_ENB_RLC_MAC_UL, T_INT(module_idP), T_INT(rntiP), + T_INT(channel_idP), T_INT(tb_sizeP)); + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + rb->set_time(rb, rlc_current_time); + rb->recv_pdu(rb, buffer_pP, tb_sizeP); + } else { + LOG_E(RLC, "%s:%d:%s: fatal: no RB found (channel ID %d)\n", + __FILE__, __LINE__, __FUNCTION__, channel_idP); + exit(1); + } + + rlc_manager_unlock(rlc_ue_manager); +} + +tbs_size_t mac_rlc_data_req( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const eNB_flag_t enb_flagP, + const MBMS_flag_t MBMS_flagP, + const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP, + char *buffer_pP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t sourceL2Id + ,const uint32_t destinationL2Id +#endif + ) +{ + int ret; + rlc_ue_t *ue; + rlc_entity_t *rb; + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + rb->set_time(rb, rlc_current_time); + ret = rb->generate_pdu(rb, buffer_pP, ue->saved_status_ind_tb_size[channel_idP - 1]); + } else { + LOG_E(RLC, "%s:%d:%s: fatal: data req for unknown RB\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + ret = 0; + } + + rlc_manager_unlock(rlc_ue_manager); + + if (enb_flagP) + T(T_ENB_RLC_MAC_DL, T_INT(module_idP), T_INT(rntiP), + T_INT(channel_idP), T_INT(ret)); + + return ret; +} + +mac_rlc_status_resp_t mac_rlc_status_ind( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const sub_frame_t subframeP, + const eNB_flag_t enb_flagP, + const MBMS_flag_t MBMS_flagP, + const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t sourceL2Id + ,const uint32_t destinationL2Id +#endif + ) +{ + rlc_ue_t *ue; + mac_rlc_status_resp_t ret; + rlc_entity_t *rb; + + /* TODO: handle time a bit more properly */ + if (rlc_current_time_last_frame != frameP || + rlc_current_time_last_subframe != subframeP) { + rlc_current_time++; + rlc_current_time_last_frame = frameP; + rlc_current_time_last_subframe = subframeP; + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + rlc_entity_buffer_status_t buf_stat; + rb->set_time(rb, rlc_current_time); + buf_stat = rb->buffer_status(rb, tb_sizeP ? tb_sizeP : 1000000); + if (buf_stat.status_size) + ret.bytes_in_buffer = buf_stat.status_size; + else if (buf_stat.retx_size) + ret.bytes_in_buffer = buf_stat.retx_size; + else + ret.bytes_in_buffer = buf_stat.tx_size; + ue->saved_status_ind_tb_size[channel_idP - 1] = tb_sizeP; + } else { + ret.bytes_in_buffer = 0; + } + + rlc_manager_unlock(rlc_ue_manager); + + ret.pdus_in_buffer = 0; + /* TODO: creation time may be important (unit: frame, as it seems) */ + ret.head_sdu_creation_time = 0; + ret.head_sdu_remaining_size_to_send = 0; + ret.head_sdu_is_segmented = 0; + return ret; +} + +int oai_emulation; + +rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + confirm_t confirmP, + sdu_size_t sdu_sizeP, + mem_block_t *sdu_pP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t *const sourceL2Id + ,const uint32_t *const destinationL2Id +#endif + ) +{ + int rnti = ctxt_pP->rnti; + rlc_ue_t *ue; + rlc_entity_t *rb; + + LOG_D(RLC, "%s rnti %d srb_flag %d rb_id %d mui %d confirm %d sdu_size %d MBMS_flag %d\n", + __FUNCTION__, rnti, srb_flagP, rb_idP, muiP, confirmP, sdu_sizeP, + MBMS_flagP); + + if (ctxt_pP->enb_flag) + T(T_ENB_RLC_DL, T_INT(ctxt_pP->module_id), + T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP)); + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + + rb = NULL; + + if (srb_flagP) { + if (rb_idP >= 1 && rb_idP <= 2) + rb = ue->srb[rb_idP - 1]; + } else { + if (rb_idP >= 1 && rb_idP <= 5) + rb = ue->drb[rb_idP - 1]; + } + + if (rb != NULL) { + rb->set_time(rb, rlc_current_time); + rb->recv_sdu(rb, (char *)sdu_pP->data, sdu_sizeP, muiP); + } else { + LOG_E(RLC, "%s:%d:%s: fatal: SDU sent to unknown RB\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_unlock(rlc_ue_manager); + + free_mem_block(sdu_pP, __func__); + + return RLC_OP_STATUS_OK; +} + +int rlc_module_init(void) +{ + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + static int inited = 0; + + if (pthread_mutex_lock(&lock)) abort(); + + if (inited) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + inited = 1; + + rlc_ue_manager = new_rlc_ue_manager(); + + if (pthread_mutex_unlock(&lock)) abort(); + + return 0; +} + +void rlc_util_print_hex_octets(comp_name_t componentP, unsigned char *dataP, const signed long sizeP) +{ +} + +static void deliver_sdu(void *_ue, rlc_entity_t *entity, char *buf, int size) +{ + rlc_ue_t *ue = _ue; + int is_srb; + int rb_id; + protocol_ctxt_t ctx; + mem_block_t *memblock; + int i; + + /* is it SRB? */ + for (i = 0; i < 2; i++) { + if (entity == ue->srb[i]) { + is_srb = 1; + rb_id = i+1; + goto rb_found; + } + } + + /* maybe DRB? */ + for (i = 0; i < 5; i++) { + if (entity == ue->drb[i]) { + is_srb = 0; + rb_id = i+1; + goto rb_found; + } + } + + LOG_E(RLC, "%s:%d:%s: fatal, no RB found for ue %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti); + exit(1); + +rb_found: + LOG_D(RLC, "%s:%d:%s: delivering SDU (rnti %d is_srb %d rb_id %d) size %d", + __FILE__, __LINE__, __FUNCTION__, ue->rnti, is_srb, rb_id, size); + + memblock = get_free_mem_block(size, __func__); + if (memblock == NULL) { + LOG_E(RLC, "%s:%d:%s: ERROR: get_free_mem_block failed\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + memcpy(memblock->data, buf, size); + + /* unused fields? */ + ctx.instance = 0; + ctx.frame = 0; + ctx.subframe = 0; + ctx.eNB_index = 0; + ctx.configured = 1; + ctx.brOption = 0; + + /* used fields? */ + ctx.module_id = 0; + ctx.rnti = ue->rnti; + ctx.enb_flag = 1; + + T(T_ENB_RLC_UL, + T_INT(0 /*ctxt_pP->module_id*/), + T_INT(ue->rnti), T_INT(rb_id), T_INT(size)); + + if (!pdcp_data_ind(&ctx, is_srb, 0, rb_id, size, memblock)) { + LOG_E(RLC, "%s:%d:%s: ERROR: pdcp_data_ind failed\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +static void successful_delivery(void *_ue, rlc_entity_t *entity, int sdu_id) +{ + rlc_ue_t *ue = _ue; + int i; + int is_srb; + int rb_id; + MessageDef *msg; + + /* is it SRB? */ + for (i = 0; i < 2; i++) { + if (entity == ue->srb[i]) { + is_srb = 1; + rb_id = i+1; + goto rb_found; + } + } + + /* maybe DRB? */ + for (i = 0; i < 5; i++) { + if (entity == ue->drb[i]) { + is_srb = 0; + rb_id = i+1; + goto rb_found; + } + } + + LOG_E(RLC, "%s:%d:%s: fatal, no RB found for ue %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti); + exit(1); + +rb_found: + LOG_D(RLC, "sdu %d was successfully delivered on %s %d\n", + sdu_id, + is_srb ? "SRB" : "DRB", + rb_id); + + /* TODO: do something for DRBs? */ + if (is_srb == 0) + return; + + msg = itti_alloc_new_message(TASK_RLC_ENB, RLC_SDU_INDICATION); + RLC_SDU_INDICATION(msg).rnti = ue->rnti; + RLC_SDU_INDICATION(msg).is_successful = 1; + RLC_SDU_INDICATION(msg).srb_id = rb_id; + RLC_SDU_INDICATION(msg).message_id = sdu_id; + /* TODO: accept more than 1 instance? here we send to instance id 0 */ + itti_send_msg_to_task(TASK_RRC_ENB, 0, msg); +} + +static void max_retx_reached(void *_ue, rlc_entity_t *entity) +{ + rlc_ue_t *ue = _ue; + int i; + int is_srb; + int rb_id; + MessageDef *msg; + + /* is it SRB? */ + for (i = 0; i < 2; i++) { + if (entity == ue->srb[i]) { + is_srb = 1; + rb_id = i+1; + goto rb_found; + } + } + + /* maybe DRB? */ + for (i = 0; i < 5; i++) { + if (entity == ue->drb[i]) { + is_srb = 0; + rb_id = i+1; + goto rb_found; + } + } + + LOG_E(RLC, "%s:%d:%s: fatal, no RB found for ue %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti); + exit(1); + +rb_found: + LOG_D(RLC, "max RETX reached on %s %d\n", + is_srb ? "SRB" : "DRB", + rb_id); + + /* TODO: do something for DRBs? */ + if (is_srb == 0) + return; + + msg = itti_alloc_new_message(TASK_RLC_ENB, RLC_SDU_INDICATION); + RLC_SDU_INDICATION(msg).rnti = ue->rnti; + RLC_SDU_INDICATION(msg).is_successful = 0; + RLC_SDU_INDICATION(msg).srb_id = rb_id; + RLC_SDU_INDICATION(msg).message_id = -1; + /* TODO: accept more than 1 instance? here we send to instance id 0 */ + itti_send_msg_to_task(TASK_RRC_ENB, 0, msg); +} + +static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s) +{ + rlc_entity_t *rlc_am; + rlc_ue_t *ue; + + struct LTE_SRB_ToAddMod__rlc_Config *r = s->rlc_Config; + struct LTE_SRB_ToAddMod__logicalChannelConfig *l = s->logicalChannelConfig; + int srb_id = s->srb_Identity; + int logical_channel_group; + + int t_reordering; + int t_status_prohibit; + int t_poll_retransmit; + int poll_pdu; + int poll_byte; + int max_retx_threshold; + + if (srb_id != 1 && srb_id != 2) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id %d\n", + __FILE__, __LINE__, __FUNCTION__, srb_id); + exit(1); + } + + switch (l->present) { + case LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue: + logical_channel_group = *l->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup; + break; + case LTE_SRB_ToAddMod__logicalChannelConfig_PR_defaultValue: + /* default value from 36.331 9.2.1 */ + logical_channel_group = 0; + break; + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + /* TODO: accept other values? */ + if (logical_channel_group != 0) { + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + switch (r->present) { + case LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue: { + struct LTE_RLC_Config__am *am; + if (r->choice.explicitValue.present != LTE_RLC_Config_PR_am) { + LOG_E(RLC, "%s:%d:%s: fatal error, must be RLC AM\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + am = &r->choice.explicitValue.choice.am; + t_reordering = decode_t_reordering(am->dl_AM_RLC.t_Reordering); + t_status_prohibit = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit); + t_poll_retransmit = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit); + poll_pdu = decode_poll_pdu(am->ul_AM_RLC.pollPDU); + poll_byte = decode_poll_byte(am->ul_AM_RLC.pollByte); + max_retx_threshold = decode_max_retx_threshold(am->ul_AM_RLC.maxRetxThreshold); + break; + } + case LTE_SRB_ToAddMod__rlc_Config_PR_defaultValue: + /* default values from 36.331 9.2.1 */ + t_reordering = 35; + t_status_prohibit = 0; + t_poll_retransmit = 45; + poll_pdu = -1; + poll_byte = -1; + max_retx_threshold = 4; + break; + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + if (ue->srb[srb_id-1] != NULL) { + LOG_D(RLC, "%s:%d:%s: warning SRB %d already exist for ue %d, do nothing\n", + __FILE__, __LINE__, __FUNCTION__, srb_id, rnti); + } else { + rlc_am = new_rlc_entity_am(100000, + 100000, + deliver_sdu, ue, + successful_delivery, ue, + max_retx_reached, ue, + t_reordering, t_status_prohibit, + t_poll_retransmit, + poll_pdu, poll_byte, max_retx_threshold); + rlc_ue_add_srb_rlc_entity(ue, srb_id, rlc_am); + + LOG_D(RLC, "%s:%d:%s: added srb %d to ue %d\n", + __FILE__, __LINE__, __FUNCTION__, srb_id, rnti); + } + rlc_manager_unlock(rlc_ue_manager); +} + +static void add_drb_am(int rnti, struct LTE_DRB_ToAddMod *s) +{ + rlc_entity_t *rlc_am; + rlc_ue_t *ue; + + struct LTE_RLC_Config *r = s->rlc_Config; + struct LTE_LogicalChannelConfig *l = s->logicalChannelConfig; + int drb_id = s->drb_Identity; + int channel_id = *s->logicalChannelIdentity; + int logical_channel_group; + + int t_reordering; + int t_status_prohibit; + int t_poll_retransmit; + int poll_pdu; + int poll_byte; + int max_retx_threshold; + + if (!(drb_id >= 1 && drb_id <= 5)) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id); + exit(1); + } + + if (channel_id != drb_id + 2) { + LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; + + /* TODO: accept other values? */ + if (logical_channel_group != 1) { + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + switch (r->present) { + case LTE_RLC_Config_PR_am: { + struct LTE_RLC_Config__am *am; + am = &r->choice.am; + t_reordering = decode_t_reordering(am->dl_AM_RLC.t_Reordering); + t_status_prohibit = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit); + t_poll_retransmit = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit); + poll_pdu = decode_poll_pdu(am->ul_AM_RLC.pollPDU); + poll_byte = decode_poll_byte(am->ul_AM_RLC.pollByte); + max_retx_threshold = decode_max_retx_threshold(am->ul_AM_RLC.maxRetxThreshold); + break; + } + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + if (ue->drb[drb_id-1] != NULL) { + LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } else { + rlc_am = new_rlc_entity_am(1000000, + 1000000, + deliver_sdu, ue, + successful_delivery, ue, + max_retx_reached, ue, + t_reordering, t_status_prohibit, + t_poll_retransmit, + poll_pdu, poll_byte, max_retx_threshold); + rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_am); + + LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } + rlc_manager_unlock(rlc_ue_manager); +} + +static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s) +{ + rlc_entity_t *rlc_um; + rlc_ue_t *ue; + + struct LTE_RLC_Config *r = s->rlc_Config; + struct LTE_LogicalChannelConfig *l = s->logicalChannelConfig; + int drb_id = s->drb_Identity; + int channel_id = *s->logicalChannelIdentity; + int logical_channel_group; + + int t_reordering; + int sn_field_length; + + if (!(drb_id >= 1 && drb_id <= 5)) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id); + exit(1); + } + + if (channel_id != drb_id + 2) { + LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; + + /* TODO: accept other values? */ + if (logical_channel_group != 1) { + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + switch (r->present) { + case LTE_RLC_Config_PR_um_Bi_Directional: { + struct LTE_RLC_Config__um_Bi_Directional *um; + um = &r->choice.um_Bi_Directional; + t_reordering = decode_t_reordering(um->dl_UM_RLC.t_Reordering); + if (um->dl_UM_RLC.sn_FieldLength != um->ul_UM_RLC.sn_FieldLength) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + sn_field_length = decode_sn_field_length(um->dl_UM_RLC.sn_FieldLength); + break; + } + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + if (ue->drb[drb_id-1] != NULL) { + LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } else { + rlc_um = new_rlc_entity_um(1000000, + 1000000, + deliver_sdu, ue, + t_reordering, + sn_field_length); + rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_um); + + LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } + rlc_manager_unlock(rlc_ue_manager); +} + +static void add_drb(int rnti, struct LTE_DRB_ToAddMod *s) +{ + switch (s->rlc_Config->present) { + case LTE_RLC_Config_PR_am: + add_drb_am(rnti, s); + break; + case LTE_RLC_Config_PR_um_Bi_Directional: + add_drb_um(rnti, s); + break; + default: + LOG_E(RLC, "%s:%d:%s: fatal: unhandled DRB type\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP, + const LTE_SRB_ToAddModList_t * const srb2add_listP, + const LTE_DRB_ToAddModList_t * const drb2add_listP, + const LTE_DRB_ToReleaseList_t * const drb2release_listP +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + ,const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP + ,const uint32_t sourceL2Id + ,const uint32_t destinationL2Id +#endif + ) +{ + int rnti = ctxt_pP->rnti; + int i; + + if (ctxt_pP->enb_flag != 1 || ctxt_pP->module_id != 0 /*|| + ctxt_pP->instance != 0 || ctxt_pP->eNB_index != 0 || + ctxt_pP->configured != 1 || ctxt_pP->brOption != 0 */) { + LOG_E(RLC, "%s: ctxt_pP not handled (%d %d %d %d %d %d)\n", __FUNCTION__, + ctxt_pP->enb_flag , ctxt_pP->module_id, ctxt_pP->instance, + ctxt_pP->eNB_index, ctxt_pP->configured, ctxt_pP->brOption); + exit(1); + } + + if (pmch_InfoList_r9_pP != NULL) { + LOG_E(RLC, "%s: pmch_InfoList_r9_pP not handled\n", __FUNCTION__); + exit(1); + } + + if (drb2release_listP != NULL) { + LOG_E(RLC, "%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (srb2add_listP != NULL) { + for (i = 0; i < srb2add_listP->list.count; i++) { + add_srb(rnti, srb2add_listP->list.array[i]); + } + } + + if (drb2add_listP != NULL) { + for (i = 0; i < drb2add_listP->list.count; i++) { + add_drb(rnti, drb2add_listP->list.array[i]); + } + } + + return RLC_OP_STATUS_OK; +} + +rlc_op_status_t rrc_rlc_config_req ( + const protocol_ctxt_t* const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t mbms_flagP, + const config_action_t actionP, + const rb_id_t rb_idP, + const rlc_info_t rlc_infoP) +{ + rlc_ue_t *ue; + int i; + + if (mbms_flagP) { + LOG_E(RLC, "%s:%d:%s: todo (mbms not supported)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if (!ctxt_pP->enb_flag) { + LOG_E(RLC, "%s:%d:%s: todo (only eNB supported, not UE)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if (actionP != CONFIG_ACTION_REMOVE) { + LOG_E(RLC, "%s:%d:%s: todo (only CONFIG_ACTION_REMOVE supported)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if (ctxt_pP->module_id) { + LOG_E(RLC, "%s:%d:%s: todo (only module_id 0 supported)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if ((srb_flagP && !(rb_idP >= 1 && rb_idP <= 2)) || + (!srb_flagP && !(rb_idP >= 1 && rb_idP <= 5))) { + LOG_E(RLC, "%s:%d:%s: bad rb_id (%d) (is_srb %d)\n", __FILE__, __LINE__, __FUNCTION__, rb_idP, srb_flagP); + exit(1); + } + rlc_manager_lock(rlc_ue_manager); + LOG_D(RLC, "%s:%d:%s: remove rb %d (is_srb %d) for UE %d\n", __FILE__, __LINE__, __FUNCTION__, rb_idP, srb_flagP, ctxt_pP->rnti); + ue = rlc_manager_get_ue(rlc_ue_manager, ctxt_pP->rnti); + if (srb_flagP) { + if (ue->srb[rb_idP-1] != NULL) { + ue->srb[rb_idP-1]->delete(ue->srb[rb_idP-1]); + ue->srb[rb_idP-1] = NULL; + } else + LOG_W(RLC, "removing non allocated SRB %d, do nothing\n", rb_idP); + } else { + if (ue->drb[rb_idP-1] != NULL) { + ue->drb[rb_idP-1]->delete(ue->drb[rb_idP-1]); + ue->drb[rb_idP-1] = NULL; + } else + LOG_W(RLC, "removing non allocated DRB %d, do nothing\n", rb_idP); + } + /* remove UE if it has no more RB configured */ + for (i = 0; i < 2; i++) + if (ue->srb[i] != NULL) + break; + if (i == 2) { + for (i = 0; i < 5; i++) + if (ue->drb[i] != NULL) + break; + if (i == 5) + rlc_manager_remove_ue(rlc_ue_manager, ctxt_pP->rnti); + } + rlc_manager_unlock(rlc_ue_manager); + return RLC_OP_STATUS_OK; +} + +void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_data_conf_cb_t rrc_data_confP) +{ + /* nothing to do */ +} + +rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x) +{ + LOG_D(RLC, "%s:%d:%s: remove UE %d\n", __FILE__, __LINE__, __FUNCTION__, x->rnti); + rlc_manager_lock(rlc_ue_manager); + rlc_manager_remove_ue(rlc_ue_manager, x->rnti); + rlc_manager_unlock(rlc_ue_manager); + + return RLC_OP_STATUS_OK; +} + diff --git a/openair2/LAYER2/rlc_v2/rlc_pdu.c b/openair2/LAYER2/rlc_v2/rlc_pdu.c new file mode 100644 index 0000000000..c55e2d9c3c --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_pdu.c @@ -0,0 +1,266 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc_pdu.h" + +#include +#include + +#include "LOG/log.h" + +/**************************************************************************/ +/* RX PDU segment and segment list */ +/**************************************************************************/ + +rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size, + int is_last, char *data, int data_offset) +{ + rlc_rx_pdu_segment_t *ret = malloc(sizeof(rlc_rx_pdu_segment_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + ret->sn = sn; + ret->so = so; + ret->size = size; + ret->is_last = is_last; + ret->next = NULL; + + ret->data = malloc(size); + if (ret->data == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + memcpy(ret->data, data, size); + + ret->data_offset = data_offset; + + return ret; +} + +void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment) +{ + free(pdu_segment->data); + free(pdu_segment); +} + +rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment) +{ + rlc_rx_pdu_segment_t head; + rlc_rx_pdu_segment_t *cur; + rlc_rx_pdu_segment_t *prev; + + head.next = list; + cur = list; + prev = &head; + + /* order is by 'sn', if 'sn' is the same then order is by 'so' */ + while (cur != NULL) { + /* check if 'pdu_segment' is before 'cur' in the list */ + if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 || + (cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) { + break; + } + prev = cur; + cur = cur->next; + } + prev->next = pdu_segment; + pdu_segment->next = cur; + return head.next; +} + +/**************************************************************************/ +/* TX PDU management */ +/**************************************************************************/ + +rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void) +{ + rlc_tx_pdu_segment_t *ret = calloc(1, sizeof(rlc_tx_pdu_segment_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + ret->retx_count = -1; + return ret; +} + +void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu) +{ + free(pdu); +} + +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list, + rlc_tx_pdu_segment_t *pdu) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + + head.next = list; + + cur = &head; + while (cur->next != NULL) { + cur = cur->next; + } + cur->next = pdu; + + return head.next; +} + +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + head.next = list; + cur = list; + prev = &head; + + /* order is by 'sn', if 'sn' is the same then order is by 'so' */ + while (cur != NULL) { + /* check if 'pdu_segment' is before 'cur' in the list */ + if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 || + (cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) { + break; + } + prev = cur; + cur = cur->next; + } + prev->next = pdu_segment; + pdu_segment->next = cur; + return head.next; +} + +/**************************************************************************/ +/* PDU decoder */ +/**************************************************************************/ + +void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size) +{ + decoder->error = 0; + decoder->byte = 0; + decoder->bit = 0; + decoder->buffer = buffer; + decoder->size = size; +} + +static int get_bit(rlc_pdu_decoder_t *decoder) +{ + int ret; + + if (decoder->byte >= decoder->size) { + decoder->error = 1; + return 0; + } + + ret = (decoder->buffer[decoder->byte] >> (7 - decoder->bit)) & 1; + + decoder->bit++; + if (decoder->bit == 8) { + decoder->bit = 0; + decoder->byte++; + } + + return ret; +} + +int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count) +{ + int ret = 0; + int i; + + if (count > 31) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + for (i = 0; i < count; i++) { + ret <<= 1; + ret |= get_bit(decoder); + if (decoder->error) return -1; + } + + return ret; +} + +void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder) +{ + if (decoder->bit) { + decoder->bit = 0; + decoder->byte++; + } +} + +/**************************************************************************/ +/* PDU encoder */ +/**************************************************************************/ + +void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size) +{ + encoder->byte = 0; + encoder->bit = 0; + encoder->buffer = buffer; + encoder->size = size; +} + +static void put_bit(rlc_pdu_encoder_t *encoder, int bit) +{ + if (encoder->byte == encoder->size) { + LOG_E(RLC, "%s:%d:%s: fatal, buffer full\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + encoder->buffer[encoder->byte] <<= 1; + if (bit) + encoder->buffer[encoder->byte] |= 1; + + encoder->bit++; + if (encoder->bit == 8) { + encoder->bit = 0; + encoder->byte++; + } +} + +void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count) +{ + int i; + int x; + + if (count > 31) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + x = 1 << (count - 1); + for (i = 0; i < count; i++, x >>= 1) + put_bit(encoder, value & x); +} + +void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder) +{ + while (encoder->bit) + put_bit(encoder, 0); +} diff --git a/openair2/LAYER2/rlc_v2/rlc_pdu.h b/openair2/LAYER2/rlc_v2/rlc_pdu.h new file mode 100644 index 0000000000..dbffe9f3cb --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_pdu.h @@ -0,0 +1,109 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_PDU_H_ +#define _RLC_PDU_H_ + +/**************************************************************************/ +/* RX PDU segment and segment list */ +/**************************************************************************/ + +typedef struct rlc_rx_pdu_segment_t { + int sn; + int so; + int size; + int is_last; + char *data; + int data_offset; + struct rlc_rx_pdu_segment_t *next; +} rlc_rx_pdu_segment_t; + +rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size, + int is_last, char *data, int data_offset); + +void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment); + +rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment); + +/**************************************************************************/ +/* TX PDU management */ +/**************************************************************************/ + +typedef struct rlc_tx_pdu_segment_t { + int sn; + void *start_sdu; /* real type is rlc_sdu_t * */ + int sdu_start_byte; /* starting byte in 'start_sdu' */ + int so; /* starting byte of the segment in full PDU */ + int data_size; /* number of data bytes (exclude header) */ + int is_segment; + int is_last; + int retx_count; + struct rlc_tx_pdu_segment_t *next; +} rlc_tx_pdu_segment_t; + +rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void); +void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu); +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list, + rlc_tx_pdu_segment_t *pdu); +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment); + +/**************************************************************************/ +/* PDU decoder */ +/**************************************************************************/ + +typedef struct { + int error; + int byte; /* next byte to decode */ + int bit; /* next bit in next byte to decode */ + char *buffer; + int size; +} rlc_pdu_decoder_t; + +void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size); + +#define rlc_pdu_decoder_in_error(d) ((d)->error == 1) + +int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count); + +void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder); + +/**************************************************************************/ +/* PDU encoder */ +/**************************************************************************/ + +typedef struct { + int byte; /* next byte to encode */ + int bit; /* next bit in next byte to encode */ + char *buffer; + int size; +} rlc_pdu_encoder_t; + +void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size); + +void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count); + +void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder); + +#endif /* _RLC_PDU_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_sdu.c b/openair2/LAYER2/rlc_v2/rlc_sdu.c new file mode 100644 index 0000000000..16465a9ff1 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_sdu.c @@ -0,0 +1,68 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc_sdu.h" + +#include +#include + +#include "LOG/log.h" + +rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id) +{ + rlc_sdu_t *ret = calloc(1, sizeof(rlc_sdu_t)); + if (ret == NULL) + goto oom; + + ret->upper_layer_id = upper_layer_id; + + ret->data = malloc(size); + if (ret->data == NULL) + goto oom; + + memcpy(ret->data, buffer, size); + + ret->size = size; + + return ret; + +oom: + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); +} + +void rlc_free_sdu(rlc_sdu_t *sdu) +{ + free(sdu->data); + free(sdu); +} + +void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu) +{ + if (*list == NULL) { + *list = sdu; + *end = sdu; + return; + } + + (*end)->next = sdu; + *end = sdu; +} diff --git a/openair2/LAYER2/rlc_v2/rlc_sdu.h b/openair2/LAYER2/rlc_v2/rlc_sdu.h new file mode 100644 index 0000000000..2c678956ee --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_sdu.h @@ -0,0 +1,39 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_SDU_H_ +#define _RLC_SDU_H_ + +typedef struct rlc_sdu_t { + int upper_layer_id; + char *data; + int size; + /* next_byte indicates the starting byte to use to construct a new PDU */ + int next_byte; + int acked_bytes; + struct rlc_sdu_t *next; +} rlc_sdu_t; + +rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id); +void rlc_free_sdu(rlc_sdu_t *sdu); +void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu); + +#endif /* _RLC_SDU_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_ue_manager.c b/openair2/LAYER2/rlc_v2/rlc_ue_manager.c new file mode 100644 index 0000000000..1d0884bb9c --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_ue_manager.c @@ -0,0 +1,182 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rlc_ue_manager.h" + +#include +#include +#include + +#include "LOG/log.h" + +typedef struct { + pthread_mutex_t lock; + rlc_ue_t **ue_list; + int ue_count; +} rlc_ue_manager_internal_t; + +rlc_ue_manager_t *new_rlc_ue_manager(void) +{ + rlc_ue_manager_internal_t *ret; + + ret = calloc(1, sizeof(rlc_ue_manager_internal_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (pthread_mutex_init(&ret->lock, NULL)) abort(); + + return ret; +} + +void rlc_manager_lock(rlc_ue_manager_t *_m) +{ + rlc_ue_manager_internal_t *m = _m; + if (pthread_mutex_lock(&m->lock)) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +void rlc_manager_unlock(rlc_ue_manager_t *_m) +{ + rlc_ue_manager_internal_t *m = _m; + if (pthread_mutex_unlock(&m->lock)) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +/* must be called with lock acquired */ +rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *_m, int rnti) +{ + /* TODO: optimze */ + rlc_ue_manager_internal_t *m = _m; + int i; + + for (i = 0; i < m->ue_count; i++) + if (m->ue_list[i]->rnti == rnti) + return m->ue_list[i]; + + LOG_D(RLC, "%s:%d:%s: new UE %d\n", __FILE__, __LINE__, __FUNCTION__, rnti); + + m->ue_count++; + m->ue_list = realloc(m->ue_list, sizeof(rlc_ue_t *) * m->ue_count); + if (m->ue_list == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + m->ue_list[m->ue_count-1] = calloc(1, sizeof(rlc_ue_t)); + if (m->ue_list[m->ue_count-1] == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + m->ue_list[m->ue_count-1]->rnti = rnti; + + return m->ue_list[m->ue_count-1]; +} + +/* must be called with lock acquired */ +void rlc_manager_remove_ue(rlc_ue_manager_t *_m, int rnti) +{ + rlc_ue_manager_internal_t *m = _m; + rlc_ue_t *ue; + int i; + int j; + + for (i = 0; i < m->ue_count; i++) + if (m->ue_list[i]->rnti == rnti) + break; + + if (i == m->ue_count) { + LOG_D(RLC, "%s:%d:%s: warning: ue %d not found\n", + __FILE__, __LINE__, __FUNCTION__, + rnti); + return; + } + + ue = m->ue_list[i]; + + for (j = 0; j < 2; j++) + if (ue->srb[j] != NULL) + ue->srb[j]->delete(ue->srb[j]); + + for (j = 0; j < 5; j++) + if (ue->drb[j] != NULL) + ue->drb[j]->delete(ue->drb[j]); + + free(ue); + + m->ue_count--; + if (m->ue_count == 0) { + free(m->ue_list); + m->ue_list = NULL; + return; + } + + memmove(&m->ue_list[i], &m->ue_list[i+1], + (m->ue_count - i) * sizeof(rlc_ue_t *)); + m->ue_list = realloc(m->ue_list, m->ue_count * sizeof(rlc_ue_t *)); + if (m->ue_list == NULL) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +/* must be called with lock acquired */ +void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity) +{ + if (srb_id < 1 || srb_id > 2) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + srb_id--; + + if (ue->srb[srb_id] != NULL) { + LOG_E(RLC, "%s:%d:%s: fatal, srb already present\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ue->srb[srb_id] = entity; +} + +/* must be called with lock acquired */ +void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity) +{ + if (drb_id < 1 || drb_id > 5) { + LOG_E(RLC, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + drb_id--; + + if (ue->drb[drb_id] != NULL) { + LOG_E(RLC, "%s:%d:%s: fatal, drb already present\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ue->drb[drb_id] = entity; +} diff --git a/openair2/LAYER2/rlc_v2/rlc_ue_manager.h b/openair2/LAYER2/rlc_v2/rlc_ue_manager.h new file mode 100644 index 0000000000..7d5ef18b1e --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_ue_manager.h @@ -0,0 +1,58 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_UE_MANAGER_H_ +#define _RLC_UE_MANAGER_H_ + +#include "rlc_entity.h" + +typedef void rlc_ue_manager_t; + +typedef struct rlc_ue_t { + int rnti; + /* due to openair calling status_ind/data_req, we need to keep this. + * To be considered 'hackish'. + */ + int saved_status_ind_tb_size[2+5]; + rlc_entity_t *srb[2]; + rlc_entity_t *drb[5]; +} rlc_ue_t; + +/***********************************************************************/ +/* manager functions */ +/***********************************************************************/ + +rlc_ue_manager_t *new_rlc_ue_manager(void); + +void rlc_manager_lock(rlc_ue_manager_t *m); +void rlc_manager_unlock(rlc_ue_manager_t *m); + +rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *m, int rnti); +void rlc_manager_remove_ue(rlc_ue_manager_t *m, int rnti); + +/***********************************************************************/ +/* ue functions */ +/***********************************************************************/ + +void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity); +void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity); + +#endif /* _RLC_UE_MANAGER_H_ */ diff --git a/openair2/LAYER2/rlc_v2/tests/LOG/log.h b/openair2/LAYER2/rlc_v2/tests/LOG/log.h new file mode 100644 index 0000000000..5c9fcd643c --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/LOG/log.h @@ -0,0 +1,10 @@ +#ifndef _LOG_H_ +#define _LOG_H_ + +#include + +#define LOG_E(x, ...) printf(__VA_ARGS__) +#define LOG_D(x, ...) printf(__VA_ARGS__) +#define LOG_W(x, ...) printf(__VA_ARGS__) + +#endif /* _LOG_H_ */ diff --git a/openair2/LAYER2/rlc_v2/tests/Makefile b/openair2/LAYER2/rlc_v2/tests/Makefile new file mode 100644 index 0000000000..14bb186d4c --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/Makefile @@ -0,0 +1,32 @@ +CC=gcc +CFLAGS=-Wall -g --coverage -I. + +LIB=rlc_entity.o rlc_entity_am.o rlc_entity_um.o rlc_pdu.o rlc_sdu.o + +tests: + @./run_tests.sh + +all: clean_run $(TEST).run + +%.run: $(TEST).bin + #valgrind ./$(TEST).bin > $(TEST).run_pre 2> $(TEST).valgrind + ./$(TEST).bin > $(TEST).run_pre + grep ^TEST $(TEST).run_pre > $(TEST).run + gunzip -c $(TEST).txt.gz > $(TEST).txt + diff -q $(TEST).txt $(TEST).run + +$(TEST).bin: $(TEST).o $(LIB) + $(CC) $(CFLAGS) -o $@ $^ + +%.o: ../%.c + $(CC) $(CFLAGS) -I.. -c -o $@ $< + +$(TEST).o: test.c + $(CC) $(CFLAGS) -c -o $@ $< -DTEST='"$(TEST).h"' + +clean_run: + rm -f $(TEST).run $(TEST).bin $(TEST).o + +clean: + rm -f *.o *.bin *.run *.run_pre *.gcov *.gcda *.gcno test*.txt a.out \ + *.valgrind diff --git a/openair2/LAYER2/rlc_v2/tests/README b/openair2/LAYER2/rlc_v2/tests/README new file mode 100644 index 0000000000..db69cd4fa7 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/README @@ -0,0 +1,38 @@ +To run tests, simply type: make + +Each test is made of: + testXX.h definition of the test + testXX.txt.gz compressed expected output of the test + +At runtime, we generate: + testXX.run actual output of the test + +test.c is the test driving program. + +Only the output lines of the test program starting with "TEST" are +stored into testXX.txt and testXX.run. + +A test is considered a success if testXX.txt and testXX.run are equal. + +Only failed tests are reported. + +How to define a new test? + +1 - get the ID + + Look in the file run_tests.sh, the variable test_count gives you + the number of existing tests. The ID of your test has to be + test_count + 1. + +2 - create files + + Create the file test.h containing the test, then generate test.run + by running 'make all TEST=test' and copy test.run to test.txt. + Then compress this file (gzip -9 test.txt). Be sure that the output + is correct, of course. + + For the file names, replace by the actual number of the test. + For example, if your test ID is 47, then name the files test47.h and + test47.txt. And run 'make all TEST=test47' to generate test47.run. + +The available instructions for a test are described at the top of test.c. diff --git a/openair2/LAYER2/rlc_v2/tests/make_pdu.c b/openair2/LAYER2/rlc_v2/tests/make_pdu.c new file mode 100644 index 0000000000..057cc3e36d --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/make_pdu.c @@ -0,0 +1,29 @@ +/* gcc -Wall make_pdu.c -I.. ../rlc_pdu.c */ + +#include "rlc_pdu.h" +#include + +int main(void) +{ + char out[100]; + rlc_pdu_encoder_t e; + int i; + + rlc_pdu_encoder_init(&e, out, 100); + + rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C + rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT + rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn + rlc_pdu_encoder_put_bits(&e, 1, 1); // e1 + rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn + rlc_pdu_encoder_put_bits(&e, 0, 1); // e1 + rlc_pdu_encoder_put_bits(&e, 0, 1); // e2 + + rlc_pdu_encoder_align(&e); + + for (i = 0; i < e.byte; i++) printf(" %2.2x", (unsigned char)e.buffer[i]); + + printf("\n"); + + return 0; +} diff --git a/openair2/LAYER2/rlc_v2/tests/run_tests.sh b/openair2/LAYER2/rlc_v2/tests/run_tests.sh new file mode 100755 index 0000000000..72feff0036 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/run_tests.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +test_count=45 + +for i in `seq $test_count` +do + make all TEST=test$i >/dev/null 2>/dev/null + if [ $? != 0 ] + then + echo TEST $i FAILURE + fi +done diff --git a/openair2/LAYER2/rlc_v2/tests/test.c b/openair2/LAYER2/rlc_v2/tests/test.c new file mode 100644 index 0000000000..734e85f1f5 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test.c @@ -0,0 +1,433 @@ +#include "../rlc_entity.h" +#include "../rlc_entity_am.h" +#include "../rlc_entity_um.h" + +#include +#include +#include +#include +#include +#include + +/* + * ENB_AM + * + * create the eNB RLC AM entity with given parameters + * + * UE_AM + * + * create the UE RLC AM entity with given parameters + * + * ENB_UM + * create the eNB RLC UM entity with given parameters + * + * UE_UM + * create the UE RLC UM entity with given parameters + * + * TIME
\n') self.htmlFile.write('

\n') self.htmlFile.write(' \n') - # GP machines = [ 'eNB', 'UE' ] - # GP for machine in machines: - #GP This needs to move back to main and be called before CreateHtmlFooter - - res = self.reseNB - if res != -1: + machines = [ 'eNB', 'UE' ] + for machine in machines: + if machine == 'eNB': + idx = 0 + else: + idx = 1 + if self.OsVersion[idx] == '': + continue + self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - - - res = self.resUE - if res != -1: - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') + self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write(' \n') diff --git a/ci-scripts/main.py b/ci-scripts/main.py index e7601f556d..595a984bbe 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -94,13 +94,6 @@ class OaiCiTest(): self.x2ENBConnectedUEs = [] self.repeatCounts = [] self.finalStatus = False - self.OsVersion = '' - self.KernelVersion = '' - self.UhdVersion = '' - self.UsrpBoard = '' - self.CpuNb = '' - self.CpuModel = '' - self.CpuMHz = '' self.UEIPAddress = '' self.UEUserName = '' self.UEPassword = '' @@ -2747,26 +2740,26 @@ class OaiCiTest(): def AutoTerminateUEandeNB(self): if (self.ADBIPAddress != 'none'): self.testCase_id = 'AUTO-KILL-UE' - RAN.SettestCase_id(self.testCase_id) + HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' self.ShowTestID() self.TerminateUE() if (self.Initialize_OAI_UE_args != ''): self.testCase_id = 'AUTO-KILL-UE' - RAN.SettestCase_id(self.testCase_id) + HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' self.ShowTestID() self.TerminateOAIUE() if (RAN.GetInitialize_eNB_args() != ''): self.testCase_id = 'AUTO-KILL-eNB' - RAN.SettestCase_id(self.testCase_id) + HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of eNB' self.ShowTestID() RAN.SeteNB_instance('0') RAN.TerminateeNB() if RAN.GetflexranCtrlInstalled() and RAN.GetflexranCtrlStarted(): self.testCase_id = 'AUTO-KILL-flexran-ctl' - RAN.SettestCase_id(self.testCase_id) + HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of FlexRan CTL' self.ShowTestID() self.TerminateFlexranCtrl() @@ -2934,19 +2927,20 @@ class OaiCiTest(): def RetrieveSystemVersion(self, machine): if RAN.GeteNBIPAddress() == 'none' or self.UEIPAddress == 'none': - self.OsVersion = 'Ubuntu 16.04.5 LTS' - self.KernelVersion = '4.15.0-45-generic' - self.UhdVersion = '3.13.0.1-0' - self.UsrpBoard = 'B210' - self.CpuNb = '4' - self.CpuModel = 'Intel(R) Core(TM) i5-6200U' - self.CpuMHz = '2399.996 MHz' + HTML.SetOsVersion('Ubuntu 16.04.5 LTS', 0) + HTML.SetKernelVersion('4.15.0-45-generic', 0) + HTML.SetUhdVersion('3.13.0.1-0', 0) + HTML.SetUsrpBoard('B210', 0) + HTML.SetCpuNb('4', 0) + HTML.SetCpuModel('Intel(R) Core(TM) i5-6200U', 0) + HTML.SetCpuMHz('2399.996 MHz', 0) return 0 if machine == 'eNB': if RAN.GeteNBIPAddress() != '' and RAN.GeteNBUserName() != '' and RAN.GeteNBPassword() != '': IPAddress = RAN.GeteNBIPAddress() UserName = RAN.GeteNBUserName() Password = RAN.GeteNBPassword() + idx = 0 else: return -1 if machine == 'UE': @@ -2954,6 +2948,7 @@ class OaiCiTest(): IPAddress = self.UEIPAddress UserName = self.UEUserName Password = self.UEPassword + idx = 1 else: return -1 @@ -2961,55 +2956,64 @@ class OaiCiTest(): SSH.command('lsb_release -a', '\$', 5) result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) if result is not None: - self.OsVersion = result.group('os_type') - logging.debug('OS is: ' + self.OsVersion) + OsVersion = result.group('os_type') + logging.debug('OS is: ' + OsVersion) + HTML.SetOsVersion(OsVersion, idx) else: SSH.command('hostnamectl', '\$', 5) result = re.search('Operating System: (?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) if result is not None: - self.OsVersion = result.group('os_type') - if self.OsVersion == 'CentOS Linux 7 ': + OsVersion = result.group('os_type') + if OsVersion == 'CentOS Linux 7 ': SSH.command('cat /etc/redhat-release', '\$', 5) result = re.search('CentOS Linux release (?P[0-9\.]+)', SSH.getBefore()) if result is not None: - self.OsVersion = self.OsVersion.replace('7 ', result.group('os_version')) - logging.debug('OS is: ' + self.OsVersion) + OsVersion = OsVersion.replace('7 ', result.group('os_version')) + logging.debug('OS is: ' + OsVersion) + HTML.SetOsVersion(OsVersion, idx) SSH.command('uname -r', '\$', 5) result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', SSH.getBefore()) if result is not None: - self.KernelVersion = result.group('kernel_version') - logging.debug('Kernel Version is: ' + self.KernelVersion) + KernelVersion = result.group('kernel_version') + logging.debug('Kernel Version is: ' + KernelVersion) + HTML.SetKernelVersion(KernelVersion, idx) SSH.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', SSH.getBefore()) if result is not None: - self.UhdVersion = result.group('uhd_version') - logging.debug('UHD Version is: ' + self.UhdVersion) + UhdVersion = result.group('uhd_version') + logging.debug('UHD Version is: ' + UhdVersion) + HTML.SetUhdVersion(UhdVersion, idx) else: SSH.command('uhd_config_info --version', '\$', 5) result = re.search('UHD (?P[a-zA-Z0-9\.\-]+)', SSH.getBefore()) if result is not None: - self.UhdVersion = result.group('uhd_version') - logging.debug('UHD Version is: ' + self.UhdVersion) + UhdVersion = result.group('uhd_version') + logging.debug('UHD Version is: ' + UhdVersion) + HTML.SetUhdVersion(UhdVersion, idx) SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 60) usrp_boards = re.findall('product: ([0-9A-Za-z]+)\\\\r\\\\n', SSH.getBefore()) count = 0 for board in usrp_boards: if count == 0: - self.UsrpBoard = board + UsrpBoard = board else: - self.UsrpBoard += ',' + board + UsrpBoard += ',' + board count += 1 if count > 0: - logging.debug('USRP Board(s) : ' + self.UsrpBoard) + logging.debug('USRP Board(s) : ' + UsrpBoard) + HTML.SetUsrpBoard(UsrpBoard, idx) SSH.command('lscpu', '\$', 5) result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', SSH.getBefore()) if result is not None: - self.CpuNb = result.group('nb_cpus') - logging.debug('nb_cpus: ' + self.CpuNb) - self.CpuModel = result.group('model') - logging.debug('model: ' + self.CpuModel) - self.CpuMHz = result.group('cpu_mhz') + ' MHz' - logging.debug('cpu_mhz: ' + self.CpuMHz) + CpuNb = result.group('nb_cpus') + logging.debug('nb_cpus: ' + CpuNb) + HTML.SetCpuNb(CpuNb, idx) + CpuModel = result.group('model') + logging.debug('model: ' + CpuModel) + HTML.SetCpuModel(CpuModel, idx) + CpuMHz = result.group('cpu_mhz') + ' MHz' + logging.debug('cpu_mhz: ' + CpuMHz) + HTML.SetCpuMHz(CpuMHz, idx) SSH.close() #----------------------------------------------------------- @@ -3199,6 +3203,8 @@ RAN = ran.RANManagement() HTML = html.HTMLManagement() EPC.SetHtmlObj(HTML) +RAN.SetHtmlObj(HTML) +RAN.SetEpcObj(EPC) argvs = sys.argv argc = len(argvs) @@ -3293,19 +3299,15 @@ while len(argvs) > 1: elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE) EPC.SetIPAddress(matchReg.group(1)) - RAN.SetIPAddress(matchReg.group(1)) elif re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCUserName=(.+)$', myArgv, re.IGNORECASE) EPC.SetUserName(matchReg.group(1)) - RAN.SetUserName(matchReg.group(1)) elif re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCPassword=(.+)$', myArgv, re.IGNORECASE) EPC.SetPassword(matchReg.group(1)) - RAN.SetPassword(matchReg.group(1)) elif re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCSourceCodePath=(.+)$', myArgv, re.IGNORECASE) EPC.SetSourceCodePath(matchReg.group(1)) - RAN.SetSourceCodePath(matchReg.group(1)) elif re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-EPCType=(.+)$', myArgv, re.IGNORECASE) if re.match('OAI', matchReg.group(1), re.IGNORECASE) or re.match('ltebox', matchReg.group(1), re.IGNORECASE) or re.match('OAI-Rel14-CUPS', matchReg.group(1), re.IGNORECASE): @@ -3466,8 +3468,12 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): HTML.SethtmlNb_CATM_Modules(len(CiTestObj.CatMDevices)) HTML.CreateHtmlHeader(CiTestObj.ADBIPAddress) elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): - HTML.SetreseNB(RetrieveSystemVersion('eNB')) - HTML.SetresUE(RetrieveSystemVersion('UE')) + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + logging.debug('\u001B[1m Creating HTML footer \u001B[0m') + logging.debug('\u001B[1m----------------------------------------\u001B[0m') + + CiTestObj.RetrieveSystemVersion('eNB') + CiTestObj.RetrieveSystemVersion('UE') HTML.CreateHtmlFooter(CiTestObj.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): @@ -3575,7 +3581,6 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re if test_case_id != id: continue CiTestObj.testCase_id = id - RAN.SettestCase_id(CiTestObj.testCase_id) HTML.SettestCase_id(CiTestObj.testCase_id) CiTestObj.desc = test.findtext('desc') HTML.Setdesc(CiTestObj.desc) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index e390b6aecb..f03cb6413c 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -46,10 +46,7 @@ import sshconnection as SSH import epc import helpreadme as HELP import constants as CONST -import html as HTML - -EPC = epc.EPCManagement() - +import html #----------------------------------------------------------- # Class Declaration @@ -90,23 +87,19 @@ class RANManagement(): self.eNBstatuses = [-1, -1, -1] self.flexranCtrlInstalled = False self.flexranCtrlStarted = False + self.epcPcapFile = '' + self.htmlObj = None + self.epcObj = None #----------------------------------------------------------- -# Setters and Getters +# Setters and Getters on Public members #----------------------------------------------------------- - def SetIPAddress(self, ipaddress): - self.EPCIPAddress = ipaddress - def SetUserName(self, username): - self.EPCUserName = username - def SetPassword(self, password): - self.EPCPassword = password - def SetSourceCodePath(self, sourcecodepath): - self.EPCSourceCodePath = sourcecodepath + def SetHtmlObj(self, obj): + self.htmlObj = obj + def SetEpcObj(self, obj): + self.epcObj = obj - - def SettestCase_id(self,tcid): - self.testCase_id = tcid def SetflexranCtrlInstalled(self,fxrctin): self.flexranCtrlInstalled = fxrctin def GetflexranCtrlInstalled(self): @@ -242,7 +235,6 @@ class RANManagement(): def BuildeNB(self): - myHTML = HTML.HTMLManagement() if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': GenericHelp(Version) sys.exit('Insufficient Parameter') @@ -315,7 +307,8 @@ class RANManagement(): mismatch = True if not mismatch: mySSH.close() - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) return mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30) @@ -341,12 +334,17 @@ class RANManagement(): mySSH.command('chmod 775 ./my-lte-softmodem-build.sh', '\$', 5) mySSH.command('echo ' + lPassWord + ' | sudo -S -E daemon --inherit --unsafe --name=build_enb_daemon --chdir=' + lSourcePath + '/cmake_targets -o ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ./my-lte-softmodem-build.sh', '\$', 5) mySSH.close() - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) - self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) + self.backgroundBuildTestId[int(self.eNB_instance)] = self.htmlObj.GettestCase_id() return mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) mySSH.close() - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) + if self.htmlObj is not None: + tId = self.htmlObj.GettestCase_id() + else: + tId = '0000' + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, tId) @@ -385,8 +383,8 @@ class RANManagement(): self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)]) def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId): - myHTML = HTML.HTMLManagement() - myHTML.SettestCase_id(testcaseId) + if self.htmlObj is not None: + self.htmlObj.SettestCase_id(testcaseId) mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 3) @@ -436,16 +434,17 @@ class RANManagement(): if buildStatus: logging.info('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Pass\u001B[0m') - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) else: logging.error('\u001B[1m Building OAI ' + nodeB_prefix + 'NB Failed\u001B[0m') - myHTML.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK) - myHTML.CreateHtmlTabFooter(False) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK) + self.htmlObj.CreateHtmlTabFooter(False) sys.exit(1) def InitializeeNB(self): - myHTML = HTML.HTMLManagement() if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress lUserName = self.eNBUserName @@ -467,21 +466,25 @@ class RANManagement(): mySSH = SSH.SSHConnection() if (self.pStatus < 0): - myHTML.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', self.pStatus) - myHTML.CreateHtmlTabFooter(False) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow(self.Initialize_eNB_args, 'KO', self.pStatus) + self.htmlObj.CreateHtmlTabFooter(False) sys.exit(1) # If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if (result is not None) and (self.epcObj is not None): + localEpcIpAddr = self.epcObj.GetIPAddress() + localEpcUserName = self.epcObj.GetUserName() + localEpcPassword = self.epcObj.GetPassword() + mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5) result = re.search('interfaceToUse=(?P[a-zA-Z0-9\-\_]+)done', mySSH.getBefore()) if result is not None: eth_interface = result.group('eth_interface') logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + '\u001B[0m') - EPC.Set_PcapFileName('enb_' + self.testCase_id + '_s1log.pcap') - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S rm -f /tmp/' + EPC.Get_PcapFileName() , '\$', 5) - mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + EPC.Get_PcapFileName() + ' > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5) + self.epcPcapFile = 'enb_' + self.testCase_id + '_s1log.pcap' + mySSH.command('echo ' + localEpcPassword + ' | sudo -S rm -f /tmp/' + self.epcPcapFile , '\$', 5) + mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -w /tmp/' + self.epcPcapFile + ' > /tmp/tshark.log 2>&1 &', localEpcUserName, 5) mySSH.close() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath, '\$', 5) @@ -520,7 +523,9 @@ class RANManagement(): mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60) # Make a copy and adapt to EPC / eNB IP addresses mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + if self.epcObj is not None: + localEpcIpAddr = self.epcObj.GetIPAddress() + mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + localEpcIpAddr + '/\' ' + ci_full_config_file, '\$', 2); mySSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); mySSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); mySSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); @@ -569,22 +574,26 @@ class RANManagement(): mySSH.close() doLoop = False logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') - myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('-O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK) # In case of T tracer recording, we need to kill tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if (result is not None) and (self.epcObj is not None): + localEpcIpAddr = self.epcObj.GetIPAddress() + localEpcUserName = self.epcObj.GetUserName() + localEpcPassword = self.epcObj.GetPassword() + mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - if EPC.Get_PcapFileName() != '': + mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + if self.epcPcapFile != '': time.sleep(0.5) - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) + mySSH.command('echo ' + localEpcPassword + ' | sudo -S chmod 666 /tmp/' + self.epcPcapFile, '\$', 5) mySSH.close() time.sleep(1) - if EPC.Get_PcapFileName() != '': - copyin_res = mySSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + EPC.Get_PcapFileName() , '.') + if self.epcPcapFile != '': + copyin_res = mySSH.copyin(localEpcIpAddr, localEpcUserName, localEpcPassword, '/tmp/' + self.epcPcapFile, '.') if (copyin_res == 0): - mySSH.copyout(lIpAddr, lUserName, lPassWord, EPC.Get_PcapFileName() , lSourcePath + '/cmake_targets/.') + mySSH.copyout(lIpAddr, lUserName, lPassWord, self.epcPcapFile, lSourcePath + '/cmake_targets/.') self.prematureExit = True return else: @@ -619,7 +628,8 @@ class RANManagement(): self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId) mySSH.close() - myHTML.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK) logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') @@ -659,7 +669,6 @@ class RANManagement(): def TerminateeNB(self): - myHTML = HTML.HTMLManagement() if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress lUserName = self.eNBUserName @@ -700,15 +709,18 @@ class RANManagement(): mySSH.close() # If tracer options is on, stopping tshark on EPC side result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - mySSH.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + if (result is not None) and (self.epcObj is not None): + localEpcIpAddr = self.epcObj.GetIPAddress() + localEpcUserName = self.epcObj.GetUserName() + localEpcPassword = self.epcObj.GetPassword() + mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) logging.debug('\u001B[1m Stopping tshark \u001B[0m') - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) - if EPC.Get_PcapFileName() != '': - mySSH.command('echo ' + self.EPCPassword + ' | sudo -S chmod 666 /tmp/' + EPC.Get_PcapFileName() , '\$', 5) - mySSH.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + EPC.Get_PcapFileName() , '.') - mySSH.copyout(lIpAddr, lUserName, lPassWord, EPC.Get_PcapFileName() , lSourcePath + '/cmake_targets/.') + if self.epcPcapFile != '': + mySSH.command('echo ' + localEpcPassword + ' | sudo -S chmod 666 /tmp/' + self.epcPcapFile, '\$', 5) + mySSH.copyin(localEpcIpAddr, localEpcUserName, localEpcPassword, '/tmp/' + self.epcPcapFile, '.') + mySSH.copyout(lIpAddr, lUserName, lPassWord, self.epcPcapFile, lSourcePath + '/cmake_targets/.') mySSH.close() logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') mySSH.open(lIpAddr, lUserName, lPassWord) @@ -725,7 +737,8 @@ class RANManagement(): mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') logStatus = self.AnalyzeLogFile_eNB(extracted_log_file) - myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.eNBLogFiles[int(self.eNB_instance)] = '' else: analyzeFile = False @@ -738,7 +751,8 @@ class RANManagement(): if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' - myHTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) self.eNBmbmsEnables[int(self.eNB_instance)] = False return if self.eNB_serverId != '0': @@ -746,14 +760,17 @@ class RANManagement(): logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze) if (logStatus < 0): - myHTML.CreateHtmlTestRow('N/A', 'KO', logStatus) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('N/A', 'KO', logStatus) self.preamtureExit = True self.eNBmbmsEnables[int(self.eNB_instance)] = False return else: - myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) else: - myHTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + if self.htmlObj is not None: + self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBstatuses[int(self.eNB_instance)] = -1 From ea376b1eb259c8a43aad3674239fcbc330c92f0b Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 21 Apr 2020 16:36:43 +0200 Subject: [PATCH 144/175] CI: fix eNB log analysis Signed-off-by: Raphael Defosseux --- ci-scripts/html.py | 2 ++ ci-scripts/ran.py | 81 +++++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/ci-scripts/html.py b/ci-scripts/html.py index 9d78ced991..6daf36a314 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -84,6 +84,8 @@ class HTMLManagement(): self.htmlUEFailureMsg = huefa def GethtmlUEFailureMsg(self): return self.htmlUEFailureMsg + def SetHmleNBFailureMsg(self, msg): + self.htmleNBFailureMsg = msg def SetreseNB(self,rsenb): self.reseNB = rsenb diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index f03cb6413c..7efe96dc2e 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -87,6 +87,7 @@ class RANManagement(): self.eNBstatuses = [-1, -1, -1] self.flexranCtrlInstalled = False self.flexranCtrlStarted = False + self.testCase_id = '' self.epcPcapFile = '' self.htmlObj = None self.epcObj = None @@ -267,6 +268,10 @@ class RANManagement(): # Worakround for some servers, we need to erase completely the workspace if self.Build_eNB_forced_workspace_cleanup: mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) + if self.htmlObj is not None: + self.testCase_id = self.htmlObj.GettestCase_id() + else: + self.testCase_id = '000000' # on RedHat/CentOS .git extension is mandatory result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) if result is not None: @@ -336,15 +341,11 @@ class RANManagement(): mySSH.close() if self.htmlObj is not None: self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK) - self.backgroundBuildTestId[int(self.eNB_instance)] = self.htmlObj.GettestCase_id() + self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id return mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500) mySSH.close() - if self.htmlObj is not None: - tId = self.htmlObj.GettestCase_id() - else: - tId = '0000' - self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, tId) + self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) @@ -463,6 +464,11 @@ class RANManagement(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': GenericHelp(Version) sys.exit('Insufficient Parameter') + + if self.htmlObj is not None: + self.testCase_id = self.htmlObj.GettestCase_id() + else: + self.testCase_id = '000000' mySSH = SSH.SSHConnection() if (self.pStatus < 0): @@ -750,8 +756,8 @@ class RANManagement(): copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') - self.htmleNBFailureMsg = 'Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' if self.htmlObj is not None: + self.htmlObj.SetHmleNBFailureMsg('Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!') self.htmlObj.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) self.eNBmbmsEnables[int(self.eNB_instance)] = False return @@ -811,7 +817,7 @@ class RANManagement(): cdrxActivationMessageCount = 0 dropNotEnoughRBs = 0 mbmsRequestMsg = 0 - self.htmleNBFailureMsg = '' + htmleNBFailureMsg = '' isRRU = False isSlave = False slaveReceivesFrameResyncCmd = False @@ -852,9 +858,9 @@ class RANManagement(): requested_option = int(res1.group('requested_option')) applied_option = int(res2.group('applied_option')) if requested_option == applied_option: - self.htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' else: - self.htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' result = re.search('Exiting OAI softmodem', str(line)) if result is not None: exitSignalReceived = True @@ -935,7 +941,6 @@ class RANManagement(): mbmsRequestMsg += 1 enb_log_file.close() logging.debug(' File analysis completed') - self.htmleNBFailureMsg = '' if self.air_interface == 'lte': nodeB_prefix = 'e' else: @@ -943,101 +948,109 @@ class RANManagement(): if uciStatMsgCount > 0: statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' + htmleNBFailureMsg += statMsg + '\n' if pdcpFailure > 0: statMsg = nodeB_prefix + 'NB showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' + htmleNBFailureMsg += statMsg + '\n' if ulschFailure > 0: statMsg = nodeB_prefix + 'NB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' + htmleNBFailureMsg += statMsg + '\n' if dropNotEnoughRBs > 0: statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') - self.htmleNBFailureMsg += statMsg + '\n' + htmleNBFailureMsg += statMsg + '\n' if rrcSetupComplete > 0: rrcMsg = nodeB_prefix + 'NB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' rrcMsg = ' -- ' + str(rrcSetupComplete) + ' were completed' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if rrcReleaseRequest > 0: rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReleaseRequest) + ' RRC Connection Release(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if rrcReconfigRequest > 0 or rrcReconfigComplete > 0: rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReconfigRequest) + ' RRC Connection Reconfiguration(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' rrcMsg = ' -- ' + str(rrcReconfigComplete) + ' were completed' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if rrcReestablishRequest > 0 or rrcReestablishComplete > 0 or rrcReestablishReject > 0: rrcMsg = nodeB_prefix + 'NB requested ' + str(rrcReestablishRequest) + ' RRC Connection Reestablishment(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' rrcMsg = ' -- ' + str(rrcReestablishComplete) + ' were completed' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if self.eNBmbmsEnables[int(self.eNB_instance)]: if mbmsRequestMsg > 0: rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if X2HO_inNbProcedures > 0: rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if X2HO_outNbProcedures > 0: rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if self.eNBOptions[int(self.eNB_instance)] != '': res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) if res1 is not None: if cdrxActivationMessageCount > 0: rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' else: rrcMsg = 'eNB did NOT ACTIVATE the CDRX Configuration' logging.debug('\u001B[1;37;43m ' + rrcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rrcMsg + '\n' + htmleNBFailureMsg += rrcMsg + '\n' if rachCanceledProcedure > 0: rachMsg = nodeB_prefix + 'NB cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rachMsg + '\n' + htmleNBFailureMsg += rachMsg + '\n' if isRRU: if isSlave: if slaveReceivesFrameResyncCmd: rruMsg = 'Slave RRU received the RRU_frame_resynch command from RAU' logging.debug('\u001B[1;30;43m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' + htmleNBFailureMsg += rruMsg + '\n' else: rruMsg = 'Slave RRU DID NOT receive the RRU_frame_resynch command from RAU' logging.debug('\u001B[1;37;41m ' + rruMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rruMsg + '\n' + htmleNBFailureMsg += rruMsg + '\n' self.prematureExit(True) return CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED if foundSegFault: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with a Segmentation Fault! \u001B[0m') + if self.htmlObj is not None: + self.htmlObj.SetHmleNBFailureMsg(htmleNBFailureMsg) return CONST.ENB_PROCESS_SEG_FAULT if foundAssertion: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB ended with an assertion! \u001B[0m') - self.htmleNBFailureMsg += msgAssertion + htmleNBFailureMsg += msgAssertion + if self.htmlObj is not None: + self.htmlObj.SetHmleNBFailureMsg(htmleNBFailureMsg) return CONST.ENB_PROCESS_ASSERTION if foundRealTimeIssue: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') - self.htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' + htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' #return ENB_PROCESS_REALTIME_ISSUE if rlcDiscardBuffer > 0: rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') - self.htmleNBFailureMsg += rlcMsg + '\n' + htmleNBFailureMsg += rlcMsg + '\n' + if self.htmlObj is not None: + self.htmlObj.SetHmleNBFailureMsg(htmleNBFailureMsg) return CONST.ENB_PROCESS_REALTIME_ISSUE + if self.htmlObj is not None: + self.htmlObj.SetHmleNBFailureMsg(htmleNBFailureMsg) return 0 From 9758abf9b9666185dfbcf2d5ecbe69eaa1ce8f71 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 21 Apr 2020 16:47:44 +0200 Subject: [PATCH 145/175] CI: cleanup Signed-off-by: Raphael Defosseux --- ci-scripts/main.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 595a984bbe..5a9836f474 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -3451,9 +3451,6 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabName',default='test-tab-' + str(count))) HTML.SethtmlTabIcons(xmlRoot.findtext('htmlTabIcon',default='info-sign')) - #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) - #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) - #CiTestObj.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign')) foundCount += 1 count += 1 if foundCount != HTML.GetnbTestXMLfiles(): @@ -3510,8 +3507,6 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re if (HTML.GetnbTestXMLfiles() == 1): HTML.SethtmlTabRefs(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) HTML.SethtmlTabNames(xmlRoot.findtext('htmlTabName',default='Test-0')) - #CiTestObj.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-0')) - #CiTestObj.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-0')) repeatCount = xmlRoot.findtext('repeatCount',default='1') CiTestObj.repeatCounts.append(int(repeatCount)) all_tests=xmlRoot.findall('testCase') From 39a5ddf5518e35af0906054b9ba8fbd279bdb48d Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 21 Apr 2020 20:15:57 +0200 Subject: [PATCH 146/175] CI: cleanup Signed-off-by: Raphael Defosseux --- ci-scripts/constants.py | 2 +- ci-scripts/epc.py | 7 ++---- ci-scripts/helpreadme.py | 2 +- ci-scripts/html.py | 50 +++++++++++-------------------------- ci-scripts/main.py | 7 +----- ci-scripts/ran.py | 16 ++---------- ci-scripts/sshconnection.py | 5 ++-- 7 files changed, 24 insertions(+), 65 deletions(-) diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py index 65fca7193b..ca3cde446d 100644 --- a/ci-scripts/constants.py +++ b/ci-scripts/constants.py @@ -1,4 +1,4 @@ - +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 07462bf762..e67de43b09 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -1,3 +1,4 @@ +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -27,7 +28,6 @@ # pexpect #--------------------------------------------------------------------- - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -124,7 +124,7 @@ class EPCManagement(): mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5) mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts', '\$', 5) mySSH.command('cd /opt/hss_sim0609', '\$', 5) - mySSH.command('echo ' + self.Password + ' | sudo -S rm -f hss.log daemon.log', '\$', 5) + mySSH.command('echo ' + self.Password + ' | sudo -S rm -f hss.log', '\$', 5) mySSH.command('echo ' + self.Password + ' | sudo -S echo "Starting sudo session" && sudo su -c "screen -dm -S simulated_hss ./starthss"', '\$', 5) else: logging.error('This option should not occur!') @@ -198,7 +198,6 @@ class EPCManagement(): if self.htmlObj is not None: self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK) - def CheckHSSProcess(self, status_queue): try: mySSH = SSH.SSHConnection() @@ -267,7 +266,6 @@ class EPCManagement(): except: os.kill(os.getppid(),signal.SIGUSR1) - def TerminateHSS(self): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) @@ -349,7 +347,6 @@ class EPCManagement(): if self.htmlObj is not None: self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - def LogCollectHSS(self): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) diff --git a/ci-scripts/helpreadme.py b/ci-scripts/helpreadme.py index 307ab4ff31..4b58c77510 100644 --- a/ci-scripts/helpreadme.py +++ b/ci-scripts/helpreadme.py @@ -1,3 +1,4 @@ +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -27,7 +28,6 @@ # pexpect #--------------------------------------------------------------------- - #----------------------------------------------------------- # Functions Declaration #----------------------------------------------------------- diff --git a/ci-scripts/html.py b/ci-scripts/html.py index 6daf36a314..ac2362477a 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -1,3 +1,4 @@ +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -27,7 +28,6 @@ # pexpect #--------------------------------------------------------------------- - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -39,6 +39,8 @@ import time import subprocess from multiprocessing import Process, Lock, SimpleQueue +import constants as CONST + #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- @@ -87,11 +89,6 @@ class HTMLManagement(): def SetHmleNBFailureMsg(self, msg): self.htmleNBFailureMsg = msg - def SetreseNB(self,rsenb): - self.reseNB = rsenb - def SetresUE(self,rsue): - self.resUE = rsue - def Setdesc(self, dsc): self.desc = dsc @@ -105,35 +102,19 @@ class HTMLManagement(): def SetranRepository(self, repository): self.ranRepository = repository - def GetranRepository(self): - return self.ranRepository - def SetranAllowMerge(self, merge): self.ranAllowMerge = merge - def GetranAllowMerge(self): - return self.ranAllowMerge - def SetranBranch(self, branch): self.ranBranch = branch - def GetranBranch(self): - return self.ranBranch - def SetranCommitID(self, commitid): self.ranCommitID = commitid - def GetranCommitID(self): - return self.ranCommitID - def SetranTargetBranch(self, tbranch): self.ranTargetBranch = tbranch - def GetranTargetBranch(self): - return self.ranTargetBranch def SethtmlUEConnected(self, nbUEs): self.htmlUEConnected = nbUEs - def SethtmlNb_Smartphones(self, nbUEs): self.htmlNb_Smartphones = nbUEs - def SethtmlNb_CATM_Modules(self, nbUEs): self.htmlNb_CATM_Modules = nbUEs @@ -400,29 +381,29 @@ class HTMLManagement(): elif (str(status) == 'KO'): if (processesStatus == 0): self.htmlFile.write(' \n') - elif (processesStatus == ENB_PROCESS_FAILED): + elif (processesStatus == CONST.ENB_PROCESS_FAILED): self.htmlFile.write(' \n') - elif (processesStatus == OAI_UE_PROCESS_FAILED): + elif (processesStatus == CONST.OAI_UE_PROCESS_FAILED): self.htmlFile.write(' \n') - elif (processesStatus == ENB_PROCESS_SEG_FAULT) or (processesStatus == OAI_UE_PROCESS_SEG_FAULT): + elif (processesStatus == CONST.ENB_PROCESS_SEG_FAULT) or (processesStatus == CONST.OAI_UE_PROCESS_SEG_FAULT): self.htmlFile.write(' \n') - elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): + elif (processesStatus == CONST.ENB_PROCESS_ASSERTION) or (processesStatus == CONST.OAI_UE_PROCESS_ASSERTION): self.htmlFile.write(' \n') - elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): + elif (processesStatus == CONST.ENB_PROCESS_REALTIME_ISSUE): self.htmlFile.write(' \n') - elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): + elif (processesStatus == CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == CONST.OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): self.htmlFile.write(' \n') - elif (processesStatus == ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): + elif (processesStatus == CONST.ENB_PROCESS_SLAVE_RRU_NOT_SYNCED): self.htmlFile.write(' \n') - elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + elif (processesStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC): self.htmlFile.write(' \n') - elif (processesStatus == HSS_PROCESS_FAILED): + elif (processesStatus == CONST.HSS_PROCESS_FAILED): self.htmlFile.write(' \n') - elif (processesStatus == MME_PROCESS_FAILED): + elif (processesStatus == CONST.MME_PROCESS_FAILED): self.htmlFile.write(' \n') - elif (processesStatus == SPGW_PROCESS_FAILED): + elif (processesStatus == CONST.SPGW_PROCESS_FAILED): self.htmlFile.write(' \n') - elif (processesStatus == UE_IP_ADDRESS_ISSUE): + elif (processesStatus == CONST.UE_IP_ADDRESS_ISSUE): self.htmlFile.write(' \n') else: self.htmlFile.write(' \n') @@ -491,4 +472,3 @@ class HTMLManagement(): self.htmlFile.write(' \n') self.htmlFile.close() - diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 5a9836f474..6aeefdef54 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -104,8 +104,6 @@ class OaiCiTest(): self.Initialize_OAI_UE_args = '' self.clean_repository = True self.expectedNbOfConnectedUEs = 0 - self.startTime = 0 - def BuildOAIUE(self): if self.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': @@ -1901,7 +1899,6 @@ class OaiCiTest(): def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue): try: - logging.debug('entring Iperf_common') # Single-UE profile -- iperf only on one UE if self.iperf_profile == 'single-ue' and idx != 0: return @@ -2239,7 +2236,6 @@ class OaiCiTest(): ue_num = len(self.UEIPAddresses) lock = Lock() status_queue = SimpleQueue() - logging.debug('ue_num = ' + str(ue_num)) for UE_IPAddress in self.UEIPAddresses: device_id = self.UEDevices[i] p = Process(target = self.Iperf_common, args = (lock,UE_IPAddress,device_id,i,ue_num,status_queue,)) @@ -3559,8 +3555,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re CiTestObj.FailReportCnt = 0 RAN.SetprematureExit(True) - CiTestObj.startTime = int(round(time.time() * 1000)) - HTML.SetstartTime(CiTestObj.startTime) + HTML.SetstartTime(int(round(time.time() * 1000)) while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): RAN.SetprematureExit(False) # At every iteratin of the retry loop, a separator will be added diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 7efe96dc2e..917410b8ae 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -1,4 +1,4 @@ - +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -28,7 +28,6 @@ # pexpect #--------------------------------------------------------------------- - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -233,8 +232,6 @@ class RANManagement(): # RAN management functions #----------------------------------------------------------- - - def BuildeNB(self): if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': GenericHelp(Version) @@ -347,8 +344,6 @@ class RANManagement(): mySSH.close() self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id) - - def WaitBuildeNBisFinished(self): if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress @@ -444,7 +439,6 @@ class RANManagement(): self.htmlObj.CreateHtmlTabFooter(False) sys.exit(1) - def InitializeeNB(self): if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress @@ -638,8 +632,6 @@ class RANManagement(): self.htmlObj.CreateHtmlTestRow('-O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK) logging.debug('\u001B[1m Initialize eNB Completed\u001B[0m') - - def CheckeNBProcess(self, status_queue): try: # At least the instance 0 SHALL be on! @@ -672,8 +664,6 @@ class RANManagement(): except: os.kill(os.getppid(),signal.SIGUSR1) - - def TerminateeNB(self): if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress @@ -780,7 +770,6 @@ class RANManagement(): self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBstatuses[int(self.eNB_instance)] = -1 - def LogCollecteNB(self): mySSH = SSH.SSHConnection() mySSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) @@ -791,7 +780,6 @@ class RANManagement(): mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) mySSH.close() - def AnalyzeLogFile_eNB(self, eNBlogFile): if (not os.path.isfile('./' + eNBlogFile)): return -1 @@ -1043,7 +1031,7 @@ class RANManagement(): if foundRealTimeIssue: logging.debug('\u001B[1;37;41m ' + nodeB_prefix + 'NB faced real time issues! \u001B[0m') htmleNBFailureMsg += nodeB_prefix + 'NB faced real time issues!\n' - #return ENB_PROCESS_REALTIME_ISSUE + #return CONST.ENB_PROCESS_REALTIME_ISSUE if rlcDiscardBuffer > 0: rlcMsg = nodeB_prefix + 'NB RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index 6fad5065e2..cdd062f846 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -1,4 +1,4 @@ - +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -28,7 +28,6 @@ # pexpect #--------------------------------------------------------------------- - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -36,6 +35,7 @@ import pexpect # pexpect import logging import time # sleep import re + #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- @@ -89,7 +89,6 @@ class SSHConnection(): else: sys.exit('SSH Connection Failed') - def command(self, commandline, expectedline, timeout): logging.debug(commandline) self.ssh.timeout = timeout From 6eb5d8c9c7169499fee869ea2331dc62f86ceeff Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 21 Apr 2020 22:25:16 +0200 Subject: [PATCH 147/175] CI: fix a few more things Signed-off-by: Raphael Defosseux --- ci-scripts/html.py | 2 ++ ci-scripts/main.py | 32 +++++++++++++++++--------------- ci-scripts/ran.py | 23 +++++++++++++++-------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/ci-scripts/html.py b/ci-scripts/html.py index ac2362477a..67deaa75ce 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -369,6 +369,8 @@ class HTMLManagement(): self.htmlFile.close() def CreateHtmlTestRow(self, options, status, processesStatus, machine='eNB'): + if (self.htmlFooterCreated or (not self.htmlHeaderCreated)): + return self.htmlFile = open('test_results.html', 'a') currentTime = int(round(time.time() * 1000)) - self.startTime self.htmlFile.write(' \n') diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 6aeefdef54..1b65fe0f19 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -353,7 +353,7 @@ class OaiCiTest(): SSH.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - SSH.command('echo "ulimit -c unlimited && ./'+ RAN.Getair_interface() +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + SSH.command('echo "ulimit -c unlimited && ./'+ RAN.Getair_interface() +'-uesoftmodem ' + modifiedUeOptions + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) SSH.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) SSH.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) self.UELogFile = 'ue_' + self.testCase_id + '.log' @@ -451,7 +451,7 @@ class OaiCiTest(): logging.debug(SSH.getBefore()) logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') tunnelInterfaceStatus = False - if RAN.GeteNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnable(0): self.command('ifconfig oaitun_uem1', '\$', 4) result = re.search('inet addr', SSH.getBefore()) if result is not None: @@ -476,7 +476,7 @@ class OaiCiTest(): self.UEDevicesStatus.append(CONST.UE_STATUS_DETACHED) else: if RAN.Getair_interface() == 'lte': - if RAN.GeteNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnable(0): HTML.SethtmlUEFailureMsg('oaitun_ue1/oaitun_uem1 interfaces are either NOT mounted or NOT configured') else: HTML.SethtmlUEFailureMsg('oaitun_ue1 interface is either NOT mounted or NOT configured') @@ -2316,13 +2316,13 @@ class OaiCiTest(): if (status < 0): result = status if result == CONST.ENB_PROCESS_FAILED: - fileCheck = re.search('enb_', str(RAN.GeteNBLogFiles[0])) + fileCheck = re.search('enb_', str(RAN.GeteNBLogFile(0))) if fileCheck is not None: - SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFiles[0], '.') - logStatus = self.AnalyzeLogFile_eNB(RAN.GeteNBLogFiles[0]) + SSH.copyin(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath() + '/cmake_targets/' + RAN.GeteNBLogFile(0), '.') + logStatus = RAN.AnalyzeLogFile_eNB(RAN.GeteNBLogFile[0]) if logStatus < 0: result = logStatus - RAN.SeteNBLogFiles[0] = '' + RAN.SeteNBLogFile('', 0) if RAN.GetflexranCtrlInstalled() and RAN.GetflexranCtrlStarted(): self.TerminateFlexranCtrl() return result @@ -2457,7 +2457,7 @@ class OaiCiTest(): result = re.search('No cell synchronization found, abandoning', str(line)) if result is not None: no_cell_sync_found = True - if RAN.GeteNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnable(0): result = re.search('TRIED TO PUSH MBMS DATA', str(line)) if result is not None: mbms_messages += 1 @@ -2583,7 +2583,7 @@ class OaiCiTest(): statMsg = 'UE showed ' + str(fatalErrorCount) + ' "MAC BSR Triggered ReTxBSR Timer expiry" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') HTML.SethtmlUEFailureMsg(HTML.GethtmlUEFailureMsg() + statMsg + '\n') - if RAN.GeteNBmbmsEnables[0]: + if RAN.GeteNBmbmsEnable(0): if mbms_messages > 0: statMsg = 'UE showed ' + str(mbms_messages) + ' "TRIED TO PUSH MBMS DATA" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') @@ -3075,6 +3075,7 @@ def GetParametersFromXML(action): CiTestObj.air_interface = 'lte' else: CiTestObj.air_interface = CiTestObj.air_interface.lower() + RAN.Setair_interface(CiTestObj.air_interface) if action == 'Terminate_eNB': RAN.SeteNB_instance(test.findtext('eNB_instance')) @@ -3088,6 +3089,7 @@ def GetParametersFromXML(action): CiTestObj.air_interface = 'lte' else: CiTestObj.air_interface = CiTestObj.air_interface.lower() + RAN.Setair_interface(CiTestObj.air_interface) if action == 'Attach_UE': nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') @@ -3120,7 +3122,7 @@ def GetParametersFromXML(action): if (CiTestObj.air_interface is None): CiTestObj.air_interface = 'lte' else: - CiTestObj.air_interface = SSH.air_interface.lower() + CiTestObj.air_interface = CiTestObj.air_interface.lower() if action == 'Terminate_OAI_UE': RAN.SeteNB_instance(test.findtext('UE_instance')) @@ -3378,17 +3380,17 @@ elif re.match('^TerminateHSS$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - CiTestObj.TerminateHSS() + EPC.TerminateHSS() elif re.match('^TerminateMME$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - CiTestObj.TerminateMME() + EPC.TerminateMME() elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - CiTestObj.TerminateSPGW() + EPC.TerminateSPGW() elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): if (RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): GenericHelp(Version) @@ -3398,7 +3400,7 @@ elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - CiTestObj.LogCollecteNB() + RAN.LogCollecteNB() elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': GenericHelp(Version) @@ -3555,7 +3557,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re CiTestObj.FailReportCnt = 0 RAN.SetprematureExit(True) - HTML.SetstartTime(int(round(time.time() * 1000)) + HTML.SetstartTime(int(round(time.time() * 1000))) while CiTestObj.FailReportCnt < CiTestObj.repeatCounts[0] and RAN.GetprematureExit(): RAN.SetprematureExit(False) # At every iteratin of the retry loop, a separator will be added diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 917410b8ae..c65c21c252 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -179,15 +179,13 @@ class RANManagement(): def GeteNB_instance(self): return self.eNB_instance - def SeteNBLogFiles(self, enblogs): - self.eNBLogFiles = enblogs - def GeteNBLogFiles(self): - return self.eNBLogFiles + def SeteNBLogFile(self, enblog, idx): + self.eNBLogFiles[idx] = enblog + def GeteNBLogFile(self, idx): + return self.eNBLogFiles[idx] - def SeteNBmbmsEnables(self, enbmbms): - self.eNBmbmsEnables = enbmbms - def GeteNBmbmsEnables(self): - return self.eNBmbmsEnables + def GeteNBmbmsEnable(self, idx): + return self.eNBmbmsEnables[idx] def SeteNB1IPAddress(self,enb1ip): self.eNB1IPAddress = enb1ip @@ -802,6 +800,7 @@ class RANManagement(): uciStatMsgCount = 0 pdcpFailure = 0 ulschFailure = 0 + ulschReceiveOK = 0 cdrxActivationMessageCount = 0 dropNotEnoughRBs = 0 mbmsRequestMsg = 0 @@ -914,6 +913,9 @@ class RANManagement(): result = re.search('ULSCH in error in round', str(line)) if result is not None: ulschFailure += 1 + result = re.search('ULSCH received ok', str(line)) + if result is not None: + ulschReceiveOK += 1 result = re.search('BAD all_segments_received', str(line)) if result is not None: rlcDiscardBuffer += 1 @@ -933,6 +935,11 @@ class RANManagement(): nodeB_prefix = 'e' else: nodeB_prefix = 'g' + if self.air_interface == 'nr': + if ulschReceiveOK > 0: + statMsg = nodeB_prefix + 'NB showed ' + str(ulschReceiveOK) + ' "ULSCH received ok" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + htmleNBFailureMsg += statMsg + '\n' if uciStatMsgCount > 0: statMsg = nodeB_prefix + 'NB showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') From 93ba34b027ed78dbf626ddede7f79455c23948fb Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 21 Apr 2020 23:44:06 +0200 Subject: [PATCH 148/175] testing for pucch format 2, 3-11 bits. Configuration works for 2 PRBs, 1 symbol only. Assertion in gNB RX otherwise. --- cmake_targets/CMakeLists.txt | 1 + openair1/PHY/INIT/nr_init.c | 3 +- openair1/PHY/NR_REFSIG/nr_refsig.h | 8 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 530 +++++++++++++++++++++++- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c | 14 +- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h | 4 +- openair1/SIMULATION/NR_PHY/pucchsim.c | 73 +++- 7 files changed, 607 insertions(+), 26 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f6fcabf82e..d07694725d 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1495,6 +1495,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/scrambling_luts.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/dmrs_nr.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 1c0d5a6aca..46fd9fb5fd 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -96,7 +96,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, while(gNB->configured == 0) usleep(10000); - init_dfts(); /* LOG_I(PHY,"[gNB %"PRIu8"] Initializing DL_FRAME_PARMS : N_RB_DL %"PRIu8", PHICH Resource %d, PHICH Duration %d nb_antennas_tx:%u nb_antennas_rx:%u PRACH[rootSequenceIndex:%u prach_Config_enabled:%u configIndex:%u highSpeed:%u zeroCorrelationZoneConfig:%u freqOffset:%u]\n", gNB->Mod_id, @@ -113,6 +112,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_gNB][MOD %02"PRIu8"][]\n", gNB->Mod_id); crcTableInit(); init_dfts(); + init_scrambling_luts(); + init_pucch2_luts(); load_nrLDPClib(); // PBCH DMRS gold sequences generation nr_init_pbch_dmrs(gNB); diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index 5af0e88099..d18f6405d7 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -26,7 +26,7 @@ #include "PHY/defs_gNB.h" #include "PHY/LTE_REFSIG/lte_refsig.h" - +#include "PHY/sse_intrin.h" /*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PBCH DMRS. @param PHY_VARS_gNB* gNB structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables @@ -49,4 +49,10 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned char lp, unsigned short nb_pusch_rb, uint8_t dmrs_type); + +void init_scrambling_luts(void); + +extern __m64 byte2m64_re[256]; +extern __m64 byte2m64_im[256]; + #endif diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index ee3e247cb0..62ced5af9d 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -1,3 +1,34 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/NR_TRANSPORT/pucch_rx.c +* \brief Top-level routines for decoding the PUCCH physical channel +* \author A. Mico Pereperez, Padarthi Naga Prasanth, Francesco Mani, Raymond Knopp +* \date 2020 +* \version 0.2 +* \company Eurecom +* \email: +* \note +* \warning +*/ #include #include #include @@ -8,10 +39,12 @@ #include "PHY/impl_defs_nr.h" #include "PHY/defs_nr_common.h" -#include "PHY/defs_nr_UE.h" +#include "PHY/defs_gNB.h" +#include "PHY/sse_intrin.h" #include "PHY/NR_UE_TRANSPORT/pucch_nr.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_transport.h" +#include "PHY/NR_REFSIG/nr_refsig.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" @@ -188,7 +221,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, for (l=0; lnr_of_symbols; l++) { l2 = l+pucch_pdu->start_symbol_index; - re_offset = (12*pucch_pdu->prb_start) + frame_parms->first_carrier_offset; + re_offset = (12*pucch_pdu->prb_start) + (12*pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; if (re_offset>= frame_parms->ofdm_symbol_size) re_offset-=frame_parms->ofdm_symbol_size; @@ -818,3 +851,496 @@ void nr_decode_pucch1( int32_t **rxdataF, } } +__m256i pucch2_3bit[8*2]; +__m256i pucch2_4bit[16*2]; +__m256i pucch2_5bit[32*2]; +__m256i pucch2_6bit[64*2]; +__m256i pucch2_7bit[128*2]; +__m256i pucch2_8bit[256*2]; +__m256i pucch2_9bit[512*2]; +__m256i pucch2_10bit[1024*2]; +__m256i pucch2_11bit[2048*2]; + +__m256i *pucch2_lut[9]={pucch2_3bit, + pucch2_4bit, + pucch2_5bit, + pucch2_6bit, + pucch2_7bit, + pucch2_8bit, + pucch2_9bit, + pucch2_10bit, + pucch2_11bit}; + +void init_pucch2_luts() { + + uint32_t out; + int8_t bit; + + for (int b=3;b<12;b++) { + for (uint16_t i=0;i<(1< 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,0); + bit = (out&0x2) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,0); + bit = (out&0x4) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,1); + bit = (out&0x8) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,1); + bit = (out&0x10) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,2); + bit = (out&0x20) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,2); + bit = (out&0x40) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,3); + bit = (out&0x80) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,3); + bit = (out&0x100) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,4); + bit = (out&0x200) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,4); + bit = (out&0x400) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,5); + bit = (out&0x800) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,5); + bit = (out&0x1000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,6); + bit = (out&0x2000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,6); + bit = (out&0x4000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,7); + bit = (out&0x8000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,7); + bit = (out&0x10000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,8); + bit = (out&0x20000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,8); + bit = (out&0x40000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,9); + bit = (out&0x80000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,9); + bit = (out&0x100000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,10); + bit = (out&0x200000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,10); + bit = (out&0x400000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,11); + bit = (out&0x800000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,11); + bit = (out&0x1000000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,12); + bit = (out&0x2000000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,12); + bit = (out&0x4000000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,13); + bit = (out&0x8000000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,13); + bit = (out&0x10000000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,14); + bit = (out&0x20000000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,14); + bit = (out&0x40000000) > 0 ? -1 : 1; + *lut_i = _mm256_insert_epi16(*lut_i,bit,15); + bit = (out&0x80000000) > 0 ? -1 : 1; + *lut_ip1 = _mm256_insert_epi16(*lut_ip1,bit,15); + } + } +} + + +void nr_decode_pucch2(PHY_VARS_gNB *gNB, + int slot, + nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu, + nfapi_nr_pucch_pdu_t* pucch_pdu) { + + int32_t **rxdataF = gNB->common_vars.rxdataF; + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); + + AssertFatal(pucch_pdu->nr_of_symbols==1 || pucch_pdu->nr_of_symbols==2, + "Illegal number of symbols for PUCCH 2 %d\n",pucch_pdu->nr_of_symbols); + + + //extract pucch and dmrs first + + int l2; + int re_offset = (12*pucch_pdu->prb_start) + (12*pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; + if (re_offset>= frame_parms->ofdm_symbol_size) + re_offset-=frame_parms->ofdm_symbol_size; + + AssertFatal(pucch_pdu->prb_size*pucch_pdu->nr_of_symbols > 1,"number of PRB*SYMB (%d,%d)< 2", + pucch_pdu->prb_size,pucch_pdu->nr_of_symbols); + + int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value; + int Prx2 = (Prx==1)?2:Prx; + // use 2 for Nb antennas in case of single antenna to allow the following allocations + int16_t r_re_ext[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + int16_t r_im_ext[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + int16_t r_re_ext2[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + int16_t r_im_ext2[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + int16_t rd_re_ext[Prx2][4*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + int16_t rd_im_ext[Prx2][4*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + + int16_t *rp[Prx2]; + __m64 dmrs_re,dmrs_im; + + for (int aa=0;aaofdm_symbol_size)+re_offset]); + +#ifdef DEBUG_NR_PUCCH_RX + printf("Decoding pucch2 for %d symbols, %d PRB\n",pucch_pdu->nr_of_symbols,pucch_pdu->prb_size); +#endif + + int nc_group_size=1; // 2 PRB + int ngroup = pucch_pdu->prb_size/nc_group_size/2; + int32_t corr32_re[ngroup][Prx2],corr32_im[ngroup][Prx2]; + for (int aa=0;aanr_of_symbols == 1) { + AssertFatal((pucch_pdu->prb_size&1) == 0,"prb_size %d is not a multiple of 2\n",pucch_pdu->prb_size); + // 24 PRBs contains 48x16-bit, so 6x8x16-bit + for (int prb=0;prbprb_size;prb+=2) { + for (int aa=0;aa (%d,%d)\n",aa,prb+(i>>2),i,rd_re_ext[aa][i],rd_im_ext[aa],i); +#endif + } // aa + } // prb + + + // first compute DMRS component + uint32_t x1, x2, s=0; + x2 = (((1<<17)*((14*slot) + (pucch_pdu->start_symbol_index) + 1)*((2*pucch_pdu->dmrs_scrambling_id) + 1)) + (2*pucch_pdu->dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause +#ifdef DEBUG_NR_PUCCH_RX + printf("slot %d, start_symbol_index %d, dmrs_scrambling_id %d\n", + slot,pucch_pdu->start_symbol_index,pucch_pdu->dmrs_scrambling_id); +#endif + s = lte_gold_generic(&x1, &x2, 1); + + + for (int group=0;group>=5; + corr32_im[group][aa]>>=5; +#ifdef DEBUG_NR_PUCCH_RX + printf("Group %d: corr32 (%d,%d)\n",group,corr32_re[group][aa],corr32_im[group][aa]); +#endif + } //aa + + if ((group&3) == 3) s = lte_gold_generic(&x1, &x2, 0); + } // group + } + else { // 2 symbol case + AssertFatal(1==0, "Fill in 2 symbol PUCCH2 case\n"); + } + + uint32_t x1, x2, s=0; + // unscrambling + x2 = ((pucch_pdu->rnti)<<15)+pucch_pdu->data_scrambling_id; + s = lte_gold_generic(&x1, &x2, 1); +#ifdef DEBUG_NR_PUCCH_RX + printf("x2 %x, s %x\n",x2,s); +#endif + __m64 c_re0,c_im0,c_re1,c_im1,c_re2,c_im2,c_re3,c_im3; + re_offset=0; + for (int prb=0;prbprb_size;prb+=2,re_offset+=16) { + c_re0 = byte2m64_re[((uint8_t*)&s)[0]]; + c_im0 = byte2m64_im[((uint8_t*)&s)[0]]; + c_re1 = byte2m64_re[((uint8_t*)&s)[1]]; + c_im1 = byte2m64_im[((uint8_t*)&s)[1]]; + c_re2 = byte2m64_re[((uint8_t*)&s)[2]]; + c_im2 = byte2m64_im[((uint8_t*)&s)[2]]; + c_re3 = byte2m64_re[((uint8_t*)&s)[3]]; + c_im3 = byte2m64_im[((uint8_t*)&s)[3]]; + + for (int aa=0;aabit_len_csi_part1 + pucch_pdu->bit_len_csi_part2 == 0,"no csi for now\n"); + AssertFatal((pucch_pdu->bit_len_harq+pucch_pdu->sr_flag > 2 ) && (pucch_pdu->bit_len_harq+pucch_pdu->sr_flag < 12),"illegal length (%d,%d)\n",pucch_pdu->bit_len_harq,pucch_pdu->sr_flag); + int nb_bit = pucch_pdu->bit_len_harq+pucch_pdu->sr_flag; + __m256i *rp_re[Prx2]; + __m256i *rp2_re[Prx2]; + __m256i *rp_im[Prx2]; + __m256i *rp2_im[Prx2]; + for (int aa=0;aa>1], + ((int16_t*)&pucch2_lut[nb_bit-3][cw<<1])[1+(i>>1)]); + } + printf("\n"); +#endif + // do complex correlation + for (int aa=0;aa corr) { + corr = corr_tmp; + cw_ML=cw; + } + } + uint8_t corr_dB = dB_fixed64((uint64_t)corr); + LOG_D(PHY,"cw_ML %d, metric %d dB\n",cw_ML,corr_dB); + uci_pdu->harq.harq_bit_len = pucch_pdu->bit_len_harq; + + + int harq_bytes=pucch_pdu->bit_len_harq>>3; + if ((pucch_pdu->bit_len_harq&7) > 0) harq_bytes++; + uci_pdu->harq.harq_payload = (nfapi_nr_harq_t*)malloc(harq_bytes); + uci_pdu->harq.harq_crc = 2; + for (int i=0;iharq.harq_payload[i] = cw_ML & 255; + cw_ML>>=8; + } + + if (pucch_pdu->sr_flag == 1) { + uci_pdu->sr.sr_bit_len = 1; + uci_pdu->sr.sr_payload = malloc(1); + uci_pdu->sr.sr_payload[0] = cw_ML; + } +} + diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index d63cef5085..2a08d54c5a 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -42,6 +42,7 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "T.h" +//#define NR_UNIT_TEST 1 #ifdef NR_UNIT_TEST #define DEBUG_PUCCH_TX #define DEBUG_NR_PUCCH_TX @@ -905,7 +906,9 @@ void nr_uci_encoding(uint64_t payload, if (A<=11) { // procedure in subclause 6.3.1.2.2 (UCI encoded by channel coding of small block lengths -> subclause 6.3.1.3.2) // CRC bits are not attached, and coding small block lengths (subclause 5.3.3) + b[0] = encodeSmallBlock((uint16_t*)&payload,A); } else if (A>=12) { + AssertFatal(1==0,"Polar encoding not supported yet for UCI\n"); // procedure in subclause 6.3.1.2.1 (UCI encoded by Polar code -> subclause 6.3.1.3.1) /*if ((A>=360 && E>=1088)||(A>=1013)) { I_seg = 1; @@ -924,10 +927,13 @@ void nr_uci_encoding(uint64_t payload, // code block segmentation and CRC attachment is performed according to subclause 5.2.1 // polar coding subclause 5.3.1 } + } //#if 0 void nr_generate_pucch2(PHY_VARS_NR_UE *ue, uint16_t crnti, + uint32_t dmrs_scrambling_id, + uint32_t data_scrambling_id, int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, @@ -961,14 +967,14 @@ void nr_generate_pucch2(PHY_VARS_NR_UE *ue, */ uint8_t *btilde = malloc(sizeof(int8_t)*M_bit); // rnti is given by the C-RNTI - uint16_t rnti=crnti, n_id=0; + uint16_t rnti=crnti; #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch2] rnti = %d ,\n",rnti); #endif /* * Implementing TS 38.211 Subclause 6.3.2.5.1 scrambling format 2 */ - nr_pucch2_3_4_scrambling(M_bit,rnti,n_id,b,btilde); + nr_pucch2_3_4_scrambling(M_bit,rnti,data_scrambling_id,b,btilde); /* * Implementing TS 38.211 Subclause 6.3.2.5.2 modulation format 2 * btilde shall be modulated as described in subclause 5.1 using QPSK @@ -1016,10 +1022,10 @@ void nr_generate_pucch2(PHY_VARS_NR_UE *ue, int m=0; for (int l=0; lN_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index 4c4847d7de..510abb8373 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -20,7 +20,7 @@ */ /*! \file PHY/NR_UE_TRANSPORT/pucch_nr.c -* \brief Top-level routines for generating and decoding the PUCCH physical channel +* \brief Top-level routines for generating the PUCCH physical channel * \author A. Mico Pereperez * \date 2018 * \version 0.1 @@ -70,6 +70,8 @@ void nr_generate_pucch1(PHY_VARS_NR_UE *ue, uint8_t nr_bit); void nr_generate_pucch2(PHY_VARS_NR_UE *ue, uint16_t crnti, + uint32_t dmrs_scrambling_id, + uint32_t data_scrambling_id, int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 3b7305bf9b..9e1609c3b4 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -93,11 +93,12 @@ int main(int argc, char **argv) uint8_t nrofSymbols=1; //number of OFDM symbols can be 1-2 for format 1 uint8_t startingSymbolIndex=0; // resource allocated see 9.2.1, 38.213 for more info.should be actually present in the resource set provided uint16_t startingPRB=0,startingPRB_intraSlotHopping=0; //PRB number not sure see 9.2.1, 38.213 for more info. Should be actually present in the resource set provided + uint16_t nrofPRB=2; uint8_t timeDomainOCC=0; SCM_t channel_model=AWGN;//Rayleigh1_anticorr; int N_RB_DL=273,mu=1; - float target_error_rate=0.01; + float target_error_rate=0.001; int frame_length_complex_samples; //int frame_length_complex_samples_no_prefix; NR_DL_FRAME_PARMS *frame_parms; @@ -112,9 +113,8 @@ int main(int argc, char **argv) randominit(0); logInit(); - set_glog(loglvl); - while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL")) != -1) { + while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:")) != -1) { switch (c) { case 'f': //write_output_file=1; @@ -263,6 +263,9 @@ int main(int argc, char **argv) case 'r': startingPRB=atoi(optarg); break; + case 'q': + nrofPRB=atoi(optarg); + break; case 'P': format=atoi(optarg); break; @@ -305,7 +308,8 @@ int main(int argc, char **argv) printf("-F Input filename (.txt format) for RX conformance testing\n"); printf("-i Enter number of ofdm symbols for pucch\n"); printf("-I Starting symbol index for pucch\n"); - printf("-r PUCCCH starting PRB\n"); + printf("-r PUCCH starting PRB\n"); + printf("-q PUCCH number of PRB\n"); printf("-P Enter the format of PUCCH\n"); printf("-b number of HARQ bits (1-2)\n"); printf("-B payload to be transmitted on PUCCH\n"); @@ -316,18 +320,22 @@ int main(int argc, char **argv) } } + set_glog(loglvl); + if (snr1set==0) snr1 = snr0+10; printf("Initializing gNodeB for mu %d, N_RB_DL %d\n",mu,N_RB_DL); - if((format!=0) && (format!=1)){ + if((format!=0) && (format!=1) && (format!=2)){ printf("PUCCH format %d not supported\n",format); exit(0); } - AssertFatal((nr_bit<3)&&(actual_payload<4),"Only format 0 and 1 currently supported. 2 bits max supported"); + AssertFatal(((format < 2)&&(nr_bit<3)&&(actual_payload<4)) || + ((format == 2)&&(nr_bit>2)&&(nr_bit<12)),"illegal combination format %d, nr_bit %d\n", + format,nr_bit); - if (nr_bit==1) actual_payload = actual_payload&1; + actual_payload &= ((1<ofdm_symbol_size); - txdataF[i] = malloc(14*frame_parms->ofdm_symbol_size*sizeof(int)); + txdataF[i] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int)); bzero(txdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int)); - rxdataF[i] = malloc(14*frame_parms->ofdm_symbol_size*sizeof(int)); + rxdataF[i] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int)); bzero(rxdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int)); } @@ -443,8 +451,8 @@ int main(int argc, char **argv) uint8_t mcs=0; startingPRB_intraSlotHopping=N_RB_DL-1; pucch_GroupHopping_t PUCCH_GroupHopping=UE->pucch_config_common_nr->pucch_GroupHopping; - uint32_t n_id=UE->pucch_config_common_nr->hoppingId; - + uint32_t hopping_id=UE->pucch_config_common_nr->hoppingId; + uint32_t dmrs_scrambling_id = 0, data_scrambling_id=0; if(format==0){ // for now we are not considering SR just HARQ-ACK if(nr_bit==1) @@ -461,9 +469,12 @@ int main(int argc, char **argv) if(format==0){ nr_generate_pucch0(UE,txdataF,frame_parms,UE->pucch_config_dedicated,amp,nr_tti_tx,m0,mcs,nrofSymbols,startingSymbolIndex,startingPRB); } - else{ + else if (format == 1){ nr_generate_pucch1(UE,txdataF,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,0,nr_bit); } + else { + nr_generate_pucch2(UE,0x1234,dmrs_scrambling_id,data_scrambling_id,txdataF,frame_parms,UE->pucch_config_dedicated,actual_payload,amp,nr_tti_tx,nrofSymbols,startingSymbolIndex,nrofPRB,startingPRB,nr_bit); + } int txlev = signal_energy(&txdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size); @@ -489,7 +500,7 @@ int main(int argc, char **argv) pucch_pdu.bit_len_harq = nr_bit; pucch_pdu.sr_flag = 0; pucch_pdu.nr_of_symbols = nrofSymbols; - pucch_pdu.hopping_id = n_id; + pucch_pdu.hopping_id = hopping_id; pucch_pdu.initial_cyclic_shift = 0; pucch_pdu.start_symbol_index = startingSymbolIndex; pucch_pdu.prb_start = startingPRB; @@ -497,21 +508,49 @@ int main(int argc, char **argv) if(nr_bit==1) ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value); else - ack_nack_errors+=((actual_payload^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value)); + ack_nack_errors+=(((actual_payload&1)^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value)); free(uci_pdu.harq->harq_list); } - else{ + else if (format==1) { - nr_decode_pucch1(rxdataF,PUCCH_GroupHopping,n_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit); + nr_decode_pucch1(rxdataF,PUCCH_GroupHopping,hopping_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit); if(nr_bit==1) ack_nack_errors+=((actual_payload^payload_received)&1); else ack_nack_errors+=((actual_payload^payload_received)&1) + (((actual_payload^payload_received)&2)>>1); } + else if (format==2) { + nfapi_nr_uci_pucch_pdu_format_2_3_4_t uci_pdu; + nfapi_nr_pucch_pdu_t pucch_pdu; + pucch_pdu.rnti = 0x1234; + pucch_pdu.subcarrier_spacing = 1; + pucch_pdu.group_hop_flag = PUCCH_GroupHopping&1; + pucch_pdu.sequence_hop_flag = (PUCCH_GroupHopping>>1)&1; + pucch_pdu.bit_len_harq = nr_bit; + pucch_pdu.sr_flag = 0; + pucch_pdu.nr_of_symbols = nrofSymbols; + pucch_pdu.hopping_id = hopping_id; + pucch_pdu.initial_cyclic_shift = 0; + pucch_pdu.start_symbol_index = startingSymbolIndex; + pucch_pdu.prb_size = nrofPRB; + pucch_pdu.prb_start = startingPRB; + pucch_pdu.dmrs_scrambling_id = dmrs_scrambling_id; + pucch_pdu.data_scrambling_id = data_scrambling_id; + nr_decode_pucch2(gNB,nr_tti_tx,&uci_pdu,&pucch_pdu); + int harq_bytes=pucch_pdu.bit_len_harq>>3; + if ((pucch_pdu.bit_len_harq&7) > 0) harq_bytes++; + for (int i=0;i>1)+(((actual_payload^payload_received)&4)>>2)+n_errors; } printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,ack_nack_errors); - if((float)ack_nack_errors/(float)(nr_bit*n_trials)<=target_error_rate){ + if((float)ack_nack_errors/(float)(n_trials)<=target_error_rate){ printf("PUCCH test OK\n"); break; } From 1e6e780a71679eeb3be35676726198b9c55834d3 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 22 Apr 2020 12:04:51 +0200 Subject: [PATCH 149/175] CI: final fixes for noS1 ping operations and LTE-M Signed-off-by: Raphael Defosseux --- ci-scripts/main.py | 25 ++++++++++++------------- ci-scripts/sshconnection.py | 7 +++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 1b65fe0f19..837c592bd7 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -86,7 +86,6 @@ class OaiCiTest(): self.CatMDevices = [] self.UEIPAddresses = [] self.htmlUEConnected = -1 - self.picocom_closure = False self.idle_sleep_time = 0 self.x2_ho_options = 'network' self.x2NbENBs = 0 @@ -452,7 +451,7 @@ class OaiCiTest(): logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') tunnelInterfaceStatus = False if RAN.GeteNBmbmsEnable(0): - self.command('ifconfig oaitun_uem1', '\$', 4) + SSH.command('ifconfig oaitun_uem1', '\$', 4) result = re.search('inet addr', SSH.getBefore()) if result is not None: logging.debug('\u001B[1m oaitun_uem1 interface is mounted and configured\u001B[0m') @@ -504,7 +503,7 @@ class OaiCiTest(): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - self.picocom_closure = True + SSH.enablePicocomClosure() SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) @@ -514,10 +513,10 @@ class OaiCiTest(): SSH.command('AT', 'OK|ERROR', 5) SSH.command('AT', 'OK', 5) # Doing a power cycle - self.command('AT^RESET', 'SIMSTORE,READY', 15) - self.command('AT', 'OK|ERROR', 5) - self.command('AT', 'OK', 5) - self.command('ATE1', 'OK', 5) + SSH.command('AT^RESET', 'SIMSTORE,READY', 15) + SSH.command('AT', 'OK|ERROR', 5) + SSH.command('AT', 'OK', 5) + SSH.command('ATE1', 'OK', 5) # Disabling the Radio SSH.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') @@ -535,7 +534,7 @@ class OaiCiTest(): logging.debug('\u001B[1;37;41m Could not check Auto-Attach! \u001B[0m') # Force closure of picocom but device might still be locked SSH.close() - self.picocom_closure = False + SSH.disablePicocomClosure() HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() @@ -543,7 +542,7 @@ class OaiCiTest(): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - self.picocom_closure = True + SSH.enablePicocomClosure() SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) @@ -556,7 +555,7 @@ class OaiCiTest(): SSH.command('AT+CFUN=0', 'OK', 5) logging.debug('\u001B[1m Cellular Functionality disabled\u001B[0m') SSH.close() - self.picocom_closure = False + SSH.disablePicocomClosure() HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) self.checkDevTTYisUnlocked() @@ -564,7 +563,7 @@ class OaiCiTest(): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': GenericHelp(Version) sys.exit('Insufficient Parameter') - self.picocom_closure = True + SSH.enablePicocomClosure() SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) # dummy call to start a sudo session. The picocom command does NOT handle well the `sudo -S` SSH.command('echo ' + self.ADBPassword + ' | sudo -S ls', '\$', 10) @@ -615,7 +614,7 @@ class OaiCiTest(): logging.debug(' RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB') logging.debug(' RSRP = ' + str(-140+nRSRP) + ' dBm') SSH.close() - self.picocom_closure = False + SSH.disablePicocomClosure() html_queue = SimpleQueue() self.checkDevTTYisUnlocked() if attach_status: @@ -1382,7 +1381,7 @@ class OaiCiTest(): sys.exit('Insufficient Parameter') try: if ping_from_eNB is not None: - SSH.open(RAN.GeteNBIPAddress, RAN.GeteNBUserName, RAN.GeteNBPassword) + SSH.open(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword()) SSH.command('cd ' + RAN.GeteNBSourceCodePath() + '/cmake_targets/', '\$', 5) else: SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index cdd062f846..649ffef26c 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -42,6 +42,13 @@ import re class SSHConnection(): def __init__(self): self.ssh = '' + self.picocom_closure = False + + def disablePicocomClosure(self): + self.picocom_closure = False + + def enablePicocomClosure(self): + self.picocom_closure = True def open(self, ipaddress, username, password): count = 0 From 009609f1f31bdcef33770222ecdebbccdb7bbba8 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 22 Apr 2020 16:46:42 +0200 Subject: [PATCH 150/175] DOC: update L2 nFAPI simulator Signed-off-by: Raphael Defosseux --- doc/L2NFAPI.md | 19 +- doc/L2NFAPI_NOS1.md | 349 +++++++++++++++++++ doc/L2NFAPI_S1.md | 167 +++++---- doc/images/L2-sim-S1-3-host-deployment.png | Bin 0 -> 88726 bytes doc/images/L2-sim-noS1-2-host-deployment.png | Bin 0 -> 57368 bytes 5 files changed, 458 insertions(+), 77 deletions(-) create mode 100644 doc/L2NFAPI_NOS1.md create mode 100644 doc/images/L2-sim-S1-3-host-deployment.png create mode 100644 doc/images/L2-sim-noS1-2-host-deployment.png diff --git a/doc/L2NFAPI.md b/doc/L2NFAPI.md index 4dcaaef3bc..137e4847e4 100644 --- a/doc/L2NFAPI.md +++ b/doc/L2NFAPI.md @@ -14,19 +14,24 @@ This simulator allows to test L2 and above Layers using the nFAPI interface. +The UE executable is able to "simulate" multiple UEs in order to stimulate the scheduler in the eNB. + **This simulator is available starting the `v1.0.0` release on the `master` branch.** -Currently the only validated deployment by CI and developers is *with S1 interface and eNB / UEs are on the same machine*. - -Others deployments will be supported later after bug fixes and validation in the CI process. - -1. [With S1 -- eNB and UE on same machine](L2NFAPI_S1.md) - - +Currently the Continuous Integration process is validating this simulator the following way: +* the LTE modem executable is run on one host (in our CI deployment it is a **Xenial Virtual Machine**) +* the UE(s) modem executable is run on another host (in our CI deployment it is also a **Xenial Virtual Machine**) +* We are testing: + * in S1 mode (ie we are connected to a 3rd-party EPC) + * in noS1 mode (no need for an EPC) +Normally it should be fine to run both executables on the same host using the `loopback` interface to communicate. **But we are not guaranting it** +1. [With S1 -- eNB and UE on 2 hosts](L2NFAPI_S1.md) +2. [No S1 -- eNB and UE on 2 hosts](L2NFAPI_NOS1.md) +---- [oai wiki home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/doc/L2NFAPI_NOS1.md b/doc/L2NFAPI_NOS1.md new file mode 100644 index 0000000000..bb4c32ec08 --- /dev/null +++ b/doc/L2NFAPI_NOS1.md @@ -0,0 +1,349 @@ +
' + str('eNB') + ' Server Characteristics
OS Version' + self.OsVersion + '' + self.OsVersion[idx] + 'Kernel Version' + self.KernelVersion + '' + self.KernelVersion[idx] + 'UHD Version' + self.UhdVersion + '' + self.UhdVersion[idx] + 'USRP Board' + self.UsrpBoard + '' + self.UsrpBoard[idx] + '
Nb CPUs' + self.CpuNb + '' + self.CpuNb[idx] + 'CPU Model Name' + self.CpuModel + '' + self.CpuModel[idx] + 'CPU Frequency' + self.CpuMHz + '
' + str('UE') + ' Server Characteristics
OS Version' + self.OsVersion + 'Kernel Version' + self.KernelVersion + 'UHD Version' + self.UhdVersion + 'USRP Board' + self.UsrpBoard + '
Nb CPUs' + self.CpuNb + 'CPU Model Name' + self.CpuModel + 'CPU Frequency' + self.CpuMHz + '' + self.CpuMHz[idx] + '
' + str(status) + 'KO - eNB process not foundKO - OAI UE process not foundKO - ' + machine + ' process ended in Segmentation FaultKO - ' + machine + ' process ended in AssertionKO - ' + machine + ' process faced Real Time issue(s)OK?KO - ' + machine + ' Slave RRU could not synchKO - UE could not syncKO - HSS process not foundKO - MME process not foundKO - SPGW process not foundKO - Could not retrieve UE IP address' + str(status) + '
+ + + + +
+ + + + + + L2 nFAPI Simulator (no S1 Mode / 2-host deployment) +
+ +## Table of Contents ## + +1. [Environment](#1-environment) +2. [Retrieve the OAI eNB-UE source code](#2-retrieve-the-oai-enb-ue-source-code) +3. [Setup of the USIM information in UE folder](#3-setup-of-the-usim-information-in-ue-folder) +4. [Setup of the Configuration files](#4-setup-of-the-configuration-files) + 1. [The eNB Configuration file](#41-the-enb-configuration-file) + 2. [The UE Configuration file](#42-the-ue-configuration-file) +5. [Build OAI UE and eNodeB](#5-build-oai-ue-and-enodeb) +6. [Start the eNB](#6-start-the-enb) +7. [Start the UE](#7-start-the-ue) +8. [Test with ping](#8-test-with-ping) +9. [Limitations](#9-limitations) + +# 1. Environment # + +You may not have access to an EPC or you don't want to hassle to deploy one. + +2 servers are used in this deployment. You can use Virtual Machines instead of each server; like it is done in the CI process. + +* Machine B contains the OAI eNB executable (`lte-softmodem`) +* Machine C contains the OAI UE(s) executable (`lte-uesoftmodem`) + +Example of L2 nFAPI Simulator testing environment: + + + +Note that the IP addresses are indicative and need to be adapted to your environment. + +# 2. Retrieve the OAI eNB-UE source code # + +At the time of writing, the tag used in the `develop` branch to do this documentation was `2020.w16`. + +The tutorial should be valid for the `master` branch tags such as `v1.2.0` or `v1.2.1`. But you may face issues that could be fixed in newer `develop` tags. + +Please try to use the same commit ID on both eNB/UE hosts. + +```bash +$ ssh sudousername@machineB +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git enb_folder +cd enb_folder +git checkout develop +``` + +```bash +$ ssh sudousername@machineC +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ue_folder +cd ue_folder +git checkout develop +``` + +# 3. Setup of the USIM information in UE folder # + +```bash +$ ssh sudousername@machineC +cd ue_folder +# Edit openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf with your preferred editor +``` + +Edit the USIM information within this file in order to match the HSS database. They **HAVE TO** match: + +* PLMN+MSIN and IMSI of users table of HSS database **SHALL** be the same. +* OPC of this file and OPC of users table of HSS database **SHALL** be the same. +* USIM_API_K of this file and the key of users table of HSS database **SHALL** be the same. + +When testing multiple UEs, it is necessary to add other UEs information like described below for 2 Users. Only UE0 (first UE) information is written in the original file. + +``` +UE0: +{ + USER: { + IMEI="356113022094149"; + MANUFACTURER="EURECOM"; + MODEL="LTE Android PC"; + PIN="0000"; + }; + + SIM: { + MSIN="0000000001"; // <-- Modify here + USIM_API_K="8baf473f2f8fd09487cccbd7097c6862"; + OPC="e734f8734007d6c5ce7a0508809e7e9c"; + MSISDN="33611123456"; + }; +... +}; +// Copy the UE0 and edit +UE1: // <- Edit here +{ + USER: { + IMEI="356113022094149"; + MANUFACTURER="EURECOM"; + MODEL="LTE Android PC"; + PIN="0000"; + }; + + SIM: { + MSIN="0000000002"; // <-- Modify here + USIM_API_K="8baf473f2f8fd09487cccbd7097c6862"; + OPC="e734f8734007d6c5ce7a0508809e7e9c"; + MSISDN="33611123456"; + }; +... +}; +``` + +You can repeat the operation for as many users you want to test with. + +# 4. Setup of the Configuration files # + +**CAUTION: both proposed configuration files resides in the ci-scripts realm. You can copy them but you CANNOT push any modification on these 2 files as part of an MR without informing the CI team.** + +## 4.1. The eNB Configuration file ## + +```bash +$ ssh sudousername@machineB +cd enb_folder +# Edit ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf with your preferred editor +``` + +First verify the nFAPI interface setup on the physical ethernet interface of machineB and put the proper IP addresses for both hosts. + +``` +MACRLCs = ( + { + num_cc = 1; + local_s_if_name = "ens3"; // <-- HERE + remote_s_address = "192.168.122.169"; // <-- HERE + local_s_address = "192.168.122.31"; // <-- HERE + local_s_portc = 50001; + remote_s_portc = 50000; + local_s_portd = 50011; + remote_s_portd = 50010; + tr_s_preference = "nfapi"; + tr_n_preference = "local_RRC"; + } +); +``` + +If you are testing more than 16 UEs, a proper setting on the RUs is necessary. **Note that this part is NOT present in the original configuration file**. + +``` +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 20 + att_rx = 0; + bands = [38]; + max_pdschReferenceSignalPower = -23; + max_rxgain = 116; + eNB_instances = [0]; + } +); +``` + +Last, the S1 interface shall be properly set. + +``` + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; // replace with 192.168.122.195 + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "ens3"; // replace with the proper interface name + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; // replace with 192.168.122.31 + ENB_INTERFACE_NAME_FOR_S1U = "ens3"; // replace with the proper interface name + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; // replace with 192.168.122.31 + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; // replace with 192.168.122.31 + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + + }; +``` + +## 4.2. The UE Configuration file ## + +```bash +$ ssh sudousername@machineB +cd ue_folder +# Edit ci-scripts/conf_files/ue.nfapi.conf with your preferred editor +``` + +Verify the nFAPI interface setup on the loopback interface. + +``` +L1s = ( + { + num_cc = 1; + tr_n_preference = "nfapi"; + local_n_if_name = "ens3"; // <- HERE + remote_n_address = "192.168.122.31"; // <- HERE + local_n_address = "192.168.122.169"; // <- HERE + local_n_portc = 50000; + remote_n_portc = 50001; + local_n_portd = 50010; + remote_n_portd = 50011; + } +); +``` + +# 5. Build OAI UE and eNodeB # + +See [Build documentation](./BUILD.md). + +# 6. Start the eNB # + +In the first terminal (the one you used to build the eNB): + +```bash +$ ssh sudousername@machineB +cd enb_folder/cmake_targets +sudo -E ./ran_build/build/lte-softmodem -O ../ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf --noS1 > enb.log 2>&1 +sleep 10 +ifconfig +ens3 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX + inet addr:192.168.122.31 Bcast:192.168.122.255 Mask:255.255.255.0 +.... +oaitun_enb1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.1.1 P-t-P:192.172.0.2 Mask:255.255.255.0 +.... +``` + +If you don't use redirection, you can test but many logs are printed on the console and this may affect performance of the L2-nFAPI simulator. + +We do recommend the redirection in steady mode once your setup is correct. + +# 7. Start the UE # + +In the second terminal (the one you used to build the UE): + +```bash +$ ssh sudousername@machineC +cd ue_folder/cmake_targets +# Test 64 UEs, 1 thread in FDD mode +sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --noS1 --L2-emul 3 --num-ues 64 --nums_ue_thread 1 --nokrnmod 1 > ue.log 2>&1 +# Test 64 UEs, 1 thread in TDD mode +sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --noS1 --L2-emul 3 --num-ues 64 --nums_ue_thread 1 --nokrnmod 1 -T 1 > ue.log 2>&1 +# The "-T 1" option means TDD config +``` + +- The number of UEs can set by using `--num-ues` option and the maximum UE number is 255 (with the `--mu*` options, otherwise 16). +- The number of threads can set with the `--nums-ue-thread`. This number **SHALL NOT** be greater than the number of UEs. + * At the time of writing, it seems to be enough to run on a single thread. +- The `--nokrnmod 1` option makes use of the preferred and supported tunnel interface. +- How many UE that can be tested depends on hardware (server , PC, etc) performance in your environment. + +For example, running with 4 UEs: + +```bash +$ ssh sudousername@machineC +cd ue_folder/cmake_targets +sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --noS1 --L2-emul 3 --num-ues 64 --nums_ue_thread 1 --nokrnmod 1 > ue.log 2>&1 +sleep 10 +ifconfig +ens3 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX + inet addr:192.168.122.169 Bcast:192.168.122.255 Mask:255.255.255.0 +.... +oaitun_ue1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.1.2 P-t-P:192.172.0.2 Mask:255.255.255.0 +.... +oaitun_ue2 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.1.3 P-t-P:192.172.0.3 Mask:255.255.255.0 +.... +oaitun_ue3 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.1.4 P-t-P:192.172.0.4 Mask:255.255.255.0 +.... +oaitun_ue4 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.1.5 P-t-P:192.172.0.5 Mask:255.255.255.0 +.... +oaitun_uem1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.2.2 P-t-P:10.0.2.2 Mask:255.255.255.0 +.... +.... +``` + +Having the 4 oaitun_ue tunnel interfaces up and with an allocated address means the connection with EPC went alright. + +# 8. Test with ping # + +In a third terminal, after around 10 seconds, the UE(s) shall be connected to the eNB: Check with ifconfig + +```bash +$ ssh sudousername@machineB +# Ping UE1 IP address based on the EPC pool used: in this example: +ping -I oaitun_enb1 -c 20 10.0.1.2 +# Ping UE4 IP address based on the EPC pool used: in this example: +ping -I oaitun_enb1 -c 20 10.0.1.5 +``` + +Ping from the UE side: + +```bash +$ ssh sudousername@machineC +ping -I oaitun_ue1 -c 20 10.0.1.1 +ping -I oaitun_ue3 -c 20 10.0.1.1 +``` + +iperf operations can also be performed. + +DL traffic: + +```bash +$ ssh sudousername@machineC +iperf -B 10.0.1.2 -u -s -i 1 -fm -p 5002 +$ ssh sudousername@machineB +iperf -c 10.0.1.2 -u -t 30 -b 3M -i 1 -fm -B 10.0.1.1 -p 5002 +``` + +UL traffic: + +```bash +$ ssh sudousername@machineB +iperf -B 10.0.1.1 -u -s -i 1 -fm -p 5002 +$ ssh sudousername@machineC +iperf -c 10.0.1.1 -u -t 30 -b 2M -i 1 -fm -B 10.0.1.2 -p 5002 +``` + +# 9. Limitations # + + +---- + +[oai wiki home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) + +[oai softmodem features](FEATURE_SET.md) + +[oai softmodem build procedure](BUILD.md) + +[L2 nfapi simulator](L2NFAPI.md) diff --git a/doc/L2NFAPI_S1.md b/doc/L2NFAPI_S1.md index b9156e9379..9fd6d51818 100644 --- a/doc/L2NFAPI_S1.md +++ b/doc/L2NFAPI_S1.md @@ -7,7 +7,7 @@ - L2 nFAPI Simulator (with S1 / same machine deployment) + L2 nFAPI Simulator (with S1 / 2-host deployment) @@ -21,25 +21,24 @@ 5. [Setup of the Configuration files](#5-setup-of-the-configuration-files) 1. [The eNB Configuration file](#51-the-enb-configuration-file) 2. [The UE Configuration file](#52-the-ue-configuration-file) -6. [Bring Up a second loopback interface](#6-bring-up-a-second-loopback-interface) -7. [Build the eNB](#7-build-the-enb) -8. [Build the UE](#8-build-the-ue) -9. [Initialize the NAS UE Layer](#9-initialize-the-nas-ue-layer) -10. [Start the eNB](#10-start-the-enb) -11. [Start the UE](#11-start-the-ue) -12. [Test with ping](#12-test-with-ping) -13. [Limitations](#13-limitations) +6. [Build OAI UE and eNodeB](#6-build-oai-ue-and-enodeb) +7. [Start EPC](#7-start-epc) +8. [Start the eNB](#8-start-the-enb) +9. [Start the UE](#9-start-the-ue) +10. [Test with ping](#10-test-with-ping) +11. [Limitations](#11-limitations) # 1. Environment # -2 servers are used in this deployment. You can use Virtual Machines instead of each server; like it is done in the CI process. +3 servers are used in this deployment. You can use Virtual Machines instead of each server; like it is done in the CI process. * Machine A contains the EPC. -* Machine B contains the OAI eNB and the OAI UE(s) +* Machine B contains the OAI eNB executable (`lte-softmodem`) +* Machine C contains the OAI UE(s) executable (`lte-uesoftmodem`) Example of L2 nFAPI Simulator testing environment: - + Note that the IP addresses are indicative and need to be adapted to your environment. @@ -47,26 +46,35 @@ Note that the IP addresses are indicative and need to be adapted to your environ Create the environment for the EPC and register all **USIM** information into the **HSS** database. -If you are using OAI-EPC ([see on GitHub](https://github.com/OPENAIRINTERFACE/openair-cn)), build **HSS/MME/SPGW** and create config files. +If you are using OAI-EPC ([see on GitHub](https://github.com/OPENAIRINTERFACE/openair-epc-fed)), build **HSS/MME/SPGW** and create config files. # 3. Retrieve the OAI eNB-UE source code # -The eNB and the UE executables will compiled into 2 separate folders on the same machine `B`. +At the time of writing, the tag used in the `develop` branch to do this documentation was `2020.w16`. + +The tutorial should be valid for the `master` branch tags such as `v1.2.0` or `v1.2.1`. But you may face issues that could be fixed in newer `develop` tags. + +Please try to use the same commit ID on both eNB/UE hosts. ```bash $ ssh sudousername@machineB -$ git clone https://gitlab.eurecom.fr/oai/openairinterface5g/ enb_folder -$ cd enb_folder -$ git checkout -f v1.0.0 -$ cd .. -$ cp -Rf enb_folder ue_folder +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git enb_folder +cd enb_folder +git checkout develop +``` + +```bash +$ ssh sudousername@machineC +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ue_folder +cd ue_folder +git checkout develop ``` # 4. Setup of the USIM information in UE folder # ```bash -$ ssh sudousername@machineB -$ cd ue_folder +$ ssh sudousername@machineC +cd ue_folder # Edit openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf with your preferred editor ``` @@ -126,19 +134,19 @@ You can repeat the operation for as many users you want to test with. ```bash $ ssh sudousername@machineB -$ cd enb_folder +cd enb_folder # Edit ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf with your preferred editor ``` -First verify the nFAPI interface setup on the 2nd loopback interface. +First verify the nFAPI interface setup on the physical ethernet interface of machineB and put the proper IP addresses for both hosts. ``` MACRLCs = ( { num_cc = 1; - local_s_if_name = "lo:"; // <-- HERE - remote_s_address = "127.0.0.1"; // <-- HERE - local_s_address = "127.0.0.2"; // <-- HERE + local_s_if_name = "ens3"; // <-- HERE + remote_s_address = "192.168.122.169"; // <-- HERE + local_s_address = "192.168.122.31"; // <-- HERE local_s_portc = 50001; remote_s_portc = 50000; local_s_portd = 50011; @@ -171,7 +179,7 @@ Last, the S1 interface shall be properly set. ``` ////////// MME parameters: - mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; // replace with 192.168.10.20 + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; // replace with 192.168.122.195 ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; @@ -181,11 +189,11 @@ Last, the S1 interface shall be properly set. NETWORK_INTERFACES : { ENB_INTERFACE_NAME_FOR_S1_MME = "ens3"; // replace with the proper interface name - ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; // replace with 192.168.10.10 + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; // replace with 192.168.122.31 ENB_INTERFACE_NAME_FOR_S1U = "ens3"; // replace with the proper interface name - ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; // replace with 192.168.10.10 + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; // replace with 192.168.122.31 ENB_PORT_FOR_S1U = 2152; # Spec 2152 - ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; // replace with 192.168.10.10 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; // replace with 192.168.122.31 ENB_PORT_FOR_X2C = 36422; # Spec 36422 }; @@ -195,7 +203,7 @@ Last, the S1 interface shall be properly set. ```bash $ ssh sudousername@machineB -$ cd ue_folder +cd ue_folder # Edit ci-scripts/conf_files/ue.nfapi.conf with your preferred editor ``` @@ -206,9 +214,9 @@ L1s = ( { num_cc = 1; tr_n_preference = "nfapi"; - local_n_if_name = "lo"; // <- HERE - remote_n_address = "127.0.0.2"; // <- HERE - local_n_address = "127.0.0.1"; // <- HERE + local_n_if_name = "ens3"; // <- HERE + remote_n_address = "192.168.122.31"; // <- HERE + local_n_address = "192.168.122.169"; // <- HERE local_n_portc = 50000; remote_n_portc = 50001; local_n_portd = 50010; @@ -217,20 +225,11 @@ L1s = ( ); ``` -# 6. Bring Up a second loopback interface # +# 6. Build OAI UE and eNodeB # -A second loopback interface is used to connect the eNB and the UEs. +See [Build documentation](./BUILD.md). -```bash -$ ssh sudousername@machineB -$ sudo ifconfig lo: 127.0.0.2 netmask 255.0.0.0 up -``` - -# 7. [Build OAI UE and eNodeB](BUILD.md) # - - - -# 8. Initialize the NAS UE Layer # +# 7. Start EPC # Start the EPC on machine `A`. @@ -239,61 +238,89 @@ $ ssh sudousername@machineA # Start the EPC ``` -# 9. Start the eNB # +# 8. Start the eNB # In the first terminal (the one you used to build the eNB): ```bash $ ssh sudousername@machineB -$ cd enb_folder/cmake_targets -$ sudo -E ./ran_build/build/lte-softmodem -O ../ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf > enb.log 2>&1 +cd enb_folder/cmake_targets +sudo -E ./ran_build/build/lte-softmodem -O ../ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf > enb.log 2>&1 ``` If you don't use redirection, you can test but many logs are printed on the console and this may affect performance of the L2-nFAPI simulator. We do recommend the redirection in steady mode once your setup is correct. -# 10. Start the UE # +# 9. Start the UE # In the second terminal (the one you used to build the UE): ```bash -$ ssh sudousername@machineB -$ cd ue_folder/cmake_targets -# Test 64 UEs, 64 threads in FDD mode -$ sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --L2-emul 3 --num-ues 64 --nums-ue-thread 64 > ue.log 2>&1 -# Test 64 UEs, 64 threads in TDD mode -$ sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --L2-emul 3 --num-ues 64 --nums-ue-thread 64 -T 1 > ue.log 2>&1 +$ ssh sudousername@machineC +cd ue_folder/cmake_targets +# Test 64 UEs, 1 thread in FDD mode +sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --L2-emul 3 --num-ues 64 --nums_ue_thread 1 --nokrnmod 1 > ue.log 2>&1 +# Test 64 UEs, 1 thread in TDD mode +sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --L2-emul 3 --num-ues 64 --nums_ue_thread 1 --nokrnmod 1 -T 1 > ue.log 2>&1 # The "-T 1" option means TDD config ``` - The number of UEs can set by using `--num-ues` option and the maximum UE number is 255 (with the `--mu*` options, otherwise 16). -- The umber of threads can set with the `--nums-ue-thread`. This number **SHALL NOT** be greater than the number of UEs. +- The number of threads can set with the `--nums-ue-thread`. This number **SHALL NOT** be greater than the number of UEs. + * At the time of writing, it seems to be enough to run on a single thread. +- The `--nokrnmod 1` option makes use of the preferred and supported tunnel interface. - How many UE that can be tested depends on hardware (server , PC, etc) performance in your environment. -# 11. Test with ping # +For example, running with 4 UEs: -In a third terminal, after around 10 seconds, the UE(s) shall be connected to the eNB: +```bash +$ ssh sudousername@machineC +cd ue_folder/cmake_targets +sudo -E ./ran_build/build/lte-uesoftmodem -O ../ci-scripts/conf_files/ue.nfapi.conf --L2-emul 3 --num-ues 64 --nums_ue_thread 1 --nokrnmod 1 > ue.log 2>&1 +sleep 10 +ifconfig +ens3 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX + inet addr:192.168.122.169 Bcast:192.168.122.255 Mask:255.255.255.0 +.... +oaitun_ue1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:192.172.0.2 P-t-P:192.172.0.2 Mask:255.255.255.0 +.... +oaitun_ue2 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:192.172.0.3 P-t-P:192.172.0.3 Mask:255.255.255.0 +.... +oaitun_ue3 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:192.172.0.4 P-t-P:192.172.0.4 Mask:255.255.255.0 +.... +oaitun_ue4 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:192.172.0.5 P-t-P:192.172.0.5 Mask:255.255.255.0 +.... +oaitun_uem1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.0.2.2 P-t-P:10.0.2.2 Mask:255.255.255.0 +.... +.... +``` + +Having the 4 oaitun_ue tunnel interfaces up and with an allocated address means the connection with EPC went alright. + +# 10. Test with ping # + +In a third terminal, after around 10 seconds, the UE(s) shall be connected to the eNB: Check with ifconfig ```bash $ ssh sudousername@machineA -# Ping UE0 IP address based on the EPC pool used: in this example: -$ ping -c 20 192.168.200.2 # Ping UE1 IP address based on the EPC pool used: in this example: -$ ping -c 20 192.168.200.4 +$ ping -c 20 192.172.0.2 +# Ping UE4 IP address based on the EPC pool used: in this example: +$ ping -c 20 192.172.0.5 ``` -# 12. Limitations # - -Testing on the CI process is currently limited at time of writing. Improvements will be made soon. - - - - - +iperf operations can also be performed. +# 11. Limitations # +---- [oai wiki home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/doc/images/L2-sim-S1-3-host-deployment.png b/doc/images/L2-sim-S1-3-host-deployment.png new file mode 100644 index 0000000000000000000000000000000000000000..4049ebd7a8ace60df576a988f32442526af7f13e GIT binary patch literal 88726 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 literal 0 HcmV?d00001 diff --git a/doc/images/L2-sim-noS1-2-host-deployment.png b/doc/images/L2-sim-noS1-2-host-deployment.png new file mode 100644 index 0000000000000000000000000000000000000000..02d29b7b3cdfb05dc912548e001fb11aa1d96fc8 GIT binary patch literal 57368 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

7PsQt@ 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 literal 0 HcmV?d00001 From a0cf40774264ad2f9c4c0c69efdb391aa373be5a Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 22 Apr 2020 17:26:34 +0200 Subject: [PATCH 151/175] CI: final fixes on help functions Signed-off-by: Raphael Defosseux --- ci-scripts/constants.py | 2 +- ci-scripts/epc.py | 6 +- ci-scripts/html.py | 4 +- ci-scripts/main.py | 162 ++++++++++-------- ci-scripts/ran.py | 10 +- .../enb_usrp210_band40_test_05mhz_tm2.xml | 2 +- 6 files changed, 98 insertions(+), 88 deletions(-) diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py index ca3cde446d..1e7e84fb32 100644 --- a/ci-scripts/constants.py +++ b/ci-scripts/constants.py @@ -31,7 +31,7 @@ #----------------------------------------------------------- # Version #----------------------------------------------------------- -Version = '0.1' +Version = '0.2' #----------------------------------------------------------- # Constants diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index e67de43b09..4926f2d6e8 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -96,7 +96,7 @@ class EPCManagement(): def InitializeHSS(self): if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '': - HELP.GenericHelp(Version) + HELP.GenericHelp(CONST.Version) HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type) sys.exit('Insufficient EPC Parameters') mySSH = SSH.SSHConnection() @@ -134,7 +134,7 @@ class EPCManagement(): def InitializeMME(self): if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '': - HELP.GenericHelp(Version) + HELP.GenericHelp(CONST.Version) HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type) sys.exit('Insufficient EPC Parameters') mySSH = SSH.SSHConnection() @@ -168,7 +168,7 @@ class EPCManagement(): def InitializeSPGW(self): if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '': - HELP.GenericHelp(Version) + HELP.GenericHelp(CONST.Version) HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type) sys.exit('Insufficient EPC Parameters') mySSH = SSH.SSHConnection() diff --git a/ci-scripts/html.py b/ci-scripts/html.py index 67deaa75ce..3d0c8f3897 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -363,8 +363,8 @@ class HTMLManagement(): def CreateHtmlRetrySeparator(self, cntnumfails): if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): self.htmlFile = open('test_results.html', 'a') - self.htmlFile.write(' \n') - self.htmlFile.write(' Try Run #' + str(cntnumfails) + '\n') + self.htmlFile.write(' \n') + self.htmlFile.write(' ---- Try Run #' + str(cntnumfails) + ' ---- \n') self.htmlFile.write(' \n') self.htmlFile.close() diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 837c592bd7..1e149c4050 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -30,11 +30,6 @@ import constants as CONST -#----------------------------------------------------------- -# Version -#----------------------------------------------------------- -Version = '0.1' - #----------------------------------------------------------- # Import #----------------------------------------------------------- @@ -61,6 +56,12 @@ logging.basicConfig( class OaiCiTest(): def __init__(self): + self.ranRepository = '' + self.ranBranch = '' + self.ranCommitID = '' + self.ranAllowMerge = False + self.ranTargetBranch = '' + self.FailReportCnt = 0 self.ADBIPAddress = '' self.ADBUserName = '' @@ -105,8 +106,8 @@ class OaiCiTest(): self.expectedNbOfConnectedUEs = 0 def BuildOAIUE(self): - if self.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - GenericHelp(Version) + if self.UEIPAddress == '' or self.ranRepository == '' or self.ranBranch == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) result = re.search('--nrUE', self.Build_OAI_UE_args) @@ -116,11 +117,11 @@ class OaiCiTest(): else: RAN.Setair_interface('lte') ue_prefix = '' - result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', RAN.GetranRepository()) + result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) if result is not None: - full_ran_repo_name = RAN.GetranRepository() + full_ran_repo_name = self.ranRepository else: - full_ran_repo_name = RAN.GetranRepository() + '.git' + full_ran_repo_name = self.ranRepository + '.git' SSH.command('mkdir -p ' + self.UESourceCodePath, '\$', 5) SSH.command('cd ' + self.UESourceCodePath, '\$', 5) SSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600) @@ -133,19 +134,19 @@ class OaiCiTest(): if result is not None: mismatch = False SSH.command('grep SRC_COMMIT LAST_BUILD_INFO.txt', '\$', 2) - result = re.search(RAN.GetranCommitID(), SSH.getBefore()) + result = re.search(self.ranCommitID, SSH.getBefore()) if result is None: mismatch = True SSH.command('grep MERGED_W_TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge()): + if self.ranAllowMerge: result = re.search('YES', SSH.getBefore()) if result is None: mismatch = True SSH.command('grep TGT_BRANCH LAST_BUILD_INFO.txt', '\$', 2) - if RAN.GetranTargetBranch() == '': + if self.ranTargetBranch == '': result = re.search('develop', SSH.getBefore()) else: - result = re.search(RAN.GetranTargetBranch(), SSH.getBefore()) + result = re.search(self.ranTargetBranch, SSH.getBefore()) if result is None: mismatch = True else: @@ -160,17 +161,17 @@ class OaiCiTest(): SSH.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) # if the commit ID is provided use it to point to it - if RAN.GetranCommitID() != '': - SSH.command('git checkout -f ' + RAN.GetranCommitID(), '\$', 5) + if self.ranCommitID != '': + SSH.command('git checkout -f ' + self.ranCommitID, '\$', 5) # if the branch is not develop, then it is a merge request and we need to do # the potential merge. Note that merge conflicts should already been checked earlier - if (RAN.GetranAllowMerge()): - if RAN.GetranTargetBranch() == '': - if (RAN.GetranBranch() != 'develop') and (RAN.GetranBranch() != 'origin/develop'): + if self.ranAllowMerge: + if self.ranTargetBranch == '': + if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'): SSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5) else: - logging.debug('Merging with the target branch: ' + RAN.GetranTargetBranch()) - SSH.command('git merge --ff origin/' + RAN.GetranTargetBranch() + ' -m "Temporary merge for CI"', '\$', 5) + logging.debug('Merging with the target branch: ' + self.ranTargetBranch) + SSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) SSH.command('source oaienv', '\$', 5) SSH.command('cd cmake_targets', '\$', 5) SSH.command('mkdir -p log', '\$', 5) @@ -188,14 +189,14 @@ class OaiCiTest(): SSH.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) if buildStatus: # Generating a BUILD INFO file - SSH.command('echo "SRC_BRANCH: ' + RAN.GetranBranch() + '" > ../LAST_BUILD_INFO.txt', '\$', 2) - SSH.command('echo "SRC_COMMIT: ' + RAN.GetranCommitID() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if (RAN.GetranAllowMerge()): + SSH.command('echo "SRC_BRANCH: ' + self.ranBranch + '" > ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "SRC_COMMIT: ' + self.ranCommitID + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + if self.ranAllowMerge: SSH.command('echo "MERGED_W_TGT_BRANCH: YES" >> ../LAST_BUILD_INFO.txt', '\$', 2) - if RAN.GetranTargetBranch() == '': + if self.ranTargetBranch == '': SSH.command('echo "TGT_BRANCH: develop" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: - SSH.command('echo "TGT_BRANCH: ' + RAN.GetranTargetBranch() + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) + SSH.command('echo "TGT_BRANCH: ' + self.ranTargetBranch + '" >> ../LAST_BUILD_INFO.txt', '\$', 2) else: SSH.command('echo "MERGED_W_TGT_BRANCH: NO" >> ../LAST_BUILD_INFO.txt', '\$', 2) SSH.close() @@ -222,7 +223,7 @@ class OaiCiTest(): if RAN.GetflexranCtrlInstalled() == False: return if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('cd /opt/flexran_rtc', '\$', 5) @@ -287,7 +288,7 @@ class OaiCiTest(): def InitializeUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') multi_jobs = [] i = 0 @@ -303,7 +304,7 @@ class OaiCiTest(): def InitializeOAIUE(self): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') if RAN.Getair_interface() == 'lte': result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) @@ -501,7 +502,7 @@ class OaiCiTest(): def InitializeCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.enablePicocomClosure() SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -540,7 +541,7 @@ class OaiCiTest(): def TerminateCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.enablePicocomClosure() SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -561,7 +562,7 @@ class OaiCiTest(): def AttachCatM(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.enablePicocomClosure() SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -635,7 +636,7 @@ class OaiCiTest(): def PingCatM(self): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -801,7 +802,7 @@ class OaiCiTest(): def AttachUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -875,7 +876,7 @@ class OaiCiTest(): def DetachUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -946,7 +947,7 @@ class OaiCiTest(): def RebootUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -980,7 +981,7 @@ class OaiCiTest(): def DataDisableUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') multi_jobs = [] i = 0 @@ -1009,7 +1010,7 @@ class OaiCiTest(): def DataEnableUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') multi_jobs = [] i = 0 @@ -1025,7 +1026,7 @@ class OaiCiTest(): def GetAllUEDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: @@ -1069,7 +1070,7 @@ class OaiCiTest(): def GetAllCatMDevices(self, terminate_ue_flag): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: @@ -1141,7 +1142,7 @@ class OaiCiTest(): def CheckStatusUE(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = False @@ -1205,13 +1206,13 @@ class OaiCiTest(): def GetAllUEIPAddresses(self): if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') ue_ip_status = 0 self.UEIPAddresses = [] if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword) SSH.command('ifconfig oaitun_ue1', '\$', 4) @@ -1373,11 +1374,11 @@ class OaiCiTest(): ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args)) if ping_from_eNB is not None: if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') else: if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') try: if ping_from_eNB is not None: @@ -1460,7 +1461,7 @@ class OaiCiTest(): self.PingNoS1() return if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): @@ -2087,7 +2088,7 @@ class OaiCiTest(): def IperfNoS1(self): if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True check_OAI_UE = True @@ -2200,7 +2201,7 @@ class OaiCiTest(): self.IperfNoS1() return if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') check_eNB = True if (len(self.UEDevices) == 1) and (self.UEDevices[0] == 'OAI-UE'): @@ -2625,7 +2626,7 @@ class OaiCiTest(): if RAN.GetflexranCtrlInstalled() == False or RAN.GetflexranCtrlStarted() == False: return if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') SSH.open(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword()) SSH.command('echo ' + EPC.GetPassword() + ' | sudo -S daemon --name=flexran_rtc_daemon --stop', '\$', 5) @@ -2737,18 +2738,21 @@ class OaiCiTest(): self.testCase_id = 'AUTO-KILL-UE' HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of UE' + HTML.Setdesc('Automatic Termination of UE') self.ShowTestID() self.TerminateUE() if (self.Initialize_OAI_UE_args != ''): - self.testCase_id = 'AUTO-KILL-UE' + self.testCase_id = 'AUTO-KILL-OAI-UE' HTML.SettestCase_id(self.testCase_id) - self.desc = 'Automatic Termination of UE' + self.desc = 'Automatic Termination of OAI-UE' + HTML.Setdesc('Automatic Termination of OAI-UE') self.ShowTestID() self.TerminateOAIUE() if (RAN.GetInitialize_eNB_args() != ''): self.testCase_id = 'AUTO-KILL-eNB' HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of eNB' + HTML.Setdesc('Automatic Termination of eNB') self.ShowTestID() RAN.SeteNB_instance('0') RAN.TerminateeNB() @@ -2756,6 +2760,7 @@ class OaiCiTest(): self.testCase_id = 'AUTO-KILL-flexran-ctl' HTML.SettestCase_id(self.testCase_id) self.desc = 'Automatic Termination of FlexRan CTL' + HTML.Setdesc('Automatic Termination of FlexRan CTL') self.ShowTestID() self.TerminateFlexranCtrl() RAN.SetprematureExit(True) @@ -3189,7 +3194,7 @@ CiTestObj = OaiCiTest() import sshconnection import epc -import helpreadme +import helpreadme as HELP import ran import html import constants @@ -3211,7 +3216,7 @@ while len(argvs) > 1: myArgv = argvs.pop(1) # 0th is this file's name if re.match('^\-\-help$', myArgv, re.IGNORECASE): - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit(0) elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) @@ -3221,6 +3226,7 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBRepository=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranRepository=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.ranRepository = matchReg.group(1) RAN.SetranRepository(matchReg.group(1)) HTML.SetranRepository(matchReg.group(1)) elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): @@ -3230,6 +3236,7 @@ while len(argvs) > 1: matchReg = re.match('^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE) doMerge = matchReg.group(1) if ((doMerge == 'true') or (doMerge == 'True')): + CiTestObj.ranAllowMerge = True RAN.SetranAllowMerge(True) HTML.SetranAllowMerge(True) elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): @@ -3237,6 +3244,7 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE) + CiTestObj.ranBranch = matchReg.group(1) RAN.SetranBranch(matchReg.group(1)) HTML.SetranBranch(matchReg.group(1)) elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): @@ -3244,6 +3252,7 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE) + CiTestObj.ranCommitID = matchReg.group(1) RAN.SetranCommitID(matchReg.group(1)) HTML.SetranCommitID(matchReg.group(1)) elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): @@ -3251,6 +3260,7 @@ while len(argvs) > 1: matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE) else: matchReg = re.match('^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE) + CiTestObj.ranTargetBranch = matchReg.group(1) RAN.SetranTargetBranch(matchReg.group(1)) HTML.SetranTargetBranch(matchReg.group(1)) elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): @@ -3352,12 +3362,12 @@ while len(argvs) > 1: if ((finalStatus == 'true') or (finalStatus == 'True')): CiTestObj.finalStatus = True else: - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Invalid Parameter: ' + myArgv) if re.match('^TerminateeNB$', mode, re.IGNORECASE): if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') RAN.SeteNB_serverId('0') RAN.SeteNB_instance('0') @@ -3365,74 +3375,74 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE): RAN.TerminateeNB() elif re.match('^TerminateUE$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') signal.signal(signal.SIGUSR1, receive_signal) CiTestObj.TerminateUE() elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE): if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') signal.signal(signal.SIGUSR1, receive_signal) CiTestObj.TerminateOAIUE() elif re.match('^TerminateHSS$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') EPC.TerminateHSS() elif re.match('^TerminateMME$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') EPC.TerminateMME() elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') EPC.TerminateSPGW() elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): if (RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''): - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectBuild() elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') RAN.LogCollecteNB() elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') EPC.LogCollectHSS() elif re.match('^LogCollectMME$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') EPC.LogCollectMME() elif re.match('^LogCollectSPGW$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') EPC.LogCollectSPGW() elif re.match('^LogCollectPing$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectPing() elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectIperf() elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): if CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') CiTestObj.LogCollectOAIUE() elif re.match('^InitiateHtml$', mode, re.IGNORECASE): if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''): - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') count = 0 foundCount = 0 @@ -3472,21 +3482,21 @@ elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): if RAN.GeteNBIPAddress() == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '' or EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetType() == '' or EPC.GetSourceCodePath() == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) if EPC.GetIPAddress() == '' or EPC.GetUserName() == '' or EPC.GetPassword() == '' or EPC.GetSourceCodePath() == '' or EPC.GetType() == '': - EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) + HELP.EPCSrvHelp(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), EPC.GetSourceCodePath(), EPC.GetType()) if RAN.GetranRepository() == '': - GitSrvHelp(RAN.GetranRepository(),RAN.GetranBranch(),RAN.GetranCommitID(),RAN.GetranAllowMerge(),RAN.GetranTargetBranch()) + HELP.GitSrvHelp(RAN.GetranRepository(), RAN.GetranBranch(), RAN.GetranCommitID(), RAN.GetranAllowMerge(), RAN.GetranTargetBranch()) if RAN.GeteNBIPAddress() == '' or RAN.GeteNBUserName() == '' or RAN.GeteNBPassword() == '' or RAN.GeteNBSourceCodePath() == '': - eNBSrvHelp(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath()) + HELP.eNBSrvHelp(RAN.GeteNBIPAddress(), RAN.GeteNBUserName(), RAN.GeteNBPassword(), RAN.GeteNBSourceCodePath()) sys.exit('Insufficient Parameter') if (EPC.GetIPAddress() != '') and (EPC.GetIPAddress() != 'none'): SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/tcp_iperf_stats.awk", "/tmp") SSH.copyout(EPC.GetIPAddress(), EPC.GetUserName(), EPC.GetPassword(), cwd + "/active_net_interfaces.awk", "/tmp") else: - if CiTestObj.UEIPAddress == '' or RAN.GetranRepository() == '' or RAN.GetranBranch() == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': - GenericHelp(Version) + if CiTestObj.UEIPAddress == '' or CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == '': + HELP.GenericHelp(CONST.Version) sys.exit('UE: Insufficient Parameter') #read test_case_list.xml file @@ -3663,6 +3673,6 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)') HTML.CreateHtmlTabFooter(True) else: - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Invalid mode') sys.exit(0) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index c65c21c252..350098e66e 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -232,7 +232,7 @@ class RANManagement(): def BuildeNB(self): if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') if self.eNB_serverId == '0': lIpAddr = self.eNBIPAddress @@ -250,7 +250,7 @@ class RANManagement(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) @@ -359,7 +359,7 @@ class RANManagement(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) @@ -454,7 +454,7 @@ class RANManagement(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') if self.htmlObj is not None: @@ -679,7 +679,7 @@ class RANManagement(): lPassWord = self.eNB2Password lSourcePath = self.eNB2SourceCodePath if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - GenericHelp(Version) + HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) diff --git a/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml b/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml index 2a035396c5..09aa0b04a2 100644 --- a/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml +++ b/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml @@ -25,7 +25,7 @@ test-05-tm2 Test-05MHz-TM2 tasks - 3 + 2 030201 040101 From 6d8aa8d6b92b6a0d89f03e81bf49f3e350757c7b Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 23 Apr 2020 01:17:11 +0200 Subject: [PATCH 152/175] added 3-bit payload for pucch0 to nr_pucchsim, fixed SNR scaling for pucch2 --- openair1/SIMULATION/NR_PHY/pucchsim.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 9e1609c3b4..d36f42f6c6 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -104,6 +104,7 @@ int main(int argc, char **argv) NR_DL_FRAME_PARMS *frame_parms; //unsigned char frame_type = 0; int loglvl=OAILOG_WARNING; + int sr_flag = 0; cpuf = get_cpu_freq_GHz(); @@ -114,7 +115,7 @@ int main(int argc, char **argv) randominit(0); logInit(); - while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:")) != -1) { + while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:c")) != -1) { switch (c) { case 'f': //write_output_file=1; @@ -275,6 +276,9 @@ int main(int argc, char **argv) case 'b': nr_bit=atoi(optarg); break; + case 'c': + sr_flag=1; + break; case 'B': actual_payload=atoi(optarg); break; @@ -455,10 +459,13 @@ int main(int argc, char **argv) uint32_t dmrs_scrambling_id = 0, data_scrambling_id=0; if(format==0){ // for now we are not considering SR just HARQ-ACK - if(nr_bit==1) + if (nr_bit ==0) + mcs=table1_mcs[0]; + else if(nr_bit==1) mcs=table1_mcs[actual_payload]; else if(nr_bit==2) mcs=table2_mcs[actual_payload]; + else AssertFatal(1==0,"Either nr_bit %d or sr_flag %d must be non-zero\n"); } for(SNR=snr0;SNR<=snr1;SNR=SNR+1){ @@ -480,8 +487,9 @@ int main(int argc, char **argv) frame_parms->ofdm_symbol_size); // printf("txlev %d (%d dB), offset %d\n",txlev,dB_fixed(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size); - // note : this scaling is for 1 PRB, to be updated for PUCCH 2 - sigma2_dB = 10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12)-SNR; + // note : this scaling + int nb_re = (format == 0 || format == 1)? 12 : 12*nrofPRB; + sigma2_dB = 10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/nb_re)-SNR; sigma2 = pow(10,sigma2_dB/10); for(i=startingSymbolIndex*frame_parms->ofdm_symbol_size; i<(startingSymbolIndex+1)*frame_parms->ofdm_symbol_size; i++) { @@ -498,7 +506,7 @@ int main(int argc, char **argv) pucch_pdu.group_hop_flag = PUCCH_GroupHopping&1; pucch_pdu.sequence_hop_flag = (PUCCH_GroupHopping>>1)&1; pucch_pdu.bit_len_harq = nr_bit; - pucch_pdu.sr_flag = 0; + pucch_pdu.sr_flag = sr_flag; pucch_pdu.nr_of_symbols = nrofSymbols; pucch_pdu.hopping_id = hopping_id; pucch_pdu.initial_cyclic_shift = 0; From 0d1edf6c477367415d9a8fd2e43f72f73ac6d676 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 23 Apr 2020 11:30:48 +0200 Subject: [PATCH 153/175] CI: add missing import Signed-off-by: Raphael Defosseux --- ci-scripts/sshconnection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index 649ffef26c..68a1d7836c 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -35,6 +35,7 @@ import pexpect # pexpect import logging import time # sleep import re +import sys #----------------------------------------------------------- # Class Declaration From 381f44843d32a9ad6e84d8ca13a7de4f9fa13546 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 23 Apr 2020 11:39:15 +0200 Subject: [PATCH 154/175] DOC: fix some formatting issues Signed-off-by: Raphael Defosseux --- doc/SystemX-tutorial-design.md | 71 +++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/doc/SystemX-tutorial-design.md b/doc/SystemX-tutorial-design.md index 371cb33a75..3e4496f7de 100644 --- a/doc/SystemX-tutorial-design.md +++ b/doc/SystemX-tutorial-design.md @@ -1,10 +1,10 @@ # OpenAirInterface for SystemX -#Terminology +# Terminology ****This document use the 5G terminology**** -**Central Unit (CU): **It is a logical node that includes the gNB +**Central Unit (CU):** It is a logical node that includes the gNB functions like Transfer of user data, Mobility control, Radio access network sharing, Positioning, Session Management etc., except those functions allocated exclusively to the DU. CU controls the operation of @@ -19,7 +19,9 @@ names like RRH/RRU/RE/RU/PNF. In OpenAir code, the terminology is often RU and BBU. # OpenAirUsage -##EPC and general environment + +## EPC and general environment + ### OAI EPC Use the stable OAI EPC, that can run in one machine (VM or standalone) @@ -27,9 +29,10 @@ Use the stable OAI EPC, that can run in one machine (VM or standalone) Draft description: -##Standalone 4G +## Standalone 4G EPC+eNB on one machine, the UE can be commercial or OAI UE. + ### USRP B210 Main current issue: traffic is good only on coaxial link between UE and @@ -55,7 +58,8 @@ the same IP tunnel end point as the UE. So, we have to create a network namespace for the UE and to route data in/out of the namespace. -``` bash + +```bash ip netns delete aNameSpace 2> /dev/null ip link delete v-eth1 2> /dev/null @@ -70,7 +74,7 @@ ip addr add 10.200.1.1/24 dev v-eth1 ip link set v-eth1 up -iptables -t nat -A POSTROUTING -s 10.200.1.0/255.255.255.0 -o enp0s31f6 +iptables -t nat -A POSTROUTING -s 10.200.1.0/255.255.255.0 -o enp0s31f6 \ -j MASQUERADE iptables -A FORWARD -i enp0s31f6 -o v-eth1 -j ACCEPT @@ -92,13 +96,15 @@ to run the UE. To make user plan traffic, the traffic generator has to run in the same namespace -`ip netns exec aNameSpace bash -` +```bash +ip netns exec aNameSpace bash +``` The traffic genenrator has to specify the interface: -`route add default oaitun_ue1 -` +```bash +route add default oaitun_ue1 +``` or specify the outgoing route in the traffic generator (like option “-I” in ping command). @@ -111,6 +117,7 @@ is this work the downlink “functional split 6”. The customer required after signature to develop also the uplink functional split 6. This is accepted, as long as the whole work is research with no delivery completeness warranty. + ### Simulation To be able to verify the new features and to help in all future @@ -119,11 +126,12 @@ during this contract. We added the channel modeling simulation, that offer to simulate various 3GPP defined channels. + ### Main loop The main log is in RF simulator is in - targets/RT/USER/lte-ru.c and targets/RT/USER/lte-enb.c + `targets/RT/USER/lte-ru.c and targets/RT/USER/lte-enb.c` As this piece of SW is very complex and doesn’t meet our goals (functional split 6), a cleaned version replaces these 2 files in @@ -142,8 +150,8 @@ The reworked main loop take care of a uniq variable that comes directly from har To use OAI, we need to set all OAI variables that derivates from this timestamp value. The function setAllfromTS() implements this. - ### Splitted main level + When FS6 is actived, a main loop for DU (du_fs6()) a main loop for CU case replaces the uniq eNB main loop. Each of these main loops calls initialization of OAI LTE data and the FS6 transport layer initialization. @@ -262,29 +270,36 @@ The end line option “--split73” enables the fs6 (also called split 7.3) mode Example: +```bash ./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 cu:127.0.0.1 -` +``` + Run the CU init of the split 6 eNB, that will call du on 127.0.0.1 address +```bash ./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 du:127.0.0.1 +``` will run the du, calling the cu on 127.0.0.1 -` + If the CU and the DU are not on the same machine, the remote address of each side need to be specified as per this example +```bash ./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 du:192.168.1.55 -` +``` + runs the functional split 6 DU -`./lte-uesoftmodem -C 2685000000 -r 50 --rfsim --rfsimulator.serveraddr 192.168.1.1 -d -` +```bash +./lte-uesoftmodem -C 2685000000 -r 50 --rfsim --rfsimulator.serveraddr 192.168.1.1 -d +``` Runs the UE (to have the UE signal scope, compile it with make uescope) -CU+DU+UE can run with option --noS1 to avoid to use a EPC and/or with --rfsim to simulate RF board +CU+DU+UE can run with option `--noS1` to avoid to use a EPC and/or with `--rfsim` to simulate RF board -##5G and F1 +## 5G and F1 Today 5G achievement is limited to physical layer. @@ -305,13 +320,17 @@ frames). Usage with RFsimulator: -gNB +**gNB** -`sudo RFSIMULATOR=server ./nr-softmodem -O -../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf ---parallel-config PARALLEL\_SINGLE\_THREAD` +```bash +sudo RFSIMULATOR=server ./nr-softmodem -O \ +../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf \ +--parallel-config PARALLEL\_SINGLE\_THREAD +``` -nrUE +**nrUE** -`sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C -3510000000 -d` +```bash +sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C \ +3510000000 -d +``` From 591b45d29f85ffb19b6cefa9d0f3e3c40c548ffd Mon Sep 17 00:00:00 2001 From: Javier Morgade Date: Thu, 23 Apr 2020 11:45:07 +0200 Subject: [PATCH 155/175] Configure right lcid range at MBMS config file Now is aligned with RMSIMULATOR config file (this should solve CI issues with monolithic tests) --- ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf index fbb8c5d6f8..de58950df4 100644 --- a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf +++ b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf @@ -288,7 +288,7 @@ MCEs = ( mnc_length = 2; } service_id=0; - lcid=8; #this must be properly defined lcid:8+service:0 -> rab_id:8 + lcid=5; #this must be properly defined lcid:8+service:0 -> rab_id:5 } ); } From e957d9cb49cecb9cc713ffe72d835b897a7e354a Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 23 Apr 2020 16:37:11 +0200 Subject: [PATCH 156/175] DOC: put correct license Signed-off-by: Raphael Defosseux --- executables/nr-ru.c | 57 ++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index a6970973a6..f947395f4a 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1,41 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ - -/*! \file lte-enb.c - * \brief Top-level threads for eNodeB - * \author R. Knopp, F. Kaltenberger, Navid Nikaein - * \date 2012 - * \version 0.1 - * \company Eurecom - * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr - * \note - * \warning +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org */ + #define _GNU_SOURCE #include #include From ddf947100254d5010d028f5613c71904264f3195 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 23 Apr 2020 16:40:52 +0200 Subject: [PATCH 157/175] DOC: license for all LFDS versions updated Signed-off-by: Raphael Defosseux --- NOTICE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE.md b/NOTICE.md index 65c6105660..96b5d4c552 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -4,7 +4,7 @@ For more details of the license, refer to [LICENSE](LICENSE) file in the same di However, the source code also contains third party software that is acknowledged here for reference. -## Credits for LFDS user space source code located in folder openair2/UTILS/LFDS/liblfds6.1.1/ ## +## Credits for LFDS user space source code located in folder openair2/UTILS/LFDS/ ## See on [liblfds website](https://liblfds.org/) the license section. From d7d196c280af839100d9fa66ef6d5db6389f1f51 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 23 Apr 2020 22:27:28 +0200 Subject: [PATCH 158/175] CI tests for nr_pucchsim : added PUCCH format 2 tests --- cmake_targets/autotests/test_case_list.xml | 28 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 085e5fb07b..7eed0ae8a1 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1177,17 +1177,37 @@ execution nr_pucchsim Test cases. (Test1: Format 0 1-bit ACK miss 106 PRB), - (Test2: Format 0 2-bit ACK miss 106 PRB) + (Test2: Format 0 2-bit ACK miss 106 PRB), + (Test3: Format 0 2-bit ACK miss, 1-bit SR 106 PRB), + (Test4: Format 2 3-bit 106 PRB), + (Test5: Format 2 4-bit 106 PRB), + (Test6: Format 2 5-bit 106 PRB), + (Test7: Format 2 6-bit 106 PRB), + (Test8: Format 2 7-bit 106 PRB), + (Test9: Format 2 8-bit 106 PRB), + (Test10: Format 2 9-bit 106 PRB), + (Test11: Format 2 10-bit 106 PRB), + (Test12: Format 2 11-bit 106 PRB) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/targets/bin/nr_pucchsim.Rel15 - -R 106 -i 1 -P 0 -b 1 -s-7 -n1000 - -R 106 -i 1 -P 0 -b 2 -s-7 -n1000 + -R 106 -i 1 -P 0 -b 1 -s-2 -n1000 + -R 106 -i 1 -P 0 -b 2 -s-2 -n1000 + -R 106 -i 1 -P 0 -b 2 -s-2 -c -n1000 + -R 106 -i 1 -P 2 -b 3 -s0 -n1000 + -R 106 -i 1 -P 2 -b 4 -s0 -n1000 + -R 106 -i 1 -P 2 -b 5 -s1 -n1000 + -R 106 -i 1 -P 2 -b 6 -s2 -n1000 + -R 106 -i 1 -P 2 -b 7 -s3 -n1000 + -R 106 -i 1 -P 2 -b 8 -s4 -n1000 + -R 106 -i 1 -P 2 -b 9 -s5 -n1000 + -R 106 -i 1 -P 2 -b 10 -s6 -n1000 + -R 106 -i 1 -P 2 -b 11 -s6 -n1000 - nr_pucchsim.test1 nr_pucchsim.test2 + nr_pucchsim.test1 nr_pucchsim.test2 nr_pucchsim.test3 nr_pucchsim.test4 nr_pucchsim.test5 nr_pucchsim.test6 nr_pucchsim.test7 nr_pucchsim.test8 nr_pucchsim.test9 nr_pucchsim.test10 nr_pucchsim.test11 nr_pucchsim.test12 PUCCH test OK segmentation fault|assertion|exiting|fatal 3 From 7689b9394ac88d6130a9fe280bf84770174875b5 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 23 Apr 2020 22:49:33 +0200 Subject: [PATCH 159/175] added missing file --- openair1/PHY/NR_REFSIG/scrambling_luts.c | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 openair1/PHY/NR_REFSIG/scrambling_luts.c diff --git a/openair1/PHY/NR_REFSIG/scrambling_luts.c b/openair1/PHY/NR_REFSIG/scrambling_luts.c new file mode 100644 index 0000000000..eae54f94fb --- /dev/null +++ b/openair1/PHY/NR_REFSIG/scrambling_luts.c @@ -0,0 +1,62 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* Lookup tables for 3GPP scrambling/unscrambling */ + +/* Author R. Knopp / EURECOM / OpenAirInterface.org */ +#ifndef __SCRAMBLING_LUTS__C__ +#define __SCRAMBLING_LUTS__C__ + +#include "PHY/impl_defs_nr.h" +#include "PHY/sse_intrin.h" + +__m64 byte2m64_re[256]; +__m64 byte2m64_im[256]; + +void init_byte2m64() { + + for (int s=0;s<256;s++) { + byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*(s&1)),0); + byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>1)&1)),0); + byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*((s>>2)&1)),1); + byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>3)&1)),1); + byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*((s>>4)&1)),2); + byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>5)&1)),2); + byte2m64_re[s] = _mm_insert_pi16(byte2m64_re[s],(1-2*((s>>6)&1)),3); + byte2m64_im[s] = _mm_insert_pi16(byte2m64_im[s],(1-2*((s>>7)&1)),3); + printf("init_scrambling_luts: s %x (%d) ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n", + ((uint16_t*)&s)[0], + (1-2*(s&1)), + ((int16_t*)&byte2m64_re[s])[0],((int16_t*)&byte2m64_im[s])[0], + ((int16_t*)&byte2m64_re[s])[1],((int16_t*)&byte2m64_im[s])[1], + ((int16_t*)&byte2m64_re[s])[2],((int16_t*)&byte2m64_im[s])[2], + ((int16_t*)&byte2m64_re[s])[3],((int16_t*)&byte2m64_im[s])[3]); + + } +} + +void init_scrambling_luts() { + + init_byte2m64(); + +} + +#endif From b1da29427c07af02c4f9fcef955fc1a19e4a20bd Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 28 Apr 2020 14:32:31 +0200 Subject: [PATCH 160/175] justone log line --- openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 0e7bdd2ae4..f357e385f0 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -780,7 +780,6 @@ void ulsch_channel_compensation(int32_t **rxdataF_ext, #endif for (rb=0; rb Date: Tue, 28 Apr 2020 15:39:50 +0200 Subject: [PATCH 161/175] set back rrc as a separate thread, lead to create back race conditions --- common/utils/ocp_itti/intertask_interface.h | 2 +- openair2/RRC/LTE/rrc_eNB.c | 15 ++++++--------- targets/COMMON/create_tasks.c | 6 +++--- targets/RT/USER/lte-softmodem.c | 9 ++++++--- targets/RT/USER/lte-uesoftmodem.c | 6 ------ 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index 265a57ca63..ed4192eed6 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -288,7 +288,7 @@ void * rrc_enb_process_msg(void*); TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_DATA_FORWARDING, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_END_MARKER, TASK_PRIORITY_MED, 200, NULL, NULL) \ - TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, rrc_enb_process_msg,NULL)\ + TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL,NULL)\ TASK_DEF(TASK_RRC_GNB, TASK_PRIORITY_MED, 200, NULL,NULL)\ TASK_DEF(TASK_RAL_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index 9cca00ca2e..181346a014 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -8884,29 +8884,26 @@ void *rrc_enb_process_itti_msg(void *notUsed) { return NULL; } -// as there are race conditions, no rrc thread //----------------------------------------------------------------------------- void * -rrc_enb_process_msg( +rrc_enb_task( void *args_p ) //----------------------------------------------------------------------------- { + rrc_enb_init(); + itti_mark_task_ready(TASK_RRC_ENB); + LOG_I(RRC,"Entering main loop of RRC message task\n"); - //while (1) { - //(void) rrc_enb_process_itti_msg(NULL); - //} - - //while (1) { + while (1) { (void) rrc_enb_process_itti_msg(NULL); { //extern volatile int go_nr; void rrc_go_nr(void); //if (go_nr) rrc_go_nr(); } - //} -return NULL; + } } /*------------------------------------------------------------------------------*/ diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 10691d2db8..4d57ab4e16 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -56,9 +56,9 @@ int create_tasks(uint32_t enb_nb) { rc = itti_create_task (TASK_ENB_APP, eNB_app_task, NULL); AssertFatal(rc >= 0, "Create task for eNB APP failed\n"); - // No more rrc thread, as many race conditions are hidden behind - rrc_enb_init(); - itti_mark_task_ready(TASK_RRC_ENB); + LOG_I(RRC,"Creating RRC eNB Task\n"); + rc = itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL); + AssertFatal(rc >= 0, "Create task for RRC eNB failed\n"); if (EPC_MODE_ENABLED && ! ( split73==SPLIT73_DU ) ) { rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index f5db3d3c5a..d8c5e25593 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -446,9 +446,12 @@ int restart_L1L2(module_id_t enb_id) { init_UE_info(&RC.mac[enb_id]->UE_info); LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); - // No more rrc thread, as many race conditions are hidden behind - rrc_enb_init(); - itti_mark_task_ready(TASK_RRC_ENB); + if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { + LOG_E(RRC, "Create task for RRC eNB failed\n"); + return -1; + } else { + LOG_I(RRC, "Re-created task for RRC eNB successfully\n"); + } /* pass a reconfiguration request which will configure everything down to * RC.eNB[i][j]->frame_parms, too */ diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 395e73bb66..2c9271888b 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -541,12 +541,6 @@ void init_pdcp(void) { pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind); } -// Stupid function addition because UE itti messages queues definition is common with eNB -void *rrc_enb_process_msg(void *notUsed) { -AssertFatal(false,""); - return NULL; -} - int main( int argc, char **argv ) { int CC_id; uint8_t abstraction_flag=0; From 9480293cdab282f33ad1da46cd292c96ed80c50a Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 28 Apr 2020 16:33:50 +0200 Subject: [PATCH 162/175] include dir --- cmake_targets/nas_sim_tools/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake_targets/nas_sim_tools/CMakeLists.txt b/cmake_targets/nas_sim_tools/CMakeLists.txt index c1a0bb419b..308c71be4c 100644 --- a/cmake_targets/nas_sim_tools/CMakeLists.txt +++ b/cmake_targets/nas_sim_tools/CMakeLists.txt @@ -14,6 +14,7 @@ set(CMAKE_C_FLAGS set(OPENAIR_DIR $ENV{OPENAIR_DIR}) set(OPENAIR3_DIR $ENV{OPENAIR_DIR}/openair3) +include_directories (${OPENAIR_DIR}/openair2/COMMON) set(CONF2UEDATA_LIB_SRC ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_emm.c From c47daed70c201742246dbead9820093b96dbd80f Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Wed, 29 Apr 2020 10:29:02 +0200 Subject: [PATCH 163/175] LIC: wrong license banner on proto-agent files Signed-off-by: Raphael Defosseux --- openair2/LAYER2/PROTO_AGENT/proto_agent.c | 48 ++++++++---------- openair2/LAYER2/PROTO_AGENT/proto_agent.h | 49 ++++++++----------- .../LAYER2/PROTO_AGENT/proto_agent_async.c | 49 ++++++++----------- .../LAYER2/PROTO_AGENT/proto_agent_async.h | 48 ++++++++---------- .../LAYER2/PROTO_AGENT/proto_agent_common.c | 48 ++++++++---------- .../LAYER2/PROTO_AGENT/proto_agent_common.h | 48 ++++++++---------- .../LAYER2/PROTO_AGENT/proto_agent_defs.h | 48 ++++++++---------- .../LAYER2/PROTO_AGENT/proto_agent_handler.c | 48 ++++++++---------- .../LAYER2/PROTO_AGENT/proto_agent_net_comm.c | 48 ++++++++---------- .../LAYER2/PROTO_AGENT/proto_agent_net_comm.h | 48 ++++++++---------- 10 files changed, 200 insertions(+), 282 deletions(-) diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent.c b/openair2/LAYER2/PROTO_AGENT/proto_agent.c index bead6ad28d..6bf9cdce22 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent.c +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent.c @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent.h * \brief top level enb agent receive thread and itti task diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent.h b/openair2/LAYER2/PROTO_AGENT/proto_agent.h index 927b714b2c..6898c9e447 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent.h +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent.h @@ -1,32 +1,23 @@ - -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file proto_agent.h * \brief top level protocol agent diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_async.c b/openair2/LAYER2/PROTO_AGENT/proto_agent_async.c index eef697c5bb..df3684ee27 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_async.c +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_async.c @@ -1,32 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ - +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ #include "proto_agent_async.h" #include "proto_agent_defs.h" diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_async.h b/openair2/LAYER2/PROTO_AGENT/proto_agent_async.h index 27030924cd..6bc952e804 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_async.h +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_async.h @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent_async.h * \brief channel implementation for async interface diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_common.c b/openair2/LAYER2/PROTO_AGENT/proto_agent_common.c index a11c029bd3..6e343343cd 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_common.c +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_common.c @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file proto_agent_common.c * \brief common primitives for all agents diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_common.h b/openair2/LAYER2/PROTO_AGENT/proto_agent_common.h index 70e6b2a84e..c805b81543 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_common.h +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_common.h @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent_common.h * \brief common message primitves and utilities diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_defs.h b/openair2/LAYER2/PROTO_AGENT/proto_agent_defs.h index 08c91e7085..cd730a6de8 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_defs.h +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_defs.h @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2016 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent_defs.h * \brief enb agent common definitions diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_handler.c b/openair2/LAYER2/PROTO_AGENT/proto_agent_handler.c index cb65da2803..82f7849717 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_handler.c +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_handler.c @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent_handler.c * \brief enb agent tx and rx message handler diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.c b/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.c index f64a58f8e1..9a63427ed5 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.c +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.c @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2016 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent_net_comm.c * \brief enb agent network interface abstraction diff --git a/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.h b/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.h index c956bf48b1..55fca5a928 100644 --- a/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.h +++ b/openair2/LAYER2/PROTO_AGENT/proto_agent_net_comm.h @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2016 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file enb_agent_net_comm.h * \brief enb agent network interface abstraction From 9ac5f6015de28abd02ccb3ac36cc367d6e205157 Mon Sep 17 00:00:00 2001 From: laurent Date: Wed, 29 Apr 2020 11:31:00 +0200 Subject: [PATCH 164/175] update license text --- cmake_targets/CMakeLists.txt | 1 + common/utils/ocp_itti/intertask_interface.cpp | 23 ++++++++++++++-- common/utils/ocp_itti/intertask_interface.h | 23 ++++++++++++++-- common/utils/threadPool/measurement_display.c | 23 ++++++++++++++-- common/utils/threadPool/thread-pool.c | 23 ++++++++++++++-- common/utils/threadPool/thread-pool.h | 23 ++++++++++++++-- executables/main-fs6.c | 23 ++++++++++++++-- executables/main-ocp.c | 26 +++++++++++++++++-- executables/split_headers.h | 24 +++++++++++++++-- executables/transport_split.c | 25 ++++++++++++++++-- targets/ARCH/rfsimulator/apply_channelmod.c | 23 +++++++++++++--- targets/ARCH/rfsimulator/simulator.c | 23 ++++++++++++++-- targets/ARCH/rfsimulator/stored_node.c | 23 ++++++++++++++-- 13 files changed, 258 insertions(+), 25 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 6382bbea51..acacba5cbc 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -884,6 +884,7 @@ include_directories("${OPENAIR2_DIR}/LAYER2/PDCP_v10.1.0") include_directories("${OPENAIR2_DIR}/RRC/LTE/MESSAGES") include_directories("${OPENAIR2_DIR}/RRC/LTE") include_directories("${OPENAIR_DIR}/common/utils") +include_directories("${OPENAIR_DIR}/common/utils/collection") include_directories("${OPENAIR_DIR}/common/utils/ocp_itti") include_directories("${OPENAIR3_DIR}/NAS/COMMON") include_directories("${OPENAIR3_DIR}/NAS/COMMON/API/NETWORK") diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 42c3828dc4..3d4d356dcf 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -1,7 +1,26 @@ /* - Author: Laurent THOMAS, Open Cells - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #include #include #include diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index ed4192eed6..0cd25ee231 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -1,7 +1,26 @@ /* - Author: Laurent THOMAS, Open Cells - Copyleft: OpenAirInterface software alliance and it's license +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #ifndef INTERTASK_INTERFACE_H_ #define INTERTASK_INTERFACE_H_ #include diff --git a/common/utils/threadPool/measurement_display.c b/common/utils/threadPool/measurement_display.c index 8f6e2c239a..0f5a3e0f69 100644 --- a/common/utils/threadPool/measurement_display.c +++ b/common/utils/threadPool/measurement_display.c @@ -1,7 +1,26 @@ /* - Author: Laurent THOMAS, Open Cells - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #include #include "thread-pool.h" diff --git a/common/utils/threadPool/thread-pool.c b/common/utils/threadPool/thread-pool.c index dd3d16d717..cbb2dbe3d9 100644 --- a/common/utils/threadPool/thread-pool.c +++ b/common/utils/threadPool/thread-pool.c @@ -1,8 +1,27 @@ /* - Author: Laurent THOMAS, Open Cells - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #define _GNU_SOURCE #include #include diff --git a/common/utils/threadPool/thread-pool.h b/common/utils/threadPool/thread-pool.h index 1b59fb1589..0ed8715811 100644 --- a/common/utils/threadPool/thread-pool.h +++ b/common/utils/threadPool/thread-pool.h @@ -1,8 +1,27 @@ /* - Author: Laurent THOMAS, Open Cells - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #ifndef THREAD_POOL_H #define THREAD_POOL_H #include diff --git a/executables/main-fs6.c b/executables/main-fs6.c index a10d96b556..45a6271887 100644 --- a/executables/main-fs6.c +++ b/executables/main-fs6.c @@ -1,7 +1,26 @@ /* - Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #include #include #include diff --git a/executables/main-ocp.c b/executables/main-ocp.c index 8171d78d5b..d2ee9418dc 100644 --- a/executables/main-ocp.c +++ b/executables/main-ocp.c @@ -1,6 +1,28 @@ /* - Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org +*/ + + +/* * This file replaces * targets/RT/USER/lte-softmodem.c * targets/RT/USER/rt_wrapper.c diff --git a/executables/split_headers.h b/executables/split_headers.h index 62293c7369..4e328f74c4 100644 --- a/executables/split_headers.h +++ b/executables/split_headers.h @@ -1,7 +1,27 @@ /* - Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + + #ifndef __SPLIT_HEADERS_H #define __SPLIT_HEADERS_H diff --git a/executables/transport_split.c b/executables/transport_split.c index 7a1ee3e85e..f380eb90e3 100644 --- a/executables/transport_split.c +++ b/executables/transport_split.c @@ -1,7 +1,28 @@ /* - Author: Laurent THOMAS, Open Cells Project company, funded by IRT SystemX - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + + + #include #include /* See NOTES */ #include diff --git a/targets/ARCH/rfsimulator/apply_channelmod.c b/targets/ARCH/rfsimulator/apply_channelmod.c index ef4e564343..faf84bb0aa 100644 --- a/targets/ARCH/rfsimulator/apply_channelmod.c +++ b/targets/ARCH/rfsimulator/apply_channelmod.c @@ -1,7 +1,24 @@ /* - Author: Laurent THOMAS, Open Cells for Nokia - copyleft: OpenAirInterface Software Alliance and it's licence - +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index a1b517a1ed..dc448b33e9 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -1,8 +1,27 @@ /* - Author: Laurent THOMAS, Open Cells for Nokia - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + /* * Open issues and limitations * The read and write should be called in the same thread, that is not new USRP UHD design diff --git a/targets/ARCH/rfsimulator/stored_node.c b/targets/ARCH/rfsimulator/stored_node.c index 2b77c5322d..73f6321ffe 100644 --- a/targets/ARCH/rfsimulator/stored_node.c +++ b/targets/ARCH/rfsimulator/stored_node.c @@ -1,8 +1,27 @@ /* - Author: Laurent THOMAS, Open Cells - copyleft: OpenAirInterface Software Alliance and it's licence +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Author and copyright: Laurent Thomas, open-cells.com +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org */ + #include volatile int oai_exit = 0; From e5ea8a5a034baecdff08dc0f1260aeb80821b309 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 29 Apr 2020 16:15:59 +0200 Subject: [PATCH 165/175] rlc v2: fix cmake file --- cmake_targets/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b5d2e0bc79..bfbec4766b 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1701,7 +1701,6 @@ set(L2_SRC ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c - ${RLC_V2} # ${RRC_DIR}/rrc_UE.c ${RRC_DIR}/rrc_eNB.c ${RRC_DIR}/rrc_eNB_endc.c @@ -1715,7 +1714,7 @@ set(L2_SRC ) set(L2_LTE_SRC - ${RLC_V1} + ${RLC_V2} ) set(L2_NR_SRC @@ -1738,7 +1737,6 @@ set(L2_SRC_UE ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c - ${RLC_V2} ${RRC_DIR}/rrc_UE.c ${RRC_DIR}/rrc_common.c ${RRC_DIR}/L2_interface_common.c @@ -1753,7 +1751,7 @@ set(LTE_NR_L2_SRC_UE ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c - ${RLC_V1} + ${RLC_V2} ) set(NR_L2_SRC_UE From cd3f5ad001d936e36e3b7e47eaf23f3b1ca7c29b Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 30 Apr 2020 09:18:54 +0200 Subject: [PATCH 166/175] added parameters to generate_pucch2 in ue pucch procedures --- openair1/SCHED_NR_UE/pucch_uci_ue_nr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c index 326c617dfb..1b62ff81bf 100644 --- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c +++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c @@ -186,6 +186,8 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_ int pucch_resource_id = MAX_NB_OF_PUCCH_RESOURCES; int pucch_resource_indicator = MAX_PUCCH_RESOURCE_INDICATOR; int n_HARQ_ACK; + uint16_t crnti=0x1234; + int dmrs_scrambling_id=0,data_scrambling_id=0; /* update current context */ @@ -591,7 +593,9 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_ case pucch_format2_nr: { nr_generate_pucch2(ue, - 0,//ue->pdcch_vars[ue->current_thread_id[proc->nr_tti_rx]][gNB_id]->crnti, + crnti, + dmrs_scrambling_id, + data_scrambling_id, ue->common_vars.txdataF, &ue->frame_parms, &ue->pucch_config_dedicated[gNB_id], From 4210c41179f1fae72fd92f22d4ad1188eb7051f4 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 30 Apr 2020 15:48:37 +0200 Subject: [PATCH 167/175] removal of a massive number of warnings --- .../PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h | 236 +++++++++--------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 +- 2 files changed, 120 insertions(+), 120 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h index 10b45ac0e7..b76750459d 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h @@ -135,25 +135,25 @@ static inline void nrLDPC_llr2llrProcBuf(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrL */ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrLDPC_procBuf* p_procBuf, uint16_t Z) { - const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0]; - const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1]; - const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2]; - const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3]; - const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4]; - const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5]; - const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6]; - const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7]; - const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8]; + const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0]; + const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1]; + const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2]; + const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3]; + const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4]; + const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5]; + const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6]; + const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7]; + const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8]; - const uint8_t (*lut_posBnInCnProcBuf_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->posBnInCnProcBuf[0]; - const uint8_t (*lut_posBnInCnProcBuf_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->posBnInCnProcBuf[1]; - const uint8_t (*lut_posBnInCnProcBuf_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->posBnInCnProcBuf[2]; - const uint8_t (*lut_posBnInCnProcBuf_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->posBnInCnProcBuf[3]; - const uint8_t (*lut_posBnInCnProcBuf_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->posBnInCnProcBuf[4]; - const uint8_t (*lut_posBnInCnProcBuf_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->posBnInCnProcBuf[5]; - const uint8_t (*lut_posBnInCnProcBuf_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->posBnInCnProcBuf[6]; - const uint8_t (*lut_posBnInCnProcBuf_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->posBnInCnProcBuf[7]; - const uint8_t (*lut_posBnInCnProcBuf_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint8_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->posBnInCnProcBuf[8]; + const uint8_t (*lut_posBnInCnProcBuf_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->posBnInCnProcBuf[0]; + const uint8_t (*lut_posBnInCnProcBuf_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->posBnInCnProcBuf[1]; + const uint8_t (*lut_posBnInCnProcBuf_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->posBnInCnProcBuf[2]; + const uint8_t (*lut_posBnInCnProcBuf_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->posBnInCnProcBuf[3]; + const uint8_t (*lut_posBnInCnProcBuf_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->posBnInCnProcBuf[4]; + const uint8_t (*lut_posBnInCnProcBuf_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->posBnInCnProcBuf[5]; + const uint8_t (*lut_posBnInCnProcBuf_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->posBnInCnProcBuf[6]; + const uint8_t (*lut_posBnInCnProcBuf_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->posBnInCnProcBuf[7]; + const uint8_t (*lut_posBnInCnProcBuf_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint8_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->posBnInCnProcBuf[8]; const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups; const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups; @@ -344,19 +344,19 @@ static inline void nrLDPC_llr2CnProcBuf_BG1(t_nrLDPC_lut* p_lut, int8_t* llr, t_ */ static inline void nrLDPC_llr2CnProcBuf_BG2(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrLDPC_procBuf* p_procBuf, uint16_t Z) { - const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0]; - const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1]; - const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2]; - const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3]; - const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4]; - const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5]; + const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0]; + const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1]; + const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2]; + const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3]; + const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4]; + const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5]; - const uint8_t (*lut_posBnInCnProcBuf_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->posBnInCnProcBuf[0]; - const uint8_t (*lut_posBnInCnProcBuf_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->posBnInCnProcBuf[1]; - const uint8_t (*lut_posBnInCnProcBuf_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->posBnInCnProcBuf[2]; - const uint8_t (*lut_posBnInCnProcBuf_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->posBnInCnProcBuf[3]; - const uint8_t (*lut_posBnInCnProcBuf_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->posBnInCnProcBuf[4]; - const uint8_t (*lut_posBnInCnProcBuf_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint8_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->posBnInCnProcBuf[5]; + const uint8_t (*lut_posBnInCnProcBuf_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->posBnInCnProcBuf[0]; + const uint8_t (*lut_posBnInCnProcBuf_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->posBnInCnProcBuf[1]; + const uint8_t (*lut_posBnInCnProcBuf_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->posBnInCnProcBuf[2]; + const uint8_t (*lut_posBnInCnProcBuf_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->posBnInCnProcBuf[3]; + const uint8_t (*lut_posBnInCnProcBuf_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->posBnInCnProcBuf[4]; + const uint8_t (*lut_posBnInCnProcBuf_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint8_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->posBnInCnProcBuf[5]; const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups; const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups; @@ -483,26 +483,26 @@ static inline void nrLDPC_cn2bnProcBuf_BG2(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups; const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups; - const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0]; - const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1]; - const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2]; - const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3]; - const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4]; - const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5]; + const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0]; + const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1]; + const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2]; + const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3]; + const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4]; + const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5]; - const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; - const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; - const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; - const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; - const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; - const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; + const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; + const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; + const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; + const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; + const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; + const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; - const uint8_t (*lut_bnPosBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0]; - const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; - const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; - const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; - const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; - const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; + const uint8_t (*lut_bnPosBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0]; + const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; + const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; + const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; + const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; + const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; int8_t* cnProcBufRes = p_procBuf->cnProcBufRes; int8_t* bnProcBuf = p_procBuf->bnProcBuf; @@ -626,34 +626,34 @@ static inline void nrLDPC_cn2bnProcBuf_BG1(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups; const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups; - const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0]; - const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1]; - const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2]; - const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3]; - const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4]; - const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5]; - const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6]; - const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7]; - const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8]; + const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0]; + const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1]; + const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2]; + const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3]; + const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4]; + const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5]; + const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6]; + const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7]; + const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8]; - const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; - const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; - const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; - const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; - const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; - const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; - const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6]; - const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7]; - const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8]; + const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; + const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; + const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; + const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; + const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; + const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; + const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6]; + const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7]; + const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8]; - const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; - const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; - const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; - const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; - const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; - const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6]; - const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7]; - const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8]; + const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; + const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; + const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; + const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; + const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; + const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6]; + const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7]; + const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8]; int8_t* cnProcBufRes = p_procBuf->cnProcBufRes; int8_t* bnProcBuf = p_procBuf->bnProcBuf; @@ -824,26 +824,26 @@ static inline void nrLDPC_bn2cnProcBuf_BG2(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups; const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups; - const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0]; - const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1]; - const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2]; - const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3]; - const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4]; - const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5]; + const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG2_R15[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[0]]) p_lut->circShift[0]; + const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG2_R15[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[1]]) p_lut->circShift[1]; + const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG2_R15[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[2]]) p_lut->circShift[2]; + const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG2_R15[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[3]]) p_lut->circShift[3]; + const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG2_R15[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[4]]) p_lut->circShift[4]; + const uint16_t (*lut_circShift_CNG10) [lut_numCnInCnGroups_BG2_R15[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG2_R15[5]]) p_lut->circShift[5]; - const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; - const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; - const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; - const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; - const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; - const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; + const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; + const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; + const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; + const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; + const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; + const uint32_t (*lut_startAddrBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; - const uint8_t (*lut_bnPosBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0]; - const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; - const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; - const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; - const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; - const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; + const uint8_t (*lut_bnPosBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint8_t(*)[lut_numCnInCnGroups[0]]) p_lut->bnPosBnProcBuf[0]; + const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; + const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; + const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; + const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; + const uint8_t (*lut_bnPosBnProcBuf_CNG10) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; int8_t* cnProcBuf = p_procBuf->cnProcBuf; int8_t* bnProcBufRes = p_procBuf->bnProcBufRes; @@ -966,34 +966,34 @@ static inline void nrLDPC_bn2cnProcBuf_BG1(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf const uint8_t* lut_numCnInCnGroups = p_lut->numCnInCnGroups; const uint32_t* lut_startAddrCnGroups = p_lut->startAddrCnGroups; - const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0]; - const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1]; - const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2]; - const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3]; - const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4]; - const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5]; - const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6]; - const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7]; - const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8]; + const uint16_t (*lut_circShift_CNG3) [lut_numCnInCnGroups_BG1_R13[0]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[0]]) p_lut->circShift[0]; + const uint16_t (*lut_circShift_CNG4) [lut_numCnInCnGroups_BG1_R13[1]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[1]]) p_lut->circShift[1]; + const uint16_t (*lut_circShift_CNG5) [lut_numCnInCnGroups_BG1_R13[2]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[2]]) p_lut->circShift[2]; + const uint16_t (*lut_circShift_CNG6) [lut_numCnInCnGroups_BG1_R13[3]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[3]]) p_lut->circShift[3]; + const uint16_t (*lut_circShift_CNG7) [lut_numCnInCnGroups_BG1_R13[4]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[4]]) p_lut->circShift[4]; + const uint16_t (*lut_circShift_CNG8) [lut_numCnInCnGroups_BG1_R13[5]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[5]]) p_lut->circShift[5]; + const uint16_t (*lut_circShift_CNG9) [lut_numCnInCnGroups_BG1_R13[6]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[6]]) p_lut->circShift[6]; + const uint16_t (*lut_circShift_CNG10)[lut_numCnInCnGroups_BG1_R13[7]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[7]]) p_lut->circShift[7]; + const uint16_t (*lut_circShift_CNG19)[lut_numCnInCnGroups_BG1_R13[8]] = (const uint16_t(*)[lut_numCnInCnGroups_BG1_R13[8]]) p_lut->circShift[8]; - const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; - const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; - const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; - const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; - const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; - const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; - const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6]; - const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7]; - const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8]; + const uint32_t (*lut_startAddrBnProcBuf_CNG3) [lut_numCnInCnGroups[0]] = (const uint32_t(*)[lut_numCnInCnGroups[0]]) p_lut->startAddrBnProcBuf[0]; + const uint32_t (*lut_startAddrBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint32_t(*)[lut_numCnInCnGroups[1]]) p_lut->startAddrBnProcBuf[1]; + const uint32_t (*lut_startAddrBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint32_t(*)[lut_numCnInCnGroups[2]]) p_lut->startAddrBnProcBuf[2]; + const uint32_t (*lut_startAddrBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint32_t(*)[lut_numCnInCnGroups[3]]) p_lut->startAddrBnProcBuf[3]; + const uint32_t (*lut_startAddrBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint32_t(*)[lut_numCnInCnGroups[4]]) p_lut->startAddrBnProcBuf[4]; + const uint32_t (*lut_startAddrBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint32_t(*)[lut_numCnInCnGroups[5]]) p_lut->startAddrBnProcBuf[5]; + const uint32_t (*lut_startAddrBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint32_t(*)[lut_numCnInCnGroups[6]]) p_lut->startAddrBnProcBuf[6]; + const uint32_t (*lut_startAddrBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint32_t(*)[lut_numCnInCnGroups[7]]) p_lut->startAddrBnProcBuf[7]; + const uint32_t (*lut_startAddrBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint32_t(*)[lut_numCnInCnGroups[8]]) p_lut->startAddrBnProcBuf[8]; - const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; - const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; - const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; - const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; - const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; - const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6]; - const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7]; - const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8]; + const uint8_t (*lut_bnPosBnProcBuf_CNG4) [lut_numCnInCnGroups[1]] = (const uint8_t(*)[lut_numCnInCnGroups[1]]) p_lut->bnPosBnProcBuf[1]; + const uint8_t (*lut_bnPosBnProcBuf_CNG5) [lut_numCnInCnGroups[2]] = (const uint8_t(*)[lut_numCnInCnGroups[2]]) p_lut->bnPosBnProcBuf[2]; + const uint8_t (*lut_bnPosBnProcBuf_CNG6) [lut_numCnInCnGroups[3]] = (const uint8_t(*)[lut_numCnInCnGroups[3]]) p_lut->bnPosBnProcBuf[3]; + const uint8_t (*lut_bnPosBnProcBuf_CNG7) [lut_numCnInCnGroups[4]] = (const uint8_t(*)[lut_numCnInCnGroups[4]]) p_lut->bnPosBnProcBuf[4]; + const uint8_t (*lut_bnPosBnProcBuf_CNG8) [lut_numCnInCnGroups[5]] = (const uint8_t(*)[lut_numCnInCnGroups[5]]) p_lut->bnPosBnProcBuf[5]; + const uint8_t (*lut_bnPosBnProcBuf_CNG9) [lut_numCnInCnGroups[6]] = (const uint8_t(*)[lut_numCnInCnGroups[6]]) p_lut->bnPosBnProcBuf[6]; + const uint8_t (*lut_bnPosBnProcBuf_CNG10)[lut_numCnInCnGroups[7]] = (const uint8_t(*)[lut_numCnInCnGroups[7]]) p_lut->bnPosBnProcBuf[7]; + const uint8_t (*lut_bnPosBnProcBuf_CNG19)[lut_numCnInCnGroups[8]] = (const uint8_t(*)[lut_numCnInCnGroups[8]]) p_lut->bnPosBnProcBuf[8]; int8_t* cnProcBuf = p_procBuf->cnProcBuf; int8_t* bnProcBufRes = p_procBuf->bnProcBufRes; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index a2f4b57121..60f9d4747a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -439,8 +439,8 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) case 2: break; default: - AssertFatal(1==0,"Only PUCCH format 0,1 and 2 are currently supported\n") - } + AssertFatal(1==0,"Only PUCCH format 0,1 and 2 are currently supported\n"); + } } } } From da54778c4ab381743c388078676103663addafcc Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 3 May 2020 18:27:07 +0200 Subject: [PATCH 168/175] fix warnings --- executables/nr-ru.c | 1 - executables/nr-softmodem.c | 1 - openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_transport.h | 7 ++ .../NR_TRANSPORT/nr_transport_proto_common.h | 69 +------------------ openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 3 +- .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 3 +- openair1/PHY/NR_UE_TRANSPORT/nr_prach.c | 1 + .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 5 +- openair1/PHY/TOOLS/nr_phy_scope.c | 6 +- openair1/SCHED_NR/nr_prach_procedures.c | 2 +- openair1/SCHED_NR_UE/phy_frame_config_nr.h | 5 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 2 +- openair1/SIMULATION/NR_PHY/prachsim.c | 7 +- openair1/SIMULATION/NR_PHY/ulsim.c | 6 +- openair2/GNB_APP/gnb_config.c | 2 - openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 3 +- openair2/RRC/NR/rrc_gNB.c | 1 + 18 files changed, 31 insertions(+), 96 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index f947395f4a..3584a59e5d 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -2147,7 +2147,6 @@ void init_NR_RU(char *rf_config_file) PHY_VARS_gNB *gNB0= (PHY_VARS_gNB *)NULL; NR_DL_FRAME_PARMS *fp = (NR_DL_FRAME_PARMS *)NULL; int i; - int CC_id; // create status mask RC.ru_mask = 0; pthread_mutex_init(&RC.ru_mutex,NULL); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 6dd3807f3c..f473d0161b 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -708,7 +708,6 @@ int stop_L1L2(module_id_t gnb_id) { */ int restart_L1L2(module_id_t gnb_id) { RU_t *ru = RC.ru[gnb_id]; - int cc_id; MessageDef *msg_p = NULL; LOG_W(GNB_APP, "restarting nr-softmodem\n"); /* block threads */ diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 856a7863f4..f120864184 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -64,7 +64,6 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr,uint16_t N_RB) a_segments = a_segments/273; } - uint16_t dlsch_bytes = a_segments*1056; // allocated bytes per segment #ifdef DEBUG_DLSCH_FREE @@ -82,7 +81,7 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr,uint16_t N_RB) #endif if (dlsch->harq_processes[i]->b) { - free16(dlsch->harq_processes[i]->b,dlsch_bytes); + free16(dlsch->harq_processes[i]->b,a_segments*1056); dlsch->harq_processes[i]->b = NULL; #ifdef DEBUG_DLSCH_FREE LOG_D(PHY,"Freeing dlsch process %d b (%p)\n",i,dlsch->harq_processes[i]->b); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport.h b/openair1/PHY/NR_TRANSPORT/nr_transport.h index be73875058..fea782c30e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport.h @@ -123,4 +123,11 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); +void compute_nr_prach_seq(uint16_t rootSequenceIndex, + uint8_t prach_ConfigIndex, + uint8_t zeroCorrelationZoneConfig, + uint8_t highSpeedFlag, + lte_frame_type_t frame_type, + nr_frequency_range_e fr, + uint32_t X_u[64][839]); #endif /*__NR_TRANSPORT__H__*/ diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto_common.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto_common.h index dd37455e26..f41dd2f0a6 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto_common.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto_common.h @@ -29,8 +29,8 @@ * \note * \warning */ -#ifndef __NR_TRANSPORT_PROTO_UE__H__ -#define __NR_TRANSPORT_PROTO_UE__H__ +#ifndef __NR_TRANSPORT_PROTO_COMMON_H__ +#define __NR_TRANSPORT_PROTO_COMMON_H__ #include "PHY/defs_nr_UE.h" #include "SCHED_NR_UE/defs.h" //#include "PHY/LTE_TRANSPORT/transport_common_proto.h" @@ -43,29 +43,6 @@ * @{ */ -/** \fn free_ue_dlsch(NR_UE_DLSCH_t *dlsch) - \brief This function frees memory allocated for a particular DLSCH at UE - @param dlsch Pointer to DLSCH to be removed -*/ -void free_nr_ue_dlsch(NR_UE_DLSCH_t *dlsch); - -/** \fn new_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t abstraction_flag) - \brief This function allocates structures for a particular DLSCH at UE - @returns Pointer to DLSCH to be removed - @param Kmimo Kmimo factor from 36-212/36-213 - @param Mdlharq Maximum number of HARQ rounds (36-212/36-213) - @param Nsoft Soft-LLR buffer size from UE-Category - @params N_RB_DL total number of resource blocks (determine the operating BW) - @param abstraction_flag Flag to indicate abstracted interface -*/ -NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_turbo_iterations,uint8_t N_RB_DL, uint8_t abstraction_flag); - - -void free_nr_ue_ulsch(NR_UE_ULSCH_t *ulsch); - - -NR_UE_ULSCH_t *new_nr_ue_ulsch(unsigned char N_RB_UL, int number_of_harq_pids, uint8_t abstraction_flag); - void fill_UE_dlsch_MCH(PHY_VARS_NR_UE *ue,int mcs,int ndi,int rvidx,int eNB_id); int rx_pmch(PHY_VARS_NR_UE *phy_vars_ue, @@ -1055,21 +1032,6 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch, NR_DL_FRAME_PARMS* frame_parms, uint8_t harq_pid); -/*! \brief Perform PUSCH scrambling. TS 38.211 V15.4.0 subclause 6.3.1.1 - @param[in] in Pointer to input bits - @param[in] size of input bits - @param[in] Nid cell id - @param[in] n_RNTI CRNTI - @param[out] out the scrambled bits -*/ - -void nr_pusch_codeword_scrambling(uint8_t *in, - uint16_t size, - uint32_t Nid, - uint32_t n_RNTI, - uint32_t* out); - - uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, UE_nr_rxtx_proc_t *proc, int eNB_id, @@ -1128,17 +1090,6 @@ int32_t nr_rx_pdsch(PHY_VARS_NR_UE *phy_vars_ue, uint8_t i_mod, uint8_t harq_pid); -int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, - uint32_t frame, - uint8_t nr_tti_rx, - uint8_t eNB_id, - MIMO_mode_t mimo_mode, - uint32_t high_speed_flag, - uint8_t is_secondary_ue, - int nb_coreset_active, - uint16_t symbol_mon, - NR_SEARCHSPACE_TYPE_t searchSpaceType); - /*! \brief Extract PSS and SSS resource elements @param phy_vars_ue Pointer to UE variables @param[out] pss_ext contain the PSS signals after the extraction @@ -1471,18 +1422,6 @@ void init_transport_channels(uint8_t); void generate_RIV_tables(void); -/*! - \brief This function performs the initial cell search procedure - PSS detection, SSS detection and PBCH detection. At the - end, the basic frame parameters are known (Frame configuration - TDD/FDD and cyclic prefix length, - N_RB_DL, PHICH_CONFIG and Nid_cell) and the UE can begin decoding PDCCH and DLSCH SI to retrieve the rest. Once these - parameters are know, the routine calls some basic initialization routines (cell-specific reference signals, etc.) - @param phy_vars_ue Pointer to UE variables - @param mode current running mode -*/ -int nr_initial_sync(UE_nr_rxtx_proc_t *proc, - PHY_VARS_NR_UE *phy_vars_ue, runmode_t mode); - - /*! \brief Encoding of PUSCH/ACK/RI/ACK from 36-212. @param a Pointer to ulsch SDU @@ -1724,10 +1663,6 @@ uint8_t get_prach_prb_offset(NR_DL_FRAME_PARMS *frame_parms, uint8_t n_ra_prboffset, uint8_t tdd_mapindex, uint16_t Nf); -void nr_pdcch_unscrambling(uint16_t crnti, NR_DL_FRAME_PARMS *frame_parms, uint8_t nr_tti_rx, - int16_t *z, uint32_t length, uint16_t pdcch_DMRS_scrambling_id, int do_common); - - uint32_t lte_gold_generic(uint32_t *x1, uint32_t *x2, uint8_t reset); int nr_rx_pdsch(PHY_VARS_NR_UE *ue, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 050c230212..6c6ff4fd05 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -70,13 +70,12 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t **ulschptr,uint8_t N_RB_UL) a_segments = a_segments/273; } - uint16_t ulsch_bytes = a_segments*1056; // allocated bytes per segment for (i=0; iharq_processes[i]) { if (ulsch->harq_processes[i]->b) { - free16(ulsch->harq_processes[i]->b,ulsch_bytes); + free16(ulsch->harq_processes[i]->b,a_segments*1056); ulsch->harq_processes[i]->b = NULL; } for (r=0; rMdlharq; i++) { if (dlsch->harq_processes[i]) { if (dlsch->harq_processes[i]->b) { - free16(dlsch->harq_processes[i]->b,dlsch_bytes); + free16(dlsch->harq_processes[i]->b,a_segments*1056); dlsch->harq_processes[i]->b = NULL; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c index adef4a7592..f81e809d18 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c @@ -40,6 +40,7 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "T.h" +#include diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 00627ac3ae..a6fd5259ae 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -60,17 +60,16 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr,unsigned char N_RB_UL) a_segments = a_segments/273; } - uint16_t ulsch_bytes = a_segments*1056; // allocated bytes per segment for (i=0; iharq_processes[i]) { if (ulsch->harq_processes[i]->a) { - free16(ulsch->harq_processes[i]->a,ulsch_bytes); + free16(ulsch->harq_processes[i]->a,a_segments*1056); ulsch->harq_processes[i]->a = NULL; } if (ulsch->harq_processes[i]->b) { - free16(ulsch->harq_processes[i]->b,ulsch_bytes); + free16(ulsch->harq_processes[i]->b,a_segments*1056); ulsch->harq_processes[i]->b = NULL; } if (ulsch->harq_processes[i]->e) { diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c index 4682a89029..67ec027a9d 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.c +++ b/openair1/PHY/TOOLS/nr_phy_scope.c @@ -157,9 +157,9 @@ void phy_scope_gNB(FD_phy_scope_gnb *form, { int i, arx; //int i,i2,arx,atx,ind,k; NR_DL_FRAME_PARMS *frame_parms = &phy_vars_gnb->frame_parms; - int nsymb_ce = 12*frame_parms->N_RB_UL*frame_parms->symbols_per_tti; + //int nsymb_ce = 12*frame_parms->N_RB_UL*frame_parms->symbols_per_tti; uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; - uint8_t nb_antennas_tx = 1; // frame_parms->nb_antennas_tx; // in LTE Rel. 8 and 9 only a single transmit antenna is assumed at the UE + //uint8_t nb_antennas_tx = 1; // frame_parms->nb_antennas_tx; // in LTE Rel. 8 and 9 only a single transmit antenna is assumed at the UE int16_t **rxsig_t, **rxsig_f; // int16_t **chest_t=NULL; // int16_t **chest_f=NULL; @@ -966,7 +966,7 @@ FD_stats_form * create_form_stats_form( void ) { } void startScope(scopeParms_t * p) { - FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; + //FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; char title[255]; fl_initialize (p->argc, p->argv, NULL, 0, 0); /* diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index 1ed8f28b49..9054ddbae5 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -55,7 +55,7 @@ extern int oai_nfapi_nr_rach_ind(nfapi_rach_indication_t *rach_ind); void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot, nfapi_nr_prach_pdu_t *prach_pdu) { - uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4]; + uint16_t max_preamble[4]={0},max_preamble_energy[4]={0},max_preamble_delay[4]={0}; uint16_t i; diff --git a/openair1/SCHED_NR_UE/phy_frame_config_nr.h b/openair1/SCHED_NR_UE/phy_frame_config_nr.h index a939584584..81b6d373df 100644 --- a/openair1/SCHED_NR_UE/phy_frame_config_nr.h +++ b/openair1/SCHED_NR_UE/phy_frame_config_nr.h @@ -29,8 +29,8 @@ * ************************************************************************/ -#ifndef PHY_FRAME_CONFIG_NR_H -#define PHY_FRAME_CONFIG_NR_H +#ifndef PHY_FRAME_CONFIG_NR_UE_H +#define PHY_FRAME_CONFIG_NR_UE_H /************** DEFINE ********************************************/ @@ -78,5 +78,6 @@ void free_tdd_configuration_nr(NR_DL_FRAME_PARMS *frame_parms); void free_tdd_configuration_dedicated_nr(NR_DL_FRAME_PARMS *frame_parms); +void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag,runmode_t mod); #endif /* PHY_FRAME_CONFIG_NR_H */ diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 99ca466fee..9d14391f71 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -410,7 +410,7 @@ int main(int argc, char **argv) uint8_t n_hf = 0; int cyclic_prefix_type = NFAPI_CP_NORMAL; - double fs, eps; + double fs=0, eps; double scs = 30000; double bw = 100e6; diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 5c00352515..e6106ce462 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -108,7 +108,7 @@ int main(int argc, char **argv) uint8_t hs_flag=0; int n_frames=1; channel_desc_t *UE2gNB; - uint32_t nsymb,tx_lev; //,tx_lev_dB; + uint32_t tx_lev=0; //,tx_lev_dB; // int8_t interf1=-19,interf2=-19; NR_DL_FRAME_PARMS *frame_parms; @@ -120,7 +120,6 @@ int main(int argc, char **argv) uint32_t prach_errors=0; uint8_t subframe=9; uint16_t preamble_energy_list[64],preamble_tx=50,preamble_delay_list[64]; - uint16_t preamble_max,preamble_energy_max; PRACH_RESOURCES_t prach_resources; //uint8_t prach_fmt; //int N_ZC; @@ -397,7 +396,7 @@ int main(int argc, char **argv) frame_parms->frame_type = TDD; frame_parms->freq_range = nr_FR1; - nsymb = (frame_parms->Ncp == 0) ? 14 : 12; + //nsymb = (frame_parms->Ncp == 0) ? 14 : 12; printf("FFT Size %d, Extended Prefix %d, Samples per subframe %d,Frame type %s, Frequency Range %s\n",NUMBER_OF_OFDM_CARRIERS, frame_parms->Ncp,frame_parms->samples_per_subframe,frame_parms->frame_type == FDD ? "FDD" : "TDD", frame_parms->freq_range == nr_FR1 ? "FR1" : "FR2"); @@ -434,7 +433,7 @@ int main(int argc, char **argv) bw = N_RB_UL*(180e3)*(1<frame_parms.numerology_index); - AssertFatal(bw<=122.88e6,"Illegal channel bandwidth %f (mu %d,N_RB_UL %d)\n",gNB->frame_parms.numerology_index,N_RB_UL); + AssertFatal(bw<=122.88e6,"Illegal channel bandwidth %f (mu %d,N_RB_UL %d)\n",bw, gNB->frame_parms.numerology_index,N_RB_UL); if (bw <= 30.72e6) fs = 30.72e6; else if (bw <= 61.44e6) fs = 61.44e6; else if (bw <= 122.88e6) fs = 122.88e6; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 7c1b441b6a..47e7c215e2 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -105,7 +105,7 @@ openair0_config_t openair0_cfg[MAX_CARDS]; int main(int argc, char **argv) { char c; - int i,sf; + int i; double SNR, snr0 = -2.0, snr1 = 2.0; double sigma, sigma_dB; double snr_step = 1; @@ -393,7 +393,7 @@ int main(int argc, char **argv) for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; mac_top_init_gNB(); - gNB_MAC_INST* gNB_mac = RC.nrmac[0]; + //gNB_MAC_INST* gNB_mac = RC.nrmac[0]; gNB_RRC_INST rrc; memset((void*)&rrc,0,sizeof(rrc)); @@ -449,7 +449,7 @@ int main(int argc, char **argv) init_nr_ue_transport(UE, 0); /* - for (sf = 0; sf < 2; sf++) { + for (int sf = 0; sf < 2; sf++) { for (i = 0; i < 2; i++) { UE->ulsch[sf][0][i] = new_nr_ue_ulsch(N_RB_UL, 8, 0); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 9355517072..e7fd2f3cf8 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -978,8 +978,6 @@ void NRRCConfig(void) { paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - char aprefix[MAX_OPTNAME_SIZE*2 + 8]; - /* get global parameters, defined outside any section in the config file */ LOG_I(GNB_APP, "Getting GNBSParams\n"); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 860b73276c..a584305adc 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -468,7 +468,6 @@ int8_t nr_ue_decode_mib(module_id_t module_id, uint32_t number_of_search_space_per_slot=UINT_MAX; uint32_t first_symbol_index=UINT_MAX; uint32_t search_space_duration; // element of search space - uint32_t coreset_duration; // element of coreset // 38.213 table 10.1-1 /// MUX PATTERN 1 @@ -604,8 +603,8 @@ int8_t nr_ue_decode_mib(module_id_t module_id, } AssertFatal(number_of_search_space_per_slot!=UINT_MAX,""); - coreset_duration = num_symbols * number_of_search_space_per_slot; /* + uint32_t coreset_duration = num_symbols * number_of_search_space_per_slot; mac->type0_pdcch_dci_config.number_of_candidates[0] = table_38213_10_1_1_c2[0]; mac->type0_pdcch_dci_config.number_of_candidates[1] = table_38213_10_1_1_c2[1]; mac->type0_pdcch_dci_config.number_of_candidates[2] = table_38213_10_1_1_c2[2]; // CCE aggregation level = 4 diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index fba6610554..6675f07427 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -81,6 +81,7 @@ #include "SIMULATION/TOOLS/sim.h" // for taus #include "executables/softmodem-common.h" +#include //#define XER_PRINT From 29f984a60abb649e56dfe541555ea6ee34272a86 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Mon, 4 May 2020 16:16:27 +0200 Subject: [PATCH 169/175] CI: fix missing class member for EPC Signed-off-by: Raphael Defosseux --- ci-scripts/epc.py | 3 +++ ci-scripts/main.py | 1 + 2 files changed, 4 insertions(+) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 4926f2d6e8..3a52a6118c 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -62,6 +62,7 @@ class EPCManagement(): self.Type = '' self.PcapFileName = '' self.htmlObj = None + self.testCase_id = '' #----------------------------------------------------------- # Setter and Getters on Public Members @@ -89,6 +90,8 @@ class EPCManagement(): return self.Type def SetHtmlObj(self, obj): self.htmlObj = obj + def SetTestCase_id(self, idx): + self.testCase_id = idx #----------------------------------------------------------- # EPC management functions diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 1e149c4050..36d6a16d17 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -3583,6 +3583,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re continue CiTestObj.testCase_id = id HTML.SettestCase_id(CiTestObj.testCase_id) + EPC.SetTestCase_id(CiTestObj.testCase_id) CiTestObj.desc = test.findtext('desc') HTML.Setdesc(CiTestObj.desc) action = test.findtext('class') From ae5a1e4131d7d520dd154683fa9b6deebb89fa3a Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Mon, 4 May 2020 16:19:04 +0200 Subject: [PATCH 170/175] CI: fix unresolved merge conflicts Signed-off-by: Raphael Defosseux --- .../inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml index 8116b9dcdf..22f8b63266 100644 --- a/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml +++ b/ci-scripts/xml_files/inria/enb_usrp210_band7_x2_ho_test_05Mhz_tm1.xml @@ -72,11 +72,7 @@ Initialize_eNB Initialize eNB #1 (FDD/Band7/5MHz) -<<<<<<< HEAD - -O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes --eNBs.[0].target_enb_x2_ip_address.[0].ipv4 CI_RCC_IP_ADDR --eNBs.[0].target_enb_x2_ip_address.[0].preference ipv4 --eNBs.[0].eNB_ID 0xe01 --eNBs.[0].component_carriers.[0].Nid_cell 1 --eNBs.[0].nr_cellid 98765 -======= -O ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf --eNBs.[0].rrc_inactivity_threshold 0 --RUs.[0].max_rxgain 120 --eNBs.[0].component_carriers.[0].pusch_p0_Nominal -90 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96 --eNBs.[0].tracking_area_code 600 --eNBs.[0].plmn_list.[0].mnc 95 --THREAD_STRUCT.[0].parallel_config PARALLEL_RU_L1_TRX_SPLIT --eNBs.[0].enable_measurement_reports yes --eNBs.[0].enable_x2 yes --eNBs.[0].nr_cellid 98765 ->>>>>>> origin/develop_inria_ci_deployment 1 1 From 454139ac63f799963d66bded4d56c32a961f7e26 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 7 May 2020 16:34:53 +0200 Subject: [PATCH 171/175] CI: fix a few typos in python framework Signed-off-by: Raphael Defosseux --- ci-scripts/html.py | 7 +++++-- ci-scripts/main.py | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ci-scripts/html.py b/ci-scripts/html.py index 3d0c8f3897..1a6e3f8fdb 100644 --- a/ci-scripts/html.py +++ b/ci-scripts/html.py @@ -83,7 +83,7 @@ class HTMLManagement(): # Setters and Getters #----------------------------------------------------------- def SethtmlUEFailureMsg(self,huefa): - self.htmlUEFailureMsg = huefa + self.htmlUEFailureMsg = huefa def GethtmlUEFailureMsg(self): return self.htmlUEFailureMsg def SetHmleNBFailureMsg(self, msg): @@ -112,7 +112,10 @@ class HTMLManagement(): self.ranTargetBranch = tbranch def SethtmlUEConnected(self, nbUEs): - self.htmlUEConnected = nbUEs + if nbUEs > 0: + self.htmlUEConnected = nbUEs + else: + self.htmlUEConnected = 1 def SethtmlNb_Smartphones(self, nbUEs): self.htmlNb_Smartphones = nbUEs def SethtmlNb_CATM_Modules(self, nbUEs): diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 36d6a16d17..a01eed2ac5 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -86,7 +86,6 @@ class OaiCiTest(): self.UEDevicesRebootCmd = [] self.CatMDevices = [] self.UEIPAddresses = [] - self.htmlUEConnected = -1 self.idle_sleep_time = 0 self.x2_ho_options = 'network' self.x2NbENBs = 0 From 2a8dacc009865689275e7dcc83138926bd1588f9 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 7 May 2020 16:35:28 +0200 Subject: [PATCH 172/175] CI: better code guideline analysis -- check if C file has a GNU GPL license -- check if C file has s suspect license -- check if C header is having correct circular dependency protection (with Laurent Thomas's help) Signed-off-by: Raphael Defosseux --- ci-scripts/checkCodingFormattingRules.sh | 65 ++++++++++++++++++++++ ci-scripts/reportBuildLocally.sh | 71 ++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/ci-scripts/checkCodingFormattingRules.sh b/ci-scripts/checkCodingFormattingRules.sh index 6ac43ca19f..fb159d4da0 100755 --- a/ci-scripts/checkCodingFormattingRules.sh +++ b/ci-scripts/checkCodingFormattingRules.sh @@ -62,6 +62,30 @@ then NB_FILES_TO_FORMAT=`astyle --dry-run --options=ci-scripts/astyle-options.txt --recursive *.c *.h | grep -c Formatted ` echo "Nb Files that do NOT follow OAI rules: $NB_FILES_TO_FORMAT" echo $NB_FILES_TO_FORMAT > ./oai_rules_result.txt + + # Testing Circular Dependencies protection + awk '/#[ \t]*ifndef/ { gsub("^.*ifndef *",""); if (names[$1]!="") print "files with same {define ", FILENAME, names[$1]; names[$1]=FILENAME } /#[ \t]*define/ { gsub("^.*define *",""); if(names[$1]!=FILENAME) print "error in declaration", FILENAME, $1, names[$1]; nextfile }' `find openair* common targets executables -name *.h |grep -v LFDS` > header-files-w-incorrect-define.txt + + # Testing if explicit GNU GPL license banner + egrep -irl --exclude-dir=.git --include=*.cpp --include=*.c --include=*.h "General Public License" . > files-w-gnu-gpl-license-banner.txt + + # Looking at exotic/suspect banner + LIST_OF_FILES_W_BANNER=`egrep -irl --exclude-dir=.git --include=*.cpp --include=*.c --include=*.h "Copyright|copyleft" .` + if [ -f ./files-w-suspect-banner.txt ]; then rm -f ./files-w-suspect-banner.txt; fi + for FILE in $LIST_OF_FILES_W_BANNER + do + IS_NFAPI=`echo $FILE | egrep -c "nfapi/open-nFAPI|nfapi/oai_integration/vendor_ext"` + IS_OAI_LICENCE_PRESENT=`egrep -c "OAI Public License" $FILE` + IS_BSD_LICENCE_PRESENT=`egrep -c "the terms of the BSD Licence" $FILE` + IS_EXCEPTION=`echo $FILE | egrep -c "common/utils/collection/tree.h|common/utils/collection/queue.h|common/utils/itti_analyzer/common/queue.h|openair3/UTILS/tree.h|openair3/UTILS/queue.h"` + if [ $IS_OAI_LICENCE_PRESENT -eq 0 ] && [ $IS_BSD_LICENCE_PRESENT -eq 0 ] + then + if [ $IS_NFAPI -eq 0 ] && [ $IS_EXCEPTION -eq 0 ] + then + echo $FILE >> ./files-w-suspect-banner.txt + fi + fi + done exit 0 fi @@ -131,8 +155,25 @@ if [ -f oai_rules_result_list.txt ] then rm -f oai_rules_result_list.txt fi +if [ -f header-files-w-incorrect-define.txt ] +then + rm -f header-files-w-incorrect-define.txt +fi +if [ -f files-w-gnu-gpl-license-banner.txt ] +then + rm -f files-w-gnu-gpl-license-banner.txt +fi +if [ -f files-w-suspect-banner.txt ] +then + rm -f files-w-suspect-banner.txt +fi +awk '/#[ \t]*ifndef/ { gsub("^.*ifndef *",""); if (names[$1]!="") print "files with same {define ", FILENAME, names[$1]; names[$1]=FILENAME } /#[ \t]*define/ { gsub("^.*define *",""); if(names[$1]!=FILENAME) print "error in declaration", FILENAME, $1, names[$1]; nextfile }' `find openair* common targets executables -name *.h |grep -v LFDS` > header-files-w-incorrect-define-tmp.txt + for FULLFILE in $MODIFIED_FILES do + # sometimes, we remove files + if [ ! -f $FULLFILE ]; then continue; fi + filename=$(basename -- "$FULLFILE") EXT="${filename##*.}" if [ $EXT = "c" ] || [ $EXT = "h" ] || [ $EXT = "cpp" ] || [ $EXT = "hpp" ] @@ -144,8 +185,32 @@ do echo $FULLFILE echo $FULLFILE >> ./oai_rules_result_list.txt fi + # Testing if explicit GNU GPL license banner + egrep -i "General Public License" $FULLFILE >> files-w-gnu-gpl-license-banner.txt + # Looking at exotic/suspect banner + IS_BANNER=`egrep -i -c "Copyright|copyleft" $FULLFILE` + if [ $IS_BANNER -ne 0 ] + then + IS_NFAPI=`echo $FULLFILE | egrep -c "nfapi/open-nFAPI|nfapi/oai_integration/vendor_ext"` + IS_OAI_LICENCE_PRESENT=`egrep -c "OAI Public License" $FULLFILE` + IS_BSD_LICENCE_PRESENT=`egrep -c "the terms of the BSD Licence" $FULLFILE` + IS_EXCEPTION=`echo $FILE | egrep -c "common/utils/collection/tree.h|common/utils/collection/queue.h|common/utils/itti_analyzer/common/queue.h|openair3/UTILS/tree.h|openair3/UTILS/queue.h"` + if [ $IS_OAI_LICENCE_PRESENT -eq 0 ] && [ $IS_BSD_LICENCE_PRESENT -eq 0 ] + then + if [ $IS_NFAPI -eq 0 ] && [ $IS_EXCEPTION -eq 0 ] + then + echo $FILE >> ./files-w-suspect-banner.txt + fi + fi + fi + fi + # Testing Circular Dependencies protection + if [ $EXT = "h" ] || [ $EXT = "hpp" ] + then + grep $FULLFILE header-files-w-incorrect-define-tmp.txt >> header-files-w-incorrect-define.txt fi done +rm -f header-files-w-incorrect-define-tmp.txt echo "" echo " ----------------------------------------------------------" echo "Nb Files that do NOT follow OAI rules: $NB_TO_FORMAT" diff --git a/ci-scripts/reportBuildLocally.sh b/ci-scripts/reportBuildLocally.sh index 54372ac6ba..0a75ff25b7 100755 --- a/ci-scripts/reportBuildLocally.sh +++ b/ci-scripts/reportBuildLocally.sh @@ -492,6 +492,77 @@ function report_build { awk '{print " "$1""}' ./oai_rules_result_list.txt >> ./build_results.html echo " " >> ./build_results.html echo "

" >> ./build_results.html + echo "
" >> ./build_results.html + fi + if [ -f ./header-files-w-incorrect-define.txt ] + then + NB_FILES_IN_ERROR=`wc -l ./header-files-w-incorrect-define.txt | sed -e "s@ .*@@"` + if [ $NB_FILES_IN_ERROR -eq 0 ] + then + echo "
" >> ./build_results.html + if [ $MR_TRIG -eq 1 ]; then echo " No Issue for CIRCULAR DEPENDENCY PROTECTION in modified files" >> ./build_results.html; fi + if [ $PU_TRIG -eq 1 ]; then echo " No Issue for CIRCULAR DEPENDENCY PROTECTION in the whole repository" >> ./build_results.html; fi + echo "
" >> ./build_results.html + else + echo "
" >> ./build_results.html + if [ $MR_TRIG -eq 1 ]; then echo " ${NB_FILES_IN_ERROR} modified files MAY NOT HAVE CIRCULAR DEPENDENCY PROTECTION" >> ./build_results.html; fi + if [ $PU_TRIG -eq 1 ]; then echo " ${NB_FILES_IN_ERROR} files in repository MAY NOT HAVE CIRCULAR DEPENDENCY PROTECTION in the whole repository" >> ./build_results.html; fi + echo "
" >> ./build_results.html + echo " " >> ./build_results.html + echo "
" >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + awk '{if($0 ~/error in/){print " "};if($0 ~/files with same/){print " "}}' ./header-files-w-incorrect-define.txt >> ./build_results.html + echo "
Potential IssueImpacted FileIncorrect Macro
error in declaration"$4""$5"
files with same #define"$5""$6"
" >> ./build_results.html + echo "
" >> ./build_results.html + echo "
" >> ./build_results.html + fi + fi + if [ -f ./files-w-gnu-gpl-license-banner.txt ] + then + NB_FILES_IN_ERROR=`wc -l ./files-w-gnu-gpl-license-banner.txt | sed -e "s@ .*@@"` + if [ $NB_FILES_IN_ERROR -ne 0 ] + then + echo "
" >> ./build_results.html + if [ $MR_TRIG -eq 1 ]; then echo " ${NB_FILES_IN_ERROR} modified files HAVE a GNU GPL license banner" >> ./build_results.html; fi + if [ $PU_TRIG -eq 1 ]; then echo " ${NB_FILES_IN_ERROR} files in repository HAVE a GNU GPL license banner" >> ./build_results.html; fi + echo "
" >> ./build_results.html + echo " " >> ./build_results.html + echo "
" >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + awk '{print " "}' ./files-w-gnu-gpl-license-banner.txt >> ./build_results.html + echo "
Filename
"$1"
" >> ./build_results.html + echo "
" >> ./build_results.html + echo "
" >> ./build_results.html + fi + fi + if [ -f ./files-w-suspect-banner.txt ] + then + NB_FILES_IN_ERROR=`wc -l ./files-w-suspect-banner.txt | sed -e "s@ .*@@"` + if [ $NB_FILES_IN_ERROR -ne 0 ] + then + echo "
" >> ./build_results.html + if [ $MR_TRIG -eq 1 ]; then echo " ${NB_FILES_IN_ERROR} modified files HAVE a suspect license banner" >> ./build_results.html; fi + if [ $PU_TRIG -eq 1 ]; then echo " ${NB_FILES_IN_ERROR} files in repository HAVE a suspect license banner" >> ./build_results.html; fi + echo "
" >> ./build_results.html + echo " " >> ./build_results.html + echo "
" >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + echo " " >> ./build_results.html + awk '{print " "}' ././files-w-suspect-banner.txt >> ./build_results.html + echo "
Filename
"$1"
" >> ./build_results.html + echo "
" >> ./build_results.html + echo "
" >> ./build_results.html + fi fi fi From bca9ecfd3cb028b92d6f0d191385394ba8d2e4a6 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 7 May 2020 16:38:00 +0200 Subject: [PATCH 173/175] add missing circular dependency protection Signed-off-by: Raphael Defosseux --- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index 510abb8373..a2446dccf9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -29,6 +29,9 @@ * \note * \warning */ +#ifndef __PUCCH_NR__H__ +#define __PUCCH_NR__H__ + //#include "PHY/defs.h" #include "PHY/impl_defs_nr.h" #include "PHY/defs_nr_common.h" @@ -417,3 +420,4 @@ void nr_generate_pucch3_4(PHY_VARS_NR_UE *ue, 73, 79, 83, 89, 97, 101,103,107,109,113, 127,131,137,139,149,151,157,163,167,173, 179,181,191,193,197,199}; +#endif From 21a2a8c6e139659dd859f1e7dc93c2a956d241f9 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 7 May 2020 18:00:21 +0200 Subject: [PATCH 174/175] rlc v2: some fixes for 'bugs' found by coverity scan Minor fixes, doesn't change anything. Not sure these are 'bugs' either, but let's be polite with coverity scan... One thing was not changed. Coverity scan says: *** CID 357991: Memory - illegal accesses (USE_AFTER_FREE) /home/carabe/raphael/openairinterface5g/openair2/LAYER2/rlc_v2/rlc_entity_am.c: 507 in tx_list_remove_sn() 501 } else { 502 prev = cur; 503 cur = cur->next; 504 } 505 } 506 >>> CID 357991: Memory - illegal accesses (USE_AFTER_FREE) >>> Using freed pointer "head.next". 507 return head.next; 508 } 509 510 void cleanup_sdu_list(rlc_entity_am_t *entity) 511 { 512 rlc_sdu_t head; But as far as I understand, there is no problem. We don't access head.next at all if it has been freed. Or is there some aliasing going on there (pointer aliasing)? I doubt it. False positive? --- openair2/LAYER2/rlc_v2/rlc_entity_um.c | 1 + openair2/LAYER2/rlc_v2/rlc_oai_api.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_um.c b/openair2/LAYER2/rlc_v2/rlc_entity_um.c index f0fe33789b..54707875a0 100644 --- a/openair2/LAYER2/rlc_v2/rlc_entity_um.c +++ b/openair2/LAYER2/rlc_v2/rlc_entity_um.c @@ -360,6 +360,7 @@ static tx_pdu_size_t tx_pdu_size(rlc_entity_um_t *entity, int maxsize) ret.data_size = 0; ret.header_size = 0; ret.last_sdu_is_full = 1; + ret.first_sdu_length = 0; /* TX PDU - let's make the biggest PDU we can with the SDUs we have */ sdu_count = 0; diff --git a/openair2/LAYER2/rlc_v2/rlc_oai_api.c b/openair2/LAYER2/rlc_v2/rlc_oai_api.c index c81cc6ff5e..bd3eebe635 100644 --- a/openair2/LAYER2/rlc_v2/rlc_oai_api.c +++ b/openair2/LAYER2/rlc_v2/rlc_oai_api.c @@ -134,7 +134,10 @@ tbs_size_t mac_rlc_data_req( } if (MBMS_flagP == MBMS_FLAG_YES) { - rb = ue->drb[channel_idP - 1]; + if (channel_idP >= 1 && channel_idP <= 5) + rb = ue->drb[channel_idP - 1]; + else + rb = NULL; } @@ -192,7 +195,10 @@ mac_rlc_status_resp_t mac_rlc_status_ind( } if (MBMS_flagP == MBMS_FLAG_YES) { - rb = ue->drb[channel_idP - 1]; + if (channel_idP >= 1 && channel_idP <= 5) + rb = ue->drb[channel_idP - 1]; + else + rb = NULL; } if (rb != NULL) { @@ -316,7 +322,9 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, if (rb_idP >= 1 && rb_idP <= 5) rb = ue->drb[rb_idP - 1]; } + if( MBMS_flagP == MBMS_FLAG_YES) { + if (rb_idP >= 1 && rb_idP <= 5) rb = ue->drb[rb_idP - 1]; } @@ -875,12 +883,19 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP mbms_service_id = MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2]; //serviceId is 3-octet string // mbms_service_id = j; +#if 0 + /* TODO: check if this code should stay there + * as it is both enb and ue cases do the same thing + */ // can set the mch_id = i if (ctxt_pP->enb_flag) { drb_id = (mbms_service_id * LTE_maxSessionPerPMCH ) + mbms_session_id;//+ (LTE_maxDRB + 3) * MAX_MOBILES_PER_ENB; // 1 } else { drb_id = (mbms_service_id * LTE_maxSessionPerPMCH ) + mbms_session_id; // + (LTE_maxDRB + 3); // 15 } +#endif + + drb_id = (mbms_service_id * LTE_maxSessionPerPMCH ) + mbms_session_id; LOG_I(RLC, PROTOCOL_CTXT_FMT" CONFIG REQ MBMS ASN1 LC ID %u RB ID %u SESSION ID %u SERVICE ID %u, mbms_rnti %x\n", PROTOCOL_CTXT_ARGS(ctxt_pP), From 301ea42482f4abc523e1dc183e1c4f9233b8d76a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sat, 9 May 2020 10:12:38 +0200 Subject: [PATCH 175/175] hotfix: fix compilation of UE with --musim The following was failing: ./build_oai --UE --musim Not sure this fix is correct, but it seems consistent with the rest of platform_constants.h. --- openair2/COMMON/platform_constants.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h index 7a7e984aca..1eb58b16b2 100644 --- a/openair2/COMMON/platform_constants.h +++ b/openair2/COMMON/platform_constants.h @@ -73,7 +73,9 @@ #ifdef UESIM_EXPANSION #define MAX_MOBILES_PER_ENB 256 #define MAX_MOBILES_PER_ENB_NB_IoT 256 + #define MAX_MOBILES_PER_GNB 256 #define MAX_eNB 2 + #define MAX_gNB 2 #else #ifdef LARGE_SCALE #define MAX_MOBILES_PER_ENB 128