Merge branch 'integration_2026_w02' into 'develop'

Integration: `2026.w02`

* !3828 L2 UE files code cleanup for static functions
* !3839 Couple rfsim fixes
* !3835 Correctly include cblas include directories for RHEL
* !3840 Fix missing return statements in SIB1 TDA validation
* !3836 move NTN UE L1 functions to a new file
* !3793 CI: Remove redundant Jenkinsfiles
* !3770 RRC UE: Implement proper NH chain synchronization for RRC Reestablishment
* !3843 fix(documentation): issue 1042
* !3842 Remove unused cmake_targets files
* !3832 Remove global iq_txshift and iq_rxrescale
* !3847 Minor CI and nr_ulsim reporting adjustments
* !3838 NR NGAP (N2HO) : Fix Time UE Stayed in Cell IE type and calculation
* !3677 Support prach with start symbol of PRACH not at symbol 0

Closes #1042 and #857

See merge request oai/openairinterface5g!3841
This commit is contained in:
Jaroslava Fiedlerova
2026-01-08 17:10:47 +00:00
49 changed files with 1651 additions and 5638 deletions
+4 -3
View File
@@ -979,6 +979,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
@@ -1038,11 +1039,11 @@ pkg_check_modules(lapacke REQUIRED lapacke)
add_library(PHY_UE ${PHY_SRC_UE})
target_link_libraries(PHY_UE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs UTIL)
# RHEL needs also cblas, but Ubuntu does not have it. So `cblas_LIBRARIES` will
# be empty for Ubuntu, a no-op
# RHEL needs also cblas, but Ubuntu does not have it. So `cblas_LIBRARIES` and
# `cblas_INCLUDE_DIRS` will be empty for Ubuntu, a no-op
pkg_check_modules(cblas cblas)
target_link_libraries(PHY_UE PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES})
target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${lapacke_INCLUDE_DIRS})
target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${cblas_INCLUDE_DIRS} ${lapacke_INCLUDE_DIRS})
add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON})
target_link_libraries(PHY_NR_COMMON PUBLIC UTIL)
-228
View File
@@ -1,228 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Location of the executor node
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
// Name of the resource
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess = false
def eNB_TargetBranch
def directoryExistsGlob(fileNameWithGlob) {
/* if multiple directories match, will join their names and call fileExists() on that */
def dir = sh returnStdout: true, script: 'find . -name \'' + fileNameWithGlob + '\' -type d'
dir = dir.replaceAll("\n", "").trim()
echo "matching '" + fileNameWithGlob + "' found: '" + dir + "'"
if (dir == "")
return false
return fileExists(dir)
}
//-------------------------------------------------------------------------------
// Pipeline start
pipeline {
agent {
label pythonExecutor
}
options {
timestamps()
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ('Verify Parameters') {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
echo "no eNB_SourceCodePath given"
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest != null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
} else {
echo "no eNB_mergeRequest given - not merging develop"
}
if (params.OC_Credentials == null) {
echo "no OC_Credentials given"
allParametersPresent = false
}
if (params.OC_ProjectName == null) {
echo "no OC_ProjectName given"
allParametersPresent = false
}
if (params.pythonTestXmlFile == null) {
echo "no pythonTestXmlFile given"
allParametersPresent = false
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
echo "Some parameters are missing"
sh "./ci-scripts/fail.sh"
}
}
}
}
stage ("Deploy and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
]) {
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
}
stage ("Log Collection") {
steps {
script {
dir ('ci-scripts') {
if (directoryExistsGlob("build_log_*")) {
sh "zip -r -qq build_log_${env.BUILD_ID}.zip build_log_*/*"
sh "rm -rf build_log_*/"
archiveArtifacts artifacts: "build_log_${env.BUILD_ID}.zip"
}
if (directoryExistsGlob("test_log_*")) {
sh "zip -r -qq test_log_${env.BUILD_ID}.zip test_log_*/*"
sh "rm -rf test_log_*/"
archiveArtifacts artifacts: "test_log_${env.BUILD_ID}.zip"
}
if (fileExists("test_results.html")) {
sh "mv test_results.html test_results-${env.JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
}
}
}
}
}
}
}
-223
View File
@@ -1,223 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Location of the executor node
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
// Name of the resource
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess = false
def eNB_TargetBranch
// Flags
def scmEvent = false
def upstreamEvent = false
//-------------------------------------------------------------------------------
// Pipeline start
pipeline {
agent {
label pythonExecutor
}
options {
timestamps()
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ('Verify Parameters') {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest != null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
}
if (params.OC_Credentials == null) {
allParametersPresent = false
}
if (params.OC_ProjectName == null) {
allParametersPresent = false
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
echo "Some parameters are missing"
sh "./ci-scripts/fail.sh"
}
}
}
}
stage ("Deploy and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
// If not present picking a default XML file
if (params.pythonTestXmlFile == null) {
// picking default
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
echo "Test XML file(default): ${testXMLFile}"
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
} else {
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
]) {
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
}
stage ("Log Collection") {
steps {
script {
dir ('ci-scripts') {
// Zipping all archived log files
sh "mkdir test_logs"
sh "mv *.log* test_logs || true"
// Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip
if (fileExists('../cmake_targets/log')) {
sh "mv ../cmake_targets/log/* test_logs || true"
}
sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/"
sh "rm -rf *test_log*/"
if (fileExists("test_logs_${env.BUILD_ID}.zip")) {
archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip"
}
if (fileExists("test_results.html")) {
sh "mv test_results.html test_results-${env.JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
}
}
}
}
}
}
}
-224
View File
@@ -1,224 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Location of the executor node
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
// Name of the resource
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess = false
def eNB_TargetBranch
// Flags
def scmEvent = false
def upstreamEvent = false
//-------------------------------------------------------------------------------
// Pipeline start
pipeline {
agent {
label pythonExecutor
}
options {
timestamps()
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ('Verify Parameters') {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest != null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
}
if (params.OC_Credentials == null) {
allParametersPresent = false
}
if (params.OC_ProjectName == null) {
allParametersPresent = false
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
echo "Some parameters are missing"
sh "./ci-scripts/fail.sh"
}
}
}
}
stage ("Deploy and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
// If not present picking a default XML file
if (params.pythonTestXmlFile == null) {
// picking default
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
echo "Test XML file(default): ${testXMLFile}"
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
} else {
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
}
withCredentials([
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
]) {
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
}
stage ("Log Collection") {
steps {
script {
dir ('ci-scripts') {
// Zipping all archived log files
sh "mkdir test_logs"
sh "mv *.log* test_logs || true"
// Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip
if (fileExists('../cmake_targets/log')) {
sh "mv ../cmake_targets/log/* test_logs || true"
}
sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/"
sh "rm -rf *test_log*/"
if (fileExists("test_logs_${env.BUILD_ID}.zip")) {
archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip"
}
if (fileExists("test_results.html")) {
sh "mv test_results.html test_results-${env.JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html"
}
}
}
}
}
}
}
-250
View File
@@ -1,250 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
// Location of the python executor node shall be in the same subnet as the others servers
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Terminate Status
def termENB = 0
def termStatusArray = new Boolean[termENB + 1]
termStatusArray[termENB] = false
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess = false
def eNB_TargetBranch
def doEpcLogCollection = true
pipeline {
agent {
label pythonExecutor
}
options {
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ("Verify Parameters") {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest != null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
currentBuild.result = 'ABORTED'
error('Stopping early because some parameters are missing')
}
}
}
}
stage ("Build and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
// If not present picking a default XML file
if (params.pythonTestXmlFile == null) {
// picking default
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
echo "Test XML file(default): ${testXMLFile}"
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
} else {
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
}
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
stage ("Terminate") {
parallel {
stage('Terminate eNB') {
steps {
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
}
post {
success {
script {
termStatusArray[termENB] = true
}
}
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Run)') {
steps {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
script {
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
}
if(fileExists("ci-scripts/test_results.html")) {
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts "test_results-${JOB_NAME}.html"
}
}
}
}
}
}
}
post {
always {
script {
if (params.pipelineZipsConsoleLog != null) {
if (params.pipelineZipsConsoleLog) {
echo "Archiving Jenkins console log"
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
}
}
}
}
}
// Making sure that we really shutdown every thing before leaving
failure {
script {
if (!termStatusArray[termENB]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
}
}
}
}
}
-225
View File
@@ -1,225 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
// Location of the python executor node shall be in the same subnet as the others servers
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess = false
def eNB_TargetBranch
pipeline {
agent {
label pythonExecutor
}
options {
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ("Verify Parameters") {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest != null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
echo "Some parameters are missing"
sh "./ci-scripts/fail.sh"
}
}
}
}
stage ("Build and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
// If not present picking a default XML file
if (params.pythonTestXmlFile == null) {
// picking default
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
echo "Test XML file(default): ${testXMLFile}"
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
} else {
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
}
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
stage ("Terminate") {
parallel {
stage('Terminate eNB') {
steps {
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Run)') {
steps {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
script {
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
}
if(fileExists("ci-scripts/test_results.html")) {
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts "test_results-${JOB_NAME}.html"
}
}
}
}
}
}
}
post {
always {
script {
if (params.pipelineZipsConsoleLog != null) {
if (params.pipelineZipsConsoleLog) {
echo "Archiving Jenkins console log"
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
}
}
}
}
}
}
}
-216
View File
@@ -1,216 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
// Location of the python executor node shall be in the same subnet as the others servers
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess
def eNB_TargetBranch
//Status fed to the database
def StatusForDb = ""
pipeline {
agent {label pythonExecutor}
options {
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ("Verify Parameters") {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest!= null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
echo "Some parameters are missing"
sh "./ci-scripts/fail.sh"
}
}
}
}
stage ("Build and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
// If not present picking a default XML file
if (params.pythonTestXmlFile == null) {
// picking default
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
echo "Test XML file(default): ${testXMLFile}"
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
} else {
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
}
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Run)') {
steps {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
script {
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
}
}
}
}
}
}
}
post {
always {
script {
if(fileExists("ci-scripts/test_results.html")) {
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts "test_results-${JOB_NAME}.html"
}
if (params.pipelineZipsConsoleLog != null) {
if (params.pipelineZipsConsoleLog) {
echo "Archiving Jenkins console log"
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
}
}
}
}
}
}
}
-260
View File
@@ -1,260 +0,0 @@
#!/bin/groovy
/*
* 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
*/
// Template Jenkins Declarative Pipeline script to run Test w/ RF HW
// Location of the python executor node shall be in the same subnet as the others servers
def pythonExecutor = params.pythonExecutor
// Location of the test XML file to be run
def testXMLFile = params.pythonTestXmlFile
def mainPythonAllXmlFiles = ""
def buildStageStatus = true
// Name of the test stage
def testStageName = params.pipelineTestStageName
def lockResources = []
if (params.LockResources != null && params.LockResources.trim().length() > 0)
params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]}
// Terminate Status
def termUE = 0
def termENB = 1
def termSPGW = 2
def termMME = 3
def termHSS = 4
def termStatusArray = new Boolean[termHSS + 1]
termStatusArray[termUE] = false
termStatusArray[termENB] = false
termStatusArray[termSPGW] = false
termStatusArray[termMME] = false
termStatusArray[termHSS] = false
// Global Parameters. Normally they should be populated when the master job
// triggers the slave job with parameters
def eNB_Repository
def eNB_Branch
def eNB_CommitID
def eNB_AllowMergeRequestProcess = false
def eNB_TargetBranch
def flexricOption = ""
pipeline {
agent {
label pythonExecutor
}
options {
ansiColor('xterm')
lock(extra: lockResources)
}
stages {
stage("Build Init") {
steps {
// update the build name and description
buildName "${params.eNB_MR}"
buildDescription "Branch : ${params.eNB_Branch}"
}
}
stage ("Verify Parameters") {
steps {
script {
echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
def allParametersPresent = true
// It is already to late to check it
if (params.pythonExecutor != null) {
echo "eNB CI executor node : ${pythonExecutor}"
}
// If not present picking a default Stage Name
if (params.pipelineTestStageName == null) {
// picking default
testStageName = 'Template Test Stage'
}
if (params.LockResources == null) {
echo "no LockResources given"
allParametersPresent = false
}
if (params.eNB_SourceCodePath == null) {
allParametersPresent = false
}
// the following 4 parameters should be pushed by the master trigger
// if not present, take the job GIT variables (used for developing)
if (params.eNB_Repository == null) {
eNB_Repository = env.GIT_URL
} else {
eNB_Repository = params.eNB_Repository
}
echo "eNB_Repository : ${eNB_Repository}"
if (params.eNB_Branch == null) {
eNB_Branch = env.GIT_BRANCH
} else {
eNB_Branch = params.eNB_Branch
}
echo "eNB_Branch : ${eNB_Branch}"
if (params.eNB_CommitID == null) {
eNB_CommitID = env.GIT_COMMIT
} else {
eNB_CommitID = params.eNB_CommitID
}
echo "eNB_CommitID : ${eNB_CommitID}"
if (params.eNB_mergeRequest != null) {
eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
if (eNB_AllowMergeRequestProcess) {
if (params.eNB_TargetBranch != null) {
eNB_TargetBranch = params.eNB_TargetBranch
} else {
eNB_TargetBranch = 'develop'
}
echo "eNB_TargetBranch : ${eNB_TargetBranch}"
}
}
if (params.Flexric_Tag != null) {
echo "This pipeline is configured to run with a FlexRIC deployment."
echo "Appending FlexRicTag option to the list of options"
flexricOption = "--FlexRicTag=${params.Flexric_Tag}"
echo "Using new Flexric option: ${flexricOption}"
}
if (allParametersPresent) {
echo "All parameters are present"
if (eNB_AllowMergeRequestProcess) {
sh "git fetch"
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
} else if (eNB_CommitID != 'develop') {
sh "git fetch"
sh "git checkout -f ${eNB_CommitID}"
}
} else {
error "Some parameters are missing"
}
}
}
}
stage ("Build and Test") {
steps {
script {
dir ('ci-scripts') {
echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
// If not present picking a default XML file
if (params.pythonTestXmlFile == null) {
// picking default
testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
echo "Test XML file(default): ${testXMLFile}"
mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
} else {
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
echo "Test XML file : ${xmlFile}"
} else {
echo "Test XML file ${xmlFile}: no such file"
}
}
}
sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} ${mainPythonAllXmlFiles}"
String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
for (xmlFile in myXmlTestSuite) {
if (fileExists(xmlFile)) {
try {
timeout (time: 60, unit: 'MINUTES') {
sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}"
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
buildStageStatus = false
}
}
}
sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}"
}
}
}
}
stage ("Terminate") {
parallel {
stage('Terminate eNB') {
steps {
echo '\u2705 \u001B[32mTerminate eNB\u001B[0m'
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
}
post {
success {
script {
termStatusArray[termENB] = true
}
}
}
}
}
}
stage('Log Collection') {
parallel {
stage('Log Collection (eNB - Run)') {
steps {
echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m'
sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}"
script {
if(fileExists("enb.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "enb.log.${env.BUILD_ID}.zip"
}
if(fileExists("ci-scripts/test_results.html")) {
sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html"
sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html"
archiveArtifacts "test_results-${JOB_NAME}.html"
}
}
}
}
}
}
}
post {
always {
script {
if (params.pipelineZipsConsoleLog != null) {
if (params.pipelineZipsConsoleLog) {
echo "Archiving Jenkins console log"
sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true"
sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true"
if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) {
archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip"
}
}
}
}
}
// Making sure that we really shutdown every thing before leaving
failure {
script {
if (!termStatusArray[termENB]) {
sh "python3 ci-scripts/main.py --mode=TerminateeNB"
}
}
}
}
}
+1 -1
View File
@@ -209,7 +209,7 @@ def CheckLogs(self, filename, HTML, RAN):
elif 'nv-cubb' in name:
msg = 'Undeploy PNF/Nvidia CUBB'
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb'])):
elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb','vnf'])):
logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m')
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
opt = f"xNB log analysis ({name})"
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
export UHD_IMAGES_DIR=$SNAP/uhd_images
exec $@
-4
View File
@@ -1,4 +0,0 @@
src=${dir}
obj-m += ${name}.o
${name}-y += ${objs}
ccflags-y += ${module_cc_opt}
@@ -1,66 +0,0 @@
# Analogue for standard CMake module with same name, appeared in CMake 2.8.3.
#
# Used for compatibility with older versions of cmake.
function(cmake_parse_arguments prefix options one_value_keywords multi_value_keywords)
set(all_keywords ${options} ${one_value_keywords} ${multi_value_keywords})
# Clear variables before parsing.
foreach(arg ${one_value_keywords} ${multie_value_keywords})
set(cpa_${arg})
endforeach()
foreach(arg ${options})
set(cpa_${arg} FALSE)
endforeach()
set(cpa_UNPARSED_ARGUMENTS)
set(current_keyword)
# Classification for current_keyword:
# 'ONE' or 'MULTY'.
set(current_keyword_type)
# now iterate over all arguments and fill the result variables
foreach(arg ${ARGN})
list(FIND all_keywords ${arg} keyword_index)
if(keyword_index EQUAL -1)
if(current_keyword)
if(current_keyword_type STREQUAL "ONE")
set(cpa_${current_keyword} ${arg})
set(current_keyword)
else(current_keyword_type STREQUAL "ONE")
list(APPEND cpa_${current_keyword} ${arg})
endif(current_keyword_type STREQUAL "ONE")
else(current_keyword)
list(APPEND cpa_UNPARSED_ARGUMENTS ${arg})
endif(current_keyword)
else(keyword_index EQUAL -1)
if(current_keyword AND current_keyword_type STREQUAL "ONE")
message(SEND_ERROR "Value is expected for one-value-keyword ${current_keyword}")
endif(current_keyword AND current_keyword_type STREQUAL "ONE")
list(FIND options ${arg} option_index)
if(option_index EQUAL -1)
set(current_keyword ${arg})
list(FIND one_value_keywords ${arg} one_value_index)
if(one_value_index EQUAL -1)
set(current_keyword_type "MULTI")
else(one_value_index EQUAL -1)
set(current_keyword_type "ONE")
endif(one_value_index EQUAL -1)
else(option_index EQUAL -1)
set(current_keyword)
set(cpa_${arg} TRUE)
endif(option_index EQUAL -1)
endif(keyword_index EQUAL -1)
endforeach(arg ${ARGN})
if(current_keyword AND current_keyword_type STREQUAL "ONE")
message(SEND_ERROR "Value is expected for one-value-keyword ${current_keyword}")
endif(current_keyword AND current_keyword_type STREQUAL "ONE")
# propagate the result variables to the caller:
foreach(keyword ${all_keywords} UNPARSED_ARGUMENTS)
set(${prefix}_${keyword} ${cpa_${keyword}} PARENT_SCOPE)
endforeach(keyword ${all_keywords})
endfunction(cmake_parse_arguments prefix options one_value_keywords multi_value_keywords)
@@ -1,48 +0,0 @@
# - Find mysqlclient
# Find the native MySQL includes and library
#
# MYSQL_INCLUDE_DIR - where to find mysql.h, etc.
# MYSQL_LIBRARIES - List of libraries when using MySQL.
# MYSQL_FOUND - True if MySQL found.
IF (MYSQL_INCLUDE_DIR)
# Already in cache, be silent
SET(MYSQL_FIND_QUIETLY TRUE)
ENDIF (MYSQL_INCLUDE_DIR)
FIND_PATH(MYSQL_INCLUDE_DIR mysql.h
/usr/local/include/mysql
/usr/include/mysql
)
SET(MYSQL_NAMES mysqlclient mysqlclient_r)
FIND_LIBRARY(MYSQL_LIBRARY
NAMES ${MYSQL_NAMES}
PATHS /usr/lib /usr/local/lib
PATH_SUFFIXES mysql
)
IF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY)
SET(MYSQL_FOUND TRUE)
SET( MYSQL_LIBRARIES ${MYSQL_LIBRARY} )
ELSE (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY)
SET(MYSQL_FOUND FALSE)
SET( MYSQL_LIBRARIES )
ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY)
IF (MYSQL_FOUND)
IF (NOT MYSQL_FIND_QUIETLY)
MESSAGE(STATUS "Found MySQL: ${MYSQL_LIBRARY}")
ENDIF (NOT MYSQL_FIND_QUIETLY)
ELSE (MYSQL_FOUND)
IF (MYSQL_FIND_REQUIRED)
MESSAGE(STATUS "Looked for MySQL libraries named ${MYSQL_NAMES}.")
MESSAGE(FATAL_ERROR "Could NOT find MySQL library")
ENDIF (MYSQL_FIND_REQUIRED)
ENDIF (MYSQL_FOUND)
MARK_AS_ADVANCED(
MYSQL_LIBRARY
MYSQL_INCLUDE_DIR
)
@@ -1,71 +0,0 @@
# - Look for GNU Bison, the parser generator
# Based off a news post from Andy Cedilnik at Kitware
# Defines the following:
# BISON_EXECUTABLE - path to the bison executable
# BISON_FILE - parse a file with bison
# BISON_PREFIX_OUTPUTS - Set to true to make BISON_FILE produce prefixed
# symbols in the generated output based on filename.
# So for ${filename}.y, you'll get ${filename}parse(), etc.
# instead of yyparse().
# BISON_GENERATE_DEFINES - Set to true to make BISON_FILE output the matching
# .h file for a .c file. You want this if you're using
# flex.
IF(NOT DEFINED BISON_PREFIX_OUTPUTS)
SET(BISON_PREFIX_OUTPUTS FALSE)
ENDIF(NOT DEFINED BISON_PREFIX_OUTPUTS)
IF(NOT DEFINED BISON_GENERATE_DEFINES)
SET(BISON_GENERATE_DEFINES FALSE)
ENDIF(NOT DEFINED BISON_GENERATE_DEFINES)
IF(NOT BISON_EXECUTABLE)
MESSAGE(STATUS "Looking for bison")
FIND_PROGRAM(BISON_EXECUTABLE bison)
IF(BISON_EXECUTABLE)
MESSAGE(STATUS "Looking for bison -- ${BISON_EXECUTABLE}")
ENDIF(BISON_EXECUTABLE)
ENDIF(NOT BISON_EXECUTABLE)
IF(BISON_EXECUTABLE)
MACRO(BISON_FILE FILENAME)
GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH)
IF("${PATH}" STREQUAL "")
SET(PATH_OPT "")
ELSE("${PATH}" STREQUAL "")
SET(PATH_OPT "/${PATH}")
ENDIF("${PATH}" STREQUAL "")
GET_FILENAME_COMPONENT(HEAD "${FILENAME}" NAME_WE)
IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
IF(BISON_PREFIX_OUTPUTS)
SET(PREFIX "${HEAD}")
ELSE(BISON_PREFIX_OUTPUTS)
SET(PREFIX "yy")
ENDIF(BISON_PREFIX_OUTPUTS)
SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.c")
IF(BISON_GENERATE_DEFINES)
SET(HEADER "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.h")
ADD_CUSTOM_COMMAND(
OUTPUT "${OUTFILE}" "${HEADER}"
COMMAND "${BISON_EXECUTABLE}"
ARGS "--name-prefix=${PREFIX}"
"--defines"
"--output-file=${OUTFILE}"
"${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" "${HEADER}" PROPERTIES GENERATED TRUE)
SET_SOURCE_FILES_PROPERTIES("${HEADER}" PROPERTIES HEADER_FILE_ONLY TRUE)
ELSE(BISON_GENERATE_DEFINES)
ADD_CUSTOM_COMMAND(
OUTPUT "${OUTFILE}"
COMMAND "${BISON_EXECUTABLE}"
ARGS "--name-prefix=${PREFIX}"
"--output-file=${OUTFILE}"
"${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE)
ENDIF(BISON_GENERATE_DEFINES)
ENDMACRO(BISON_FILE)
ENDIF(BISON_EXECUTABLE)
@@ -1,46 +0,0 @@
# - Look for GNU flex, the lexer generator.
# Defines the following:
# FLEX_EXECUTABLE - path to the flex executable
# FLEX_FILE - parse a file with flex
# FLEX_PREFIX_OUTPUTS - Set to true to make FLEX_FILE produce outputs of
# lex.${filename}.c, not lex.yy.c . Passes -P to flex.
IF(NOT DEFINED FLEX_PREFIX_OUTPUTS)
SET(FLEX_PREFIX_OUTPUTS FALSE)
ENDIF(NOT DEFINED FLEX_PREFIX_OUTPUTS)
IF(NOT FLEX_EXECUTABLE)
MESSAGE(STATUS "Looking for flex")
FIND_PROGRAM(FLEX_EXECUTABLE flex)
IF(FLEX_EXECUTABLE)
MESSAGE(STATUS "Looking for flex -- ${FLEX_EXECUTABLE}")
ENDIF(FLEX_EXECUTABLE)
ENDIF(NOT FLEX_EXECUTABLE)
IF(FLEX_EXECUTABLE)
MACRO(FLEX_FILE FILENAME)
GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH)
IF("${PATH}" STREQUAL "")
SET(PATH_OPT "")
ELSE("${PATH}" STREQUAL "")
SET(PATH_OPT "/${PATH}")
ENDIF("${PATH}" STREQUAL "")
IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
IF(FLEX_PREFIX_OUTPUTS)
GET_FILENAME_COMPONENT(PREFIX "${FILENAME}" NAME_WE)
ELSE(FLEX_PREFIX_OUTPUTS)
SET(PREFIX "yy")
ENDIF(FLEX_PREFIX_OUTPUTS)
SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/lex.${PREFIX}.c")
ADD_CUSTOM_COMMAND(
OUTPUT "${OUTFILE}"
COMMAND "${FLEX_EXECUTABLE}"
ARGS "--prefix=${PREFIX}"
"--outfile=${OUTFILE}"
"${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE)
ENDMACRO(FLEX_FILE)
ENDIF(FLEX_EXECUTABLE)
@@ -1,8 +0,0 @@
# FindGCCXML
# ----------
find_program(GCCXML
NAMES gccxml
PATHS "/usr/bin"
"usr/local/bin"
)
mark_as_advanced(GCCXML)
@@ -1,105 +0,0 @@
# - Support for building kernel modules
# This module defines several variables which may be used when build
# kernel modules.
#
# The following variables are set here:
# Kbuild_VERSION_STRING - kernel version.
# Kbuild_ARCH - architecture.
# Kbuild_BUILD_DIR - directory for build kernel and/or its components.
# Kbuild_VERSION_{MAJOR|MINOR|TWEAK} - kernel version components
# Kbuild_VERSION_STRING_CLASSIC - classic representation of version,
# where parts are delimited by dots.
#
# Cache variables which affect on this package:
# CMAKE_SYSTEM_VERSION - change Kbuild_VERSION_STRING
# Also, setting CMAKE_SYSTEM_VERSION will be interpreted by cmake as crosscompile.
#
# Cache variables(ADVANCED) which affect on this package:
# ARCH - if not empty, change Kbuild_ARCH
# KBUILD_DIR - change Kbuild_BUILD_DIR
set(Kbuild_VERSION_STRING ${CMAKE_SYSTEM_VERSION})
# Form classic version view.
string(REGEX MATCH "([0-9]+)\\.([0-9]+)[.-]([0-9]+)"
_kernel_version_match
"${Kbuild_VERSION_STRING}"
)
if(NOT _kernel_version_match)
message(FATAL_ERROR "Kernel version has unexpected format: ${Kbuild_VERSION_STRING}")
endif(NOT _kernel_version_match)
set(Kbuild_VERSION_MAJOR ${CMAKE_MATCH_1})
set(Kbuild_VERSION_MINOR ${CMAKE_MATCH_2})
set(Kbuild_VERSION_TWEAK ${CMAKE_MATCH_3})
# Version string for compare
set(Kbuild_VERSION_STRING_CLASSIC "${Kbuild_VERSION_MAJOR}.${Kbuild_VERSION_MINOR}.${Kbuild_VERSION_TWEAK}")
set(KBUILD_DIR "/lib/modules/${Kbuild_VERSION_STRING}/build" CACHE PATH
"Directory for build linux kernel and/or its components."
)
mark_as_advanced(KBUILD_DIR)
set(Kbuild_BUILD_DIR "${KBUILD_DIR}")
set(ARCH "" CACHE STRING
"Architecture for build linux kernel components for, empty string means autodetect."
)
mark_as_advanced(ARCH)
if(NOT ARCH)
# Autodetect arch.
execute_process(COMMAND uname -m
RESULT_VARIABLE uname_m_result
OUTPUT_VARIABLE ARCH_DEFAULT
)
if(NOT uname_m_result EQUAL 0)
message("'uname -m' failed:")
message("${ARCH_DEFAULT}")
message(FATAL_ERROR "Failed to determine system architecture.")
endif(NOT uname_m_result EQUAL 0)
string(REGEX REPLACE "\n$" "" ARCH_DEFAULT "${ARCH_DEFAULT}")
# Pairs of pattern-replace for postprocess architecture string from
# 'uname -m'.
# Taken from ./Makefile of the kernel build.
set(_kbuild_arch_replacers
"i.86" "x86"
"x86_64" "x86"
"sun4u" "sparc64"
"arm.*" "arm"
"sa110" "arm"
"s390x" "s390"
"parisc64" "parisc"
"ppc.*" "powerpc"
"mips.*" "mips"
"sh[234].*" "sh"
"aarch64.*" "arm64"
)
set(_current_pattern)
foreach(p ${_kbuild_arch_replacers})
if(_current_pattern)
string(REGEX REPLACE "${_current_pattern}" "${p}" ARCH_DEFAULT "${ARCH_DEFAULT}")
set(_current_pattern)
else(_current_pattern)
set(_current_pattern "${p}")
endif(_current_pattern)
endforeach(p ${_kbuild_arch_replacers})
set(Kbuild_ARCH "${ARCH_DEFAULT}")
else(NOT ARCH)
# User-provided value is used.
set(Kbuild_ARCH "${ARCH}")
endif(NOT ARCH)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Kbuild
REQUIRED_VARS Kbuild_BUILD_DIR
VERSION_VAR KBuild_VERSION_STRING_CLASSIC
)
-4
View File
@@ -1,4 +0,0 @@
src=${dir}
obj-m += ${name}.o
${name}-y += ${objs}
ccflags-y += ${module_cc_opt}
@@ -1,229 +0,0 @@
# Create rule for obtain one file by copying another one
function(rule_copy_file target_file source_file)
add_custom_command(OUTPUT ${target_file}
COMMAND cp -p ${source_file} ${target_file}
DEPENDS ${source_file}
)
endfunction(rule_copy_file target_file source_file)
# rule_copy_source([source_dir] file ...)
#
# Create rule for obtain file(s) in binary tree by copiing it from source tree.
#
# Files are given relative to ${source_dir}, if it is set, or
# relative to ${CMAKE_CURRENT_SOURCE_DIR}.
#
# Files will be copied into ${CMAKE_CURRENT_BINARY_DIR} with same
# relative paths.
#
# ${source_dir} should be absolute path(that is, starts from '/').
# Otherwise first argument is treated as first file to copy.
function(rule_copy_source file)
string(REGEX MATCH "^/" is_abs_path ${file})
if(is_abs_path)
set(source_dir ${file})
set(files ${ARGN})
else(is_abs_path)
set(source_dir ${CMAKE_CURRENT_SOURCE_DIR})
set(files ${file} ${ARGN})
endif(is_abs_path)
foreach(file_real ${files})
rule_copy_file("${CMAKE_CURRENT_BINARY_DIR}/${file_real}"
${source_dir}/${file_real})
endforeach(file_real ${files})
endfunction(rule_copy_source file)
# to_abs_path(output_var path [...])
#
# Convert relative path of file to absolute path:
# use path in source tree, if file already exist there.
# otherwise use path in binary tree.
# If initial path already absolute, return it.
function(to_abs_path output_var)
set(result)
foreach(path ${ARGN})
string(REGEX MATCH "^/" _is_abs_path ${path})
if(_is_abs_path)
list(APPEND result ${path})
else(_is_abs_path)
file(GLOB to_abs_path_file
"${CMAKE_CURRENT_SOURCE_DIR}/${path}"
)
if(NOT to_abs_path_file)
set (to_abs_path_file "${CMAKE_CURRENT_BINARY_DIR}/${path}")
endif(NOT to_abs_path_file)
list(APPEND result ${to_abs_path_file})
endif(_is_abs_path)
endforeach(path ${ARGN})
set("${output_var}" ${result} PARENT_SCOPE)
endfunction(to_abs_path output_var path)
# is_path_inside_dir(output_var dir path)
#
# Set output_var to true if path is absolute path inside given directory.
# NOTE: Path should be absolute.
macro(is_path_inside_dir output_var dir path)
file(RELATIVE_PATH _rel_path ${dir} ${path})
string(REGEX MATCH "^\\.\\." _is_not_inside_dir ${_rel_path})
if(_is_not_inside_dir)
set(${output_var} "FALSE")
else(_is_not_inside_dir)
set(${output_var} "TRUE")
endif(_is_not_inside_dir)
endmacro(is_path_inside_dir output_var dir path)
# Write given content to the file.
#
# If file is already exists and its content is same as written one, file
# is not rewritten, so its write timestamp remains unchanged.
function(file_update filename content)
if(EXISTS "${filename}")
file(READ "${filename}" old_content)
if(old_content STREQUAL "${content}")
return()
endif(old_content STREQUAL "${content}")
endif(EXISTS "${filename}")
# File doesn't exists or its content differ.
file(WRITE "${filename}" "${content}")
endfunction(file_update filename content)
# Write given content to the file in APPEND mode.
#
# For append we use position variable <pos> which should be initialized
# to 0 for every new build process and which is updated every time when
# this function is called.
# If file is already exists and its content at given <pos> is same as
# written one, file is not rewritten, so its write timestamp remains unchanged.
#
# Note, that file will not be rewritten if new build process issues less
# APPEND actions than one which create file.
# But similar problem exists for file_update() and even for built-in
# configure_file() command: file will not be removed if new build process
# do not call configure_file() for it.
function(file_update_append filename content POS)
set(pos "${${POS}}")
string(LENGTH "${content}" len)
# Update output variable first.
# This allows to use return() when need not to do anything
math(EXPR pos_new "${pos}+${len}")
set(${POS} "${pos_new}" PARENT_SCOPE)
if(EXISTS "${filename}")
file(READ "${filename}" old_content LIMIT "${len}" OFFSET "${pos}")
if(old_content STREQUAL "${content}")
return()
elseif(old_content STREQUAL "")
file(APPEND "${filename}" "${content}")
return()
endif(old_content STREQUAL "${content}")
else(EXISTS "${filename}")
if(NOT pos EQUAL 0)
message(FATAL_ERROR "Appending to non-zero position to non-existent file.")
endif(NOT pos EQUAL 0)
endif(EXISTS "${filename}")
# File doesn't exists or its content differ.
if(NOT pos EQUAL 0)
file(READ "${filename}" prefix LIMIT "${pos}")
else(NOT pos EQUAL 0)
set(prefix)
endif(NOT pos EQUAL 0)
file(WRITE "${filename}" "${prefix}${content}")
endfunction(file_update_append filename content POS)
# Common mechanism for output status message
# when checking different aspects.
#
# Normal using:
#
# check_begin("Checking <...>")
# if(NOT <check-already-has-been-done>)
# check_try() # Here message is printed
# # Perform check(try_compile(), etc.)
# endif(NOT <check-already-has-been-done>)
# check_end("<check-result>") # Here message is printed with result.
# Should be called (unconditionally) when new cheking is issued.
# Note, that given @status_msg is not printed at that step.
function(check_begin status_msg)
set(_check_status_msg ${status_msg} PARENT_SCOPE)
set(_check_has_tries PARENT_SCOPE)
endfunction(check_begin status_msg)
# Should be called before every real checking, that is which is not come
# from cache variables comparision.
#
# First call of that function is trigger printing of @status_msg,
# passed to check_begin().
function(check_try)
if(NOT _check_has_tries)
message(STATUS "${_check_status_msg}")
set(_check_has_tries "1" PARENT_SCOPE)
endif(NOT _check_has_tries)
endfunction(check_try)
# Should be called when cheking is end, and @result_msg should be short
# description of check result.
# If any check_try() has been issued before,
# "@status_msg - @result_msg"
# will be printed.
# Otherwise,
# "@status_msg - [cached] @result_msg"
# will be printed, at it will be the only message for that check.
function(check_end result_msg)
if(NOT _check_has_tries)
message(STATUS "${_check_status_msg} [cached] - ${result_msg}")
else(NOT _check_has_tries)
message(STATUS "${_check_status_msg} - ${result_msg}")
endif(NOT _check_has_tries)
set(_check_status_msg PARENT_SCOPE)
set(_check_has_tries PARENT_SCOPE)
endfunction(check_end result_msg)
# set_bool_string(var true_string false_string value [CACHE ... | PARENT_SCOPE])
#
# Set variable to one of two string according to true property of some value.
#
# If 'value' is true-evaluated, 'var' will be set to 'true_string',
# otherwise to 'var' will be set to 'false_string'.
# Like standard set(), macro accept CACHE and PARENT_SCOPE modifiers.
#
# Useful for form meaningful value for cache variables, contained result
# of some operation.
# Also may be used for form message for check_end().
macro(set_bool_string var true_string false_string value)
# Macro parameters are not a variables, so them cannot be tested
# using 'if(value)'.
# Usage 'if(${value})' leads to warnings since 2.6.4 when ${val}
# is boolean constant
# (because until 2.6.4 'if(value)' always dereference val).
# So copy 'value' to local variable for test it.
set(_set_bool_string_value ${value})
if(_set_bool_string_value)
set(${var} "${true_string}" ${ARGN})
else()
set(${var} "${false_string}" ${ARGN})
endif()
endmacro(set_bool_string)
# set_zero_string(var true_string false_string value [CACHE ... | PARENT_SCOPE])
#
# Set variable to one of two string according to zero property of some value.
#
# If 'value' is '0' (presizely), 'var' will be set to 'zero_string',
# otherwise to 'var' will be set to 'nonzero_string'.
# Like standard set(), macro accept CACHE and PARENT_SCOPE modifiers.
#
# Useful for form meaningful value for cache variables, contained result
# of execute_process().
# Also may be used for form message for check_end().
macro(set_zero_string var zero_string nonzero_string value)
set(_set_zero_string_value ${value})
if(_set_zero_string_value EQUAL "0")
set(${var} ${zero_string} ${ARGN})
else()
set(${var} ${nonzero_string} ${ARGN})
endif()
endmacro(set_zero_string)
File diff suppressed because it is too large Load Diff
-539
View File
@@ -1,539 +0,0 @@
set(kmodule_this_module_dir "${CMAKE_SOURCE_DIR}/cmake/modules/")
set(kmodule_test_sources_dir "${CMAKE_SOURCE_DIR}/cmake/kmodule_sources")
set(kmodule_function_map_file "")
if (CMAKE_CROSSCOMPILING)
if (KEDR_SYSTEM_MAP_FILE)
set (kmodule_function_map_file "${KEDR_SYSTEM_MAP_FILE}")
else (KEDR_SYSTEM_MAP_FILE)
# KEDR_SYSTEM_MAP_FILE is not specified, construct the default path
# to the symbol map file.
set (kmodule_function_map_file
"${KEDR_ROOT_DIR}/boot/System.map-${KBUILD_VERSION_STRING}"
)
endif (KEDR_SYSTEM_MAP_FILE)
endif (CMAKE_CROSSCOMPILING)
# List of unreliable functions, that is, the functions that may be
# be exported and mentioned in System.map but still cannot be used
# because no header provides their declarations.
set(unreliable_functions_list
"__kmalloc_node"
"kmem_cache_alloc_node"
"kmem_cache_alloc_node_notrace"
"kmem_cache_alloc_node_trace"
)
# kmodule_is_function_exist(function_name RESULT_VAR)
# Verify, whether given function exist in the kernel space on the current system.
# RESULT_VAR is TRUE, if function_name exist in the kernel space, FALSE otherwise.
# RESULT_VAR is cached.
function(kmodule_is_function_exist function_name RESULT_VAR)
check_begin("Looking for ${function_name} in the kernel")
if(NOT DEFINED ${RESULT_VAR})
check_try()
execute_process(
COMMAND sh "${kmodule_this_module_dir}/kmodule_files/scripts/lookup_kernel_function.sh"
${function_name} ${kmodule_function_map_file}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
RESULT_VARIABLE kmodule_is_function_exist_result
OUTPUT_QUIET)
if (kmodule_is_function_exist_result EQUAL 0)
list(FIND unreliable_functions_list ${function_name} unreliable_function_index)
if(unreliable_function_index GREATER -1)
# Additional verification for unreliable function
kbuild_try_compile(kmodule_function_is_exist_reliable
"${CMAKE_BINARY_DIR}/check_unreliable_functions/${function_name}"
"${kmodule_test_sources_dir}/check_unreliable_functions/${function_name}.c"
)
if(NOT kmodule_function_is_exist_reliable)
set(kmodule_is_function_exist_result 1)
endif(NOT kmodule_function_is_exist_reliable)
endif(unreliable_function_index GREATER -1)
endif(kmodule_is_function_exist_result EQUAL 0)
if (kmodule_is_function_exist_result EQUAL 0)
set(${RESULT_VAR} "TRUE" CACHE INTERNAL "Does ${function_name} exist in the kernel?")
elseif(kmodule_is_function_exist_result EQUAL 1)
set(${RESULT_VAR} "FALSE" CACHE INTERNAL "Does ${function_name} exist in the kernel?")
else(kmodule_is_function_exist_result EQUAL 0)
message(FATAL_ERROR
"Cannot determine whether function '${function_name}' exists in the kernel"
)
endif(kmodule_is_function_exist_result EQUAL 0)
endif(NOT DEFINED ${RESULT_VAR})
set_bool_string(check_result "found" "not found" ${${RESULT_VAR}})
check_end(${check_result})
endfunction(kmodule_is_function_exist function_name RESULT_VAR)
# Creates the list of functions that actually exist on the
# current system.
#
# kmodule_configure_kernel_functions(output_list
# {[REQUIRED | OPTIONAL] {func | ONE_OF_LIST}} ...)
#
# ONE_OF_LIST := ONE_OF_BEGIN {func ...} ONE_OF_END
#
# There are 2 modes of function lookup:
# OPTIONAL - if the function doesn't exist, it is silently ignored.
# REQUIRED - if the function doesn't exist, FATAL_ERROR message is printed.
#
# Initial mode is REQUIRED, and it can be changed at any time by REQUIRED
# and OPTIONAL keywords.
#
# ONE_OF_BEGIN/ONE_OF_END determine a section for which no more than one
# function among all listed there should exist. FATAL_ERROR message is
# printed otherwise. When mode is REQUIRED, precisely one function must
# exist.
# Inside this section other keywords must not be used (even another
# ONE_OF_BEGIN).
function(kmodule_configure_kernel_functions output_list)
set(kmodule_configure_kernel_functions_mode "REQUIRED")
set(kmodule_configure_kernel_functions_one_of_section "FALSE")
set(output_list_tmp)
set(${output_list})
foreach(arg ${ARGN})
if(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL")
if(kmodule_configure_kernel_functions_one_of_section)
message(FATAL_ERROR
"Inside ONE_OF_BEGIN/ONE_OF_END section, other keywords are not allowed."
)
endif(kmodule_configure_kernel_functions_one_of_section)
set(kmodule_configure_kernel_functions_mode ${arg})
elseif(arg STREQUAL "ONE_OF_BEGIN")
if(kmodule_configure_kernel_functions_one_of_section)
message(FATAL_ERROR "Nested ONE_OF_BEGIN/ONE_OF_END sections are not allowed.")
endif(kmodule_configure_kernel_functions_one_of_section)
set(kmodule_configure_kernel_functions_one_of_section "TRUE")
set(kmodule_configure_kernel_functions_one_of_section_function)
elseif(arg STREQUAL "ONE_OF_END")
if(NOT kmodule_configure_kernel_functions_one_of_section)
message(FATAL_ERROR "ONE_OF_END without ONE_OF_BEGIN is not allowed.")
endif(NOT kmodule_configure_kernel_functions_one_of_section)
if(kmodule_configure_kernel_functions_one_of_section_function)
list(APPEND output_list_tmp ${kmodule_configure_kernel_functions_one_of_section_function})
else(kmodule_configure_kernel_functions_one_of_section_function)
if(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED")
message(FATAL_ERROR
"None of the functions listed in ONE_OF section exist in the kernel but it is required."
)
endif(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED")
endif(kmodule_configure_kernel_functions_one_of_section_function)
set(kmodule_configure_kernel_functions_one_of_section "FALSE")
else(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL")
set(kmodule_func_varname _KMODULE_IS_${arg}_EXIST)
kedr_find_function(${arg} ${kmodule_func_varname})
if(kmodule_configure_kernel_functions_one_of_section)
if(${kmodule_func_varname})
if(kmodule_configure_kernel_functions_one_of_section_function)
message(FATAL_ERROR "Two functions from ONE_OF sections exist in the kernel.")
else(kmodule_configure_kernel_functions_one_of_section_function)
set(kmodule_configure_kernel_functions_one_of_section_function ${arg})
endif(kmodule_configure_kernel_functions_one_of_section_function)
endif(${kmodule_func_varname})
else(kmodule_configure_kernel_functions_one_of_section)
if(${kmodule_func_varname})
list(APPEND output_list_tmp ${arg})
else(${kmodule_func_varname})
if(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED")
message(FATAL_ERROR "Function ${arg} is not found in the kernel but it is required.")
endif(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED")
endif(${kmodule_func_varname})
endif(kmodule_configure_kernel_functions_one_of_section)
endif(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL")
endforeach(arg ${ARGN})
if(kmodule_configure_kernel_functions_one_of_section)
message(FATAL_ERROR "Found ONE_OF_BEGIN without ONE_OF_END")
endif(kmodule_configure_kernel_functions_one_of_section)
set(${output_list} ${output_list_tmp} PARENT_SCOPE)
endfunction(kmodule_configure_kernel_functions output_list)
############################################################################
# Utility macros to check for particular features. If the particular feature
# is supported, the macros will set the corresponding variable to TRUE,
# otherwise - to FALSE (the name of variable is mentioned in the comments
# for the macro).
############################################################################
# Check if the system has everything necessary to build at least simple
# kernel modules.
# The macro sets variable 'MODULE_BUILD_SUPPORTED'.
macro(check_module_build)
check_begin("Checking if kernel modules can be built on this system")
if (NOT MODULE_BUILD_SUPPORTED)
check_try()
kbuild_try_compile(module_build_supported_impl
"${CMAKE_BINARY_DIR}/check_module_build"
"${kmodule_test_sources_dir}/check_module_build/module.c"
)
set_bool_string(MODULE_BUILD_SUPPORTED "yes" "no" ${module_build_supported_impl}
CACHE INTERNAL "Can kernel modules be built on this system?"
)
endif (NOT MODULE_BUILD_SUPPORTED)
check_end("${MODULE_BUILD_SUPPORTED}")
if (NOT MODULE_BUILD_SUPPORTED)
message(FATAL_ERROR
"There are problems with building kernel modules on this system. "
"Please check that the appropriate kernel headers and build tools "
"are installed."
)
endif (NOT MODULE_BUILD_SUPPORTED)
endmacro(check_module_build)
# Check if reliable stack trace information can be obtained.
# This is the case, for example, if the kernel is compiled with support
# for frame pointers and/or stack unwind on.
# The macro sets variable 'STACK_TRACE_RELIABLE'.
macro(check_stack_trace)
check_begin("Checking if stack trace information is reliable")
if (NOT DEFINED STACK_TRACE_RELIABLE)
check_try()
kbuild_try_compile(stack_trace_reliable_impl
"${CMAKE_BINARY_DIR}/check_stack_trace"
"${kmodule_test_sources_dir}/check_stack_trace/module.c"
)
set_bool_string(STACK_TRACE_RELIABLE "yes" "no" ${stack_trace_reliable_impl}
CACHE INTERNAL "Are stack traces reliable on this system?")
endif (NOT DEFINED STACK_TRACE_RELIABLE)
check_end("${STACK_TRACE_RELIABLE}")
if (NOT STACK_TRACE_RELIABLE)
message ("\n[WARNING]\n"
"It looks like reliable stack traces cannot be obtained on this system.\n"
"The output of KEDR-based tools like LeakCheck will be less detailed\n"
"(each stack trace shown will contain only one frame).\n"
"If this is not acceptable, you could rebuild the kernel with\n"
"CONFIG_FRAME_POINTER or CONFIG_STACK_UNWIND (if available) set to \"y\"\n"
"and then reconfigure and rebuild KEDR.\n")
endif (NOT STACK_TRACE_RELIABLE)
endmacro(check_stack_trace)
# Check whether ring buffer is implemented by the kernel.
# Set cache variable RING_BUFFER_IMPLEMENTED according to this checking.
function(check_ring_buffer)
check_begin("Checking if ring buffer is implemented in the kernel")
if (NOT DEFINED RING_BUFFER_IMPLEMENTED)
check_try()
kbuild_try_compile(ring_buffer_implemented_impl
"${CMAKE_BINARY_DIR}/check_ring_buffer"
"${kmodule_test_sources_dir}/check_ring_buffer/module.c"
)
set_bool_string(RING_BUFFER_IMPLEMENTED "yes" "no" "${ring_buffer_implemented_impl}"
CACHE INTERNAL "Whether ring buffer is implemented in the kernel"
)
endif (NOT DEFINED RING_BUFFER_IMPLEMENTED)
check_end(${RING_BUFFER_IMPLEMENTED})
if (NOT RING_BUFFER_IMPLEMENTED)
message("\n[WARNING]\nRing buffer is not supported by the system.\n"
"The tracing facilities as well as call monitoring plugins will not be built.\n"
"If this is not acceptable, you could rebuild the kernel with\n"
"CONFIG_RING_BUFFER set to \"y\" and then reconfigure and rebuild KEDR.\n")
endif (NOT RING_BUFFER_IMPLEMENTED)
endfunction(check_ring_buffer)
# Check which memory allocator is used by the kernel.
# Set KERNEL_MEMORY_ALLOCATOR to 'slab', 'slub', 'slob' or 'other'.
#
# Some functions in that allocators may have same names, but different signatures.
function(check_allocator)
check_begin("Checking which memory allocator is used by the kernel")
if(NOT DEFINED KERNEL_MEMORY_ALLOCATOR)
check_try()
# Use local variable for detect allocator,
# Cache one will be set at the end
set(allocator "")
if(allocator STREQUAL "")
kbuild_try_compile(is_allocator_slab
"${CMAKE_BINARY_DIR}/check_allocator_slab"
"${kmodule_test_sources_dir}/check_allocator/module.c"
KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLAB"
)
if (is_allocator_slab)
set(allocator "slab")
endif (is_allocator_slab)
endif(allocator STREQUAL "")
if(allocator STREQUAL "")
kbuild_try_compile(is_allocator_slub
"${CMAKE_BINARY_DIR}/check_allocator_slub"
"${kmodule_test_sources_dir}/check_allocator/module.c"
KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLUB"
)
if (is_allocator_slub)
set(allocator "slub")
endif (is_allocator_slub)
endif(allocator STREQUAL "")
if(allocator STREQUAL "")
kbuild_try_compile(is_allocator_slob
"${CMAKE_BINARY_DIR}/check_allocator_slob"
"${kmodule_test_sources_dir}/check_allocator/module.c"
KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLOB"
)
if (is_allocator_slob)
set(allocator "slob")
endif (is_allocator_slub)
endif(allocator STREQUAL "")
if(allocator STREQUAL "")
set(allocator "other")
endif(allocator STREQUAL "")
set(KERNEL_MEMORY_ALLOCATOR "${allocator}" CACHE INTERNAL
"Memory allocator which is used by the kernel"
)
endif (NOT DEFINED KERNEL_MEMORY_ALLOCATOR)
check_end("${KERNEL_MEMORY_ALLOCATOR}")
endfunction(check_allocator)
# Check if 'kfree_rcu' is available in the kernel (it is likely to be
# a macro or an inline). If it is available, we should handle it as
# 'free' in LeakCheck. As KEDR cannot normally intercept kfree_rcu()
# itself, it needs to intercept call_rcu/call_rcu_sched and check their
# arguments.
# The macro sets variable 'HAVE_KFREE_RCU'.
macro(check_kfree_rcu)
check_begin("Checking if kfree_rcu() is available")
if (NOT DEFINED HAVE_KFREE_RCU)
check_try()
kbuild_try_compile(have_kfree_rcu_impl
"${CMAKE_BINARY_DIR}/check_kfree_rcu"
"${kmodule_test_sources_dir}/check_kfree_rcu/module.c"
)
set_bool_string(HAVE_KFREE_RCU "yes" "no" ${have_kfree_rcu_impl}
CACHE INTERNAL "Is kfree_rcu() available?"
)
endif ()
check_end("${HAVE_KFREE_RCU}")
endmacro(check_kfree_rcu)
############################################################################
# Check if posix_acl_from_xattr() accepts struct user_namespace as the
# first argument.
# The macro sets variable 'POSIX_ACL_XATTR_HAS_USER_NS'.
macro(check_xattr_user_ns)
check_begin("Checking if posix_acl_from_xattr() has struct user_namespace * argument")
if (NOT DEFINED POSIX_ACL_XATTR_HAS_USER_NS)
check_try()
kbuild_try_compile(have_xattr_user_ns_impl
"${CMAKE_BINARY_DIR}/check_xattr_user_ns"
"${kmodule_test_sources_dir}/check_xattr_user_ns/module.c"
)
set_bool_string(POSIX_ACL_XATTR_HAS_USER_NS "yes" "no" ${have_xattr_user_ns_impl}
CACHE INTERNAL "Does posix_acl_from_xattr() have struct user_namespace argument?"
)
endif ()
check_end("${POSIX_ACL_XATTR_HAS_USER_NS}")
endmacro(check_xattr_user_ns)
############################################################################
# Check if hlist_for_each_entry*() macros accept only 'type *pos' argument
# rather than both 'type *tpos' and 'hlist_node *pos' as the loop cursors.
# The macro sets variable 'HLIST_FOR_EACH_ENTRY_POS_ONLY'.
macro(check_hlist_for_each_entry)
check_begin("Checking the signatures of hlist_for_each_entry*() macros")
if (NOT DEFINED HLIST_FOR_EACH_ENTRY_POS_ONLY)
check_try()
kbuild_try_compile(pos_only_impl
"${CMAKE_BINARY_DIR}/check_hlist_for_each_entry"
"${kmodule_test_sources_dir}/check_hlist_for_each_entry/module.c"
)
set_bool_string(HLIST_FOR_EACH_ENTRY_POS_ONLY "yes" "no" ${pos_only_impl}
CACHE INTERNAL
"Do hlist_for_each_entry*() macros have only 'type *pos' to use as a loop cursor?"
)
endif ()
set_bool_string(check_result "do not use additional loop cursor" "use additional loop cursor"
${HLIST_FOR_EACH_ENTRY_POS_ONLY})
check_end(${check_result})
endmacro(check_hlist_for_each_entry)
############################################################################
# Check if 'random32' is available in the kernel.
# The macro sets variable 'KEDR_HAVE_RANDOM32'.
macro(check_random32)
check_begin("Checking if random32() is available")
if (NOT DEFINED KEDR_HAVE_RANDOM32)
check_try()
kbuild_try_compile(have_random32_impl
"${CMAKE_BINARY_DIR}/check_random32"
"${kmodule_test_sources_dir}/check_random32/module.c"
)
set_bool_string(KEDR_HAVE_RANDOM32 "yes" "no" "${have_random32_impl}"
CACHE INTERNAL "Is random32() available?"
)
endif ()
check_end("${KEDR_HAVE_RANDOM32}")
endmacro(check_random32)
############################################################################
# The payload modules should call kedr_find_function() for each kernel
# function they would like to process. If the function is not known
# to KEDR (absent from the "function database", see "functions/" directory),
# kedr_find_function() issues a fatal error.
#
# 'func_name' is the name of the function,
# 'found_var' is the name of the output variable (the variable will evaluate
# as "true" if found, as "false" otherwise).
function (kedr_find_function func_name found_var)
if (NOT DEFINED KEDR_DATA_FILE_${func_name})
message(FATAL_ERROR "Unsupported function: ${func_name}")
endif (NOT DEFINED KEDR_DATA_FILE_${func_name})
# OK, known function.
kmodule_is_function_exist(${func_name} ${found_var})
if (${found_var})
# Mark the function as used by at least one payload module.
# This can be used when preparing the tests for call interception.
# The actual value does not matter, it only matters that this
# variable is defined.
set(KEDR_FUNC_USED_${func_name} "yes" CACHE INTERNAL
"Is kernel function ${func_name} used by any payload module?")
set(${found_var} "${${found_var}}" PARENT_SCOPE)
else ()
set(${found_var} "NO" PARENT_SCOPE)
endif (${found_var})
endfunction (kedr_find_function func_name found_var)
# Returns (in ${path_var}) the path to the .data file for the function
# ${func_name}. The function must be present in the system and
# kedr_find_function() must be called for it before kedr_get_data_for_func().
function (kedr_get_data_for_func func_name path_var)
if (NOT DEFINED KEDR_FUNC_USED_${func_name})
message(FATAL_ERROR
"Attempt to lookup data for a function that is not marked as used: "
"${func_name}")
endif (NOT DEFINED KEDR_FUNC_USED_${func_name})
set(${path_var} "${KEDR_DATA_FILE_${func_name}}" PARENT_SCOPE)
endfunction (kedr_get_data_for_func func_name path_var)
# kedr_get_header_data_list(list_var func1 [func2 func3 ...])
# Get the list of paths to the 'header.data' files for the given functions.
# The functions must be present in the system and # kedr_find_function()
# must be called for each of them before kedr_get_header_data_list() is
# called.
# The resulting list is returned in ${list_var}. It will contain at least
# one item. It will not contain duplicates.
function (kedr_get_header_data_list list_var)
set(hdata_list)
foreach (func ${ARGN})
if (NOT DEFINED KEDR_FUNC_USED_${func})
message(FATAL_ERROR
"Attempt to lookup header data for a function that is not marked as used: "
"${func}")
endif (NOT DEFINED KEDR_FUNC_USED_${func})
list(APPEND hdata_list "${KEDR_HEADER_DATA_FILE_${func}}")
endforeach ()
list(REMOVE_DUPLICATES hdata_list)
list(LENGTH hdata_list hdata_list_len)
if (NOT hdata_list_len)
message(FATAL_ERROR
"kedr_get_header_data_list(): BUG: the output list is empty.")
endif (NOT hdata_list_len)
set(${list_var} ${hdata_list} PARENT_SCOPE)
endfunction (kedr_get_header_data_list list_var)
# kedr_create_header_rules(
# header_impl_file header_data_file func1 [func2 ...])
# Create the rules to generate ${header_impl_file} from
# ${header_data_file} and the specific header files for the given
# functions.
function(kedr_create_header_rules header_impl_file header_data_file
functions)
set(hlist_data)
kedr_get_header_data_list(hlist_data ${functions} ${ARGN})
to_abs_path(hdata_files_abs ${header_data_file} ${hlist_data})
add_custom_command(OUTPUT ${header_impl_file}
COMMAND cat ${hdata_files_abs} > ${header_impl_file}
DEPENDS ${hdata_files_abs}
)
endfunction(kedr_create_header_rules header_impl_file header_data_file
functions)
# kedr_create_data_rules(func)
# Create the rules to generate ${func}_impl.data from
# ${func}.data (contains processing instructions specific to the current
# payload) and the .data file from "func_db" (contains function signature).
function(kedr_create_data_rules func)
set(func_db_data_file)
kedr_get_data_for_func(${func} func_db_data_file)
set(func_proc_data_file)
to_abs_path(func_proc_data_file ${func}.data)
add_custom_command(OUTPUT "${func}_impl.data"
COMMAND printf "\"[group]\\n\"" > "${func}_impl.data"
COMMAND grep -E -v '\\[group\\]'
"${func_db_data_file}" >> "${func}_impl.data"
COMMAND printf "\"\\n\"" >> "${func}_impl.data"
COMMAND grep -E -v '\\[group\\]'
"${func_proc_data_file}" >> "${func}_impl.data"
DEPENDS
"${func_proc_data_file}"
"${func_db_data_file}"
)
endfunction(kedr_create_data_rules func)
# kedr_create_payload_module(module_name payload_data_file template_dir)
# Create the rules to build a payload module with the given name.
# 'payload_data_file' defines how the kernel functions are to be processed
# by this payload module.
# 'template_dir' - path to the direcotry containing the templates to be used
# to prepare the source code of the module from 'payload_data_file'.
function(kedr_create_payload_module module_name payload_data_file
template_dir)
# Rules to build the module
kbuild_add_module(${module_name}
"payload.c"
"functions_support.c"
)
kbuild_link_module(${module_name} kedr)
# Rules to obtain the source files of the module
kedr_generate("payload.c" ${payload_data_file} "${template_dir}")
kedr_generate("functions_support.c" ${payload_data_file} "${KEDR_GEN_TEMPLATES_DIR}/functions_support.c")
endfunction(kedr_create_payload_module module_name payload_data_file
template_dir)
# kedr_create_payload_data(payload_data_file func1 [func2 ...])
# Create .data files and the header data files for the functions and prepare
# the main .data file (${payload_data_file}) for the payload module.
function(kedr_create_payload_data header_data_file payload_data_file
functions)
set(header_impl_file "header_impl.data")
set(functions_data)
foreach(func ${functions} ${ARGN})
list(APPEND functions_data "${func}_impl.data")
kedr_create_data_rules(${func})
endforeach(func ${functions} ${ARGN})
kedr_create_header_rules(${header_impl_file} ${header_data_file}
${functions} ${ARGN})
to_abs_path(payload_data_file_abs ${payload_data_file})
to_abs_path(source_files_abs ${header_impl_file} ${functions_data})
set(payload_data_file_abs "${CMAKE_CURRENT_BINARY_DIR}/${payload_data_file}")
add_custom_command(OUTPUT ${payload_data_file_abs}
COMMAND cat ${source_files_abs} > ${payload_data_file_abs}
DEPENDS ${source_files_abs}
)
endfunction(kedr_create_payload_data header_data_file payload_data_file
functions)
############################################################################
@@ -1,98 +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
# */
# file example_oaisim_enb_ue_mme_virtual.txt
# brief
# author Lionel Gauthier
TODO: a document file, PDF for example, with nice pictures, etc
This example shows how to generate and launch enb, 1 ue (NAS still not virtualized in UE) in virtualised mode, mme_gw, hss executables on the same host:
################
Configuration
################
freediameter 1.2.0 (not 1.1.5, 1.1.6,...) has to be installed and patched (done by check_install_oai_software() calling install_freediameter_from_source() in script build_helper)
Config File:
/etc/hosts must contain the fqdn of the MME and HSS (same since both run on the same host):
(assuming the realm is openair4G.eur)
127.0.0.1 localhost
127.0.1.1 yang.openair4G.eur yang
...
################
BUILDING, RUNNING
################
Building HSS:
yang@yang:~/openair4G/trunk/cmake_targets$ tools/build_hss -c --connect-to-mme yang.openair4G.eur -t -T --realm openair4G.eur
Configuring the HSS:
In oai_db (easier for newbies to access HSS database through http://127.0.0.1/phpmyadmin)
In table mmeidentity, enter the record corresponding to your MME:
(idmmeidentity, mmehost, mmerealm)
In table pdn, enter the record allowing an IMSI to connect to an APN
In table users, enter the record corresponding to your USIM card.
Running the HSS:
yang@yang:~/openair4G/trunk/cmake_targets$ sudo tools/run_hss -g
Building the MME-GW:
yang@yang:~/openair4G/trunk/cmake_targets/tools$ ./build_epc -c -d -t -T --s6a-server
Configuring the MME-GW:
You can configure in file openair4G/trunk/cmake_targets/tools/epc.local.enb.conf.in the following parameters:
MCC/MNC of your network
SGI interface (outgoing interface of the S/P-GW)
Integrity algorithms, Ciphering algorithms
Please note that DNS addresses are hardcoded in source code (TODO in list).
Running the MME-GW:
yang@yang:~/openair4G/trunk/cmake_targets/tools$ sudo ./run_epc -l -g -K
Building eNB:
yang@yang:~/openair4G/trunk/cmake_targets$ ./build_oai --oaisim
Configuring the eNB:
The default configuration file for the eNB is trunk/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.generic.oaisim.local_mme.conf
Running eNB:
yang@yang:~/openair4G/trunk/cmake_targets$ tools/run_enb_ue_virt_s1 -m /tmp -K /tmp/enb_ue_virt_s1_itti.log
Putting some IP UL/DL traffic in the bearer:
ping -s 1000 -m 1 192.168.12.100 -I oip1
################
Tools available:
###############
1) itti_analyser (list messages exchanged between protocol layers)
2) xforms (Layer 1)
3) vcd (timing mesurements)
-21
View File
@@ -1,21 +0,0 @@
#!/usr/bin/env bash
CACHE_DIR=/mnt/oai_agent_cache
if [ ! -d $CACHE_DIR ]; then
echo "Creating cache dir in $CACHE_DIR"
sudo mkdir $CACHE_DIR
fi
if grep -qs "$CACHE_DIR" /proc/mounts; then
echo "Agent cache is already mounted"
else
echo "Agent cache was not mounted"
echo "Mounting..."
sudo mount -o size=100m -t tmpfs none "$CACHE_DIR"
if [ $? -eq 0 ]; then
echo "Mount success"
else
echo "Something went wrong with the mount"
fi
fi
-13
View File
@@ -1,13 +0,0 @@
#!/bin/bash
for i in $(seq 1 $1);
do
let table=1000+$i
echo "sudo ip route add 10.0.1.0/24 dev oaitun_ue$i table $table"
sudo ip route add 10.0.1.0/24 dev oaitun_ue$i table $table
echo "sudo ip route add default via 10.0.1.1 dev oaitun_ue$i table $table"
sudo ip route add default via 10.0.1.1 dev oaitun_ue$i table $table
let octet=$i+1
echo "sudo ip rule add from 10.0.1.$octet table $table"
sudo ip rule add from 10.0.1.$octet table $table
done
-171
View File
@@ -497,8 +497,6 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32
return carrier_freq;
}
static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx);
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
{
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
@@ -735,175 +733,6 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
return rem_samples + next_slot_first_symbol;
}
static void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame)
{
if (!UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.is_targetcell = false;
const int epoch_frame = UE->nrUE_config.ntn_config.epoch_sfn;
const int diff1 = (frame - epoch_frame + 1024) % 1024;
const int diff2 = (epoch_frame - frame + 1024) % 1024;
int *epoch_hfn = &UE->nrUE_config.ntn_config.epoch_hfn;
if (diff1 < diff2) { // epoch_frame in the past
LOG_I(PHY, "epoch is %d frames in the past\n", diff1);
if (epoch_frame <= frame)
*epoch_hfn = hfn;
else
*epoch_hfn = hfn - 1;
} else { // epoch_frame in the future
LOG_I(PHY, "epoch is %d frames in the future\n", diff2);
if (epoch_frame >= frame)
*epoch_hfn = hfn;
else
*epoch_hfn = hfn + 1;
}
LOG_I(PHY, "setting epoch_hfn = %d\n", *epoch_hfn);
}
#define SPEED_OF_LIGHT 299792458
// calculate TA and Doppler based on the NTN-Config, if abs_subframe_tx < 0 then apply only Doppler
static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx)
{
const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
// Handle terrestrial networks
if (ntn_config_params->cell_specific_k_offset == 0) {
if (abs_subframe_tx >= 0)
UE->timing_advance_ntn = 0;
UE->dl_Doppler_shift = 0;
UE->ul_Doppler_shift = 0;
return;
}
const int abs_subframe_epoch = ntn_config_params->epoch_subframe
+ ntn_config_params->epoch_sfn * 10
+ ntn_config_params->epoch_hfn * 10240;
const int ms_since_epoch = abs_subframe_tx < 0 ? 0 : abs_subframe_tx - abs_subframe_epoch;
const position_t pos_sat_0 = ntn_config_params->pos_sat_0;
const position_t vel_sat_0 = ntn_config_params->vel_sat_0;
position_t pos_sat;
position_t vel_sat;
const double omega = ntn_config_params->omega;
if (omega) {
const double cos_wt = cos(omega * ms_since_epoch);
const double sin_wt = sin(omega * ms_since_epoch);
const position_t pos_sat_90 = ntn_config_params->pos_sat_90;
pos_sat = (position_t){pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt,
pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt,
pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt};
const position_t vel_sat_90 = ntn_config_params->vel_sat_90;
vel_sat = (position_t){vel_sat_0.X * cos_wt + vel_sat_90.X * sin_wt,
vel_sat_0.Y * cos_wt + vel_sat_90.Y * sin_wt,
vel_sat_0.Z * cos_wt + vel_sat_90.Z * sin_wt};
} else {
pos_sat = (position_t){pos_sat_0.X + vel_sat_0.X * ms_since_epoch / 1000,
pos_sat_0.Y + vel_sat_0.Y * ms_since_epoch / 1000,
pos_sat_0.Z + vel_sat_0.Z * ms_since_epoch / 1000};
vel_sat = vel_sat_0;
}
position_t pos_ue = {0};
get_position_coordinates(UE->Mod_id, &pos_ue);
// calculate directional vector from SAT to UE
const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z};
// calculate distance between SAT and UE
const double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z);
// calculate projected velocity from SAT towards UE
const double vel_sat_ue = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance;
// calculate DL Doppler shift (moving source)
const double dl_Doppler_shift = (vel_sat_ue / (SPEED_OF_LIGHT - vel_sat_ue)) * fp->dl_CarrierFreq;
// calculate UL Doppler shift (moving target)
const double ul_Doppler_shift = (vel_sat_ue / SPEED_OF_LIGHT) * fp->ul_CarrierFreq;
// calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000)
const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT;
const double N_common_ta_adj = ntn_config_params->N_common_ta_adj;
const double N_common_ta_drift = ntn_config_params->N_common_ta_drift;
const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant;
if (abs_subframe_tx >= 0) {
UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj + N_common_ta_drift * ms_since_epoch / 1e6
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
* fp->samples_per_subframe;
}
UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift;
UE->dl_Doppler_shift = dl_Doppler_shift;
UE->ul_Doppler_shift = ul_Doppler_shift;
if (abs_subframe_tx < 0) {
LOG_I(PHY,
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n",
vel_sat_ue,
dl_Doppler_shift / 1000,
ul_Doppler_shift / 1000);
}
}
// apply values based on the NTN-Config
static void apply_ntn_config(PHY_VARS_NR_UE *UE,
NR_DL_FRAME_PARMS *fp,
int hfn_rx,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
int *timing_advance,
int *ntn_koffset,
bool *ntn_targetcell)
{
// return if there is no pending update
if (!UE->nrUE_config.ntn_config.params_changed)
return;
*ntn_targetcell = UE->nrUE_config.ntn_config.is_targetcell;
// skip update if it is for the target cell
if (UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.params_changed = false;
const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
const int mu = fp->numerology_index;
const int koffset = ntn_config_params->cell_specific_k_offset;
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
if (koffset > *ntn_koffset)
*timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu);
else if (koffset < *ntn_koffset)
*timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu);
*ntn_koffset = koffset;
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
apply_ntn_timing_advance_and_doppler(UE, fp, abs_subframe_tx);
LOG_I(PHY,
"k_offset: %dms, N_Common_Ta: %fms, drift: %fµs/s, variant: %fµs/s², "
"timing_advance_ntn: %d samples, DL Doppler shift: %fkHz, UL Doppler shift: %fkHz\n",
koffset << mu,
ntn_config_params->N_common_ta_adj,
ntn_config_params->N_common_ta_drift,
ntn_config_params->N_common_ta_drift_variant,
UE->timing_advance_ntn,
UE->dl_Doppler_shift / 1000,
UE->ul_Doppler_shift / 1000);
}
void *UE_thread(void *arg)
{
//this thread should be over the processing thread to keep in real time
@@ -40,7 +40,6 @@ Linking C shared module libldpc_aal.so
At runtime, to successfully use LDPC accelerators (e.g., Xilinx T2/Intel ACCs), you will need to install the corresponding drivers and tools.
Please refer to the dedicated documentation at [LDPC_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_OFFLOAD_SETUP.md).
<<<<<<< HEAD
```
./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 01:00.0 --nrLDPC_coding_aal.dpdk_core_list 0-1
```
@@ -12,11 +12,7 @@ data storage. */
#include<complex.h>
#include <stdlib.h>
#include <linux/version.h>
#if defined RHEL_RELEASE_CODE
#include <cblas/cblas.h>
#else
#include <cblas.h>
#endif
#include <string.h>
#include <linux/version.h>
#include <lapacke_utils.h>
+191
View File
@@ -0,0 +1,191 @@
/*
* 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 "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame)
{
if (!UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.is_targetcell = false;
const int epoch_frame = UE->nrUE_config.ntn_config.epoch_sfn;
const int diff1 = (frame - epoch_frame + 1024) % 1024;
const int diff2 = (epoch_frame - frame + 1024) % 1024;
int *epoch_hfn = &UE->nrUE_config.ntn_config.epoch_hfn;
if (diff1 < diff2) { // epoch_frame in the past
LOG_I(PHY, "epoch is %d frames in the past\n", diff1);
if (epoch_frame <= frame)
*epoch_hfn = hfn;
else
*epoch_hfn = hfn - 1;
} else { // epoch_frame in the future
LOG_I(PHY, "epoch is %d frames in the future\n", diff2);
if (epoch_frame >= frame)
*epoch_hfn = hfn;
else
*epoch_hfn = hfn + 1;
}
LOG_I(PHY, "setting epoch_hfn = %d\n", *epoch_hfn);
}
#define SPEED_OF_LIGHT 299792458
// calculate TA and Doppler based on the NTN-Config, if abs_subframe_tx < 0 then apply only Doppler
void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx)
{
const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
// Handle terrestrial networks
if (ntn_config_params->cell_specific_k_offset == 0) {
if (abs_subframe_tx >= 0)
UE->timing_advance_ntn = 0;
UE->dl_Doppler_shift = 0;
UE->ul_Doppler_shift = 0;
return;
}
const int abs_subframe_epoch = ntn_config_params->epoch_subframe
+ ntn_config_params->epoch_sfn * 10
+ ntn_config_params->epoch_hfn * 10240;
const int ms_since_epoch = abs_subframe_tx < 0 ? 0 : abs_subframe_tx - abs_subframe_epoch;
const position_t pos_sat_0 = ntn_config_params->pos_sat_0;
const position_t vel_sat_0 = ntn_config_params->vel_sat_0;
position_t pos_sat;
position_t vel_sat;
const double omega = ntn_config_params->omega;
if (omega) {
const double cos_wt = cos(omega * ms_since_epoch);
const double sin_wt = sin(omega * ms_since_epoch);
const position_t pos_sat_90 = ntn_config_params->pos_sat_90;
pos_sat = (position_t){pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt,
pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt,
pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt};
const position_t vel_sat_90 = ntn_config_params->vel_sat_90;
vel_sat = (position_t){vel_sat_0.X * cos_wt + vel_sat_90.X * sin_wt,
vel_sat_0.Y * cos_wt + vel_sat_90.Y * sin_wt,
vel_sat_0.Z * cos_wt + vel_sat_90.Z * sin_wt};
} else {
pos_sat = (position_t){pos_sat_0.X + vel_sat_0.X * ms_since_epoch / 1000,
pos_sat_0.Y + vel_sat_0.Y * ms_since_epoch / 1000,
pos_sat_0.Z + vel_sat_0.Z * ms_since_epoch / 1000};
vel_sat = vel_sat_0;
}
position_t pos_ue = {0};
get_position_coordinates(UE->Mod_id, &pos_ue);
// calculate directional vector from SAT to UE
const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z};
// calculate distance between SAT and UE
const double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z);
// calculate projected velocity from SAT towards UE
const double vel_sat_ue = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance;
// calculate DL Doppler shift (moving source)
const double dl_Doppler_shift = (vel_sat_ue / (SPEED_OF_LIGHT - vel_sat_ue)) * fp->dl_CarrierFreq;
// calculate UL Doppler shift (moving target)
const double ul_Doppler_shift = (vel_sat_ue / SPEED_OF_LIGHT) * fp->ul_CarrierFreq;
// calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000)
const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT;
const double N_common_ta_adj = ntn_config_params->N_common_ta_adj;
const double N_common_ta_drift = ntn_config_params->N_common_ta_drift;
const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant;
if (abs_subframe_tx >= 0) {
UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj + N_common_ta_drift * ms_since_epoch / 1e6
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
* fp->samples_per_subframe;
}
UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift;
UE->dl_Doppler_shift = dl_Doppler_shift;
UE->ul_Doppler_shift = ul_Doppler_shift;
if (abs_subframe_tx < 0) {
LOG_I(PHY,
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n",
vel_sat_ue,
dl_Doppler_shift / 1000,
ul_Doppler_shift / 1000);
}
}
// apply values based on the NTN-Config
void apply_ntn_config(PHY_VARS_NR_UE *UE,
NR_DL_FRAME_PARMS *fp,
int hfn_rx,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
int *timing_advance,
int *ntn_koffset,
bool *ntn_targetcell)
{
// return if there is no pending update
if (!UE->nrUE_config.ntn_config.params_changed)
return;
*ntn_targetcell = UE->nrUE_config.ntn_config.is_targetcell;
// skip update if it is for the target cell
if (UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.params_changed = false;
const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
const int mu = fp->numerology_index;
const int koffset = ntn_config_params->cell_specific_k_offset;
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
if (koffset > *ntn_koffset)
*timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu);
else if (koffset < *ntn_koffset)
*timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu);
*ntn_koffset = koffset;
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
apply_ntn_timing_advance_and_doppler(UE, fp, abs_subframe_tx);
LOG_I(PHY,
"k_offset: %dms, N_Common_Ta: %fms, drift: %fµs/s, variant: %fµs/s², "
"timing_advance_ntn: %d samples, DL Doppler shift: %fkHz, UL Doppler shift: %fkHz\n",
koffset << mu,
ntn_config_params->N_common_ta_adj,
ntn_config_params->N_common_ta_drift,
ntn_config_params->N_common_ta_drift_variant,
UE->timing_advance_ntn,
UE->dl_Doppler_shift / 1000,
UE->ul_Doppler_shift / 1000);
}
@@ -330,7 +330,17 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
pdsch_scope_req_t *scope_req);
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData);
void apply_ntn_config(PHY_VARS_NR_UE *UE,
NR_DL_FRAME_PARMS *fp,
int hfn_rx,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
int *timing_advance,
int *ntn_koffset,
bool *ntn_targetcell);
void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame);
void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx);
void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid);
void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb);
-4
View File
@@ -108,10 +108,6 @@ int main(int argc, char **argv) {
.sdr_addrs=usrp_addrs,
//! Auto calibration flag
.autocal={0},
//! rf devices work with x bits iqs when oai have its own iq format
//! the two following parameters are used to convert iqs
.iq_txshift=0,
.iq_rxrescale=0,
//! Configuration file for LMS7002M
.configFilename="",
//! remote IP/MAC addr for Ethernet interface
+1 -1
View File
@@ -1742,7 +1742,7 @@ int main(int argc, char *argv[])
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving time");
printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate recovery time");
printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate matching time");
printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time");
printStatIndent(&gNB->rx_srs_stats,"RX SRS time");
printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time");
+2 -2
View File
@@ -473,8 +473,8 @@ typedef struct {
cell_id_t id;
// Cell type
uint8_t type;
// Time UE Stayed in Cell
long time_in_cell;
// Time UE Stayed in Cell (seconds)
uint16_t time_in_cell;
// Cause
ngap_cause_t *cause;
} last_visited_ngran_cell_info_t;
@@ -38,7 +38,7 @@
#include "executables/softmodem-common.h"
#include <stdio.h>
void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, const uint32_t Y)
static void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, const uint32_t Y)
{
LOG_T(NR_MAC_DCI, "Filling search candidates for DCI\n");
@@ -89,7 +89,7 @@ void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dc
rel15->number_of_candidates = i;
}
NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int coreset_id)
static NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int coreset_id)
{
if (config->commonControlResourceSet && coreset_id == config->commonControlResourceSet->controlResourceSetId)
return config->commonControlResourceSet;
@@ -362,12 +362,12 @@ bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per
return monitor;
}
bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
const NR_SearchSpace_t *ss,
const int abs_slot,
const int frame,
const int slot,
const int slots_per_frame)
static bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
const NR_SearchSpace_t *ss,
const int abs_slot,
const int frame,
const int slot,
const int slots_per_frame)
{
const int duration = ss->duration ? *ss->duration : 1;
int period, offset;
@@ -58,13 +58,6 @@ static const int nb_symbols_excluding_dmrs[11][2][2]
/* 14 */ {{ 12 , 12 } , { 10 , 10 }},
};
static int get_deltatf(uint16_t nb_of_prbs,
uint8_t N_symb_PUCCH,
uint8_t freq_hop_flag,
uint8_t add_dmrs_flag,
int N_sc_ctrl_RB,
int O_UCI);
// ∆MPR according to Table 6.2.2-3 38.101-1
static float get_delta_mpr(uint16_t nr_band, frame_type_t frame_type, int scs, int channel_bandwidth, int n_prbs, int start_prb, int power_class)
{
@@ -256,6 +249,28 @@ int get_sum_delta_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame)
return delta_tpc_sum;
}
static int get_deltatf(uint16_t nb_of_prbs,
uint8_t N_symb_PUCCH,
uint8_t freq_hop_flag,
uint8_t add_dmrs_flag,
int N_sc_ctrl_RB,
int O_UCI)
{
int DELTA_TF;
int O_CRC = compute_pucch_crc_size(O_UCI);
int N_symb = N_symb_PUCCH < 4 ? N_symb_PUCCH : nb_symbols_excluding_dmrs[N_symb_PUCCH - 4][add_dmrs_flag][freq_hop_flag];
float N_RE = nb_of_prbs * N_sc_ctrl_RB * N_symb;
float K1 = 6;
if (O_UCI + O_CRC < 12)
DELTA_TF = 10 * log10((double)(((K1 * (O_UCI)) / N_RE)));
else {
float K2 = 2.4;
float BPRE = (O_UCI + O_CRC) / N_RE;
DELTA_TF = 10 * log10((double)(pow(2, (K2 * BPRE)) - 1));
}
return DELTA_TF;
}
// PUCCH Power control according to 38.213 section 7.2.1
int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
int scs,
@@ -399,28 +414,6 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
return pucch_power;
}
static int get_deltatf(uint16_t nb_of_prbs,
uint8_t N_symb_PUCCH,
uint8_t freq_hop_flag,
uint8_t add_dmrs_flag,
int N_sc_ctrl_RB,
int O_UCI)
{
int DELTA_TF;
int O_CRC = compute_pucch_crc_size(O_UCI);
int N_symb = N_symb_PUCCH < 4 ? N_symb_PUCCH : nb_symbols_excluding_dmrs[N_symb_PUCCH - 4][add_dmrs_flag][freq_hop_flag];
float N_RE = nb_of_prbs * N_sc_ctrl_RB * N_symb;
float K1 = 6;
if (O_UCI + O_CRC < 12)
DELTA_TF = 10 * log10((double)(((K1 * (O_UCI)) / N_RE)));
else {
float K2 = 2.4;
float BPRE = (O_UCI + O_CRC) / N_RE;
DELTA_TF = 10 * log10((double)(pow(2, (K2 * BPRE)) - 1));
}
return DELTA_TF;
}
// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
// Assumptions:
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -490,16 +490,16 @@ static bool check_sib1_tda(gNB_MAC_INST *gNB_mac,
// the UE may assume that this PDSCH resource allocation is not applied (Table 5.1.2.1.1-4 and 5 in 38.214)
int row = tda + 1;
if (table_type == defaultB && (row == 12 || row == 13 || row == 14))
false;
return false;
if (table_type == defaultC && (row == 1 || row == 6 || row == 7 ||row > 12))
false;
return false;
// assuming normal CP
NR_tda_info_t tda_info = get_info_from_tda_tables(table_type, tda, scc->dmrs_TypeA_Position, true);
// SIB1 TDA going to the last symbol would cause overlap with CSI-RS
if (!tda_info.valid_tda || tda_info.startSymbolIndex + tda_info.nrOfSymbols == 14)
false;
return false;
if (tda_info.startSymbolIndex < type0_PDCCH_CSS_config->first_symbol_index + type0_PDCCH_CSS_config->num_symbols)
false;
return false;
NR_pdsch_dmrs_t dmrs_parms = get_dl_dmrs_params(scc, NULL, &tda_info, 1);
// Configure sched_ctrlCommon for SIB1
+7 -1
View File
@@ -1092,7 +1092,13 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
uint32_t ssb_arfcn = get_ssb_arfcn(du);
LOG_I(NR_RRC, "Reestablishment update key pci=%d, earfcn_dl=%u\n", cell_info->nr_pci, ssb_arfcn);
nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, ue_p->nh_ncc > 0 ? ue_p->nh : ue_p->kgnb, ue_p->kgnb);
/* Per TS 33.501 6.9.2.3.4: When sending RRCReestablishment with nextHopChainingCount,
* we're staying at the same NCC level (not advancing), so use horizontal derivation
* from the currently active KgNB. Vertical derivation (from NH) is only used when
* advancing to a new NCC level, which happens during handover or masterKeyUpdate. */
const uint8_t *base_key = ue_p->kgnb;
nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, base_key, ue_p->kgnb);
int size = do_RRCReestablishment(ue_context_pP->ue_context.nh_ncc, buffer, NR_RRC_BUF_SIZE, xid);
LOG_A(NR_RRC, "Send RRCReestablishment [%d bytes] to RNTI %04x\n", size, ue_p->rnti);
+1 -1
View File
@@ -1649,7 +1649,7 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc,
msg.source2target->ue_history_info.cause->type = NGAP_CAUSE_RADIO_NETWORK;
msg.source2target->ue_history_info.cause->value = NGAP_CAUSE_RADIO_NETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON;
msg.source2target->ue_history_info.type = NGAP_CellSize_small;
msg.source2target->ue_history_info.time_in_cell = 500; // dummy number for now
msg.source2target->ue_history_info.time_in_cell = min(time(NULL) - UE->last_seen, 4095);
msg.source2target->ue_history_info.id = target_cell;
/* Fill both PDU Session Resource List IE (M) in Handover Required
+155 -46
View File
@@ -527,13 +527,141 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
}
static void nr_rrc_nh_update(NR_UE_RRC_INST_t *rrc, uint8_t *kamf, uint8_t *sync_input)
/** @brief Synchronize NH chain based on nextHopChainingCount
*
* This function synchronizes the NH parameter chain as specified in 3GPP TS 33.501 Annex A.10.
* Use cases: Master Key Update, RRC Reestablishment: The UE receives an NCC value that is
* different from the NCC associated with the currently active KgNB. The NH chain is synchronized
* by computing the function defined in Annex A.10 iteratively (and increasing the NCC value until
* it matches the NCC value received from the source ng-gNB).
*
* @param kamf K_AMF key from NAS
* @param kgnb Current KgNB key (input/output)
* @param nh Current NH parameter (input/output)
* @param nhcc Pointer to current nextHopChainingCount (input/output)
* @param target_ncc Target nextHopChainingCount value to synchronize to */
static void nr_sync_nh_chain(const uint8_t kamf[SECURITY_KEY_LEN],
uint8_t kgnb[SECURITY_KEY_LEN],
uint8_t nh[SECURITY_KEY_LEN],
uint64_t *nhcc,
const int8_t target_ncc)
{
uint8_t nh[SECURITY_KEY_LEN] = {0};
nr_derive_nh(kamf, sync_input, nh);
log_hex_buffer("Sync input = stored NH", rrc->nh, SECURITY_KEY_LEN);
memcpy(rrc->nh, nh, SECURITY_KEY_LEN);
rrc->nhcc++; // Increase stored nextHopChainingCount
// If the UE received an NCC value that was different from the NCC associated with the
// currently active KgNB, the UE shall first synchronize the locally kept NH
// parameter by computing the function defined in Annex A.10 iteratively (and increasing
// the NCC value until it matches the NCC value received from the source ng-gNB).
if (target_ncc <= *nhcc) {
LOG_W(NR_RRC, "Received NCC=%d is less than or equal to current nhcc=%ld (nothing to sync)\n", target_ncc, *nhcc);
return;
}
if (target_ncc > *nhcc) {
LOG_I(NR_RRC, "Synchronizing NH chain: current nhcc=%ld, target ncc=%d\n", *nhcc, target_ncc);
if (*nhcc == 0) {
// First derivation: derive KgNB from KAMF, then derive NH from KgNB (per TS 33.501 A.10)
// Note: For the first NH derivation, we use UL NAS COUNT = 0 to match the AMF's derivation
// during handover. The AMF derives the first NH using the UL NAS COUNT from the last
// successful NAS SMC, which is 0 for the initial derivation.
derive_kgnb(kamf, 0, kgnb);
nr_derive_nh(kamf, kgnb, nh);
*nhcc = 1;
}
// Following derivations: iterate from current nhcc to target_ncc
for (uint8_t i = *nhcc; i < target_ncc; i++) {
LOG_D(NR_RRC, "Derive keys for ChainingCount = %d\n", i);
nr_derive_nh(kamf, nh, nh);
}
*nhcc = target_ncc;
}
}
/** @brief Derive KNG-RAN* (KgNB*) using horizontal derivation
*
* This function derives KNG-RAN* from the currently active KgNB (horizontal derivation)
* as specified in 3GPP TS 33.501 Annex A.11 and A.12.
* Used when NCC values match (no NH synchronization needed).
*
* @param pci Physical Cell ID
* @param nr_arfcn_dl NR ARFCN-DL
* @param kgnb Current KgNB key (input/output)
*/
static void nr_derive_kgnb_horizontal(const uint16_t pci, const uint64_t nr_arfcn_dl, uint8_t kgnb[SECURITY_KEY_LEN])
{
// When the NCC values match, the UE shall derive the KNG-RAN* from the currently active
// KgNB and the target PCI and its frequency ARFCN-DL using the function defined in Annex A.11 and A.12.
LOG_D(NR_RRC, "Deriving KNG-RAN* using horizontal derivation (from current KgNB)\n");
nr_derive_key_ng_ran_star(pci, nr_arfcn_dl, kgnb, kgnb);
}
/** @brief Derive KNG-RAN* (KgNB*) using vertical derivation
*
* This function derives KNG-RAN* from the synchronized NH parameter (vertical derivation)
* as specified in 3GPP TS 33.501 Annex A.11 and A.12.
* Used after NH chain synchronization when NCC values differ.
*
* @param pci Physical Cell ID
* @param nr_arfcn_dl NR ARFCN-DL
* @param kgnb Current KgNB key (input/output)
* @param nh Synchronized NH parameter (input)
*/
static void nr_derive_kgnb_vertical(const uint16_t pci,
const uint64_t nr_arfcn_dl,
uint8_t kgnb[SECURITY_KEY_LEN],
const uint8_t nh[SECURITY_KEY_LEN])
{
// When the NCC values match (after synchronization), the UE shall compute the K NG-RAN *
// from the synchronized NH parameter and the target PCI and its frequency ARFCN-DL
// using the function defined in Annex A.11 and A.12.
LOG_D(NR_RRC, "Deriving KNG-RAN* using vertical derivation (from synchronized NH)\n");
nr_derive_key_ng_ran_star(pci, nr_arfcn_dl, nh, kgnb);
}
/** @brief Update KgNB based on received nextHopChainingCount
*
* This function implements the common logic for updating KgNB based on received NCC value,
* as specified in 3GPP TS 33.501 6.9.2.3.4.
*
* Per 33.501 6.9.2.3.4 and Fig 6.9.2.1.1-1:
* - If NCC received == current NCC: use horizontal derivation (from currently active KgNB)
* This applies regardless of whether NCC is 0 or >0. For a fixed NCC level, multiple
* horizontal derivations can be done within that level.
* - If NCC received > current NCC: synchronize NH chain (Annex A.10), then use vertical
* derivation (from NH) to enter the new NCC level.
*
* Horizontal derivation = derive KNG-RAN* from currently active KgNB + (PCI, ARFCN-DL)
* Vertical derivation = derive KNG-RAN* from NH + (PCI, ARFCN-DL)
*
* @param rrc RRC instance pointer
* @param kamf K_AMF key from NAS
* @param received_ncc Received nextHopChainingCount value */
static void nr_update_kgnb_from_ncc(NR_UE_RRC_INST_t *rrc, const uint8_t kamf[SECURITY_KEY_LEN], int8_t received_ncc)
{
const uint64_t original_nhcc = rrc->nhcc;
if (received_ncc == original_nhcc) {
// NCC values match: use horizontal derivation from currently active KgNB
// Per TS 33.501 6.9.2.3.4: "derive the KNG-RAN* from the currently active KgNB"
// This applies regardless of NCC being 0 or >0. For a fixed NCC level, we stay
// within that level using horizontal derivations.
LOG_D(NR_RRC, "NCC values match (%d), using horizontal derivation\n", received_ncc);
nr_derive_kgnb_horizontal(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb);
} else if (received_ncc < original_nhcc) {
// Note: According to spec, NCC should only increase. If received_ncc < original_nhcc,
// this is an error condition, but we handle it gracefully.
LOG_W(NR_RRC,
"Received NCC=%d is less than current nhcc=%ld (unexpected per spec, NH chain should only increase)\n",
received_ncc,
original_nhcc);
} else {
// received_ncc > original_nhcc: synchronize NH chain first (per 33.501 A.10)
nr_sync_nh_chain(kamf, rrc->kgnb, rrc->nh, &rrc->nhcc, received_ncc);
// Store the received nextHopChainingCount value (per 38.331 5.3.7.5)
LOG_D(NR_RRC, "Synchronizing NH chain to target NCC %d\n", received_ncc);
rrc->nhcc = received_ncc;
// After synchronization, derive KNG-RAN* from synchronized NH (vertical derivation)
// per 33.501 6.9.2.3.4: "When the NCC values match, the UE shall compute the K NG-RAN *
// from the synchronized NH parameter"
nr_derive_kgnb_vertical(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->nh);
}
}
/** @brief AS security key update procedure (5.3.5.7 3GPP TS 38.331) */
@@ -545,40 +673,17 @@ void as_security_key_update(NR_UE_RRC_INST_t *rrc, NR_MasterKeyUpdate_t *mku)
if (mku->keySetChangeIndicator) {
LOG_E(NR_RRC, "derive or update the K gNB key based on the K AMF key, as specified in TS 33.501: not implemented yet\n");
} else {
/* derive or update the K gNB key based on the current K gNB key or the NH, using the nextHopChainingCount
value indicated in the received masterKeyUpdate, as specified in 6.9.2.3.3 3GPP TS 33.501 */
if (mku->nextHopChainingCount != rrc->nhcc) {
// - If the UE received an NCC value that was different from the NCC associated with the currently active
// K gNB/K eNB, the UE shall first synchronize the locally kept NH parameter by computing the function defined in
// Annex A.10 iteratively (and increasing the NCC value until it matches the NCC value received from the source
// ng-eNB/gNB via the HO command message.
LOG_A(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount);
/** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized
* with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig
* processing that triggers bearer modifications. Security configueration of bearers must
* complete using the newly derived keys. As a workaround NAS is directly accessed here. */
nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id);
uint8_t *kamf = nas->security.kamf;
log_hex_buffer("Stored kamf", kamf, SECURITY_KEY_LEN);
if (rrc->nhcc == 0) { // First derivation
derive_kgnb(kamf, 0, rrc->kgnb);
log_hex_buffer("Sync input = derived kgnb", rrc->kgnb, SECURITY_KEY_LEN);
nr_rrc_nh_update(rrc, kamf, rrc->kgnb);
}
for (int i = rrc->nhcc; i < mku->nextHopChainingCount; i++) { // Following derivations
LOG_D(NR_RRC, "Derive keys for ChainingCount = %d\n", i);
nr_rrc_nh_update(rrc, kamf, rrc->nh);
}
nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->nh, rrc->kgnb);
// When the NCC values match, the UE shall compute the K NG-RAN *
// from the synchronized NH parameter and the target PCI and its frequency ARFCN-DL/EARFCN-DL using the
// function defined in Annex A.11 and A.12.
// The UE shall use the KNG-RAN * as the K gNB when communicating with the target gNB and as the KeNB when
// communicating with the target ng-eNB.
} else {
nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->kgnb);
}
log_hex_buffer("Derived kgnb", rrc->kgnb, SECURITY_KEY_LEN);
LOG_I(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount);
/** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized
* with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig
* processing that triggers bearer modifications. Security configueration of bearers must
* complete using the newly derived keys. As a workaround NAS is directly accessed here. */
nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id);
const uint8_t *kamf = nas->security.kamf;
// KgNB update (TS 33.501 §6.9.2.3.3):
// If received NCC != local NCC, iteratively derive NH (Annex A.10) until NCC matches.
// Then derive the new KgNB from the synchronized NH.
nr_update_kgnb_from_ncc(rrc, kamf, mku->nextHopChainingCount);
}
}
@@ -2246,6 +2351,9 @@ static void nr_rrc_ue_generate_rrcReestablishmentComplete(const NR_UE_RRC_INST_t
nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL);
}
/** @brief Process RRCReestablishment message
* This function processes the RRCReestablishment message received from the gNB,
* implementing procedures as described in 38.331 section 5.3.7.5 */
static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc,
const int gNB_index,
const NR_RRCReestablishment_t *rrcReestablishment,
@@ -2254,18 +2362,19 @@ static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc,
int msg_size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
// implementign procedues as described in 38.331 section 5.3.7.5
// stop timer T301
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
nr_timer_stop(&timers->T301);
// store the nextHopChainingCount value
NR_RRCReestablishment_IEs_t *ies = rrcReestablishment->criticalExtensions.choice.rrcReestablishment;
AssertFatal(ies, "Not expecting RRCReestablishment_IEs to be NULL\n");
// TODO need to understand how to use nextHopChainingCount
// int nh = rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nextHopChainingCount;
// update the K gNB key based on the current K gNB key or the NH, using the stored nextHopChainingCount value
nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->kgnb);
// Update KgNB based on the current K gNB key or the NH,
// using the received nextHopChainingCount (per 33.501 6.9.2.3.4)
// received from RRCReestablishment and update the stored value in rrc->nhcc
int8_t received_ncc = ies->nextHopChainingCount;
nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id);
const uint8_t *kamf = nas->security.kamf;
nr_update_kgnb_from_ncc(rrc, kamf, received_ncc);
// derive the K_RRCenc key associated with the previously configured cipheringAlgorithm
// derive the K_RRCint key associated with the previously configured integrityProtAlgorithm
+17 -2
View File
@@ -150,8 +150,23 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t
* NOTE: knas is dynamically allocated by the KDF function
*/
/** @brief KgNB derivation (A.9 3GPP TS 33.501) */
void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb)
/** @brief KgNB derivation function (Annex A.9 3GPP TS 33.501)
*
* Derives KgNB from K_AMF and the uplink NAS COUNT.
* This function is applied when cryptographically protected 5G radio bearers are
* established and when a key change on-the-fly is performed.
*
* KDF input S structure (per Annex A.9):
* - FC = 0x6E
* - P0 = Uplink NAS COUNT (count parameter)
* - L0 = length of uplink NAS COUNT (0x00 0x04)
* - P1 = Access type distinguisher (0x01 for 3GPP access)
* - L1 = length of Access type distinguisher (0x00 0x01)
*
* @param[in] kamf 256-bit K_AMF key (input key KEY to KDF)
* @param[in] count Uplink NAS COUNT value (P0 in KDF input S)
* @param[out] kgnb Derived 256-bit KgNB key */
void derive_kgnb(const uint8_t kamf[32], const uint32_t count, uint8_t *kgnb)
{
/* Compute the KDF input parameter
* S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01
+1 -1
View File
@@ -16,7 +16,7 @@ typedef enum {
UP_INT_ALG = 0x06
} algorithm_type_dist_t;
void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb);
void derive_kgnb(const uint8_t kamf[32], const uint32_t count, uint8_t *kgnb);
void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB);
-4
View File
@@ -957,8 +957,6 @@ int device_init(openair0_device *device,
/* device specific */
//openair0_cfg->txlaunch_wait = 1;//manage when TX processing is triggered
//openair0_cfg->txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
openair0_cfg->iq_txshift = 0;// shift
openair0_cfg->iq_rxrescale = 15;//rescale iqs
// init required params
switch ((int)openair0_cfg->sample_rate) {
@@ -983,8 +981,6 @@ int device_init(openair0_device *device,
exit(-1);
break;
}
openair0_cfg->iq_txshift= 0;
openair0_cfg->iq_rxrescale = 15; /*not sure*/
openair0_cfg->rx_gain_calib_table = calib_table_fx4;
// The number of buffers to use in the underlying data stream
-4
View File
@@ -276,10 +276,6 @@ typedef struct openair0_config {
char *sdr_addrs;
//! Auto calibration flag
int autocal[8];
//! rf devices work with x bits iqs when oai have its own iq format
//! the two following parameters are used to convert iqs
int iq_txshift;
int iq_rxrescale;
//! Configuration file for LMS7002M
char *configFilename;
//! remote IP/MAC addr for Ethernet interface
-34
View File
@@ -540,40 +540,6 @@ int transport_init(openair0_device *device,
eth->if_name = eth_params->local_if_name;
device->priv = eth;
/* device specific */
// openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
// openair0_cfg[0].iq_txshift = eth_params->iq_txshift;// shift
// openair0_cfg[0].tx_sample_advance = eth_params->tx_sample_advance;
/* RRU does not have any information to make this configuration atm */
/*
if (device->host_type == RAU_HOST) {
switch ((int)openair0_cfg[0].sample_rate) {
case 30720000:
openair0_cfg[0].samples_per_packet = 3840;
break;
case 23040000:
openair0_cfg[0].samples_per_packet = 2880;
break;
case 15360000:
openair0_cfg[0].samples_per_packet = 1920;
break;
case 7680000:
openair0_cfg[0].samples_per_packet = 960;
break;
case 1920000:
openair0_cfg[0].samples_per_packet = 240;
break;
default:
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
exit(-1);
break;
}
}*/
device->openair0_cfg=&openair0_cfg[0];
return 0;
}
+12 -15
View File
@@ -478,14 +478,15 @@ static int trx_usrp_write(openair0_device *device,
nsamps2 = (nsamps+7)>>3;
simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2];
// bring RX data into 12 LSBs for softmodem RX
// bring TX data into 16 MSBs, assuming it is on the 12 LSB after OAI computation
const int shift = 4;
for (int i = 0; i < cc; i++) {
for (int j = 0; j < nsamps2; j++) {
if ((((uintptr_t)buff[i]) & 0x1F) == 0) {
buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], 4);
buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], shift);
} else {
simde__m256i tmp = simde_mm256_loadu_si256(((simde__m256i *)buff[i]) + j);
buff_tx[i][j] = simde_mm256_slli_epi16(tmp, 4);
buff_tx[i][j] = simde_mm256_slli_epi16(tmp, shift);
}
}
}
@@ -605,17 +606,17 @@ void *trx_usrp_write_thread(void * arg){
nsamps2 = (nsamps+7)>>3;
simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2];
// bring RX data into 12 LSBs for softmodem RX
// bring TX data into 16 MSBs, assuming it is on the 12 LSB after OAI computation
const int shift = 4;
for (int i = 0; i < cc; i++) {
for (int j = 0; j < nsamps2; j++) {
if ((((uintptr_t) buff[i])&0x1F)==0) {
buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], 4);
buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], shift);
}
else
{
simde__m256i tmp = simde_mm256_loadu_si256(((simde__m256i *)buff[i]) + j);
buff_tx[i][j] = simde_mm256_slli_epi16(tmp,4);
buff_tx[i][j] = simde_mm256_slli_epi16(tmp, shift);
}
}
}
@@ -752,11 +753,13 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
// bring RX data into 12 LSBs for softmodem RX
for (int i=0; i<cc; i++) {
for (int j = 0; j < nsamps2; j++) {
// FK: in some cases the buffer might not be 32 byte aligned, so we cannot use avx2
// bring RX data into 12 LSBs for softmodem RX,
// this keeps the significant bits of B210 and may loose better ADC results,
// but it makes free bits in MSB for signal processing on int16
if ((((uintptr_t) buff[i])&0x1F)==0) {
((simde__m256i *)buff[i])[j] = simde_mm256_srai_epi16(buff_tmp[i][j], rxshift);
} else {
// FK: in some cases the buffer might not be 32 byte aligned, so we cannot use avx2
simde__m256i tmp = simde_mm256_srai_epi16(buff_tmp[i][j], rxshift);
simde_mm256_storeu_si256(((simde__m256i *)buff[i]) + j, tmp);
}
@@ -1339,12 +1342,6 @@ extern "C" {
}
}
/* device specific */
//openair0_cfg[0].txlaunch_wait = 1;//manage when TX processing is triggered
//openair0_cfg[0].txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
openair0_cfg[0].iq_txshift = 4;//shift
openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
if(openair0_cfg[0].tx_subdev!=NULL){
LOG_I(HW, "openair0_cfg[0].tx_subdev == %s\n", openair0_cfg[0].tx_subdev);
tx_subdev = openair0_cfg[0].tx_subdev;
+6 -3
View File
@@ -173,6 +173,9 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
struct xran_fh_init *fh_init = get_xran_fh_init();
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
nr_prach_info_t prach_info = get_prach_info(0);
int prach_start_sym = prach_info.start_symbol;
int prach_end_sym = prach_info.N_dur + prach_start_sym;
struct xran_ru_config *ru_conf = &fh_cfg->ru_conf;
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology;
@@ -190,7 +193,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
LOG_W(HW, "we get rach data from ru, but it is not scheduled %d.%d\n", frame, slot);
return -1;
}
for (sym_idx = 0; sym_idx < prach_info.N_dur; sym_idx++) {
for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) {
for (int aa = 0; aa < ru->nb_rx; aa++) {
int16_t *dst, *src;
int idx = 0;
@@ -200,7 +203,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
src = (int16_t *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData;
/* convert Network order to host order */
if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) {
if (sym_idx == 0) {
if (sym_idx == prach_start_sym) {
for (idx = 0; idx < 139 * 2; idx++) {
dst[idx] = ((int16_t)ntohs(src[idx + g_kbar]));
}
@@ -233,7 +236,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
AssertFatal(1 == 0, "BFP decompression not supported on this architecture");
#endif
// note: this is hardwired for 139 point PRACH sequence, kbar=2
if (sym_idx == 0) //
if (sym_idx == prach_start_sym)
for (idx = 0; idx < (139 * 2); idx++)
dst[idx] = local_dst[idx + g_kbar];
else
+4 -4
View File
@@ -54,6 +54,10 @@ extern "C" {
#include <common/utils/load_module_shlib.h>
#include <openair1/SIMULATION/TOOLS/sim.h>
#include "rfsimulator.h"
extern int get_currentchannels_type(const char *buf,
int debug,
webdatadef_t *tdata,
telnet_printfunc_t prnt); // in random_channel.c
}
#include <queue>
#include <mutex>
@@ -112,10 +116,6 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
};
// clang-format on
static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt);
extern int get_currentchannels_type(const char *buf,
int debug,
webdatadef_t *tdata,
telnet_printfunc_t prnt); // in random_channel.c
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
+1
View File
@@ -177,6 +177,7 @@ int main(int argc, char *argv[]) {
timestamp+=blockSize;
header.option_value=0;
header.option_flag=0;
header.beam_map = 1;
} else {
AssertFatal(read(fd,&header,sizeof(header)), "");
}