#!/bin/bash

# 脚本用途：
# 1. 将 bond0 下所有物理网卡的 RX 和 TX 队列数设置为 4096。
# 2. 为每个物理网卡创建 32 个虚拟函数（VF）。
# 3. 为所有 VF 设置最大传输速率（max_tx_rate）为 1000 Mbps。

CONFIG_FILE="${SERVICE_DIR}/config.ini"

# 定义默认值
DEFAULT_SRIOV_NUMVFS_COUNT=32
DEFAULT_BOND_SKIP_PRIMARY_DEVICE=True
DEFAULT_VF_PORT_SPEED=1000  # 默认VF端口速率为1000 Mbps

# 初始化变量
SRIOV_NUMVFS_COUNT=""
BOND_SKIP_PRIMARY_DEVICE=""
VF_PORT_SPEED=""

# 读取配置值，如果文件存在
if [ -f "$CONFIG_FILE" ]; then
    # 使用awk提取配置值，处理可能的空格和注释
    SRIOV_NUMVFS_COUNT=$(awk -F '=' '/^SRIOV_NUMVFS_COUNT[[:space:]]*=/{gsub(/[[:space:]]+/, "", $2); print $2}' "$CONFIG_FILE")
    BOND_SKIP_PRIMARY_DEVICE=$(awk -F '=' '/^BOND_SKIP_PRIMARY_DEVICE[[:space:]]*=/{gsub(/[[:space:]]+/, "", $2); print $2}' "$CONFIG_FILE")
    VF_PORT_SPEED=$(awk -F '=' '/^VF_PORT_SPEED[[:space:]]*=/{gsub(/[[:space:]]+/, "", $2); print $2}' "$CONFIG_FILE")
fi

# 如果未获取到配置值，则使用默认值
SRIOV_NUMVFS_COUNT=${SRIOV_NUMVFS_COUNT:-$DEFAULT_SRIOV_NUMVFS_COUNT}
BOND_SKIP_PRIMARY_DEVICE=${BOND_SKIP_PRIMARY_DEVICE:-$DEFAULT_BOND_SKIP_PRIMARY_DEVICE}
VF_PORT_SPEED=${VF_PORT_SPEED:-$DEFAULT_VF_PORT_SPEED}



# 函数：打印错误信息并退出
error_exit() {
    echo "错误: $1" >&2
    exit 1
}

# 检查是否以 root 身份运行
if [[ $EUID -ne 0 ]]; then
   error_exit "此脚本必须以 root 用户运行。"
fi

# 检查 ethtool 是否安装
if ! command -v ethtool &> /dev/null; then
    error_exit "ethtool 未安装。请使用包管理器安装 ethtool。"
fi

# 检查 lspci 是否安装
if ! command -v lspci &> /dev/null; then
    error_exit "lspci 未安装。请使用包管理器安装 pciutils。"
fi

# 检查 bond0 是否存在
if ! ip link show bond0 &> /dev/null; then
    error_exit "bond0 接口不存在。请确保 bond0 已正确配置。"
fi


# 获取 bond0 的模式
BOND_MODE_FILE="/sys/class/net/bond0/bonding/mode"

if [ ! -f "$BOND_MODE_FILE" ]; then
  error_exit "错误: 文件 $BOND_MODE_FILE 不存在，请确认 bond0 已配置为绑定模式。"
fi

# 读取模式
BOND_MODE=$(cat "$BOND_MODE_FILE" | awk '{print $2}')

echo "开始配置 bond0 下的所有物理网卡..."

# 获取 bond0 的从属物理网卡列表
SLAVE_INTERFACES=$(grep "Slave Interface:" /proc/net/bonding/bond0 | awk '{print $3}')

if [[ -z "$SLAVE_INTERFACES" ]]; then
    error_exit "未找到 bond0 的从属物理网卡。"
fi

PRIMARY_DEVICE=$(cat /sys/class/net/bond0/bonding/primary)
echo "发现以下从属物理网卡: $SLAVE_INTERFACES"

# 数组用于存储所有 VF 接口名称
declare -a VF_INTERFACES=()

