ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

TCP/IPコミュのUDPのPORT番号についての質問

  • mixiチェック
  • このエントリーをはてなブックマークに追加
図のUDP offload engine を学校で設計する事になりました。TCPもUDPも初心者なので、一生懸命本を読んだりしているのですが、イマイチわかっていませんので、下記質問についてご教授いただけたら、と思います。

UDPはEthernetからIPを通って来たデータに対しては、UDPヘッダを取り除いたデータ部をPCIなど内部バスなど通してシステムに渡し、逆に内部バスなどと通してEthernetに送られるデータについては、UDPヘッダを付けてIPにデータを渡す・・・というのが基本的な動作だと理解しています。このUDPヘッダで使用される送信側PORT番号、受信側PORT番号というのは、どのようにして取得するものなのでしょうか?例えばNFSのアプリケーションやOSがデータを送るときに、NFSヘッダに記述されていたりするのでしょうか?

もしかしたら初歩的な質問かもしれませんが、よろしくお願いいたします。

コメント(12)

はじめまして。

OS によっても異なりますが、通常はアプリケーションからのデータ送受信時に宛先アドレス・宛先ポート・発信元アドレス・発信元ポートの情報を渡します。
一般的に、アプリケーションとネットワークの間は通称 BSD socket と呼ばれる API が使われます。ごく小規模な組み込み専用 OS を除けば、世の中の大抵の TCP/IP 準拠システムは BSD 互換ないし類似の API を持っています。

BSD socket API を用いて、文字列 "ABCDEFG" を宛先 IPv4 アドレス 192.168.0.1, ポート番号 8000 へ、発信元「自分のアドレス」の「適当な空いているポート」から送るには以下のようなプログラムになります。

struct sockaddr_in src, dst;
socket s;
char data[8] = "ABCDEFG";

// UDP ソケット作成
s=socket(AF_INET, SOCK_DGRAM, 0);

// 発信元アドレス指定
// INADDR_ANY は「自分のアドレスから適切なものを自動選択」を指定
// port = 0 は「空いているポートから適当なものを自動選択」を指定
src.sin_addr.s_addr = htonl(INADDR_ANY);
src.sin_port = htons(0);
bind(s, &src, sizeof(src));

// 宛先ソケットアドレス作成
dst.sin_addr.s_addr = htonl(0xc0a80001);
dst.sin_port = htons(0x8000);

// 指定宛先にデータ送信
sendto(s, data, 8, 0, (struct sockaddr*)dst, sizeof(dst));

// ソケット閉鎖
close(s);

ここで「8000」は適当に選んでいます。NFS などオープンな標準プロトコルは固定番号のポート(Well-Known port と呼ばれます)に割り当てられており、その一覧は IANA によって管理されています。
http://www.iana.org/assignments/port-numbers


個々の構造体や API の意味については検索してみてください。多くの情報やサンプルプログラムが得られるでしょう。

オフロード処理の実装はその OS において API の中身がどう実装されているか、何をどう弄くれば API の内部処理を外部ハードウェアに導けるかというところを理解しなければなりませんが、そのためにはまずアプリケーションの動作、パケットヘッダの Encapsulate / Stripping がどういう原則に基づいて行われているかを理解しなければ始まりません。

学生さんのようですから、先は長いです。結果を焦らず基礎からじっくり勉強してゆきましょう。
みるぴたすさん。図を見せて欲しいです。どんなオフロードエンジンを作るのでしょう?

ポート番号ですが、一般的なネットアプリの場合は「サーバー側のポート番号は決めうちで固定値」、「クライアント側のポート番号は決まっていなくてダイナミック割り当て」です。

でも、NFSはちょっと違っていて、サーバー側のポート番号は標準的には固定値で決められていますが、RPCプロトコルでサーバーからクライアントに教えるのが流儀になっています。NFSはUDPを使ったプロトコル、というより、RPCというセッション層を使ったプロトコル、なので、トランスポート層のポート番号は気にしたくないのではないかと思います。

作りたいシステムによって、ポート番号の決め方が変わるかもしれませんので、システムの詳細な説明が聞きたいです。
「*うさじぃさん*」さん
「ささき」さん
「むーさん」さん

お忙しい中、ご回答を頂きまして、ありがとうございました。とても詳しく書いていただいて感激しております。

「PORT番号とは何か?」
「APIが行っている事をOffloadEngineにさせる」
など、とても参考になる解説を頂き、イメージが掴めました。

教授から指示されているのは、添付図に示されますTCP/UDP Offload Engine(TOUE)のUDP offload engineの部分をVerilogHDLで設計し検証までする、というものです。MUXを通ってIP engineにデータを渡しますが、教授からは「MUXを通るIPとの接続は、TCPと同じmodule port定義でなくて良い。とにかく最も高スペックの出るUDP engineを設計するように」と言われております。

この場合、システム側(左側)からPCIを通って送られてくるデータにUDPヘッダを加えてIPに情報を渡したりすると思うのですが、このヘッダに含まれる「送信ポート番号」と「受信ポート番号」をどのように認識させるのか、というのがわかりませんでした。

