私は100 Mbpsの高速イーサネットを使用しています。そのフレームサイズは1500バイト未満です(私の教科書によると、ペイロード用に1472バイトです)。その中で、メッセージサイズ65507バイトのUDPパケットを送受信できました。つまり、パケットサイズは65507 + 20(IPヘッダー)+ 8(UDPヘッダー)= 65535でした。
フレームのペイロードサイズ自体が最大1472バイト(私の教科書によると)の場合、IPのパケットサイズは65535のサイズよりもどのように大きくなりますか?
私は送信者コードを次のように使用しました
char buffer[100000];
for (int i = 1; i < 100000; i++)
{
int len = send (socket_id, buffer, i);
printf("%d\n", len);
}
受信者コード
while (len = recv (socket_id, buffer, 100000))
{
printf("%d\n". len);
}
returns -1
およびsend
のrecv
i > 65507
がmaximum of length 65507
のパケットを印刷または受信することを確認しました。
UDPデータグラムはMTUサイズとはほとんど関係がなく、上記の最大64Kまでは好きなだけ大きくすることができます。大きなデータグラムより大きなサイズのジャンボフレームを使用している限り、パケットの1つをパケット全体で送信することもできます。
ただし、ジャンボフレームは、フレームが通過するすべての機器でサポートされる必要があり、これが問題となります。実用的な目的では、イーサネットフレームが最も一般的な転送サイズであり、これらのMTUは約1500バイトです。今後は1500バイトと言いますが、常にそうとは限りません。基礎となるMTU(示されているように、ほとんどの場合イーサネット)より大きいUDPデータグラムを作成すると、静かにいくつかの1500バイトフレームに分割されます。このトラフィックをtcpdumpすると、MTU境界で壊れたパケットの数が表示され、フラグメント数とともに、より多くのフラグメントフラグが設定されます。最初のパケットにはフラグメント番号0とより多くのフラグメントが設定され、最後のパケットにはゼロ以外のフラグメント番号とより多くのフラグメントが設定されていません。
では、なぜ気にするのでしょうか?実装の詳細は実際に重要です。フラグメンテーションは、ネットワークのパフォーマンスを低下させる可能性がありますが、大きな問題ではありませんが、注意が必要です。巨大なデータグラムサイズを使用した場合、フラグメントが失われた場合は、データグラム全体を再送信する必要があります。同様に大量に、そして今日、これらは完全に達成可能な量であり、再組み立て時にフレームの誤った関連付けが可能です。また、フラグメント化されたUDPパケットを取得して、ロードバランサーがパケットを分散するエンタープライズファイアウォール構成を通過する際に問題が発生する場合があります。一方のフラグメントが一方のファイアウォールにあり、もう一方のフラグメントが別のファイアウォールにある場合、トラフィックは不完全なものとしてドロップされます。
したがって、MTUサイズの断片化よりも大きなUDPデータグラムを作成しないでください。必要な場合と、通信するインフラストラクチャが近い(同じサブネットが近い)ことを指定する必要がある場合は、ジャンボフレームを使用することをお勧めします。
IP層は、送信側でパケットをフラグメント化し、UDPに渡す前に受信側で再構成します。 UDP層からは、パケットがフラグメント化されていることを実際に確認することはできません。 Wireshark のようなパケットキャプチャツールを使用すると、コンピュータがMTUに制限されたIPパケットを受信していることがわかります。
UDPはMTUについて何も知りません。 UDPパケットのサイズは8〜65535バイトです。 UDPの下のプロトコル層は、特定のサイズのパケットを送信できるか、大きすぎる場合はエラーでそのパケットの送信を拒否します。
UDPの下の層は通常、IPであり、IPv4またはIPv6です。 IPパケットのサイズは、20(IPv4)/ 40(IPv6)から65535バイトまで、UDPと同じ最大サイズです。ただし、IPはフラグメンテーションと呼ばれるメカニズムをサポートしています。 IPパケットのサイズが下の層が転送できるサイズより大きい場合、IPは単一のパケットをフラグメントと呼ばれる複数のパケットに分割できます。すべてのフラグメントは、実際には独自のIPパケットであり(独自のIPヘッダーがあります)、独自に宛先に送信されます。次に、宛先のタスクは、すべてのフラグメントを収集し、次の上位層(UDPなど)で受信データを渡す前に、フラグメントから完全なパケットを再構築することです。
イーサネットプロトコルは、46〜1500バイトのペイロードを持つフレームのみを転送できます(例外はありますが、この応答の範囲を超えています)。ペイロードデータが46バイト未満の場合は、46バイトになるようにパディングされます。ペイロードデータが1500バイトを超える場合、インターフェイスはそれを受け入れることを拒否します。その場合、パケットをフラグメント化するかどうかを決定するのはIPレイヤー次第であり、フラグメントが1500バイトを超えないようにするか、この特定の接続でフラグメンテーションが無効化または禁止されている場合は、次の上位レイヤーにエラーを報告します。
断片化は一般に避けられるべきです、
TCP=パケットがIPをフラグメント化することを決して要求しないように、そのフレームサイズをインテリジェントに採用します。これは、IPを禁止してパケットをフラグメント化すること、およびIPがパケットが大きすぎると報告した場合に実行できます。送信、TCPはエラーが報告されなくなるまで、フレームサイズを縮小して再試行します。
ただし、UDPの場合、これはアプリケーション自体のタスクです。UDPは「ダム」プロトコルであるため、独自の管理ロジックがないため、非常に柔軟、高速、かつ単純です。
常に転送可能であると信頼できる唯一のUDPサイズは、576マイナス8バイトのUDPヘッダーとマイナス20(v4)/ 40(v6)バイトのIPヘッダーです。IP標準では、すべてのIPホストがIPパケットを受信できる必要があるためです合計サイズは576バイトです。プロトコルの実装は、少なくともそのサイズのパケットを受け入れることができない場合、標準に準拠しません。ただし、標準ではフラグメンテーションなしの576は規定されていないため、576バイトのIPパケットでも2つのホスト間でフラグメント化される可能性があることに注意してください。
フラグメントの最小IPヘッダーは20/48バイト(v4/v6)であり、フラグメントには少なくとも4/8が必要であるため、フラグメント化なしで転送可能であると信頼できる唯一のパケットサイズは、IPv4の24バイトと56バイトのIPv6です。バイト(v4/v6)ペイロードデータ。したがって、少なくともこれらのサイズのパケットを転送できないIP層の下の転送システムは、IPトラフィックの転送には使用できません。
そして、誰かがIPv6ヘッダーは40バイトしかないとコメントする前に:それは正しいですが、IPv4ヘッダーとは異なり、標準のIPv6ヘッダーには断片化のためのヘッダーフィールドがありません。パケットをフラグメント化する必要がある場合は、IPv6ベースヘッダーの下にフラグメンテーション拡張ヘッダーを追加する必要があります。この拡張ヘッダーの長さは8バイトです。また、IPv4とは異なり、IPv6のフラグメンテーションオフセットは4バイト単位ではなく8バイトでカウントされるため、IPv6の場合、フラグメントは8バイトの倍数のペイロードしか運ぶことができません。
TCP/IPスタックが必要に応じてパケットをフラグメント化できるようにすると、個々のパケットを送信するよりもオーバーヘッドが大幅に低くなることがわかりました。
あなたの質問に答えるために、「私の教科書によると、フレームのペイロードサイズ自体が最大1472バイトである場合、IPのパケットサイズは、ここにある65535よりもどのように大きくなりますか?」
これは、UFO(UDP Fragmentation Offload)と呼ばれるオフロード機能によるものです。 this リンクを参照してください。
オフロード機能は、それぞれethtool -k ethXおよびethtool -K ethXを使用して確認および切り替えることができます。
送信フレームを監視している場合、ネットワークアダプターがセグメンテーションオフロードをサポートしていて、有効になっている可能性があります。セグメンテーションオフロードを有効にすると、ネットワークカード自体が、ネットワークスタックではなく、パケット/フレームを適切なサイズにセグメント化します。これにより、コンピューターのCPUが解放されて他のタスクを実行できるようになり、パフォーマンスが向上します。 Linuxでは、「ethtool -k [device]」でオフロードフラグが表示されます。