MPLS Labels and the Label Stack
An MPLS label is attached to a packet as a 4-byte label stack entry defined in RFC 3032. This article explains the contents of those 4 bytes, how several labels are stacked, and the label values that are reserved, then captures labeled packets in an IOS XR (XRd) lab to confirm it. The role of the label and terms such as LSR and LSP are covered in What Is MPLS.
Label Stack Entry Format
| Field | Bits | Meaning |
|---|---|---|
| Label | 20 | Label value, 0 to 1048575. Values 0 to 15 are reserved for special purposes (see below). |
| EXP / TC | 3 | Carries the QoS class. RFC 3032 only defined it as “experimental use” (EXP); RFC 5462 renamed it TC (Traffic Class). Neither the size nor the position changed, and IOS XR and Wireshark still say EXP, so this site calls it EXP. IOS XR still calls it EXP in show output and configuration, and by default copies the IP Precedence (upper 3 bits of the DSCP) into it when the label is pushed. |
| S (Bottom of Stack) | 1 | Set to 1 only on the last (bottom) entry. The receiver uses it to find the end of the label stack. |
| TTL (Time to Live) | 8 | Same role as the IP TTL. The IP TTL is copied in when the first label is pushed, only the label TTL is decremented at each LSR, and it is written back to the IP TTL when the label is popped. A packet whose TTL reaches 0 is not forwarded. |
Labels that IOS XR assigns dynamically start at 24000 by default (show mpls label range).
The Label Stack
Label stack entries sit right after the Layer 2 header and right before the Layer 3 header, as many as needed. The first is the top and the last is the bottom, and forwarding looks only at the top label.
On Ethernet, the EtherType 0x8847 (unicast) or 0x8848 (multicast) says that a label stack follows (RFC 3032 section 5). The label stack itself has no field that says whether the payload is IPv4 or IPv6 (section 2.2). The LSR that pops the last label tells the payload type from the bottom label value or from the first byte of the IP header (the version).
The depth of the stack depends on the application: one entry for IGP prefixes carried by LDP, two in MPLS VPN (one to reach the egress PE and one to identify the VPN), and one more on a traffic engineering backup path. The lab in this article observes both a global route (one entry) and an MPLS VPN route (two entries).
Reserved Labels (0 to 15)
Label values 0 to 15 are reserved for special purposes. RFC 3032 defines 0 to 3, and 4 to 15 are managed by IANA (Special-Purpose MPLS Label Values).
| Value | Name | Meaning |
|---|---|---|
| 0 | IPv4 Explicit NULL | The receiving LSR pops this entry and forwards by the label beneath it, or by the IPv4 header if there is none. RFC 3032 allowed it only at the bottom; RFC 4182 removed that restriction. |
| 1 | Router Alert | Legal anywhere except the bottom. When on top, the packet is handed to software and the label is pushed back before forwarding. |
| 2 | IPv6 Explicit NULL | The IPv6 counterpart of 0. |
| 3 | Implicit NULL | Never appears on the wire. The egress LSR distributes it to tell the previous LSR to pop the label (PHP). |
| 4 | MPLS Network Actions | RFC 9994. |
| 7 | Entropy Label Indicator (ELI) | RFC 6790. Says that an entropy label for load balancing follows. |
| 13 | Generic Associated Channel Label (GAL) | RFC 5586. Control channel for OAM and similar. |
| 14 | OAM Alert | RFC 3429. |
| 15 | Extension Label (XL) | RFC 7274, RFC 9017. Says that an extended special-purpose label follows. |
The values missing from the table, 5 and 6 and 8 to 12, are unassigned (as of September 2026).
The two you see every day are 0 and 3. The default is implicit-null (3): the egress LSR distributes 3 for its directly connected prefixes (such as loopbacks) and the previous LSR pops the label, so unlabeled IP packets flow on the link before the egress LSR. To deliver the EXP value to the egress LSR, have it distribute explicit-null (0) instead. The previous LSR then swaps the label to 0, and the egress LSR reads the EXP from label 0 before popping it. On IOS XR this is label local advertise explicit-null under mpls ldp.
| Value distributed by the egress LSR | Action at the previous LSR | Link before the egress LSR |
|---|---|---|
| 3 (implicit-null, default) | Pop | No label |
| 0 (explicit-null) | Swap to label 0 | Label 0 |
The label operations themselves are covered in MPLS Label Operations (push / swap / pop) and PHP.
Lab Verification
Lab Setup
CE1, PE1, P1, P2, P3, PE2, and CE2 are connected in a row. PE1 / P1 / P2 / P3 / PE2 in AS 65001 form the MPLS network, with OSPF (area 0, every link network point-to-point) distributing routes and LDP distributing labels. CE1 and CE2 are customer routers without MPLS that exchange routes with the PEs over eBGP. PE1 and PE2 peer over iBGP between their Loopback0 addresses with next-hop-self, so the next hop of an external route is the PE’s own Loopback0. P1, P2, and P3 do not run BGP.
In addition, CE3 is attached to PE1 and CE4 to PE2 in VRF CUST-A (RD / RT 65001:1), and VPNv4 is added to the PE1 - PE2 iBGP session. Traffic between CE3 and CE4 is carried by the MPLS VPN route and gets two labels. VRFs and VPNv4 are covered in the MPLS L3VPN series; this article looks only at the label stack.
There are three P routers so that all four core links can be captured. That makes it possible to follow, without a gap, how the label is swapped at every hop, how the TTL drops by one each time, and how the label is removed by PHP on the last hop.
| Router | Role | Lo0 | Links |
|---|---|---|---|
| CE1 | Customer side (AS 65101), advertises 192.168.1.0/24 | 1.1.1.1/32 | Gi0/0/0/0 10.1.2.1 |
| PE1 | Ingress / egress LSR (AS 65001) | 2.2.2.2/32 | Gi0/0/0/0 10.1.2.2 / Gi0/0/0/1 10.2.3.2 |
| P1 | Intermediate LSR | 3.3.3.3/32 | Gi0/0/0/0 10.2.3.3 / Gi0/0/0/1 10.3.4.3 |
| P2 | Intermediate LSR | 4.4.4.4/32 | Gi0/0/0/0 10.3.4.4 / Gi0/0/0/1 10.4.5.4 |
| P3 | Intermediate LSR (performs PHP) | 5.5.5.5/32 | Gi0/0/0/0 10.4.5.5 / Gi0/0/0/1 10.5.6.5 |
| PE2 | Ingress / egress LSR (AS 65001) | 6.6.6.6/32 | Gi0/0/0/0 10.5.6.6 / Gi0/0/0/1 10.6.7.6 |
| CE2 | Customer side (AS 65102), advertises 192.168.2.0/24 | 7.7.7.7/32 | Gi0/0/0/0 10.6.7.7 |
| CE3 | Customer side in VRF CUST-A (AS 65103), advertises 192.168.3.0/24 | 8.8.8.8/32 | Gi0/0/0/0 10.2.8.8 (PE1 Gi0/0/0/2) |
| CE4 | Customer side in VRF CUST-A (AS 65104), advertises 192.168.4.0/24 | 9.9.9.9/32 | Gi0/0/0/0 10.6.9.9 (PE2 Gi0/0/0/2) |
CE1 pings 192.168.2.1 (global) and CE3 pings 192.168.4.1 (VPN) while we capture on all four core links (PE1 - P1, P1 - P2, P2 - P3, and P3 - PE2). The BGP next hop of both routes is PE2’s Loopback0 (6.6.6.6), so the top label PE1 pushes is the one P1 distributed for 6.6.6.6/32.
Steps
| STEP | Action | What to confirm |
|---|---|---|
| 0 | Initial state (default = implicit-null) | Labeled packets (EtherType 0x8847) on PE1 - P1, one entry for the global route and two for the VPN route. The label is swapped at every hop and the TTL drops by one. No label is left on P3 - PE2 |
| 1 | Send pings with a ToS value (no configuration change) | The IP precedence is copied into the label EXP. The IP DSCP itself does not change |
| 2 | label local advertise explicit-null on PE2 | Label 0 appears on P3 - PE2, on top of the VPN label for VPN traffic |
| 3 | Remove STEP 2 (final state) | Back to the same state as STEP 0 |
Inside a Labeled Packet
For 192.168.2.0/24, whose BGP next hop is 6.6.6.6, PE1 pushes label 24005, the value it received from P1. In show mpls forwarding, the row for local label 24006 (the value PE1 itself assigned to 6.6.6.6/32) carries outgoing label 24005. The last row, 24007, is the VPN label PE1 assigned to 192.168.3.0/24 in VRF CUST-A ([V]).
RP/0/RP0/CPU0:PE1#show mpls forwarding
Sun Sep 20 12:31:04.869 UTC
Local Outgoing Prefix Outgoing Next Hop Bytes
Label Label or ID Interface Switched
------ ----------- ------------------ ------------ --------------- ------------
24000 Pop 3.3.3.3/32 Gi0/0/0/1 10.2.3.3 150
24001 Pop 10.3.4.0/24 Gi0/0/0/1 10.2.3.3 0
24002 24001 4.4.4.4/32 Gi0/0/0/1 10.2.3.3 0
24003 24002 10.4.5.0/24 Gi0/0/0/1 10.2.3.3 0
24004 24003 5.5.5.5/32 Gi0/0/0/1 10.2.3.3 0
24005 24004 10.5.6.0/24 Gi0/0/0/1 10.2.3.3 0
24006 24005 6.6.6.6/32 Gi0/0/0/1 10.2.3.3 36750
24007 Unlabelled 192.168.3.0/24[V] Gi0/0/0/2 10.2.8.8 13088Dynamic labels start at 24000, as show mpls label range shows.
RP/0/RP0/CPU0:P1#show mpls label range
Sun Sep 20 12:32:03.861 UTC
Range for dynamic labels: Min/Max: 24000/1048575No.37 of the PE1 - P1 capture, taken while CE1 pinged 192.168.2.1, is the labeled echo request. The EtherType is 0x8847 and the entry carries label 24005, TC 0 (tshark calls it Experimental Bits), S = 1, and TTL 254, with the IPv4 header following the four bytes. The label TTL of 254 is the TTL 255 that CE1 sent, decremented once by PE1 and copied into the label.
Type: MPLS label switched packet (0x8847)
[Stream index: 4]
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.1.1, Dst: 192.168.2.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
0000 00.. = Differentiated Services Codepoint: Default (0)
.... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
Total Length: 100
Identification: 0x0000 (0)
000. .... = Flags: 0x0
0... .... = Reserved bit: Not set
.0.. .... = Don't fragment: Not set
..0. .... = More fragments: Not set
...0 0000 0000 0000 = Fragment Offset: 0
Time to Live: 254The TTL Changes at Every Hop, the IP Header Does Not
The label TTL drops by one at every LSR. Looking at the same echo request on all four core links, it goes 254, 253, 252 — and on the last link there is no label at all.
$ tshark -r - -Y 'icmp.type==8 && ip.src==192.168.1.1' -T fields -e frame.number -e mpls.label -e mpls.ttl -e ip.ttl \
< mpls-label-step0-pe1p1.pcap
37 24005 254 254
$ tshark -r - -Y 'icmp.type==8 && ip.src==192.168.1.1' -T fields -e frame.number -e mpls.label -e mpls.ttl -e ip.ttl \
< mpls-label-step0-p1p2.pcap
33 24005 253 254
$ tshark -r - -Y 'icmp.type==8 && ip.src==192.168.1.1' -T fields -e frame.number -e mpls.label -e mpls.ttl -e ip.ttl \
< mpls-label-step0-p2p3.pcap
34 24005 252 254
$ tshark -r - -Y 'icmp.type==8 && ip.src==192.168.1.1' -T fields -e frame.number -e mpls.label -e mpls.ttl -e ip.ttl \
< mpls-label-step0-p3pe2.pcap
35 251The last line has neither a label value nor a label TTL: P3 removed the label (PHP), so the frame carries EtherType 0x0800 and a plain IP packet. That is where the IP TTL changes from 254 to 251. While a label is present the IP TTL stays untouched, and the decrements made on the label are written back when the label is popped (RFC 3032 2.4.2 and 2.4.3).
Type: IPv4 (0x0800)
[Stream index: 2]
Internet Protocol Version 4, Src: 192.168.1.1, Dst: 192.168.2.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
0000 00.. = Differentiated Services Codepoint: Default (0)
.... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
Total Length: 100
Identification: 0x0000 (0)
000. .... = Flags: 0x0
0... .... = Reserved bit: Not set
.0.. .... = Don't fragment: Not set
..0. .... = More fragments: Not set
...0 0000 0000 0000 = Fragment Offset: 0
Time to Live: 251A traceroute from CE1 shows the same thing. Hops 2 to 4 carry a label; PE2 (10.5.6.6) does not.
RP/0/RP0/CPU0:CE1#traceroute 192.168.2.1 source 192.168.1.1 timeout 1 probe 2 maxttl 7
Sun Sep 20 12:30:19.585 UTC
Type escape sequence to abort.
Tracing the route to 192.168.2.1
1 10.1.2.2 5 msec 5 msec
2 10.2.3.3 [MPLS: Label 24005 Exp 0] 18 msec 16 msec
3 10.3.4.4 [MPLS: Label 24005 Exp 0] 17 msec 46 msec
4 10.4.5.5 [MPLS: Label 24005 Exp 0] 20 msec 18 msec
5 10.5.6.6 17 msec 37 msec
6 10.6.7.7 21 msec *A Label Value Is Only Meaningful Between Two Adjacent Routers
Every LSR allocates labels on its own. In this lab P1, P2, and P3 happened to assign 24005 to 6.6.6.6/32, so the value does not appear to change in the captures above. The show mpls forwarding output of each router shows what actually happens: each one pops its own local label and pushes the label of the next router.
RP/0/RP0/CPU0:P1#show mpls forwarding
Sun Sep 20 12:32:03.269 UTC
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 38119
24001 Pop 4.4.4.4/32 Gi0/0/0/1 10.3.4.4 274
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 0
24004 24004 10.5.6.0/24 Gi0/0/0/1 10.3.4.4 0
24005 24005 6.6.6.6/32 Gi0/0/0/1 10.3.4.4 37705RP/0/RP0/CPU0:P2#show mpls forwarding
Sun Sep 20 12:32:27.311 UTC
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 38421
24001 Pop 3.3.3.3/32 Gi0/0/0/0 10.3.4.3 318
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 318
24004 Pop 10.5.6.0/24 Gi0/0/0/1 10.4.5.5 0
24005 24005 6.6.6.6/32 Gi0/0/0/1 10.4.5.5 38553RP/0/RP0/CPU0:P3#show mpls forwarding
Sun Sep 20 12:32:52.214 UTC
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.4.5.4 37510
24001 24001 3.3.3.3/32 Gi0/0/0/0 10.4.5.4 0
24002 Pop 4.4.4.4/32 Gi0/0/0/0 10.4.5.4 380
24003 24002 10.2.3.0/24 Gi0/0/0/0 10.4.5.4 0
24004 Pop 10.3.4.0/24 Gi0/0/0/0 10.4.5.4 0
24005 Pop 6.6.6.6/32 Gi0/0/0/1 10.5.6.6 38246A Two-Entry Label Stack
Pings from CE3 to 192.168.4.1 (CE4) are carried by the VRF CUST-A route. For that destination PE1 pushes the VPN label 24007, which PE2 distributed over VPNv4, and on top of it 24005 to reach the egress PE2. That is the labels imposed {24005 24007} in show cef vrf CUST-A.
RP/0/RP0/CPU0:PE1#show cef vrf CUST-A 192.168.4.0/24 detail
Sun Sep 20 12:31:10.752 UTC
192.168.4.0/24, version 7, internal 0x5000001 0x30 (ptr 0x885196d0) [1], 0x0 (0x0), 0x208 (0x89a22518)
Updated Sep 20 12:05:56.194
Prefix Len 24, traffic index 0, precedence n/a, priority 3
gateway array (0x8972ea58) reference count 1, flags 0x2038, source rib (7), 0 backups
[1 type 1 flags 0x48441 (0x89a5b4b8) ext 0x0 (0x0)]
LW-LDI[type=0, refc=0, ptr=0x0, sh-ldi=0x0]
gateway array update type-time 1 Sep 20 12:05:56.194
LDI Update time Sep 20 12:05:56.194
via 6.6.6.6/32, 3 dependencies, recursive [flags 0x6000]
path-idx 0 NHID 0x0 [0x8856ecc8 0x0]
recursion-via-/32
next hop VRF - 'default', table - 0xe0000000
next hop 6.6.6.6/32 via 24006/0/21
next hop 10.2.3.3/32 GigabitEthernet0/0/0/1 labels imposed {24005 24007}
Load distribution: 0 (refcount 1)No.524 of the PE1 - P1 capture is that echo request with two entries. The top entry, 24005, has S = 0 and the bottom entry, 24007, has S = 1, with the IPv4 header following the S = 1 entry. Both labels carry TTL 254.
Type: MPLS label switched packet (0x8847)
[Stream index: 4]
MultiProtocol Label Switching Header, Label: 24005, Exp: 0, S: 0, TTL: 254
0000 0101 1101 1100 0101 .... .... .... = MPLS Label: 24005 (0x05dc5)
.... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
.... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
.... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
MultiProtocol Label Switching Header, Label: 24007, Exp: 0, S: 1, TTL: 254
0000 0101 1101 1100 0111 .... .... .... = MPLS Label: 24007 (0x05dc7)
.... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
.... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
.... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
Internet Protocol Version 4, Src: 192.168.3.1, Dst: 192.168.4.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
0000 00.. = Differentiated Services Codepoint: Default (0)
.... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
Total Length: 100
Identification: 0x0000 (0)
000. .... = Flags: 0x0
0... .... = Reserved bit: Not set
.0.. .... = Don't fragment: Not set
..0. .... = More fragments: Not set
...0 0000 0000 0000 = Fragment Offset: 0
Time to Live: 254No.523 of the P3 - PE2 capture is the same packet after P3 popped the top label. Only the VPN label 24007 is left and its TTL is 251: when P3 popped the top entry it copied the TTL of that moment (251) into the entry that became the new top (RFC 3032 2.4.2).
Type: MPLS label switched packet (0x8847)
[Stream index: 2]
MultiProtocol Label Switching Header, Label: 24007, Exp: 0, S: 1, TTL: 251
0000 0101 1101 1100 0111 .... .... .... = MPLS Label: 24007 (0x05dc7)
.... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
.... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
.... .... .... .... .... .... 1111 1011 = MPLS TTL: 251
Internet Protocol Version 4, Src: 192.168.3.1, Dst: 192.168.4.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
0000 00.. = Differentiated Services Codepoint: Default (0)
.... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
Total Length: 100
Identification: 0x0000 (0)
000. .... = Flags: 0x0
0... .... = Reserved bit: Not set
.0.. .... = Don't fragment: Not set
..0. .... = More fragments: Not set
...0 0000 0000 0000 = Fragment Offset: 0
Time to Live: 254On PE2, local label 24007 maps to 192.168.4.0/24 in VRF CUST-A ([V]), and that label sends the packet out of the interface towards CE4. How VPN labels are distributed is covered in the MPLS L3VPN series.
RP/0/RP0/CPU0:PE2#show mpls forwarding
Sun Sep 20 12:31:34.064 UTC
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.5.6.5 36599
24001 24001 3.3.3.3/32 Gi0/0/0/0 10.5.6.5 0
24002 24002 4.4.4.4/32 Gi0/0/0/0 10.5.6.5 0
24003 Pop 5.5.5.5/32 Gi0/0/0/0 10.5.6.5 212
24004 24003 10.2.3.0/24 Gi0/0/0/0 10.5.6.5 0
24005 24004 10.3.4.0/24 Gi0/0/0/0 10.5.6.5 0
24006 Pop 10.4.5.0/24 Gi0/0/0/0 10.5.6.5 0
24007 Unlabelled 192.168.4.0/24[V] Gi0/0/0/2 10.6.9.9 13088TC Receives a Copy of the IP Precedence
When it pushes a label, IOS XR copies the IP precedence (the top three bits of the DSCP) into TC by default. Pinging from CE1 with a ToS value set through type gives TC 5 for packets with DSCP 46 (EF). The DSCP in the IP header itself is not rewritten.
| ToS sent by CE1 | IP DSCP | Label TC |
|---|---|---|
| 0 | 0 (CS0) | 0 |
| 96 | 24 (CS3) | 3 |
| 184 | 46 (EF) | 5 |
Type: MPLS label switched packet (0x8847)
[Stream index: 4]
MultiProtocol Label Switching Header, Label: 24005, Exp: 5, S: 1, TTL: 254
0000 0101 1101 1100 0101 .... .... .... = MPLS Label: 24005 (0x05dc5)
.... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5
.... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
.... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
Internet Protocol Version 4, Src: 192.168.1.1, Dst: 192.168.2.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0xb8 (DSCP: EF, ECN: Not-ECT)
1011 10.. = Differentiated Services Codepoint: Expedited Forwarding (46)How TC is used is covered in MPLS QoS.
Implicit-Null Never Appears as a Label
PE2, the egress LSR, distributes implicit-null (3) for its own Loopback0 (6.6.6.6/32). In P3’s show mpls ldp bindings the value from PE2 is ImpNull, and show mpls forwarding shows Pop as the outgoing label.
RP/0/RP0/CPU0:P3#show mpls ldp bindings 6.6.6.6/32
Sun Sep 20 12:32:51.320 UTC
6.6.6.6/32, rev 18
Local binding: label: 24005
Remote bindings: (2 peers)
Peer Label
----------------- ---------
4.4.4.4:0 24005
6.6.6.6:0 ImpNullRP/0/RP0/CPU0:P3#show mpls forwarding
Sun Sep 20 12:32:52.214 UTC
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.4.5.4 37510
24001 24001 3.3.3.3/32 Gi0/0/0/0 10.4.5.4 0
24002 Pop 4.4.4.4/32 Gi0/0/0/0 10.4.5.4 380
24003 24002 10.2.3.0/24 Gi0/0/0/0 10.4.5.4 0
24004 Pop 10.3.4.0/24 Gi0/0/0/0 10.4.5.4 0
24005 Pop 6.6.6.6/32 Gi0/0/0/1 10.5.6.6 38246show mpls label table detail lists the reserved labels a router actually holds. The LSD (Label Switching Database) holds 0 (IPv4 Explicit NULL), 1 (Router Alert), 2 (IPv6 Explicit NULL), and 13 (GAL); 3 is absent. Implicit-null is a value carried by LDP, and it appears neither in the label table nor on the wire.
RP/0/RP0/CPU0:P3#show mpls label table detail
Sun Sep 20 12:32:52.919 UTC
Table Label Owner State Rewrite
----- ------- ------------------------------- ------ -------
0 0 LSD(A) InUse Yes
0 1 LSD(A) InUse Yes
0 2 LSD(A) InUse Yes
0 13 LSD(A) InUse Yes
0 24000 LDP(A) InUse Yes
(IPv4, vers:0, 'default':4U, 2.2.2.2/32)Explicit-Null Appears on the Wire
Now label local advertise explicit-null is configured on PE2.
mpls ldp\n address-family ipv4\n label local advertise explicit-nullThe value P3 receives becomes ExpNullv4, and the outgoing label becomes Exp-Null-v4.
RP/0/RP0/CPU0:P3#show mpls ldp bindings 6.6.6.6/32
Sun Sep 20 12:44:24.835 UTC
6.6.6.6/32, rev 18
Local binding: label: 24005
Remote bindings: (2 peers)
Peer Label
----------------- ---------
4.4.4.4:0 24005
6.6.6.6:0 ExpNullv4RP/0/RP0/CPU0:P3#show mpls forwarding
Sun Sep 20 12:44:25.602 UTC
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.4.5.4 37581
24001 24001 3.3.3.3/32 Gi0/0/0/0 10.4.5.4 0
24002 Pop 4.4.4.4/32 Gi0/0/0/0 10.4.5.4 362
24003 24002 10.2.3.0/24 Gi0/0/0/0 10.4.5.4 0
24004 Pop 10.3.4.0/24 Gi0/0/0/0 10.4.5.4 0
24005 Exp-Null-v4 6.6.6.6/32 Gi0/0/0/1 10.5.6.6 39763In No.85 of the P3 - PE2 capture, the echo request from CE1 arrives with label 0 on it. The label TTL is 251 while the IP TTL is still 254 — again, the IP TTL does not change while a label is present.
Type: MPLS label switched packet (0x8847)
[Stream index: 4]
MultiProtocol Label Switching Header, Label: 0 (IPv4 Explicit-Null), Exp: 0, S: 1, TTL: 251
0000 0000 0000 0000 0000 .... .... .... = MPLS Label: IPv4 Explicit-Null (0)
.... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
.... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
.... .... .... .... .... .... 1111 1011 = MPLS TTL: 251
Internet Protocol Version 4, Src: 192.168.1.1, Dst: 192.168.2.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
0000 00.. = Differentiated Services Codepoint: Default (0)
.... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
Total Length: 100
Identification: 0x0000 (0)
000. .... = Flags: 0x0
0... .... = Reserved bit: Not set
.0.. .... = Don't fragment: Not set
..0. .... = More fragments: Not set
...0 0000 0000 0000 = Fragment Offset: 0
Time to Live: 254For the VPN route the stack has two entries, as in No.574: label 0 on top (S = 0) and the VPN label 24007 at the bottom (S = 1). RFC 3032 allowed explicit-null only at the bottom of the stack; RFC 4182 removed that restriction and states that an LSR receiving it on top pops the entry and processes the label beneath. PE2 pops label 0 and then forwards into VRF CUST-A by 24007.
Type: MPLS label switched packet (0x8847)
[Stream index: 4]
MultiProtocol Label Switching Header, Label: 0 (IPv4 Explicit-Null), Exp: 0, S: 0, TTL: 251
0000 0000 0000 0000 0000 .... .... .... = MPLS Label: IPv4 Explicit-Null (0)
.... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
.... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
.... .... .... .... .... .... 1111 1011 = MPLS TTL: 251
MultiProtocol Label Switching Header, Label: 24007, Exp: 0, S: 1, TTL: 254
0000 0101 1101 1100 0111 .... .... .... = MPLS Label: 24007 (0x05dc7)
.... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
.... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
.... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
Internet Protocol Version 4, Src: 192.168.3.1, Dst: 192.168.4.1
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
0000 00.. = Differentiated Services Codepoint: Default (0)
.... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
Total Length: 100
Identification: 0x0000 (0)
000. .... = Flags: 0x0
0... .... = Reserved bit: Not set
.0.. .... = Don't fragment: Not set
..0. .... = More fragments: Not set
...0 0000 0000 0000 = Fragment Offset: 0
Time to Live: 254Removing the configuration brings the value P3 receives back to ImpNull. Filtering P3’s LDP trace on 6.6.6.6/32 lines up the history of what PE2 advertised: 3, then 0, then 3. In both changes there are ten seconds between the withdrawal of the old value (Remove) and the arrival of the new one (Add).
RP/0/RP0/CPU0:P3#show mpls ldp trace binding | include "6.6.6.6/32"
Sun Sep 20 12:50:26.582 UTC
Sep 20 12:04:48.308 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:161: VRF(0x60000000): Prefix(6.6.6.6/32): Created, reason 3
Sep 20 12:04:48.309 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:221: VRF(0x60000000): Prefix(6.6.6.6/32): label 24005 (rev#18) assigned
Sep 20 12:05:00.768 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:279: VRF(0x60000000): Prefix(6.6.6.6/32): Add label 24005 from peer 4.4.4.4:0
Sep 20 12:05:10.171 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:279: VRF(0x60000000): Prefix(6.6.6.6/32): Add label 3 from peer 6.6.6.6:0
Sep 20 12:40:20.170 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:339: VRF(0x60000000): Prefix(6.6.6.6/32): Remove label 3 from peer 6.6.6.6:0
Sep 20 12:40:30.170 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:279: VRF(0x60000000): Prefix(6.6.6.6/32): Add label 0 from peer 6.6.6.6:0
Sep 20 12:46:00.170 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:339: VRF(0x60000000): Prefix(6.6.6.6/32): Remove label 0 from peer 6.6.6.6:0
Sep 20 12:46:10.170 mpls/ldp/bndg 0/RP0/CPU0 t4208 [BNDG]:279: VRF(0x60000000): Prefix(6.6.6.6/32): Add label 3 from peer 6.6.6.6:0Reachability
Traffic between the CEs keeps flowing in every STEP. Changing how labels are assigned does not affect forwarding itself.
RP/0/RP0/CPU0:CE1#ping 192.168.2.1 source 192.168.1.1 count 50 timeout 1
Sun Sep 20 12:30:17.594 UTC
Type escape sequence to abort.
Sending 50, 100-byte ICMP Echos to 192.168.2.1 timeout is 1 seconds:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Success rate is 100 percent (50/50), round-trip min/avg/max = 18/23/44 msRP/0/RP0/CPU0:CE3#ping 192.168.4.1 source 192.168.3.1 count 50 timeout 1
Sun Sep 20 12:30:44.808 UTC
Type escape sequence to abort.
Sending 50, 100-byte ICMP Echos to 192.168.4.1 timeout is 1 seconds:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Success rate is 100 percent (50/50), round-trip min/avg/max = 18/21/35 msConfigurations and show Output
For every STEP the following files were collected from all nine routers, one file per router. The verification config is the ..._run.txt (the final state is the one from the last STEP). Each STEP was collected in the order “clear the counters, ping, then show”, so Bytes Switched in show mpls forwarding and the counters in show interface cover only the pings sent during that STEP.
| File | Contents |
|---|---|
..._clear.txt | The counters cleared at the start of the STEP (clear counters interface and clear mpls forwarding counters) |
..._ping.txt | ping (50 packets) and traceroute: CE1 - CE2 (global), CE3 - CE4 (VPN), PE1 - PE2 (the core LSP) |
..._show.txt | show version / show interface description / show route / OSPF / LDP / show mpls forwarding / show mpls label table detail / show cef and more; the PEs add BGP and VPN output |
..._log.txt | show logging limited to the range of that STEP |
..._run.txt | show running-config at that STEP (that is, the verification config for the STEP) |
..._trace.txt | The five core routers only: show mpls ldp trace binding / peer / discovery / forwarding and show mpls lsd trace |
..._commit.cfg | The configuration actually committed in that STEP (only the routers that were changed) |
STEP 4 and STEP 5 were collected to check when IOS XR starts using a changed dynamic label range. They are not discussed in this article, but the files are kept as a record.
STEP 0: Initial state (implicit-null)
| Router | show | ping | clear | syslog | running-config | trace | committed config | operation run |
|---|---|---|---|---|---|---|---|---|
| CE1 | show | ping | clear | log | run | — | — | — |
| PE1 | show | ping | clear | log | run | trace | — | — |
| P1 | show | — | clear | log | run | trace | — | — |
| P2 | show | — | clear | log | run | trace | — | — |
| P3 | show | — | clear | log | run | trace | — | — |
| PE2 | show | ping | clear | log | run | trace | — | — |
| CE2 | show | ping | clear | log | run | — | — | — |
| CE3 | show | ping | clear | log | run | — | — | — |
| CE4 | show | ping | clear | log | run | — | — | — |
STEP 1: Pings with a ToS value
| Router | show | ping | clear | syslog | running-config | trace | committed config | operation run |
|---|---|---|---|---|---|---|---|---|
| CE1 | show | ping | clear | log | run | — | — | — |
| PE1 | show | ping | clear | log | run | trace | — | — |
| P1 | show | — | clear | log | run | trace | — | — |
| P2 | show | — | clear | log | run | trace | — | — |
| P3 | show | — | clear | log | run | trace | — | — |
| PE2 | show | ping | clear | log | run | trace | — | — |
| CE2 | show | ping | clear | log | run | — | — | — |
| CE3 | show | ping | clear | log | run | — | — | — |
| CE4 | show | ping | clear | log | run | — | — | — |
STEP 2: label local advertise explicit-null on PE2
| Router | show | ping | clear | syslog | running-config | trace | committed config | operation run |
|---|---|---|---|---|---|---|---|---|
| CE1 | show | ping | clear | log | run | — | — | — |
| PE1 | show | ping | clear | log | run | trace | — | — |
| P1 | show | — | clear | log | run | trace | — | — |
| P2 | show | — | clear | log | run | trace | — | — |
| P3 | show | — | clear | log | run | trace | — | — |
| PE2 | show | ping | clear | log | run | trace | cfg | — |
| CE2 | show | ping | clear | log | run | — | — | — |
| CE3 | show | ping | clear | log | run | — | — | — |
| CE4 | show | ping | clear | log | run | — | — | — |
STEP 3: Remove explicit-null
| Router | show | ping | clear | syslog | running-config | trace | committed config | operation run |
|---|---|---|---|---|---|---|---|---|
| CE1 | show | ping | clear | log | run | — | — | — |
| PE1 | show | ping | clear | log | run | trace | — | — |
| P1 | show | — | clear | log | run | trace | — | — |
| P2 | show | — | clear | log | run | trace | — | — |
| P3 | show | — | clear | log | run | trace | — | — |
| PE2 | show | ping | clear | log | run | trace | cfg | — |
| CE2 | show | ping | clear | log | run | — | — | — |
| CE3 | show | ping | clear | log | run | — | — | — |
| CE4 | show | ping | clear | log | run | — | — | — |
STEP 4: Change the label ranges on P2 and P3
| Router | show | ping | clear | syslog | running-config | trace | committed config | operation run |
|---|---|---|---|---|---|---|---|---|
| CE1 | show | ping | clear | log | run | — | — | — |
| PE1 | show | ping | clear | log | run | trace | — | — |
| P1 | show | — | clear | log | run | trace | — | — |
| P2 | show | — | clear | log | run | trace | cfg | clearldp |
| P3 | show | — | clear | log | run | trace | cfg | clearldp |
| PE2 | show | ping | clear | log | run | trace | — | — |
| CE2 | show | ping | clear | log | run | — | — | — |
| CE3 | show | ping | clear | log | run | — | — | — |
| CE4 | show | ping | clear | log | run | — | — | — |
STEP 5: Restart LDP on P2 and P3 (final state)
| Router | show | ping | clear | syslog | running-config | trace | committed config | operation run |
|---|---|---|---|---|---|---|---|---|
| CE1 | show | ping | clear | log | run | — | — | — |
| PE1 | show | ping | clear | log | run | trace | — | — |
| P1 | show | — | clear | log | run | trace | — | — |
| P2 | show | — | clear | log | run | trace | — | restart |
| P3 | show | — | clear | log | run | trace | — | restart |
| PE2 | show | ping | clear | log | run | trace | — | — |
| CE2 | show | ping | clear | log | run | — | — | — |
| CE3 | show | ping | clear | log | run | — | — | — |
| CE4 | show | ping | clear | log | run | — | — | — |
Packet captures were taken per STEP on all four core links.
| STEP | PE1 - P1 | P1 - P2 | P2 - P3 | P3 - PE2 |
|---|---|---|---|---|
| 0 | pcap | pcap | pcap | pcap |
| 1 | pcap | pcap | pcap | pcap |
| 2 | pcap | pcap | pcap | pcap |
| 3 | pcap | pcap | pcap | pcap |
| 4 | pcap | pcap | pcap | pcap |
| 5 | pcap | pcap | pcap | pcap |
References
| RFC | Title | Summary |
|---|---|---|
| RFC 3032 | MPLS Label Stack Encoding | Label stack entry format, reserved labels 0 to 3, TTL processing, EtherTypes. |
| RFC 5462 | Multiprotocol Label Switching (MPLS) Label Stack Entry: “EXP” Field Renamed to “Traffic Class” Field | Renames the EXP field to the Traffic Class field. |
| RFC 4182 | Removing a Restriction on the use of MPLS Explicit NULL | Allows Explicit NULL anywhere in the stack, not only at the bottom. |
| RFC 3031 | Multiprotocol Label Switching Architecture | PHP (section 3.16). |
Reserved label registry: IANA Special-Purpose MPLS Label Values
Book: Luc De Ghein, MPLS Fundamentals (Cisco Press, 2006), Chapters 2 to 3
Related Articles
- What Is MPLS
- MPLS Labels and the Label Stack
- MPLS Label Operations (push / swap / pop) and PHP
- MPLS TTL Processing and MTU
- What Is LDP
- LDP Label Distribution Modes and Label Spaces
- LDP-IGP Synchronization and LDP Session Protection
- LDP label advertisement control (filtering)
- LDP session authentication (TCP MD5)
- MPLS OAM (LSP ping and LSP traceroute)
- What Is MPLS TE (RSVP-TE)
- MPLS TE CSPF and Path Constraints (Bandwidth, Affinity, TE Metric)
- Steering Traffic into MPLS TE Tunnels
- MPLS TE Fast Reroute (Link and Node Protection)
- MPLS TE Fast Reroute (Auto-Tunnel Backup and SRLG)
- MPLS QoS (EXP and Uniform / Pipe / Short-Pipe)
- MPLS QoS Rate Control and Queuing (policer / shaper / priority)