技術入門

Linux kernelが提供するパケット受信処理
~NAPI~

NIC ネットワーク制御ソフトウェアプロジェクト

長谷川 優斗(はせがわ まさと)

#ネットワーク#ソフトウェア#Linux

2024/12/27

はじめに

ネットワークイノベーションセンタ ネットワーク制御ソフトウェアプロジェクト・新入社員の長谷川です。私たちのプロジェクトでは、安心・安全な通信インフラを支えるソフトウェア技術の研究開発に取り組んでいます。


私たちの研究開発の適用領域の一つに、通信キャリアが提供するネットワーク(キャリアネットワーク)があります。例えば、スマートフォンやタブレットなどの移動端末の通信を可能にするモバイルネットワークが挙げられます。キャリアネットワークでは、パケットデータをインターネットに届けるまでに複数のサーバを経由します。従来のキャリアネットワークは、大量のパケットを高速・低遅延に処理するために、パケット処理のみを行う専用ハードウェアで処理を行うことがほとんどでした。しかし、近年ではCPUやGPUのように、様々な用途に使用可能な汎用ハードウェアの性能向上や仮想化技術の発展に伴い、汎用ハードウェア上のソフトウェアでパケット処理を行うケースが増えています。このソフトウェアベースのパケット処理では、従来の専用機器と同等以上の処理性能を実現する必要があります。


ソフトウェアでパケット処理を行う場合、OS (Operating System) がその処理の一端を担います。広く普及したOSの一つにLinuxがありますが、Linuxにはパケット処理ならではの工夫がたくさんあります。したがって、キャリアネットワークのサーバに関わる技術者は、上記の仕組みを深く理解し、技術検討を進める必要があり、新入社員である私もこれらの習熟に取り組んでいます。


そこで今回は、このような技術の一つとしてLinuxが大量のパケットを高速・低遅延に処理するための工夫の1つである、NAPI(New API)についてご紹介します。

LinuxのI/Oデバイス処理

サーバ内にはLAN (Local Area Network) ケーブルや光ケーブルが刺さるNIC (Network Interface Card) というカードがあり、サーバはケーブルを介して送信されてきたパケットをこのNICから受け取ります。OSはこの受け取ったパケットを読み取り、アプリケーションに渡すという役割を担っています。(より詳細には、NICは、電気信号や光信号から、bit列を抽出し、そのデータをメインメモリへとコピーし、その後OSはこのメインメモリを読み取ることでパケットデータを受信します:"NAPI (New API)"節の図を参照)


サーバに接続されるハードウェアには、NICやストレージ(ハードディスクなど)、キーボードなど、様々なデバイスがあります。これらのサーバとの間でデータの入出力が必要なデバイスは、一般にI/Oデバイスと呼称されます。サーバにとって、これらのI/Oデバイスから「いつ」データが到着するかは、予測が難しいです。例えば、通信相手がいつデータを送信してくるか、人間がいつキーボードを押下するか、サーバは予測することが難しいからです。


このように、予測が難しいI/Oデバイスからのデータ到着をOSが検知する方法としては、主に割り込み方式とポーリング方式があり、これらはそれぞれ以下のような特徴を持ちます。

割り込み方式

  • デバイスからデータが到着すると、デバイスからCPUへ信号を送信(割り込み)
  • CPUは実行中のタスクを中断した上でその状態を保存し、割り込みに対応するための処理を実行
  • 処理が終わるとCPUを元の状態に戻し、割り込み前に実行していたタスクを再開
  • パケット受信の場合、パケット到着ごとにNICからCPUに割り込みが発生し、パケット処理を行うイメージ
  • ポーリング方式

  • CPUが常にデバイスからのデータ到着を確認
  • データ到着があった時には必要な処理を実行
  • 常にデータ到着の確認を行っているため、他のタスクは実行できない
  • パケット受信の場合、NICのパケットの到着を常に確認し、パケットが届いていれば処理を行うイメージ

  • ここで、パケット受信処理の場合のこれらの方式について、パケット到着頻度に基づいて比較してみます。
    まず、割り込み方式については、パケット到着頻度が低い場合、パケットが到着しない間は割り込みが発生せず処理が必要ありません。したがって、不必要にCPUを動かさなくてよく、電力効率が高い方法となります。一方で、パケット到着頻度が高い場合、パケット到着の度にパケット処理と他の処理とを行ったり来たりするため、スループットは小さくなり、処理遅延は大きくなってしまいます。そのため、同時アクセスが少なくパケット負荷が大きくなりにくい、小規模なWebサーバなどには向いた方式と言えます。
    ポーリング方式については、パケット到着頻度が高い場合、他の処理からの切り替えがない分スループットが大きく、処理遅延は小さくなります。一方で、パケット到着頻度が低い場合、パケットが到着していなくても処理が発生するため、CPUが無駄な動作をすることが多く、電力効率が低い方法となってしまいます。そのため、常に大量のパケット転送が必要でパケット負荷が大きくなりやすい、ソフトウェアルータなどには向いた方式と言えます。

    01.jpg
    パケット受信処理におけるメリットとデメリット

    このように、これらの方式にはそれぞれ一長一短がありますが、Linuxではパケット受信処理において、これらを組み合わせることで、"いいとこどり"をする仕組みを持っています。

    NAPI (New API)

    Linuxは、パケット受信処理の効率化のために、NAPI (New API) という仕組みを実装しています。NAPIは割り込みとポーリングを組み合わせることで、パケット受信処理を最適化しています。下記の図では、パケット受信におけるNAPIのデータの流れを示しています。

    02.jpg
    NAPIの処理の流れ

    ネットワーク通信では、大きいデータは複数のパケットに分割して送信することが一般的です。その結果、受信側では1つのパケットが到着すると、連続して複数のパケットが到着するという特徴があります。
    NAPIではこのパケット受信の特徴を生かし、以下のように割り込みとポーリングを組み合わせたハイブリッドな仕組みでパケット受信処理を行います。(①②は割り込み方式、③④はポーリング方式)


    ① 最初のパケットが届くとNICはCPUへ割り込みを発生させ、割り込みハンドラが起動
    ② 割り込みハンドラは、割り込みを無効化しポーリング機構を起動
    ③ ポーリング機構は、メモリ内のパケットが格納されている箇所からパケットを取得し、プロトコルスタックに渡す。(パケットがなくなるまで繰り返す)
    ④ ポーリング機構は、パケットがなくなるまで処理が完了すると、割り込みを有効化し、終了

    (プロトコルスタックではイーサネット・IP・TCP/UDPなどのプロトコルの処理を行います)
    (ユーザアプリケーションがパケットに格納されたデータを使用する場合はsocketインターフェースを通じてデータを取得します)


    LinuxのNAPIはこのようにして、パケット到着頻度が低い場合は割り込みが発生するまでは他の処理を実行し、パケット到着頻度が高い場合はポーリングによって効率的なパケット処理を行うことで、最適なパケット受信処理を実現しています。

    最後に

    今回はLinuxのネットワーク処理における工夫の1つであるNAPIの処理についてご紹介しました。LinuxにはNAPI以外にもBusy Poll Socket, XDP (eXpress Data Path), Threaded NAPIなど、ネットワーク処理の高速化・高効率化のための仕組みがいくつもあるため、今後も継続して紹介していきます。
    まだまだこれからではありますが、私自身としてもこれからも色々学びつつ、通信インフラ分野におけるサーバソフトウェアの新規技術の創出に取り組んでいきたいと考えています。

    関連するプロジェクト

    プロジェクト一覧へ

    採用情報

    採用情報