メインコンテンツへスキップ
  1. ネットワーク 記事一覧/
  2. MPLS記事一覧/

MPLSのラベル操作(push / swap / pop)とPHP

目次

MPLSのラベル操作(push / swap / pop)とPHP

MPLSのルータ(LSR)がパケットに対して行う操作は、ラベルを積むpush、先頭のラベルを付け替えるswap、先頭のラベルを外すpopの3つです。本記事では、1つのパケットが入口のPEから出口のPEまで運ばれる間に各ルータがどの表を引いて何をするか、出口の1つ手前でラベルを外すPHP(Penultimate Hop Popping)とは何かを解説し、IOS XR(XRd)のラボで1ホップずつ確かめます。ラベルの形式はMPLSラベルとラベルスタックで解説しています。

3つの操作と2つの表

操作行うLSR内容
push入口LSR(PE1)ラベルの付いていないIPパケットを受け取り、宛先で決まるFECのラベルを積んで送り出す。
swap中継LSR(P1)先頭のラベルを、次のLSRから受け取ったラベルに付け替える。
pop出口LSRの1つ手前(P2)または出口LSR先頭のラベルを外す。外した結果ラベルが無くなれば、IPパケットとして扱う。

どの表を引くかは、受け取ったパケットにラベルが付いているかで決まります。

受け取ったパケット引く表IOS XRの確認コマンド
ラベル無し(IPパケット)FIB。宛先IPアドレスをロンゲストマッチで検索し、結果に付いているラベルをpushする(RFC 3031のFTN)show cef <プレフィックス> detaillabels imposed {…}
ラベル付きLFIB。先頭のラベル値を索引に、操作(swap / pop)と出力先を引く(同ILM)show mpls forwarding(Local / Outgoing 列)

中継LSRはIPヘッダーを見ません。先頭のラベルだけを引き、Outgoing Labelの値に付け替える(swap)か、Popなら外して送り出します。

show mpls forwardingOutgoing Label列には、ラベル値のほかに次の表示が出ます。

表示意味
数値その値にswapする。
Pop先頭のラベルを外す。次のLSRがこのプレフィックスに対してimplicit-null(3)を配ってきたとき。
Exp-Null-v4先頭のラベルを0(IPv4 Explicit NULL)にswapする。次のLSRがexplicit-nullを配ってきたとき。
Unlabelledラベルを外してIPパケットとして送る。次ホップがMPLSを話さない(CE向けなど)か、次ホップからそのプレフィックスのラベルを受け取っていないとき。
Aggregateラベルを外し、改めてIP検索を行う。集約したプレフィックスやVRFの経路に使われる。

ラベルは1ホップごとに付け替わる

ラベルは隣接する2台の間でだけ意味を持つ値なので、パケットがLSRを通るたびに値が変わります。上の図では、PE1が付けた24003(P1が5.5.5.5/32に割り当てた値)を、P1が30000(P2が同じプレフィックスに割り当てた値)に付け替えています。値の決まり方はLDPの記事で解説します。各LSRは自分のローカルラベルを独立に割り当てるため、隣どうしでたまたま同じ値になることもあります。その場合も付け替えは行われており、値が一致しているだけです。割り当てはルータを再起動すると変わるので、ラベルの値そのものに意味はありません。

PHP(Penultimate Hop Popping)

出口LSRは、自分に直結する経路(ループバックなど)に対してimplicit-null(3) を配ります。これを受け取った1つ手前のLSRは、そのプレフィックス宛てのパケットからラベルを外して(pop)送ります。この動作がPHPです。

PHPの目的は、出口LSRの検索回数を減らすことです(RFC 3031 3.16節)。出口LSRがラベル付きのまま受け取ると、まずLFIBでラベルを引いて「自分宛てなので外す」と判断し、続けてIPヘッダーでFIBを引く、という2回の検索が必要になります。1つ手前でラベルを外しておけば、出口LSRはIPパケットとして受け取り、FIBの検索1回で済みます。

