2

パケットのセグメンテーションに問題があります。イーサネット MTU (1500 B) より大きいサイズのパケットをセグメント化するための一般化された方法である GSO について、私はすでに多くの情報源から読みました。しかし、私が心に抱いている疑問に対する答えは見つかりませんでした。

L2 層と L3 層の間に新しいバイト セット (「NH」という名前の新しいヘッダーなど) を追加する場合、カーネルは NH を通過し、パケットをオフロードするために sk_buff ポインターを L3 の先頭に調整できる必要があります。 L3 プロトコル タイプの「ポリシー」に従います (例: IPv4 フラグメンテーション)。私の考えは、skb_network_protocol()関数を変更することでした。この関数は、私が間違っていなければ、skb_mac_gso_segment()がさまざまなタイプの L3 プロトコルの GSO 関数を適切に呼び出すことを可能にします。ただし、パケットを適切にセグメント化できません。

ネットワーク (OVS、Open vSwitch) 経由でパケットを転送するカーネル モジュールがあります。私が実行したテスト (h1 --ping-- h2) では、ホストは大きな ICMP パケットを生成し、MTU サイズ以下のパケットを送信します。これらのパケットは、新しいヘッダー NH を付加する最初のスイッチによって受信されるため、パケットが 1500B の場合、1500B + NH の長さになります。ここに問題があります。スイッチはすでにホストから断片化されたパケットを受信して​​おり、スイッチはパケットにさらにバイトを追加します (一種の VLAN が行います)。

そのため、最初は大きなパケットに対して ping を試みましたが、うまくいきませんでした。OVS では、 dev_queue_xmit() を呼び出す前に、skb_gso_segment()呼び出してパケットをセグメント化できます。ただし、パケットはnetif_needs_gso()によってチェックされる条件を通過する必要があります。しかし、パケットを適切にセグメント化するためにskb_gso_segment()を使用する必要があるかどうかはわかりません。

また、 needs_gso_segment()関数を true にするには、skb_shinfo(skb)->gso_sizeを true にする必要があることにも気付きました。ただし、受信したすべてのパケットの gso_size の値は常にゼロです。そこで、ランダムな値を gso_size に割り当ててテストを行いました (ex. 1448B)。私のテストでは、h1 から h2 に ping できましたが、最初の 2 つのパケットが失われました。別のテストでは、TCP のパフォーマンスは非常に低かった。それ以来、カーネル警告が表示されるようになりました: " [ 5212.694418] [c1642e50] ? skb_warn_bad_offload+0xd0/0xd8 "

小さなパケット (< MTU) の場合、問題はなく、ping は正常に機能します。TCP は問題なく動作しますが、ウィンドウ サイズが小さい場合です。

誰かが何が起こっているのか知っていますか?大きなパケットを取得するときは、常に GSO を使用する必要がありますか? 断片化された IPv4 パケットを断片化することは可能ですか?

新しいヘッダーは L2 と L3 の間にあるため、ヘッダーの追加による IPv4 パケットの拡大は、VLAN の場合と似ていると思います。VLAN はセグメンテーションの問題をどのように処理できますか?

前もって感謝します、

4

0 に答える 0