はじめに:IPって再送しないの?
ネスペ(ネットワークスペシャリスト試験)の勉強をしていたら、解説文に「IPはコネクションレス型なので、パケットの順序管理や再送、フロー制御、輻輳制御などは行わない」という趣旨の一文が出てきました。
正直、最初に思ったのは「えっ、IPって再送しないんだっけ・・・?」でした。
IPアドレスやルーティングは毎日のように触っているのに、パケットが途中で捨てられたらその後どうなるのか、普段まったく意識していなかったんです。
しかも一文の中に分からない言葉が次々と出てきます。コネクションレス型って何がコネクションなのか。ウインドウとフロー制御とは。輻輳制御ってQoSのことじゃないのか。スロースタートと輻輳回避って何だっけ。そして最後の「など」には他に何が入るのか。
この記事では、その疑問を出てきた順に一つずつ解いていきます。最後に、ルータの設定でおまじないのように入れていた adjust-mss の意味がようやく分かった話もします。
結論:IPは「運ぶだけ」、信頼性はTCPの仕事
IPの仕事は、宛先IPアドレスを見てパケットを次のルータへ渡すことだけです。届いたかどうか、順番どおりか、相手が受け取れる量か、はIPの関心の外にあります。この「できる限り運ぶが、保証はしない」方式をベストエフォートと呼びます。
届かなかったパケットの送り直し、順番の並べ直し、送る量の調整は、IPの上にいるTCPが担当しています。
| 層 | プロトコル | 担当すること |
|---|---|---|
| ネットワーク層 | IP | 宛先まで運ぶ(経路選択と転送) |
| トランスポート層 | TCP | 確実に、順番どおりに、ちょうどいい量で届ける |
| トランスポート層 | UDP | ポート番号でアプリを区別するだけ(信頼性の仕組みはなし) |
なぜIPに再送させないのか
理由は大きく2つあります。
1つ目は、途中のルータを単純で速くするためです。ルータが通過する全パケットについて「届いたか」を覚えて再送まで面倒を見ると、状態の管理が膨大になります。運ぶことに専念させ、信頼性は通信の両端(送信元と宛先のホスト)に任せたほうが、ネットワーク全体を高速かつ大規模にできます。この考え方はエンドツーエンド原理と呼ばれます。
2つ目は、再送が要らない通信もあるからです。音声通話のように「遅れて届いたデータは使えない」通信では、再送はむしろ邪魔になります。IPが一律に再送しないからこそ、再送が必要ならTCP、不要ならUDP、と上の層で選べるわけです。
「コネクションレス型」って何がコネクションなの?
言葉としては知っていても、「何をもってコネクションと呼ぶのか」は意外と説明できませんでした。答えは、通信の前に相手と合意し、通信中も状態を持ち続けるかどうかです。
イメージするなら、コネクション型は電話、コネクションレス型はハガキです。電話は相手が出て「もしもし」と応答してから話し始め、切るまで回線がつながった状態が続きます。ハガキはポストに入れたら終わりで、届いたかどうかは差出人には分かりません。
| コネクション型(TCP) | コネクションレス型(IP、UDP) | |
|---|---|---|
| 通信前の合意 | あり(3ウェイハンドシェイク) | なし |
| 通信中の状態 | 両端で持つ(どこまで送ったか、どこまで届いたか) | 持たない(1パケットずつ独立) |
| 届いたかの確認 | ACK(確認応答)で確認する | 確認しない |
| 終了の手続き | あり(FINまたはRST) | なし |
| 例え | 電話 | ハガキ |
TCPは通信の最初に、SYN → SYN/ACK → ACK の3回のやり取り(3ウェイハンドシェイク)で「今から通信します」と合意します。このとき互いの初期シーケンス番号や受信できる量(ウインドウ)などを伝え合い、以降はその情報を状態として持ちながら通信します。
一方のIPは、パケット1つ1つが独立しています。同じ宛先へのパケットでも、途中で別の経路を通ることさえあります。その結果、到着順が入れ替わったり、途中で捨てられたりしますが、IP自身はそれを気にしません。
「など」には他に何が入るの?IPがやらないこと一覧
問題文の「など」が気になったので、TCPが担っていてIPがやらない機能を一覧にしました。
| 機能 | 内容 | 担当 |
|---|---|---|
| コネクションの確立・切断 | 3ウェイハンドシェイクで開始、FINまたはRSTで終了 | TCP |
| 確認応答(ACK) | 「ここまで受け取った」を送信元に返す | TCP |
| 順序管理 | シーケンス番号で受信データを並べ直す | TCP |
| 再送 | ACKが一定時間来なければ再送(RTO)、重複ACKが3回来たら即再送(高速再送) | TCP |
| 選択的確認応答(SACK) | 欠けた部分だけを伝えて、そこだけ再送させる | TCP |
| フロー制御 | 受信側のバッファの空きに合わせて送る量を抑える | TCP |
| 輻輳制御 | ネットワークの混雑に合わせて送る量を抑える | TCP |
| データ部の誤り検出 | チェックサムで壊れたデータを見つける | TCP、UDP |
| ポート番号による多重化 | どのアプリ宛てのデータかを区別する | TCP、UDP |
紛らわしいところを2つ補足します。
- IPv4ヘッダにもチェックサムはありますが、対象はヘッダ部分だけで、データ部は検査しません(IPv6ではヘッダのチェックサム自体が廃止されています)。
- IPv4ヘッダの識別子(Identification)は、分割(フラグメント)されたパケットを組み立て直すための番号で、順序保証のための番号ではありません。
また、途中のルータでパケットが捨てられたとき、ICMPで送信元に通知が返ることはあります。ただしICMPは「届かなかった」と知らせるだけで、再送はしません。
ウインドウとは
1パケット送るたびにACKを待っていたら、往復の時間(RTT)のたびに手が止まってしまいます。そこでTCPは「ACKを待たずに連続で送ってよい量」を決めて、その範囲内でまとめて送ります。この量がウインドウです。
ウインドウが大きいほど待ち時間なしに送れるので、速度が出ます。逆に言えば、通信速度の上限はおおよそ次の式で決まります。
最大スループット ≒ ウインドウサイズ ÷ RTTたとえばウインドウが65,535バイト、RTTが10ミリ秒なら、65,535バイト ÷ 0.01秒 ≒ 6.5MB/秒で、約52Mbpsが上限です。回線が1Gbpsあっても、遠い拠点との通信で速度が出ない理由の一つがこれです。実際には、ウインドウスケールというオプションでこの上限を大きく引き上げられます。
フロー制御とは
フロー制御は、受信側が溢れないように送信量を抑える仕組みです。受信側は「今のバッファの空きはこれだけ」という値(受信ウインドウ、rwnd)をTCPヘッダに入れて送信元に伝え続けます。送信元はその量を超えて送りません。
ポイントは、フロー制御が見ているのは「受信側ホストの都合」だということです。途中のネットワークが混んでいるかどうかは、次の輻輳制御が担当します。
「輻輳制御ってQoSでしょ?」と思っていた
輻輳(ふくそう)は、ネットワークが混雑してパケットがあふれる状態のことです。混雑への対策と聞いて、私はQoSを思い浮かべ、「それならIPの領域では?」と思っていました。半分は合っていて、半分は違いました。
輻輳制御は、送信元ホストのTCPが自分の送る量を自主的に絞る仕組みです。パケットが失われたら「途中が混んでいる」と推測して、送信量を減らします。このとき使う値が輻輳ウインドウ(cwnd)で、実際に送れる量は、フロー制御の rwnd と輻輳制御の cwnd の小さいほうになります。
QoSは、ルータやスイッチが混雑時の交通整理をする仕組みです。キューイングで優先度の高いパケットを先に送ったり、シェーピングやポリシングで帯域を抑えたりして、「混んだときにどれを優先し、どれを捨てるか」を決めます。
| フロー制御 | 輻輳制御 | QoS | |
|---|---|---|---|
| 誰がやる | TCP(受信側が通知) | TCP(送信側が自主規制) | ルータ・スイッチ |
| 守る対象 | 受信側ホスト | 途中のネットワーク | 途中のネットワーク(特に重要な通信) |
| 使う値・機能 | 受信ウインドウ(rwnd) | 輻輳ウインドウ(cwnd) | キューイング、シェーピング、ポリシング |
では、IPはまったく関係ないのかというと、そうでもありません。IPヘッダには、QoSのための目印であるDSCPと、輻輳を通知するためのECNというフィールドがあります。ただしIPがやっているのは目印を運ぶところまでで、制御そのものはルータのQoS機能やTCPが行います。
QoSと輻輳制御は連携している
2つは別物ですが、実際には組み合わさって動いています。QoSでパケットが捨てられると、TCPがロスを検知して減速します。
これを積極的に利用するのがWRED(Weighted Random Early Detection)です。キューが満杯になってから一斉に捨てると、そこを通る多数のTCPが同時に減速し、同時に加速し直す「グローバル同期」が起きて、回線の使用率が波打ちます。WREDはキューが満杯になる前から少しずつランダムに捨てて、TCPに順番にブレーキを踏ませることで、これを防ぎます。
スロースタートと輻輳回避って何だっけ
名前は聞いたことがあっても、違いを説明できなかった2つです。どちらも輻輳制御の中で、輻輳ウインドウ(cwnd)をどう増やすかのルールです。
- スロースタート:通信を始めた直後は、経路の混み具合が分かりません。そこでcwndを小さく始め、ACKが1つ返るたびに1セグメントずつ増やします。1RTTでおよそ倍になるので、実際には指数的に急増します。「スロー」は増え方ではなく「小さく始める」という意味です。現在のOSでは初期値を10セグメント程度にするのが一般的です。
- 輻輳回避:cwndが閾値(ssthresh)に達したら、そこからは1RTTごとに1セグメントずつ、線形に慎重に増やします。
ロスを検知したときの動きは、検知の仕方で変わります。
- 重複ACKが3回来た場合:一部だけが失われた軽い混雑と判断し、すぐに再送したうえで(高速再送)、ssthreshとcwndを半分にして輻輳回避を続けます(高速リカバリ)。
- タイムアウトした場合:深刻な混雑と判断し、cwndを初期値まで戻してスロースタートからやり直します。
少しずつ増やし、ロスしたら大きく減らすこのギザギザの動きを、AIMD(加算的増加・乗算的減少)と呼びます。現在のLinuxやWindowsではCUBIC、GoogleはBBRといった改良版のアルゴリズムが使われていますが、「混雑を探りながら送る量を調整する」という基本は同じです。
「でもYouTubeは途切れないよね?」
ここまで調べて、新しい疑問が出てきました。ロスがあると音声通話は音が途切れるのに、YouTubeは途切れ途切れにならず、一旦止まって「くるくる」してから再生が再開されます。この違いは何なのか。
答えは、リアルタイム性が必要かどうかでした。
YouTubeのような録画済みの動画は、再生している位置より先の部分を前もってダウンロードして貯めています(バッファ)。転送には再送の仕組みがあるので、ロスした分は送り直されます。再送している間もバッファに貯めた分で再生が続くため、少しのロスなら見ている側は気づきません。ロスや減速が続いてバッファを使い切ったときに初めて、再生が止まります。さらに、回線が細いと判断すると画質を自動で下げてデータ量を減らします(アダプティブビットレート)。
一方、音声通話やビデオ会議は、相手が今話している内容を一瞬で届けなければ会話が成り立ちません。遅れて再送されたデータは使い道がないので、再送せずに捨てて先に進みます。そのため、ロスが音切れや映像の乱れとしてそのまま表に出ます。
| 録画済み動画(YouTubeなど) | 通話・ビデオ会議 | |
|---|---|---|
| 遅延の許容 | 数秒〜数十秒でもよい | 0.1〜0.3秒程度が限度 |
| ロスしたとき | 再送する | 再送せずに捨てる |
| 体感 | 一時停止、画質低下 | 音切れ、映像の乱れ |
ライブ配信はその中間で、遅延を小さくするほどバッファも小さくなり、止まりやすくなります。
YouTubeは実はUDPも使っている
もう一つ意外だったのが、YouTubeはTCPだけでなく、UDPの上で動くQUIC(HTTP/3で使われるプロトコル)も使っていることです。
UDP自体は再送も順序管理もしません。QUICはその代わりに、順序管理、再送、輻輳制御をUDPの上で自前で実装しています。つまり「UDPだから再送しない」のではなく、「UDPは何もしないので、必要な機能はその上に作る」というのが正確です。IPが運ぶことに専念し、信頼性は上の層に任せるという考え方が、ここでも生きています。
現場でどう効く?おまじないだった adjust-mss の意味
ここまでの話が一番つながったのが、ルータの adjust-mss の設定でした。
これまでルータを設定するとき、ip tcp adjust-mss auto をおまじないのように入れることがありました。ただ、入れない構成もあって、何が違うのかはよく分かっていませんでした。TCPの仕組みを調べてみて、ようやく意味が分かりました。
adjust-mss は何をしているのか
TCPは3ウェイハンドシェイクのとき、「1回に送るデータの最大サイズ」であるMSS(Maximum Segment Size)を相手に伝えます。PCは自分のLANのMTU(通常1500バイト)しか知らないので、そこからIPヘッダ20バイトとTCPヘッダ20バイトを引いた1460バイトをMSSとして申告します。
ところが、経路の途中にPPPoEのような区間があると、PPPoEのヘッダが増えるぶん、通せるパケットの最大サイズ(MTU)が小さくなります。NTTのフレッツ回線のPPPoEでは、MTUを1454バイトにするのが一般的です。
adjust-mss は、ルータを通過するTCPのSYNパケットに書かれたMSSの値を、ルータが小さく書き換える機能です。両端のホストは最初から小さいサイズで送るので、途中で大きすぎて通れない、ということが起きなくなります。
NEC IXルータでは、PPPoEのインターフェースに次のように設定します(抜粋)。
interface GigaEthernet0.1
encapsulation pppoe
ip tcp adjust-mss autoencapsulation pppoe:このインターフェースでPPPoEを使う設定です。ip tcp adjust-mss auto:通過するTCPのSYNのMSSを書き換えます。autoは、そのインターフェースのMTUからMSSを自動計算する指定です(MTU 1454なら1414)。
Cisco IOSなら、インターフェースで ip tcp adjust-mss 1414 のように値を直接指定します。
入れないと何が起きるのか
本来は、大きすぎて通せないパケットを受け取ったルータが、ICMPで「サイズを小さくして」と送信元に知らせ、送信元がサイズを下げる仕組み(Path MTU Discovery)があります。
ところが、途中のFWや相手のサーバ側でこのICMPが捨てられていると、送信元は気づかないまま大きなパケットを送り続け、すべて途中で捨てられます。ハンドシェイクのような小さいパケットは通るので、次のような分かりにくい症状になります。
- pingは通るのに、Webページが一部だけ表示されない
- ログインはできるのに、ファイル転送が途中で止まる
入れる・入れないの判断
判断のポイントは、経路の途中にMTUが1500バイトより小さい区間があるかどうかです。
| 回線・構成 | MTUの目安 | adjust-mss |
|---|---|---|
| PPPoE(IPv4) | 1454バイトなど | 必要 |
| IPoE(IPv4 over IPv6:MAP-E、DS-Lite) | 1460バイト程度 | 必要 |
| IPsec VPN、GRE | 構成によって小さくなる | 必要 |
| 通常のLAN、MTU 1500のままの経路 | 1500バイト | 不要(入れても実質変わらない) |
私が「入れないこともあった」のは、その構成にMTUの小さい区間がなかったからでした。逆に、MTU 1500の経路で auto を入れても計算結果は1460になるだけなので、害はほとんどありません。おまじないとして入れていたのは、結果的には安全側の判断だったわけです。
なお、adjust-mss が効くのはTCPだけです。UDPやQUICはMSSを交渉しないので、この方法では救えません。
他にもこんな場面で効く
ここからは私自身の経験ではありませんが、TCPの仕組みを知っていると役立つ場面です。
- FWのステートフルインスペクション:FWはTCPのコネクションの状態(SYN、SYN/ACK、ACK)を追跡しています。行きと帰りで別のFWを通る非対称ルーティングになると、片方のFWはコネクションの始まりを見ていないため、通信を落とします。
- QUICの扱い:FWでSSLインスペクションをかける場合、QUIC(UDP/443)は中身を検査しにくいため、QUICをブロックしてブラウザをTCPに切り替えさせる設定がよく使われます(製品やバージョンによってはQUICの検査に対応しているものもあります)。
- 速度が出ないときの切り分け:遅延の大きい拠点間で速度が出ないときは、前述の「ウインドウサイズ ÷ RTT」の上限に当たっていないかを疑えます。
- パケットロスの影響の読み方:TCPはロスを輻輳と判断して大きく減速するので、ロス率がわずかでも体感速度は大きく落ちることがあります。
まとめ:ネスペで狙われるポイント
IPが再送しないのは、運ぶことに専念させてネットワークを単純かつ高速にし、信頼性は通信の両端のTCPに任せる設計だからでした。
ネスペの問題文で引っかからないために、押さえておきたいポイントは次のとおりです。
- IPはコネクションレス型で、順序管理、再送、フロー制御、輻輳制御を行わない。これらはTCPの役割
- フロー制御は受信側を守る仕組み(rwnd)、輻輳制御はネットワークを守る仕組み(cwnd)
- 輻輳制御はホストのTCPが行い、QoSはルータやスイッチが行う。IPヘッダのDSCPやECNは目印にすぎない
- スロースタートは小さく始めて指数的に増やし、輻輳回避は閾値を超えたら線形に増やす
- 再送は、タイムアウト(RTO)と重複ACK3回による高速再送の2通り
- MSSはTCPの機能なので、adjust-mss が効くのはTCPだけ
普段何気なく使っているIPですが、「何をしないか」を知ると、上のTCPやQoS、MTUの設定まで一本の線でつながりました。今後は自宅ラボで、ICMPを止めて実際にMTUの問題を起こし、adjust-mss で解消するところまで検証してみる予定です。

コメントを残す