Commit c72696c5 authored by wujing's avatar wujing

merge OAI develop_2019_w04

parents 63dda4aa f7938a4b
job1:
script:
- date
- pwd
- echo $OAI_TEST_CASE_GROUP
- echo $MACHINELIST
- echo $MACHINELISTGENERIC
- echo $RESULT_DIR
- echo $NRUNS_LTE_SOFTMODEM
- source oaienv
- rm -rf cmake_targets/autotests/log
- mkdir cmake_targets/autotests/log
- cd cmake_targets/autotests/v2
- python main.py
- date
only:
- triggers
......@@ -9,26 +9,36 @@ Please see NOTICE.txt for third party software that is included in the sources.
The OpenAirInterface (OAI) software is composed of the following parts:
openairinterface5g
├── cmake_targets: build utilities to compile (simulation, emulation and real-time platforms), and generated build files
├── common : some common OAI utilities, other tools can be found at openair2/UTILS
├── ci-scripts: Meta-scripts used by the OSA CI process. Contains also configuration files used day-to-day by CI.
├── cmake_targets: Build utilities to compile (simulation, emulation and real-time platforms), and generated build files
├── common : Some common OAI utilities, other tools can be found at openair2/UTILS
├── doc : Contains an up-to-date feature set list
├── LICENSE
├── maketags : script to generate emacs tags
├── openair1 : 3GPP LTE Rel-10 PHY layer + PHY RF simulation and a subset of Rel 12 Features.
├── openair2 :3GPP LTE Rel-10 RLC/MAC/PDCP/RRC/X2AP implementation.
├── maketags : Script to generate emacs tags
├── nfapi : Contains the NFAPI code. A local Readme file provides more details.
├── openair1 : 3GPP LTE Rel-10/12 PHY layer + PHY RF simulation. A local Readme file provides more details.
├── openair2 : 3GPP LTE Rel-10 RLC/MAC/PDCP/RRC/X2AP implementation.
├── COMMON
├── DOCS
├── ENB_APP
├── LAYER2/RLC/ with the following subdirectories: UM_v9.3.0, TM_v9.3.0, and AM_v9.3.0.
├── LAYER2/PDCP/PDCP_v10.1.0.
├── RRC/LITE
├── NETWORK_DRIVER
├── PHY_INTERFACE
├── RRC/LITE
├── UTIL
├── X2AP
├── ENB_APP
├── openair3: 3GPP LTE Rel10 for S1AP, NAS GTPV1-U for both ENB and UE.
├── COMMON
├── DOCS
├── GTPV1-U
├── NAS
├── S1AP
├── SCTP
├── SECU
├── UDP
└── targets: top level wrapper for unitary simulation for PHY channels, system-level emulation (eNB-UE with and without S1), and realtime eNB and UE and RRH GW.
├── UTILS
└── targets: Top-level wrappers for unitary simulation for PHY channels, system-level emulation (eNB-UE with and without S1), and realtime eNB and UE and RRH GW.
RELEASE NOTES:
......@@ -44,3 +54,10 @@ v0.6 -> RRH functionality, UE greatly improved, better TDD support,
a lot of bugs fixed. WARNING: oaisim in PHY abstraction mode does not
work, you need to use v0.5.2 for that.
v0.6.1 -> Mostly bugfixes. This is the last version without NFAPI.
v1.0.0 -> January 2019. This version first implements the architectural split described in doc/oai_lte_enb_func_split_arch.png picture.
Only FAPI, nFAPI and IF4.5 interfaces are implemented.
Repository tree structure prepares future integrations of features such as LTE-M, nbIOT or 5G-NR.
Preliminary X2 support has been implemented.
S1-flex has been introduced.
New tools: config library, telnet server, ...
A lot of bugfixes and a proper automated Continuous Integration process validates contributions.
This diff is collapsed.
......@@ -187,8 +187,12 @@ pipeline {
]) {
sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${testXMLFile}"
}
<<<<<<< HEAD
} catch (Exception e) {
currentBuild.result = 'FAILURE'
=======
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
>>>>>>> develop_integration_2019_w04
}
}
}
......
......@@ -201,8 +201,8 @@ MACRLCs = (
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
......@@ -228,6 +228,15 @@ RUs = (
}
);
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_ENABLE";
}
);
NETWORK_CONTROLLER :
{
FLEXRAN_ENABLED = "no";
......
......@@ -201,8 +201,8 @@ MACRLCs = (
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
......@@ -222,12 +222,21 @@ RUs = (
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 115;
max_rxgain = 125;
eNB_instances = [0];
}
);
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_ENABLE";
}
);
NETWORK_CONTROLLER :
{
FLEXRAN_ENABLED = "no";
......
......@@ -201,8 +201,8 @@ MACRLCs = (
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
......@@ -222,12 +222,21 @@ RUs = (
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 115;
max_rxgain = 120;
eNB_instances = [0];
}
);
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_ENABLE";
}
);
NETWORK_CONTROLLER :
{
FLEXRAN_ENABLED = "no";
......
......@@ -200,8 +200,8 @@ MACRLCs = (
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
......@@ -234,7 +234,7 @@ RUs = (
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
......
......@@ -200,8 +200,8 @@ MACRLCs = (
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
......@@ -234,7 +234,7 @@ RUs = (
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
......
......@@ -200,8 +200,8 @@ MACRLCs = (
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
puSch10xSnr = 160;
puCch10xSnr = 160;
}
);
......@@ -234,7 +234,7 @@ RUs = (
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
......
This diff is collapsed.
......@@ -20,7 +20,7 @@ RUs = (
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
......
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 ="medium";
rlc_log_level ="info";
rlc_log_verbosity ="medium";
pdcp_log_level ="info";
pdcp_log_verbosity ="medium";
rrc_log_level ="info";
rrc_log_verbosity ="full";
};
L1s = (
{
num_cc = 1;
tr_n_preference = "nfapi";
local_n_if_name = "lo";
remote_n_address = "127.0.0.2";
local_n_address = "127.0.0.1";
local_n_portc = 50000;
remote_n_portc = 50001;
local_n_portd = 50010;
remote_n_portd = 50011;
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 90
att_rx = 0;
bands = [7,38,42,43];
max_pdschReferenceSignalPower = -27;
max_rxgain = 125;
}
);
This diff is collapsed.
......@@ -40,6 +40,7 @@ function variant_usage {
echo " --variant cppcheck OR -v4"
echo " --variant enb-ethernet OR -v7"
echo " --variant ue-ethernet OR -v8"
echo " --variant l2-sim OR -v9"
echo " --variant flexran-rtc OR -v10"
}
......@@ -285,6 +286,18 @@ case $key in
NBARGS=$[$NBARGS+256]
shift
;;
-v9)
VM_NAME=ci-l2-sim
VM_MEMORY=8192
VM_CPU=8
ARCHIVES_LOC=l2_sim
LOG_PATTERN=.Rel14.txt
NB_PATTERN_FILES=4
BUILD_OPTIONS="--eNB -t ETHERNET"
RUN_OPTIONS="complex"
NBARGS=$[$NBARGS+256]
shift
;;
-v10)
VM_NAME=ci-flexran-rtc
ARCHIVES_LOC=flexran
......@@ -350,6 +363,17 @@ case $key in
BUILD_OPTIONS="--UE -t ETHERNET --noS1"
NBARGS=$[$NBARGS+256]
;;
l2-sim)
VM_NAME=ci-l2-sim
VM_MEMORY=8192
VM_CPU=8
ARCHIVES_LOC=l2_sim
LOG_PATTERN=.Rel14.txt
NB_PATTERN_FILES=4
BUILD_OPTIONS="--eNB -t ETHERNET"
RUN_OPTIONS="complex"
NBARGS=$[$NBARGS+256]
;;
flexran-rtc)
VM_NAME=ci-flexran-rtc
ARCHIVES_LOC=flexran
......
......@@ -504,6 +504,130 @@ then
done
fi
ARCHIVES_LOC=archives/l2_sim/test
if [ -d $ARCHIVES_LOC ]
then
echo " <h3>L2-NFAPI Simulator Check</h3>" >> ./test_simulator_results.html
if [ -f $ARCHIVES_LOC/test_final_status.log ]
then
if [ `grep -c TEST_OK $ARCHIVES_LOC/test_final_status.log` -eq 1 ]
then
echo " <div class=\"alert alert-success\">" >> ./test_simulator_results.html
echo " <strong>TEST was SUCCESSFUL <span class=\"glyphicon glyphicon-ok-circle\"></span></strong>" >> ./test_simulator_results.html
echo " </div>" >> ./test_simulator_results.html
else
echo " <div class=\"alert alert-danger\">" >> ./test_simulator_results.html
echo " <strong>TEST was a FAILURE! <span class=\"glyphicon glyphicon-ban-circle\"></span></strong>" >> ./test_simulator_results.html
echo " </div>" >> ./test_simulator_results.html
fi
else
echo " <div class=\"alert alert-danger\">" >> ./test_simulator_results.html
echo " <strong>COULD NOT DETERMINE TEST FINAL STATUS! <span class=\"glyphicon glyphicon-ban-circle\"></span></strong>" >> ./test_simulator_results.html
echo " </div>" >> ./test_simulator_results.html
fi
echo " <button data-toggle=\"collapse\" data-target=\"#oai-l2-sim-test-details\">More details on L2-NFAPI Simulator test results</button>" >> ./test_simulator_results.html
echo " <div id=\"oai-l2-sim-test-details\" class=\"collapse\">" >> ./test_simulator_results.html
echo " <table border = \"1\">" >> ./test_simulator_results.html
echo " <tr bgcolor = \"#33CCFF\" >" >> ./test_simulator_results.html
echo " <th>Log File Name</th>" >> ./test_simulator_results.html
echo " <th>Command</th>" >> ./test_simulator_results.html
echo " <th>Status</th>" >> ./test_simulator_results.html
echo " <th>Statistics</th>" >> ./test_simulator_results.html
echo " </tr>" >> ./test_simulator_results.html
TRANS_MODES=("fdd")
BW_CASES=(05)
for TMODE in ${TRANS_MODES[@]}
do
for BW in ${BW_CASES[@]}
do
ENB_LOG=$ARCHIVES_LOC/${TMODE}_${BW}MHz_enb.log
UE_LOG=`echo $ENB_LOG | sed -e "s#enb#ue#"`
if [ -f $ENB_LOG ] && [ -f $UE_LOG ]
then
NAME_ENB=`echo $ENB_LOG | sed -e "s#$ARCHIVES_LOC/##"`
NAME_UE=`echo $UE_LOG | sed -e "s#$ARCHIVES_LOC/##"`
echo " <tr>" >> ./test_simulator_results.html
echo " <td>$NAME_ENB --- $NAME_UE</td>" >> ./test_simulator_results.html
echo " <td>N/A</td>" >> ./test_simulator_results.html
NB_ENB_GOT_SYNC=`egrep -c "got sync" $ENB_LOG`
NB_UE_GOT_SYNC=`egrep -c "got sync" $UE_LOG`
NB_ENB_SYNCED_WITH_UE=`egrep -c "Sending NFAPI_START_RESPONSE" $UE_LOG`
if [ $NB_ENB_GOT_SYNC -eq 1 ] && [ $NB_UE_GOT_SYNC -eq 3 ] && [ $NB_ENB_SYNCED_WITH_UE -eq 1 ]
then
echo " <td bgcolor = \"green\" >OK</td>" >> ./test_simulator_results.html
else
echo " <td bgcolor = \"red\" >KO</td>" >> ./test_simulator_results.html
fi
echo " <td><pre>" >> ./test_simulator_results.html
if [ $NB_ENB_GOT_SYNC -eq 1 ]
then
echo "<font color = \"blue\">- eNB --> got sync</font>" >> ./test_simulator_results.html
else
echo "<font color = \"red\"><b>- eNB NEVER got sync</b></font>" >> ./test_simulator_results.html
fi
if [ $NB_UE_GOT_SYNC -eq 3 ]
then
echo "<font color = \"blue\">- UE --> got sync</font>" >> ./test_simulator_results.html
else
echo "<font color = \"red\"><b>- UE NEVER got sync</b></font>" >> ./test_simulator_results.html
fi
if [ $NB_ENB_SYNCED_WITH_UE -eq 1 ]
then
echo "<font color = \"blue\">- UE attached to eNB</font>" >> ./test_simulator_results.html
else
echo "<font color = \"red\"><b>- UE NEVER attached to eNB</b></font>" >> ./test_simulator_results.html
fi
echo " </pre></td>" >> ./test_simulator_results.html
echo " </tr>" >> ./test_simulator_results.html
fi
PING_CASE=$ARCHIVES_LOC/${TMODE}_${BW}MHz_ping_epc.txt
if [ -f $PING_CASE ]
then
echo " <tr>" >> ./test_simulator_results.html
NAME=`echo $PING_CASE | sed -e "s#$ARCHIVES_LOC/##"`
echo " <td>$NAME</td>" >> ./test_simulator_results.html
CMD=`egrep "COMMAND IS" $PING_CASE | sed -e "s#COMMAND IS: ##"`
echo " <td>$CMD</td>" >> ./test_simulator_results.html
FILE_COMPLETE=`egrep -c "ping statistics" $PING_CASE`
if [ $FILE_COMPLETE -eq 0 ]
then
echo " <td bgcolor = \"red\" >KO</td>" >> ./test_simulator_results.html
echo " <td>N/A</td>" >> ./test_simulator_results.html
else
NB_TR_PACKETS=`egrep "packets transmitted" $PING_CASE | sed -e "s# packets transmitted.*##"`
NB_RC_PACKETS=`egrep "packets transmitted" $PING_CASE | sed -e "s#^.*packets transmitted, ##" -e "s# received,.*##"`
if [ $NB_TR_PACKETS -eq $NB_RC_PACKETS ]
then
echo " <td bgcolor = \"green\" >OK</td>" >> ./test_simulator_results.html
else
echo " <td bgcolor = \"red\" >KO</td>" >> ./test_simulator_results.html
fi
echo " <td>" >> ./test_simulator_results.html
echo " <pre>" >> ./test_simulator_results.html
STATS=`egrep "packets transmitted" $PING_CASE | sed -e "s#^.*received, ##" -e "s#, time.*##" -e "s# packet loss##"`
echo "Packet Loss : $STATS" >> ./test_simulator_results.html
RTTMIN=`egrep "rtt min" $PING_CASE | awk '{split($4,a,"/"); print a[1] " " $5}'`
echo "RTT Minimal : $RTTMIN" >> ./test_simulator_results.html
RTTAVG=`egrep "rtt min" $PING_CASE | awk '{split($4,a,"/"); print a[2] " " $5}'`
echo "RTT Average : $RTTAVG" >> ./test_simulator_results.html
RTTMAX=`egrep "rtt min" $PING_CASE | awk '{split($4,a,"/"); print a[3] " " $5}'`
echo "RTT Maximal : $RTTMAX" >> ./test_simulator_results.html
echo " </pre>" >> ./test_simulator_results.html
echo " </td>" >> ./test_simulator_results.html
fi
echo " </tr>" >> ./test_simulator_results.html
fi
done
done
echo " </table>" >> ./test_simulator_results.html
echo " </div>" >> ./test_simulator_results.html
fi
echo "</body>" >> ./test_simulator_results.html
echo "</html>" >> ./test_simulator_results.html
......
This diff is collapsed.
......@@ -26,9 +26,9 @@
<htmlTabIcon>tasks</htmlTabIcon>
<TestCaseRequestedList>
040101
030121 040301 040521 040623 040624 040625 040626 040627 040662 040661 040663 040664 040401 040201 030201
030121 040301 040521 040623 040624 040625 040662 040401 040201 030201
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<TestCaseExclusionList>040626 040627 040661 040663 040664</TestCaseExclusionList>
<testCase id="030121">
<class>Initialize_eNB</class>
......@@ -110,16 +110,16 @@
<testCase id="040661">
<class>Iperf</class>
<desc>iperf (20MHz - UL/20Mbps/UDP)(30 sec)(balanced profile)</desc>
<iperf_args>-u -b 20M -t 30 -i 1 -R</iperf_args>
<desc>iperf (20MHz - UL/12Mbps/UDP)(30 sec)(balanced profile)</desc>
<iperf_args>-u -b 12M -t 30 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>balanced</iperf_profile>
</testCase>
<testCase id="040662">
<class>Iperf</class>
<desc>iperf (20MHz - UL/20Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 20M -t 30 -i 1 -R</iperf_args>
<desc>iperf (20MHz - UL/17Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 17M -t 30 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
......
......@@ -94,9 +94,9 @@
<testCase id="040652">
<class>Iperf</class>
<desc>iperf (10MHz - UL/20Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 20M -t 30 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<desc>iperf (10MHz - UL/5Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 5M -t 30 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>60</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
......
......@@ -86,16 +86,16 @@
<testCase id="040624">
<class>Iperf</class>
<desc>iperf (20MHz - DL/70Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 70M -t 30 -i 1</iperf_args>
<desc>iperf (20MHz - DL/50Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 50M -t 30 -i 1</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
<testCase id="040662">
<class>Iperf</class>
<desc>iperf (20MHz - UL/20Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 20M -t 30 -i 1 -R</iperf_args>
<desc>iperf (20MHz - UL/10Mbps/UDP)(30 sec)(single-ue profile)</desc>
<iperf_args>-u -b 10M -t 30 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
......
......@@ -183,7 +183,6 @@ 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
add_definitions(-DCMAKER)
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")
......@@ -2155,7 +2154,6 @@ add_executable(test_epc_generate_scenario
${OPENAIR2_DIR}/ENB_APP/enb_config.h
${OPENAIR2_DIR}/COMMON/commonDef.h
${OPENAIR2_DIR}/COMMON/messages_def.h
${OPENAIR2_DIR}/COMMON/messages_types.h
${OPENAIR3_DIR}/S1AP/s1ap_eNB_defs.h
)
target_link_libraries (test_epc_generate_scenario
......@@ -2175,7 +2173,6 @@ add_executable(test_epc_play_scenario
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.h
${OPENAIR2_DIR}/COMMON/commonDef.h
${OPENAIR2_DIR}/COMMON/messages_def.h
${OPENAIR2_DIR}/COMMON/messages_types.h
)
target_include_directories(test_epc_play_scenario PUBLIC /usr/local/share/asn1c)
target_link_libraries (test_epc_play_scenario
......
......@@ -76,7 +76,6 @@ macro(add_boolean_option name val helpstr)
endmacro(add_boolean_option)
# compilation flags
# added CMAKER conditional compilation to not bother legacy building system
#############################################
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
......@@ -84,7 +83,7 @@ endif()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel)
#
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.2 -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -DCMAKER")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.2 -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat ")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -DMALLOC_CHECK_=3")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ggdb -DMALLOC_CHECK_=3 -O2")
......
......@@ -32,8 +32,8 @@ OS_DISTRO=$(grep "^ID=" /etc/os-release | sed "s/ID=//" | sed "s/\"//g")
OS_RELEASE=$(grep "^VERSION_ID=" /etc/os-release | sed "s/VERSION_ID=//" | sed "s/\"//g")
case "$OS_DISTRO" in
fedora) OS_BASEDISTRO="fedora"; INSTALLER="dnf"; CMAKE="cmake" ;;
rhel) OS_BASEDISTRO="fedora"; INSTALLER="yum"; CMAKE="cmake3" ;;
centos) OS_BASEDISTRO="fedora"; INSTALLER="yum"; CMAKE="cmake3" ;;
rhel) OS_BASEDISTRO="fedora"; INSTALLER="yum --skip-broken"; CMAKE="cmake3" ;;
centos) OS_BASEDISTRO="fedora"; INSTALLER="yum --skip-broken"; CMAKE="cmake3" ;;
debian) OS_BASEDISTRO="debian"; INSTALLER="apt-get"; CMAKE="cmake" ;;
ubuntu) OS_BASEDISTRO="debian"; INSTALLER="apt-get"; CMAKE="cmake" ;;
esac
......
# OAI configuration module
The configuration module provides an api that other oai components can use to get parameters at init time. It defines a parameter structure, used to describe parameters attributes (for example name and type). The same structure includes a pointer to the variable where the configuration module writes the parameter value, at run time, when calling config_get or config_getlist functions. For each parameter a function to check the value can be specified and pre-defined functions are provided for some common parameter validations (integer in a range or in a list, string in a list). The module also include a mechanism to check that no unknown options have been entered on the command line
The configuration module provides an api that other oai components can use to get parameters at init time. It defines a parameter structure, used to describe parameters attributes (for example name and type). The same structure includes a pointer to the variable where the configuration module writes the parameter value, at run time, when calling config_get or config_getlist functions. For each parameter a function to check the value can be specified and pre-defined functions are provided for some common parameter validations (integer in a range or in a list, string in a list). The module also include an api to check that no unknown options have been entered on the command line and a a mechanism to display a help text for suppoted parameters.
## Documentation
......
```c
configmodule_interface_t *load_configmodule(int argc, char **argv)
configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t initflags)
```
* Parses the command line options, looking for the –O argument
* Loads the `libparams_<configsource>.so` (today `libparams_libconfig.so`) shared library
* Looks for `config_<config source>_init` symbol and calls it , passing it an array of string corresponding to the « : » separated strings used in the –O option
* Looks for `config_<config source>_get`, `config_<config source>_getlist` and `config_<config source>_end` symbols which are the three functions a configuration library should implement. Get and getlist are mandatory, end is optional.
* Stores all the necessary information in a `configmodule_interface_t structure`, which is of no use for caller as long as we only use one configuration source.
* if the bit CONFIG_ENABLECMDLINEONLY is set in `initflags` then the module allows parameters to be set only via the command line. This is used for the oai UE.
```c
void End_configmodule(void)
......
......@@ -27,6 +27,63 @@ $ ./lte-softmodem -O libconfig:<config>:dbgl1
```bash
$ ./lte-uesoftmodem -O cmdlineonly:dbgl1
```
To get help on supported parameters you can use specific options:
* ---help: print help for command line only parameters and for parameters not defined in a specific section
* ---help_< prefix > : print help for parameters defined under the section < prefix >
```
./lte-softmodem -O libconfig:/usr/local/oai/conf/enb.nbiot.band7.tm1.50PRB.usrpb210.conf --help
[CONFIG] get parameters from libconfig /usr/local/oai/conf/enb.nbiot.band7.tm1.50PRB.usrpb210.conf , debug flags: 0x00000000
.............................................
[LIBCONFIG] (root): 19/19 parameters successfully set, (16 to default value)
-----Help for section (root section) : 019 entries------
--rf-config-file: Configuration file for front-end (e.g. LMS7002M)
--ulsch-max-errors: set the eNodeB max ULSCH erros
--phy-test: test UE phy layer, mac disabled
--usim-test: use XOR autentication algo in case of test usim mode
--emulate-rf: Emulated RF enabled(disable by defult)
--clock: tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)
--wait-for-sync: Help string not specified
--single-thread-enable: Disables single-thread mode in lte-softmodem
-C: Set the downlink frequency for all component carriers
-a: Channel id offset
-d: Enable soft scope and L1 and L2 stats (Xforms)
-q: Enable processing timing measurement of lte softmodem on per subframe basis
-S: Skip the missed slots/subframes
--numerology: adding numerology for 5G
--parallel-config: three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'
--worker-config: two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'
--nbiot-disable: disable nb-iot, even if defined in config
--noS1: Disable s1 interface
--nokrnmod: (noS1 only): Use tun instead of namesh module
--------------------------------------------------------------------
[LIBCONFIG] (root): 4/4 parameters successfully set, (4 to default value)
-----Help for section (root section) : 004 entries------
-R: Enable online log
-g: Set the global log level, valide options: (4:trace, 3:debug, 2:info, 1:warn, (0:error))
--telnetsrv: Start embedded telnet server
--msc: Enable the MSC tracing utility
--------------------------------------------------------------------
[LIBCONFIG] loader: 2/2 parameters successfully set, (2 to default value)
[LIBCONFIG] loader.telnetsrv: 2/2 parameters successfully set, (1 to default value)
[LOADER] library libtelnetsrv.so is not loaded: libtelnetsrv.so: cannot open shared object file: No such file or directory
Getting ENBSParams
[LIBCONFIG] (root): 3/3 parameters successfully set, (1 to default value)
-----Help for section (root section) : 003 entries------
--Asn1_verbosity: Help string not specified
--Active_eNBs: Help string not specified
--noS1: Help string not specified
--------------------------------------------------------------------
/usr/local/oai/issue390_configmodule_cmdlinebug/openairinterface5g/common/config/config_cmdline.c:224 config_process_cmdline() Exiting OAI softmodem: [CONFIG] Exiting after displaying help
```
For the lte-softmodem (the eNodeB) The config source parameter defaults to libconfig, preserving the initial -O option format. In this case you cannot specify the debug level.
```bash
......
......@@ -37,7 +37,7 @@
#include <errno.h>
#include <platform_types.h>
#include "config_userapi.h"
#include "../utils/LOG/log.h"
int parse_stringlist(paramdef_t *cfgoptions, char *val) {
char *atoken;
......@@ -74,14 +74,15 @@ int processoption(paramdef_t *cfgoptions, char *value) {
if ( value == NULL) {
if( (cfgoptions->paramflags &PARAMFLAG_BOOL) == 0 ) { /* not a boolean, argument required */
fprintf(stderr,"[CONFIG] command line, option %s requires an argument\n",cfgoptions->optname);
return 0;
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an argument\n",cfgoptions->optname);
} else { /* boolean value option without argument, set value to true*/
tmpval = defbool;
}
}
switch(cfgoptions->type) {
char *charptr;
case TYPE_STRING:
if (cfgoptions->numelt == 0 ) {
config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(tmpval)+1);
......@@ -105,14 +106,24 @@ int processoption(paramdef_t *cfgoptions, char *value) {
case TYPE_UINT8:
case TYPE_INT8:
config_check_valptr(cfgoptions, (char **)&(cfgoptions->iptr),sizeof(int32_t));
config_assign_int(cfgoptions,cfgoptions->optname,(int32_t)strtol(tmpval,NULL,0));
config_assign_int(cfgoptions,cfgoptions->optname,(int32_t)strtol(tmpval,&charptr,0));
if( *charptr != 0) {
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an integer argument\n",cfgoptions->optname);
}
optisset=1;
break;
case TYPE_UINT64:
case TYPE_INT64:
config_check_valptr(cfgoptions, (char **)&(cfgoptions->i64ptr),sizeof(uint64_t));
*(cfgoptions->i64ptr)=strtoll(tmpval,NULL,0);
*(cfgoptions->i64ptr)=strtoll(tmpval,&charptr,0);
if( *charptr != 0) {
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an integer argument\n",cfgoptions->optname);
}
printf_cmdl("[CONFIG] %s set to %lli from command line\n", cfgoptions->optname, (long long)*(cfgoptions->i64ptr));
optisset=1;
break;
......@@ -123,7 +134,12 @@ int processoption(paramdef_t *cfgoptions, char *value) {
case TYPE_DOUBLE:
config_check_valptr(cfgoptions, (char **)&(cfgoptions->dblptr),sizeof(double));
*(cfgoptions->dblptr) = strtof(tmpval,NULL);
*(cfgoptions->dblptr) = strtof(tmpval,&charptr);
if( *charptr != 0) {
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires a double argument\n",cfgoptions->optname);
}
printf_cmdl("[CONFIG] %s set to %lf from command line\n", cfgoptions->optname, *(cfgoptions->dblptr));
optisset=1;
break;
......@@ -132,7 +148,7 @@ int processoption(paramdef_t *cfgoptions, char *value) {
break;
default:
fprintf(stderr,"[CONFIG] command line, %s type %i not supported\n",cfgoptions->optname, cfgoptions->type);
CONFIG_PRINTF_ERROR("[CONFIG] command line, %s type %i not supported\n",cfgoptions->optname, cfgoptions->type);
break;
} /* switch on param type */
......@@ -143,16 +159,20 @@ int processoption(paramdef_t *cfgoptions, char *value) {
return optisset;
}
int config_check_cmdlineopt(char *prefix) {
/*--------------------------------------------------------------------*/
/* check unknown options in the command line
*/
int config_check_unknown_cmdlineopt(char *prefix) {
int unknowndetected=0;
char testprefix[CONFIG_MAXOPTLENGTH]="";
char testprefix[CONFIG_MAXOPTLENGTH];
int finalcheck = 0;
memset(testprefix,0,sizeof(testprefix));
if (prefix != NULL) {
if (strcmp(prefix,CONFIG_CHECKALLSECTIONS) == 0)
finalcheck = 1;
else if (strlen(prefix) > 0) {
sprintf(testprefix,"--%s.",prefix);
sprintf(testprefix,"--%.*s.",CONFIG_MAXOPTLENGTH-1,prefix);
}
}
......@@ -161,6 +181,8 @@ int config_check_cmdlineopt(char *prefix) {
if ( !finalcheck && testprefix[0]==0 && index(config_get_if()->argv[i],'.') != NULL) continue;
if ( !finalcheck && isdigit(config_get_if()->argv[i][0])) continue;
if ( !finalcheck && config_get_if()->argv[i][0] == '-' && isdigit(config_get_if()->argv[i][1])) continue;
if ( (config_get_if()->argv_info[i] & CONFIG_CMDLINEOPT_PROCESSED) == 0 ) {
......@@ -170,10 +192,13 @@ int config_check_cmdlineopt(char *prefix) {
}
}
printf_cmdl("[CONFIG] %i unknown option(s) in command line starting with %s (section %s)\n",
if (unknowndetected > 0) {
CONFIG_PRINTF_ERROR("[CONFIG] %i unknown option(s) in command line starting with %s (section %s)\n",
unknowndetected,testprefix,((prefix==NULL)?"":prefix));
}
return unknowndetected;
} /* parse_cmdline*/
} /* config_check_unknown_cmdlineopt */
int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix) {
int c = config_get_if()->argc;
......@@ -194,7 +219,7 @@ int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
if (pp == NULL || strcasecmp(pp,config_get_if()->argv[i] ) == 0 ) {
if( prefix == NULL) {
config_printhelp(cfgoptions,numoptions);
config_printhelp(cfgoptions,numoptions,"(root section)");
if ( ! ( CONFIG_ISFLAGSET(CONFIG_NOEXITONHELP)))
exit_fun("[CONFIG] Exiting after displaying help\n");
......@@ -203,8 +228,7 @@ int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
pp=strtok_r(NULL, " ",&tokctx);
if ( prefix != NULL && pp != NULL && strncasecmp(prefix,pp,strlen(pp)) == 0 ) {
printf ("Help for %s section:\n",prefix);
config_printhelp(cfgoptions,numoptions);
config_printhelp(cfgoptions,numoptions,prefix);
if ( ! (CONFIG_ISFLAGSET(CONFIG_NOEXITONHELP))) {
fprintf(stderr,"[CONFIG] %s %i section %s:", __FILE__, __LINE__, prefix);
......@@ -267,16 +291,5 @@ int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix)
} /* fin du while */
printf_cmdl("[CONFIG] %s %i options set from command line\n",((prefix == NULL) ? "(root)":prefix),j);
if ( !(CONFIG_ISFLAGSET( CONFIG_NOCHECKUNKOPT )) ) {
i=config_check_cmdlineopt(prefix);
if (i > 0) {
fprintf(stderr,"[CONFIG] %i unknown options for section %s detected in command line\n",
i,((prefix==NULL)?"\"root section\"":prefix));
exit_fun(" Exiting after detecting errors in command line \n");
}
}
return j;
} /* parse_cmdline*/
......@@ -36,12 +36,15 @@
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <platform_types.h>
#define CONFIG_LOADCONFIG_MAIN
#include "config_load_configmodule.h"
#include "config_userapi.h"
#include "../utils/LOG/log.h"
#define CONFIG_SHAREDLIBFORMAT "libparams_%s.so"
int load_config_sharedlib(configmodule_interface_t *cfgptr) {
void *lib_handle;
char fname[128];
......@@ -198,7 +201,7 @@ configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t init
}
if ( strstr(argv[i], "help_config") != NULL ) {
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params),CONFIG_SECTIONNAME);
exit(0);
}
......@@ -304,7 +307,7 @@ configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t init
if (cfgmode != NULL) free(cfgmode);
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params));
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params),CONFIG_SECTIONNAME );
// exit(-1);
}
......@@ -342,7 +345,7 @@ void free_configmodule(void) {
if( cfgptr->cfgmode != NULL) free(cfgptr->cfgmode);
printf ("[CONFIG] free %u config parameter pointers\n",cfgptr->num_cfgP);
printf ("[CONFIG] free %i config parameter pointers\n",cfgptr->num_cfgP);
for (int i=0; i<cfgptr->num_cfgP; i++) {
if ( cfgptr->cfgP[i] != NULL) free(cfgptr->cfgP[i]);
......
......@@ -51,7 +51,6 @@
#define CONFIG_PRINTPARAMS 1 // print parameters values while processing
#define CONFIG_DEBUGPTR (1<<1) // print memory allocation/free debug messages
#define CONFIG_DEBUGCMDLINE (1<<2) // print command line processing messages
#define CONFIG_NOCHECKUNKOPT (1<<3) // disable check unprocessed (so invalid) command line options
#define CONFIG_NOABORTONCHKF (1<<4) // disable abort execution when parameter checking function fails
#define CONFIG_NOEXITONHELP (1<<19) // do not exit after printing help
#define CONFIG_HELP (1<<20) // print help message
......@@ -109,5 +108,7 @@ extern configmodule_interface_t *cfgptr;
#define CONFIG_ENABLECMDLINEONLY (1<<1)
extern configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t initflags);
extern void end_configmodule(void);
#define CONFIG_PRINTF_ERROR(f, x... ) if (isLogInitDone ()) { LOG_E(ENB_APP,f,x);} else {printf(f,x);}; if ( !CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) ) exit_fun("exit because configuration failed\n");
#endif /* INCLUDE_CONFIG_LOADCONFIGMODULE_H */
......@@ -39,15 +39,13 @@
#include <errno.h>
#include <dlfcn.h>
#include <arpa/inet.h>
#include <platform_types.h>
#include "config_userapi.h"
#include "../utils/LOG/log.h"
configmodule_interface_t *config_get_if(void) {
if (cfgptr == NULL) {
fprintf(stderr,"[CONFIG] %s %d config module not initialized\n",__FILE__, __LINE__);
exit(-1);
CONFIG_PRINTF_ERROR("[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__);
}
return cfgptr;
......@@ -66,9 +64,8 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) {
config_get_if()->numptrs++;
}
} else {
fprintf(stderr, "[CONFIG] %s %d option %s, cannot allocate pointer: %s \n",
CONFIG_PRINTF_ERROR("[CONFIG] %s %d option %s, cannot allocate pointer: %s \n",
__FILE__, __LINE__, cfgoptions->optname, strerror(errno));
exit(-1);
}
}
......@@ -78,9 +75,8 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) {
if (*ptr != NULL) {
return *ptr;
} else {
fprintf(stderr,"[CONFIG] %s %d option %s, definition error: value pointer is NULL, declared as %i bytes allocated\n",
CONFIG_PRINTF_ERROR("[CONFIG] %s %d option %s, definition error: value pointer is NULL, declared as %i bytes allocated\n",
__FILE__, __LINE__,cfgoptions->optname, cfgoptions->numelt);
exit(-1);
}
}
......@@ -95,8 +91,7 @@ char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) {
config_get_if()->numptrs++;
}
} else {
fprintf (stderr,"[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
exit(-1);
CONFIG_PRINTF_ERROR("[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
}
}
......@@ -157,8 +152,7 @@ void config_assign_processedint(paramdef_t *cfgoption, int val) {
if ( cfgoption->processedvalue != NULL) {
*(cfgoption->processedvalue) = val;
} else {
fprintf (stderr,"[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
exit(-1);
CONFIG_PRINTF_ERROR("[CONFIG] %s %d malloc error\n",__FILE__, __LINE__);
}
}
......@@ -177,15 +171,17 @@ int config_get_processedint(paramdef_t *cfgoption) {
return ret;
}
void config_printhelp(paramdef_t *params,int numparams) {
void config_printhelp(paramdef_t *params,int numparams, char *prefix) {
printf("\n-----Help for section %-26s: %03i entries------\n",(prefix==NULL)?"(root section)":prefix ,numparams);
for (int i=0 ; i<numparams ; i++) {
if ( params[i].helpstr != NULL) {
printf("%s%s: %s",
printf(" %s%s: %s",
(strlen(params[i].optname) <= 1) ? "-" : "--",
params[i].optname,
params[i].helpstr);
}
}
(params[i].helpstr != NULL)?params[i].helpstr:"Help string not specified\n");
} /* for on params entries */
printf("--------------------------------------------------------------------\n\n");
}
int config_execcheck(paramdef_t *params,int numparams, char *prefix) {
......@@ -202,11 +198,7 @@ int config_execcheck(paramdef_t *params,int numparams, char *prefix) {
}
if (st != 0) {
fprintf(stderr,"[CONFIG] config_execcheck: section %s %i parameters with wrong value\n", prefix, -st);
if ( CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) == 0) {
exit_fun("exit because configuration failed\n");
}
CONFIG_PRINTF_ERROR("[CONFIG] config_execcheck: section %s %i parameters with wrong value\n", prefix, -st);
}
return st;
......@@ -263,6 +255,7 @@ int config_getlist(paramlist_def_t *ParamList, paramdef_t *params, int numparams
for (int i = 0; i < ParamList->numelt; ++i) {
// TODO config_process_cmdline?
sprintf(cfgpath, "%s.[%i]", newprefix, i);
config_process_cmdline(ParamList->paramarray[i],numparams,cfgpath);
config_execcheck(ParamList->paramarray[i], numparams, cfgpath);
}
......@@ -370,6 +363,12 @@ int config_checkstr_assign_integer(paramdef_t *param) {
return -1;
}
void config_set_checkfunctions(paramdef_t *params, checkedparam_t *checkfunctions, int numparams) {
for (int i=0; i< numparams ; i++ ) {
params[i].chkPptr = &(checkfunctions[i]);
}
}
int config_setdefault_string(paramdef_t *cfgoptions, char *prefix) {
int status = 0;
......
......@@ -49,7 +49,7 @@ extern "C"
/* utility functions, to be used by configuration module and/or configuration libraries */
extern configmodule_interface_t *config_get_if(void);
extern char *config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) ;
extern void config_printhelp(paramdef_t *,int numparams);
extern void config_printhelp(paramdef_t *,int numparams, char *prefix);
extern int config_process_cmdline(paramdef_t *params,int numparams, char *prefix);
extern void config_assign_processedint(paramdef_t *cfgoption, int val);
extern void config_assign_int(paramdef_t *cfgoptions, char *fullname, int val);
......@@ -57,10 +57,13 @@ extern int config_assign_ipv4addr(paramdef_t *cfgoptions, char *ipv4addr);
/* apis to get/check parameters, to be used by oai modules, at configuration time */
#define CONFIG_CHECKALLSECTIONS "ALLSECTIONS"
extern int config_check_cmdlineopt(char *prefix);
extern int config_check_unknown_cmdlineopt(char *prefix);
extern int config_get(paramdef_t *params,int numparams, char *prefix);
extern int config_getlist(paramlist_def_t *ParamList, paramdef_t *params, int numparams, char *prefix);
/* apis to set some of the paramdef_t fields before using the get/getlist api's */
extern void config_set_checkfunctions(paramdef_t *params, checkedparam_t *checkfunctions, int numparams);
/* apis to retrieve parameters info after calling get or getlist functions */
extern int config_isparamset(paramdef_t *params,int paramidx);
extern int config_get_processedint(paramdef_t *cfgoption);
......
This diff is collapsed.
......@@ -219,7 +219,6 @@ void log_getconfig(log_t *g_log) {
paramdef_t logparams_logfile[MAX_LOG_PREDEF_COMPONENTS];
paramdef_t logparams_debug[sizeof(log_maskmap)/sizeof(mapping)];
paramdef_t logparams_dump[sizeof(log_maskmap)/sizeof(mapping)];
CONFIG_SETRTFLAG(CONFIG_NOCHECKUNKOPT);
int ret = config_get( logparams_defaults,sizeof(logparams_defaults)/sizeof(paramdef_t),CONFIG_STRING_LOG_PREFIX);
if (ret <0) {
......@@ -305,8 +304,8 @@ void log_getconfig(log_t *g_log) {
}
config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
CONFIG_CLEARRTFLAG(CONFIG_NOCHECKUNKOPT);
config_get( logparams_dump,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
config_check_unknown_cmdlineopt(CONFIG_STRING_LOG_PREFIX);
/* set the debug mask according to the debug parameters values */
for (int i=0; log_maskmap[i].name != NULL ; i++) {
......
......@@ -145,6 +145,7 @@ extern "C" {
#define DEBUG_CTRLSOCKET (1<<10)
#define DEBUG_SECURITY (1<<11)
#define DEBUG_NAS (1<<12)
#define DEBUG_RLC (1<<13)
#define UE_TIMING (1<<20)
......@@ -162,6 +163,7 @@ extern "C" {
{"CTRLSOCKET", DEBUG_CTRLSOCKET},\
{"SECURITY", DEBUG_SECURITY},\
{"NAS", DEBUG_NAS},\
{"RLC", DEBUG_RLC},\
{"UE_TIMING", UE_TIMING},\
{NULL,-1}\
}
......@@ -345,6 +347,8 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
}
#define LOG_OPTIONS_IDX 2
/*----------------------------------------------------------------------------------*/
/** @defgroup _debugging debugging macros
* @ingroup _macro
......
......@@ -19,7 +19,7 @@ T_IDs.h: $(GENIDS) T_messages.txt
./$(GENIDS) T_messages.txt T_IDs.h
check_vcd:
gcc -Wall -I. -I.. -I../itti -Itracer -o _check_vcd check_vcd.c tracer/database.c tracer/utils.c -lm -pthread
gcc -Wall -I. -I.. -I../itti -I../../../openair2/COMMON -Itracer -o _check_vcd check_vcd.c tracer/database.c tracer/utils.c -lm -pthread
./_check_vcd || (rm -f ./_check_vcd ./T_IDs.h ./T_messages.txt.h && false)
rm -f ./_check_vcd
......
......@@ -14,12 +14,14 @@
#define QUIT(x) do { \
printf("T tracer: QUIT: %s\n", x); \
exit(1); \
} while (0)
} while (0)
/* array used to activate/disactivate a log */
static int T_IDs[T_NUMBER_OF_IDS];
int *T_active = T_IDs;
int T_stdout;
int T_stdout = 1;
static int T_socket;
......@@ -32,67 +34,90 @@ volatile int *T_freelist_head = &_T_freelist_head;
T_cache_t *T_cache;
#if BASIC_SIMULATOR
/* global variables used by T_GET_SLOT, see in T.h */
volatile uint64_t T_next_id;
volatile uint64_t T_active_id;
/* global variables used by T_GET_SLOT, see in T.h */
volatile uint64_t T_next_id;
volatile uint64_t T_active_id;
#endif
static void get_message(int s)
{
static void get_message(int s) {
char t;
int l;
int id;
int is_on;
if (read(s, &t, 1) != 1) QUIT("get_message fails");
printf("T tracer: got mess %d\n", t);
printf("T tracer: got mess %d\n", t);
switch (t) {
case 0:
/* toggle all those IDs */
/* optimze? (too much syscalls) */
if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
while (l) {
if (read(s, &id, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
T_IDs[id] = 1 - T_IDs[id];
l--;
}
break;
case 1:
/* set IDs as given */
/* optimize? */
if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails");
id = 0;
while (l) {
if (read(s, &is_on, sizeof(int)) != sizeof(int))
QUIT("get_message fails");
T_IDs[id] = is_on;
id++;
l--;
}
break;
case 2: break; /* do nothing, this message is to wait for local tracer */
case 2:
break; /* do nothing, this message is to wait for local tracer */
}
}
static void *T_receive_thread(void *_)
{
static void *T_receive_thread(void *_) {
while (1) get_message(T_socket);
return NULL;
}
static void new_thread(void *(*f)(void *), void *data)
{
static void new_thread(void *(*f)(void *), void *data) {
pthread_t t;
pthread_attr_t att;
if (pthread_attr_init(&att))
{ fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
{ fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
if (pthread_create(&t, &att, f, data))
{ fprintf(stderr, "pthread_create err\n"); exit(1); }
if (pthread_attr_destroy(&att))
{ fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
if (pthread_attr_init(&att)) {
fprintf(stderr, "pthread_attr_init err\n");
exit(1);
}
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) {
fprintf(stderr, "pthread_attr_setdetachstate err\n");
exit(1);
}
if (pthread_create(&t, &att, f, data)) {
fprintf(stderr, "pthread_create err\n");
exit(1);
}
if (pthread_attr_destroy(&att)) {
fprintf(stderr, "pthread_attr_destroy err\n");
exit(1);
}
}
/* defined in local_tracer.c */
......@@ -104,53 +129,64 @@ void T_local_tracer_main(int remote_port, int wait_for_tracer,
*/
#include <sys/types.h>
#include <sys/wait.h>
static void monitor_and_kill(int child1, int child2)
{
static void monitor_and_kill(int child1, int child2) {
int child;
int status;
child = wait(&status);
if (child == -1) perror("wait");
kill(child1, SIGKILL);
kill(child2, SIGKILL);
exit(0);
}
void T_init(int remote_port, int wait_for_tracer, int dont_fork)
{
void T_init(int remote_port, int wait_for_tracer, int dont_fork) {
int socket_pair[2];
int s;
int child1, child2;
int i;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
{ perror("socketpair"); abort(); }
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair)) {
perror("socketpair");
abort();
}
/* setup shared memory */
T_cache = mmap(NULL, T_CACHE_SIZE * sizeof(T_cache_t),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (T_cache == MAP_FAILED)
{ perror("mmap"); abort(); }
if (T_cache == MAP_FAILED) {
perror("mmap");
abort();
}
/* let's garbage the memory to catch some potential problems
* (think multiprocessor sync issues, barriers, etc.)
*/
memset(T_cache, 0x55, T_CACHE_SIZE * sizeof(T_cache_t));
for (i = 0; i < T_CACHE_SIZE; i++) T_cache[i].busy = 0;
/* child1 runs the local tracer and child2 (or main) runs the tracee */
child1 = fork();
if (child1 == -1) abort();
child1 = fork(); if (child1 == -1) abort();
if (child1 == 0) {
close(socket_pair[1]);
T_local_tracer_main(remote_port, wait_for_tracer, socket_pair[0],
T_cache);
exit(0);
}
close(socket_pair[0]);
if (dont_fork == 0) {
child2 = fork(); if (child2 == -1) abort();
child2 = fork();
if (child2 == -1) abort();
if (child2 != 0) {
close(socket_pair[1]);
munmap(T_cache, T_CACHE_SIZE * sizeof(T_cache_t));
......@@ -161,27 +197,21 @@ void T_init(int remote_port, int wait_for_tracer, int dont_fork)
s = socket_pair[1];
/* wait for first message - initial list of active T events */
get_message(s);
T_socket = s;
new_thread(T_receive_thread, NULL);
}
void T_Config_Init(void)
{
int T_port; /* by default we wait for the tracer */
int T_nowait; /* default port to listen to to wait for the tracer */
int T_dont_fork; /* default is to fork, see 'T_init' to understand */
void T_Config_Init(void) {
int T_port=TTRACER_DEFAULT_PORTNUM; /* by default we wait for the tracer */
int T_nowait=0; /* default port to listen to to wait for the tracer */
int T_dont_fork=0; /* default is to fork, see 'T_init' to understand */
paramdef_t ttraceparams[] = CMDLINE_TTRACEPARAMS_DESC;
/* for a cleaner config file, TTracer params should be defined in a
* specific section...
*/
config_get(ttraceparams,
sizeof(ttraceparams) / sizeof(paramdef_t),
TTRACER_CONFIG_PREFIX);
/* compatibility: look for TTracer command line options in root section */
config_process_cmdline(ttraceparams,
sizeof(ttraceparams) / sizeof(paramdef_t),
......
......@@ -8,7 +8,7 @@
#include "T_defs.h"
#ifdef T_SEND_TIME
#include <time.h>
#include <time.h>
#endif
/* T message IDs */
......@@ -598,20 +598,21 @@ extern int *T_active;
#define TTRACER_CONFIG_PREFIX "TTracer"
/*------------------------------------------------------------------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
/* configuration parameters for TTRACE utility */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*------------------------------------------------------------------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
#define TTRACER_DEFAULT_PORTNUM 2021
#define CMDLINE_TTRACEPARAMS_DESC { \
{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:2021, TYPE_INT, 0}, \
{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0}, \
{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:0, TYPE_INT, 0}, \
{"T_stdout", CONFIG_HLP_STDOUT, PARAMFLAG_BOOL, iptr:&T_stdout, defintval:1, TYPE_INT, 0}, \
}
{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:TTRACER_DEFAULT_PORTNUM, TYPE_INT, 0},\
{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0},\
{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:0, TYPE_INT, 0},\
{"T_stdout", CONFIG_HLP_STDOUT, PARAMFLAG_BOOL, iptr:&T_stdout, defintval:1, TYPE_INT, 0},\
}
/* log on stdout */
/* log on stdout */
void T_init(int remote_port, int wait_for_tracer, int dont_fork);
void T_Config_Init(void);
#else /* T_TRACER */
......
......@@ -22,9 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#ifdef CMAKER
#include <platform_types.h>
#endif
#if defined(ENB_MODE)
# define display_backtrace()
......
This diff is collapsed.
......@@ -80,8 +80,8 @@ typedef int(*msc_init_t)(const msc_env_t, const int );
typedef void(*msc_start_use_t)(void );
typedef void(*msc_end_t)(void);
typedef void(*msc_log_event_t)(const msc_proto_t,char *, ...);
typedef void(*msc_log_message_t)(const char * const, const msc_proto_t, const msc_proto_t,
const uint8_t* const, const unsigned int, char * , ...);
typedef void(*msc_log_message_t)(const char *const, const msc_proto_t, const msc_proto_t,
const uint8_t *const, const unsigned int, char *, ...);
typedef struct msc_interface {
int msc_loaded;
msc_init_t msc_init;
......@@ -99,15 +99,17 @@ void msc_end(void);
void msc_log_declare_proto(const msc_proto_t protoP);
void msc_log_event(const msc_proto_t protoP,char *format, ...);
void msc_log_message(
const char * const message_operationP,
const char *const message_operationP,
const msc_proto_t receiverP,
const msc_proto_t senderP,
const uint8_t* const bytesP,
const uint8_t *const bytesP,
const unsigned int num_bytes,
char *format, ...);
#else
#define MESSAGE_CHART_GENERATOR msc_interface.msc_loaded
msc_interface_t msc_interface;
#define MSC_INIT(arg1,arg2) if(msc_interface.msc_loaded) msc_interface.msc_init(arg1,arg2)
#define MSC_START_USE if(msc_interface.msc_loaded) msc_interface.msc_start_use
......
This diff is collapsed.
#ifndef _TIME_UTILS_H_
#define _TIME_UTILS_H_
#include <time.h>
#include <stdint.h>
static inline int64_t clock_difftime_ns(struct timespec start, struct timespec end)
{
struct timespec temp;
int64_t temp_ns;
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;
}
temp_ns = (int64_t)(temp.tv_sec) * (int64_t)1000000000 + (temp.tv_nsec);
return temp_ns;
}
#endif /* _TIME_UTILS_H_ */
......@@ -8,7 +8,8 @@
5. [eNB RRC Layer](#enb-rrc-layer)
6. [eNB X2AP](#enb-x2ap)
7. [eNB Advanced Features](#enb-advanced-features)
2. [OpenAirInterface UE Feature Set](#openairinterface-ue-feature-set)
2. [OpenAirInterface Functional Split](#openairinterface-functional-split)
3. [OpenAirInterface UE Feature Set](#openairinterface-ue-feature-set)
1. [LTE UE PHY Layer](#lte-ue-phy-layer)
2. [LTE UE MAC Layer](#lte-ue-mac-layer)
3. [LTE UE RLC Layer](#lte-ue-rlc-layer)
......@@ -128,6 +129,18 @@ The X2AP layer is based on **3GPP 36.423** v14.6.0 and implements the following
**To be completed**
# OpenAirInterface Functional Split #
- RCC: Radio-Cloud Center
- RAU: Radio-Access Unit
- RRU: Remote Radio-Unit
![Functional Split Architecture](./oai_lte_enb_func_split_arch.png)
- IF4.5 / IF5 : similar to IEEE P1914.1
- FAPI (IF2) : specified by Small Cell Forum (open-nFAPI implementation)
- IF1 : F1 in 3GPP Release 15 (not implemented yet)
# OpenAirInterface UE Feature Set #
## LTE UE PHY Layer ##
......@@ -169,3 +182,10 @@ The RRC layer is based on **3GPP 36.331** v14.3.0 and implements the following f
- System Information decoding
- RRC connection establishment
## LTE UE NAS Layer ##
The NAS layer is based on **3GPP 24.301** and implements the following functions:
- EMM attach/detach, authentication, tracking area update, and more
- ESM default/dedicated bearer, PDN connectivity, and more
......@@ -270,6 +270,7 @@ int pnf_param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_re
for(int i = 0; i < resp->pnf_phy.number_of_phys; ++i)
{
phy_info phy;
memset(&phy,0,sizeof(phy));
phy.index = resp->pnf_phy.phy[i].phy_config_index;
printf("[VNF] (PHY:%d) phy_config_idx:%d\n", i, resp->pnf_phy.phy[i].phy_config_index);
......@@ -287,6 +288,7 @@ int pnf_param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_re
for(int i = 0; i < resp->pnf_rf.number_of_rfs; ++i) {
rf_info rf;
memset(&rf,0,sizeof(rf));
rf.index = resp->pnf_rf.rf[i].rf_config_index;
printf("[VNF] (RF:%d) rf_config_idx:%d\n", i, resp->pnf_rf.rf[i].rf_config_index);
......@@ -912,7 +914,7 @@ int param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t
// for now just 1
printf("[VNF] %d.%d pnf p7 %s:%d timing %d %d %d %d\n", p5_idx, phy->id, phy->remote_addr, phy->remote_port, p7_vnf->timing_window, p7_vnf->periodic_timing_period, p7_vnf->aperiodic_timing_enabled, p7_vnf->periodic_timing_period);
printf("[VNF] %d.%d pnf p7 %s:%d timing %u %u %u %u\n", p5_idx, phy->id, phy->remote_addr, phy->remote_port, p7_vnf->timing_window, p7_vnf->periodic_timing_period, p7_vnf->aperiodic_timing_enabled, p7_vnf->periodic_timing_period);
req->header.message_id = NFAPI_CONFIG_REQUEST;
req->header.phy_id = phy->id;
......@@ -934,7 +936,7 @@ int param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t
req->nfapi_config.timing_window.tl.tag = NFAPI_NFAPI_TIMING_WINDOW_TAG;
req->nfapi_config.timing_window.value = p7_vnf->timing_window;
printf("[VNF] Timing window:%d\n", p7_vnf->timing_window);
printf("[VNF] Timing window:%u\n", p7_vnf->timing_window);
req->num_tlv++;
if(p7_vnf->periodic_timing_enabled || p7_vnf->aperiodic_timing_enabled) {
......
......@@ -1237,11 +1237,11 @@ int pnf_connect(pnf_t* pnf)
}
struct addrinfo *p = servinfo;
int i = 0;
int connected = 0;
while(p != NULL && connected == 0)
{
#ifdef NFAPI_TRACE_ENABLED
char* family = "Unknown";
char* address = "Unknown";
char _addr[128];
......@@ -1261,6 +1261,7 @@ int pnf_connect(pnf_t* pnf)
}
NFAPI_TRACE(NFAPI_TRACE_NOTE, "Host address info %d Family:%s Address:%s\n", i++, family, address);
#endif
if (pnf->sctp)
{
......
......@@ -389,7 +389,7 @@ static uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr)
{
if(now_hr < sf_start_hr)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier than start of subframe now_hr:%u sf_start_hr:%u\n", now_hr, sf_start_hr);
//NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier than start of subframe now_hr:%u sf_start_hr:%u\n", now_hr, sf_start_hr);
return 0;
}
else
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1438,8 +1438,6 @@ uint8_t rx_pcfich(LTE_DL_FRAME_PARMS *frame_parms,
void generate_phich_reg_mapping(LTE_DL_FRAME_PARMS *frame_parms);
void init_transport_channels(uint8_t);
void generate_RIV_tables(void);
/*!
......
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100755 to 100644
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment