スイッチが A から B へのフレームを初めて受信した際、B の位置は不明ですが、B が正常に受信できる可能性があります。これは、A の入力ポートを学習し、許可された他のポートへ未知の宛先フレームをフロッピング(広範転送)することで実現されます。B が返信すると、逆方向の送信元も学習されます。このプロセスは FDB(転送データベース)の形成を説明しますが、ループがどのように消滅するかまでは説明できません。ループ制御とトンネル拡張には、それぞれ独自のメカニズムが必要です。
問題 本稿の入り口 核心的な区別
宛先 MAC が未学習なのにどうして通信できるのか 3フレーム学習の推論 ソースアドレスを学習し、宛先アドレスを参照
VLAN 内にマルチキャストがあるのに受信できない 転送許可と MDB フロッピング範囲、メンバー、ポート状態
Linux bridge は必ずしも純粋なソフトウェアなのか ブリッジパス 管理インターフェースとハードウェアオフロード
冗長な2本のケーブルでなぜループが発生するのか STP / RSTP 物理トポロジと転送トポロジ
VXLAN で何枚のテーブルを参照するか VTEP パス 内側 MAC、遠端 VTEP、外側ルーティングとネイバー
1500 バイトのトンネルでなぜ送信できないのか MTU 計算例 内側 MTU と外側 IP 長
3つのフレームで学習と転送を理解する
ポート p1、p2、p3 がすべて VLAN 10 に属し、転送が許可されていると仮定します。A は p1 に、B は p2 に、C は p3 にいます。初期状態の FDB は空です。以下では、ローカル終端と特殊アドレスの処理は省略します。
到着したフレーム 学習されるソース位置 宛先に対するテーブル参照 出口
A→B、p1 から入力 (VLAN 10, A) → p1 B は不明 p2、p3 へフロッピング、B は受信可能
B→A、p2 から入力 (VLAN 10, B) → p2 A は p1 にいる p1 のみ
A→B、再度 p1 から入力 A の位置/時間を更新 B は p2 にいる p2 のみ
動的学習には、ポートが学習を許可する状態にあり、対応する入力ルールを通過する必要があります。すべてのフレーム到着が無条件で更新されるわけではありません。FDB のキーには VLAN などのコンテキストも含まれるため、同じ MAC でも異なる VLAN では異なる位置を持つことができます。スイッチングデバイスが維持するのは、各自の観察/制御プレーンから得られた局所情報であり、スイッチ間で自動的に同期されるグローバルハッシュテーブルと解釈してはいけません。
宛先位置が入力ポートと一致する場合、通常のブリッジングではこの転送をフィルタリングします。ヘアピン(Hairpin)機能により、特定のシナリオで同一ポートへの戻り転送を許可できます。この入力フィルタリングは完全なループ防止を意味するものではなく、フレームが他のリンクから戻ってきた場合、再度転送される可能性があります。
フロッピングとエイジングは、1つのパケットのドロップを意味しない
未知ユニキャストは、通常、同一 VLAN 内で、フロッピングが許可され、転送状態にある関連ポートにコピーされます。スイッチの全ポートに無条件で送信されるわけではありません。ブロードキャストも VLAN、分離、制御ポリシーによって制限されます。マルチキャストの場合、IGMP/MLD スヌーピングの MDB メンバーおよびルーターポートに基づいて出口が選択され、リンクローカルマルチキャストには特別なルールがあります。
動的 FDB がエイジアウト(期限切れ)すると、次のフレームは未知ユニキャストとなりフロッピングされる可能性がありますが、これは通常、ターゲットに到達します。必ずしも1つのパケットがドロップされるわけではありません。 未知ユニキャストがポリシーによって禁止されている場合、フロッピングパスが制限されている場合、またはネットワークが混雑している場合にのみ、さらに分析が必要です。ターゲットが受信した後、すぐに学習が回復するかどうかは、学習可能なソースフレームをターゲットが送信しているかどうかにかかっています。
アドレスの移動は、新しい入力からのソーストラフィックによって位置を更新できますが、継続的な往復移動は、重複する MAC アドレスやレイヤー2ループを示している可能性があります。静的、永続、制御プレーン管理、またはハードウェアオフロードのエントリは異なるライフサイクルを持ち、すべてのエントリを固定の 300 秒後に削除されるものとして記述すべきではありません。
スイッチは1つのフレームしか見えないが、どちら半分を学習できるか?
同じ図に「現在の学習テーブル」と「直近の転送結果」を保持します。まず A→B を送信し、次に B→A を送信し、最後に A→B を再送信します。これにより、指向性転送の証拠がどのように生成されるかを確認できます。テーブルクリアは後続の参照に影響しますが、すでに発生した転送を書き換えるものではありません。そのため、クリア後も画面には最後の出口が保持されます。
図を準備しています 再読み込み
スイッチは1つのフレームしか見えないが、どちら半分を学習できるか? 入力ポートはソース MAC の位置を実証しますが、宛先 MAC の位置は独立した証拠が必要です。宛先エントリをエイジアウトすると、再度フロッピングされます。同名 MAC の VLAN キーは独立して管理されます。
{"id":"bridge-local-learning","title":"スイッチは1つのフレームしか見えないが、どちら半分を学習できるか?","summary":"入力ポートはソース MAC の位置を実証しますが、宛先 MAC の位置は独立した証拠が必要です。宛先エントリをエイジアウトすると、再度フロッピングされます。同名 MAC の VLAN キーは独立して管理されます。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><label class=\"form-field\"><span data-i18n=\"src\"></span><select id=\"src\"><option value=\"A\">A</option><option value=\"B\">B</option><option value=\"C\">C</option></select></label><label class=\"form-field\"><span data-i18n=\"dst\"></span><select id=\"dst\"><option value=\"B\">B</option><option value=\"C\">C</option><option value=\"A\">A</option></select></label><label class=\"form-field\"><span data-i18n=\"vid\"></span><select id=\"vid\"><option value=\"10\">10</option><option value=\"20\">20</option></select></label><div class=\"actions\"><button id=\"send\" data-i18n=\"send\"></button><button id=\"age\" data-i18n=\"age\"></button><button id=\"reset\" data-i18n=\"reset\"></button></div><svg id=\"ports\" class=\"diagram\" viewBox=\"0 0 360 180\" role=\"img\" data-i18n-label=\"heading\"></svg><div class=\"metrics\"><div><span data-i18n=\"out\"></span><strong id=\"out\"></strong></div><div><span data-i18n=\"mode\"></span><strong id=\"mode\"></strong></div></div><section class=\"panel\"><h3 data-i18n=\"fdb\"></h3><div id=\"fdb\"></div></section><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#fdb .tr{grid-template-columns:.7fr 1fr 1fr}.metrics strong{font-size:17px}","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 fdb={},last=null;function draw(){table('fdb',[[t('vid'),'MAC','Port'],...[10,20].flatMap(v=>[...'ABC'].map(n=>[v,n,fdb[v+':'+n]??'∅']))]);set('out',last?fmt(last.ports):'∅');set('mode',t(last?(last.known?'known':'flood'):'pending'));graph('ports',[{name:'SW',x:180,y:100},...[...'ABC'].map((name,i)=>({name,x:[45,180,315][i],y:[35,175,35][i],cls:last?.ports.includes(i+1)?'on':'',sub:'p'+(i+1)}))],[[0,1],[0,2],[0,3]]);$('#ports').setAttribute('viewBox','0 0 360 225');$('#fdb').dataset.entries=JSON.stringify(fdb);$('#out').dataset.ports=last?.ports.join(',')||'';}$('#send').onclick=()=>{const v=$('#vid').value,s=$('#src').value,d=$('#dst').value,p='ABC'.indexOf(s)+1;fdb[v+':'+s]=p;const dest=fdb[v+':'+d];last={known:dest!==undefined,ports:dest===undefined?[1,2,3].filter(n=>n!==p):dest===p?[]:[dest]};draw()};$('#age').onclick=()=>{const v=$('#vid').value;Object.keys(fdb).filter(k=>k.startsWith(v+':')).forEach(k=>delete fdb[k]);draw()};$('#reset').onclick=()=>{fdb={};last=null;draw()};draw();","audio":false,"strings":{"age":"この VLAN のエントリをエイジアウト","dst":"宛先","fdb":"現在の局所 FDB","flood":"不明:フロッピング","heading":"スイッチは1つのフレームしか見えないが、どちら半分を学習できるか?","intro":"ソース、宛先、VLAN を選択して送信します。学習テーブルは各観察を保持し、未知のフロッピングと既知のユニキャストを比較します。","known":"既知:指向性転送または同一ポートフィルタ","mode":"テーブル参照結果","out":"直近の転送出口","pending":"未送信","reset":"リセット","scope":"3つのポートはすべて学習と転送を許可します。VLAN10/20 はすべて3ポートをカバーし、A/B/C は p1/p2/p3 に固定されています。通常のユニキャスト、ヘアピン、STP、MDB、ポート分離なし。エイジボタンは選択した VLAN の動的エントリのみをクリアします。","scopeLabel":"モデルの範囲と規約","send":"選択したフレームを送信","src":"ソース","vid":"VLAN"}}
Linux bridge:ソフトウェアオブジェクトでハードウェア転送を管理
Linux bridge はレイヤー2ブリッジングを提供します。veth、TAP、物理インターフェース、または VXLAN デバイスはすべて関連ポートとして機能できます。ホストがこのレイヤー2ネットワークで IP 通信に参加するには、ブリッジマスターデバイスまたは対応する VLAN インターフェースを通じてレイヤー3機能を設定できます。ポートを bridge に追加しても、IP ルーティングが自動的に有効になるわけではありません。
Linux 7.2 の net/bridge/br_private.h では、FDB は MAC と VLAN ID を含むキーを使用し、宛先ポートおよび更新情報を関連付けます。学習および転送パスは br_input.c、br_forward.c で確認できます。
Linux はまた、switchdev を介して FDB などの情報をハードウェアにプッシュでき、データプレーンはフレームごとに CPU を通過する必要はありません。したがって、「Linux bridge はハードウェアより10倍遅く、10 Gb/s 以下しか使用できない」という主張には一般的な根拠がありません。パフォーマンスはパケットサイズ、CPU/NUMA、ドライバー、ルール、およびオフロード能力に基づいて測定する必要があります。Linux switchdev モデル
実際の状態を確認するには、まず読み取り専用コマンドを使用します。デバイス名は例です。
ip - d link show br0
bridge link show
bridge vlan show
bridge fdb show br br0
bridge mdb show
従来の bridge sysfs の ageing_time は clock_t/USER_HZ で表されるため、echo 60 を直接 60 秒と呼んではいけません。ローカルの br_sysfs_br.c と br_stp.c には明確な変換があり、一般的な USER_HZ=100 の場合、1分は 6000 に相当します。より安全なのは、使用しているツールのドキュメントに従って入力単位を確認することです。Linux bridge インターフェースドキュメント
ブリッジフィルタリングとレイヤー3フィルタリングの期待値を混同しない
br_netfilter を使用すると、一部のブリッジトラフィックが対応するレイヤー3 netfilter パスに入力できます。これは歴史的に iptables ルールに使用されてきましたが、純粋なレイヤー2転送がすべての ip/inet ルールを通過するわけではないことを意味しません。nftables の bridge ファミリーは、ブリッジ層を直接処理でき、br_netfilter を一律にロードする必要はありません。nftables ブリッジフィルタリング
トラブルシューティング時には、パケットがブリッジ上で転送されているのか、ローカルに送信されているのか、ルーティングに入っているのかを把握し、対応するフック、ルールカウント、オフロードパスを決定する必要があります。ヘアピン、ポート分離、VLAN フィルタリングは異なる設定であり、1つのファイアウォールスイッチで全転送ポリシーを代替することはできません。
STP:TTL がないレイヤー2転送を生成木で制約する
通常のイーサネットフレームには、IP の TTL のようなホップごとの減衰フィールドはありません。冗長リンクがループを形成すると、ブロードキャスト/未知ユニキャストのコピーが継続的に循環し、同時にソース MAC がポート間でドリフトする可能性があります。STP は物理的な冗長性を保持しつつ、ポートの役割と状態の選択によってループのない転送トポロジを選択します。これは、特定の重複フレームを識別して自動的にデジュープリケーションするものではありません。
三角トポロジ:物理リンクは保持され、転送トポロジはループを除去
A:ルートブリッジ
Bridge ID が最小であると仮定
B:ルートまでのコスト 10
B—A はルートポート
C:ルートまでのコスト 10
C—A はルートポート
コスト 10
コスト 10
B—C コスト 10
B の ID が小さいと仮定すると、C 側のポートは代替/ドロップ状態
B、C はどちらも A への直接接続を優先します。B—C 間はブリッジ ID などのルールで競合解決されます。リンク断線後、検出、役割変更、FDB 収束が必要です。
まず、Bridge ID などのルールに基づいてルートを選択し、非ルートブリッジはルートまでのパスコストおよび後続の競合解決フィールドを比較してルートポートを選択します。各セグメントでは、指定ポートが選択されます。図ではすべてのリンクコストが 10 で、B、C のルートまでの直接コストはどちらも 10 です。相手経由の場合は 20 になります。B—C セグメントでは双方のルートコストが同じであり、B の ID が小さいと仮定すると、B が指定役割を獲得し、C 側は代替/転送しないパスになります。
BPDU はプロトコル制御パケットです。従来の STP は対応する 802.3 長さ/LLC エンキャプスレーションを使用し、一般的な DSAP/SSAP は 0x42 です。出現する 0x0026 の長さを EtherType として記述してはいけません。STP 設定 BPDU、トポロジ変更 BPDU、および RSTP BPDU のフォーマット/タイプは完全に同一ではありません。
RSTP は、役割、エッジポート、およびポイントツーポイントリンクでの Proposal/Agreement を介して、安全な転送変換を高速化します。すべての障害が 1〜3 秒以内に保証されるわけではありません。従来の STP の待機タイマーも、トポロジ、設定、障害検出の影響を受けるため、特定のデフォルトシナリオでの収束時間を固定のパフォーマンス指標として扱うことはできません。Cisco:RSTP メカニズム
BPDU フィルタリング、エッジポート設定、保護機能はアクセス側の役割に基づいて設計する必要があります。BPDU を誤って隠蔽すると、実際のループが保持される可能性があります。Linux bridge で STP が有効になっているかどうか、必要な高速/マルチインスタンスプロトコルがユーザー空間デーモンによって実装されているかどうかを確認する必要があります。インターフェース名が bridge であるからといって、ループ防止が有効であると推論してはいけません。
VXLAN:外側の到達可能性を解決し、内側のネイバー関係を確立する
VXLAN は UDP を介して内側のイーサネットフレームを伝送し、VTEP はエンキャプスレーション/デキャプスレーションのエンドポイントです。基本ヘッダーは 8 バイトで、VNI は 24 ビットを使用し、I フラグは VNI が有効であることを示します。標準の UDP 宛先ポートは 4789 ですが、展開時には互換性のある値を明確に設定する必要があります。VNI は約 1677 万の番号空間を提供しますが、ハードウェアが同じ数のアクティブテナントを収容できることを保証するものではありません。
VXLAN:内側はテナントフレームを伝送し、外側は遠端 VTEP へのみ責任を負う
VTEP A
192.0.2.1
IP Underlay
外側宛先 IP に基づくルーティング
VTEP B
192.0.2.2
外側 IP
IPv4 20 B
UDP
8 B
VXLAN
8 B / VNI
内側 Ethernet
14 B、FCS なし
内側 L3 データ
例 1500 B
外側 Ethernet は描画されていない;これは Underlay の IP MTU には含まれない
この例では外側 IP 長 = 20 + 8 + 8 + 14 + 1500 = 1550 B
追加のタグ、IPv4 オプション、または他のトンネルなし。外側 IPv6 基本ヘッダーはさらに 20 B 増加する。VXLAN 自体には暗号化認証が含まれていない。
A 側のローカルブリッジはまず、宛先 MAC が VXLAN ポートを通じて送信されるべきであることを決定します。VXLAN 転送情報は遠端 VTEP を特定し、外側 IP ルーティングは物理出口を決定し、最後に外側ネイバー解決によって現在のリンクの次のホップ MAC を取得します。外側の次のホップは中間ルーターである可能性があり、必ずしも遠端 VTEP の物理 MAC である必要はありません。相手側は外側を剥がした後、VNI とローカル転送設定に基づいて内側フレームを処理します。RFC 7348:VXLAN
状態 対応する問題
ローカル bridge FDB 内側宛先 MAC がローカルポートかトンネルポートか
VXLAN FDB / 制御プレーンマッピング その MAC またはコピーエントリがどの遠端 VTEP に対応するか
Underlay ルーティング 外側 VTEP IP がどの出口から、どの次のホップを経て到達するか
Underlay ネイバーテーブル 現在の出口の次のホップのリンクアドレスは何か
UDP ソースポートにはフローハッシュ情報が含まれる可能性があり、Underlay ECMP が異なる内側フローを分散するのに役立ちます。これにより NAT トゥルーザーのネゴシエーションが自動的に行われるわけではありません。ファイアウォール、戻りパス、MTU、許可された VTEP にはそれぞれ対応する設定が必要です。VXLAN 自体はテナントコンテンツの暗号化と相手側認証を提供しません。
MTU は外側 IP 長で決済する
内側 VLAN がなく、IPv4 オプションもない例では、内側 L3 は 1500 バイト、内側 Ethernet 14 バイト、VXLAN 8 バイト、UDP 8 バイト、外側 IPv4 20 バイトを加えて、合計 1550 バイトの外側 IP パケット となります。内側 FCS は通常エンキャプスレーションされず、外側 Ethernet は IP MTU の外側にあります。Underlay IP MTU が 1500 のみの場合、同じ仮定では内側 L3 は 1450 バイトを使用できます。外側 IPv6 基本ヘッダーは 40 バイトであるため、1430 バイトとなります。
追加のタグ、拡張ヘッダー、または暗号化トンネルはさらに予算を占有します。物理ポートの MTU を大きく設定するだけでは、すべてのパスと遠端が一致すると推論できません。フラグメンテーション、ドロップ、およびエラーフィードバックは、具体的なプロトコルと実装の制限の影響を受けます。小さな ping は通るが、大きな負荷は通らない場合、内外層の長さとパスの動作をそれぞれ確認する必要があります。
BUM コピーと EVPN:制御プレーンで未知の情報を削減
ブロードキャスト、未知ユニキャスト、マルチキャストは総称して BUM と呼ばれますが、その転送ポリシーは必ずしも完全に同一である必要はありません。VXLAN は対応する Underlay マルチキャストまたはエントリポイントコピーなどのソリューションを使用でき、コピー対象はその VNI の関連遠端メンバーであり、展開されたすべての VTEP ではありません。1つのエントリが3つの遠端にそれぞれ 1 MiB の内側データをコピーする必要がある場合、コピーされた内側データ量のみで 3 MiB となり、外側オーバーヘッドは含まれません。
EVPN は BGP を介して MAC/IP と関連の到達可能性情報を配布し、純粋なデータプレーン学習よりも明確な制御プレーンを提供します。これは Open vSwitch などのスイッチング実装とは異なる概念です。ARP/ND 抑制は、信頼でき有効なバインディングを利用してローカルで一部の解決リクエストに応答しますが、すべてのブロードキャストを排除できるわけではなく、バインディングが期限切れになった後に古い回答を自由に提供することもできません。RFC 8365:EVPN Overlay
MAC の移動、VTEP の障害、コピーメンバーの変化、および基盤ルーティングの収束は依然として処理が必要です。Overlay はレイヤー2の境界をレイヤー3ネットワークを越えて拡張可能ですが、障害影響範囲も拡張する可能性があります。「トンネルがより遠くまで伸びる」ことを「分離がより強力である」と直接見なしてはいけません。
ローカル転送とエンキャプスレーションモデル
以下は、同一 VLAN、すべてのポートが学習/転送を許可、通常のユニキャスト、ヘアピンなしという基本論理のみをシミュレートします。実際の bridge の並行処理、エイジング、または制御パケットはシミュレートしません。
ports = { 10 : { ' p1' , ' p2' , ' p3' } , 20 : { ' p1' , ' p4' } }
fdb = { }
def forward ( vid , ingress , source , dest ) :
assert ingress in ports [ vid ]
fdb [ ( vid , source ) ] = ingress
out = fdb . get ( ( vid , dest ) )
if out is None :
return ports [ vid ] - { ingress }
return { out } if out != ingress else set ( )
assert forward ( 10 , ' p1' , ' A' , ' B' ) == { ' p2' , ' p3' }
assert forward ( 10 , ' p2' , ' B' , ' A' ) == { ' p1' }
assert forward ( 10 , ' p1' , ' A' , ' B' ) == { ' p2' }
assert forward ( 20 , ' p4' , ' B' , ' A' ) == { ' p1' }
assert fdb [ ( 10 , ' B' ) ] == ' p2' and fdb [ ( 20 , ' B' ) ] == ' p4'
assert forward ( 10 , ' p1' , ' D' , ' A' ) == set ( )
vni = 100
header = bytes ( [ 0x 08, 0 , 0 , 0 ] ) + vni . to_bytes ( 3 , ' big' ) + bytes ( 1 )
assert len ( header ) == 8 and header . hex ( ) == ' 0800000000006400'
assert 20 + 8 + 8 + 14 + 1500 == 1550
assert 1500 - ( 20 + 8 + 8 + 14 ) == 1450
assert 1500 - ( 40 + 8 + 8 + 14 ) == 1430
print ( ' 学習/フロッピング/同一ポートフィルタ、VLAN 独立キー、VXLAN エンコーディング、MTU 計算が通過' )
ローカルチェックでは、ブリッジの作成、VXLAN トンネルの確立、またはプロダクションネットワークへのレイヤー2フレームの注入は行われません。
継続的な参照