SRIOV.sh
#!/bin/bash
__FileName__=""
__Author__="ShiWei"
__Time__="/2021/05/08"
__Version__="V1"
# 打印命令 并且 执行命令 函数
execute_and_pirnt_cmd() {
# 第二个 参数 所执行命令 的注释
# echo -e "\n $2 "
printf "\n%12s %-s\n" " " $2
echo "[root@shiwei ~]# ${1}"
res=-1 # 无 特殊字符命令的 输出状态
result=0 # 有特殊字符命令的 输出结果
echo $1 | grep -E ['!'@#\$%^\&*\(\)\>\<\|_+] &> /dev/zero
# 0 : 有 特殊字符 ; 1 : 无 特殊字符
if [ $? -ne 0 ];then
$1
res=$?
else
# 命令之后包含 管道符
echo $1 > cmd_script
chmod 777 cmd_script
bash cmd_script
# ./cmd_script > result_file
# result=`cat result_file`
# rm -rf result_file
rm -rf cmd_script
# return ${result}
# res=$? # 此种方式 获取命令 执行结果 失败
fi
return ${res}
}
# 自动判断 该参数是否 配置,
read_or_config () {
# 必须保证两个参数
# 先判断 该参数是否已 配置
if [ -z `eval 'echo $'"${2}"` ]; then
read -p "$1" "$2"
fi
}
# 优化网口
optim_net_card () {
# 优化 物理网口
ip link set ${1// /} mtu 9000
combined=`ethtool -l ${1} | grep "Combined" | head -1 | awk -F ":" '{print $2}'`
ethtool -L ${1} combined ${combined// /}
# 设置网卡最大缓存
rx_num=`ethtool -g ${1} | grep -i rx: | sed -n '1p' | cut -d: -f2`
tx_num=`ethtool -g ${1} | grep -i tx: | sed -n '1p' | cut -d: -f2`
ethtool -G ${1} rx ${rx_num// /} tx ${tx_num// }
} &> /dev/zero
bus () {
echo '[root@Num_eigth_46 ~]# lspci -vvv | grep -i ether'
lspci -vvv | grep -i ether
printf "%-15s %-8s %-15s %-15s %-20s %-32s %18s\n" "网口名" " 状态" " Bus 号" " 驱动名" " 驱动版本" " 固件版本" " 槽位号"
for i in `cat /proc/net/dev | egrep -iv 'lo:|virbr|vnet|face|inter' | cut -d: -f1 | sort`
do
printf "%-15s" $i
state=`ip addr show $i | sed '1p' -n | awk -F state '{print $2}' | awk '{print $1}'`
printf "%-8s" $state
bus=`ethtool -i $i | grep -i bus | awk -F info: '{print $2}'`
printf "%-15s" $bus
driver_name=`ethtool -i $i | sed '1p' -n | awk -F river: '{print $2}'`
printf "%-15s" $driver_name
driver_ver=`ethtool -i $i | sed '2p' -n | awk -F sion: '{print $2}'`
printf "%-20s" $driver_ver
fw_version=`ethtool -i $i | sed '3p' -n | cut -d: -f2`
printf "%-32s" "$fw_version"
slots=`lspci -v -s ${bus} | grep 'Physical Slot' | cut -d ':' -f2 | grep -v 'Input/output'`
printf "%-6s\n" $slots
done
}
# [[ ${arr[@]/ens4f0/} != ${arr[@]} ]] && echo "Yes" || echo "No"
echo "#############################################################################################"
echo "##################### SRIOV 自动化脚本 ########################"
echo "#############################################################################################"
echo
printf "****** 若当前为 SSH 链接机器, 则链接 IP 不可为当前所要配置SRIOV的网卡的IP ******** \n"
printf "****** 若该卡的是1G 电口卡,且驱动为 igb, 则SRIOV 的配置方法为 modprobe igb max_vfs=2,2,2,2 \n 当同时存在多个驱动为 igb 的1G电口卡时, 默认优先分离板载的, ****\n"
printf "****** 到当前为止 , 对 intel , mellanox, wangxun 卡 均有效 *****\n"
printf "****** 需要打 VF 驱动的网卡请自行先把 VF 驱动打好,否则即使分离 VF 口成功了, \n 由于不存在 VF 驱动的拉起, 你是看不到 VF 网口名的,但是各个 VF 口的 PCI 设备是存在的 \n"
echo "#############################################################################################"
echo
PLATFORM='intel'
VIRT_BIOS='yes'
int_name=""
BUS=""
VF_NUM="0"
CURR_VF_NUM="0"
VF_ROOT=""
MAX_VF=""
TP_1G_SPEED="0"
echo
echo
# <1. 判断 CPU 平台
lscpu | sed '19p' -n | grep -i "VT-x" # intel
if [ $? -eq 0 ]; then
echo "该系统 CPU 为 Intel 平台"
else
lscpu | sed '19p' -n | grep -i "amd-v" # amd
if [ $? -eq 0 ]; then
PLATFORM="amd"
echo "*********** 该系统 CPU 为 AMD 平台"
else
PLATFORM="other"
echo "*********** 该系统 CPU 为未知 平台"
exit
fi
fi
# <2. 判断 系统是否 开启 IOMMU, Intel 平台 在 /etc/default/grub 文件中添加 "intel_iommu=on iommu=pt",
# Intel 平台 开启 IOMMU
# 判断 Intel 平台 是否开启 IOMMU
if [ "$PLATFORM" == "intel" ]; then
virt-host-validate | grep -i warn
if [ $? -eq 0 ]; then
grubby --update-kernel=`grubby --default-kernel` --args="intel_iommu=on iommu=pt"
grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
echo "*********** 该 Intel 平台系统内核已配置 IOMMU, 请重启就好 ......."
fi
fi
# 提示 要重启, 使其新添加的内核 参数 生效
# AMD 平台 无需开启 IOMMU, 自动开启
# <3. 判断 系统 BIOS 是否开启 SRIOV 虚拟化开关
# Intel 平台在 Bios 下开启 VT-D 虚拟化开关
# AMD 平台需要在 Bios 下开启 SRIOV 和 SVM 两个 开关
virt-host-validate | grep "/dev/kvm exists" | grep -i "fail"
if [ $? -eq 0 ]; then
VIRT_BIOS="no"
fi
if [ "$VIRT_BIOS" == "no" ];then
if [ "$PLATFORM" == "amd" ]; then
modprobe kvm
modprobe ccp
modprode kvm_amd
echo "*********** 该 AMD 平台系统在 BIOS 下 未 开启虚拟化 SRIOV 和 SVM 开关, 请开启........."
exit
elif [ "$PLATFORM" == "intel" ]; then
modprobe kvm
mobprobe kvm_intel
echo "*********** 该 Intel 平台系统在 BIOS 下 未 开启虚拟化 VT-D 开关, 请开启........."
exit
fi
else
echo "*********** 该 ${PLATFORM} 平台系统在 BIOS 下已开启虚拟化开关。"
fi
echo
# 展示 SRIOV vF 信息
bus
echo
# 输入待测网口名
while :
do
read_or_config "请输入本机待测网口名:" int_name
cat /proc/net/dev | egrep -iv 'lo:|virbr|vnet|face|inter' | cut -d: -f1 | grep ${int_name// /} &> /dev/zero
if [ $? -eq 0 ];then
break
else
echo "Sorry !本机无此网口, 请重新输入.........."
int_name=""
fi
done
echo
# 获取网卡 品牌 信息
bus_str=`ethtool -i ${int_name} | grep 'bus-info' | awk '{print $2}' | sed 's# ##g'`
driver_name=`ethtool -i ${int_name} | grep 'driver:' | awk '{print $2}' | sed 's# ##g'`
type_str=`lspci -vvv | grep 'Ethernet controller' | grep "${bus_str#*:}" | awk '{print $4,$5}' | tr A-Z a-z `
# 获取网卡是电口还是 光口(TP: 电口; FIBRE: 光口)
cable_type=`ethtool ${int_name} | grep 'Supported ports:' | sed -r 's#.*\[(.*)\]$#\1#g' | sed 's/ //g'`
# 获取网卡当前速率
net_curr_speed=`ethtool ${int_name} | grep 'Speed:' | awk '{print $2}'`
# 判断该网卡是 几 P 的(几个接口的)
net_port_total=`ls -al "/sys/bus/pci/drivers/${driver_name}/" | grep ${bus_str%.*} | wc -l`
# 判断当前 网口是 该网卡的 第几个 接口
net_port_num=${bus_str##*.}
# 当前 该网卡所有 网口的 vf 数量
declare -a every_curr_vfs
for num in $(seq 0 $(echo $((4-1))))
do
every_curr_vfs[${num}]=`cd /sys/bus/pci/drivers/${driver_name} && cat ${bus_str%.*}.${num}/sriov_numvfs`
done
if [ "${cable_type}" == "TP" -a "${driver_name}" == "igb" ]; then
echo "******** 该网卡接口为电口, 且速率为 ${net_curr_speed}"
TP_1G_SPEED="1"
elif [ "${cable_type}" == "FIBRE" ]; then
echo "******** 该网卡接口为光口 "
fi
#* 表示任意字符串。
#[abc] 表示 a、b、c 三个字符中的任意一个。比如,[15ZH] 表示 1、5、Z、H 四个字符中的任意一个。
#[m-n] 表示从 m 到 n 的任意一个字符。比如,[0-9] 表示任意一个数字,[0-9a-zA-Z] 表示字母或数字。
#| 表示多重选择,类似逻辑运算中的或运算。比如,abc | xyz 表示匹配字符串 "abc" 或者 "xyz"。
case ${type_str} in
*intel*)
brand="intel"
;;
*mellanox*)
brand="mellanox"
;;
*wangxun*)
brand="wangxun"
;;
*)
brand="no"
;;
esac
echo "******** 网卡品牌为: ${brand}"
cd "/sys/bus/pci/devices/"
# 等价地址
# /sys/class/net/<网口名>/device
# 获取 Bus 号
BUS=`ethtool -i ${int_name} | grep -i bus | awk -F info: '{print $2}'`
BUS=${BUS// /}
echo "*********** ${int_name} 网口的 BUS 号为: $BUS"
#VF_ROOT="/sys/bus/pci/devices/${BUS}"
#cd VF_ROOT
# 展示 可分离的 最大 VF 口数量
MAX_VF=`cat ${BUS// /}/sriov_totalvfs`
CURR_VF_NUM=`cat ${BUS// /}/sriov_numvfs`
echo "*********** ${int_name} 网口可分离的最大 VF 数量为: ${MAX_VF}"
echo "*********** ${int_name} 网口当前已分离的 VF 口数量为: ${CURR_VF_NUM}"
echo
# 设置 VF
while :
do
read -p "请输入${int_name} 网口要分离的 VF 口数量:" VF_NUM
# 判断输入得是否有效
if [[ ${VF_NUM// /} -gt $MAX_VF || ${VF_NUM// /} -lt 0 ]];then
echo " 可分离 VF 口有效范围为: (0 <= VF <= ${MAX_VF})"
else
# 判断是否不为 1G 电口卡
if [ "${TP_1G_SPEED}" == "0" ]; then
echo ${VF_NUM} > ${BUS// /}/sriov_numvfs
else
modprobe -r igb
sleep 1
# 给该网卡所有网口
every_curr_vfs[${net_port_num}]=${VF_NUM}
config_str="${every_curr_vfs[0]},${every_curr_vfs[1]},${every_curr_vfs[2]},${every_curr_vfs[3]}"
modprobe igb max_vfs=${config_str}
# modprobe igb max_vfs=2,2,2,2
echo
fi
echo "*********** VF 口分离完成。"
wait
sleep 1
break
fi
done
sleep 7
# 展示 所有 创建的 VF 口
if [[ "${VF_NUM}" -ne "0" ]]; then
#bus | grep "${int_name}v"
echo "在 ${int_name} 物理网口上所创建的所有 VF 口如下:"
all_vf=($(cat /proc/net/dev | egrep -iv 'lo:|virbr|vnet|face|inter' | cut -d: -f1 | egrep -i "${int_name}.{1,}" | sort --field-separator=" " --key=3))
for vf in $(seq $(echo $((${VF_NUM// /} - 1 ))) -1 0)
do
if [ `expr ${vf} % 5` == "0" ]; then
printf "\n"
fi
printf " ${all_vf[${vf}]} "
done
echo " ${all_vf[0]} "
# 设置物理口的 mtu 为 9000
optim_net_card ${int_name}
# 设置 所有 VF 口 的 mtu 为 9000
for vf_dev in `cat /proc/net/dev | egrep -iv 'lo:|virbr|vnet|face|inter' | cut -d: -f1 | egrep -i "${int_name}[a-z]{1,}" | sort --field-separator=" " --key=3 | awk '{print $1}'`
do
# ip link set ${vf_dev// /} mtu 9000
optim_net_card ${vf_dev}
done
fi
echo
echo
# 优化 物理网口
# 设置最大队列
#combined=`ethtool -l ${int_name} | grep "Combined" | head -1 | awk -F ":" '{print $2}'`
#ethtool -L ${int_name} combined ${combined}
# # 设置网卡最大缓存
#rx_num=`ethtool -g ${int_name} | grep -i rx | sed -n '1p' | cut -d: -f2`
#tx_num=`ethtool -g ${int_name} | grep -i tx | sed -n '1p' | cut -d: -f2`
#ethtool -G ${int_name} rx ${rx_num} tx ${tx_num}
# DHCP 获取 IP
dhclient -r
dhclient &> /dev/zero
# 善意的提醒
# 1. 测试 SRIOV bond 时 , 别忘记安装 python3 了