在飞牛中对上行带宽进行端口限速

前段时间对网卡做了上行限制,导致本地打开飞牛后台也很慢。因为在系统中部署了PCDN,所以需要有针对性的将PCDN上行按时段限制,同时不影响其它进程。

于是先按进程名程建立上行限速规则,但过于复杂,效果并不好。遂决定按端口限速,即将所有端口限速但排除常用的端口,比如飞牛的5666、ssh的22端口。

先新建脚本nano /usr/local/bin/fn_speedlimit.sh

#!/bin/bash

# ============================================
# 飞牛 (fnOS) 上行带宽限速脚本
# 用法:./fn_speedlimit.sh {start|stop|status|restart}
# ============================================

# ===== 用户配置区域 =====
INTERFACE="eth0"            # 修改为你的网卡名,用 ip link show 查看
LIMIT_RATE="10mbit"         # 限速值,如 5mbit / 10mbit / 100mbit
EXCLUDE_PORTS="22,443,8080" # 排除的端口,逗号分隔,无则留空 ""
# =========================

IPMARK="100"
TC_CLSID="1:${IPMARK}"

start_limit() {
    echo "正在为网卡 $INTERFACE 设置上行限速: $LIMIT_RATE ..."
    tc qdisc del dev $INTERFACE root 2>/dev/null
    tc qdisc add dev $INTERFACE root handle 1: htb default 20
    tc class add dev $INTERFACE parent 1: classid 1:1 htb rate $LIMIT_RATE
    tc class add dev $INTERFACE parent 1:1 classid 1:20 htb rate $LIMIT_RATE
    tc class add dev $INTERFACE parent 1:1 classid $TC_CLSID htb rate 10000mbit
    tc filter add dev $INTERFACE parent 1: protocol ip prio 1 u32 match ip mark $IPMARK 0xffffffff flowid $TC_CLSID

    iptables -t mangle -D OUTPUT -j FN_SPEED_LIMIT 2>/dev/null
    iptables -t mangle -F FN_SPEED_LIMIT 2>/dev/null
    iptables -t mangle -X FN_SPEED_LIMIT 2>/dev/null
    iptables -t mangle -N FN_SPEED_LIMIT
    iptables -t mangle -A OUTPUT -j FN_SPEED_LIMIT

    IFS=',' read -ra PORTS <<< "$EXCLUDE_PORTS"
    for PORT in "${PORTS[@]}"; do
        if [[ -n "$PORT" ]]; then
            iptables -t mangle -A FN_SPEED_LIMIT -p tcp --sport $PORT -j MARK --set-mark $IPMARK
            iptables -t mangle -A FN_SPEED_LIMIT -p udp --sport $PORT -j MARK --set-mark $IPMARK
            echo "已添加排除端口: $PORT"
        fi
    done
    iptables -t mangle -A FN_SPEED_LIMIT -j MARK --set-mark 0
    echo "限速规则已生效。"
}

stop_limit() {
    echo "正在停止所有限速规则..."
    tc qdisc del dev $INTERFACE root 2>/dev/null
    iptables -t mangle -D OUTPUT -j FN_SPEED_LIMIT 2>/dev/null
    iptables -t mangle -F FN_SPEED_LIMIT 2>/dev/null
    iptables -t mangle -X FN_SPEED_LIMIT 2>/dev/null
    echo "限速规则已清除。"
}

status_check() {
    echo "========== 限速状态检查 =========="
    if tc qdisc show dev $INTERFACE | grep -q "htb 1:"; then
        echo -e "[状态] 限速: 已启用"
        echo "当前限速设置:"
        tc class show dev $INTERFACE | grep "htb rate"
    else
        echo "[状态] 限速: 已停止"
    fi
    echo "排除端口: $EXCLUDE_PORTS"
    echo "================================="
}

case "$1" in
    start)
        start_limit
        ;;
    stop)
        stop_limit
        ;;
    status)
        status_check
        ;;
    restart)
        stop_limit
        start_limit
        ;;
    *)
        echo "使用方法: $0 {start|stop|status|restart}"
        exit 1
        ;;
esac

保存后chmod +x /usr/local/bin/fn_speedlimit.sh赋予权限。

测试脚本:/usr/local/bin/fn_speedlimit.sh start

然后检查状态:/usr/local/bin/fn_speedlimit.sh status

预期结果:应该显示“限速: 已启用”。

增加系统重启后自动启动功能:nano /etc/systemd/system/fn-speedlimit.service

[Unit]
Description=FN OS Bandwidth Limiter
After=network.target
Wants=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/fn_speedlimit.sh start
ExecStop=/usr/local/bin/fn_speedlimit.sh stop
StandardOutput=journal

[Install]
WantedBy=multi-user.target

然后添加定时任务: crontab -e

#定时开启限速
30 22 * * * /usr/local/bin/fn_speedlimit.sh start
#定时停止限速 
30 18 * * * /usr/local/bin/fn_speedlimit.sh stop

按以上格式,自定义时间;如需要设定不同限速值,可以新建另一个脚本定义好上行限值,同样添加到定时任务中即可,会自动按时间切换规则。