ubuntu 16.04系统LimeSDR V1.4使用最新版本的OpenAirInterface5g代码搭建LTE实验环境

注意,最新开发版本的代码不稳定,存在问题,以下的仅仅是记录自己的操作过程,代码并不能正常工作。正常使用的话,请不要使用如下的版本操作。

参考ubuntu 16.04系统LimeSDR V1.4使用OpenAirInterface搭建LTE实验环境,并参考 解决ubuntu 16.04系统上2017.06版本之后的LimeSDR V1.4驱动不能正常运行OpenAirInterface搭建的LTE实验环境的问题使用最新的LimeSDR驱动能正常进行LTE实验之后,我们开始尝试把OpenAirInterface的代码更新到最新版本(2018_w15),新版本的代码结构更加清晰,但是不可用

$ cd ~

$ cd openairinterface5g

$ rm -rf *

$ git checkout develop

$ git pull

#对于国内的用户来说,国外的几个代码地址需要修改一下,否则会出现无法下载或者下载非常慢的情况
$ sed -i "s/git clone https:\/\/gist.github.com\/2190472.git \/opt\/ssh/wget https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/03\/ssh.tar.gz \&\& sudo tar -zxvf ssh.tar.gz -C \/opt/g" cmake_targets/tools/build_helper
 
$ sed -i "s/git clone https:\/\/gitlab.eurecom.fr\/oai\/asn1c.git \/tmp\/asn1c/wget https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/03\/asn1c.tar.gz \&\& tar -zxvf asn1c.tar.gz -C \/tmp/g" cmake_targets/tools/build_helper
 
$ sed -i "s/https:\/\/pypi.python.org\/packages\/18\/fa\/dd13d4910aea339c0bb87d2b3838d8fd923c11869b1f6e741dbd0ff3bc00\/netifaces-0.10.4.tar.gz/https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/03\/netifaces-0.10.4.tar.gz/g" cmake_targets/tools/build_helper
 
$ sed -i "s/https:\/\/github.com\/google\/protobuf\/releases\/download\/v3.3.0\/protobuf-cpp-3.3.0.tar.gz/https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/04\/protobuf-cpp-3.3.0.tar.gz/g" cmake_targets/tools/build_helper
 
$ sed -i "s/git clone https:\/\/github.com\/protobuf-c\/protobuf-c.git/wget https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/03\/protobuf-c.tar.gz \&\& tar -zxvf protobuf-c.tar.gz/g" cmake_targets/tools/build_helper
 
#修正兼容问题,更高版本的protobuf-c跟我们上面安装的版本不匹配,会导致编译错误
$ sed -i "s/cd protobuf-c/cd protobuf-c \&\& git checkout 2a46af42784abf86804d536f6e0122d47cfeea45/g" cmake_targets/tools/build_helper

# 如果使用最新版本的limesdr驱动已经修正了数据读取的BUG,不需要丢弃第一次的报文,我们需要
# 阻止第一个报文的丢弃,否则数据读取是错误的
$ sed -r -i "s/first_rx[ \t]*=[ \t]*1;/first_rx = 0;/g" targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp

#执行编译
$ source oaienv  
 
$ ./cmake_targets/build_oai -I       # install SW packages from internet
 
# ./cmake_targets/build_oai  -w USRP --eNB -t ETHERNET# compile eNB
# 注意如果后续重新编译过limesdr的驱动,这部分也需要重新编译
 
$ ./cmake_targets/build_oai -c -w LMSSDR --eNB -x

接下来就是创建LimeSDR的启动配置文件(从enb.band7.tm1.50PRB.usrpb210.conf修改而来):

$ vim targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.25PRB.lmssdr.conf

里面的内容如下:

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";

    mobile_country_code =  "208";

    mobile_network_code =  "92";

    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                 			      = 25;
      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             			      = 32;
      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";
      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;
      }
    );


    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";
                            }
                          );

    NETWORK_INTERFACES :
    {

        ENB_INTERFACE_NAME_FOR_S1_MME            = "lo";
        ENB_IPV4_ADDRESS_FOR_S1_MME              = "127.0.0.10/8";
        ENB_INTERFACE_NAME_FOR_S1U               = "lo";
        ENB_IPV4_ADDRESS_FOR_S1U                 = "127.0.0.10/8";
        ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
    };
  }
);