# 遍历每个从属物理网卡
for IFACE in $SLAVE_INTERFACES; do
    echo "配置网卡: $IFACE"

    # 检查网卡是否存在
    if ! ip link show "$IFACE" &> /dev/null; then
        echo "警告: 网卡 $IFACE 不存在，跳过。"
        continue
    fi

    # 设置 RX 和 TX 队列数为 4096
    echo "设置网卡 $IFACE 的 RX 和 TX 队列数为 4096..."
    ethtool -G "$IFACE" rx 4096 tx 4096
    if [[ $? -ne 0 ]]; then
        echo "错误: 无法设置网卡 $IFACE 的 RX/TX 队列数。请检查网卡是否支持此操作。"
        #continue
    fi

    if [[ "$BOND_MODE" != "6" ]] && [[ "$BOND_MODE" != "1" ]];then
        echo "只有Bond 1|6 模式下才能启动sr-iov"
        continue
    fi

    if [[ "$BOND_SKIP_PRIMARY_DEVICE" == "True" ]] && [[ "$PRIMARY_DEVICE" == "$IFACE" ]] ;then
        echo "跳过主网卡设备 $IFACE"
        continue
    fi

    # 获取当前 SR-IOV 配置路径
    SRIOV_NUMVFS_PATH="/sys/class/net/$IFACE/device/sriov_numvfs"
    SRIOV_TOTALVFS_PATH="/sys/class/net/$IFACE/device/sriov_totalvfs"

    # 检查 SR-IOV 是否支持
    if [[ ! -w "$SRIOV_NUMVFS_PATH" ]]; then
        echo "警告: 无法访问 $SRIOV_NUMVFS_PATH，可能不支持 SR-IOV，跳过 VF 创建。"
        continue
    fi

    # 获取当前启用的 VF 数量
    CURRENT_VFS=$(cat "$SRIOV_NUMVFS_PATH" 2>/dev/null)
    TOTAL_VFS=$(cat "$SRIOV_TOTALVFS_PATH" 2>/dev/null)


    # 检查网卡支持的最大 VF 数量
    if [[ "$SRIOV_NUMVFS_COUNT" -gt "$TOTAL_VFS" ]]; then
        echo "警告: 网卡 $IFACE 仅支持最多 $TOTAL_VFS 个 VF，无法创建 $SRIOV_NUMVFS_COUNT 个 VF。"
        SRIOV_NUMVFS_COUNT="$TOTAL_VFS"
    fi

    # 配置 SR-IOV 并创建 VF
    echo "为网卡 $IFACE 创建 $SRIOV_NUMVFS_COUNT 个 VF..."
    echo "$SRIOV_NUMVFS_COUNT" > "$SRIOV_NUMVFS_PATH"
    if [[ $? -ne 0 ]]; then
        echo "错误: 无法为网卡 $IFACE 创建 VF。"
        continue
    fi

    # 验证 VF 是否创建成功
    NEW_VFS=$(cat "$SRIOV_NUMVFS_PATH" 2>/dev/null)
    if [[ "$NEW_VFS" -eq "$SRIOV_NUMVFS_COUNT" ]]; then
        echo "成功: 网卡 $IFACE 已配置 $SRIOV_NUMVFS_COUNT 个 VF。"
    else
        echo "警告: 网卡 $IFACE 的 VF 数量为 $NEW_VFS，未达到预期的 $SRIOV_NUMVFS_COUNT 个。"
    fi

    # 识别并存储 VF 接口名称
    # 方法：
    # 1. 通过 virtfn* 目录获取 VF 的 PCI 地址
    # 2. 通过 lspci 获取对应的网络接口名称
    sleep 2
    for VF_NUM in $(seq 0 $((SRIOV_NUMVFS_COUNT - 1))); do

        if [ ${VF_PORT_SPEED} -gt 0 ];then
            # 设置 VF 接口的最大传输速率为 1000 Mbps
            #echo "设置 VF 接口 $VF_IFACE 的最大传输速率为 ${VF_PORT_SPEED} Mbps..."
            ip link set "$IFACE" vf "$VF_NUM" max_tx_rate ${VF_PORT_SPEED}
            if [[ $? -eq 0 ]]; then
               echo "成功: 为 ${IFACE}v${VF_NUM}  接口 $VF_IFACE 设置了最大传输速率 ${VF_PORT_SPEED} Mbps。"
            else
               echo "警告: 无法为 VF 接口 $VF_IFACE 设置最大传输速率。请检查驱动是否支持该操作。"
            fi
        fi
    done
done

echo "所有配置已完成。"

exit 0