PHPを使わない場合は、出口LSRにexplicit-null(0) を配らせます。1つ手前のLSRはラベルを0にswapして送り、出口LSRはラベル0を外してからIP検索を行います。ラベルのTC(QoSのクラス)を出口LSRまで届けたいときに使います。IOS XRではmpls ldp配下のlabel local advertise explicit-nullで切り替えます。

出口LSRが配る値1つ手前のLSRの操作出口LSRの検索
implicit-null(3、既定)popIP検索1回
explicit-null(0)0にswapラベル検索 + IP検索

PHPはあくまで「最後のラベルを1つ手前で外す」動作です。MPLS VPNのようにラベルが2段ある場合、1つ手前のLSRが外すのは先頭のトランスポートラベルだけで、VPNラベルは出口PEまで届きます。

実機での検証

検証環境

CE1 — PE1 — P1 — P2 — PE2 — CE2 を直列につないでいます。AS 65001のPE1 / P1 / P2 / PE2がMPLSネットワークで、OSPF(area 0、全リンクnetwork point-to-point)で経路を、LDPでラベルを配っています。CE1とCE2はPEとeBGPで経路を交換し、PE1とPE2はLoopback0間のiBGP(next-hop-self)で外部経路のネクストホップを自分のLoopback0にします。CE3 / CE4はVRF CUST-Aの顧客で、本記事ではVPNラベルがPHPで外れないことの確認に使います。

ルータ役割Lo0リンク
CE1顧客側(AS 65101)、192.168.1.0/24を広告1.1.1.1/32Gi0/0/0/0 10.1.2.1
PE1入口 / 出口LSR(AS 65001)2.2.2.2/32Gi0/0/0/0 10.1.2.2 / Gi0/0/0/1 10.2.3.2
P1中継LSR3.3.3.3/32Gi0/0/0/0 10.2.3.3 / Gi0/0/0/1 10.3.4.3
P2中継LSR4.4.4.4/32Gi0/0/0/0 10.3.4.4 / Gi0/0/0/1 10.4.5.4
PE2入口 / 出口LSR(AS 65001)5.5.5.5/32Gi0/0/0/0 10.4.5.5 / Gi0/0/0/1 10.5.6.5
CE2顧客側(AS 65102)、192.168.6.0/24を広告6.6.6.6/32Gi0/0/0/0 10.5.6.6
CE3VRF CUST-Aの顧客側(AS 65107)、192.168.7.0/24を広告7.7.7.7/32Gi0/0/0/0 10.2.7.7(PE1 Gi0/0/0/2)
CE4VRF CUST-Aの顧客側(AS 65108)、192.168.8.0/24を広告8.8.8.8/32Gi0/0/0/0 10.5.8.8(PE2 Gi0/0/0/2)

CE1から192.168.6.1へのpingを、PE1 - P1、P1 - P2、P2 - PE2の3リンクで同時にキャプチャーし、1つのパケットが各リンクでどのラベルを持つかを、各ルータのFIB / LFIBと突き合わせます。

検証のSTEP

STEP操作狙い
0初期状態(既定 = PHP)PE1がpush、P1がswap、P2がpopすること。3リンクのpcapとFIB / LFIBを突き合わせる
1P2の動的ラベルの範囲をmpls label range table 0 30000 1048575に変更ラベルがLSRごとに独立して割り当てられること。P2の割り当てが30000台になり、P1がswapする先の値だけが変わる。範囲の変更はルータの再起動後に有効になる
2PE2にlabel local advertise explicit-nullpopの場所が P2 から PE2 に移り、P2の操作がExp-Null-v4へのswapになること。VPNの2段ではVPNラベルが残ったままPE2に届くこと
3STEP 1・2を削除(最終状態)STEP 0と同じに戻ること

STEP 0:初期状態(既定 = PHP)

PE1は192.168.6.0/24をiBGPでネクストホップ5.5.5.5(PE2のLoopback0)として学んでいるため、pushするラベルは再帰先の5.5.5.5/32のエントリに入っています。