MACRLCs = (
	{
	num_cc = 1;
	tr_s_preference = "local_L1";
	tr_n_preference = "local_RRC";
	phy_test_mode = 1;
        }  
);

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                    = 125;
         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";
};

     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";
    };

另外,最新版本运行的时候如果增加-d参数,启动图形界面,程序会崩溃。目前这个版本可以运行,但是貌似会导致LimeSDR驱动数据发送异常,目前已知,这个版本的驱动没有正确的读取配置文件,导致给硬件的配置信息是错误的,暂时这个版本还不可用。

ubuntu 16.04使用rssh配置rsync服务通过ssh同步

  • 安装配置RSSH为数据同步进行准备
$ sudo apt-get install rsync

# ubuntu 16.04/18.04默认源中都存在rssh ,但是 ubuntu 20.04开始,已经没办法从系统源中安装了。
# 原因在于 rssh 存在安全漏洞,并且长时间没有修复,并且已经没人维护了,需要使用 rrsync 替代。

$ sudo apt-get install rssh

$ export RSH_RSYNC_USER=rsh_backup

$ export RSH_RSYNC_USER_PASSWORD=rsh_password

# 如果需要备份/var/log 目录,建议把用户组设置成 adm 用户组,否则很多日志没办法读取
# sudo useradd -s /usr/bin/rssh $RSH_RSYNC_USER -g users -G adm
# 后期也可以通过 sudo usermod -g users -G adm $RSH_RSYNC_USER 更改用户组

$ sudo useradd -s /usr/bin/rssh $RSH_RSYNC_USER

$ echo $RSH_RSYNC_USER:$RSH_RSYNC_USER_PASSWORD | sudo chpasswd

# 配置文件中的umask可以限制用户是否只读,是否有可执行权限

# 许可用户执行rsync操作
$ sudo sed -i "s/^#allowrsync$/allowrsync/g" /etc/rssh.conf

# 增加许可的用户操作
$ sudo sed -i '$a\user = \"'$RSH_RSYNC_USER':011:100000:\"' /etc/rssh.conf

# 在ubuntu 16.04上 通过 setfacl 给予同步用户某些特殊目录读取权限的方式,目前测试来看会出现很多问题
# 如果是自建的目录,这个操作是没问题的,但是对于系统目录,比如/var/log/ 这个工具会导致
# mysql,tomcat等软件工作异常。
# 我需要备份日志,因此需要给予日志目录读取权限,注意,我们需要给予执行权限,
# 否则没办法同步,尽管我们只需要读取数据
# 如果我们只给予 r 权限 会导致报告如下错误 
# rsync: readlink_stat("/data/log/denyhosts.3.gz") failed: Permission denied (13)
# 我们的 /data/log 实际上上/var/log目录的一个软连接,内部文件权限复杂,因此需要特殊处理
# ubuntu 16.04 不要使用 
# sudo apt-get install acl && sudo setfacl -m u:$RSH_RSYNC_USER:r-x -R -L /data/log/ 
# 这个工具存在 BUG,可能设置的时候正常,过一段时间,就出现问题了。
# 还是老的 chmod 工作稳定,rsync 需要读取+执行权限,才能同步文件,
# 因此设置为 755 设置为 645的时候 mysql/tomcat8工作不正常
$ sudo chmod -R 755 /data/log
  • 客户端同步,测试是否正常工作
$ export RSH_RSYNC_USER=rsh_backup 

$ export RSH_RSYNC_USER_PASSWORD=rsh_password

$ export RSH_RSYNC_PORT=22

$ export REMOTE_SERVER=www.mobibrw.com

$ export SYNC_DIR=/var/www

