web-dev-qa-db-ja.com

linux-htbでのキューイング

Linux-htbQDiscのキューイングメカニズムとlinuxtcのQDisc全般を理解しようとしています。

収集できるもの:TX中、パケットはlinuxtc内のキューに入れられます。このキューは、デフォルトで、txqueuelenが1000のpfifo_fast QDiscに従います。パケットスケジューラは、このキューからパケットをデキューし、TXドライバキュー(リングバッファ)に配置します。
linux-htbを使用する場合、txqueuelenはデフォルトのキューに対してのみ継承されます。 [ リンク ]。私の質問:ツリーについて考えてみましょう(レートは括弧()内のキロビット/秒で指定されています):

      1:   root qdisc (class htb)
     (100)
     / | \ 
    /  |  \
   /   |   \
 1:1  1:2  1:3    parent qdiscs (class htb)
(30)  (10)  (60)
  1. 親htbクラス(1:1、1:2、および1:3)ごとに内部キューが維持されていますか?はいの場合、キューの長さはどれくらいですか?そうでない場合、実際に維持されているキューの数と目的は何ですか?キューの長さはどれくらいですか?

  2. Queuing Discipline(QDisc)とは正確にはどういう意味ですか?使用されるデータ構造(キュー)のプロパティですか?またはそれはパケットスケジューラのプロパティですか?それとも両方を組み合わせたのでしょうか?

  3. Htb QDisc [ Link ]のソースコードを読んでいると、ダイレクトキューと呼ばれるものに出くわしました。 direct_queueとは何ですか?

可能であれば、関連するソースへのリンクを提供します。

1
sbhTWR

私は自分でソースコードの読み取りと調査作業を行ったので、自分の質問に答えるつもりです。自分で調査作業をしていなかった場合は、frostschutzとsourcejediによる回答も大いに役立ちます。私の知識では正しいようです(詳細はそれほど詳しくありませんが、出発点になります)。残りの研究を自分で行うため)。

いくつかの理論:キューイングの分野には、クラスフルとクラスレスの2種類があります。

クラスフルの分野は(sourcejediによる回答が言うように)柔軟です。それらを使用すると、子にクラスフルqdiscsをアタッチでき、可能であれば、他のクラスと帯域幅を共有できます。リーフクラスには、クラスレスqdisc(エレメンタリー/ファンダメンタルqdisc)がアタッチされています(エレメンタリーqdiscとも呼ばれます)。これらの基本的なqdiscsによって管理されるキューは、パケットがキューに入れられ、キューから取り出される場所です。パケットは、クラスに対応するアルゴリズムによって、これらのクラスからデキューおよびエンキューされます。クラスフルqdiscsの例は、HTBとCBQです。

Classlessqdiscsは、基本または基本のqdiscであり、子qdiscをアタッチしたり、帯域幅を共有したりできないという意味で厳格です。素朴な言葉で言えば、彼らは彼ら自身です。これらのqdiscは、qdiscに対応するアルゴリズムに従ってパケットをキューに入れたりデキューしたりするキューを所有します。クラスレスqdiscの例:pfifo、bfifo、pfifo_fast(Linux tcでデフォルトで使用)、tbf、sfqなど。

問題のツリーの例では、リーフhtbクラス1:1、1:2、および1:3のそれぞれに、デフォルトでpfifo(pfifo_fastではない)である基本qdiscがアタッチされています。リーフにアタッチされた基本qdiscは、次の方法でtcユーザースペースユーティリティを使用して変更できます。

_tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5 
tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10
_

これについての詳細は HTB Linuxキューイング規律マニュアル にあります。したがって、ツリーは実際には次のようになります。

_       1: root qdisc (class htb)
     (100)
     / | \ 
    /  |  \
   /   |   \
 1:1  1:2  1:3    parent qdiscs (class htb)
(30)  (10)  (60)
 ||    ||    || -----> pfifo qdiscs (queue length: txqueuelen (default, can be changed by tc utitlity))
_

パラメータtxqueuelenがインターフェイス固有のパラメータであることに注意してください。つまり、パラメータはインターフェイスのプロパティであり、_iproute2_またはifconfigを使用して変更できます。デフォルトでは、その値は1000です。_iproute2_を使用して200に変更する方法の例を次に示します。

_ip link set eth0 txqueuelen 200
_

リーフノードが作成されると(HTB qdiscのコンテキストで)、pfifoqdiscはデフォルトでリーフクラスにアタッチされます。このpfifoは、インターフェイスのtxqueuelenのキュー制限で初期化されます。これは、関数htb_change_class()の-​​ sch_htb.c 、1395行目にあります。

_/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
 * so that can't be used inside of sch_tree_lock
 * -- thanks to Karlis Peisenieks
 */
new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
                          classid, NULL);
_

Pfifoキューのデフォルトのキューの長さについては、 sch_fifo.c 、61行目を参照してください。

_u32 limit = qdisc_dev(sch)->tx_queue_len;
_

カーネルは、パケットをキューに入れたり、キューから取り出したりするときに、ルートqdisc(おそらくクラスフルまたはクラスレス)と直接対話します。ルートqdiscがクラスフルで子を持っている場合、最初にパケットを分類します(パケットの送信先の子を決定します)。それが行われるカーネルソース: sch_htb.c 、209行目:

