#!/bin/bash

# 定义颜色变量
RED='\E[1;31m'        # 红
GREEN='\E[1;32m'      # 绿
YELLOW='\E[1;33m'     # 黄
BLUE='\E[1;34m'       # 蓝
PINK='\E[1;35m'       # 粉红
SHANGREEN='\E[32;5m'  # 绿色闪烁警示
SHANBLUE='\E[34;5m'   # 蓝闪烁警示
RES='\E[0m'           # 清除颜色

#网络聚合,脚本快速引导

check_ip() {
     local  IP=$1
     # 改进IP格式检查，确保每个八位字节都在0-255之间
     if  echo  "$IP" | grep  -E  "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"  > /dev/null ;  then
         local octet1=$(echo "$IP" | awk -F. '{print $1}')
         local octet2=$(echo "$IP" | awk -F. '{print $2}')
         local octet3=$(echo "$IP" | awk -F. '{print $3}')
         local octet4=$(echo "$IP" | awk -F. '{print $4}')

         if (( octet1 >= 0 && octet1 <= 255 )) && \
            (( octet2 >= 0 && octet2 <= 255 )) && \
            (( octet3 >= 0 && octet3 <= 255 )) && \
            (( octet4 >= 0 && octet4 <= 255 )); then
             echo  "IP $IP  ok!"
             return  0
         else
             echo  "IP $IP not available (octet out of range)!"
             return  1
         fi
     else
         echo  "IP 格式错误!"
         return  1
     fi
}

# 把数字转换为8位二进制数字，不足前补0
D2B_PADDED()
{
	local num="$1"
	local d2b=$(echo "obase=2;$num" | bc)
	printf "%08d" "$d2b" # 不加换行符，方便拼接
}

# 验证掩码的正确性 (兼容CIDR和点分十进制)
check_mask_format()
{	
	local mask_input="$1"

    # 1. 检查是否是CIDR前缀 (0-32之间的数字)
    if [[ "$mask_input" =~ ^([0-9]|[12][0-9]|3[0-2])$ ]]; then
        # 确保是有效的数字范围
        if (( mask_input >= 0 && mask_input <= 32 )); then
            return 0 # 有效的CIDR前缀
        fi
    fi

    # 2. 如果不是CIDR，检查是否是点分十进制格式
	echo "$mask_input" | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" > /dev/null  
	if [ $? -ne 0 ]; then # 如果不是点分十进制格式
		return 1 # 无效格式
	fi
	
	# 3. 如果是点分十进制，检查八位字节值范围和连续的1/0模式
	local octet1=$(echo "$mask_input" | awk -F. '{print $1}')
	local octet2=$(echo "$mask_input" | awk -F. '{print $2}')
	local octet3=$(echo "$mask_input" | awk -F. '{print $3}')
	local octet4=$(echo "$mask_input" | awk -F. '{print $4}')

    # 检查每个八位字节是否在0到255之间
    if ! (( octet1 >= 0 && octet1 <= 255 )) || \
       ! (( octet2 >= 0 && octet2 <= 255 )) || \
       ! (( octet3 >= 0 && octet3 <= 255 )) || \
       ! (( octet4 >= 0 && octet4 <= 255 )); then
        return 2 # 八位字节超出范围
    fi
	
	local bin_mask=""
	bin_mask+=$(D2B_PADDED "$octet1")
	bin_mask+=$(D2B_PADDED "$octet2")
	bin_mask+=$(D2B_PADDED "$octet3")
	bin_mask+=$(D2B_PADDED "$octet4")
	
	# 检查是否是连续的1后面跟着连续的0 (标准子网掩码特征)
	if [[ "$bin_mask" =~ ^1*0*$ ]]; then
		return 0 # 有效的点分十进制掩码
	else
		return 3 # 无效的掩码模式 (例如: 255.255.255.1)
	fi
}

# 掩码转换 (统一转换为CIDR前缀长度)
mask2cdr ()
{
    local mask_input="$1"
    local masknum=0

    # 1. 如果输入已经是CIDR前缀 (0-32之间的数字)
    if [[ "$mask_input" =~ ^([0-9]|[12][0-9]|3[0-2])$ ]]; then
        echo "$mask_input" # 直接输出该数字
        return 0
    fi

    # 2. 如果是点分十进制，转换为32位二进制并计算前导1的个数
    local octet1=$(echo "$mask_input" | awk -F. '{print $1}')
    local octet2=$(echo "$mask_input" | awk -F. '{print $2}')
    local octet3=$(echo "$mask_input" | awk -F. '{print $3}')
    local octet4=$(echo "$mask_input" | awk -F. '{print $4}')

    local bin_mask=""
    bin_mask+=$(D2B_PADDED "$octet1")
    bin_mask+=$(D2B_PADDED "$octet2")
    bin_mask+=$(D2B_PADDED "$octet3")
    bin_mask+=$(D2B_PADDED "$octet4")
    
    # 计算前导'1'的个数
    masknum=$(echo "$bin_mask" | grep -o "1" | wc -l)
    
    echo "$masknum" # 输出计算出的CIDR前缀长度
    return 0
}

# 删除之前bond
echo -e "${GREEN}删除之前的bond0和slave配置文件${RES}"

