347 lines
9.6 KiB
Bash
Executable File
Vendored
347 lines
9.6 KiB
Bash
Executable File
Vendored
#!/bin/bash
|
||
|
||
# Auto N2 Handover Test Script
|
||
# 自动启动两个基站和一个UE,完成N2切换测试
|
||
|
||
set -e
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 日志函数
|
||
log_info() {
|
||
echo -e "${GREEN}[INFO]${NC} $1"
|
||
}
|
||
|
||
log_warn() {
|
||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||
}
|
||
|
||
log_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
log_step() {
|
||
echo -e "${BLUE}[STEP]${NC} $1"
|
||
}
|
||
|
||
# 获取脚本目录
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
UERANSIM_DIR="$(dirname "$SCRIPT_DIR")"
|
||
|
||
# 配置文件路径
|
||
GNB1_CONFIG="$UERANSIM_DIR/config/free5gc-gnb.yaml"
|
||
GNB2_CONFIG="$UERANSIM_DIR/config/free5gc-gnb2.yaml"
|
||
UE_CONFIG="$UERANSIM_DIR/config/free5gc-ue.yaml"
|
||
|
||
# 日志目录
|
||
LOG_DIR="$UERANSIM_DIR/logs"
|
||
mkdir -p "$LOG_DIR"
|
||
|
||
# PID文件
|
||
GNB1_PID_FILE="$LOG_DIR/gnb1.pid"
|
||
GNB2_PID_FILE="$LOG_DIR/gnb2.pid"
|
||
UE_PID_FILE="$LOG_DIR/ue.pid"
|
||
|
||
# 清理函数
|
||
cleanup() {
|
||
log_step "开始清理进程..."
|
||
|
||
# 停止UE
|
||
if [ -f "$UE_PID_FILE" ]; then
|
||
UE_PID=$(cat "$UE_PID_FILE")
|
||
if kill -0 "$UE_PID" 2>/dev/null; then
|
||
log_info "停止UE进程 (PID: $UE_PID)"
|
||
sudo kill "$UE_PID" || true
|
||
fi
|
||
rm -f "$UE_PID_FILE"
|
||
fi
|
||
|
||
# 停止gNB进程
|
||
if [ -f "$GNB1_PID_FILE" ]; then
|
||
GNB1_PID=$(cat "$GNB1_PID_FILE")
|
||
if kill -0 "$GNB1_PID" 2>/dev/null; then
|
||
log_info "停止gNB1进程 (PID: $GNB1_PID)"
|
||
sudo kill "$GNB1_PID" || true
|
||
fi
|
||
rm -f "$GNB1_PID_FILE"
|
||
fi
|
||
|
||
if [ -f "$GNB2_PID_FILE" ]; then
|
||
GNB2_PID=$(cat "$GNB2_PID_FILE")
|
||
if kill -0 "$GNB2_PID" 2>/dev/null; then
|
||
log_info "停止gNB2进程 (PID: $GNB2_PID)"
|
||
sudo kill "$GNB2_PID" || true
|
||
fi
|
||
rm -f "$GNB2_PID_FILE"
|
||
fi
|
||
|
||
# 清理所有相关进程
|
||
sudo pkill -f "nr-gnb" || true
|
||
sudo pkill -f "nr-ue" || true
|
||
|
||
log_info "清理完成"
|
||
}
|
||
|
||
# 检查进程状态
|
||
check_process() {
|
||
local pid=$1
|
||
local name=$2
|
||
if kill -0 "$pid" 2>/dev/null; then
|
||
log_info "$name 运行正常 (PID: $pid)"
|
||
return 0
|
||
else
|
||
log_error "$name 进程异常退出"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 等待gNB连接到AMF
|
||
wait_gnb_ready() {
|
||
local gnb_name=$1
|
||
local log_file=$2
|
||
local max_wait=30
|
||
local count=0
|
||
|
||
log_info "等待 $gnb_name 连接到AMF..."
|
||
|
||
while [ $count -lt $max_wait ]; do
|
||
if grep -q "NG Setup procedure is successful" "$log_file" 2>/dev/null; then
|
||
log_info "$gnb_name 成功连接到AMF"
|
||
return 0
|
||
fi
|
||
sleep 1
|
||
count=$((count + 1))
|
||
done
|
||
|
||
log_error "$gnb_name 连接AMF超时"
|
||
return 1
|
||
}
|
||
|
||
# 等待UE注册完成
|
||
wait_ue_registered() {
|
||
local log_file=$1
|
||
local max_wait=30
|
||
local count=0
|
||
|
||
log_info "等待UE完成注册..."
|
||
|
||
while [ $count -lt $max_wait ]; do
|
||
if grep -q "Initial Registration is successful" "$log_file" 2>/dev/null; then
|
||
log_info "UE注册成功"
|
||
return 0
|
||
fi
|
||
sleep 1
|
||
count=$((count + 1))
|
||
done
|
||
|
||
log_error "UE注册超时"
|
||
return 1
|
||
}
|
||
|
||
# 获取UE ID
|
||
get_ue_id() {
|
||
local gnb_name=$1
|
||
local ue_list_output
|
||
ue_list_output=$("$UERANSIM_DIR/build/nr-cli" "$gnb_name" -e "ue-list" 2>/dev/null || echo "")
|
||
|
||
if [ -n "$ue_list_output" ]; then
|
||
echo "$ue_list_output" | grep "ue-id:" | head -1 | sed 's/.*ue-id: *//' | awk '{print $1}'
|
||
else
|
||
echo ""
|
||
fi
|
||
}
|
||
|
||
# 检查handover是否成功
|
||
check_handover_success() {
|
||
local source_gnb=$1
|
||
local target_gnb=$2
|
||
local original_ue_id=$3
|
||
|
||
log_info "检查handover结果..."
|
||
|
||
# 检查目标gNB是否有UE
|
||
local target_ue_id
|
||
target_ue_id=$(get_ue_id "$target_gnb")
|
||
|
||
# 检查源gNB的UE数量
|
||
local source_ue_count
|
||
source_ue_count=$("$UERANSIM_DIR/build/nr-cli" "$source_gnb" -e "ue-list" 2>/dev/null | grep -c "ue-id:" || echo "0")
|
||
|
||
log_info "源gNB ($source_gnb) UE数量: $source_ue_count"
|
||
log_info "目标gNB ($target_gnb) UE ID: ${target_ue_id:-无}"
|
||
|
||
# 如果目标gNB有UE,认为handover成功(源gNB可能需要更多时间清理)
|
||
if [ -n "$target_ue_id" ]; then
|
||
log_info "✅ Handover成功!"
|
||
log_info " 目标gNB ($target_gnb): UE ID = $target_ue_id"
|
||
|
||
if [ "$source_ue_count" -eq 0 ]; then
|
||
log_info " 源gNB ($source_gnb): UE已完全清理"
|
||
else
|
||
log_warn " 源gNB ($source_gnb): UE还未完全清理 (数量: $source_ue_count) - 这是正常的,清理可能需要更多时间"
|
||
fi
|
||
return 0
|
||
else
|
||
log_error "❌ Handover失败!"
|
||
log_error " 源gNB UE数量: $source_ue_count"
|
||
log_error " 目标gNB UE ID: ${target_ue_id:-无}"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
log_step "=== 自动N2 Handover测试开始 ==="
|
||
|
||
# 设置退出时清理
|
||
trap cleanup EXIT
|
||
|
||
# 1. 清理现有进程
|
||
log_step "步骤1: 清理现有进程"
|
||
cleanup
|
||
sleep 2
|
||
|
||
# 2. 启动gNB1 (目标gNB)
|
||
log_step "步骤2: 启动gNB1 (192.168.8.117)"
|
||
sudo "$UERANSIM_DIR/build/nr-gnb" -c "$GNB1_CONFIG" > "$LOG_DIR/gnb1.log" 2>&1 &
|
||
GNB1_PID=$!
|
||
echo "$GNB1_PID" > "$GNB1_PID_FILE"
|
||
log_info "gNB1已启动 (PID: $GNB1_PID)"
|
||
|
||
# 等待gNB1连接AMF
|
||
if ! wait_gnb_ready "gNB1" "$LOG_DIR/gnb1.log"; then
|
||
log_error "gNB1启动失败"
|
||
exit 1
|
||
fi
|
||
|
||
# 3. 启动gNB2 (源gNB)
|
||
log_step "步骤3: 启动gNB2 (192.168.8.118)"
|
||
sleep 3
|
||
sudo "$UERANSIM_DIR/build/nr-gnb" -c "$GNB2_CONFIG" > "$LOG_DIR/gnb2.log" 2>&1 &
|
||
GNB2_PID=$!
|
||
echo "$GNB2_PID" > "$GNB2_PID_FILE"
|
||
log_info "gNB2已启动 (PID: $GNB2_PID)"
|
||
|
||
# 等待gNB2连接AMF
|
||
if ! wait_gnb_ready "gNB2" "$LOG_DIR/gnb2.log"; then
|
||
log_error "gNB2启动失败"
|
||
exit 1
|
||
fi
|
||
|
||
# 4. 启动UE并连接到gNB2
|
||
log_step "步骤4: 启动UE并连接到gNB2"
|
||
sleep 3
|
||
sudo "$UERANSIM_DIR/build/nr-ue" -c "$UE_CONFIG" > "$LOG_DIR/ue.log" 2>&1 &
|
||
UE_PID=$!
|
||
echo "$UE_PID" > "$UE_PID_FILE"
|
||
log_info "UE已启动 (PID: $UE_PID)"
|
||
|
||
# 等待UE注册完成
|
||
if ! wait_ue_registered "$LOG_DIR/ue.log"; then
|
||
log_error "UE注册失败"
|
||
exit 1
|
||
fi
|
||
|
||
# 5. 检查初始状态
|
||
log_step "步骤5: 检查初始UE分布"
|
||
sleep 2
|
||
|
||
# 确定UE连接到哪个gNB
|
||
log_info "检查gNB1的UE列表..."
|
||
UE_LIST_GNB1=$("$UERANSIM_DIR/build/nr-cli" "UERANSIM-gnb-460-0-1" -e "ue-list" 2>/dev/null || echo "")
|
||
log_info "gNB1 UE列表输出: '$UE_LIST_GNB1'"
|
||
|
||
log_info "检查gNB2的UE列表..."
|
||
UE_LIST_GNB2=$("$UERANSIM_DIR/build/nr-cli" "UERANSIM-gnb-460-0-16" -e "ue-list" 2>/dev/null || echo "")
|
||
log_info "gNB2 UE列表输出: '$UE_LIST_GNB2'"
|
||
|
||
UE_ID_GNB1=$(echo "$UE_LIST_GNB1" | grep "ue-id:" | head -1 | sed 's/.*ue-id: *//' | awk '{print $1}')
|
||
UE_ID_GNB2=$(echo "$UE_LIST_GNB2" | grep "ue-id:" | head -1 | sed 's/.*ue-id: *//' | awk '{print $1}')
|
||
|
||
if [ -n "$UE_ID_GNB1" ]; then
|
||
SOURCE_GNB="UERANSIM-gnb-460-0-1"
|
||
TARGET_GNB="UERANSIM-gnb-460-0-16"
|
||
TARGET_CELL="16"
|
||
UE_ID="$UE_ID_GNB1"
|
||
log_info "UE连接到gNB1,UE ID: $UE_ID"
|
||
elif [ -n "$UE_ID_GNB2" ]; then
|
||
SOURCE_GNB="UERANSIM-gnb-460-0-16"
|
||
TARGET_GNB="UERANSIM-gnb-460-0-1"
|
||
TARGET_CELL="1"
|
||
UE_ID="$UE_ID_GNB2"
|
||
log_info "UE连接到gNB2,UE ID: $UE_ID"
|
||
else
|
||
log_error "未找到UE连接"
|
||
exit 1
|
||
fi
|
||
|
||
# 6. 执行handover
|
||
log_step "步骤6: 执行N2 Handover"
|
||
log_info "从 $SOURCE_GNB 切换UE $UE_ID 到目标Cell $TARGET_CELL"
|
||
|
||
HANDOVER_OUTPUT=$("$UERANSIM_DIR/build/nr-cli" "$SOURCE_GNB" -e "handover $UE_ID $TARGET_CELL" 2>&1)
|
||
log_info "Handover命令输出: $HANDOVER_OUTPUT"
|
||
|
||
# 7. 等待handover完成
|
||
log_step "步骤7: 等待handover完成"
|
||
sleep 15 # 等待handover完成 (8秒清理时间 + 7秒缓冲)
|
||
|
||
# 8. 验证handover结果
|
||
log_step "步骤8: 验证handover结果"
|
||
if check_handover_success "$SOURCE_GNB" "$TARGET_GNB" "$UE_ID"; then
|
||
log_step "=== ✅ N2 Handover测试成功完成 ==="
|
||
|
||
# 显示最终状态
|
||
echo ""
|
||
log_info "最终UE分布:"
|
||
echo "gNB1 (UERANSIM-gnb-460-0-1):"
|
||
"$UERANSIM_DIR/build/nr-cli" "UERANSIM-gnb-460-0-1" -e "ue-list" 2>/dev/null || echo " 无UE连接"
|
||
echo ""
|
||
echo "gNB2 (UERANSIM-gnb-460-0-16):"
|
||
"$UERANSIM_DIR/build/nr-cli" "UERANSIM-gnb-460-0-16" -e "ue-list" 2>/dev/null || echo " 无UE连接"
|
||
|
||
# 保持运行以便观察
|
||
echo ""
|
||
log_info "测试完成!按Ctrl+C退出并清理进程"
|
||
while true; do
|
||
sleep 5
|
||
# 检查进程状态
|
||
if ! check_process "$GNB1_PID" "gNB1" || ! check_process "$GNB2_PID" "gNB2" || ! check_process "$UE_PID" "UE"; then
|
||
log_warn "发现进程异常,退出测试"
|
||
break
|
||
fi
|
||
done
|
||
else
|
||
log_step "=== ❌ N2 Handover测试失败 ==="
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 检查是否以root权限运行
|
||
if [ "$EUID" -ne 0 ]; then
|
||
echo -e "${RED}[ERROR]${NC} 请使用sudo运行此脚本"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查构建目录
|
||
if [ ! -f "$UERANSIM_DIR/build/nr-gnb" ] || [ ! -f "$UERANSIM_DIR/build/nr-ue" ]; then
|
||
log_error "找不到UERANSIM构建文件,请先运行make编译"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查配置文件
|
||
for config in "$GNB1_CONFIG" "$GNB2_CONFIG" "$UE_CONFIG"; do
|
||
if [ ! -f "$config" ]; then
|
||
log_error "找不到配置文件: $config"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
# 运行主函数
|
||
main "$@"
|