_static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
                                      int *qerr)
_

コメントを読むと、この関数が次のいずれかを返すことが簡単に推測できます。

  1. パケットをドロップする必要がある場合はNULL

  2. -1、パケットをdirect_queueにキューイングする必要がある場合

  3. リーフノード(パケットが実際に終了する基本的なqdiscを含む)この関数は、パケットをキューに入れる必要があるリーフノードを返すまで、ツリーのすべての内部ノード(クラス)をトラバースします。

デキュー中、各クラスはqdiscに関連付けられたアルゴに従って、どの子からデキューするかを決定します。子は、リーフクラスに接続された基本qdiscからパケットがデキューされるまで、同じことを行います。これにより、子クラスのレートがその親を超えないようにすることもできます。 (パケットが通過するかどうかは親が決定するため)。 htbでのデキューのソースを確認していないため、そのソースを提供できません。

ダイレクトキュー:これは、HTB qdiscによって維持される特別な内部FIFOキューであり、ハードウェア速度でパケットがデキューされます。そのキューの長さはtxqueuelenです。 HTBがパケットを子qdiscsのいずれかに分類できず、デフォルトが指定されていない場合、パケットは直接キューに入れられます。

だから私自身の質問への答え:

  1. はい、それらはリーフノードであるため、デフォルトでは、インターフェイスのキュー長txqueuelenがデフォルトで1000であり、変更可能なpfifoキューです。

  2. キューイングの分野は、キューを1つのパッケージにまとめたアルゴのようなものです。私に言わせれば、キューイングの規律は、キューのタイプとパケットスケジューラの両方の特性です(ここで、パケットスケジューラとは、パケットをエンキューおよびデキューするアルゴリズムを意味します)。たとえば、キュ​​ーのタイプはpfifoまたはbfifoの場合があります。エンキューとデキューに使用されるアルゴリズムは同じですが、キューの長さはバイトFIFO(bfifo)のバイト単位で測定されます。バイト制限に達すると、パケットはbfifoでドロップされます。デフォルトのバイト制限は_mtu*txqueuelen_として計算されます。たとえば、パケットがキューに入れられると、パケットの長さが現在のキューの長さに追加されます。同様に、パケットがデキューされると、パケットの長さがキューの長さから差し引かれます。

  3. 上で答えた。

相談するかもしれないいくつかの情報源:

  1. Linuxネットワークトラフィック制御—実装の概要(PDF)

  2. Linuxカーネルの中心への旅:トラフィック制御、シェーピング、QoS

  3. TCの謎解き-Criteo R&Dブログ

  4. Linuxネットワークスタックのキューイング-Linux Journal

1
sbhTWR

免責事項:これらは多くの質問であり、私は10年ほどHTBを使用していませんか?だから自信を持って答えることはできません。しかし、これまでのところ返信がないので、これはまだ役立つかもしれません。


親htbクラス(1:1、1:2、および1:3)ごとに内部キューが維持されていますか?

それらはリーフクラスであり、それぞれがqdiscキュー構造体で表されるため、内部キューとしてカウントされると想定しています。キューの長さがわからない-申し訳ありません。

sch_htb.cからのコード

struct htb_class_leaf {
    int     deficit[TC_HTB_MAXDEPTH];
    struct Qdisc    *q;
} leaf;

qdisc構造はinclude/net /sch_generic.hで定義されています

Queuing Discipline(QDisc)とは正確にはどういう意味ですか?

これはコンテキストによって異なりますが、基本的には、パケットがエンキューおよびデキューされるカーネルAPIです。そのため、QDiscには、着信したパケットが再び送信される(または完全にドロップされる)順序(または時間)に関する制御が与えられます。これが、HTB、SFQ、PRIOなどのQDiscが、帯域幅制限の優先順位付けや適用など、さまざまな方法でトラフィックを形成する方法です。

sch_api.cからのコメント

   Generally, queueing discipline ("qdisc") is a black box,
   which is able to enqueue packets and to dequeue them (when
   device is ready to send something) in order and at times
   determined by algorithm hidden in it.

そして、HTBはそのようなアルゴリズムの1つにすぎません。

Direct_queueとは何ですか?

APIの一部ではありませんが、内部で処理されます...したがって、HTBアルゴリズムの一部と見なすことができます。

意図的にパケットをX:0に分類した場合、またはデフォルトのクラスが存在しない場合、HTBはそれらを別のキューに入れることを決定し、デキュー時にそれらのパケットを最初に送信しようとします。

sch_htb.cからのコメント

 * [...] If we end up with classid MAJOR:0 we enqueue the skb into special
 * internal fifo (direct). These packets then go directly thru. If we still
 * have no valid leaf we try to use MAJOR:default leaf. It still unsuccessful
 * then finish and return direct queue.

...そして これは最初に直接パケットをデキューする場所です

これは通常、設定ミス(存在しないクラスにパケットを送信する)の結果ですが、その場合、HTB開発者は、すべてのトラフィックをドロップするのではなく、すべてのトラフィックを渡す必要があると判断しました(破壊的すぎる)。

2
frostschutz