#!/bin/bash
PROJ_ROOT=$(
cd $(dirname $0)/
pwd
)
confPath="/etc/gazelle/lstack.conf"
backupPath="/etc/gazelle/lstack.conf.bak"
selectConf="$confPath"
declare -A lstack_settings
lstack_settings=(
["use_ltran"]="是否使用ltran?:number:0,1"
["listen_shadow"]="是否使用影子fd监听,单个listen线程多个协议栈线程时使用:number:0,1"
["num_cpus"]="lstack线程绑定的cpu编号,编号的数量为lstack线程个数(小于等于网卡多队列数量)。可按NUMA选择cpu:string"
["app_bind_numa"]="应用的epoll和poll线程是否绑定到协议栈所在的numa,缺省值是1,即绑定:number:0,1"
["app_exclude_cpus"]="应用的epoll和poll线程不会绑定到的cpu编号,app_bind_numa = 1时才生效。示例:\"7,8,9 ...\":string"
["low_power_mode"]="是否开启低功耗模式,暂不支持:number:0,1"
["kni_switch"]="rte_kni开关,默认为0。只有不使用ltran时才能开启:number:0,1"
["unix_prefix"]="gazelle进程间通信使用的unix socket文件前缀字符串,默认为空,和需要通信的ltran.conf的unix_prefix或gazellectl的-u参数配置一致。不能含有特殊字符,最大长度为128:string"
["host_addr"]="协议栈的IP地址,必须和redis-server配置文件里的“bind”字段保存一致:string"
["mask_addr"]="掩码地址:string"
["gateway_addr"]="网关地址:string"
["devices"]="网卡通信的mac地址,需要与ltran.conf的bond_macs配置一致;在lstack bond1模式下,可指定bond1的主接口,取值为bond_slave_mac之一:string"
["send_connect_number"]="设置为正整数,表示每次协议栈循环中发包处理的连接个数:number"
["read_connect_number"]="设置为正整数,表示每次协议栈循环中收包处理的连接个数:number"
["rpc_number"]="设置为正整数,表示每次协议栈循环中rpc消息处理的个数:number"
["nic_read_num"]="设置为正整数,表示每次协议栈循环中从网卡读取的数据包的个数:number"
["tcp_conn_count"]="tcp的最大连接数,该参数乘以mbuf_count_per_conn是初始化时申请的mbuf池大小,配置过小会启动失败,tcp_conn_count * mbuf_count_per_conn * 2048字节不能大于大页大小:number"
["mbuf_count_per_conn"]="每个tcp连接需要的mbuf个数,该参数乘以tcp_conn_count是初始化时申请的mbuf地址池大小,配置过小会启动失败,tcp_conn_count * mbuf_count_per_conn * 2048字节不能大于大页大小:number"
["nic_rxqueue_size"]="网卡接收队列深度,范围512-8192,缺省值是4096:number"
["nic_txqueue_size"]="网卡发送队列深度,范围512-8192,缺省值是2048:number"
["nic_vlan_mode"]="vlan模式开关,变量值为vlanid,取值范围-1~4094,-1关闭,缺省值是-1:number"
["bond_mode"]="bond模式,目前支持ACTIVE_BACKUP/8023AD/ALB三种模式,对应的取值是1/4/6;当取值为-1或者NULL时,表示未配置bond:number:1,4,6,-1"
["bond_slave_mac"]="用于组bond的两个子口的mac地址:string"
["bond_miimon"]="链路监控时间,单位为ms,取值范围为1到2^31 - 1,缺省值为10ms:number"
["flow_bifurcation"]="流量分叉开关(替代kni方案),通过gazelle将不支持处理的报文转发到内核,缺省值是0,即关闭:number:0,1"
["stack_thread_mode"]="默认即可:string"
)
keys=(
"use_ltran"
"listen_shadow"
"num_cpus"
"app_bind_numa"
"app_exclude_cpus"
"low_power_mode"
"kni_switch"
"unix_prefix"
"host_addr"
"mask_addr"
"gateway_addr"
"devices"
"send_connect_number"
"read_connect_number"
"rpc_number"
"nic_read_num"
"tcp_conn_count"
"mbuf_count_per_conn"
"nic_rxqueue_size"
"nic_txqueue_size"
"nic_vlan_mode"
"bond_mode"
"bond_slave_mac"
"bond_miimon"
"flow_bifurcation"
"stack_thread_mode"
)
declare -A conditions
conditions=(
["app_exclude_cpus"]="app_bind_numa=1"
["kni_switch"]="ltran=0"
)
dpdk_para_args=("--socket-mem" "--huge-dir" "--proc-type" "--iova-mode")
dpdk_onoff_args=("--legacy-mem" "--map-perfect" "-d")
ask_for_start() {
while true; do
read -p "是否继续进行lstack进行配置?(y/n): " ifstart
case "$ifstart" in
[yY][eE][sS]|[yY]|"")
ifstart=true
break
;;
[nN][oO]|[nN])
ifstart=false
break
;;
*)
echo "输入有误,请重新输入!"
;;
esac
done
if [ "$ifstart" == false ]; then
echo "已退出lstack配置"
exit 0
fi
}
check_backup_config() {
if [ -f "$backupPath" ]; then
while true; do
read -p "是否从已有的配置文件开始?输入 'y' 使用已有配置,输入 'n' 使用默认配置 (y/n): " userChoice
case "$userChoice" in
[yY][eE][sS]|[yY]|"")
selectConf="$confPath"
break
;;
[nN][oO]|[nN])
selectConf="$backupPath"
break
;;
*)
echo "输入有误,请重新输入!"
;;
esac
done
else
cp "$confPath" "$backupPath"
fi
}
read_config() {
origin_setting_text=$(<"$selectConf")
while IFS= read -r line; do
text=$(echo "$line" | tr -d ' ')
if [ -z "$text" ] || [[ $text == \#* ]]; then
continue
fi
IFS='=' read -r name value <<< "$text"
if [ "$name" == "dpdk_args" ]; then
dpdk_data=($(echo $value | sed 's/[][]//g' | tr -d '"' | tr ',' '\n' | xargs))
fi
if [ -n "${lstack_settings[$name]}" ]; then
IFS=':' read -r tip type choice <<< "${lstack_settings[$name]}"
if [ "$type" == "number" ]; then
lstack_settings["$name,default"]=$(echo "$value")
elif [ "$type" == "string" ]; then
lstack_settings["$name,default"]=$(echo "$value")
fi
fi
done <<< "$origin_setting_text"
}
set_dpdk_args() {
output_args=()
for name in "${dpdk_para_args[@]}"; do
if [[ " ${dpdk_data[@]} " =~ " ${name} " ]]; then
index=$(printf "%s\n" "${dpdk_data[@]}" | grep -n -w -- "$name" | cut -d: -f1)
default_value="${dpdk_data[index]}"
read -p "请设定dpdk参数${name}值,默认值为${default_value}:" userChoice
userChoice=${userChoice:-$default_value}
output_args+=("$name" "$userChoice")
else
read -p "请设定dpdk参数${name}值,默认跳过不使用该参数:" userChoice
if [ -n "$userChoice" ]; then
output_args+=("$name" "$userChoice")
fi
fi
done
for name in "${dpdk_onoff_args[@]}"; do
default_value=false
if [[ " ${dpdk_data[@]} " =~ " ${name} " ]]; then
default_value=true
fi
while true; do
read -p "是否使用dpdk参数${name},默认为$(if $default_value; then echo "启用"; else echo "不启用"; fi) (y/n):" userChoice
userChoice=${userChoice,,}
if [ -z "$userChoice" ]; then
userChoice=$default_value
break
elif [[ "$userChoice" =~ ^(y|yes)$ ]]; then
userChoice=true
break
elif [[ "$userChoice" =~ ^(n|no)$ ]]; then
userChoice=false
break
else
echo "输入有误,请重新输入!"
fi
done
if $userChoice; then
output_args+=("$name")
fi
done
outputtext="${output_args[*]}"
}
set_lstack_args() {
for name in "${keys[@]}"; do
IFS=":" read -r tip type choice <<< "${lstack_settings[$name]}"
default="${lstack_settings[$name,default]}"
if [[ -n "${conditions[$name]}" && "$outputtext" != *"${conditions[$name]}"* ]]; then
continue
fi
options_text=""
if [[ -n "$choice" ]]; then
options_text="可选项:$choice,"
fi
if [[ -n "$default" ]]; then
text="请输入${name}参数。说明:${tip}。${options_text}默认为${default}:"
else
text="请输入${name}参数。说明:${tip}。默认为不设置${options_text}:"
fi
while true; do
read -p "$text" userChoice
if [[ -z "$userChoice" ]]; then
if [[ -n "$default" ]]; then
validChoice="$default"
break
else
validChoice=""
break
fi
fi
if [[ "$type" == "number" ]]; then
if [[ -n "$choice" ]]; then
if [[ ",$choice," == *",$userChoice,"* ]]; then
validChoice="$userChoice"
break
fi
else
if [[ "$userChoice" =~ ^[0-9]+$ ]]; then
validChoice="$userChoice"
break
fi
fi
elif [[ "$type" == "string" ]]; then
userChoice="${userChoice//\"/}"
if [[ -z "$choice" || ",$choice," == *",$userChoice,"* ]]; then
validChoice="\"$userChoice\""
break
fi
fi
echo "输入参数格式有误,请重新输入!"
done
if [[ -n "$validChoice" ]]; then
outputtext+="${name}=${validChoice}\n"
fi
done
}
save_config() {
echo "以下是最终得到的配置内容:"
echo -e "$outputtext"
while true; do
read -p "您确定要保存这些内容吗?默认配置文件已备份于$backupPath (y/n): " confirm
case "$confirm" in
[yY][eE][sS]|[yY]|"")
echo "$outputtext" > $confPath
echo "内容已保存到 $confPath"
break
;;
[nN][oO]|[nN])
echo "未进行保存,配置已结束。"
break
;;
*)
echo "输入有误,请输入 y 或 n。"
;;
esac
done
}
ask_for_start
check_backup_config
read_config
set_dpdk_args
set_lstack_args
save_config