# 测试是否可以正常工作,另一个方面是许可ssh的登录key否则我们后续没办法使用sshpass
# 可以使用 --exclude 参数忽略指定的目录,相对路径,不是绝对路径
$ sudo rsync -avzP --delete -e 'ssh -p $RSH_RSYNC_PORT' $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_DIR $SYNC_DIR
  • 转化为定时任务,自动同步
# 安装密码自动填写软件
$ sudo apt-get install sshpass

$ cd ~

$ touch backup_rsync.sh

$ chmod +x backup_rsync.sh

$ echo -e '#!'"/bin/bash\n" >> backup_rsync.sh

$ sed -i '$a\export RSH_RSYNC_USER=rsh_backup' backup_rsync.sh

$ sed -i '$a\export RSH_RSYNC_USER_PASSWORD=rsh_password' backup_rsync.sh

$ sed -i '$a\export RSH_RSYNC_PORT=22' backup_rsync.sh

$ sed -i '$a\export REMOTE_SERVER=www.mobibrw.com' backup_rsync.sh

# 此处注意最后的分隔符/如果没有这个分隔符,会导致目标目录多一个名为www的父目录
$ sed -i '$a\export SYNC_DIR=/var/www/' backup_rsync.sh

# 可以使用 --exclude 参数忽略指定的目录,相对路径,不是绝对路径
$ sed -i '$a\sshpass -p $RSH_RSYNC_USER_PASSWORD rsync -avzP --delete -e \"ssh -p $RSH_RSYNC_PORT\" $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_DIR $SYNC_DIR' backup_rsync.sh

# 打开计划任务的日志,默认不开
$ sudo sed -i -r "s/#cron\.\*[ \t]*\/var\/log\/cron.log/cron.*                         \/var\/log\/cron.log/g" /etc/rsyslog.d/50-default.conf

#write out current crontab
$ sudo crontab -l > addcron

#echo new cron into cron file ,每隔30分钟我们调度一次任务,前面是文件锁,防止并发冲突
#如果需要每小时执行一次,则修改为 "* */1 * * * flock ...."
#如果需要凌晨2点执行,则修改为 "* 2 * * * flock ...."
$ echo "30 * * * * flock -x -w 10 /dev/shm/backup_rsync_corn.lock -c \"bash `echo ~`/backup_rsync.sh\"" >> addcron

#install new cron file
$ sudo crontab addcron

$ rm addcron

$ sudo service cron restart

目前我的阿里云,腾讯云服务器之间的同步脚本如下:

#!/bin/bash

export RSH_RSYNC_USER=user
export RSH_RSYNC_USER_PASSWORD=password
export RSH_RSYNC_PORT=22
export REMOTE_SERVER=121.199.27.227

export SYNC_WWW_DIR=/var/www/

sshpass -p $RSH_RSYNC_USER_PASSWORD rsync -avzP --delete -e "ssh -p $RSH_RSYNC_PORT" $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_WWW_DIR $SYNC_WWW_DIR --exclude "wordpress/wp-content/cache/" --exclude "wordpress/wp-content/plugins/crayon-syntax-highlighter/log.txt"

export SYNC_DATA_DIR=/data/
 
# 此处注意,如果使用 --exclude "/root/" 则忽略最顶部的root目录
# 如果使用 --exclude "root/" 则忽略所有路径中包含 root 的目录
# 主要 rsync 的 top-directroty 部分的规则
sshpass -p $RSH_RSYNC_USER_PASSWORD rsync -avzP --delete -e "ssh -p $RSH_RSYNC_PORT" $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_DATA_DIR $RSYNC_DATA_DIR --exclude "/root/"

参考链接


OpenAirInterface使用LimeSDR代码分析PHY层流程

参考ubuntu 16.04系统LimeSDR V1.4使用OpenAirInterface搭建LTE实验环境建立完成的环境。

代码为当时的代码,不是最新的代码。

数据接收流向