nmcli connection delete bond01 &>/dev/null
nmcli connection delete bond0 &>/dev/null

array=(`nmcli -f DEVICE device | grep -v DEVICE|grep -v virbr0 |grep -v lo |grep -v bond`)

NUM=${#array[@]}
NUM=`expr $NUM - 1`
 
for i in $(seq 0 $NUM)
do
    temp=${array[$i]}
    nmcli connection delete bond0-slave-$temp &>/dev/null
done

nmcli connection show

#设置bond0接口
echo -e "${GREEN}设置bond0接口,模式0${RES}"
nmcli connection add type bond con-name bond01 ifname bond0 mode 0
#设置bond0的IP
echo -e "${GREEN}设置bond0的IP${RES}"
printf "输入聚合网口bond0的第一个ip:\n"

while  true ;  do
     read  -p  "输入ip: "  bondIP
     check_ip "$bondIP"
     [ $? -eq  0 ] &&  break
done

while  true ;  do
     read  -p  "输入子网掩码 (例如: 255.255.255.0 或 24): "  bondmask
     check_mask_format "$bondmask"
     if [ $? -eq 0 ]; then
         break
     else
         echo -e "${RED}子网掩码格式或值不正确，请重新输入。${RES}"
     fi
done

# 捕获mask2cdr的输出作为CIDR前缀
mask_prefix=$(mask2cdr "$bondmask")
ipandmask="$bondIP/$mask_prefix"
echo "设置的IP地址和掩码为: $ipandmask"
nmcli connection modify bond01 ipv4.addresses "$ipandmask"



while :
do
	printf "是否设置其他IP,是输入y,否n:"
	read otherIP
	if [ "y" = "$otherIP" ]; then
    	printf "输入聚合网口bond0的其他ip:\n"
		while  true ;  do
		     read  -p  "输入ip: "  bondIP
		     check_ip "$bondIP"
		     [ $? -eq  0 ] &&  break
		done

		while  true ;  do
		     read  -p  "输入子网掩码 (例如: 255.255.255.0 或 24): "  bondmask
		     check_mask_format "$bondmask"
		     if [ $? -eq 0 ]; then
                 break
             else
                 echo -e "${RED}子网掩码格式或值不正确，请重新输入。${RES}"
             fi
		done

		# 捕获mask2cdr的输出作为CIDR前缀
		mask_prefix=$(mask2cdr "$bondmask")
		ipandmask="$bondIP/$mask_prefix"
		echo "添加的IP地址和掩码为: $ipandmask"
		nmcli connection modify bond01 +ipv4.addresses "$ipandmask"

    elif [ "n" = "$otherIP" ]; then
        break
	else
        echo -e "${YELLOW}输入错误，请输入 'y' 或 'n'。${RES}"
    fi

done

#设置IP 为手动模式
nmcli connection modify bond01 ipv4.method manual
#关闭ipv6
nmcli connection modify bond01 ipv6.method "disabled"



#将需要聚合的接口加入bond0
echo -e "${GREEN}将聚合的接口加入bond0${RES}"
printf "当前外网接口为:\n"
route -n | grep UG | awk '{print $8}'
echo "当前所有网络接口:"

array=(`nmcli -f DEVICE device | grep -v DEVICE|grep -v virbr0 |grep -v lo |grep -v bond`)

NUM=${#array[@]}
NUM=`expr $NUM - 1`
 
for i in $(seq 0 $NUM)
do
    temp=${array[$i]}
    echo "$i:$temp"
done

while :
do
    printf "输入需要加入的一个接口序号,选择完毕输入n:"
     
    read devicenum
    if [ "n" = "$devicenum" ]; then
        break
    fi 

    # 检查输入是否为数字
    if ! [[ "$devicenum" =~ ^[0-9]+$ ]]; then
        echo -e "${RED}输入错误，请输入数字序号或 'n'。${RES}"
        continue
    fi

    if [ "$devicenum" -gt "$NUM" ]; then
	  echo -e "${RED}序号错误,重新输入${RES}"
        continue
    fi

    device=${array[$devicenum]}
    echo "将接口 $device 加入 bond0-slave-$device"

	# 获取 UUID
	uuid=$(nmcli -t -f DEVICE,UUID c show | grep "^$device:" | cut -d':' -f2)
  
	# 检查 UUID 是否存在并断开
	if [ -n "$uuid" ]; then
		echo "正在断开 $device (UUID: $uuid)..."
		nmcli c down "$uuid" &>/dev/null
		nmcli connection modify "$uuid" connection.autoconnect no &>/dev/null
		else
		echo "未找到 $device 的连接。"
	fi
    
    nmcli connection add type bond-slave con-name bond0-slave-$device ifname "$device" master bond01
        
done

#nmcli connection add type bond-slave con-name bond0-slave1 ifname enp2s0f0 master bond01
#nmcli connection add type bond-slave con-name bond0-slave2 ifname enp2s0f1 master bond01
#启用bond0聚合接口
echo -e "${GREEN}启用bond0聚合接口${RES}"
nmcli connection up bond01
echo -e "${GREEN}bond0接口信息${RES}"
nmcli connection show
sleep 3
ip addr show bond0
echo -e "${GREEN}bond0接口速度${RES}"
sleep 5
ethtool bond0 |grep Speed
exit