PE1 show cef 5.5.5.5/32 detail(末尾)
   via 10.2.3.3/32, GigabitEthernet0/0/0/1, 6 dependencies, weight 0, class 0 [flags 0x0]
    path-idx 0 NHID 0x4 [0x8a76a5a0 0x0]
    next hop 10.2.3.3/32
    local adjacency
     local label 24004      labels imposed {24003}

labels imposed {24003}が、PE1がpushする値です。続いてP1とP2のLFIBを見ます。

P1 show mpls forwarding
Local  Outgoing    Prefix             Outgoing     Next Hop        Bytes
Label  Label       or ID              Interface                    Switched
------ ----------- ------------------ ------------ --------------- ------------
24000  Pop         2.2.2.2/32         Gi0/0/0/0    10.2.3.2        10426
24001  Pop         4.4.4.4/32         Gi0/0/0/1    10.3.4.4        1230
24002  Pop         10.4.5.0/24        Gi0/0/0/1    10.3.4.4        0
24003  24003       5.5.5.5/32         Gi0/0/0/1    10.3.4.4        7547
P2 show mpls forwarding
Local  Outgoing    Prefix             Outgoing     Next Hop        Bytes
Label  Label       or ID              Interface                    Switched
------ ----------- ------------------ ------------ --------------- ------------
24000  24000       2.2.2.2/32         Gi0/0/0/0    10.3.4.3        9028
24001  Pop         3.3.3.3/32         Gi0/0/0/0    10.3.4.3        1248
24002  Pop         10.2.3.0/24        Gi0/0/0/0    10.3.4.3        0
24003  Pop         5.5.5.5/32         Gi0/0/0/1    10.4.5.5        9148

P1は24003を受けて24003へswapし、P2は24003を受けてPopします。この採取ではP1とP2が5.5.5.5/32に同じ24003を割り当てており、値が一致しています。3リンクのキャプチャーでCE1 - CE2のecho requestを追うと次のようになります。

リンクEtherTypeラベル
PE1 - P10x884724003
P1 - P20x884724003
P2 - PE20x0800(無し)

P2 - PE2でEtherTypeが0x0800に戻り、ラベルが消えています。PHPによってP2が最後のラベルを外したためです。

VRF CUST-Aの経路では、PE1が2つのラベルをpushします。

PE1 show cef vrf CUST-A 192.168.8.0/24 detail(末尾)
   via 5.5.5.5/32, 3 dependencies, recursive [flags 0x6000]
    path-idx 0 NHID 0x0 [0x8857f048 0x0]
    recursion-via-/32
    next hop VRF - 'default', table - 0xe0000000
    next hop 5.5.5.5/32 via 24004/0/21
     next hop 10.2.3.3/32 GigabitEthernet0/0/0/1 labels imposed {24003 24005}

CE3 - CE4のecho requestは3リンクで次のように流れます。

リンクラベル
PE1 - P124003, 24005
P1 - P224003, 24005
P2 - PE224005

P2が外したのは先頭の24003だけで、VPNラベル24005はPE2まで届いています。

STEP 1:P2の動的ラベルの範囲を変更

P2にmpls label range table 0 30000 1048575を投入してP2を再起動すると、P2のローカルラベルが30000台になります。P1のLFIBはswap先だけが変わります。

STEP 1 P1 show mpls forwarding
Local  Outgoing    Prefix             Outgoing     Next Hop        Bytes
Label  Label       or ID              Interface                    Switched
------ ----------- ------------------ ------------ --------------- ------------
24000  Pop         2.2.2.2/32         Gi0/0/0/0    10.2.3.2        19988
24001  Pop         4.4.4.4/32         Gi0/0/0/1    10.3.4.4        840
24002  Pop         10.4.5.0/24        Gi0/0/0/1    10.3.4.4        0
24003  30000       5.5.5.5/32         Gi0/0/0/1    10.3.4.4        6747

P1が受け取る24003は変わらず、送り出す値だけが30000になりました。PE1 - P1は24003のまま、P1 - P2が30000に変わります。CE1のtracerouteにも同じ値が出ます。

