6-1 MPLS 基礎 — ラベルで転送する仕組みと LSP の作られ方
ラベルで転送する MPLS を csr1000v 4 台の実機で扱います。LDP が配ったラベルを LIB と LFIB の差で読み分け、出口の手前で外す PHP と、経路が変わると使うラベルだけが入れ替わる様子を逐語の show 出力で確かめます。
1. 前節の振り返りと本節の内容
前章の最終節 5-11 QoS トラブルシュート では、組んだ QoS が効いていないときに、分類・マーキング・キューイングのどの段で崩れているかを特定する手順を扱いました。第 5 章を通しての主題は、1 つの機器あるいは 1 本の経路の中で通信に優先順位をつけることでした。
本章の主題は、その経路そのものをどう作るかです。拠点と拠点をどう結ぶか、という視点に変わります。その 1 節目である本節は、ラベルで転送する MPLS (Multi-Protocol Label Switching) を扱います。
MPLS という言葉は本書の最初のページにも出てきました。1-1 ネットワークの基本概念 では、広域を自前で敷設するのは現実的でないため通信事業者の回線を契約する、という文脈で「専用線・MPLS・インターネット VPN など」と回線メニューの 1 つとして挙げています。本節はその中身を開けます。
何が IP 転送と違うのか
第 3 章で扱った IP ルーティングでは、ルータは受け取ったパケットの宛先 IP アドレスを見て、経路表の中からいちばん長く一致するプレフィックスを選びます (最長一致)。MPLS の網の中では、これが変わります。入口のルータがパケットに固定長の番号を貼り、以降のルータはその番号だけを見て転送します。宛先 IP アドレスは読みません。
ここで「ラベルのほうが速いから MPLS が生まれた」と要約したくなりますが、その言い方は原典に無いものを足しています。MPLS のアーキテクチャを定義した RFC 3031 §2.1 は、この方式の利点を 5 つ挙げています。1 つ目はこうです。
MPLS forwarding can be done by switches which are capable of doing label lookup and replacement, but are either not capable of analyzing the network layer headers, or are not capable of analyzing the network layer headers at adequate speed. — RFC 3031 §2.1
「ネットワーク層ヘッダを解析できない、あるいは十分な速度で解析できない装置でも、ラベルの検索と置換ならできる」— 速度で勝るという話ではなく、当時のハードウェアでの実行可能性の話です。
そして 5 つ目には、こう書かれています。
Sometimes it is desirable to force a packet to follow a particular route which is explicitly chosen at or before the time the packet enters the network, rather than being chosen by the normal dynamic routing algorithm as the packet travels through the network. This may be done as a matter of policy, or to support traffic engineering. — RFC 3031 §2.1
経路を明示的に選ぶこと (トラフィックエンジニアリング) は、後から見つかった応用ではなく、最初から挙げられている動機です。 残りの 3 つも「入口で FEC を決められる」「入口ごとに違う扱いができる」「分類がどれだけ複雑になっても中継ルータには波及しない」で、いずれも入口で決めて中では番号だけ見るという構造から出てきます。
一方、顧客ごとの経路表を運ぶ用途 (MPLS L3VPN) は、この 5 つには入っていません。別の RFC が定める応用で、§12 で予告します。
本節では、csr1000v 4 台で組んだ MPLS 網の上で、ラベルは誰が決めて、どこで付け替わり、どこで外れるのかを、実機の show 出力で 1 本の経路について追い切ります。
2. 登場人物と 1 パケットの旅
2.1 用語は 2 つの軸に分かれる
MPLS の説明でつまずきやすいのは、装置の種別を表す語とその経路上での位置を表す語が混ざって出てくる点です。この 2 つは別の軸です。
| 軸 | 語 | 意味 |
|---|---|---|
| 装置の種別 | LSR (Label Switching Router) | ラベルを扱えるルータ全般 |
| 装置の種別 | LER (Label Edge Router) | MPLS 網の縁にいて、IP の世界と接する LSR |
| 経路上の位置 | ingress | その LSP の入口。ラベルを貼る (push) |
| 経路上の位置 | transit | 途中。ラベルを付け替える (swap) |
| 経路上の位置 | penultimate | 出口の 1 つ手前。条件が揃えばここでラベルを外す (pop・§7) |
| 経路上の位置 | egress | その LSP の出口 |
位置は装置の属性ではなく、LSP ごとに決まります。 本節のラボでは R3 は「出口の 1 つ手前」ですが、向きが逆の経路では途中の 1 台にすぎません。同じ機器が経路によって別の役を演じます。
残りの用語も並べておきます。
- FEC (Forwarding Equivalence Class): 同じ扱いを受けるパケットの集合。本節では「宛先が 10.0.4.0/24 のパケット」がひとまとまりの FEC です。
- LSP (Label Switched Path): ある FEC のパケットが通る、ラベルで作られた片方向の道。
- LDP (Label Distribution Protocol): 隣り合う LSR どうしがラベルを配り合うプロトコル。
2.2 1 パケットの旅
用語を並べただけでは動きが見えないので、先に 1 つのパケットを最後まで追います。数値はすべてこのあと実機で確かめるものです。
要点は 1 つです。ラベルの値を決めるのは、そのパケットを受け取る側 (下流) の LSR で、送る側 (上流) はそれをそのまま使います。
3. ラベルの中身
ラベルは 32 ビットのかたまりで、データリンク層ヘッダの後ろ、ネットワーク層ヘッダの手前に入ります。RFC 3032 の記述はそのまま次のとおりです。
The label stack entries appear AFTER the data link layer headers, but BEFORE any network layer headers. — RFC 3032 §2.1
L2 でも L3 でもない位置にあることから、L2.5 と呼ばれます。5-2 マーキング体系 で「L2 と L3 の中間に位置づけられる L2.5 の MPLS ラベル」と触れたのは、この構造のことです。
| フィールド | ビット数 | 役割 |
|---|---|---|
| Label | 20 | 転送に使う番号 |
| Traffic Class (旧 EXP) | 3 | 優先度の印 |
| S (Bottom of Stack) | 1 | このラベルが最下段かどうか |
| TTL | 8 | ループ防止のホップ数。IP ヘッダの TTL とは別物 |
3.1 3 ビットの印 — 5-2 で預けた宿題
5-2 では、優先度の印が階層ごとに別の場所にあること (L2 は 802.1Q タグ内の CoS、L3 は IP ヘッダの DS フィールド、L2.5 は MPLS の 3 ビット) を確認し、その 3 ビットの詳細は本章に預けてありました。
まず名前です。RFC 3032 はこのフィールドを EXP (Experimental Use) と定義していましたが、実験用という名前が誤解を招いたため、RFC 5462 が TC (Traffic Class) へ改名しました。改名の理由は原文にこう書かれています。
The designation “for experimental use” has led other Standards Development Organizations (SDOs) and implementors to assume that it is possible to use the field for other purposes. This document changes the name of the field to clearly indicate its use as a traffic classification field. — RFC 5462 §1 Introduction
ただし Cisco の CLI と show 出力は現在も Exp と表示します。 本節の後半で出てくる [MPLS: Label 19 Exp 0] がその表記です。規格上は TC、機器の画面上は Exp と覚えておくと、実機を触ったときに戸惑いません。
次に幅です。3 ビットは 8 通りしか表せません。 5-2 で扱った DSCP は 6 ビット 64 通りですから、DSCP をそのままラベルの印へ写すことはできず、64 通りを 8 通りへ畳むことになります。
ここで大事なのは、畳む動作は設定しなくても既に起きていることです。本ラボでは TC に関する設定を一切していません。その状態で印を付けたパケットを流し、ラベルが乗っている区間 (R1 → R2) を捕まえてラベルの中身を読むと、こうなります。
! R1 から ping 10.0.4.20 source Loopback0 tos 160 (IP precedence 5) を 5 回
! R2 の受信側でキャプチャした MPLS フレームの先頭
0000: 525400E0 29E05254 00E45F31 88470001
0010: 3BFF45A0 ...
!
! 先頭から数えて 0x0C-0x0D = 88 47 … イーサタイプ (MPLS unicast)
! 0x0E-0x11 = 00 01 3B FF … 32 ビットのラベルエントリ
! → Label = 19 / TC(EXP) = 5 / S = 1 / TTL = 255 (5 パケットとも同じ)
! 0x12 以降 = 45 A0 ... … ここから内側の IP ヘッダ送った IP パケットの precedence は 5 で、ラベルの TC も 5 になっています。
この測定には限界が 2 つあります。1 つは、印を付けたのが R1 自身が出したパケットであること (端末側の ping に ToS を指定する手段が本ラボの環境に無いため)。端末から流したトラフィックで同じことが起きるかは確かめていません。もう 1 つは、比較対象として precedence 0 のラベルも撮ろうとしたのですが、コマンドが受け付けられず precedence 0 側のラベル値は取れていないことです。
DSCP の上位 3 ビット (= IP precedence) が、何も設定しなくてもそのまま TC へ写ります。 ここで注意したいのは、§8 以降に出てくる Exp 0 は、この動きの証拠にも反証にもならないことです。Exp 0 は「写像が起きていない」でも「precedence 0 を写した結果」でも同じ値になります。印の付いていないトラフィックをいくら見ても、この 2 つは区別できません。 上の測定に意味があるのは、印を付けた側を撮ったからです。
写るのは上位 3 ビットだけです。ただし顧客の IP ヘッダそのものは書き換わりません。 上のキャプチャでラベルの直後に続く内側 IP ヘッダは 45 A0 で始まっており、送ったときの ToS 0xA0 (DSCP 40) がそのまま残っています。分解能が落ちるのは「ラベルへ写したコピー」のほうで、5-2 で扱った DSCP は IP ヘッダに乗ったまま網を通り抜けます。
網の中の LSR が見るのは 3 ビットに畳まれたコピーなので、網の中でどこまで細かく扱い分けられるかがここで決まります。ただし §7 で見るとおり出口の 1 つ手前でラベルは外れるので、このコピーを見られるのはラベルが乗っている区間だけです。どう写すか、出口で何をするかは事業者と顧客の間で決める設計事項で、本節では扱いません。
3.2 S ビット — ラベルは積める
S ビットが 1 なら、そのラベルが最下段で、次に来るのは L3 ヘッダです。0 なら、その下にもう 1 枚ラベルがあります。つまりラベルは重ねられます。 本節はグローバルな経路表だけを扱うので登場するラベルは常に 1 枚ですが、S ビットが存在する理由は重ねられることにあります。2 枚重ねの実物は 6-2 で扱います。
3.3 予約ラベル
0 から 15 までは特別な用途に予約されています。RFC 3032 §2.1 が定義しているのは次の 4 つです。
| 値 | 名前 |
|---|---|
| 0 | IPv4 Explicit NULL Label |
| 1 | Router Alert Label |
| 2 | IPv6 Explicit NULL Label |
| 3 | Implicit NULL Label |
このうち 3 の Implicit NULL が本節の後半で主役になります。RFC 3032 の定義はこうです。
A value of 3 represents the “Implicit NULL Label”. This is a label that an LSR may assign and distribute, but which never actually appears in the encapsulation. — RFC 3032 §2.1
「配ることはあるが、実際のパケットには決して現れない」ラベルです。何のためにあるのかは §7 で確かめます。
残りの 4 から 15 について、RFC 3032 は「予約」とだけ書いていました。その後 RFC 7274 が登録簿を Special-Purpose MPLS Label Values と改称し、その前後で 4 (RFC 9994)・7 (RFC 6790)・13 (RFC 5586)・14 (RFC 3429)・15 (RFC 7274) に用途が割り当てられています (割り当てた RFC は値ごとに違い、RFC 7274 自身が割り当てたのは 15 です)。「4 以降は未使用」で止めると 2001 年時点の知識になります。
4. ラボ構成
csr1000v を 4 台つないで MPLS 網を作り、両端に検証用の端末を置きます。4 台とも同じソフトウェアです。
Cisco IOS XE Software, Version 17.03.08a以降に出てくる出力・既定値は、すべてこのバージョンで実測したものです。
| ノード | 役割 | Loopback0 | 主なインタフェース |
|---|---|---|---|
| R1 | ingress LER | 1.1.1.1/32 | Gi2 = 10.0.1.1/24 (顧客側) / Gi3 = 10.10.12.1/30 (→R2) / Gi4 = 10.10.13.1/30 (→R3) |
| R2 | transit LSR | 2.2.2.2/32 | Gi2 = 10.10.12.2/30 / Gi3 = 10.10.23.1/30 |
| R3 | penultimate LSR | 3.3.3.3/32 | Gi2 = 10.10.23.2/30 / Gi3 = 10.10.34.1/30 / Gi4 = 10.10.13.2/30 |
| R4 | egress LER | 4.4.4.4/32 | Gi2 = 10.10.34.2/30 / Gi3 = 10.0.4.1/24 (顧客側) |
| PC1 | 送信側の端末 | — | 10.0.1.10/24 |
| PC2 | 受信側の端末 | — | 10.0.4.20/24 |
4.1 設定は 3 種類に分けて考える
インタフェースは役割ごとに設定が違います。この区別を間違えると、エラーは出ないのに MPLS が成立しません。
掲載する設定は実機の show running-config interface からの抜粋です。
interface GigabitEthernet3
description to R2 Gi2 (core / primary)
ip address 10.10.12.1 255.255.255.252
ip ospf 1 area 0
ip ospf cost 3
negotiation auto
mpls ip
no mop enabled
no mop sysid
endコア向けのインタフェースには ip ospf と mpls ip の両方を入れます。一方、顧客セグメント側は次のようになります。
interface GigabitEthernet2
description PC1 LAN (customer side / no MPLS)
ip address 10.0.1.1 255.255.255.0
ip ospf 1 area 0
negotiation auto
no mop enabled
no mop sysid
endmpls ip がありません。ラベルを載せるのは網の中の区間だけで、顧客が受け取るのは素の IP パケットです。ただし ip ospf 1 area 0 は入れます。ここを外すと 10.0.1.0/24 が IGP に載らず、PC2 から PC1 への復路が消えます。本節が主に追う 10.0.4.0/24 の経路は R4 Gi3 側なので、そちらを OSPF から外すと今度は追う対象そのものが無くなります。顧客側のインタフェースは、MPLS には入れないが IGP には入れる、という扱いです。
Loopback0 にも ip ospf 1 area 0 が要ります。理由は次項の LDP セッションにあります。グローバル側は次の 2 か所です。
router ospf 1
router-id 1.1.1.1mpls ldp router-id Loopback0 force上の 2 つを別々に撮っているのには理由があります。
show running-config | include ^mpls|^router ospfのように行頭一致で抜き出すと、router ospf 1の子行であるrouter-id 1.1.1.1が落ちます。| includeは行単位のフィルタで、ブロックの中身までは連れてこないためです。掲載用には| section router ospfのようにブロックごと撮るほうが安全です。
この抜粋に mpls label protocol ldp が出てこないのは、IOS-XE の既定のラベル配布プロトコルが LDP で、既定値は running-config に表示されないためです (本ラボでは明示的に投入していますが、表示されません)。書いても構いませんが、必須の 1 行ではありません。
mpls ldp router-id Loopback0 force の末尾の force は、「安定させる」という意味ではなく その場で即座に反映するという意味です。R2 で試すと、こうなります。
! (1) 開始時 — mpls ldp router-id Loopback0 force
Local LDP Identifier:
2.2.2.2:0
! (2) mpls ldp router-id GigabitEthernet2 force を投入した直後
Local LDP Identifier:
10.10.12.2:0
! (3) mpls ldp router-id Loopback0 force で戻した後
Local LDP Identifier:
2.2.2.2:0
State: Oper; Msgs sent/rcvd: 13/13; Downstream
State: Oper; Msgs sent/rcvd: 13/13; Downstream指定を変えた瞬間に識別子が入れ替わっています。 確かめられたのはここまでで、セッションが実際に張り直されたかどうかは、この観測だけでは言えません (Msgs sent/rcvd は機器ごと・セッションごとの累積値なので、別の機器や別の時刻の値と比べても意味がありません)。
この 1 行をまったく書かなかったときに何が選ばれるかは、本ラボでは確かめていません。分かっているのは、識別子が LDP の接続先アドレスそのものになることと、それを設定で固定できることです。
4.2 LDP セッションを確認する
Peer LDP Ident: 3.3.3.3:0; Local LDP Ident 1.1.1.1:0
TCP connection: 3.3.3.3.22186 - 1.1.1.1.646
State: Oper; Msgs sent/rcvd: 19/19; Downstream
Up time: 00:05:59
LDP discovery sources:
GigabitEthernet4, Src IP addr: 10.10.13.2
Addresses bound to peer LDP Ident:
3.3.3.3 10.10.23.2 10.10.34.1 10.10.13.2 R1 から見た R3 とのセッションです。読みどころが 3 つあります。
Local LDP Ident 1.1.1.1:0— 識別子が Loopback0 のアドレスになっています。この識別子へ TCP で接続するので、Loopback0 が IGP に載っていないとセッションが張れません。4.1 で Loopback0 を OSPF に入れたのはこのためです。TCP connection: ... - 1.1.1.1.646— LDP セッションは TCP の 646 番で張られます。GigabitEthernet4— これは OSPF コスト 100 を入れたバックアップリンクです。既定では通らない経路でも、LDP のセッションは張られています。 この事実が §6 で効いてきます。
show mpls interfaces で、MPLS が有効なインタフェースを確認できます。
Interface IP Tunnel BGP Static Operational
GigabitEthernet3 Yes (ldp) No No No Yes
GigabitEthernet4 Yes (ldp) No No No Yes R1 で有効なのは Gi3 と Gi4 だけで、顧客側の Gi2 と管理用の Gi1 は並んでいません。設計どおりです。
ラベルの割当範囲も見ておきます。
Downstream Generic label region: Min/Max label: 16/1048575予約されている 0 から 15 を避けて 16 から始まります。この先に出てくるラベル値が 19 や 20 なのは、範囲の先頭付近から順に払い出されているからです。
5. ラベルは誰が決めるのか
宛先 10.0.4.0/24 に対して、4 台がそれぞれ自分のラベルをどう決めたかを並べます。show mpls ldp bindings の local binding が「自分が配った値」です。
| LSR | local binding |
|---|---|
| R1 | 20 |
| R2 | 19 |
| R3 | 20 |
| R4 | imp-null |
R1 と R3 がどちらも 20 を選んでいます。 これは珍しいことではありません。本ラボで LDP が配ったラベルをすべて並べると、10 個の FEC のうち 4 つで R1 と R3 の値が一致していました (数値の一致が 3 つ、imp-null どうしの一致が 1 つ)。4 台は同じ機種・同じソフトウェアで、同じ範囲の先頭から順に払い出しているので、こうした一致は珍しくありません。ただし揃うのが普通というわけでもなく、一致するかどうかは規格の保証外です。
そもそも規格は、ラベルの値を「その場限りのもの」として定義しています。
A label is a short, fixed length, locally significant identifier which is used to identify a FEC. — RFC 3031 §3.1
locally significant — 意味を持つ範囲がその場に限られる、という一語がすべてです。R1 の 20 は R1 の表の中でだけ意味を持ち、R3 の 20 とは何の関係もありません。値が一致するかどうかは規格の関心事ですらなく、どう割り当てるかは各 LSR に委ねられています。
したがって「ラベルの値が機器ごとに違う」ことを、ローカルな意味しか持たないことの証拠にはできません。 示すべきなのは値の相違ではなく、値の帰属です。
5.1 上流は下流が配った値を使う
その帰属を確かめるには、各 LSR の転送表 (LFIB) と、隣の LSR の local binding を突き合わせます。
! ===== [R1] show mpls forwarding-table 10.0.4.0 24 =====
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
20 19 10.0.4.0/24 0 Gi3 10.10.12.2
! ===== [R2] show mpls forwarding-table 10.0.4.0 24 ===== (以降は同じ列見出しなので省略)
19 20 10.0.4.0/24 1420 Gi3 10.10.23.2
! ===== [R3] show mpls forwarding-table 10.0.4.0 24 =====
20 Pop Label 10.0.4.0/24 1864 Gi3 10.10.34.2
! ===== [R4] show mpls forwarding-table 10.0.4.0 24 =====
None No Label 10.0.4.0/24 0 punt読み方は「Local Label で入ってきたら、Outgoing Label に付け替えて Outgoing interface から出す」です。
- R1 の Outgoing Label は 19。これは R2 の
local bindingと同じ値です。 - R2 の Outgoing Label は 20。これは R3 の
local bindingと同じ値です。
貼る値は毎回、次に渡す相手が配ってきたものです。 連鎖が 2 段そろっているので、これは偶然の一致ではありません。
5.2 入口でラベルを貼るのは LFIB ではない
R1 の LFIB には行がありますが、Bytes Label Switched は 0 のままです。これは動いていないという意味ではありません。この列は「ラベル付きで入ってきたパケット」を数えるもので、R1 に入ってくるのは PC1 からの素の IP パケットだからです。
なお Bytes Label Switched は累積カウンタなので、撮った時刻が違えば値も変わります (本節の別の場所には同じ R2 の行が別の値で出てきます)。本節はこの列を主張の根拠に使いません。
では R1 はどこでラベルを貼っているのか。IP の転送表 (CEF) の側です。
10.0.4.0/24, epoch 2
dflt local label info: global/20 [0x3]
nexthop 10.10.12.2 GigabitEthernet3 label 19-(local:20)最後の 1 行に両方が書かれています。label 19 が貼る値 (R2 の値)、(local:20) が R1 自身が配っている値です。ラベルを貼る判断は宛先 IP の最長一致と同時に行われ、その結果が CEF のエントリに焼き込まれています。
6. 配られた全部と、いま使う 1 本
ここまで local binding だけを見てきましたが、show mpls ldp bindings にはもう 1 種類の行があります。R1 の出力をそのまま示します。
lib entry: 10.0.4.0/24, rev 18
local binding: label: 20
remote binding: lsr: 2.2.2.2:0, label: 19
remote binding: lsr: 3.3.3.3:0, label: 20remote binding が 2 行あります。 R2 (2.2.2.2) から 19、R3 (3.3.3.3) から 20。R3 経由はコスト 100 のバックアップ経路で、いま使っていません。それでも広告は届き、R1 はそれを捨てずに持っています。
この表を LIB (Label Information Base) と呼びます。一方、§5.1 で見た show mpls forwarding-table の表は LFIB (Label Forwarding Information Base) です。同じ FEC について、LIB には 3 行、LFIB には 1 行しかありません。
LIB は「誰が何を配ってきたか」の記録、LFIB は「いまどれを使うか」の判断です。 使わない広告を捨てずに持っておくことで、経路が変わったときに配り直しを待たずに切り替えられます。
なお R3 の LIB はもっと賑やかで、remote binding が 3 件あります。出口側の R4 からの広告に加えて、上流の R1 と R2 が配った値まで持っています。LDP は隣接している相手すべてにラベルを配るので、こうなります。
この記事で扱っている範囲について: ここで見た「最短経路でない隣接からの広告も保持する」という動作は、RFC 5036 が liberal label retention と呼ぶ振る舞いに一致します。ただし IOS-XE の既定がそれであると明記した Cisco の資料は見つけられていません (明記があるのは IOS-XR の資料です)。本節はあくまで「この機器・このバージョンで実測するとこう動いた」として記録します。
7. 出口の手前でラベルを外す — PHP
R4 の local binding だけが数値ではなく imp-null でした。もう一度、R4 の出力を見ます。
lib entry: 10.0.4.0/24, rev 6
local binding: label: imp-null
remote binding: lsr: 3.3.3.3:0, label: 20imp-null は §3.3 で見た予約ラベル 3 の Implicit NULL です。R4 はこれを R3 へ配っています。受け取った側の R3 の LFIB はこうなります。
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
20 Pop Label 10.0.4.0/24 1864 Gi3 10.10.34.2 Outgoing Label の列が Pop Label になっています。 付け替える値がないので、R3 はラベルを外して素の IP パケットとして R4 へ渡します。この動作を PHP (Penultimate Hop Popping、最後から 2 番目のホップでのラベル除去) と呼びます。
紛らわしい略語: 5-2 で扱った PHB (Per-Hop Behavior) とは別物です。PHB は「印を見た機器がどう扱うか」の規定、PHP は「出口の 1 つ手前でラベルを外す」という転送の動作です。
外した結果、R4 は同じ FEC についてこうなります。
None No Label 10.0.4.0/24 0 puntLocal Label が None です。R4 はこの FEC に数値のラベルを割り当てていないので、ラベルで引く表に入る余地がありません。届いたときにはもうラベルは無く、普通の IP パケットとして処理されます。
7.1 出口の手前で外す理由
出口の R4 で外しても動作しますが、その場合 R4 は「ラベルを外す」処理と「宛先 IP を引く」処理を続けて行うことになります。手前で外しておけば、R4 は届いた素の IP パケットを 1 回引くだけで済みます。出口の仕事を 1 回分減らすのが PHP の狙いです。
7.2 imp-null が配られる条件
R4 が imp-null を配ったのは、10.0.4.0/24 が R4 に直結しているプレフィックスだからです。R4 の Loopback0 である 4.4.4.4/32 も同様です。
lib entry: 4.4.4.4/32, rev 2
local binding: label: imp-null
remote binding: lsr: 3.3.3.3:0, label: 19「出口の LSR は常に imp-null を配る」ではありません。 本ラボで imp-null が付いていたのは、その LSR に直結しているプレフィックスだけでした (4 台分の show mpls ldp bindings を全件見て確認しています)。
規格の側は、ラベルを 1 つ手前で外す条件をこう定めています。
the penultimate node pops the label stack only if this is specifically requested by the egress node, OR if the next node in the LSP does not support MPLS — RFC 3031 §3.16
imp-null の広告が、この「egress からの要求」にあたります。どのプレフィックスについて要求するかは実装の判断で、本ラボの IOS-XE ではそれが直結のプレフィックスと一致していました。
8. 通しで見る
ここまで各機器の表を個別に見てきました。1 本の経路として通しで見るには、入口の R1 から traceroute を打ちます。
Type escape sequence to abort.
Tracing the route to 10.0.4.20
VRF info: (vrf in name/id, vrf out name/id)
1 10.10.12.2 [MPLS: Label 19 Exp 0] 3 msec
2 10.10.23.2 [MPLS: Label 20 Exp 0] 2 msec
3 10.10.34.2 4 msec
4 10.0.4.20 3 msec各行のラベル表示は、そのホップに届いた時点でパケットが背負っていたラベルです。
- 1 行目 (R2 に届いた時点): ラベル 19 — R1 が貼った値
- 2 行目 (R3 に届いた時点): ラベル 20 — R2 が付け替えた値
- 3 行目 (R4 に届いた時点): ラベル表示なし — R3 が外した後
- 4 行目: 宛先の PC2
§5 から §7 で個別に見たものが、そのまま 1 本に並んでいます。 末尾の Exp 0 については §3.1 のとおりで、この表示だけでは「印が付いていない」のか「precedence 0 が写った」のかは区別できません (上の traceroute は ToS を指定していません)。
2 点、読み方の注意があります。
- この表示は、TTL の伝播が既定のまま有効であることを前提にしています。 次の §9 でこの前提を外すと、この表示自体が変わります。
- 各行の時間を距離として読まないでください。 同じ経路を測り直すだけで値は動きます (この節の 3 ホップ目は 4 msec ですが、§9.1 に載せた同じ経路の測定では 2 msec でした)。本ラボの規模では、時間の列から読み取れることはほとんどありません。
9. TTL の伝播は制御できる
§3 で見たとおり、ラベルには IP ヘッダとは別に 8 ビットの TTL があります。既定では、入口でラベルを貼るときに IP の TTL がラベルの TTL へ写され、ラベルを外すノードで IP ヘッダへ書き戻されます。本節のラボは PHP が効いているので、外すのは出口の R4 ではなく その 1 つ手前の R3 です (§7)。その結果、MPLS 網の中の各ホップが、外から見ても 1 ホップとして数えられます。
顧客側の PC1 から traceroute を打つと、既定ではこう見えます。
traceroute to 10.0.4.20 (10.0.4.20), 8 hops max, 46 byte packets
1 10.0.1.1 0.553 ms
2 10.10.12.2 2.477 ms
3 10.10.23.2 1.696 ms
4 10.10.34.2 2.371 ms
5 10.0.4.20 2.390 msR1・R2・R3・R4 が全部見えています。事業者の立場からすると、顧客に網の中の構成が見えている状態です。これを止める設定が no mpls ip propagate-ttl です。
入口の R1 に no mpls ip propagate-ttl forwarded を入れると、顧客側の見え方はこうなります。
traceroute to 10.0.4.20 (10.0.4.20), 8 hops max, 46 byte packets
1 10.0.1.1 0.535 ms
2 10.10.34.2 2.175 ms
3 10.0.4.20 2.349 ms消えたのは中継の R2 (10.10.12.2) と R3 (10.10.23.2) です。 入口の R1 と出口の R4 (10.10.34.2) は見えたままです。「コアが丸ごと消える」のではなく、通り抜けるだけの LSR が数えられなくなる、という変化です。
9.1 forwarded を付けるかどうかで、誰から隠れるかが変わる
forwarded を付けた状態で、R1 自身から traceroute を打つとこうなります。
1 10.10.12.2 [MPLS: Label 19 Exp 0] 3 msec
2 10.10.23.2 [MPLS: Label 20 Exp 0] 2 msec
3 10.10.34.2 2 msec
4 10.0.4.20 3 msecホップの並びもラベル表示も変わっていません (時間だけは測るたびに動くので、§8 とは 3 ホップ目が違います)。顧客が通す (転送される) パケットからは隠れ、事業者自身が出したパケットからは見える、という状態です。
引数なしの no mpls ip propagate-ttl に変えると、R1 自身から打った結果も変わります。
1 10.10.34.2 2 msec
2 10.0.4.20 3 msec事業者からも見えなくなりました。 運用上は、顧客からは隠しつつ自分の切り分け手段は残したい場面が多いので、この違いは実務的です。
9.2 受信側で TTL を直接読む
traceroute で見えるホップ数は、TTL がいくつ減ったかの間接的な表れです。実際の値を見るために、受信側の PC2 で届いたパケットの IP ヘッダを直接読みました。送出時の TTL は §9.3 で別途実測しており、64 です。
| 設定 | PC2 に届いたときの IP TTL |
|---|---|
| 既定 | 60 |
R1 に no mpls ip propagate-ttl | 62 |
| R1 と R3 の両方に投入 | 62 |
| 既定へ復旧 | 60 |
既定では 4 減り、伝播を止めると 2 減ります。§9 の traceroute で応答したルータが 4 台 (R1・R2・R3・R4) から 2 台 (R1・R4) へ減ったこと (forwarded 付きでも引数なしでも 2 台でした) と、TTL の減り方が同じ数を指しています。 応答した固有 IP の 5 件・3 件には宛先の PC2 が含まれますが、PC2 は TTL を減らさないので数から外しています。traceroute は応答したルータを数え、こちらは TTL の値そのものを読んでいるので、別々の読み方で同じ結論に届いた形です。 traceroute はホップを数え、こちらは TTL の値そのものを読んでいるので、別々の読み方で同じ結論に届いた形です。
9.3 どの装置が TTL を減らしているのか
上の表は「PC2 に届いた時点」の値なので、網の中のどこで減ったのかは見えません。そこで R4 の受信側 (R3 からのリンク) でパケットを直接捕まえ、R3 がラベルを外した直後の IP TTL を読みました。
| 設定 | R4 に届いた時点 | PC2 に届いた時点 |
|---|---|---|
| 既定 | 61 | 60 |
R1 に no mpls ip propagate-ttl | 63 | 62 |
PC1 が送り出す時点の TTL は、R1 の受信側でパケットを捕まえて 64 であることを確かめてあります。
- 既定: R1 が IP の TTL を 63 にしてラベルへ写し、ラベル側の TTL が R2 で 62、R3 で 61 と減ります。R3 はラベルを外すときにこの 61 を IP ヘッダへ書き戻すので、R4 には 61 で届き、R4 が減らして 60 になります。網の中の各ホップがきちんと 1 ずつ数えられています。
- 伝播を止めた場合: R1 が減らした 63 のまま R4 に届いています。 R2 と R3 は IP ヘッダの TTL に触っていません。ラベルを外した R3 も、ラベル側の TTL を IP ヘッダへ書き戻していません。
この「書き戻していない」ことが、§9.2 で TTL が 2 しか減らなかった理由です。
本ラボで確かめていないこと: Cisco の資料は、入口と出口の両方でこの設定を行うよう求めており、その理由として「MPLS 網を出るときの IP TTL が、入るときより大きくなることがある」ことを挙げています。本ラボではその症状は起きませんでした。 上のとおり書き戻しが発生していないためです。どのような条件でその症状が現れるのか (ラベルを出口の装置で外す構成、別のバージョンなど) は確かめていないので、「入口だけで十分」という一般化はしません。 出口側にも設定を入れるかどうかは、自分の構成で同じ測定をしてから決めるべき事項です。
10. 経路が変われば、使うラベルが変わる
最後に、§6 で見た LIB と LFIB の関係を動かして確かめます。バックアップリンク (R1 Gi4 と R3 Gi4) の OSPF コストを 100 から 1 へ下げます。触るのは IGP のコストだけで、LDP には何も設定しません。
まず経路が変わります。
Routing entry for 10.0.4.0/24
Known via "ospf 1", distance 110, metric 3, type intra area
Last update from 10.10.13.2 on GigabitEthernet4, 00:00:20 ago
Routing Descriptor Blocks:
* 10.10.13.2, from 4.4.4.4, 00:00:20 ago, via GigabitEthernet4
Route metric is 3, traffic share count is 1メトリックが 6 から 3 になり、出口が Gi3 から Gi4 へ移りました。ここで 2 つの表を見比べます。
LIB は変わりません。
lib entry: 10.0.4.0/24, rev 18
local binding: label: 20
remote binding: lsr: 2.2.2.2:0, label: 19
remote binding: lsr: 3.3.3.3:0, label: 203 行とも切替前と同じです。R2 が配った 19 も、依然として持っています。
LFIB だけが入れ替わります。
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
20 20 10.0.4.0/24 0 Gi4 10.10.13.2 Outgoing Label が 19 から 20 へ、Outgoing interface が Gi3 から Gi4 へ変わりました。LIB は配布の記録なので変わらず、LFIB は現在の判断なので変わる、という非対称がそのまま出ています。
10.1 同じ 20 が 2 つの別のものを指している
切替後の LFIB の行をもう一度見てください。Local Label が 20、Outgoing Label も 20 です。
- 左の 20 = R1 自身が配った値 (上流から入ってくるときの鍵)
- 右の 20 = R3 が配った値 (下流へ出ていくときに貼る値)
§5 で見た「R1 と R3 がどちらも 20 を選んだ」という重なりが、ここで 1 行の中に並びました。左の 20 と右の 20 は、それぞれ別の LSR が配った値です。§5.1 で追った帰属の連鎖が、切替後は R1 と R3 のあいだで閉じている、というだけの行です。
10.2 ラベルを付け替えるホップが消えた
切替後に R1 から traceroute を打つと、こうなります。
1 10.10.13.2 [MPLS: Label 20 Exp 0] 7 msec
2 10.10.34.2 2 msec
3 10.0.4.20 3 msecラベル表示のある行が 1 つだけになりました。R2 がこの LSP から外れたためです。経路が R1 → R3 → R4 の 2 ホップになったことで、R1 の次が penultimate の R3 になり、付け替え (swap) を行うホップ自体が無くなりました。
では R2 側はどうなったのか。切替の前後で R2 の表を撮ると、こうなります。
! ===== [R2] show mpls ldp bindings 10.0.4.0 24 ===== (切替の前後で同一)
lib entry: 10.0.4.0/24, rev 14
local binding: label: 19
remote binding: lsr: 1.1.1.1:0, label: 20
remote binding: lsr: 3.3.3.3:0, label: 20
! ===== [R2] show mpls forwarding-table 10.0.4.0 24 ===== (切替の前後で同一)
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
19 20 10.0.4.0/24 7814 Gi3 10.10.23.2 何も変わっていません。 R2 は自分のラベル 19 を配り続け、19 で入ってきたら 20 に付け替えて出す、という用意もそのまま持っています。変わったのは「この LSP が R2 を通らなくなった」ことだけで、それは上の traceroute が示しています。
R2 は装置としては LSR のままで、失ったのは「この LSP 上での位置」だけです。§2.1 で位置と装置の種別を分けて整理したのは、この場面のためです。
11. 落とし穴・補足
- 等コストになると LFIB の行が増えます。 本ラボは R1–R2 区間のコストを 3 に置いてあります。(本ラボでは試していない机上の計算ですが) 全リンクを既定のコスト 1 にすると、§10 の切替後に 10.10.23.0/30 が via R2 = 2 / via R3 = 2 の等コストになり、LFIB に 2 行現れる計算になります。「使うのは 1 本」という説明と食い違って見えるので、対比を見せたいときは等コストを避けた設計にしておくと読みやすくなります。本ラボでは切替後に R1 の主要な 5 つのプレフィックス (10.0.4.0/24・10.10.23.0/30・10.10.34.0/30・2.2.2.2/32・4.4.4.4/32) を確認し、いずれも出口が 1 つでした。
- 設定の抜き出し方で中身が落ちます。
show running-config | section mplsだとmpls ipはインタフェース設定の中の 1 行なので、interfaceの行が付かず、どのインタフェースの設定か分からない裸の行が並びます。| include ^router ospfのような行頭一致では、子行のrouter-idが落ちます (§4.1)。掲載用にはshow running-config interface <IF>や| section router ospfのように、ブロックごと撮るほうが確実です。 tracerouteの時間を距離として読まないでください (§8 の再掲)。同じ経路を測り直すだけで値が動きます。pingが表示する TTL は環境によって当てになりません。 本ラボの端末 (BusyBox) では、1 ホップ先を叩いても 4 ホップ先を叩いても同じ値が表示されました。TTL を根拠にするなら、§9.2 のように受信側でパケットを直接読むほうが確実です。- 予約ラベルは 4 以降も割り当てが進んでいます (§3.3)。RFC 3032 だけを見て「4 から 15 は未使用」と覚えると古い知識になります。
mpls label protocol ldpは IOS-XE では既定です (§4.1)。設定例に入っていても「必須の 1 行」ではありません。
12. 次節
本節では、ラベルで転送するとはどういうことかを 1 本の経路について追いました。ラベルの値は下流の LSR が決め、上流はそれを使うこと、配られた広告を全部持つ LIB と使う 1 本だけを持つ LFIB が別物であること、出口の 1 つ手前でラベルが外れること、経路が変わると LFIB だけが入れ替わることを、実機の出力で確かめました。ここまでのラベルは常に 1 枚で、運んでいたのはグローバルな経路表の宛先です。
次節 6-2 MPLS L3VPN では、この仕組みの上に顧客ごとの経路表を載せます。顧客ごとに経路表を分ける VRF、経路を区別するための RD、どの経路をどの顧客に配るかを決める RT、そして事業者側の PE と顧客側の CE の関係が登場します。§3.2 で触れた「ラベルは積める」が、そこで実際の形を取ります。