RF处理线程
targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp
int trx_lms_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int antenna_id)-> targets/RT/USER/lte-enb.c
void rx_rf(PHY_VARS_eNB *eNB,int *frame,int *subframe) (eNB->rfdevice.trx_read_func

->

targets/RT/USER/lte-enb.c
static void* eNB_thread_FH( void* param ) (eNB->rx_fh

接收完成后,触发信号,通知后续线程,也就是后面的发送接收线程。

eNB收发处理线程

targets/RT/USER/lte-enb.c
static void* eNB_thread_rxtx( void* param )

->

targets/RT/USER/lte-enb.c
static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) (eNB->proc_uespec_rx(eNB, proc, no_relay ))

->

openair1/SCHED/phy_procedures_lte_eNb.c
void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *phy_vars_eNB,eNB_rxtx_proc_t *proc,relaying_type_t r_type)

->

openair1/SCHED/phy_procedures_lte_eNb.c
void pucch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid,uint8_t do_srs)

->

此处实际的解码,涉及到相位信息,这部分是PUCCH部分的数据,主要是通信控制数据,比如信噪比等,不包含实际的通信数据,比如TCP,UDP协议等等

openair1/PHY/LTE_TRANSPORT/pucch.c
uint32_t rx_pucch(PHY_VARS_eNB *phy_vars_eNB,
PUCCH_FMT_t fmt,
uint8_t UE_id,
uint16_t n1_pucch,
uint16_t n2_pucch,
uint8_t shortened_format,
uint8_t *payload,
int frame,
uint8_t subframe,
uint8_t pucch1_thres)

->
此处实际的解码,涉及到相位信息,实际的通信数据,比如TCP,UDP协议等等

openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c
unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,
uint8_t UE_id,
uint8_t control_only_flag,
uint8_t Nbundled,
uint8_t llr8_flag) ( eNB->td

->

此处解析数据段,TCP,IP相关部分了

openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c
int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag)

解码后的数据通过rx_sdu函数上报到MAC层。

IQ信号

当前的数字射频芯片,无一例外的用到了I/Q信号,就算是RFID芯片,内部也用到了I/Q信号,然而绝大部分射频人员,对于IQ的了解除了名字之外,基本上一无所知。I/Q信号一般是模拟的。也有数字的比如方波。基带内处理的一般是数字信号,在出口处都要进行D/A(数—>模)转换,每个基带的结构图里都有,可以仔细看。

网上有大量关于IQ信号的资料,但都是公式一大堆,什么四相图,八相图之类的,最后还是不明白,除了知道这两个名次解释:

I:in-phase 表示同相
Q:quadrature 表示正交,与I相位差90度。

继续阅读IQ信号

hosts.allow、hosts.deny配置不生效的解决方法

通过配置hosts.allow、hosts.deny,控制SSH限制固定IP登陆

按照以往的方法,分别在hosts.allow、hosts.deny加入以下配置

# more /etc/hosts.allow

sshd:192.168.x.x

# more /etc/hosts.deny

sshd:all

保存后测试,发现配置无效,其他IP还是可以登陆成功。

解决方法如下:

hosts.allow和hosts.deny属于tcp_Wrappers防火墙的配置文件,而用tcp_Wrappers防火墙控制某一服务访问策略的前提是,该服务支持tcp_Wrappers防火墙,即该服务应用了libwrapped库文件。

查看某服务(如ssh)是否应用了libwrapped库文件的方法是:

$ ldd /usr/sbin/sshd |grep libwrap.so.0

没有显示,表示此服务器上安装的SSH没有应用libwrapped库文件,也就不能用tcp_Wrappers防火墙控制访问策略。(一般情况下服务器默认安装的SSH都是支持libwrapped库文件,这台服务器不清楚为什么不支持)

最终解决方法是重新安装SSH。

$ yum -y remove openssh

$ yum -y install openssh

$ yum -y install openssh-server

安装完成后再次查看是否应用了libwrapped库文件,显示支持。

$ ldd /usr/sbin/sshd |grep libwrap.so.0
	libwrap.so.0 => /lib/x86_64-linux-gnu/libwrap.so.0 (0x00007f195feb4000)

再测试SSH登陆,配置生效。

参考链接


hosts.allow、hosts.deny配置不生效的解决方法