STEP 1 CE1 traceroute 192.168.6.1 source 192.168.1.1
 1  10.1.2.2 11 msec  4 msec  4 msec
 2  10.2.3.3 [MPLS: Label 24003 Exp 0] 14 msec  12 msec  13 msec
 3  10.3.4.4 [MPLS: Label 30000 Exp 0] 17 msec  17 msec  12 msec
 4  10.4.5.5 12 msec  13 msec  10 msec
 5  10.5.6.6 18 msec  *  23 msec
P1 - P2でラベル30000になったパケット(No.9)のpcapをダウンロード

STEP 2:PE2にlabel local advertise explicit-null

PE2がimplicit-null(3)ではなくexplicit-null(0)を配るようにすると、P2のOutgoing LabelExp-Null-v4に変わります。

STEP 2 P2 show mpls forwarding
Local  Outgoing    Prefix             Outgoing     Next Hop        Bytes
Label  Label       or ID              Interface                    Switched
------ ----------- ------------------ ------------ --------------- ------------
30000  Exp-Null-v4 5.5.5.5/32         Gi0/0/0/1    10.4.5.5        6684
30001  24000       2.2.2.2/32         Gi0/0/0/0    10.3.4.3        14107
30002  Pop         3.3.3.3/32         Gi0/0/0/0    10.3.4.3        1608
30003  Pop         10.2.3.0/24        Gi0/0/0/0    10.3.4.3        0

P2はラベルを外さず0にswapするので、P2 - PE2にもMPLSヘッダーが乗ります。VRFのパケットでは0とVPNラベルの2段になります。

STEP 2 P2 - PE2のNo.87 tshark -V(MPLSヘッダー部分)
MultiProtocol Label Switching Header, Label: 0 (IPv4 Explicit-Null), Exp: 0, S: 0, TTL: 252
    0000 0000 0000 0000 0000 .... .... .... = MPLS Label: IPv4 Explicit-Null (0)
    .... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
    .... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
    .... .... .... .... .... .... 1111 1100 = MPLS TTL: 252
MultiProtocol Label Switching Header, Label: 24005, Exp: 0, S: 1, TTL: 254
    0000 0101 1101 1100 0101 .... .... .... = MPLS Label: 24005 (0x05dc5)
    .... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
    .... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
    .... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
Internet Protocol Version 4, Src: 192.168.7.1, Dst: 192.168.8.1
上のtshark出力のパケット(No.87、explicit-nullとVPNラベルの2段)のpcapをダウンロード

先頭のラベルは0でS = 0、2段目の24005でS = 1です。explicit-nullにしても外れるのは先頭だけで、VPNラベルはPE2まで届きます。PE2はラベル0を外してからIP検索を行うため、検索が2回になります。

STEP 3:STEP 1・2を削除(最終状態)

両方の設定を外してP2を再起動すると、P2のラベル範囲は24000台に戻り、Outgoing LabelPopに戻ります。

STEP 3 P2 show mpls forwarding
Local  Outgoing    Prefix             Outgoing     Next Hop        Bytes
Label  Label       or ID              Interface                    Switched
------ ----------- ------------------ ------------ --------------- ------------
24000  Pop         5.5.5.5/32         Gi0/0/0/1    10.4.5.5        7892
24001  24000       2.2.2.2/32         Gi0/0/0/0    10.3.4.3        7050
24002  Pop         3.3.3.3/32         Gi0/0/0/0    10.3.4.3        512
24003  Pop         10.2.3.0/24        Gi0/0/0/0    10.3.4.3        0

再起動でP2の割り当て順が変わり、5.5.5.5/32には24000が付きました。STEP 0と違ってP1の値(24003)と一致しないため、tracerouteでも付け替えが見えます。

STEP 3 CE1 traceroute 192.168.6.1 source 192.168.1.1
 1  10.1.2.2 6 msec  5 msec  5 msec
 2  10.2.3.3 [MPLS: Label 24003 Exp 0] 15 msec  14 msec  13 msec
 3  10.3.4.4 [MPLS: Label 24000 Exp 0] 13 msec  14 msec  21 msec
 4  10.4.5.5 15 msec  15 msec  14 msec
 5  10.5.6.6 19 msec  *  19 msec

