Linuxトラフィック制御(tc):実践ガイド

12分で読めます - 2026年6月5日

hero section cover
目次
  • Linux トラフィック制御 (tc): 実践ガイド
  • tcの仕組み
  • Linuxサーバーでのtcの設定
  • HTB によるアウトバウンドトラフィックのシェーピング
  • IFB を使用したインバウンドトラフィックのシェーピング
  • DSCP によるトラフィックの優先順位付け
  • 監視とトラブルシューティング
共有

tcを使用して、Linux上で帯域幅を制御し、トラフィックを優先順位付けし、入口と出口を形成する。実サーバーのHTB、IFB、DSCP、fq_codelコンフィグ。

Linux トラフィック制御 (tc): 実践ガイド

Linuxの tc コマンドを使用すると、サーバーによるネットワークトラフィックの処理方法を直接制御できます。 サービスごとの帯域幅を制限したり、大容量転送が急増した際にも SSH などの対話型セッションの応答性を維持したり、単一のツールで送信および受信の両方のトラフィックをシェーピングしたりすることができます。このガイドでは、中核となる概念、HTB の実用的な設定、IFB によるインバウンドシェーピング、DSCP ベースの優先順位付け、および問題が発生した際のデバッグ方法について解説します。


 

tcの仕組み

すべての tc セットアップは、4つの構成要素から成り立っています:

  • qdisc(キューイング・ディシプリン)。ネットワークインターフェースに紐づくスケジューラ。パケットのキューへの追加(enqueue)とキューからの取り出し(dequeue)の方法を決定します。
  • Class。クラスフル qdisc 内の細分化。独自の速度制限を持つ車線のようなものと考えてください。
  • Filter。パケットヘッダー(IPアドレス、ポート、マーク)を検査し、各パケットをクラスに割り当てます。
  • アクション。パケットが条件に一致した際に実行される処理:転送、破棄、リダイレクト。

これらはツリー構造を形成します。パケットはルートqdiscから入り、フィルタを通過し、 major:minor ハンドルによってクラスに分類され、最終的にリーフQdiscのキューに入れられて送信されます。

ポートベースのマッチングよりも複雑な処理を行う場合は、iptables または nftables の mangle テーブルでパケットにマークを付け、その後 fw filter tc を使用してマークごとに分類します。これは、すべてのトラフィックタイプに対して生の u32 ルールをチェーンするよりも、はるかに優れたスケーラビリティを発揮します。

送信(Egress)と受信(Ingress)

方向は重要です。カーネルは送信パケットをバッファリングして遅延させることができ、これが真のシェーピングを可能にします。受信パケットは、あなたがそれを確認する時点ですでにネットワークを経由して到着しているため、最初に IFB デバイスにリダイレクトしない限り、それらをポリシング(しきい値を超えたものをドロップ)することしかできません。

機能送信イングレスの
方向送信インバウンド
シェーピングネイティブIFBが必要
ポリシングサポート対象サポート対象
一般的な用途QoS、帯域幅の共有、ペーシングレート制限、基本的なDDoS対策

実際に使用するqdisc

  • HTB (Hierarchical Token Bucket)。クラスあり。サービスごとに保証された最小帯域幅を確保しつつ、他のクラスから未使用の容量を借りられる機能が必要な場合に使用します。
  • TBF (Token Bucket Filter)。クラスレス。インターフェース全体を単一のレートに制限したい場合に使用します。
  • fq_codel (Fair Queuing Controlled Delay)。 フローごとの公平性とアクティブキュー管理を組み合わせ、バッファブロートを解消します。systemd 217以降、ほとんどのLinuxディストリビューションでデフォルトのqdiscとなっており、RHEL 9ではデフォルトで搭載されています。必ずHTBクラスの下位にあるリーフqdiscとして配置してください。そうしないと、1つの貪欲なフローがクラス全体を占有してしまう可能性があります。

Linuxサーバーでのtcの設定

tciproute2 パッケージに含まれています。Debian および Ubuntu では、以下のコマンドでインストールしてください apt-get install iproute2でインストールします。RHELおよびその派生ディストリビューションでは、 yum install iprouteでインストールします。root権限またはsudoが必要です。

まず、正しいインターフェース名を確認してください。インターフェース名の指定ミスは、設定が何も反応しない最も一般的な原因です:

