Linuxゲートウェイでトラフィックシェーピングを ここに記述 として設定しようとしています。複数のLANインターフェイスがあるため、スクリプトをカスタマイズする必要があります。したがって、LAN側を形成するために、ifb疑似デバイスを次のように作成することを計画しています。
modprobe ifb
ip link set dev ifb0 up
/sbin/tc qdisc add dev $WAN_INTERFACE ingress
/sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
上記のGistリポジトリのスクリプトには、次の行があります。
/sbin/tc qdisc add dev $WAN_INTERFACE handle ffff: ingress
/sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 1 u32 match ip sport $INTERACTIVE_PORT 0xffff flowid :1
/sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 1 u32 match ip dport $INTERACTIVE_PORT 0xffff flowid :1
/sbin/tc filter add dev $WAN_INTERFACE parent ffff: protocol ip prio 5 0 u32 match ip src 0.0.0.0/0 police rate $MAX_DOWNRATE_INGRESS burst 20k drop flowid :2
このコードとifbインターフェース作成コードはうまく連携していません。カスタマイズされたスクリプトが実行されますが、ifb0デバイスはトラフィック統計を表示しません。入力Gistリポジトリコード(上記で引用)をコメント化すると、ifb0デバイスに転送されたパケットの数が表示されます。また、これらの行を一緒に実行することはできません:
/sbin/tc qdisc add dev $WAN_INTERFACE ingress
/sbin/tc qdisc add dev $WAN_INTERFACE handle ffff: ingress
ファイルが存在するというエラーが表示されます。では、WAN_INTERFACEでのイングレスをどのように形成し、同時にifb0デバイス経由でLANに向かうトラフィックも形成できますか?
IFBは、仮想インターフェイスにリダイレクトしてそれを出力トラフィックとして扱うことにより、入力トラフィックを処理するためのtcフィルターの代替手段です.eth0からifb0、eth1からifb1などに入力トラフィックをリダイレクトするには、物理インターフェイスごとに1つのifbインターフェイスが必要ですオン。
Ifbモジュールを挿入するときに、必要な仮想インターフェースの数を伝えます。デフォルトは2です。
modprobe ifb numifbs=1
次に、すべてのifbインターフェイスを有効にします。
ip link set dev ifb0 up # repeat for ifb1, ifb2, ...
また、物理インターフェイスから対応するifbインターフェイスに入力トラフィックをリダイレクトします。 eth0-> ifb0の場合:
tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
繰り返しますが、シェーピングしたいすべてのインターフェースがカバーされるまで、eth1-> ifb1、eth2-> ifb2などについて繰り返します。
これで、必要なすべてのルールを適用できます。 eth0の下りルールは通常どおりeth0に適用されます。たとえば、帯域幅を制限しましょう。
tc qdisc add dev eth0 root handle 1: htb default 10
tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1mbit
言うまでもなく、eth1、eth2、...について繰り返します。
Eth0の上りルールは、ifb0の下りルールとして適用されます(ifb0に入るものは何でも出る必要があり、eth0の上りトラフィックのみがifb0に入ります)。ここでも、帯域幅制限の例:
tc qdisc add dev ifb0 root handle 1: htb default 10
tc class add dev ifb0 parent 1: classid 1:1 htb rate 1mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 1mbit
このアプローチの利点は、出力ルールが入力フィルターよりもはるかに柔軟であることです。フィルターを使用すると、パケットのドロップのみが可能になります。たとえば、待ち時間を導入することはできません。入力トラフィックを出力として処理することにより、トラフィッククラスと、必要に応じてフィルターを使用して、キューの規則を設定できます。単純なフィルターだけでなく、tcツリー全体にアクセスできます。
SérgioCarvalhoの回答に基づいて、帯域幅を制限するために小さなbashスクリプトを作成しました。
ファイル名:netspeed
#!/bin/bash
#USAGE: Sudo ./netspeed -l limit_in_kbit -s
usage="Sudo $(basename "$0") -l speed_limit -s
-l speed_limit - speed limit with units (eg. 1mbit, 100kbit, more on \`man tc\`)
-s - remove all limits
"
# default values
LIMIT=0
STOP=0
# hardcoded constats
IFACE=ifb0 # fake interface name which will be used for shaping the traffic
NETFACE=wlan0 # interface which in connected to the internet
# shift all required and leave only optional
while getopts ':hl:s' option; do
case "$option" in
l) LIMIT=$OPTARG
;;
s) STOP=1
;;
h) echo "$usage"
exit
;;
esac
done
#
# functions used in script
#
function limitExists { # detected by ingress on $NETFACE qdisc
# -n equals true if non-zero string length
if [[ -n `tc qdisc show | grep "ingress .* $NETFACE"` ]]
then
return 0 # true
else
return 1 # false
fi
}
function ifaceExists {
# -n equals true if non-zero string length
if [[ -n `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep $IFACE` ]]
then
return 0 # true
else
return 1 # false
fi
}
function ifaceIsUp {
# -n equals true if non-zero string length
if [[ -n `ifconfig | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep $IFACE` ]]
then
return 0 # true
else
return 1 # false
fi
}
function createLimit {
#3. redirect ingress
tc qdisc add dev $NETFACE handle ffff: ingress
tc filter add dev $NETFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $IFACE
#4. apply egress rules to local inteface (like wlan0)
tc qdisc add dev $NETFACE root handle 1: htb default 10
tc class add dev $NETFACE parent 1: classid 1:1 htb rate $LIMIT
tc class add dev $NETFACE parent 1:1 classid 1:10 htb rate $LIMIT
#5. and same for our relaying virtual interfaces (to simulate ingress)
tc qdisc add dev $IFACE root handle 1: htb default 10
tc class add dev $IFACE parent 1: classid 1:1 htb rate $LIMIT
tc class add dev $IFACE parent 1:1 classid 1:10 htb rate $LIMIT
}
function updateLimit {
#3. redirect ingress
tc filter replace dev $NETFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $IFACE
#4. apply egress rules to local inteface (like wlan0)
tc class replace dev $NETFACE parent 1: classid 1:1 htb rate $LIMIT
tc class replace dev $NETFACE parent 1:1 classid 1:10 htb rate $LIMIT
#5. and same for our relaying virtual interfaces (to simulate ingress)
tc class replace dev $IFACE parent 1: classid 1:1 htb rate $LIMIT
tc class replace dev $IFACE parent 1:1 classid 1:10 htb rate $LIMIT
}
function removeLimit {
if limitExists ; then
tc qdisc del dev $NETFACE ingress
tc qdisc del dev $NETFACE root
tc qdisc del dev $IFACE root
fi
if ifaceIsUp ; then
ip link set dev $IFACE down
fi
}
#
# main script
#
if [[ `whoami` != "root" ]]; then
echo "WARNING: script must be executed with root privileges!"
echo $usage
exit 1
fi
if [ $STOP -eq 1 ]; then
echo "REMOVING limit"
removeLimit
echo "limit REMOVED"
Elif [ "$LIMIT" != "0" ]; then
# prepare interface
if ! ifaceExists ; then
echo "CREATING $IFACE by modprobe"
modprobe ifb numifbs=1
if ! ifaceExists ; then
echo "creating $IFACE by modprobe FAILED"
echo "exit with ERROR code 2"
exit 2
fi
fi
# set interface up
if ifaceIsUp ; then
echo "$IFACE is already up"
else
echo "set $IFACE up"
ip link set dev $IFACE up # ( use ifconfig to see results)
if ifaceIsUp ; then
echo "$IFACE is up"
else
echo "enabling $IFACE by ip link FAILED"
echo "exit with ERROR code 3"
exit 3
fi
fi
# create/update limits
if limitExists ; then
echo "update limit"
updateLimit
else
echo "create limit"
createLimit
fi
echo "limit CREATED"
exit 0
else
echo $usage
fi
送受信トラフィック用のLinuxルーターボックスでそれを行う簡単なスクリプトがあります。
https://github.com/rfrail3/misc/blob/master/tc/traffic-control.sh