#!/bin/bash
# --------------------------------------------------
# @author yangxiao
# @date 2018-06-20 创建脚本，默认所有网卡做聚合
# @date 2018-06-21 修改脚本，新增网卡选择，针对选择网卡做聚合
# @date 2018-06-22 修改脚本，新增配置网卡开机自启动
# --------------------------------------------------
# @update by yanghong8
# @date 2018-09-07 在原功能上就进行优化
# --------------------------------------------------
# @update by x01279
# @date 2021-07-13 调整脚本，更适合UNV设备的聚合模式
# --------------------------------------------------
# @update by x01279
# @date 2022-01-17 调整脚本，兼容UNV超融合设备的聚合模式
# --------------------------------------------------
# @update by l09036
# @date 2023-11-27 调整脚本，兼容欧拉操作系统

OLD_LANG=`echo $LANG`
export LANG=zh_CN.utf8

checkip()
{
	inputorigin="$1"
	strLen=$(expr length $inputorigin)
	#判断输入IP是否是环回地址#
	if [ "$inputorigin" = "127.0.0.1" ]
	then
		echo "IP address can not be loopback IP address"
		return 1
	elif [ "$strLen" -gt "15" ] || [ "$strLen" -lt "7" ]    #判断IP地址的位数是否非法#
	then
		echo "Wrong ip address,the length of ip address should be less than 15 and more than 7"
		return 1
	fi
	#判断IP地址是否包含非法字符#
	teststring=${inputorigin#*[!0-9.]}
	if [ "$inputorigin" != "$teststring" ]
	then
		echo "IP address can only contain 0-9 and dot."
		return 1
	fi

	for i in 0 1 2 3
	do
		if [ $i = 0 ]                    #判断第一个数字段是否非法#
		then
			ipval=${inputorigin%%.*}
			if [ -z "$ipval" ]
			then
				echo "ip0val:$ipval "
				return 1
			fi
			iptmp0=${inputorigin#*.}
			if [ "$iptmp0" = "$inputorigin" ]
			then
				echo "$ipval error"
				return 1
			fi
			if [ "$ipval" -le "0" ]       #判断第一个数字段是否小于等于0#
			then
				echo "ip0 is smaller than 0 ,$ipval error"
				return 1
			elif [ "$ipval" -eq "127" ]    #判断第一个数字段是否等于127#
			then
				echo "ip0 equals to 127 ,$ipval error"
				return 1
			elif [ "$ipval" -gt "223" ]    #判断第一个数字段是否大于223#
			then
				echo "ip0 is greater than 223 ,$ipval error"
				return 1
			elif [ `echo $ipval | grep ^0` ]
			then
				echo "ip0 ,$ipval error"
				return 1
			fi
		elif [ $i = 1 ]                    #判断第二个数字段是否非法#
		then
			ipval=${iptmp0%%.*}
			if [ -z "$ipval" ]
			then
				echo "ip1val:$ipval is null"
				return 1
			fi
			iptmp1=${iptmp0#*.}
			if [ "$iptmp1" = "$iptmp0" ]
			then
				echo "$ipval error"
				return 1
			fi
			if [ "$ipval" -lt "0" ]         #判断第二个数字段是否小于0#
			then
				echo "ip1 is smaller than 0 ,$ipval error"
				return 1
			elif [ "$ipval" -gt "255" ]      #判断第二个数字段是否大于255#
			then
				echo "ip1 is greater than 255 ,$ipval error"
				return 1
			elif [ `echo $ipval | grep ^0` ] && [ $(expr length $ipval) -gt 1 ]
			then
				echo "ip1  ,$ipval error"
				return 1
			fi
		elif [ $i = 2 ]                       #判断第三个数字段是否非法#
		then
			ipval=${iptmp1%%.*}
			if [ -z "$ipval" ]
			then
				echo "ip2val:$ipval is null"
				return 1
			fi
			iptmp2=${iptmp1#*.}
			if [ "$iptmp2" = "$iptmp1" ]
			then
				echo "$ipval error"
				return 1
			fi
			if [ "$ipval" -lt "0" ]           #判断第三个数字段是否小于0#
			then
				echo "ip2 is smaller than 0 ,$ipval error"
				return 1
			elif [ "$ipval" -gt "255" ]       #判断第三个数字段是否大于255#
			then
				echo "ip2 is greater than 255 ,$ipval error"
				return 1
			elif [ `echo $ipval | grep ^0` ] && [ $(expr length $ipval) -gt 1 ]
			then
				echo "ip2  $ipval error"
				return 1
			fi
		elif [ $i = 3 ]                        #判断第四个数字段是否非法#
		then
			ipval=${iptmp2%%.*}
			if [ -z "$ipval" ]
			then
				echo "ip3val:$ipval is null"
				return 1
			fi
			if [ `echo $iptmp2 | grep [.]` ]    #判断第四个数字段后面是否还有.#
			then
				echo "wrongwrongwrong$inputorigin "
				return 1
			fi
			if [ "$ipval" -lt "0" ]            #判断第四个数字段是否小于0#
			then
				echo "ip3 is smaller than 0 ,$ipval error"
				return 1
			elif [ "$ipval" -gt "255" ]        #判断第四个数字段是否大于255#
			then
				echo "ip3 is great than 255 ,$ipval error"
				return 1
			elif [ `echo $ipval | grep ^0` ] && [ $(expr length $ipval) -gt 1 ]
			then
				echo "ip3  ,$ipval error"
				return 1
			fi
		fi
	done
	return 0
}

bondcentos(){
    echo "欢迎使用网卡绑定脚本"
    echo "该脚本需在root用户下完成,开始效验用户"

    user=`whoami`
    if [ "${user}" != "root" ];then
        echo "请在root用户下执行本脚本！" &&  echo "参考命令：su - root" && exit 0
    else
        echo "当前执行用户校验正确！"
    fi

    net_pwd=/etc/sysconfig/network-scripts

    BAK=$net_pwd/bak
    if [ -d $BAK ] ;then
        rm -rf $BAK/*
    else
        mkdir $BAK
    fi

    echo "您将需要输入以下信息完成配置"
    echo "----------------------------------------------------"
    echo "1-新创建的聚合网卡绑定名称，建议为bond0（数字0）"
    echo "2-网卡绑定模式,XOR方式聚合设为2,主备模式设为1,静态负载均衡设为0"
    echo "3-服务器IP地址,"
    echo "4-服务器子网掩码,"
    echo "5-服务器子网掩码位数,如255.255.255.0,与PREFIX=24表示意思相同"
    echo "6-服务器网关,"
    echo "7-需要绑定的实际网卡名称"
    echo "----------------------------------------------------"
    while true
    do
        read -p "1-新创建网卡绑定名称:" deviceName
        echo "您已经配置绑定名称为: $deviceName"
        echo "2-请选择网卡绑定模式: 0 | 1 | 2 | 3 | 4 | 5 | 6 :"
        read -n 1 -p "(Default: type 2): " BondType
        echo
        case $BondType in
        0)
        echo "您已经选择绑定模式为0 balance-rr."
        BondType=balance-rr
        break;;
        1)
        echo "您已经选择绑定模式为1 active-backup."
        BondType=active-backup
        break;;
        2)
        echo "您已经选择绑定模式为2 balance-xor."
        BondType=balance-xor
        break;;
        3)
        echo "您已经选择绑定模式为3 broadcast."
        BondType=broadcast
        break;;
        4)
        echo "您已经选择绑定模式为4 802.3ad."
        BondType=802.3ad
        break;;
        5)
        echo "您已经选择绑定模式为5 balance-tlb."
        BondType=balance-tlb
        break;;
        6)
        echo "您已经选择绑定模式为6 balance-alb."
        BondType=balance-alb
        break;;
        *)
        echo "您已经选择绑定模式为2 balance-xor"
        BondType=balance-xor
        break;;
        esac
    done

    read -p "3-服务器IP地址:" Ipaddr
    echo "您已经输入设备IP为 : $Ipaddr"

    read -p "4-服务器子网掩码:" Netmask
    echo "您已经输入设备子网掩码为: $Netmask"

    read -p "5-服务器子网掩码位数:" Prefix
    echo "您已经输入设备子网掩码为: $Prefix"

    read -p "6-服务器网关:" Gateway
    echo "您已经输入设备网关为: $Gateway"

    if [ -f ${net_pwd}/ifcfg-$deviceName  ];then
        mv ${net_pwd}/ifcfg-$deviceName $BAK
    fi

    touch ifcfg-$deviceName

    echo "DEVICE=$deviceName" >>ifcfg-$deviceName
    echo "NAME=$deviceName"  >>ifcfg-$deviceName
    echo "BONDING_OPTS=\"miimon=100 updelay=0 xmit_hash_policy=1 downdelay=0 mode=$BondType\"" >>ifcfg-$deviceName
    echo "TYPE=Bond"  >>ifcfg-$deviceName
    echo "BONDING_MASTER=yes"  >>ifcfg-$deviceName
    echo "BOOTPROTO=none"  >>ifcfg-$deviceName
    echo "USERCTL=no"  >>ifcfg-$deviceName
    echo "NM_CONTROLLED=no"  >>ifcfg-$deviceName
    echo "IPADDR=$Ipaddr"  >>ifcfg-$deviceName
    echo "NETMASK=$Netmask"  >>ifcfg-$deviceName
    echo "GATEWAY=$Gateway"  >>ifcfg-$deviceName
    echo "DEFROUTE=yes" >>ifcfg-$deviceName
    echo "ONBOOT=yes"  >>ifcfg-$deviceName

    mv ifcfg-$deviceName  ${net_pwd}/

    ADAPTER_NAME_ALL=`ip a|grep -E "en|em" |grep -v lo|awk -F ":" '{print $2}'|awk '{sub("^ *","");sub(" *$","");print}'`
    echo -e "以下是系统识别到的所有网卡:\n\n$ADAPTER_NAME_ALL"

    echo "7-请输入需要绑定的网卡名称,多个网卡之间用英文空格隔开,不需要输入静静等候"
    read -p "网卡名称:" ethname

    for i in `echo $ethname`
    do
        cd ${net_pwd}
        echo "写入以下配置信息到对应网卡中ifcfg-$i"
        echo "--------------------------------------------"

        mv ${net_pwd}/ifcfg-$i $BAK
        echo "DEVICE=$i" |tee -a ifcfg-$i
        echo "BOOTPROTO=none" |tee -a ifcfg-$i
        echo "MASTER=$deviceName" |tee -a ifcfg-$i
        echo "SLAVE=yes" |tee -a ifcfg-$i
        echo "NM_CONTROLLED=no" |tee -a ifcfg-$i
        echo "USERCTL=no" |tee -a ifcfg-$i
        echo "ONBOOT=yes" |tee -a ifcfg-$i
        echo "--------------------------------------------"
    done

    systemctl stop NetworkManager
    systemctl disable NetworkManager 2>&1 >/dev/null

    systemctl restart network
}

yesnoinput()
{
    while :
    do
        read ANSWER
        case $ANSWER in
        "y"|"Y"|"yes"|"YES")
            return 0
            ;;
        "n"|"N"|"no"|"NO")
            return 1
            ;;
        *)
            echo "Unknown input."
            ;;
        esac
        printf "Please input [yes..no]:"
    done
}

checkbond(){
    if [ ! -z "`nmcli c | grep bond`" ];then
        echo "当前服务器已创建网口聚合，请选择是否删除重建创建[yes/no]:"
        yesnoinput
        if [ "$?" -eq 0 ];then
			echo "正在删除聚合网口"
            for i in `nmcli c | grep bond | awk '{print $1}'`
            do
                nmcli connection delete ${i}
            done
            if [ -z "`nmcli c | grep bond`" ];then
                echo "聚合网口删除成功！"
            else
                echo "聚合网口删除失败！"
                exit 1
            fi
		else
			echo "程序退出"
			exit 0
		fi
    fi
}

bondopenEuler(){
    echo "欢迎使用网卡绑定脚本"
    echo "该脚本需在root用户下完成,开始效验用户"

    user=`whoami`
    if [ "${user}" != "root" ];then
        echo "请在root用户下执行本脚本！" &&  echo "参考命令：su - root" && exit 0
    else
        echo "当前执行用户校验正确！"
    fi

    # 判断当前是否已创建网口聚合
    checkbond

    # 此脚本不支持存储设备网口聚合，使用存储控制台设置网口聚合
    if [ -f /proc/product/main_board ];then
        echo "此设备为存储设备，请登录存储控制台设置网口聚合！"
        echo "存储控制台：存储设备默认80端口，超融合（VMP-E600）设备8078端口"
        exit 0
    fi

    echo "您将需要输入以下信息完成配置"
    echo "----------------------------------------------------"
    echo "1-新创建的聚合网卡绑定名称，建议为bond0（数字0）"
    echo "2-网卡绑定模式,XOR方式聚合设为2,主备模式设为1,静态负载均衡设为0"
    echo "3-服务器IP地址,"
    echo "4-服务器子网掩码位数,如255.255.255.0,与PREFIX=24表示意思相同"
    echo "5-服务器网关,"
    echo "6-需要绑定的实际网卡名称"
    echo "----------------------------------------------------"
    while true
    do
        read -p "1-新创建网卡绑定名称:" deviceName
        echo "您已经配置绑定名称为: ${deviceName}"
        echo "2-请选择网卡绑定模式: 0 | 1 | 2 | 3 | 4 | 5 | 6 :"
        read -n 1 -p "(Default: type 2): " BondType
        echo
        case ${BondType} in
        0)
        echo "您已经选择绑定模式为0 balance-rr."
        BondType=balance-rr
        break;;
        1)
        echo "您已经选择绑定模式为1 active-backup."
        BondType=active-backup
        break;;
        2)
        echo "您已经选择绑定模式为2 balance-xor."
        BondType=balance-xor
        break;;
        3)
        echo "您已经选择绑定模式为3 broadcast."
        BondType=broadcast
        break;;
        4)
        echo "您已经选择绑定模式为4 802.3ad."
        BondType=802.3ad
        break;;
        5)
        echo "您已经选择绑定模式为5 balance-tlb."
        BondType=balance-tlb
        break;;
        6)
        echo "您已经选择绑定模式为6 balance-alb."
        BondType=balance-alb
        break;;
        *)
        echo "您已经选择绑定模式为2 balance-xor"
        BondType=balance-xor
        break;;
        esac
    done

    while true
    do
        read -p "3-服务器IP地址:" Ipaddr
        checkip ${Ipaddr}
        case "$?" in
        "0")
            echo "您已经输入设备IP为: ${Ipaddr}"
            break;;
        "1")
            echo "您输入的IP存在问题，需要重新输入："
        ;;
        esac
    done

    while true
    do
        read -p "4-服务器子网掩码位数:" Prefix
        testPrefix=${Prefix#*[!0-9]}
        if [ "${testPrefix}" != "${Prefix}" ];then
            echo "您输入的子网掩码位数存在问题，需要重新输入："
        else
            if [ "$Prefix" -ge "0" ] && [ "$Prefix" -le "32" ];then
                echo "您已经输入设备子网掩码位数为: ${Prefix}"
                break
            else
                echo "您输入的子网掩码范围存在问题，需要重新输入："
            fi
        fi
    done

    while true
    do
        read -p "5-服务器网关:" Gateway
        checkip ${Gateway}
        case "$?" in
        "0")
            echo "您已经输入设备网关为: ${Gateway}"
            break;;
        "1")
            echo "您输入的IP存在问题，需要重新输入："
        ;;
        esac
    done

    ADAPTER_NAME_ALL=`ip a|grep -E "en|em" |grep -v lo|awk -F ":" '{print $2}'|awk '{sub("^ *","");sub(" *$","");print}'`
    echo -e "以下是系统识别到的所有网卡:\n\n$ADAPTER_NAME_ALL"

    echo "6-请输入需要绑定的网卡名称,多个网卡之间用英文空格隔开"
    read -p "网卡名称:" ethname

    # 创建网口聚合命令
    nmcli con add type bond ifname ${deviceName} con-name ${deviceName} mode ${BondType}
    for i in `echo ${ethname}`
    do
        nmcli con add type bond-slave ifname ${i} master ${deviceName}
    done
    nmcli con modify ${deviceName} ipv4.address ${Ipaddr}/${Prefix} ipv4.gateway ${Gateway} ipv4.method manual ipv6.method ignore
    nmcli con up ${deviceName}
}

################################ main ###############################
# 判断操作系统类型
if [ -f /etc/openEuler-release ];then
    bondopenEuler
elif [ -f /etc/redhat-release ];then
    bondcentos
else
    echo "[Warn] System type not supported."
fi
export LANG=$OLD_LANG