このドキュメントで説明するソフトウェアは、Extended SupportまたはSustaining Supportのいずれかにあります。 詳細は、https://www.oracle.com/us/support/library/enterprise-linux-support-policies-069172.pdfを参照してください。
Oracleでは、このドキュメントに記載されているソフトウェアをできるだけ早くアップグレードすることをお薦めします。

機械翻訳について

6.7 ネットワーク・デバイス・ドライバについて

ネットワーク・デバイス・ドライバは、外部のシステムに接続するハードウェア・インタフェース上でデータ・パケットを送受信し、ネットワーク・プロトコルでアクセス可能な統一されたインタフェースを提供します。 Oracle Linuxでは、これらのドライバは、基礎となるレイヤー1プロトコルとレイヤー2プロトコルを隠蔽するネットワーク・アダプタ自体のハードウェア実装から抽象化されます。

ブロック・ドライバのdriver_request()ルーチンと同様に、ネットワーク・ドライバのコールバック・ルーチンのほとんどをカーネルに登録して、ネットワーク・ポートでのデータ着信時またはカーネルがネットワーク・ポート上でデータを送信する必要があるときに、カーネルがこれらのルーチンを実行できるようにする必要があります。 文字ドライバと同様に、ネットワーク・ドライバは物理的にアドレス可能なストレージ・メディアにはアクセスしません(またはファイル・システム・アクセスをサポートしません)。 ブロック・デバイス・ドライバや文字デバイス・ドライバと異なり、ネットワーク・ドライバは/devにデバイス・ファイルを持ちません。 かわりに、ユーザーがnet_device構造体を使用してネットワーク・インタフェースの機能を定義し、ipなどのコマンドを使用してインタフェースを構成したときに、カーネルがこの構造体のメンバーを更新します。

ネットワーク・デバイス・ドライバの実装は、LinuxとUNIXオペレーティング・システム間において様々な点で異なる場合があり、相違点のほとんどは、ドライバがネットワーク・リクエストの処理に使用する関数、ネットワーク・ドライバのメソッドの表現やネットワーク・インタフェースのプロパティの定義に使用される構造体、およびネットワーク・キューを処理するためのカーネル・インタフェース・ルーチンに関するものです。

UNIXネットワーク・ドライバがデバイスの割込みを処理したり、ネットワーク・デバイスからの着信データをアップストリーム・プロトコル・モジュールに転送する場合に使用するdriver_int()ルーチンとdriver_svr()ルーチンは、Linuxシステムでは通常driver_interrupt()およびdriver_rx()と呼ばれます。 driver_rx()メソッドはnetif_rx()をコールしてソケット・バッファをアップストリーム・モジュールに渡します。

UNIXネットワーク・デバイス・ドライバがネットワーク・デバイス上でデータの送信に使用するdriver_put()ルーチンは、Linuxシステムのndo_start_xmit()メソッドに相当します。 このメソッドは、次のユーティリティ関数を使用して送信ソケット・バッファのアップストリーム・キューを制御できます。

netif_queue_stopped()

キューが現在停止しているかどうかをカーネルに問い合せます。

netif_start_queue()

ドライバがパケット送信を開始できる状態にあることをカーネルに通知します。

netif_stop_queue()

送信バッファがフルになったときにパケット送信の停止を、またはデバイスのクローズ時にドライバのクリーンアップをカーネルに要求します。

netif_wake_queue()

現在停止中のキューをウェイクアップして、パケット送信を再開するようにカーネルに要求します。

ネットワーク・パケットが正常に送信されると、driver_interrupt()driver_txルーチンをコールし、これによりソケット・バッファ・データのドライバのコピーが削除されます。

<linux/netdevice.h>に定義されたネットワーク・デバイスのnet_device_ops構造体には、システムがデバイスとやり取りする方法を指定する一連のメソッド・ポインタが含まれます。

