Category Archives: TCP

pingの代わり

TCPは通信をはじめる際にSYNフラグの立つセグメントを送信する。

もし相手端末のTCPサービスが起動していればSYN+ACKを返信することでコネクションを開くのだが、もし相手端末のTCPサービスが起動していなければどうするのか。つまりポートが開いていない場合もカーネルにはセグメントが届いており、RSTフラグのたったセグメントでコネクションがリセットされる。

このため、TCPを利用して相手のカーネルが生存しているかどうか確認することも可能である。よってpingの返信を解除していてもTCPで通信を開始しようとすれば分かる。

ちなみにUDPの場合は、どんな動作がされるのか。その場合はICMPでポート不到達エラーが出される。

TCPタイムアウトの変更(3)

HZを250から1000にするためには、Kernelコンパイル時のconfigで1000HZを選択する。

Processor type and features —>
Timer frequency (1000 HZ) —>
( ) 100 HZ
( ) 250 HZ
(X) 1000 HZ

また、Omicron TCP/RTOpatchをそのまま入れるとipv6がわめくので、

Networking —>
Networking options —>
<> The IPv6 protocol

IPv6さらば…。

ネットワークにおける帯域幅という概念

ネットワークの論文を読んでいると、「スループット」や「グッドプット」という言葉が出てくるが、この言葉の意味について深く考えたことはあるだろうか。

この言葉の意味について、ロキ・ジョーゲンソン博士がTechTargetジャパン:「帯域幅」という用語は正しくないという記事を投稿している。

 それでも次のように尋ねる人は多い――「帯域幅はどうやって測定すればいいのか?」、あるいは「(トラフィックを差し引いた)利用可能な帯域幅はどう測定するのか?」、「自社のネットワークのパイプの太さはどのくらいか?」と。こういった質問に対する短い答えは、「あなたが“帯域幅”という言葉で何を意味しているのか、そして何を求めているかによって異なる」ということだ。そして答えは……かなり長い説明になる。

と、帯域幅は求める人によって答えが異なることを示唆し、そこで終わらずさらにケースバイケースによってどんな帯域幅が存在するのかまで言及している。

たとえば、TCPのようなプロトコルを考える場合には、エンドツーエンドの項が参考になる。

TCPタイムアウトの変更(2)

前回の投稿において、タイマ粒度はどうなっているのか、という疑問があったが、良く見るとHZの値がキーであることに気がついた。

#define TCP_RTO_MIN ((unsigned)(HZ/5))

Linux KernelにおけるHZについて詳しい説明があるのが@IT:Linux Kernel Watch 8月版 割り込み頻度変更で消費電力は低下するか?(1/2)で、

 カーネル2.6.13-rc1にて、タイマー割り込みの頻度「HZ」が変更可能になりました。その際に、デフォルトの値が以前の
HZ=1000

から
HZ=250

になりました。このデフォルト値変更は多くの議論を巻き起こしました。

と説明している。実際に/boot/config-2.6.18-3-686を見てみると、

# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250

と、それらしきことが書いてある。よってTCP_RTO_MINはHZ/5=250/5=50ということだ。

で、おそらく、このHZがKernelの割り込みであるのだから、TCPの割り込みもそれで入っているのかもしれない。また、興味深い事実として、

 デフォルト値を250から1000に戻してほしいという要求に対して、Linusは「それが必要なユーザーが1000に変更したらよいだけだろう」と反論しました。そして、「『デフォルトを1000にするべきだ』と主張するのであれば、それが本当に良いということを示すデータを見せろ」というのです。

と書かれている。すなわち、もしTCPのタイマの粒度=Kernelのタイマの粒度であるのなら、HZを1000にしてより細かい粒度のタイマを試すことも可能かもしれない。

4msタイマと1msタイマの違いがどれほどあるのか分からないが、レイヤ2との協調性を実現する道具としては魅力的ではある。誤差の範囲にしかならないかもしれないが…

TCPタイムアウトの変更(1)

Linux kernelの2.6.18のTCPのタイムアウト時間を変更したいため、kernel実装を見つめる。

RTO(Retransmission TimeOut)が関係していることは分かっていたので、grep。RTOについてはたtcp_input.cが一番多く出てきた。見てみると、ACK受信時の処理やRTT、RTOの計算などTCPの入力系が書かれる。

中でも気になったのはTCP_RTO_MINで、includeのnet/tcp.cの中で、

#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))
#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value */

と定義されている。TCP_RTO_MINがHZ/5ということはすなわち、1s / 5 = 200ms。Omicron TCP/RTOにて

Linux の tcp_set_rto を見る限り,”RTO = SRTT + 4 * RTTVAR” になっている気がするけど.最小値(TCP_RTO_MIN)は 200ms,最大値(TCP_RTO_MAX)は 120s.

と書かれているので、ほぼ間違いないだろう。さらに

最小が 200ms なのは,TCP/遅延ACKタイマが 200ms だから,これ以上小さくすると不必要な再送が増えるため.で,遅延 ACK はなぜ 200ms なのかというと…

とも言及している。確かに遅延ACKが200msだと遅延ACKが入る前にタイムアウト再送してしまう…。遅延ACKについて調べてみると、

#define TCP_DELACK_MAX ((unsigned)(HZ/5)) /* maximal time to delay before sending an ACK */
#if HZ >= 100
#define TCP_DELACK_MIN ((unsigned)(HZ/25)) /* minimal time to delay before sending an ACK */
#define TCP_ATO_MIN ((unsigned)(HZ/25))
#else
#define TCP_DELACK_MIN 4U
#define TCP_ATO_MIN 4U
#endif

TCP_DELACK_MAXはHZ/5でTCP_RTO_MINと同じ。ほうほう。

ちなみにOmicronさんのTCP/RTOページにはLinux kernelのpatchが置いてあって、ページ内でそのできることに言及はしていないが、実はsysctlで動的にTCP_RTO_MAXとTCP_RTO_MINを変更できるコードが書いてある。素晴らしい…

もし遅延ACKが問題になるようであれば、TCP_DELACK_MIN / MAXともに変更できるようにpatchを変更しよう。そこまでやれば後は現在のTCP_RTO_MINである200msより下限なRTOがRTTによって適切に決められることだろう。

TCP における確認応答と再送制御 – The all-round Dictionary of Network Terms技術フェチ日誌(2006-11-02)が参考になるかもしれない。もし、RTOが上限と下限を決めても上手く動作しない場合は、RTOのインスタンス値であるtp->mdevの計算ロジックを変更する必要がありそうだ。

後、調べておくべきことはタイマの粒度だが、タイマの粒度を調べるには、”いつRTO(tp->mdev)が待ち時間と「比較」されて再送ロジックに入っているのか”を調べればいいだろうと思っている。しかし、再送ロジックに入るところがまだ探せて確定できてない。もしタイマの粒度が最低200msだったら嫌だなと思っているが、遅延ACKの最低値がHZ/25(40ms)なので、そこまでなら大丈夫な気がしている。

ここまで調べておけば何とかなるか。