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:
+4
-3
@@ -979,6 +979,7 @@ set(PHY_SRC_UE
|
|||||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c
|
${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.c
|
||||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.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_ue_rf_helpers.c
|
||||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
|
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
|
||||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.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})
|
add_library(PHY_UE ${PHY_SRC_UE})
|
||||||
target_link_libraries(PHY_UE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs UTIL)
|
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
|
# RHEL needs also cblas, but Ubuntu does not have it. So `cblas_LIBRARIES` and
|
||||||
# be empty for Ubuntu, a no-op
|
# `cblas_INCLUDE_DIRS` will be empty for Ubuntu, a no-op
|
||||||
pkg_check_modules(cblas cblas)
|
pkg_check_modules(cblas cblas)
|
||||||
target_link_libraries(PHY_UE PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES})
|
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})
|
add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON})
|
||||||
target_link_libraries(PHY_NR_COMMON PUBLIC UTIL)
|
target_link_libraries(PHY_NR_COMMON PUBLIC UTIL)
|
||||||
|
|||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -209,7 +209,7 @@ def CheckLogs(self, filename, HTML, RAN):
|
|||||||
elif 'nv-cubb' in name:
|
elif 'nv-cubb' in name:
|
||||||
msg = 'Undeploy PNF/Nvidia CUBB'
|
msg = 'Undeploy PNF/Nvidia CUBB'
|
||||||
HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK)
|
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')
|
logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m')
|
||||||
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
|
logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers)
|
||||||
opt = f"xNB log analysis ({name})"
|
opt = f"xNB log analysis ({name})"
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
export UHD_IMAGES_DIR=$SNAP/uhd_images
|
|
||||||
exec $@
|
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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
@@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -497,8 +497,6 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32
|
|||||||
return carrier_freq;
|
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)
|
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
|
||||||
{
|
{
|
||||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
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;
|
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)
|
void *UE_thread(void *arg)
|
||||||
{
|
{
|
||||||
//this thread should be over the processing thread to keep in real time
|
//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.
|
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).
|
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
|
./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<complex.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#if defined RHEL_RELEASE_CODE
|
|
||||||
#include <cblas/cblas.h>
|
|
||||||
#else
|
|
||||||
#include <cblas.h>
|
#include <cblas.h>
|
||||||
#endif
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <lapacke_utils.h>
|
#include <lapacke_utils.h>
|
||||||
|
|||||||
@@ -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);
|
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);
|
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 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);
|
void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb);
|
||||||
|
|
||||||
|
|||||||
@@ -108,10 +108,6 @@ int main(int argc, char **argv) {
|
|||||||
.sdr_addrs=usrp_addrs,
|
.sdr_addrs=usrp_addrs,
|
||||||
//! Auto calibration flag
|
//! Auto calibration flag
|
||||||
.autocal={0},
|
.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
|
//! Configuration file for LMS7002M
|
||||||
.configFilename="",
|
.configFilename="",
|
||||||
//! remote IP/MAC addr for Ethernet interface
|
//! remote IP/MAC addr for Ethernet interface
|
||||||
|
|||||||
@@ -1742,7 +1742,7 @@ int main(int argc, char *argv[])
|
|||||||
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
|
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
|
||||||
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
|
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
|
||||||
printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving 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");
|
printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time");
|
||||||
printStatIndent(&gNB->rx_srs_stats,"RX SRS time");
|
printStatIndent(&gNB->rx_srs_stats,"RX SRS time");
|
||||||
printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time");
|
printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time");
|
||||||
|
|||||||
@@ -473,8 +473,8 @@ typedef struct {
|
|||||||
cell_id_t id;
|
cell_id_t id;
|
||||||
// Cell type
|
// Cell type
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
// Time UE Stayed in Cell
|
// Time UE Stayed in Cell (seconds)
|
||||||
long time_in_cell;
|
uint16_t time_in_cell;
|
||||||
// Cause
|
// Cause
|
||||||
ngap_cause_t *cause;
|
ngap_cause_t *cause;
|
||||||
} last_visited_ngran_cell_info_t;
|
} last_visited_ngran_cell_info_t;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
#include "executables/softmodem-common.h"
|
#include "executables/softmodem-common.h"
|
||||||
#include <stdio.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");
|
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;
|
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)
|
if (config->commonControlResourceSet && coreset_id == config->commonControlResourceSet->controlResourceSetId)
|
||||||
return config->commonControlResourceSet;
|
return config->commonControlResourceSet;
|
||||||
@@ -362,12 +362,12 @@ bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per
|
|||||||
return monitor;
|
return monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
|
static bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
|
||||||
const NR_SearchSpace_t *ss,
|
const NR_SearchSpace_t *ss,
|
||||||
const int abs_slot,
|
const int abs_slot,
|
||||||
const int frame,
|
const int frame,
|
||||||
const int slot,
|
const int slot,
|
||||||
const int slots_per_frame)
|
const int slots_per_frame)
|
||||||
{
|
{
|
||||||
const int duration = ss->duration ? *ss->duration : 1;
|
const int duration = ss->duration ? *ss->duration : 1;
|
||||||
int period, offset;
|
int period, offset;
|
||||||
|
|||||||
@@ -58,13 +58,6 @@ static const int nb_symbols_excluding_dmrs[11][2][2]
|
|||||||
/* 14 */ {{ 12 , 12 } , { 10 , 10 }},
|
/* 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
|
// ∆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)
|
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;
|
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
|
// PUCCH Power control according to 38.213 section 7.2.1
|
||||||
int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
|
int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
|
||||||
int scs,
|
int scs,
|
||||||
@@ -399,28 +414,6 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
|
|||||||
return pucch_power;
|
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
|
// 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
|
// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
|
||||||
// Assumptions:
|
// 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)
|
// 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;
|
int row = tda + 1;
|
||||||
if (table_type == defaultB && (row == 12 || row == 13 || row == 14))
|
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))
|
if (table_type == defaultC && (row == 1 || row == 6 || row == 7 ||row > 12))
|
||||||
false;
|
return false;
|
||||||
// assuming normal CP
|
// assuming normal CP
|
||||||
NR_tda_info_t tda_info = get_info_from_tda_tables(table_type, tda, scc->dmrs_TypeA_Position, true);
|
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
|
// 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)
|
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)
|
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);
|
NR_pdsch_dmrs_t dmrs_parms = get_dl_dmrs_params(scc, NULL, &tda_info, 1);
|
||||||
// Configure sched_ctrlCommon for SIB1
|
// Configure sched_ctrlCommon for SIB1
|
||||||
|
|||||||
@@ -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;
|
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
|
||||||
uint32_t ssb_arfcn = get_ssb_arfcn(du);
|
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);
|
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);
|
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);
|
LOG_A(NR_RRC, "Send RRCReestablishment [%d bytes] to RNTI %04x\n", size, ue_p->rnti);
|
||||||
|
|||||||
@@ -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->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.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.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;
|
msg.source2target->ue_history_info.id = target_cell;
|
||||||
|
|
||||||
/* Fill both PDU Session Resource List IE (M) in Handover Required
|
/* Fill both PDU Session Resource List IE (M) in Handover Required
|
||||||
|
|||||||
+155
-46
@@ -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);
|
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};
|
// If the UE received an NCC value that was different from the NCC associated with the
|
||||||
nr_derive_nh(kamf, sync_input, nh);
|
// currently active KgNB, the UE shall first synchronize the locally kept NH
|
||||||
log_hex_buffer("Sync input = stored NH", rrc->nh, SECURITY_KEY_LEN);
|
// parameter by computing the function defined in Annex A.10 iteratively (and increasing
|
||||||
memcpy(rrc->nh, nh, SECURITY_KEY_LEN);
|
// the NCC value until it matches the NCC value received from the source ng-gNB).
|
||||||
rrc->nhcc++; // Increase stored nextHopChainingCount
|
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) */
|
/** @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) {
|
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");
|
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 {
|
} else {
|
||||||
/* derive or update the K gNB key based on the current K gNB key or the NH, using the nextHopChainingCount
|
LOG_I(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount);
|
||||||
value indicated in the received masterKeyUpdate, as specified in 6.9.2.3.3 3GPP TS 33.501 */
|
/** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized
|
||||||
if (mku->nextHopChainingCount != rrc->nhcc) {
|
* with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig
|
||||||
// - If the UE received an NCC value that was different from the NCC associated with the currently active
|
* processing that triggers bearer modifications. Security configueration of bearers must
|
||||||
// K gNB/K eNB, the UE shall first synchronize the locally kept NH parameter by computing the function defined in
|
* complete using the newly derived keys. As a workaround NAS is directly accessed here. */
|
||||||
// Annex A.10 iteratively (and increasing the NCC value until it matches the NCC value received from the source
|
nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id);
|
||||||
// ng-eNB/gNB via the HO command message.
|
const uint8_t *kamf = nas->security.kamf;
|
||||||
LOG_A(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount);
|
// KgNB update (TS 33.501 §6.9.2.3.3):
|
||||||
/** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized
|
// If received NCC != local NCC, iteratively derive NH (Annex A.10) until NCC matches.
|
||||||
* with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig
|
// Then derive the new KgNB from the synchronized NH.
|
||||||
* processing that triggers bearer modifications. Security configueration of bearers must
|
nr_update_kgnb_from_ncc(rrc, kamf, mku->nextHopChainingCount);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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);
|
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,
|
static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc,
|
||||||
const int gNB_index,
|
const int gNB_index,
|
||||||
const NR_RRCReestablishment_t *rrcReestablishment,
|
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,
|
int msg_size,
|
||||||
const nr_pdcp_integrity_data_t *msg_integrity)
|
const nr_pdcp_integrity_data_t *msg_integrity)
|
||||||
{
|
{
|
||||||
// implementign procedues as described in 38.331 section 5.3.7.5
|
|
||||||
// stop timer T301
|
// stop timer T301
|
||||||
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
|
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
|
||||||
nr_timer_stop(&timers->T301);
|
nr_timer_stop(&timers->T301);
|
||||||
// store the nextHopChainingCount value
|
|
||||||
NR_RRCReestablishment_IEs_t *ies = rrcReestablishment->criticalExtensions.choice.rrcReestablishment;
|
NR_RRCReestablishment_IEs_t *ies = rrcReestablishment->criticalExtensions.choice.rrcReestablishment;
|
||||||
AssertFatal(ies, "Not expecting RRCReestablishment_IEs to be NULL\n");
|
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
|
// Update KgNB based on the current K gNB key or the NH,
|
||||||
nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->kgnb);
|
// 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_RRCenc key associated with the previously configured cipheringAlgorithm
|
||||||
// derive the K_RRCint key associated with the previously configured integrityProtAlgorithm
|
// derive the K_RRCint key associated with the previously configured integrityProtAlgorithm
|
||||||
|
|||||||
@@ -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
|
* NOTE: knas is dynamically allocated by the KDF function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @brief KgNB derivation (A.9 3GPP TS 33.501) */
|
/** @brief KgNB derivation function (Annex A.9 3GPP TS 33.501)
|
||||||
void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb)
|
*
|
||||||
|
* 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
|
/* Compute the KDF input parameter
|
||||||
* S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01
|
* S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ typedef enum {
|
|||||||
UP_INT_ALG = 0x06
|
UP_INT_ALG = 0x06
|
||||||
} algorithm_type_dist_t;
|
} 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);
|
void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB);
|
||||||
|
|
||||||
|
|||||||
@@ -957,8 +957,6 @@ int device_init(openair0_device *device,
|
|||||||
/* device specific */
|
/* device specific */
|
||||||
//openair0_cfg->txlaunch_wait = 1;//manage when TX processing is triggered
|
//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->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
|
// init required params
|
||||||
switch ((int)openair0_cfg->sample_rate) {
|
switch ((int)openair0_cfg->sample_rate) {
|
||||||
@@ -983,8 +981,6 @@ int device_init(openair0_device *device,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
openair0_cfg->iq_txshift= 0;
|
|
||||||
openair0_cfg->iq_rxrescale = 15; /*not sure*/
|
|
||||||
openair0_cfg->rx_gain_calib_table = calib_table_fx4;
|
openair0_cfg->rx_gain_calib_table = calib_table_fx4;
|
||||||
|
|
||||||
// The number of buffers to use in the underlying data stream
|
// The number of buffers to use in the underlying data stream
|
||||||
|
|||||||
@@ -276,10 +276,6 @@ typedef struct openair0_config {
|
|||||||
char *sdr_addrs;
|
char *sdr_addrs;
|
||||||
//! Auto calibration flag
|
//! Auto calibration flag
|
||||||
int autocal[8];
|
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
|
//! Configuration file for LMS7002M
|
||||||
char *configFilename;
|
char *configFilename;
|
||||||
//! remote IP/MAC addr for Ethernet interface
|
//! remote IP/MAC addr for Ethernet interface
|
||||||
|
|||||||
@@ -540,40 +540,6 @@ int transport_init(openair0_device *device,
|
|||||||
|
|
||||||
eth->if_name = eth_params->local_if_name;
|
eth->if_name = eth_params->local_if_name;
|
||||||
device->priv = eth;
|
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];
|
device->openair0_cfg=&openair0_cfg[0];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-15
@@ -478,14 +478,15 @@ static int trx_usrp_write(openair0_device *device,
|
|||||||
nsamps2 = (nsamps+7)>>3;
|
nsamps2 = (nsamps+7)>>3;
|
||||||
simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2];
|
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 i = 0; i < cc; i++) {
|
||||||
for (int j = 0; j < nsamps2; j++) {
|
for (int j = 0; j < nsamps2; j++) {
|
||||||
if ((((uintptr_t)buff[i]) & 0x1F) == 0) {
|
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 {
|
} else {
|
||||||
simde__m256i tmp = simde_mm256_loadu_si256(((simde__m256i *)buff[i]) + j);
|
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;
|
nsamps2 = (nsamps+7)>>3;
|
||||||
simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2];
|
simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2];
|
||||||
|
// bring TX data into 16 MSBs, assuming it is on the 12 LSB after OAI computation
|
||||||
// bring RX data into 12 LSBs for softmodem RX
|
const int shift = 4;
|
||||||
for (int i = 0; i < cc; i++) {
|
for (int i = 0; i < cc; i++) {
|
||||||
for (int j = 0; j < nsamps2; j++) {
|
for (int j = 0; j < nsamps2; j++) {
|
||||||
if ((((uintptr_t) buff[i])&0x1F)==0) {
|
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
|
else
|
||||||
{
|
{
|
||||||
simde__m256i tmp = simde_mm256_loadu_si256(((simde__m256i *)buff[i]) + j);
|
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
|
// bring RX data into 12 LSBs for softmodem RX
|
||||||
for (int i=0; i<cc; i++) {
|
for (int i=0; i<cc; i++) {
|
||||||
for (int j = 0; j < nsamps2; j++) {
|
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) {
|
if ((((uintptr_t) buff[i])&0x1F)==0) {
|
||||||
((simde__m256i *)buff[i])[j] = simde_mm256_srai_epi16(buff_tmp[i][j], rxshift);
|
((simde__m256i *)buff[i])[j] = simde_mm256_srai_epi16(buff_tmp[i][j], rxshift);
|
||||||
} else {
|
} 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__m256i tmp = simde_mm256_srai_epi16(buff_tmp[i][j], rxshift);
|
||||||
simde_mm256_storeu_si256(((simde__m256i *)buff[i]) + j, tmp);
|
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){
|
if(openair0_cfg[0].tx_subdev!=NULL){
|
||||||
LOG_I(HW, "openair0_cfg[0].tx_subdev == %s\n", openair0_cfg[0].tx_subdev);
|
LOG_I(HW, "openair0_cfg[0].tx_subdev == %s\n", openair0_cfg[0].tx_subdev);
|
||||||
tx_subdev = openair0_cfg[0].tx_subdev;
|
tx_subdev = openair0_cfg[0].tx_subdev;
|
||||||
|
|||||||
@@ -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_init *fh_init = get_xran_fh_init();
|
||||||
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||||
nr_prach_info_t prach_info = get_prach_info(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;
|
struct xran_ru_config *ru_conf = &fh_cfg->ru_conf;
|
||||||
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
|
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
|
||||||
int slots_per_subframe = 1 << 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);
|
LOG_W(HW, "we get rach data from ru, but it is not scheduled %d.%d\n", frame, slot);
|
||||||
return -1;
|
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++) {
|
for (int aa = 0; aa < ru->nb_rx; aa++) {
|
||||||
int16_t *dst, *src;
|
int16_t *dst, *src;
|
||||||
int idx = 0;
|
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;
|
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 */
|
/* convert Network order to host order */
|
||||||
if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) {
|
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++) {
|
for (idx = 0; idx < 139 * 2; idx++) {
|
||||||
dst[idx] = ((int16_t)ntohs(src[idx + g_kbar]));
|
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");
|
AssertFatal(1 == 0, "BFP decompression not supported on this architecture");
|
||||||
#endif
|
#endif
|
||||||
// note: this is hardwired for 139 point PRACH sequence, kbar=2
|
// 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++)
|
for (idx = 0; idx < (139 * 2); idx++)
|
||||||
dst[idx] = local_dst[idx + g_kbar];
|
dst[idx] = local_dst[idx + g_kbar];
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ extern "C" {
|
|||||||
#include <common/utils/load_module_shlib.h>
|
#include <common/utils/load_module_shlib.h>
|
||||||
#include <openair1/SIMULATION/TOOLS/sim.h>
|
#include <openair1/SIMULATION/TOOLS/sim.h>
|
||||||
#include "rfsimulator.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 <queue>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -112,10 +116,6 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt);
|
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_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_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);
|
static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ int main(int argc, char *argv[]) {
|
|||||||
timestamp+=blockSize;
|
timestamp+=blockSize;
|
||||||
header.option_value=0;
|
header.option_value=0;
|
||||||
header.option_flag=0;
|
header.option_flag=0;
|
||||||
|
header.beam_map = 1;
|
||||||
} else {
|
} else {
|
||||||
AssertFatal(read(fd,&header,sizeof(header)), "");
|
AssertFatal(read(fd,&header,sizeof(header)), "");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user