traffic control Mini-Howto 井之上 和弘, pierre@astrum.co.jp 1999/11/09 v0.13 この Mini-HOWTO では、Linux を稼働中のホストから送出されるパケットの流 量を QoS 機能を用いてコントロールする方法について簡単に説明します。 ______________________________________________________________________ 目次 1. はじめに 1.1 本ドキュメントの有用性 1.2 免責 1.3 著作権表記 1.4 その他 2. 一般的な基礎知識 2.1 帯域制御と優先制御 2.1.1 帯域制御 2.1.2 優先制御 2.2 QoS 3. ソフトウェアの入手・設定 3.1 必要なソフトウェア 3.2 インストール先の決定 3.3 QoS サポートを組み込んだカーネルのコンパイル 3.4 iproute+tc のインストール 3.5 cbq.init スクリプトのインストール 4. トラフィックコントロールの設計 4.1 注意事項 4.2 トラフィックコントロールの設計 4.2.1 すべてのパケットの帯域を制限する 4.2.2 http, ftp のみ制限する 4.2.3 ファイヤウォールを通過するパケットについて制限する 5. 設定手順 5.1 すべてのパケットを制限する 5.2 http, ftp のみ制限する 5.3 ファイヤウォールを通過するパケットについて制限する 6. さいごに ______________________________________________________________________ 1. はじめに 1.1. 本ドキュメントの有用性 下記に該当する方は、本ドキュメントを参照することで何らかのメリットがあ るかもしれません。 o ftp や http で linux カーネルなどの大量のデータを受信中に暇つぶしを 兼ねてメールの送受信その他を実行してみたものの、レスポンスが悪く、 いらいらしたことがある方 o ネットワークに対する負荷の高い機材を Linux で運用していて、なんとか したいと考えている方 o ファイヤウォールを通過するパケットの帯域を制限したい方 o telnet や ssh で遠隔地の機材のメンテナンスを行う際のレスポンスが ftp や http などのトラフィックで低下することを避けたい方 逆に下記に該当する方には、本ドキュメントは不要かもしれません。 o 現在の回線品質に不満を感じていない方 o ネットワークに対する負荷の高い機材を運用していない方 1.2. 免責 このドキュメントの内容について作成者は一切の責任を負いません。 1.3. 著作権表記 Copyright (C) 1999 Kazuhiro Inoue (Astrum, Inc) このドキュメントは、フリーソフトウエアです。 GNU General Public License 第二版 (もしくはそれ以降の版) に従う限り、この文書を配布または 変更できます。 1.4. その他 本ドキュメントにおける各種用語の用法は間違っている可能性があります。こ のドキュメントは「とりあえず動く」ことを最大の目的としていますので正し い理解を深めるには他の適切な書籍等をあわせてお読みください。 日本語で読めるドキュメントとしては Internet Week 98 チュートリアル C12「QoS技術:Intservとdiffserv」 などが参考になりま す。 また、帯域制御が可能なルータのドキュメントを読むのもよいでしょう。 2. 一般的な基礎知識 2.1. 帯域制御と優先制御 ネットワークに接続されている機器がパケットを送出する場合、パケットの衝 突が発生しない限りは無条件に送出が行われます。 このため同一セグメントに大量のパケットを送出する機器が存在すると他の機 器のデータの送受信のレスポンスが大幅に悪化する原因となります。 また 128Kbps 以下の低速な回線では、 ftp や http で大量のデータの送受信 が行われると、メールの送受信や telnet, ssh のような接続でレスポンスが 著しく悪化します。内部側ネットワークに複数の端末を接続している場合に は、レスポンスの悪化がより顕著に出てきます。 しかしパケットの送信先アドレスやポート番号に応じて帯域の上限値や優先度 を調整することができれば、ftp で大量のデータを受信中でも pop3 や smtp などのパケットを優先的に送出でき、レスポンスの向上につながります。 Linux カーネルではこのような制御を帯域制御と優先制御を組み合わせて設定 できます。 2.1.1. 帯域制御 帯域制御では基本的に次のルールでパケットの送出を行っています。 o 単位時間あたりの転送量が設定値を下回っている間はパケットの送出を行 う。 o 単位時間あたりの転送量が設定値を超えた場合はパケットの送出を停止す る。 たとえば 128Kbps の回線において ftp の帯域を 64Kbps と設定した場合、そ の他のパケットについては少なくとも 64Kbps の帯域が残っているため、外部 ネットワークの pop3 サーバからメールを受信するような場合でもレスポンス が大きく低下することはありません。 2.1.2. 優先制御 優先制御では同時に複数のパケットの送信が発生した場合に優先度の高いパ ケットから処理を行います。優先度の高いパケットが存在する間は基本的に優 先度の低いパケットの送出は行われません。 たとえば telnet や ssh のようなパケットを ftp や http のパケットよりも 優先するように設定すれば、遠隔地のホストに接続する場合でも十分なレスポ ンスを確保することも不可能ではありません。しかし優先度の設定を逆にする と、ftp や http で大量のデータを受信中に telnet や ssh の接続を行って も全然接続できないという困った状況になります。 そのため、優先制御の設定を行う際は十分に注意する必要があります。 2.2. QoS QoS (Quality of Service) はネットワークの帯域をより効果的に利用するた めの技術で、Linux kernel では開発版カーネルの 2.1 で実装され、現在の安 定版カーネル 2.2.x で利用できます。 Linux kernel の QoS では前述の帯域制御と優先制御の両方が可能です。 3. ソフトウェアの入手・設定 3.1. 必要なソフトウェア QoS 機能を利用するには下記のソフトウェアが必要です。 1. Linux kernel 2.2 本ドキュメント執筆時点 (1999/10/29) での安定版カーネルのバージョン は 2.2.13 です。 QoS は開発版カーネル (2.1.x) でもサポートされてい ますが、特別な理由がなければ安定版カーネルを利用するのがよいでしょ う。 2. iproute+tc QoS の設定には iproute+tc が必要です。 から入手できます。 tarball ではな く rpm を入手したい場合は から入手できるようですが、筆者は主 に Slackware を使用しているため動作の確認はしておりません。 3. cbq.init 設定内容がシンプルな場合は cbq.init スクリプトを用いると便利です。 から入手できま す。 3.2. インストール先の決定 iproute2+tc も cbq.init も適切なパスに自分でコピーする必要がありますの で、どのディレクトリにコピーするかを予め決めておきましょう。 cbq.init をデフォルト設定のままで利用する場合は下記のとおりとなりま す。 o iproute2+tc /sbin o cbq.init /etc/rc.d o cbq.init で使用する設定ファイル /etc/sysconfig/cbq 3.3. QoS サポートを組み込んだカーネルのコンパイル ここではカーネルをコンパイルする方法をすでに理解しているという前提で話 を進めます。カーネルのコンパイルについての知識が不十分な場合は Linux Kernel HOWTO などの適切なドキュメントを先に参照してください。 QoS を利用するには少なくとも以下のオプションを組み込んでコンパイルする 必要があります。モジュールとしてコンパイルしても動作するようですが、確 認はしていません。 o Prompt for development and/or incomplete code/drivers o QoS and/or fair queueing o CBQ packet scheduler o TBF queue o QoS support o Rate estimator o Packet classifier API o Routing table based classifier o Firewall based classifier o U32 classifier o Ingres traffic policing 3.4. iproute+tc のインストール iproute2-current.tar.gz を任意のディレクトリで展開してください。な お、libc5 の環境で BIND 4 の libresolv シェアードライブラリが存在しな い場合は Makefile の修正が必要です。glibc6 では特別な修正は不要です。 コンパイルの準備ができたら make を実行します。コンパイルが正常に終了し たら生成されたバイナリのうち、ip/ip と tc/tc を適切なディレクトリにコ ピーします。 cbq.init では /sbin にインストールされていることを前提としていますから よくわからない方はここにコピーしてください。 3.5. cbq.init スクリプトのインストール cbq.init スクリプトを適切なディレクトリにコピーし、chmod 500 cbq.init などの適切なパーミッションを設定しておきます。 Slackware の場合は /etc/rc.d あたりにコピーしておくとよいでしょう。 さらに環境に合わせて cbq.init の修正を行います。変更が必要な設定を挙げ ておきます。 o PATH ip, tc のインストールパスが含まれるようにしてください。 /sbin にイ ンストールしている場合は変更不要です。 o CBQ_PATH cbq.init が使用する設定ファイルを格納するパスで、デフォルトは /etc/sysconfig/cbq です。必要に応じて修正してください。 o CBQ_INIT cbq.init ではスクリプト自身ののインストールパスを /etc/rc.d として いるため、異なるパスにインストールした場合は正しいパスを指定しま す。ただし現在のところこの変数は未使用のようなので特に変更しなくて も問題はないと思われます。 o モジュールの組み込み設定 QoS 関連のモジュールをカーネルに直接組み込んでいる場合は、モジュー ルの組み込みを行っている個所をコメントにします。 o その他 tc, ip のインストールパスが /sbin 以外の場合は、cbq.init 内で /sbin/tc, /sbin/ip が存在しているかどうかを確認している個所が 1 個 所ありますので適切に修正してください。 4. トラフィックコントロールの設計 4.1. 注意事項 設計を行う前に一つだけ注意すべき点があります。 QoS の設定はデバイスか ら送出するパケットについてのみ有効であり、受信するパケットについて設定 することはできません。 ファイヤウォールを経由する送受信の場合は、内部側デバイスで設定を行うこ とで外部から受信するパケットについての流量を調整することになります。 4.2. トラフィックコントロールの設計 タイトルは堅苦しい表現を使っていますが、別に難しい話をするつもりはあり ません。どのプロトコル(ポート番号)にどの程度の帯域を割り当てるかを決 めましょう、ということです。 ここでは例として下記のような設定を行うものとします。 4.2.1. すべてのパケットの帯域を制限する このケースでは設定は非常にシンプルなので、cbq.init を使用しなくても設 定できます。しかし負荷の高い機材でこれを行うと telnet 等でのメンテナン スも困難となりますのでこの設定を行うケースは少ないかもしれません。 ここでは eth0 の帯域を 512Kbps に制限する設定を行ってみます。 4.2.2. http, ftp のみ制限する このケースでは cbq.init スクリプトを利用したほうが設定が簡単です。ここ では http に 64Kbps, ftp に 32Kbps の帯域を割り当てるケースを考えま す。 4.2.3. ファイヤウォールを通過するパケットについて制限する ここでは次のようなネットワークについて設定を行うものとします。 192.168.0.0/24 はプライベートネットワークで、local 側からファイヤウォ ールを通過するすべてのパケットは IP マスカレードで変換されるものとしま す。 (any) | router | ---------------------------- 172.16.0.0/24 (global) | | eth0, 10baseT, 172.16.0.1 F/W | eth1, 10BaseT, 192.168.0.1 | ---------------------------- 192.168.0.0/24 (local) 設定方針: o telnet, ssh は制限なし。 o local -> global は制限なし。 o any <-> local の http を 96Kbps に制限 o any <-> local の ftp は 64kbps に制限 o any <-> local へのその他のパケットは制限なし。 o その他のパケットは制限しない。 o 優先順位は ftp < http < その他の順で ftp が最も低い 5. 設定手順 5.1. すべてのパケットを制限する 次のコマンドを実行してください。 tc qdisc add dev eth0 root tbf limit 15Kb buffer 10Kb/8 rate 512Kbps 次に設定が有効となっていることを適切なツールを用いて確認します。 ncftp や wget などのように転送レートが確認できるツールを用いてファイルの転送 を行ってみてください。 設定を削除する場合は次のコマンドを実行します。 tc qdisc del dev eth0 root 帯域の上限値は rate の部分を任意の数値に変更することで自由に設定できま す。単位は Kbps, Mbps が使用できます。 動作が確認できたら、設定コマンドが起動時スクリプトの適切な個所で実行さ れるようにしてください。 5.2. http, ftp のみ制限する cbq.init 用の設定ファイルを下記のように作成します。 /etc/sysconfig/cbq/cbq-64.http DEVICE=eth0,10Mbit,1Mbit RATE=64Kbit WEIGHT=6Kbit PRIO=5 RULE=:80 /etc/sysconfig/cbq/cbq-32.ftp DEVICE=eth0,10Mbit,1Mbit RATE=32Kbit WEIGHT=3Kbit PRIO=5 RULE=:20 RULE=:21 この例はネットワークデバイスの帯域速度が 10Mbps を前提としていますの で、 100BaseTX のカードを利用している場合は DEVICE=eth0,100Mbit,10Mbit と設定します。 ファイルが作成できたら 'cbq.init start' を実行し、wget や ncftp などで 動作を確認します。 動作が確認できたら cbq.init スクリプトが起動時スクリプトの適切な個所で 実行されるようにします。 cbq.init の設定ファイルの細かい説明については、cbq.init スクリプトのコ メント部分に解説がありますのでそちらを参照してください。 5.3. ファイヤウォールを通過するパケットについて制限する ファイヤウォールを通過するパケットについても、基本的には cbq.init スク リプトを使用して設定することができます。しかし設定が複雑になると cbq.init スクリプトではエラーとなるケースがありますので、ここでは tc コマンドを直接実行するスクリプトを作成してみます。 iproute+tc に添付のドキュメントは英語なので、英語が苦手な方はこれを読 むのも一苦労だと思いますが日本語で細かい説明をはじめるとドキュメントの 量が増えてしまいます。 そのため動確認済みのサンプルスクリプトを引用しておきますので、これを適 当に修正して使うなり、参照しながら iproute+tc のドキュメントを読むなり して理解してください。 サンプルスクリプトでは cbq.init と同様に CBQ (Class Based Queue) スケ ジューラを用いて設定を行っています。 CBQ の大きな特徴はその名前のとお り、クラス構造による帯域制御を行うことが可能であるということです。 そのため CBQ での基本的な設定手順は次のようになります。 1. ルートクラスの設定 ネットワークデバイスに cbq パケットスケジューラを設定します。 2. 親クラスの帯域設定 すべてのクラスのベースとなる親クラスを設定します。 3. 子クラスの帯域設定 親クラスから派生する子クラスを設定します。 4. 子クラスに孫クラスを設定するか、またはパケットスケジューラを設定 子クラスに対して必要に応じて孫クラスを設定します。孫クラスが不要な 場合はここで tbf パケットスケジューラを設定します。 5. 設定したクラスを適用するフィルタの設定 設定した各クラスを適用するフィルタを設定します。 なお IP マスカレードを使用している環境でも、これらの設定を行う際には内 部側、外部側のネットワークをそのまま指定するだけで設定を行うことができ ます。 以下は設定スクリプトの例です。 #!/bin/sh ######################################################################## # # rc.cbq # # 1999/10/10 Kazuhiro Inoue (Astrum, Inc) # ######################################################################## PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin" GLOBAL=172.16.0.0/16 LOCAL=192.168.0.0/24 ################ # ルールの初期化 tc qdisc del dev eth0 root 1> /dev/null 2> /dev/null tc qdisc del dev eth1 root 1> /dev/null 2> /dev/null ############################## # ルートクラス・親クラスの作成 ## /dev/eth0 のルートクラスに cbq をセットし、ハンドルを 10 とする ## tc qdisc add dev eth0 root handle 10: cbq \ bandwidth 10Mbit avpkt 1000 cell 8 ## /dev/eth1 のルートクラスに cbq をセットし、ハンドルを 11 とする ## tc qdisc add dev eth1 root handle 11: cbq \ bandwidth 10Mbit avpkt 1000 cell 8 ## 10Mbit/sec の帯域クラスを priority 8 で作成 (classid 10:1) ## ## 以後、handle 10:1 を parent とするクラスは最大で 10Mbit/sec の ## 帯域が利用可能となる。 tc class add dev eth0 parent 10:0 classid 10:1 cbq \ bandwidth 10Mbit rate 10Mbit allot 1514 cell 8 \ weight 1Mbit prio 8 maxburst 20 avpkt 1000 ## 10Mbit/sec の帯域クラスを priority 8 で作成 (classid 10:1) ## ## 以後、handle 11:1 を parent とするクラスは最大で 10Mbit/sec の ## 帯域が利用可能となる。 tc class add dev eth1 parent 11:0 classid 11:1 cbq \ bandwidth 10Mbit rate 10Mbit allot 1514 cell 8 \ weight 1Mbit prio 8 maxburst 20 avpkt 1000 ################################## # /dev/eth0 の帯域制御クラスの作成 ## 64Kbit/sec の帯域クラスを priority 5, classid 10:64, parent 10:1 で ## ## 作成し tbf スケジューラを設定 ## tc class add dev eth0 parent 10:1 classid 10:64 cbq \ bandwidth 10Mbit rate 64Kbit allot 1514 cell 8 \ weight 6Kbit prio 5 maxburst 20 avpkt 1000 bounded tc qdisc add dev eth0 parent 10:64 tbf \ rate 64Kbit buffer 10Kb/8 limit 15Kb ## 96Kbit/sec の帯域クラスを priority 4, classid 10:65, parent 10:1 で ## ## 作成し tbf スケジューラを設定 ## tc class add dev eth0 parent 10:1 classid 10:65 cbq \ bandwidth 10Mbit rate 96Kbit allot 1514 cell 8 \ weight 9Kbit prio 4 maxburst 20 avpkt 1000 bounded tc qdisc add dev eth0 parent 10:65 tbf \ rate 96Kbit buffer 10Kb/8 limit 15Kb ## 10Mbit/sec の帯域クラスを priority 3, classid 10:66, parent 10:1 で ## ## 作成し tbf スケジューラを設定 ## tc class add dev eth0 parent 10:1 classid 10:66 cbq \ bandwidth 10Mbit rate 10Mbit allot 1514 cell 8 \ weight 1Mbit prio 3 maxburst 20 avpkt 1000 bounded tc qdisc add dev eth0 parent 10:66 tbf \ rate 10Mbit buffer 10Kb/8 limit 15Kb ########################################## # 各帯域クラスを適用するネットワークを定義 ## GLOBAL と LOCAL の間にクラス 10:66 を適用 ## tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip src $GLOBAL \ match ip dst $LOCAL flowid 10:66 ## LOCAL から任意のホストへの ssh にクラス 10:66 を適用 ## tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip sport 22 0xffff \ match ip dst $LOCAL flowid 10:66 ## LOCAL から任意のホストへの telnet にクラス 10:66 を適用 ## tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip sport 23 0xffff \ match ip dst $LOCAL flowid 10:66 ## LOCAL から任意のホストへの http にクラス 10:65 を適用 ## tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip sport 80 0xffff \ match ip dst $LOCAL flowid 10:65 ## LOCAL から任意のホストへの ftp にクラス 10:64 を適用 ## tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip sport 21 0xffff \ match ip dst $LOCAL flowid 10:64 tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip sport 20 0xffff \ match ip dst $LOCAL flowid 10:64 ## LOCAL から任意のホストへの任意の接続にクラス 10:66 を適用 ## tc filter add \ dev eth0 parent 10:0 protocol ip prio 100 u32 \ match ip dst $LOCAL flowid 10:66 ################################## # /dev/eth1 の帯域制御クラスの作成 ## 64Kbit/sec の帯域クラスを priority 4, classid 11:64, parent 11:1 で ## ## 作成し tbf スケジューラを設定 ## tc class add dev eth1 parent 11:1 classid 11:64 cbq \ bandwidth 10Mbit rate 64Kbit allot 1514 cell 8 \ weight 6Kbit prio 5 maxburst 20 avpkt 1000 bounded tc qdisc add dev eth1 parent 11:64 tbf \ rate 64Kbit buffer 10Kb/8 limit 15Kb ## 96Kbit/sec の帯域クラスを priority 4, classid 11:65, parent 11:1 で ## ## 作成し tbf スケジューラを設定 ## tc class add dev eth1 parent 11:1 classid 11:65 cbq \ bandwidth 10Mbit rate 96Kbit allot 1514 cell 8 \ weight 9Kbit prio 4 maxburst 20 avpkt 1000 bounded tc qdisc add dev eth1 parent 11:65 tbf \ rate 96Kbit buffer 10Kb/8 limit 15Kb ## 10Mbit/sec の帯域クラスを priority 3, classid 11:66, parent 11:1 で ## ## 作成し tbf スケジューラを設定 ## tc class add dev eth1 parent 11:1 classid 11:66 cbq \ bandwidth 10Mbit rate 10Mbit allot 1514 cell 8 \ weight 1Mbit prio 3 maxburst 20 avpkt 1000 bounded tc qdisc add dev eth1 parent 11:66 tbf \ rate 10Mbit buffer 10Kb/8 limit 15Kb ########################################## # 各帯域クラスを適用するネットワークを定義 ## GLOBAL と LOCAL の間にクラス 11:66 を適用 ## tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip src $LOCAL \ match ip dst $GLOBAL flowid 11:66 ## LOCAL から任意のホストへの ssh にクラス 11:66 を適用 ## tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip sport 22 0xffff \ match ip dst $LOCAL flowid 11:66 ## LOCAL から任意のホストへの telnet にクラス 11:66 を適用 ## tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip sport 23 0xffff \ match ip dst $LOCAL flowid 11:66 ## LOCAL から任意のホストへの http にクラス 11:65 を適用 ## tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip sport 80 0xffff \ match ip dst $LOCAL flowid 11:65 ## LOCAL から任意のホストへの ftp にクラス 11:64 を適用 ## tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip sport 20 0xffff \ match ip dst $LOCAL flowid 11:64 tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip sport 21 0xffff \ match ip dst $LOCAL flowid 11:64 ## LOCAL から任意のホストへの任意の接続にクラス 11:66 を適用 ## tc filter add \ dev eth1 parent 11:0 protocol ip prio 100 u32 \ match ip dst $LOCAL flowid 11:66 ## end of rc.cbq ## 6. さいごに このドキュメントは内容が不十分なため、これだけで 100% を理解することは 難しいかもしれません。しかし Linux kernel の QoS 機能については日本語 はおろか英語のドキュメントでさえもあまり存在しないようです。 そういう意味では、このドキュメントでも QoS 機能を利用してみたいという 方には何らかの役に立つことでしょう。