#!/bin/bash

# 清理指定网卡的ingress规则
clean_ingress() {
    local dev=$1
    echo "清理 $dev 的 ingress 规则..."
    tc qdisc del dev $dev ingress 2>/dev/null
    echo "清理完成"
}

# 设置 IFB 模块的函数
setup_ifb() {
    local num=$1
    
    # 先卸载已存在的 IFB 模块
    rmmod ifb 2>/dev/null
    
    # 加载 IFB 模块并指定接口数量
    modprobe ifb numifbs=$num
    
    # 启用所有 IFB 接口并清理现有规则
    for i in $(seq 0 $(echo "$num - 1" | bc)); do
        ip link set dev ifb$i up
        tc qdisc del dev ifb$i root 2>/dev/null
    done
}

# 计算quantum值的函数
calculate_quantum() {
    local rate=$1  # 速率（Mbit/s）
    local mtu=1500
    # 基础quantum为MTU的10倍
    local base_quantum=$(echo "$mtu * 10" | bc)
    
    # 根据速率调整quantum
    # 对于更高的速率，增加quantum值以提高性能
    if [ $(echo "$rate <= 100" | bc) -eq 1 ]; then
        echo $base_quantum
    elif [ $(echo "$rate <= 1000" | bc) -eq 1 ]; then
        echo $(echo "$base_quantum * 2" | bc)
    else
        echo $(echo "$base_quantum * 4" | bc)
    fi
}

# 设置流量控制规则的函数
setup_tc() {
    local dev=$1
    local num_ifb=$2
    local speed=$3
    local adjspeed=$4
    local speed_per_ifb=$(echo "scale=2; $adjspeed/$num_ifb" | bc)
    
    POWER=1
    while [ $(echo "$POWER < $num_ifb" | bc) -eq 1 ]; do
        POWER=$(echo "$POWER * 2" | bc)
    done
    MASK=$(echo "$POWER - 1" | bc)
    MASK_HEX=$(printf "0x%02x" $MASK)
    
    # 计算 burst 和 cburst 值 (基于100ms)
    # burst = rate / 8 (转换为字节) * 0.1 (100ms)
    local burst_bytes=$(echo "scale=0; $speed_per_ifb * 1024 * 1024 / 8 / 10" | bc)
    local cburst_bytes=$(echo "scale=0; $speed_per_ifb * 1024 * 1024 / 8 / 10" | bc)
    
    # 计算 quantum
    local r2q=10
    local rate_bytes_per_sec=$(echo "scale=0; $speed_per_ifb * 1024 * 1024 / 8" | bc)
    local quantum=$(echo "scale=0; $rate_bytes_per_sec / $r2q" | bc)
    
    # 确保 quantum 至少为 1500 (MTU)，最多为 30000
    if [ $(echo "$quantum < 1500" | bc) -eq 1 ]; then
        quantum=1500
    elif [ $(echo "$quantum > 30000" | bc) -eq 1 ]; then
        quantum=30000
    fi
    
    echo "IFB设置参数："
    echo "速率: ${speed_per_ifb}Mbit"
    echo "quantum: ${quantum}"
    echo "burst: ${burst_bytes} bytes"
    echo "cburst: ${cburst_bytes} bytes"
    echo "MASK_HEX: ${MASK_HEX}"
    
    # 删除现有的入口排队规则
    tc qdisc del dev $dev ingress 2>/dev/null
    
    # 删除IFB设备上现有的根排队规则并设置新的规则
    for i in $(seq 0 $(echo "$num_ifb - 1" | bc)); do
        # 清除现有规则
        tc qdisc del dev ifb$i root 2>/dev/null
        
        # 设置HTB作为根队列规则
        tc qdisc add dev ifb$i root handle 1: htb default 10 r2q $r2q
        
        # 添加根类
        tc class add dev ifb$i parent 1: classid 1:1 htb \
            rate ${speed_per_ifb}mbit \
            ceil ${speed}mbit \
            burst ${burst_bytes}b \
            cburst ${cburst_bytes}b \
            mtu 1500 \
            quantum $quantum
        
        # 添加叶子类
        tc class add dev ifb$i parent 1:1 classid 1:10 htb \
            rate ${speed_per_ifb}mbit \
            ceil ${speed}mbit \
            burst ${burst_bytes}b \
            cburst ${cburst_bytes}b \
            mtu 1500 \
            quantum $quantum
        
        # 为叶子类添加公平队列
        tc qdisc add dev ifb$i parent 1:10 handle 20: fq_codel \
            limit 10240 \
            flows 1024 \
            quantum 1514 \
            target 5ms \
            interval 100ms \
            memory_limit 32Mb \
            ecn
    done
    
    # 添加入口队列规则
    tc qdisc add dev $dev handle ffff: ingress
    
    # 为每个IFB添加过滤规则
    for i in $(seq 0 $(echo "$num_ifb - 1" | bc)); do
        tc filter add dev $dev parent ffff: protocol ip prio 1 \
            u32 match ip src 0.0.0.0/0 \
            match u8 $(printf "0x%02x" $i) $MASK_HEX at 5 \
            action mirred egress redirect dev ifb$i
    done

    #sleep 5
    #tc qdisc del dev $dev ingress 2>/dev/null
}

# 主脚本开始

# 获取并显示可用的网络接口
echo "可用的网络接口:"
echo "-------------------"
# 修改后的网络接口显示方式
ip -o link show | grep -v ifb | grep -v lo | while read -r line; do
    if_name=$(echo "$line" | awk -F': ' '{print $2}' | cut -d@ -f1)
    if_state=$(echo "$line" | grep -o "state [A-Z]* " | cut -d' ' -f2)
    echo "$if_name  [$if_state]"
done
echo "-------------------"

echo "请输入要应用流量控制的网络接口名称:"
read interface

if ! ip link show "$interface" >/dev/null 2>&1; then
    echo "无效的接口名称"
    exit 1
fi

# 清理选定网卡的ingress规则
clean_ingress "$interface"

echo "请输入需要的IFB接口数量(1-32):"
read num_ifb

if ! [[ "$num_ifb" =~ ^[0-9]+$ ]] || [ $(echo "$num_ifb < 1" | bc) -eq 1 ] || [ $(echo "$num_ifb > 32" | bc) -eq 1 ]; then
    echo "无效的数字,请输入1到32之间的数字。"
    exit 1
fi

# 设置IFB接口
setup_ifb $num_ifb

echo "请输入下载速度限制(单位:Mbit,例如输入100表示100Mbit):"
read speed

if ! [[ "$speed" =~ ^[0-9]+$ ]] || [ $(echo "$speed < 1" | bc) -eq 1 ]; then
    echo "无效的速度值"
    exit 1
fi
adjspeed=$(echo "$speed * 1.06809079" | bc)
# 设置流量控制规则
setup_tc "$interface" $num_ifb $speed $adjspeed

echo "流量控制设置完成!"
echo "下载速度限制: ${speed}Mbit"
echo "每个IFB的速度: $(echo "scale=2; $adjspeed/$num_ifb" | bc)Mbit"