struct net_device_ops {
        int                     (*ndo_init)(struct net_device *dev);
        void                    (*ndo_uninit)(struct net_device *dev);
        int                     (*ndo_open)(struct net_device *dev);
        int                     (*ndo_stop)(struct net_device *dev);
        netdev_tx_t             (*ndo_start_xmit) (struct sk_buff *skb,
                                                   struct net_device *dev);
        u16                     (*ndo_select_queue)(struct net_device *dev,
                                                    struct sk_buff *skb);
        void                    (*ndo_change_rx_flags)(struct net_device *dev,
                                                       int flags);
        void                    (*ndo_set_rx_mode)(struct net_device *dev);
        void                    (*ndo_set_multicast_list)(struct net_device *dev);
        int                     (*ndo_set_mac_address)(struct net_device *dev,
                                                       void *addr);
        int                     (*ndo_validate_addr)(struct net_device *dev);
        int                     (*ndo_do_ioctl)(struct net_device *dev,
                                                struct ifreq *ifr, int cmd);
        int                     (*ndo_set_config)(struct net_device *dev,
                                                  struct ifmap *map);
        int                     (*ndo_change_mtu)(struct net_device *dev,
                                                  int new_mtu);
        int                     (*ndo_neigh_setup)(struct net_device *dev,
                                                   struct neigh_parms *);
        void                    (*ndo_tx_timeout) (struct net_device *dev);

        struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
                                                     struct rtnl_link_stats64 *storage);
        struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);

        void                    (*ndo_vlan_rx_register)(struct net_device *dev,
                                                        struct vlan_group *grp);
        void                    (*ndo_vlan_rx_add_vid)(struct net_device *dev,
                                                       unsigned short vid);
        void                    (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
                                                        unsigned short vid);
        /* Several lines omitted */
};

単純なネットワーク・デバイス・ドライバであれば、次のように、この構造体に定義された関数のサブセットを実装するだけで作成できる場合があります。

struct net_device_ops driver_netdevops = {
    .ndo_init       = driver_init,
    .ndo_open       = driver_open,
    .ndo_stop       = foo_close,
    .ndo_start_xmit = foo_start_xmit,
    .ndo_do_ioctl   = foo_ioctl,
    .ndo_tx_timeout = foo_tx_timeout,
};

カーネルは、ネットワーク・インタフェースを起動してアドレスを割り当てる際にndo_open()を、インタフェースの停止時にndo_stop()を、パケットの送信時にndo_start_xmit()をそれぞれコールします。

<linux/netdevice.h>に定義された文字デバイスのnet_device構造体では、ネットワーク・インタフェースのプロパティを定義します。

net_device構造体の最も重要なメンバーを次に示します。

dev_addr

ハードウェアのメディア・アクセス制御(MAC)アドレス。

features

デバイスがサポートしている機能を表すビット・マスク。

flags

次に示すような、デバイスの現在のプロパティを表します。

IFF_BROADCAST

broadcastモードが有効です。

IFF_LOOPBACK

インタフェースはループバック・デバイスに対応します。

IFF_MULTICAST

multicastモードが有効です。

IFF_NOARP

インタフェースではアドレス解決の実行にARPを使用しません。 このフラグは通常、ポイント・ツー・ポイント・インタフェースによって設定されます。

IFF_PROMISC

promiscuousモードが有効です。

IFF_UP

インタフェースが有効です。 ドライバではこのフラグを設定しません。 ipなどのアプリケーションを使用してインタフェースを起動または停止すると、カーネルはndo_open()メソッドまたはndo_stop()メソッドを呼び出してフラグを設定/設定解除し、インタフェースの状態を示します。

irq

割込み要求(IRQ)番号。

mtu

最大転送単位(MTU)。デバイスが送信可能な最大フレーム・サイズのことです。

name

インタフェースの名前(eth0lo0など)。

netdev_ops

インタフェースのメソッドを定義するnet_device_ops構造体へのポインタ。

promiscuity

インタフェースをpromiscuousモードに設定しているクライアント・アプリケーションの数を示すカウンタ。

stats

インタフェース使用率の統計が含まれるnet_device_stats構造体。

driver_interrupt()などのドライバ・メソッドや関連するヘルパー・ルーチンと同様に、ドライバのロード/アンロード時にコールされるドライバ用のmodule_init()初期化ルーチンとmodule_exit()クリーンアップ・ルーチンを定義するのが一般的です。 これらのルーチンはregister_netdev()およびunregister_netdev()をコールして、デバイスを登録/登録解除し、alloc_netdev()およびfree_netdev()をコールして、デバイスのカーネル表現を割当て/削除します。 イーサネット・デバイスの場合、alloc_netdev()のかわりにalloc_etherdev()をコールするのが一般的です。 ドライバを初期化する場合、request_irq()を使用して割込みハンドラをインストールしますが、その際、flags引数のSA_SHIRQビットと、一意のdev_id(ハンドラはこれを使用して、処理する必要のある割込みを特定できます)を設定して、共有割込みを必ず指定してください。 クリーンアップ・ルーチンではfree_irq()をコールしてハンドラを登録解除します。