ip link show

インターフェースに現在何が設定されているか、ライブカウンターも含めて確認してください:

tc -s qdisc show dev eth0

新しい設定を適用する前に、既存の root qdisc をすべて削除し、 RTNETLINK answers: File exists エラーを回避してください:

tc qdisc del dev eth0 root 2>/dev/null || true

ゼロから設定するのではなく、既存のルールを更新する場合は、 replace ではなく add を使用して、アトミックな置換を行ってください。

TSOやGSOのようなハードウェアオフロードは、シェーピングに干渉するような方法でパケットをバンドルします。シェーピング対象のインターフェースでは、これらを無効にしてください:

sudo ethtool -K eth0 tso off gso off

新しいインターフェースのシステム全体のデフォルトqdiscとして fq_codel を新しいインターフェースのシステム全体のデフォルトqdiscとして設定します:

sysctl -w net.core.default_qdisc=fq_codel

負荷の高いサーバーでは、BBR輻輳制御アルゴリズム(カーネル4.9以降)と組み合わせて使用してください。BBRはキューを膨らませることなくスループットを高く維持します:

sysctl -w net.ipv4.tcp_congestion_control=bbr

SSH経由でリモートマシンを設定する際の安全対策として、2つ目のセッションを開き、 tc qdisc del dev eth0 root 貼り付けられるように準備しておくことです。誤ったフィルタルールは、即座に接続を遮断してしまう可能性があります。

HTB によるアウトバウンドトラフィックのシェーピング

HTBを使用すると、各サービスに対して保証された下限値(rate)と上限(ceil)を設定できます。未使用の帯域幅は、優先順位に従ってそれを必要とするトラフィックに割り当てられます。以下は、1 Gbpsのアップリンク向けの動作する3層構成の例です。

ルートHTB qdiscを作成します。 default 30 は、分類されていないパケットをクラス 1:30 に送信し、ルールをバイパスさせないようにします:

tc qdisc add dev eth0 root handle 1: htb default 30

総スループットを900 Mbpsに制限します。常に実際のリンク容量よりわずかに低い値にシェイプしてください。そうしないと、制御できない上流のルーターやモデムにキューが発生してしまいます:

tc class add dev eth0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit

サービス階層を定義します。 prio 値ほど、未使用の帯域幅を優先的に割り当てます:

# High priority: web and API traffic
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1
 
# Medium priority: database replication
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 300mbit ceil 900mbit prio 2
 
# Low priority: bulk and backup traffic
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 100mbit ceil 900mbit prio 3

各クラスのリーフqdiscとして fq_codel 各クラスにリーフqdiscとしてアタッチし、単一のフローがそのティアを独占できないようにします:

tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

次にトラフィックを分類します。単純なポートマッチングの場合、 u32 が最も高速です:

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip dport 443 0xffff flowid 1:10

ステートフルな処理を行う場合は、iptablesでマークを付け、そのマークを fw:

iptables -t mangle -A OUTPUT -p tcp --dport 5432 -j MARK --set-mark 2
tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 2 fw flowid 1:20

IFB を使用したインバウンドトラフィックのシェーピング

パケットが到着する時点ですでに帯域幅が消費されているため、ネイティブにインバウンドトラフィックをシェーピングすることはできません。その回避策として、インバウンドトラフィックを中間機能ブロック(IFB)仮想インターフェースにリダイレクトします。これにより、カーネルはそれをアウトバウンドとして扱い、クラスベースのqdiscを適用できるようになります。

モジュールをロードし、インターフェースを起動します:

modprobe ifb numifbs=1
ip link set dev ifb0 up

物理インターフェースにingress qdiscを追加し、すべてのトラフィックを ifb0:

tc qdisc add dev eth0 ingress handle ffff:
tc filter add dev eth0 parent ffff: protocol all u32 \
  match u32 0 0 action mirred egress redirect dev ifb0

これ以降、 ifb0 は他のインターフェースと同様に動作します。出力時と同様に、HTBツリーを適用してください:

tc qdisc add dev ifb0 root handle 1: htb default 30
tc class add dev ifb0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1

DSCP によるトラフィックの優先順位付け

