mbuf

読み:エムバフ
読み:エムバッファー
外語:mbuf 英語
品詞:名詞

BSDがカーネル内で用いるデータ構造。主としてネットワークパケットの処理に用いられる。

目次

mbufは小さな固定長のバッファーポインターで結ぶ、連結リスト形式のバッファーである。

ポインターで結ばれる一つのリスト列を「mbufチェーン」と呼び、複数のチェーンをまとめて、一つの「キューレコード」となる。

利用目的

mbufは、簡潔に述べればネットワークのデータを格納するバッファーのことである。

TCP/IPを例にすれば、ネットワークからパケットを受信した場合、EthernetIPTCPの順に、処理を遷移する。上位の層に到達するまでに、ヘッダーの除去や、断片化されたパケットの再構築、あるいはパケット順序の入れ替えなどの作業が必要となる。逆に送信する場合は、下の層に移る度に、ヘッダーの付加や、データの分割などが必要になる。

通常の方法であれば、こういった作業は効率面で問題がある。何度もバッファーを確保してデータを複写したり、不要になったバッファーを解放したりせねばならない。

しかしmbufは連結リストなので、バッファの再確保やデータのコピーをすることなく、データの前、中、後、好きな場所に、ヘッダーや断片化されたパケットの一部を付加ないし挿入することが可能である。

ネットワーク処理を効率的に行なう方法として、BSDではmbufが使われている。

大きさ

sys/mbuf.hで、mbuf構造体が定義されている。

mbuf構造体はヘッダー部分とデータ部分に分かれているが、その合計サイズは固定長である。CではMSIZEとして定義され、MSIZEはFreeBSDならsys/param.hで定義があり、FreeBSD 8.0なら256バイトである。環境によって変わり、128バイトなどの環境もあるようである。

mbufの機構がややこしいため、BSDスタックのソース解読は最初はとっつきにくいが、使っていないLinuxのそれと比べて大幅に簡潔かつ読みやすいものになっている。

TCP/IPに依存したLinuxの実装と更に比較すると、TCP/IPの速度などの性能は当然Linuxの方が上ということになるが代わりに汎用性がなく、一方のmbufは効率を若干犠牲にする代わりに汎用性が高く、このためTCP/IPとは無関係の通信処理(例えばBluetoothの処理など)にも使われている。

定義

具体的な内容については後で説明されるが、ヘッダーにおける構造体の定義は次の通りである。

struct mbuf {
    struct m_hdr    m_hdr;
    union {
        struct {
            struct pkthdr   MH_pkthdr;  /* M_PKTHDR set */
            union {
                struct m_ext    MH_ext; /* M_EXT set */
                char        MH_databuf[MHLEN];
            } MH_dat;
        } MH;
        char    M_databuf[MLEN];        /* !M_PKTHDR, !M_EXT */
    } M_dat;
};

上述のように、ヘッダー部分とデータ部分に分かれ、データ部分は何重かのunionで同じ領域を共用化している。

プリプロセッサーシンボルは、次のように定義されている。

#define MLEN        (MSIZE - sizeof(struct m_hdr))  /* normal data len */
#define MHLEN       (MLEN - sizeof(struct pkthdr))  /* data len w/pkthdr */

以上はsys/mbuf.h内、次がsys/param.h内。

#ifndef MSIZE
#define MSIZE       256     /* size of an mbuf */
#endif  /* MSIZE */

かくして、一つのstruct mbufは256バイトの固定長となっている。

struct m_hdr

struct m_hdr構造体には、二つのmbuf構造体へのポインターがある。

  • struct mbuf *mh_next … 同じチェーンの次のバッファーへのポインター
  • struct mbuf *mh_nextpkt … キューレコード中の次のチェーンへのポインター

この他、次の変数を含む。

  • caddr_t mh_data … データ領域で使用されている領域の先頭を指すポインター
  • int mh_len … 使用されている領域の長さ(バイト数)
  • int mh_flags … フラグ
  • short mh_type … データ領域に格納されているデータの種類
  • uint8_t pad[M_HDR_PAD] … アラインメントのための詰め物

mbufは単なるバッファーとしてだけでなく、経路制御表などの構成にも使われるため、mbufの使われ方をmh_typeとmh_flagsで表わす。

padは8バイト(64ビット)アラインメントのためのパディングであり、データ型モデルによってサイズが変わる。

#if defined(__LP64__)
#define M_HDR_PAD    6
#else
#define M_HDR_PAD    2
#endif

__LP64__が定義されるLP64時は構造体のサイズを40バイトに、それ以外(ILP32を想定)時は構造体のサイズを24バイトにすることで、これに続くデータ部は64ビット境界に配置される。

struct mbufデータ部

mbufデータ部は、MSIZEバイトからヘッダーの長さを引いた分となり、共用体となっているため、次の三種類の使い方ができる。

  • char M_databuf[MLEN] … 全てをcharとして扱う
  • struct pkthdr MH_pkthdr … struct pkthdrとして扱う。mbuf flags=M_PKTHDRの時に使われる
  • struct m_extとchar MH_databuf[MHLEN] … 外部記憶を使用するmbuf。mbuf flags=M_EXTの時に使われる

mbufでは、多様な関数とマクロが定義されている。関数は/usr/src/sys/kern/uipc_mbuf.cに実体があり、マクロはsys/mbuf.hで定義される。

よく使われるものを以下に説明する(順不同)。

関数

m_get(how, t)
mbuf領域を確保し、そのポインターを返す。tは、mbufのtypeに格納する、mbufの用途IDである。
m_free(m)
mbuf領域mを一つ解放する。前のmbuf領域から次のmbuf領域へのポインターは自動的に変更される。

関数(mbufチェーンで動作するもの)

m_freem(m)
mbuf領域mから、チェーンの最後までをまとめて解放する。
m_adj(m, len)
lenが正の値ならmbuf領域mを先頭としたmbufチェーンの先頭からlenバイトを取り除き目的位置を頭出しし、さもなくば末尾から切り取る。
m_pullup(m, len)
mbuf領域mのデータ領域から、lenバイトを連続させて一つのmbufに格納するようデータをコピーする。mtod()を使うときに使用する。
当然、一つのmbufに収まるサイズでなければならない。具体的には、lenはMHLEN(mbufのデータ部の最大長)未満でなければならない。
m_cat(m, n)
mbufチェーンnを、mbuf領域mの後に挿入連結する。mとnのtypeは同一でなければならない。

マクロ

mtod(m, t)
mbuf領域mのデータ部の先頭を、指定した型tにキャストするマクロ。
MGET(m, how, type)
m_get(how, type)で領域を確保し、結果をmに入れる。
用語の所属
BSD
関連する用語
連結リスト

コメントなどを投稿するフォームは、日本語対応時のみ表示されます


KisoDic通信用語の基礎知識検索システム WDIC Explorer Version 7.04a (27-May-2022)
Search System : Copyright © Mirai corporation
Dictionary : Copyright © WDIC Creators club