VRFのパケットでは、PHPで先頭が外れてVPNラベルだけが残る様子がそのまま出ます。

STEP 3 CE3 traceroute 192.168.8.1 source 192.168.7.1
 1  10.2.7.2 6 msec  14 msec  5 msec
 2  10.2.3.3 [MPLS: Labels 24003/24005 Exp 0] 20 msec  16 msec  16 msec
 3  10.3.4.4 [MPLS: Labels 24000/24005 Exp 0] 17 msec  16 msec  17 msec
 4  10.4.5.5 [MPLS: Label 24005 Exp 0] 17 msec  18 msec  19 msec
 5  10.5.8.8 20 msec  *  18 msec

キャプチャー

3リンクを同時に採取したpcapです。MPLSを含むためフィルターなしで取得しています。

STEP 0 PE1 - P1

STEP 0 P1 - P2

STEP 0 P2 - PE2

STEP 1 PE1 - P1

STEP 1 P1 - P2

STEP 1 P2 - PE2

STEP 2 PE1 - P1

STEP 2 P1 - P2

STEP 2 P2 - PE2

STEP 3 PE1 - P1

STEP 3 P1 - P2

STEP 3 P2 - PE2

検証Configおよびshow結果

各STEPで8台すべてから、次の種類をルータごとに分けて取得しています。検証Configはこの..._run.txtです(最終状態は最後のSTEPのもの)。

ファイル内容
..._show.txtshow version / show interface description / show route / OSPF・LDP・MPLS転送・BGPの一式
..._log.txtそのSTEPの範囲だけに絞ったshow logging。各STEPの開始時にlogmsgでマーカーを入れ、その時刻をshow logging startに指定して取得したもの
..._run.txtそのSTEP時点のshow running-config(=そのSTEPの検証Config)
..._trace.txtコア4台のLDPとLSDのトレース(show mpls ldp trace binding / peer / discovery / route / forwardingshow mpls lsd trace
..._debug.txtCE1とCE3のtraceroute(最終STEPのみ)

STEP 0:初期状態(既定 = PHP)

ルータshow出力syslogrunning-configtrace
CE1showlogrun-
PE1showlogruntrace
P1showlogruntrace
P2showlogruntrace
PE2showlogruntrace
CE2showlogrun-
CE3showlogrun-
CE4showlogrun-

STEP 1:P2の動的ラベルの範囲を変更

ルータshow出力syslogrunning-configtrace
CE1showlogrun-
PE1showlogruntrace
P1showlogruntrace
P2showlogruntrace
PE2showlogruntrace
CE2showlogrun-
CE3showlogrun-
CE4showlogrun-

STEP 2:PE2にlabel local advertise explicit-null

ルータshow出力syslogrunning-configtrace
CE1showlogrun-
PE1showlogruntrace
P1showlogruntrace
P2showlogruntrace
PE2showlogruntrace
CE2showlogrun-
CE3showlogrun-
CE4showlogrun-

STEP 3:STEP 1・2を削除(最終状態)

ルータshow出力syslogrunning-configtracetraceroute
CE1showlogrun-traceroute
PE1showlogruntrace-
P1showlogruntrace-
P2showlogruntrace-
PE2showlogruntrace-
CE2showlogrun--
CE3showlogrun-traceroute
CE4showlogrun--

参考

RFCタイトル概要
RFC 3031Multiprotocol Label Switching ArchitectureNHLFE / ILM / FTN(3.10〜3.12節)、ラベルの付け替え(3.13節)、PHP(3.16節)。
RFC 3032MPLS Label Stack Encoding予約ラベル(implicit-null 3、explicit-null 0)。
RFC 4182Removing a Restriction on the use of MPLS Explicit NULLExplicit NULLをボトム以外にも置けるようにした改訂。

書籍: Luc De Ghein『MPLS Fundamentals』(Cisco Press, 2006)Chapter 3

関連記事