DSCP(Differentiated Services Code Point)は、TOSバイト内の6ビット値でパケットにタグ付けを行うため、 tc フィルタは、ルールセット全体でポートを追跡するのではなく、タグに基づいて分類できます。DSCPを照合する際は tc、値を2ビット左にシフトします。DSCP EF (46) は 0xb8となります。このマスクは 0xfc は、6 ビットの DSCP ビットを 2 ビットの ECN ビットから分離します。

サーバーワークロード向けの適切なデフォルトのマッピング:

トラフィックタイプDSCPTOS 16進数
対話型EF0xb8SSH、DNS、VoIP
ビジネスAF410x88HTTP、HTTPS、API
BulkCS10x20バックアップ、FTP、パッケージの更新
ベストエフォートCS00x00その他すべて

アウトバウンドパケットがフィルタに到達する前に、iptables でタグ付けする tc フィルターに到達する前にタグを付ける:

iptables -t mangle -A OUTPUT -p tcp --dport 22 -j DSCP --set-dscp 46

その後、 tc でタグを照合し、適切なHTBクラスへルーティングします:

# EF (SSH, VoIP) goes to the high-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip tos 0xb8 0xfc flowid 1:10
 
# AF41 (web traffic) goes to the medium class
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 \
  match ip tos 0x88 0xfc flowid 1:20
 
# CS1 (bulk) goes to the low-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 \
  match ip tos 0x20 0xfc flowid 1:30

監視とトラブルシューティング

常に使用する3つのコマンド:

tc -s qdisc show dev eth0
tc -s class show dev eth0
tc -s filter show dev eth0

以下の droppedoverlimits カウンターを注視してください。パケットのドロップはキューが飽和していることを意味し、オーバーリミットはクラスの上限に達し、カーネルがトラフィックを遅延または破棄せざるを得なかったことを示します。リアルタイムの表示には:

watch -n 1 'tc -s class show dev eth0'

内部パラメータ(ターゲット、間隔、クォンタム)の -d を追加して内部パラメータ(target、interval、quantum)を確認し、 -j メトリクススタックへパイプする場合、JSON出力用にを追加します。 ss -tin と組み合わせて使用すると、TCPレイヤーでのRTT推定値や再送信を確認できます。

失敗のほとんどは以下の短いリストに分類されます:

症状考えられる原因対処法
RTNETLINK answers: File existsルートqdiscは既に設定済みtc qdisc del dev eth0 root 最初に
ルールは適用されているが、トラフィックが制限されていないインターフェースが間違っているか、TSO/GSOがまだ有効になっている以下で確認 ip link showで確認し、 ethtool -K
フィルタが一致しないポート/IPの構文が不正、またはマスクの整列が不適切カウンターアクションを追加し、 tc -s filter show
再起動後にルールが消える設定はメモリ内のみスクリプトにラップし、systemd または NetworkManager ディスパッチャから呼び出す
優先度の高いトラフィックで高遅延が発生リーフqdiscがない、またはバーストが低すぎるリーフクラスにアタッチ fq_codel リーフクラスにアタッチし、 burst

設定ミスでアクセスできなくなってしまった場合でも、リセットは簡単です:

tc qdisc del dev eth0 root

tc 持っていない帯域幅を作り出すことはできませんが、適切にプロビジョニングされたアップリンクであれば、予測可能なパフォーマンスと、1人のテナントが大規模な転送を開始した瞬間に機能不全に陥るサーバーとの差を決定づけます。生の帯域幅と、それを自由にシェイピングする自由度が必要な場合は、FDCの専用サーバーをご検討ください。

ブログ

今週の特集

その他の記事
Linuxトラフィック制御(tc):実践ガイド

Linuxトラフィック制御(tc):実践ガイド

tcを使用して、Linux上で帯域幅を制御し、トラフィックを優先順位付けし、入口と出口を形成する。実サーバーのHTB、IFB、DSCP、fq_codelコンフィグ。

12分で読めます - 2026年6月5日

パワフルで無制限のVPSが重要な理由

7分で読めます - 2025年5月9日

その他の記事
background image

ご質問またはカスタムソリューションが必要ですか?

icon

柔軟なオプション

icon

グローバル・リーチ

icon

即時展開

icon

柔軟なオプション

icon

グローバル・リーチ

icon

即時展開