日本語 man コマンド類 (ja-man-1.1j_5) と日本語 man ドキュメント (ja-man-doc-5.4 (5.4-RELEASE 用) など) をインストールすると、以下のような man コマンド閲覧、キーワード検索が コンソールからできるようになります。
4.11-RELEASE-K, 5.4-RELEASE-K, 5.5-RELEASE-K, 6.0-RELEASE-K から 6.4-RELEASE-K, 7.0-RELEASE-K から 7.4-RELEASE-K, 8.0-RELEASE-K から 8.4-RELEASE-K, 9.0-RELEASE-K から 9.3-RELEASE-K, 10.0-RELEASE-K から 10.3-RELEASE-K, 11.0-RELEASE-K から 11.4-RELEASE-K, 12.0-RELEASE-K, 12.1-RELEASE-K は、 プライベート版 (小金丸が編集してまとめたもの) ですが、 より多くの翻訳したファイルが含まれています。 (5.4-RELEASE-K から 6.4-RELEASE-K, 7.0-RELEASE-K から 7.4-RELEASE-K, 8.0-RELEASE-K から 8.4-RELEASE-K, 9.0-RELEASE-K から 9.3-RELEASE-K, 10.0-RELEASE-K から 10.3-RELEASE-K, 11.0-RELEASE-K から 11.4-RELEASE-K, 12.0-RELEASE-K から 12.3-RELEASE-K, 13.0-RELEASE-K から 13.2-RELEASE-K は、全翻訳済み)
13.3-STABLE-K, 15.0-CURRENT-K は現在、作成中で日々更新されています。
Table of Contents
ALTQ(9) FreeBSD カーネル開発者マニュアル ALTQ(9) 名称 ALTQ -- ネットワークインタフェースにおいて出力キューを操作するためのカー ネルインタフェース 書式 #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_var.h> エンキューマクロ IFQ_ENQUEUE(struct ifaltq *ifq, struct mbuf *m, int error); IFQ_HANDOFF(struct ifnet *ifp, struct mbuf *m, int error); IFQ_HANDOFF_ADJ(struct ifnet *ifp, struct mbuf *m, int adjust, int error); デキューマクロ IFQ_DEQUEUE(struct ifaltq *ifq, struct mbuf *m); IFQ_POLL_NOLOCK(struct ifaltq *ifq, struct mbuf *m); IFQ_PURGE(struct ifaltq *ifq); IFQ_IS_EMPTY(struct ifaltq *ifq); ドライバで管理されたデキューマクロ IFQ_DRV_DEQUEUE(struct ifaltq *ifq, struct mbuf *m); IFQ_DRV_PREPEND(struct ifaltq *ifq, struct mbuf *m); IFQ_DRV_PURGE(struct ifaltq *ifq); IFQ_DRV_IS_EMPTY(struct ifaltq *ifq); 一般的なセットアップマクロ IFQ_SET_MAXLEN(struct ifaltq *ifq, int len); IFQ_INC_LEN(struct ifaltq *ifq); IFQ_DEC_LEN(struct ifaltq *ifq); IFQ_INC_DROPS(struct ifaltq *ifq); IFQ_SET_READY(struct ifaltq *ifq); 解説 ALTQ システムはネットワークインタフェースでキューに入れられる制御規則を管 理するフレームワークです。ALTQ は、出力キューを操作するための新しいマクロ を導入します。出力キューマクロは、抽象的なキュー操作に使用され、出力 キュー構造体の内部フィールドに作用しません。マクロは、ALTQ の実装から独立 していて、移行の容易さのために、伝統的な ifqueue マクロと互換性がありま す。 IFQ_ENQUEUE(), IFQ_HANDOFF() と IFQ_HANDOFF_ADJ() はパケット m をキュー ifq に入れます。基本的なキュー制御規則はパケットを捨てるかもしれません。 error 引数は成功すれば 0 に設定され、またはパケットが捨てられるなら、 ENOBUFS に設定されます。m によって指されたパケットは、成功すればデバイス ドライバによって解放され、または失敗すればキュー制御規則によって解放され るので、呼び出し側はキューに入れた後に m に作用するべきではありません。 IFQ_HANDOFF() と IFQ_HANDOFF_ADJ() はキューに入れる操作を統計値の生成を結 び付けます、そして、実際の送信を開始するためにキューに入れることが成功す れば、if_start() を呼び出します。 IFQ_DEQUEUE() はキューからパケットをデキュー (キューから出す) します。デ キューされたパケットは m に返されます、またはデキューするパケットがなけれ ば、m に NULL が設定されます。空でないキューがレート制限で NULL を返すか もしれないので、呼び出し側は常に m をチェックしなければなりません。 IFQ_POLL_NOLOCK() は、キューからそれを取り除かないで、次のパケットを返し ます。その後の呼び出しで IFQ_DEQUEUE_NOLOCK() が同じパケットをデキューす ることを保証するために IFQ_POLL_NOLOCK() を呼び出すとき、呼び出し側は キューミューテックスを保持しなければなりません。 IFQ_*_NOLOCK() は、(利用可能であるなら) 常に呼び出し側がキューミューテッ クスを保持すると仮定します。それらは IFQ_LOCK() で取得することができ、 IFQ_UNLOCK() で解放することができます。 IFQ_PURGE() はキュー中のすべてのパケットを捨てます。仕事を保存しない キューはデキューの繰り返しによって空にすることができないので、パージ操作 は必要です。 IFQ_IS_EMPTY() は、キューが空であるかどうかチェックするために使用すること ができます。IFQ_DEQUEUE() はキュー制御規則が仕事を保存しないなら、まだ NULL を返するかもしれないことに注意してください。 IFQ_DRV_DEQUEUE() は、キューから ``driver managed'' キューに ifq->ifq_drv_maxlen パケットに繰り上げて、m を通して最初のものを返しま す。IFQ_DEQUEUE() に関して、m は空でないキューのためさえ NULL であるかも しれません。IFQ_DRV_DEQUEUE() へのその後の呼び出しは、キューミューテック スを取得しないで、``driver managed'' キューからパケットを渡します。並列ア クセスに対して保護するのは、呼び出し側の責任です。与えられたキューのため に ALTQ を有効にすることは、ifq_drv_maxlen の、より高い値のために IFQ_DRV_DEQUEUE() によって実行された ``bulk dequeue'' が ALTQ の内部のタ イミングに不利であるように、ifq_drv_maxlen を 0 に設定します。デフォルト マクロが mbuf リーク (漏れ) を導くかもしれない ``driver managed'' キュー を見ないように、ドライバが IFQ_DRV_*() マクロをデフォルトのデキューマクロ と混同してはならないことに注意してください。 IFQ_DRV_PREPEND() は、m を IFQ_DRV_DEQUEUE() への次の呼び出しで取得される ところからの ``driver managed'' キューの先頭に追加します。 IFQ_DRV_PURGE() は、``driver managed'' キューのすべてのパケットをフラッ シュして、後で、IFQ_PURGE() を呼び出します。 IFQ_DRV_IS_EMPTY() はキューの ``driver managed'' 部分のパケットをチェック します。それが空であるなら、IFQ_IS_EMPTY() へフォワードします。 IFQ_SET_MAXLEN() は、デフォルトの FIFO キューにキューの長さの制限を設定し ます。ifaltq 構造体の ifq_drv_maxlen メンバは ``driver managed'' キューの 長さの制限を制御します。 IFQ_INC_LEN() と IFQ_DEC_LEN() は、パケットの現在のキューの長さを増加させ るか、または減少させます。これは主に内部の用途のためのものです。 IFQ_INC_DROPS() はドロップカウンタを増加して、IF_DROP() と同じです。それ は、名前付けの一貫性のためだけに定義されています。 IFQ_SET_READY() は、ドライバが新しいマクロを使用するために変換されたこと を示すフラグを設定します。ALTQ は、このフラグとのインタフェースだけで有効 にすることができます。 互換性 ifaltq 構造体 既存のコードとの互換性を保つために、新しい出力キュー構造体 ifaltq には同 じフィールドがあります。伝統的な IF_*() マクロと if_snd の中でフィールド を直接参照するコードは ifaltq でまだ動作しています。 ##古いスタイル## ##新しいスタイル## | struct ifqueue { | struct ifaltq { struct mbuf *ifq_head; | struct mbuf *ifq_head; struct mbuf *ifq_tail; | struct mbuf *ifq_tail; int ifq_len; | int ifq_len; int ifq_maxlen; | int ifq_maxlen; }; | /* ドライバキューフィールド */ | ...... | /* altq 関連フィールド */ | ...... | }; | 新しい構造体は struct ifnet で struct ifqueue を置き換えます。 ##古いスタイル## ##新しいスタイル## | struct ifnet { | struct ifnet { .... | .... | struct ifqueue if_snd; | struct ifaltq if_snd; | .... | .... }; | }; | (簡易型) の新しい IFQ_*() マクロは次に似ています: #define IFQ_DEQUEUE(ifq, m) \ if (ALTQ_IS_ENABLED((ifq)) \ ALTQ_DEQUEUE((ifq), (m)); \ else \ IF_DEQUEUE((ifq), (m)); エンキュー操作 エンキュー (キューに入れる) 操作の動作を変更します。新しいスタイルでは、 エンキューとパケットドロップは、多くのキュー制御規則で容易に分離すること ができないので、結合されます。新しいエンキュー操作は古いマクロで書かれて いる次のマクロに対応しています。 #define IFQ_ENQUEUE(ifq, m, error) \ do { \ if (IF_QFULL((ifq))) { \ m_freem((m)); \ (error) = ENOBUFS; \ IF_DROP(ifq); \ } else { \ IF_ENQUEUE((ifq), (m)); \ (error) = 0; \ } \ } while (0) IFQ_ENQUEUE() は次を行います: - パケットをキューに入れる。 - エンキュー操作が失敗するなら、パケットを落し (て解放し) ます。 エンキュー操作が失敗するなら、error は ENOBUFS に設定されます。m mbuf は キュー制御規則によって解放されます。呼び出し側が、統計のためにあらかじめ m_pkthdr.len または m_flags フィールドをコピーする必要があるように、呼び 出し側は、IFQ_ENQUEUE() を呼び出した後に mbuf に作用するべきではありませ ん。デフォルトのインタフェース統計と if_start() への迅速な呼び出しだけが 要求されるなら、IFQ_HANDOFF() と IFQ_HANDOFF_ADJ() を使用することができま す。mbuf が既に解放されているので、呼び出し側は senderr() を使用するべき ではありません。 新しいスタイルの概観は if_output() は次のようです: ##古いスタイル## ##新しいスタイル## | int | int ether_output(ifp, m0, dst, rt0) | ether_output(ifp, m0, dst, rt0) { | { ...... | ...... | | mflags = m->m_flags; | len = m->m_pkthdr.len; s = splimp(); | s = splimp(); if (IF_QFULL(&ifp->if_snd)) { | IFQ_ENQUEUE(&ifp->if_snd, m, | error); IF_DROP(&ifp->if_snd); | if (error != 0) { splx(s); | splx(s); senderr(ENOBUFS); | return (error); } | } IF_ENQUEUE(&ifp->if_snd, m); | ifp->if_obytes += | ifp->if_obytes += len; m->m_pkthdr.len; | if (m->m_flags & M_MCAST) | if (mflags & M_MCAST) ifp->if_omcasts++; | ifp->if_omcasts++; | if ((ifp->if_flags & IFF_OACTIVE) | if ((ifp->if_flags & IFF_OACTIVE) == 0) | == 0) (*ifp->if_start)(ifp); | (*ifp->if_start)(ifp); splx(s); | splx(s); return (error); | return (error); | bad: | bad: if (m) | if (m) m_freem(m); | m_freem(m); return (error); | return (error); } | } | 既存のドライバをどのように変換するか 最初に、対応する if_output() が既に新しいスタイルに変換されることを確実に します。 ドライバで if_snd を検索します。たぶん、利用者は、if_snd を含んでいる行に 変更する必要があります。 空のチェック操作 コードが、キューが空であるかどうか調べるために ifq_head をチェックするな ら、IFQ_IS_EMPTY() を使用します。 ##古いスタイル## ##新しいスタイル## | if (ifp->if_snd.ifq_head != NULL) | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | IFQ_IS_EMPTY() は、いくつかのパケットがキューに格納されているかどうかだけ チェックします。IFQ_IS_EMPTY() が FALSE であるときでさえ、キューがレート 制限であるなら、IFQ_DEQUEUE() がまだ NULL を返すかもしれないことに注意し てください。 デキュー操作 IF_DEQUEUE() を IFQ_DEQUEUE() に取り替えます。つねに、デキューされた mbuf が NULL であるかどうかチェックします。IFQ_IS_EMPTY() が FALSE, であるとき でさえ、レート制限のために IFQ_DEQUEUE() が NULL を返すかもしれないことに 注意してください。 ##古いスタイル## ##新しいスタイル## | IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m); | if (m == NULL) | return; | ドライバは、次のデキューの引き金のために転送完了の割り込みから if_start() を呼び出すはずです。 ポーリングとデキュー操作 コードがキューの先頭でパケットをポーリングし、実際にデキューする前にパ ケットを使用するなら、IFQ_POLL_NOLOCK() と IFQ_DEQUEUE_NOLOCK() を使用し ます。 ##古いスタイル## ##新しいスタイル## | | IFQ_LOCK(&ifp->if_snd); m = ifp->if_snd.ifq_head; | IFQ_POLL_NOLOCK(&ifp->if_snd, m); if (m != NULL) { | if (m != NULL) { | /* リソースを取得するために */ | /* リソースを取得するために */ /* m を使用 */ | /* m を使用 */ if (something goes wrong) | if (something goes wrong) | IFQ_UNLOCK(&ifp->if_snd); return; | return; | IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE_NOLOCK(&ifp->if_snd, m); | IFQ_UNLOCK(&ifp->if_snd); | /* ハードウェアをキックする */ | /* ハードウェアをキックする */ } | } | 前の IFQ_POLL_NOLOCK() のように同じロックの下で IFQ_DEQUEUE_NOLOCK() が同 じパケットを返すことが保証されます。それらは IFQ_LOCK() によって保護され る必要があることに注意してください。 IF_PREPEND() の排除 コードが IF_PREPEND() を使用するなら、代わりに IFQ_DRV_PREPEND() の使用を 許す、``driver managed'' キューを使用することができないなら、利用者はそれ を削除しなければなりません。IF_PREPEND() の共通的な使用法は、前のデキュー 操作をキャンセルすることです。利用者は論理 (ロジック) をポーリングとデ キューすることに変換しなければなりません。 ##古いスタイル## ##新しいスタイル## | | IFQ_LOCK(&ifp->if_snd); IF_DEQUEUE(&ifp->if_snd, m); | IFQ_POLL_NOLOCK(&ifp->if_snd, m); if (m != NULL) { | if (m != NULL) { | if (something_goes_wrong) { | if (something_goes_wrong) { IF_PREPEND(&ifp->if_snd, m); | IFQ_UNLOCK(&ifp->if_snd); return; | return; } | } | | /* 現時点では、ドライバは、 | * このパケットを送信する | * ためにコミットされる. | */ | IFQ_DEQUEUE_NOLOCK(&ifp->if_snd, m); | IFQ_UNLOCK(&ifp->if_snd); | /* ハードウェアをキックする */ | /* ハードウェアをキックする */ } | } | パージ (消去) 操作 キューを空にするために、IFQ_PURGE() を使用します。キューを出す繰り返しに よって、仕事を保存しないキューを空にすることができないことに注意してくだ さい。 ##古いスタイル## ##新しいスタイル## | while (ifp->if_snd.ifq_head != NULL) {| IFQ_PURGE(&ifp->if_snd); IF_DEQUEUE(&ifp->if_snd, m); | m_freem(m); | } | | ドライバで管理されたキューを使用する変換 IF_*() マクロをそれらと同等な IFQ_DRV_*() に変換して、適切なところで IFQ_DRV_IS_EMPTY() を使用します。 ##古いスタイル## ##新しいスタイル## | if (ifp->if_snd.ifq_head != NULL) | if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | IFQ_DRV_DEQUEUE(), IFQ_DRV_PREPEND() と IFQ_DRV_PURGE() への呼び出しがあ る種のミューテックスで保護されることを確認します。 アタッチルーチン ifq_maxlen を len に設定するために IFQ_SET_MAXLEN() を使用します。 IFQ_DRV_*() マクロを使用する計画があるなら、目的にふさわしい値で ifq_drv_maxlen を初期化します。このドライバが新しいスタイルに変換されるこ とを示すために IFQ_SET_READY() を追加します。(これは新しいスタイルのドラ イバを識別するために使用されます。) ##古いスタイル## ##新しいスタイル## | ifp->if_snd.ifq_maxlen = qsize; | IFQ_SET_MAXLEN(&ifp->if_snd, qsize); | ifp->if_snd.ifq_drv_maxlen = qsize; | IFQ_SET_READY(&ifp->if_snd); if_attach(ifp); | if_attach(ifp); | 他の問題 統計のための新しいマクロは次の通りです: ##古いスタイル## ##新しいスタイル## | IF_DROP(&ifp->if_snd); | IFQ_INC_DROPS(&ifp->if_snd); | ifp->if_snd.ifq_len++; | IFQ_INC_LEN(&ifp->if_snd); | ifp->if_snd.ifq_len--; | IFQ_DEC_LEN(&ifp->if_snd); | キュー制御規則 キュー制御規則は、(IFQ_IS_EMPTY() によって使用される) ifq_len を維持する 必要があります。また、キュー制御規則は、IFQ_DEQUEUE() が IFQ_POLL() の直 後に呼び出されるなら、同じ mbuf が返されることを保証する必要があります。 関連項目 pf(4), pf.conf(5), pfctl(8) 歴史 ALTQ システムは、1997 年 3 月にはじめて登場しまし、KAME プロジェクトの ホームで見つかります (http://www.kame.net)。それは、5.3 の FreeBSD に取り 込まれました。 FreeBSD 12.2 March 20, 2018 FreeBSD 12.2