皆様の貴重な解説より、もう少し調べてみたいと思います。もし追加でアドバイスなど頂けると嬉しいです。よろしくお願いいたします。
実は UDP がやるべき事って凄く少ないんですよ。Next-hop(ルート)探索、Path-MTU 探索、MTU に応じたパケット分割と再構成は IP の仕事ですし、またパケットが伝送路上で欠落した場合のデータ保証は TCP なら行いますが(TCP の最適実装はそれだけで一冊の本が書けるほど深遠な話題です)、UDP は「投げっぱなし」です。パケット構成図を見ても判ると思いますが、UDP パケットは IP パケットに「ポート番号」が追加されただけですし、処理的にもそれしか行いません(一応チェックサムもありますが)。

ポート番号というのはアパートの部屋番号みたいなもので、特定の住所(IPアドレス)に届いたパケットが部屋番号(ポート)ごとに分割されて配送されます。現実世界のアパートは部屋の数だけ郵便受けがありますが、TCP/IP のポート番号は理論上 16bit 65536 種類の値を取り得るので、65536 個の受信キューを予め用意しておくことは現実的ではありません。有限個の受信キューとソケットの間を柔軟に、かつ効率的に結びつけるアーキテクチャ設計が一つの肝になるでしょう。(ソフト的にはハッシュテーブルを使ったりしてポート→ソケット参照時間を短縮する工夫がなされますが、使用されるソケット数上限が比較的小さな組み込み専用の実装では速度的に大差がないため、実装容量上有利な順次探索が使われたりもします。この辺も想定されるアプリケーションによって最適実装が異なってくる部分です)。

また受信パケットはアプリケーションが受信処理するより速く到来する可能性があり、受信キューには複数個以上のパケットが格納できるようにしておく仕組みが必要です。受信メモリバッファはいずれにせよ有限の資源ですから、これを各キューごとに固定数で均等に割り当てるか、何らかの動的割り当て手段を取るのかという所もあります。動的割り当てを採用した場合、DoS 攻撃などによって1つのキュー(ポート)に受信パケットが集中してバッファが枯渇してしまい、他のポートの受信動作が停止してしまう現象の防止策が必要となります(広義のQoSともいえます)。

また「パケットバッファ」を Ethernet 最大パケット長である 1500 バイト固定として実装するか(実装は容易になり高速化も期待できるが、全ての UDP パケットが 1500 バイトをフル活用するとは限らず、細切れのパケットが大量受信された時のメモリ使用効率が悪化する)、あるいは分断メモリのリンクチェーンとして実装するか(メモリ利用効率は一般向上するが、実装は困難になる)という選択もあるでしょう。Unix 系 OS では mbuf と呼ばれる 128byte ないし 256byte 単位のメモリをリンクチェーン結合した構造が使われています。

単純に実装しようと思えばそれなりに単純にでき、凝ろうと思えばそれなりに凝れるのが UDP の実装だと思います(TCP ではこうはいかず、最も基本的な実装ですら複数の遷移状態、カウンタ、フラグ、タイマを持たせる必要があります)。業務ではなく課題として「UDP のハードウェア実装」が出されたということは、むしろその実装という結果よりも、その実装に必要となる周辺技術の調査・理解・習得がゼミの目的なのではないかな…とうがって考えてみたりします(^^;
みるぴたすさん

誤解していました。UDPを使って何かの処理をオフロードするのかと思ったら、UDPの処理自体をオフロードするのですね。

それであれば、パケットを送信するときは送受信ポート番号はPCIから来ることになりますし、パケットを受信するときにはヘッダに書かれている送受信ポート番号をPCIで送らないといけません。ポート番号だけではなく、IPアドレスや、TCPなのかUDPなのかを識別する情報も必要になると思います。

UDPプロトコルのオフロード処理であれば、チェックサムの処理がメインになるのではないかと思います。スペック重視ということですし、チェックサムの演算ロジックが大切なのかもしれませんね。
ささきさん、むーさん、色々と詳細なご説明をいただいてありがとうございました。また、お返事が遅くなって申し訳ありません。

頂いた説明を読み、さらに理解を深め、担当教授などに色々と聞きながら、UDPの設計がかなり具体的に見えてきました。なので、少しづつですが、仕様について模索しはじめました。

大変申し訳ないのですが、もしよろしかったら教えてください。

IPにはIPv4とIPv6があるかと思いますが、「IPv6に関してはUDP Psuedo Headerを付ける」云々・・・というのを見つけたのですが、このPsuedo Headerは、UDPがIPにIPv4用に送るデータの前に加える追加Headerなんでしょうか?(添付図)、それとも、IPv4用のUDP Headerの代わりに使われるものなのでしょうか?

図を見ると、追加で加えるものだと思うのですが、自信がないです。ご面倒をおかけして申し訳ありませんが、もしよろしかったら、よろしくお願い他します。
「擬似ヘッダ」は IPv4, IPv6 ともに用いられ、UDP および TCP のチェックサム計算時に「そこに含まれているものと仮定して」演算を行うためのもので、実際の送受信パケットとして付けられるものではありません。(それが「擬似」たる所以ですが)

これをチェックサム計算に取り入れることで、単にデータ部分の正当性をチェックするにとどまらず、ヘッダ部分の正当性をある程度トランスポート層で検証できる(何かの手違いで DST IP の異なるパケットが受信されてしまったとしても、チェックサム検査で弾くことが可能になる)という意味があります。
ささきさん>
いつもご丁寧な解説をいただきまして、本当にありがとうございます。感謝してもしきれません。

「擬似ヘッダ」について、かなり理解できました。ささきさんの解説から考察する限り、IPからUDPへ、UDPからIPへのデータのやりとりは、IPv4であってもIPv6であっても、擬似ヘッダのついたデータのやりとりが行われるもの、と理解しましたが、よろしいでしょうか?

もう少し質問させていただきたいのですが、

1)UDP headerの16bit-UDP-Lengthは、擬似ヘッダを含まないデータのLengthをByte単位で示し、擬似ヘッダの16bit-UDP-Lengthは、擬似ヘッダを含むすべてのデータLengthをByte単位で示す・・・と理解でよろしいでしょうか?

