9.7. 中間キューイングデバイス (Intermediate queueing device :IMQ)

中間キューデバイスは qdisc ではないのですが、 その利用法は qdisc と深く関連しています。 linux では qdisc はネットワークデバイスに属しており、 デバイスにキューされたものは、すべてこの qdisc にキューされます。 このコンセプトには、2 つの限界があります。

1. 出口での帯域制限しかできない (入口 qdisc もありますが、 クラスフルな qdisc に比べると非常に機能が限られています)。

2. ある qdisc はひとつのインターフェースにおけるトラフィックしか見ないので、 グローバルな制限を置くことはできません。

IMQ はこれら 2 つの制限を解決するためにあるのです。 簡単にいうと、qdisc で選んだものすべてを IMQ に置けるのです。 専用の印がついたパケットは netfilter の NF_IP_PRE_ROUTING と NF_IP_POST_ROUTING 各フックで割り込みを受け、 imq デバイスに属する qdisc へと渡されます。 パケットに印を付けるには、iptables のターゲットを用います。

これによって、 つまりある場所から来たパケットに印を付けて入口での帯域制限もできますし、 また複数のインターフェースをクラスとみなしてグローバルな制限を設定できます。 他にも例えば http トラフィックを qdisc に入れたり、 新しい接続要求を qdisc に入れたり、などいろいろなことができます。

9.7.1. 設定例

最初に思い浮かぶのは、入口での帯域制限を用いて 確実に保証されたバンド幅を使えるようにすることでしょう ;) 設定は他のインターフェースでのものと似ています。
tc qdisc add dev imq0 root handle 1: htb default 20

tc class add dev imq0 parent 1: classid 1:1 htb rate 2mbit burst 15k

tc class add dev imq0 parent 1:1 classid 1:10 htb rate 1mbit
tc class add dev imq0 parent 1:1 classid 1:20 htb rate 1mbit

tc qdisc add dev imq0 parent 1:10 handle 10: pfifo
tc qdisc add dev imq0 parent 1:20 handle 20: sfq

tc filter add dev imq0 parent 10:0 protocol ip prio 1 u32 match \
		ip dst 10.0.0.230/32 flowid 1:10
この例では u32 をクラス選別に用いています。 他のクラス選別器も、期待通りに動作します。 次に、トラフィックを選別して imq0 にエンキューされるよう印を付けます。
iptables -t mangle -A PREROUTING -i eth0 -j IMQ --todev 0

ip link set imq0 up

iptables の IMQ ターゲットは、mangle テーブルの PREROUTING チェインと POSTROUTING チェインで使えます。 文法は以下の通り:
IMQ [ --todev n ]	n : imq デバイスの番号
ip6tables ターゲットも提供されています。

トラフィックがエンキューされるのは、ターゲットに当たったときではなく、 それ以降になります。実際にトラフィックが imq デバイスに入る場所は、 トラフィックの方向 (in/out) によって異なります。 これらは iptables で用いられる、定義済みの netfilter フックです。
enum nf_ip_hook_priorities {
        NF_IP_PRI_FIRST = INT_MIN,
        NF_IP_PRI_CONNTRACK = -200,
        NF_IP_PRI_MANGLE = -150,
        NF_IP_PRI_NAT_DST = -100,
        NF_IP_PRI_FILTER = 0,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_LAST = INT_MAX,
};

入口トラフィックでは、imq は自分自身を NF_IP_PRI_MANGLE + 1 の 優先度を持つとして登録します。つまりパケットは、 mangle テーブルの PREROUTING チェインを通過した後に、 直接 imq デバイスに入るのです。

出口の imq では、NF_IP_PRI_LAST を用います。 つまり、filter テーブルが破棄したパケットはバンド幅を占有すべきでない、 という事情を尊重しています。

パッチとやや詳しい情報が、 imq のサイト にあります。