4000 バイトの IPv4 データグラムが 1500 バイトの出口 MTU に遭遇した場合、3 つのフラグメントに分割されるか、破棄されてエラー通知がトリガーされるかのどちらかになります。鍵となるのは DF(Don't Fragment)ビット、パス、およびエンドポイントの処理です。IPv4 はベストエフォートなデータグラム伝送を提供し、アドレス、長さ、TTL、フラグメントフィールドが、現在のパケットがどのように転送されるかを決定します。信頼性、順序付け、輻輳回復は、それぞれ対応する上位層のメカニズムに依存します。
参照すべき問題 この記事の入り口 最も計算ミスしやすい部分
ヘッダ長とパケット長をどう区別するか フィールドごとの解説とチェックサム IHL × 4、Total Length はヘッダを含む
複数のルートが一致する場合、どちらを選ぶか CIDR と次のホップ 最長プレフィックス、ポリシー、およびネイバー
フラグメントオフセットがなぜ 185 なのか フラグメンテーションの完全な計算例 IP データオフセットは 8 バイト単位
最後のフラグメントを受信したら配信できるか 再構成の条件 総長さ、ギャップ、オーバーラップ、およびタイムアウト
小さなパケットは通るが、大きなパケットは通らない PMTUD サイズ依存の現象と因果関係の証拠
DSCP/ECN はどのように共存するか サービスと輻輳のマーキング 6 ビットの DSCP と 2 ビットの ECN は独立している
アドレスとルーティング:32 ビットアドレスは物理的な位置そのものではない
CIDR プレフィックスは、アドレスをルーティング集約に使用される上位ビットと、残りの部分に分割します。192.0.2.130/26 が属するネットワークは 192.0.2.128/26 であり、マスクは 255.255.255.192 です。通常のブロードキャストサブネットのセマンティクスでは、アドレス範囲は 192.0.2.191 まで続き、その中でネットワークアドレスとブロードキャストアドレスは通常のホストとは異なる用途を持ちます。「サブネットごとに必ず 2 を減算する」というルールを /31 のポイントツーポイントや /32 のホストレートに一般化することはできません。
通常の宛先ルーティングテーブルでは、198.51.100.0/24 に一致するパケットは、同じく一致する 0.0.0.0/0 よりも優先して使用されます。ポリシールーティング、VRF、マルチパスは選択のコンテキストを増やすことができますが、ARP がルーティング判断に代わるわけではありません。ルーティングが出口/次のホップを選択した後に、初めてそのリンクのネイバーマッピングが処理されます。
アドレスは送信者の認証を提供しません。NAT はアドレスおよび関連フィールドを書き換える可能性がありますが、IPv4 を信頼性のある伝送プロトコルにはしません。32 ビットの番号空間はすべてが公開割り当て可能であることを意味するものではなく、歴史的な割り当てプールの枯渇は、すべての地域、機関、および用途が同じ日にアドレスを失うことを意味するものではありません。
基本ヘッダのフィールドごとの理解
IPv4 基本ヘッダ:各行 32 ビット、合計 20 バイト;フィールド幅はビット比率に従う
V=4
IHL
DSCP
ECN
Total Length
Identification
Flags
Fragment Offset
TTL
Protocol
Header Checksum
Source Address
Destination Address
IHL は 4 バイト単位;IHL > 5 の場合、その後にオプションと必要なパディングが続く
図はネットワークバイトオーダーで左から右に配置されています;コードで Flags/Offset を解析する際は、0x4000、0x2000、0x1fff などのマスクを使用してください。
フィールド セマンティクス 解釈の境界
Version / IHL IPv4;ヘッダ長は IHL×4 バイト 最小 20 バイト、最大 60 バイト;5 未満であってはならない
Total Length 現在の IP パケットのヘッダとデータの合計 最大 65535 バイト、イーサネットパディング/FCS を含まない
Identification 再構成が必要なデータグラムに識別子を提供 すべての IPv4 パケットがグローバルにユニークな番号ではない
Flags / Fragment Offset フラグメンテーション禁止、さらにフラグメントあり、データの位置 オフセットはイーサネットヘッダまたは IP ヘッダから始まらない
TTL 転送の存続期間を制限 ルーティング転送時に少なくとも減算される;初期値だけでシステムを正確に特定することはできない
Protocol 上位層を示す(例:TCP 6、UDP 17) ポート番号ではない
Header Checksum 現在の IPv4 ヘッダのチェックサム IP ペイロードをカバーせず、送信元も認証しない
解析時は、まず実際に利用可能なバイトが十分であることを確認し、バージョン、IHL、および Total Length の間の関係をチェックします。イーサネットから受信した追加のパディングを IP データに含めてはいけません。IP Options には独自の形式とコピー属性があり、すべてのフラグメントに同じヘッダが単純にコピーされるとは限りません。RFC 791:IPv4 フォーマットとフラグメンテーション
TTL とヘッダチェックサムがホップごとに更新される理由
ルータは転送時に TTL を更新し、ヘッダが変更されるため、チェックサムも更新する必要があります。ソース/宛先は通常の非 NAT 転送中変更されませんが、それは IP ヘッダ全体が変わらないことを意味するものではありません。TTL が尽きるとパケットは破棄され、プロトコルとリソース/ポリシーの条件が許す場合に ICMP Time Exceeded が生成されます。エラー通知には例外とレート制限があり、すべての破棄に対して可視な ICMP が返されるとは限りません。
IPv4 ヘッダチェックサムは 16 ビットワードに対して 1 の補数和を計算し、その逆数を取ります。桁あふれは下位 16 ビットに折り返されます。完全なヘッダを検証する場合、1 の補数和はすべて 1 になるはずであり、等価な「逆数後の結果」は 0 になります。これは IPv4 ヘッダのみを保護します。TCP/UDP のチェックサムには擬似ヘッダとペイロードのカバレッジルールが別途あり、IPv4 UDP にはゼロチェックサムの特定のセマンティクスもあります。すべての上位層が同じ保証を提供するとは言えません。
末尾のコードは完全なヘッダを構築し、チェックサムを検証し、TTL を 64 から 63 に変更して、古いチェックサムがもはや有効でないことを確認し、再計算を行います。これは単に「ルータはホップごとに 1 を減算する」と覚えるよりも、フィールド間の依存関係をよりよく示しています。
TTL が 1 しか変わらないのに、なぜ古いチェックサムが無効になるのか?
TTL と Protocol で構成される 16 ビットワードを金色で、チェックサムフィールドを青色で示します。両方の変化は同じヘッダ内で発生します。下部には元の値を保持し、再計算で何が修正されたかを確認できるようにしています。ペイロードのスイッチは意図的にヘッダを変更せず、チェックサムのカバレッジ範囲の境界を示しています。
図を準備しています 再読み込み
TTL が 1 しか変わらないのに、なぜ古いチェックサムが無効になるのか? IPv4 ヘッダチェックサムはヘッダフィールドをカバーします。TTL の変更は古いチェックサムを破壊しますが、ペイロードの変更はしません;ヘッダチェックサムからはデータや送信者の信頼性を証明できません。
{"id":"ipv4-checksum-dependency","title":"TTL が 1 しか変わらないのに、なぜ古いチェックサムが無効になるのか?","summary":"IPv4 ヘッダチェックサムはヘッダフィールドをカバーします。TTL の変更は古いチェックサムを破壊しますが、ペイロードの変更はしません;ヘッダチェックサムからはデータや送信者の信頼性を証明できません。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"control\"><label for=\"ttl\" data-i18n=\"ttl\"></label><output for=\"ttl\" id=\"ttl-value\"></output><input id=\"ttl\" type=\"range\" min=\"1\" max=\"64\" value=\"63\" step=\"1\"></div><label class=\"check\"><input type=\"checkbox\" id=\"payload\"><span data-i18n=\"payload\"></span></label><section class=\"panel\"><h3 data-i18n=\"header\"></h3><div id=\"header\"></div></section><div class=\"metrics\"><div><span data-i18n=\"original\"></span><strong id=\"original\"></strong></div><div><span data-i18n=\"test\"></span><strong id=\"test\"></strong></div><div><span data-i18n=\"new\"></span><strong id=\"new\"></strong></div><div><span data-i18n=\"valid\"></span><strong id=\"valid\"></strong></div></div><p id=\"equation\" class=\"formula\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px var(--viz-font-ui);padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 var(--viz-font-ui);overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n#header{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:5px}.metrics strong{font-size:19px}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}const initial=[0x4500,28,0x1234,0,0x4011,0,0xc000,0x020a,0xc633,0x6414];function checksum(words){let sum=words.reduce((a,b)=>a+b,0);while(sum>>>16)sum=(sum&65535)+(sum>>>16);return(~sum)&65535}const old=checksum(initial),hex=n=>'0x'+n.toString(16).padStart(4,'0');function draw(){const h=[...initial],ttl=+$('#ttl').value;h[4]=(ttl<<8)|17;h[5]=old;const test=checksum(h);h[5]=0;const value=checksum(h);h[5]=value;cells('header',h.map((v,i)=>({text:hex(v),cls:i===4?'gold':i===5?'on':''})));set('ttl-value',ttl);set('original',hex(old));set('test',hex(test)+(test===0?' ✓':' ✗'));set('new',hex(value));set('valid',hex(checksum(h))+' ✓');set('equation','payload bit = '+Number($('#payload').checked)+'\\nheader only: checksum = 0 means valid');$('#test').dataset.value=test;$('#new').dataset.value=value;}document.querySelectorAll('input').forEach(e=>e.oninput=draw);draw();","audio":false,"strings":{"header":"ヘッダの 10 個の 16 ビットワード","heading":"TTL が 1 しか変わらないのに、なぜ古いチェックサムが無効になるのか?","intro":"TTL を変更し、古いチェックサム、再計算後のチェックサム、ペイロード変更を比較します。ここでは 16 ビット 1 の補数チェックサムを実際に実行します。","new":"再計算後のチェックサム値","original":"元のヘッダチェックサム値","payload":"ペイロードの 1 ビットを反転","reset":"リセット","scope":"オプションなしの 20 バイト IPv4 ヘッダ、元の TTL 64;メモリ内のパケットバイトのみに計算します。ペイロードは完全な UDP メッセージではなく、上位層のチェックサムや実際の転送はシミュレートしません。","scopeLabel":"モデルの範囲と規約","test":"古いチェックサムを保持した場合の検証値","ttl":"現在の TTL","valid":"再計算後の検証値"}}
フラグメンテーション:データ長に合わせ、フラグメント全体の長さではない
元のデータグラムの Total Length=4000、IHL=5、オプションなしと仮定すると、IP データは 3980 バイトです。出口 MTU=1500 で、各フラグメントは少なくとも 20 バイトのヘッダを保持する必要があります。末尾以外のフラグメントのデータ長は 8 バイトの整数倍である必要があり、最大値は floor((1500−20)/8)×8=1480 バイトです。
4000 バイトの IP データグラムが MTU 1500 を通過:分割されるのは 3980 バイトのデータ
元のパケット:20 バイト IP ヘッダ + 3980 バイト IP データ
データのインデックス 0 … 3979、IP オプションなし、DF=0 と仮定
フラグメント 1:1480 バイトのデータ
offset=0、MF=1
フラグメント 2:1480 バイトのデータ
offset=185、MF=1
フラグメント 3:1020 バイトのデータ
offset=370、MF=0
Total Length = 1500
Total Length = 1500
Total Length = 1040
オフセットは元の IP データ部分から計算され、単位は 8 バイトです。各フラグメントには独自の IP ヘッダが付加され、最初のフラグメントのみがトランスポート層の開始ヘッダを含みます。
フラグメント 元のデータ範囲 データ長 Offset フィールド MF 本フラグメントの Total Length
1 0~1479 1480 0 1 1500
2 1480~2959 1480 185 1 1500
3 2960~3979 1020 370 0 1040
1480/8=185、2960/8=370 です。末尾以外のフラグメントはデータ長 が 8 に合わせられ、1500 バイトのフラグメント全体の長さは 8 の整数倍ではありません。各フラグメントには独自の Total Length、オフセット、MF、およびチェックサムがあり、Identification は同じデータグラムに属するフラグメントを結びつけるために使用されます。TCP/UDP の開始ヘッダは元のデータの先頭だけに位置し、各フラグメントにコピーされるわけではありません。
DF は 16 ビット Flags/Offset ワードの 0x4000、MF は 0x2000、オフセットマスクは 0x1fff です。これは、図で左から数えたフラグビットの番号を最下位ビットの番号と誤認しないようにするためです。DF を設定してもデータが自動的に小さくなるわけではなく、出口に収まらない場合は通常、破棄されて適切なフィードバックが提供されます。
Identification の制約は、ソース、宛先、プロトコル、および再構成のタイムウィンドウと組み合わせて考慮する必要があります。RFC 6864 はフラグメンテーションのない atomic datagram に対して ID の使用要件を緩和しているため、「すべての IP パケットにユニークな ID が必要」とは限りません。高いパケットレートでは、限られた ID 空間と再構成がさらに注目されるようになります。RFC 6864:IPv4 ID のセマンティクス
再構成は区間を埋める必要があり、最後のフラグメントを待つだけではない
MF=0 の最後のフラグメントを受信した後、8×Offset + 本フラグメントのデータ長 によって元の IP データの総長さを得ることができます。この例では 370×8+1020=3980 バイトとなり、元の最初のフラグメントのヘッダ長を加えて 4000 バイトになります。Offset の元の値を最後のフラグメントの Total Length に直接足してはいけません。さらに、最後のフラグメントの IP ヘッダをデータ範囲に再度含めてはいけません。
総長さが分かっても不十分で、前の区間にギャップがないことを確認し、対応するオーバーラップ、境界、およびリソースのチェックを行う必要があります。フラグメントは順序不同で到着する可能性があります。通常の IP 転送パスではホップごとの再構成は必要ありませんが、ファイアウォールや NAT などの中間処理では、その機能のために再構成が行われる可能性があります。タイムアウトまたはリソース制限により再構成が失敗した場合、IP 層自体は特定のフラグメントの再送を要求しません。上位層が再送するかどうか、およびどのように再送するかはプロトコルに依存します。
再構成タイムアウトは実装および設定によって決定され、ネットワーク全体の統一された定数ではありません。Linux 7.2 の IP_FRAG_TIME は 30×HZ であり、設定可能な ipfrag_time の初期化に使用されます。これは依然としてその実装の基準値であり、実際のネットワーク上のすべてのデバイスを表すものではありません。フラグメンテーションは中間デバイスの処理をより複雑にするため、現代のアプリケーションは通常、適切なパケット分割によってこれを回避したいと考えています。
最後のフラグメントが届いたのに、なぜまだ配信できないのか?
最後に最後のフラグメントを配信し、中間のフラグメントを補完することで、「長さが分かること」と「すでに揃っていること」の違いを観察します。各ボタン上の Offset はパケットフィールドであり、区間図上の位置はすでに 8 倍されています。同じフラグメントを重複して配信しても、既存のカバレッジを再利用するだけで、受信済みバイト数を虚増させることはできません。
C = 8 ⌊ 8 MT U − 20 ⌋ , L d a t a = 8 O ff se t l a s t + L l a s t
図を準備しています 再読み込み
最後のフラグメントが届いたのに、なぜまだ配信できないのか? MF=0 は終点を明らかにするだけです。再構成には、終点からゼロまでの間にギャップがないことが要求されます。Offset の単位は 8 バイトであり、重複配信は他の場所の穴を埋めることはできません。
{"id":"ipv4-fragment-coverage","title":"最後のフラグメントが届いたのに、なぜまだ配信できないのか?","summary":"MF=0 は終点を明らかにするだけです。再構成には、終点からゼロまでの間にギャップがないことが要求されます。Offset の単位は 8 バイトであり、重複配信は他の場所の穴を埋めることはできません。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"mtu\"><button data-mode=\"576\" data-i18n=\"m576\"></button><button data-mode=\"1280\" data-i18n=\"m1280\"></button><button data-mode=\"1500\" data-i18n=\"m1500\"></button></div><div class=\"fragment-area\"><div id=\"fragments\" class=\"choices\"></div><p id=\"fragment-info\"></p></div><div class=\"actions\"><button id=\"duplicate\" data-i18n=\"duplicate\"></button><button id=\"reset\" data-i18n=\"reset\"></button></div><div id=\"ranges\" class=\"coverage\"></div><div class=\"legend\"><span data-i18n=\"receivedLegend\"></span><span class=\"second\" data-i18n=\"missingLegend\"></span></div><div class=\"metrics\"><div><span data-i18n=\"known\"></span><strong id=\"known\"></strong></div><div><span data-i18n=\"received\"></span><strong id=\"received\"></strong></div><div><span data-i18n=\"ready\"></span><strong id=\"ready\"></strong></div></div><p id=\"equation\" class=\"formula\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px var(--viz-font-ui);padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 var(--viz-font-ui);overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n.fragment-area{position:relative}#fragment-info{position:absolute;inset:auto 0 0;margin:0;padding:16px 8px;height:96px;display:flex;align-items:center;font-size:13px;color:var(--muted)}#fragments{grid-template-columns:repeat(4,minmax(0,1fr))}#fragments button{min-height:96px;white-space:pre-line;font:12px/1.5 var(--viz-font-ui)}.coverage{display:flex;gap:2px;height:42px;margin:14px 0}.coverage i{min-width:0;background:var(--second-soft);border-bottom:3px solid var(--second);font:12px/39px var(--viz-font-ui);text-align:center;font-style:normal}.coverage i.on{background:var(--accent-soft);border-color:var(--accent)}.metrics strong{font-size:18px}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}let mtu=1500,pieces=[],received=new Set,last=null;function reset(){const chunk=Math.floor((mtu-20)/8)*8;pieces=[];for(let start=0;start<3980;start+=chunk)pieces.push({start,end:Math.min(start+chunk,3980)});received=new Set;last=null;draw()}function draw(){const bytes=[...received].reduce((s,i)=>s+pieces[i].end-pieces[i].start,0),known=received.has(pieces.length-1),ready=bytes===3980;const box=$('#fragments');if(!box.children.length)for(let i=0;i<8;i++){const b=document.createElement('button');b.dataset.fragment=i;b.onclick=()=>{received.add(i);last=i;draw()};box.append(b)}[...box.children].forEach((b,i)=>{const p=pieces[i];b.disabled=!p||received.has(i);b.style.visibility=p?'visible':'hidden';b.textContent=p?'#'+(i+1)+' '+(received.has(i)?'✓':'→')+'\\nOffset '+p.start/8+'\\nMF '+Number(i<pieces.length-1):'·'});$('#ranges').replaceChildren(...pieces.map((p,i)=>{const e=document.createElement('i');e.style.flex=String(p.end-p.start);e.className=received.has(i)?'on':'';e.textContent=p.end-p.start>=398?'#'+(i+1):'';e.title='['+p.start+','+p.end+')';return e;}));set('fragment-info',t('splitSummary').replace('{count}',pieces.length).replace('{chunk}',Math.floor((mtu-20)/8)*8));$('#fragment-info').style.visibility=pieces.length<=4?'visible':'hidden';set('known',known?3980:t('unknown'));set('received',bytes);set('ready',t(ready?'yes':'no'));set('equation','chunk = floor(('+mtu+' − 20)/8)×8 = '+Math.floor((mtu-20)/8)*8+'\\nend = Offset×8 + fragment data\\ncoverage = '+bytes+' / 3980');$('#duplicate').disabled=last===null;$('#ready').dataset.ready=String(ready);$('#known').dataset.known=String(known);$('#ranges').dataset.pieces=JSON.stringify(pieces);pressed(String(mtu));}$('#duplicate').onclick=()=>{received.add(last);draw()};$('#reset').onclick=reset;document.querySelectorAll('[data-mode]').forEach(b=>b.onclick=()=>{mtu=+b.dataset.mode;reset()});reset();","audio":false,"strings":{"deliver":"フラグメントを配信","duplicate":"最後の配信を重複","heading":"最後のフラグメントが届いたのに、なぜまだ配信できないのか?","intro":"MTU を変更し、任意のフラグメントの配信順序を選択します。総長さと受信済みの区間はそれぞれ保持されます。","known":"データ総長 / B","m1280":"1280","m1500":"1500","m576":"576","missingLegend":"ギャップあり","mtu":"出口 MTU(B)","no":"まだ不可能","ready":"再構成配信可能か","received":"受信済みデータ / B","receivedLegend":"受信済み","reset":"リセット","scope":"固定の 4000 バイト、オプションなしの IPv4 データグラム、20 バイトのヘッダ、3980 バイトのデータ;合法でオーバーラップしないフラグメントのみを提供し、タイムアウトとリソース回収は無視します。MTU を変更して新しい再構成を開始します。","scopeLabel":"モデルの範囲と規約","splitSummary":"{count} 個のフラグメント、フラグメントあたりのデータ上限 {chunk} B。","unknown":"不明","yes":"可能"}}
PMTUD:エラー通知がエンドポイントのパケットサイズ調整を支援する
古典的な IPv4 PMTUD では、エンドポイントは DF パケットを送信し、中間の出口 MTU が不十分な場合、ルータは破棄し、条件に従って ICMP Destination Unreachable Type 3 Code 4 を返し、MTU などの情報を含めます。エンドポイントはこれに基づいてパス推定を更新し、トランスポート/アプリケーション層が後続のパケット分割を調整します。これは、元のパケットの DF を自動的にクリアして送信を続けるわけではありません。RFC 1191
必要な ICMP がフィルタリングされる場合、エンドポイントは過大なパケットを継続して再送し、ブラックホールを形成する可能性があります。しかし、「小さな ping は通るが、大きな ping は通らない」のはサイズに関連する問題を示すだけであり、フィルタリング、レート制限、または異なるパスである可能性もあります。検証には、探知サイズ、プロトコル、および方向を制御し、出入口または ICMP の証拠を観察する必要があり、1 回の探知だけで結論を下すことはできません。
TCP MSS 通告は、対向側が送信する TCP データの規模を制約しますが、それは全体の MTU とは等しくなく、UDP はカバーしません。MSS clamping は特定の TCP パス問題を緩和できますが、その根拠となる PMTU が不完全である可能性があり、パスが変化する可能性もあるため、すべての ICMP がシャットダウンされているシナリオにおける必然的な修復策ではありません。PLPMTUD/DPLPMTUD は、パケット分割層の探知と確認メカニズムを利用して利用可能なサイズを発見するのを助けますが、そのステートマシンは正しく実装されている必要があります。RFC 8899:データグラム伝送の DPLPMTUD
DSCP:マーキングはネットワークポリシーによって実現される必要がある
IPv4 の 2 番目のバイトの上位 6 ビットは DSCP、下位 2 ビットは ECN であり、ECN は「DSCP の下位 2 ビット」ではありません。DSCP はホップごとの転送動作を選択し、デバイスがそれを信頼するか、再マーキングするか、整形するか、どのキューにマッピングするかは、ネットワークポリシーによって決定されます。RFC 2474:DS フィールド
CS クラス、AF クラス、および EF は異なるサービス設計を表します。AF の異なるドロップ優先度は、対応するクラス内での処理次元であり、すべてのコードポイントを数字の大きさで統一された高低順に並べることはできません。EF の一般的なコードポイントは 10 進数の 46 ですが、それは任意のデバイス上の「無限の最高優先度」を意味するものではありません。低遅延動作には、サービスレート、アクセス制御、およびスケジューリングの制約の設定が必要です。RFC 3246:EF PHB
例えば、DSCP=46、ECN=ECT(0)=2 の場合、完全なバイトは (46<<2)|2=0xBA になります。DSCP を変更する際は、必要な ECN ビットを保持し、輻輳信号を破壊しないようにするために、バイト全体を安易に上書きしてはいけません。
ECN:まずネゴシエーションがあり、その後輻輳通知を解釈する
ECN 2 ビット 意味
00 Not-ECT
10 ECT(0)
01 ECT(1)
11 CE、輻輳を経験
RFC 3168 の古典的な TCP ECN の例では、SYN は TCP ECE/CWR フラグを使用してネゴシエーションを表現し、SYN-ACK は対応する応答を使用します。これは、初期 SYN の IP ヘッダに ECT を書き込むことでネゴシエーションを行うわけではありません。その後、適切なデータパケットに ECT をマークでき、ECN をサポートするネットワークノードは、対応する輻輳条件で CE をマークできます。受信側は ACK の ECE で報告し、送信側は輻輳応答を実行し、CWR で応答済みであることを示します。RFC 3168:古典的な ECN
CE は、それ以降パケットが決して失われないことを保証するものではありません。キュー、深刻な輻輳、およびサポートされていないパスにより、パケットは依然としてドロップされる可能性があります。送信側のウィンドウ応答は使用されている輻輳アルゴリズムに依存し、一律に「毎回半分にする」と呼べるものではありません。DCTCP などには異なるフィードバック処理があります。後続の仕様では一部の実験的制限が緩和されているため、上記のプロセスを明確に古典的なベースラインとして扱い、すべての現代の ECN の派生方式をカバーするためにこれを使用しないでください。RFC 8311:ECN 実験的境界の更新
ローカル構築、フラグメンテーション、およびチェックサム
import struct
from ipaddress import IPv4Address , IPv4Network
def checksum ( data ) :
assert len ( data ) % 2 == 0
total = sum ( struct . unpack ( ' !%d H' % ( len ( data ) / / 2 ) , data ) )
while total > > 16 :
total = ( total & 0x ffff) + ( total > > 16 )
return ( ~ total ) & 0x ffff
header = bytearray ( struct . pack ( ' !BBHHHBBH4s4s' ,
0x 45, ( 46 < < 2 ) | 2 , 4000 , 0x 1234, 0 , 64 , 17 , 0 ,
IPv4Address ( ' 192.0.2.10' ) . packed , IPv4Address ( ' 198.51.100.20' ) . packed ) )
header [ 10 : 12 ] = struct . pack ( ' !H' , checksum ( header ) )
assert checksum ( header ) == 0
assert header [ 1 ] == 0x BA
header [ 8 ] = 63
assert checksum ( header ) != 0
header [ 10 : 12 ] = bytes ( 2 )
header [ 10 : 12 ] = struct . pack ( ' !H' , checksum ( header ) )
assert checksum ( header ) == 0
payload = bytes ( i % 251 for i in range ( 3980 ) )
chunk = ( ( 1500 - 20 ) / / 8 ) * 8
fragments = [ ]
for start in range ( 0 , len ( payload ) , chunk ) :
data = payload [ start : start + chunk ]
fragments . append ( ( start / / 8 , int ( start + len ( data ) < len ( payload ) ) , len ( data ) + 20 , data ) )
assert [ f [ : 3 ] for f in fragments ] == [ ( 0 , 1 , 1500 ) , ( 185 , 1 , 1500 ) , ( 370 , 0 , 1040 ) ]
assert b ' ' . join ( f [ 3 ] for f in fragments ) == payload
assert fragments [ - 1 ] [ 0 ] * 8 + len ( fragments [ - 1 ] [ 3 ] ) + 20 == 4000
assert str ( IPv4Network ( ' 192.0.2.130/26' , strict = False ) ) == ' 192.0.2.128/26'
print ( ' IPv4 ヘッダチェックサム、TTL 更新、DS バイト、フラグメント区間、および CIDR チェックが通過' )
これはオプションなしの教育用パケットのローカル検証であり、探知トラフィックの送信、MTU/MSS の変更、または輻輳制御設定の調整は行われていません。
継続的な参照