2)UDP headerの16bit Checksumは擬似ヘッダの部分も含めたチェックサム計算の結果を示す・・・という理解でよろしいでしょうか?

3)擬似ヘッダ内の「プロトコル番号」は調べてみましたら、17(「17」は、IPヘッダ中において、UDPプロトコルを表すためのプロトコル番号)とありました。ということは、この「プロトコル番号は、常に17を与えればいいのでしょうか?

毎回、お世話になってしまいまして、大変恐縮です。でも、いつもとてもご丁寧な解説をいただき、本当に嬉しく思います。よろしくお願いいたします。
そろそろ RFC 原文(IP=791, UDP=768)を当たっていただくか、参考書を読んで頂きたいのですが。洋書ならば Addison-Wesley の TCP/IP Illustrated がお勧めです。特に Vol.2 は TCP/IP 実装のツボとなる部分を押さえた名著で実装者のバイブルです。

http://www.kohala.com/start/tcpipiv1.html
http://www.kohala.com/start/tcpipiv2.html

シリコンバレー近辺でしたらローレンス沿いの Digital Guru でコンピュータ専門書籍は一通り揃っている筈です。
http://www.digitalguru.com/
(私もシリコンバレーには5年住んでいたので、この界隈にはよく通っていました。Computer Literacy が閉店しちゃったのは残念だったなぁ…)

また、スタンフォード下の学生街にも何軒か専門書店はある筈です。

1) 繰り返しますが、「擬似ヘッダ」はチェックサム算出の都合上「本当は無いんだけど有ることにして計算する」ものです。擬似ヘッダ自身の長さはどちらにも含まれません。UDP ヘッダに含まれる Length 値も、擬似ヘッダ算出時に参照される UDP Length 値も実は全く同じ値で、「UDP ヘッダ長+UDP データ長」です。

2) そうです。UDP のヘッダ+データ部に対して算出したチェックサム値(16bit)に対し、さらに SRC-ADDR(hi/lo), DST-ADDR(hi/lo), Protocol ID, UDP length を加算するという手順になります。(加算の順番は順不同です)

3) Protocol ID=17 は UDP が IP パケットに梱包される際、「このパケットは UDP である」という事を示すために付けられる番号です。ほかに ICMP=1, TCP=6 などが決まっています。詳しくは IANA の Protocol Numbers 管理情報サイトを参照してください。

http://www.iana.org/assignments/protocol-numbers
>UDP over IPv6 の場合
RFC2460 Section 8.1 を参照してください。

「擬似ヘッダ」は IP 層と上位層(TCP/UDP)の間で交換される情報の一形式であって、必ずその形(擬似ヘッダという構造)で扱わなければならないという物ではありません。要は「UDP サム値には UDP パケットに含まれる以外の情報も幾つか加算されなければならない」ということであって、その情報が「擬似ヘッダ」という構造を取ろうが、IP ヘッダの該当領域から引っ張りだされようが、個々に引数としてバラバラに渡されようが、結果が同じであれば何でも構わないのです。
ささきさん>
詳しいご説明、ありがとうございました。今日、DigitalGuruに行き、Volume1の方を入手してきました。少し読んでみましたが、かなり詳しく書かれていて、びっくりしました。良書を紹介してくださってありがとうございます。Volume2が見つからなかったので、スタンフォード近郊の本屋など色々と探して、早急に入手したいと思います。

またRFCについてのアクセス方法もVolume1に記述されていたので、768,2460、2147など入手して読んでみました。こういう標準規定をちゃんと読まないといけませんね。ちょっと今まで焦っていて、手を抜いていました。

これらの資料を読んで、また何かアドバイスをいただけたら、と思います。ささきさんのご親切を無駄にしないように頑張ります。ありがとうございました!

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

TCP/IP 更新情報

TCP/IPのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング