Skip to main content
  1. Network Articles/
  2. MPLS Articles/

MPLS Label Operations (push / swap / pop) and PHP

Table of Contents

MPLS Label Operations (push / swap / pop) and PHP

An MPLS router (LSR) performs three operations on a packet: push to add a label, swap to replace the top label, and pop to remove the top label. This article explains which table each router consults and what it does as a single packet travels from the ingress PE to the egress PE, and what PHP (Penultimate Hop Popping) is, then confirms it hop by hop in an IOS XR (XRd) lab. The label format is covered in MPLS Labels and the Label Stack.

Three operations and two tables

OperationLSR that performs itWhat happens
pushIngress LSR (PE1)Receives an unlabelled IP packet and adds the label of the FEC chosen by the destination.
swapTransit LSR (P1)Replaces the top label with the label received from the next LSR.
popPenultimate LSR (P2) or egress LSRRemoves the top label. If no label remains, the packet is handled as IP.

Which table is consulted depends on whether the received packet carries a label.

Received packetTableIOS XR command
No label (IP packet)FIB. The destination IP address is looked up by longest match and the label attached to the result is pushed (the FTN of RFC 3031)show cef <prefix> detail (labels imposed {…})
LabelledLFIB. The top label value indexes the operation (swap / pop) and the outgoing interface (the ILM of the same RFC)show mpls forwarding (Local / Outgoing columns)

A transit LSR never looks at the IP header. It consults the top label only, and either replaces it with the value in Outgoing Label (swap) or removes it when the entry says Pop.

The Outgoing Label column of show mpls forwarding shows the following in addition to a label value.

DisplayMeaning
A numberSwap to that value.
PopRemove the top label. Shown when the next LSR advertised implicit-null (3) for this prefix.
Exp-Null-v4Swap the top label to 0 (IPv4 Explicit NULL). Shown when the next LSR advertised explicit-null.
UnlabelledRemove the label and send the packet as IP. Shown when the next hop does not speak MPLS (a CE, for example) or has not advertised a label for that prefix.
AggregateRemove the label and perform a fresh IP lookup. Used for aggregated prefixes and VRF routes.

A label is replaced at every hop

A label is only meaningful between two adjacent routers, so its value changes each time the packet passes an LSR. In the figure above, the 24003 that PE1 pushed (the value P1 assigned to 5.5.5.5/32) is replaced by P1 with 30000 (the value P2 assigned to the same prefix). How the values are chosen is covered in the LDP article. Each LSR assigns its local labels independently, so two neighbours may happen to pick the same value. The swap still takes place; only the values coincide. The assignment also changes when a router reboots, so the label value itself carries no meaning.

PHP (Penultimate Hop Popping)

An egress LSR advertises implicit-null (3) for the routes connected to itself, such as its loopback. The LSR one hop before it removes the label from packets destined for that prefix (pop) before forwarding them. That behaviour is PHP.

The purpose of PHP is to reduce the number of lookups at the egress LSR (RFC 3031 section 3.16). If the egress LSR received the packet still labelled, it would first consult the LFIB to decide that the label is its own and must be removed, then consult the FIB with the IP header, which is two lookups. Removing the label one hop earlier lets the egress LSR receive an IP packet and do a single FIB lookup.

To avoid PHP, the egress LSR is made to advertise explicit-null (0). The penultimate LSR swaps the label to 0 and forwards it, and the egress LSR removes label 0 before doing the IP lookup. This is used when the TC field (the QoS class) of the label needs to reach the egress LSR. On IOS XR it is selected with label local advertise explicit-null under mpls ldp.

Value the egress LSR advertisesOperation at the penultimate LSRLookups at the egress LSR
implicit-null (3, default)popOne IP lookup
explicit-null (0)Swap to 0A label lookup plus an IP lookup

PHP only removes the last label one hop early. When there are two labels, as in an MPLS VPN, the penultimate LSR removes only the top transport label, and the VPN label reaches the egress PE.

Lab verification

Lab setup

CE1 — PE1 — P1 — P2 — PE2 — CE2 are connected in a line. PE1 / P1 / P2 / PE2 in AS 65001 form the MPLS network, distributing routes with OSPF (area 0, network point-to-point on every link) and labels with LDP. CE1 and CE2 exchange routes with the PEs over eBGP, and PE1 and PE2 run iBGP between their Loopback0 addresses with next-hop-self so that external routes take their own Loopback0 as the next hop. CE3 and CE4 are customers in VRF CUST-A, used here to confirm that the VPN label is not removed by PHP.

RouterRoleLo0Links
CE1Customer side (AS 65101), advertises 192.168.1.0/241.1.1.1/32Gi0/0/0/0 10.1.2.1
PE1Ingress / egress LSR (AS 65001)2.2.2.2/32Gi0/0/0/0 10.1.2.2 / Gi0/0/0/1 10.2.3.2
P1Transit LSR3.3.3.3/32Gi0/0/0/0 10.2.3.3 / Gi0/0/0/1 10.3.4.3
P2Transit LSR4.4.4.4/32Gi0/0/0/0 10.3.4.4 / Gi0/0/0/1 10.4.5.4
PE2Ingress / egress LSR (AS 65001)5.5.5.5/32Gi0/0/0/0 10.4.5.5 / Gi0/0/0/1 10.5.6.5
CE2Customer side (AS 65102), advertises 192.168.6.0/246.6.6.6/32Gi0/0/0/0 10.5.6.6
CE3Customer side in VRF CUST-A (AS 65107), advertises 192.168.7.0/247.7.7.7/32Gi0/0/0/0 10.2.7.7 (PE1 Gi0/0/0/2)
CE4Customer side in VRF CUST-A (AS 65108), advertises 192.168.8.0/248.8.8.8/32Gi0/0/0/0 10.5.8.8 (PE2 Gi0/0/0/2)

A ping from CE1 to 192.168.6.1 is captured simultaneously on the three links PE1 - P1, P1 - P2 and P2 - PE2, and the label each link carries is matched against the FIB and LFIB of each router.

Verification steps

STEPChangeWhat it shows
0Initial state (PHP, the default)PE1 pushes, P1 swaps and P2 pops. The three captures are matched against the FIB and LFIB
1Change P2’s dynamic label range to mpls label range table 0 30000 1048575Labels are assigned independently by each LSR. P2’s assignment moves into the 30000 range and only the value P1 swaps to changes. The range change takes effect after the router reboots
2label local advertise explicit-null on PE2The pop moves from P2 to PE2 and P2’s operation becomes a swap to Exp-Null-v4. With two labels, the VPN label still reaches PE2
3Remove STEP 1 and STEP 2 (final state)The state returns to that of STEP 0

STEP 0: Initial state (PHP, the default)

PE1 learns 192.168.6.0/24 over iBGP with next hop 5.5.5.5 (PE2’s Loopback0), so the label it pushes is held in the entry for the recursive next hop 5.5.5.5/32.

PE1 show cef 5.5.5.5/32 detail (tail)
   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} is the value PE1 pushes. Next are the LFIBs of P1 and P2.

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 receives 24003 and swaps it to 24003, and P2 receives 24003 and pops it. In this run P1 and P2 both assigned 24003 to 5.5.5.5/32, so the values coincide. Following the CE1 - CE2 echo request through the three captures gives the following.

LinkEtherTypeLabel
PE1 - P10x884724003
P1 - P20x884724003
P2 - PE20x0800(none)

On P2 - PE2 the EtherType is back to 0x0800 and the label is gone, because PHP made P2 remove the last label.

For a route in VRF CUST-A, PE1 pushes two labels.

PE1 show cef vrf CUST-A 192.168.8.0/24 detail (tail)
   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}

The CE3 - CE4 echo request travels through the three links as follows.

LinkLabels
PE1 - P124003, 24005
P1 - P224003, 24005
P2 - PE224005

P2 removed only the top label 24003; the VPN label 24005 reached PE2.

STEP 1: Change P2’s dynamic label range

Configuring mpls label range table 0 30000 1048575 on P2 and rebooting it moves P2’s local labels into the 30000 range. Only the swap target changes in P1’s LFIB.

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

The 24003 that P1 receives is unchanged; only the value it sends becomes 30000. PE1 - P1 still carries 24003 while P1 - P2 changes to 30000. The same values appear in a traceroute from CE1.

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
Download the pcap of the packet carrying label 30000 on P1 - P2 (No.9)

STEP 2: label local advertise explicit-null on PE2

When PE2 advertises explicit-null (0) instead of implicit-null (3), P2’s Outgoing Label becomes Exp-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 swaps to 0 instead of removing the label, so P2 - PE2 also carries an MPLS header. For a VRF packet there are two labels, 0 and the VPN label.

STEP 2 No.87 on P2 - PE2, tshark -V (MPLS headers)
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
Download the pcap of the packet in the tshark output above (No.87, explicit-null over the VPN label)

The top label is 0 with S = 0, and the second label 24005 has S = 1. Even with explicit-null only the top label is affected, and the VPN label reaches PE2. PE2 removes label 0 before the IP lookup, which makes two lookups.

STEP 3: Remove STEP 1 and STEP 2 (final state)

Removing both settings and rebooting P2 returns P2’s label range to the 24000 range and its Outgoing Label to Pop.

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

The reboot changed the order in which P2 assigns labels, and 5.5.5.5/32 received 24000. Unlike STEP 0 this does not match P1’s value (24003), so the replacement is visible in a traceroute as well.

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

For a VRF packet, the top label is removed by PHP and only the VPN label remains.

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

Captures

The pcaps taken simultaneously on the three links. They were captured without a filter because they contain 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

Verification config and show output

The following file types were collected from all eight routers at every STEP, split per router. The verification config is these ..._run.txt files (the final state is the one from the last STEP).

FileContents
..._show.txtshow version / show interface description / show route and the OSPF, LDP, MPLS forwarding and BGP set
..._log.txtshow logging limited to that STEP. A marker is written with logmsg at the start of each STEP and its timestamp passed to show logging start
..._run.txtshow running-config at that STEP (the verification config for that STEP)
..._trace.txtLDP and LSD traces on the four core routers (show mpls ldp trace binding / peer / discovery / route / forwarding, and show mpls lsd trace)
..._debug.txttraceroute from CE1 and CE3 (final STEP only)

STEP 0: Initial state (PHP, the default)

Routershowsyslogrunning-configtrace
CE1showlogrun-
PE1showlogruntrace
P1showlogruntrace
P2showlogruntrace
PE2showlogruntrace
CE2showlogrun-
CE3showlogrun-
CE4showlogrun-

STEP 1: Change P2’s dynamic label range

Routershowsyslogrunning-configtrace
CE1showlogrun-
PE1showlogruntrace
P1showlogruntrace
P2showlogruntrace
PE2showlogruntrace
CE2showlogrun-
CE3showlogrun-
CE4showlogrun-

STEP 2: label local advertise explicit-null on PE2

Routershowsyslogrunning-configtrace
CE1showlogrun-
PE1showlogruntrace
P1showlogruntrace
P2showlogruntrace
PE2showlogruntrace
CE2showlogrun-
CE3showlogrun-
CE4showlogrun-

STEP 3: Remove STEP 1 and STEP 2 (final state)

Routershowsyslogrunning-configtracetraceroute
CE1showlogrun-traceroute
PE1showlogruntrace-
P1showlogruntrace-
P2showlogruntrace-
PE2showlogruntrace-
CE2showlogrun--
CE3showlogrun-traceroute
CE4showlogrun--

References

RFCTitleSummary
RFC 3031Multiprotocol Label Switching ArchitectureNHLFE / ILM / FTN (sections 3.10 to 3.12), label swapping (section 3.13) and PHP (section 3.16).
RFC 3032MPLS Label Stack EncodingReserved labels (implicit-null 3, explicit-null 0).
RFC 4182Removing a Restriction on the use of MPLS Explicit NULLThe revision that allows Explicit NULL outside the bottom of the stack.

Book: Luc De Ghein, MPLS Fundamentals (Cisco Press, 2006), Chapter 3

Related articles