MPLS labels are 32-bit shim headers inserted between the data link layer and the IP header. They carry the label value, traffic class (formerly EXP), the bottom-of-stack bit, and TTL. Multiple labels can be stacked. If you understand the label format and how the stack works, the rest of MPLS becomes mechanics.
This article walks through the byte-level format, the label stack, special reserved labels, Penultimate Hop Popping (PHP), and how labels look on the wire in real packet captures. If you are studying for CCIE Service Provider, troubleshooting an MPLS-VPN packet, or trying to figure out why show mpls forwarding-table shows what it shows, this is the byte reference.
The Label Format
+---------------------+-----+---+-------------+
| Label | EXP | S | TTL |
| 20 bits | 3 | 1 | 8 bits |
+---------------------+-----+---+-------------+
| Field | Bits | Purpose |
|---|---|---|
| Label | 20 | The label value, 0 to 1,048,575. Locally significant per LSR. |
| EXP / Traffic Class | 3 | QoS priority; carries equivalent of DSCP top 3 bits across MPLS |
| S (Bottom of Stack) | 1 | 1 if this is the bottom label; 0 if more labels follow below |
| TTL | 8 | Hop count, decremented at each LSR; mirrors IP TTL |
Total 32 bits = 4 bytes per label. The shim header is inserted in the frame between the Layer 2 header (Ethernet, etc.) and the Layer 3 payload (IP).
Reserved Labels
The first 16 label values (0-15) are reserved for special meanings. Three matter in practice:
| Label | Name | Use |
|---|---|---|
| 0 | IPv4 Explicit Null | Tells the egress LSR to pop the label and forward as IPv4. Used in PHP scenarios where the egress wants to preserve EXP/TC info. |
| 1 | Router Alert | Treats the packet specially (like IP Router Alert). Sent to control plane for inspection. |
| 2 | IPv6 Explicit Null | Same as label 0 but for IPv6. |
| 3 | Implicit Null | Used in LDP signaling to request PHP. The penultimate hop pops the label entirely instead of swapping. |
| 13 | OAM Alert | Operations and management traffic |
| 14 | Generic Alert | Reserved for new features |
Labels 16 to 1,048,575 are available for use as forwarding labels. Different platforms may reserve some additional ranges (e.g. Cisco IOS reserves the first ~16,000 for specific features), so customer-installed labels typically start at 16,000 or higher.
The Label Stack
Multiple labels can be pushed onto a single packet. The stack is a sequence of label entries with the S bit indicating which is the bottom. Reading from outer to inner:
+--------+--------+--------+---------+
| Outer | Middle | Inner | IP/payld|
| S=0 | S=0 | S=1 | |
+--------+--------+--------+---------+
First popped or swapped
Last popped, payload exposedCommon scenarios:
| Service | Stack | Outer label purpose | Inner label purpose |
|---|---|---|---|
| IP/MPLS forwarding | Single label | LDP/IGP transport | n/a |
| L3VPN (VPNv4) | Two labels | LDP transport across MPLS core | VPN label identifying customer VRF |
| L3VPN with TE | Three labels | RSVP-TE TE label | LDP transport (intermediate), VPN label (innermost) |
| L2VPN (pseudowire) | Two labels | LDP transport | Pseudowire label identifying the L2 circuit |
| SR-MPLS | Variable | Segment list (path) | Service label or none |
Each LSR along the path looks at the outermost label, performs swap/pop/push as configured, and forwards. P routers in the core typically only swap the outer transport label. The inner labels are invisible to them.
Label Actions: Push, Swap, Pop
Each LSR can perform three operations on the label stack:
| Action | Effect | Where it happens |
|---|---|---|
| Push | Adds one or more labels to the top of the stack | Ingress PE (encapsulating customer traffic) |
| Swap | Replaces the outermost label with a new one | Every P router along the LSP |
| Pop | Removes the outermost label | Egress PE (decapsulating); also penultimate hop in PHP |
The forwarding table entry tells the LSR which action to perform for each (incoming label, incoming interface) tuple. Verify with:
R1# show mpls forwarding-table
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
17 18 10.10.10.0/24 123456 Gi0/0/1 10.0.12.2
18 Pop Label 10.20.20.0/24 78901 Gi0/0/2 10.0.13.3
19 No Label 10.30.30.0/24 45678 Gi0/0/0 10.0.14.4"Pop Label" means PHP - this LSR pops the label and forwards the unlabeled packet. "No Label" means the next hop is not running MPLS for this prefix.
Penultimate Hop Popping (PHP)
The egress PE has the work of looking up which VRF a customer packet belongs to (based on the inner VPN label) and forwarding it to the customer. If it also had to look up the outer transport label, that is two label lookups instead of one.
Penultimate Hop Popping optimizes this. The penultimate (second-to-last) LSR pops the outer label before forwarding to the egress PE. The egress PE receives a packet with only the inner VPN label, performs one label lookup, and forwards to the customer.
Signaling: the egress PE advertises label "implicit null" (label 3) to its upstream neighbors via LDP. This is a request to pop the label rather than swap it. The penultimate router sees implicit null in the LDP table and pops accordingly.
PHP is enabled by default in most Cisco IOS XE deployments. Verify with:
P1# show mpls forwarding-table 10.10.10.10 32
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
17 Pop Label 10.10.10.10/32 123456 Gi0/0/2 10.0.PE2.PE2The "Pop Label" outgoing label confirms PHP for the egress PE's loopback (10.10.10.10/32).
Disable PHP if you want the egress PE to see the outer label (e.g. to preserve EXP/TC bits across the boundary):
! On the egress PE
mpls ldp explicit-nullThis advertises "explicit null" (label 0 for IPv4, label 2 for IPv6) instead of implicit null. The penultimate router still pops one level of stack, but the egress PE sees an explicit null label - useful for QoS preservation.
TTL Handling
The MPLS label has its own TTL. Two modes for handling it at ingress and egress:
| Mode | Ingress behavior | Egress behavior |
|---|---|---|
| Uniform (default) | Copy IP TTL to MPLS label TTL minus 1 | Copy MPLS TTL back to IP TTL |
| Pipe | Set MPLS TTL to 255 | Decrement IP TTL by 1 (the entire MPLS path counts as one hop) |
Uniform mode lets traceroute work as expected through the MPLS network - each LSR appears as a hop. Pipe mode hides the MPLS topology - the customer sees one big "hop" across the entire MPLS network, which is what service providers usually want for security reasons.
Configure with:
! Pipe mode (hide MPLS topology)
mpls ip propagate-ttl no
! Uniform mode (default; show MPLS topology)
mpls ip propagate-ttlEtherType and Encapsulation
On Ethernet, an MPLS-encapsulated frame has:
| Field | Value |
|---|---|
| EtherType (unicast) | 0x8847 |
| EtherType (multicast) | 0x8848 |
An Ethernet frame with EtherType 0x8847 carries one or more MPLS labels followed by the payload (typically IP). The receiver parses the labels until S=1, then treats the remainder as the underlying protocol.
Show Commands
! All MPLS forwarding entries
Router# show mpls forwarding-table
! For a specific prefix
Router# show mpls forwarding-table 10.10.10.0 24
! LDP-assigned labels per prefix
Router# show mpls ldp bindings
! Per-interface MPLS state
Router# show mpls interfaces
! IP-to-label mapping in CEF
Router# show ip cef 10.10.10.0/24
10.10.10.0/24, version 123, ...
via 10.0.12.2, GigabitEthernet0/0/0
push label 17, ...The CEF output shows the label being pushed for each prefix. This is what actually drives forwarding. LDP populates the binding table; CEF uses the bindings to populate the forwarding-information base; packets follow the FIB.
In a Packet Capture
An MPLS-labeled frame in Wireshark shows as:
Ethernet II, Src: ..., Dst: ..., Type: MPLS (0x8847)
MPLS Label, Exp: 0, S: 0, TTL: 64 <-- outer
MPLS Label: 17
MPLS Label, Exp: 0, S: 1, TTL: 64 <-- inner (S=1 = bottom)
MPLS Label: 1234
Internet Protocol Version 4, Src: ..., Dst: ...Wireshark parses the label stack automatically. The S=1 on the inner label terminates the stack; everything after is parsed as IP (or whatever the inner protocol indicates).
Summary
MPLS labels are 32-bit shim headers (20-bit label, 3-bit EXP/TC, 1-bit S, 8-bit TTL) that sit between the data link header and the payload. Stacks of labels enable services like L3VPN (two-label stack) and traffic engineering. Penultimate Hop Popping optimizes egress PE work by having the second-to-last LSR pop the outer label.
Master the label format, the three actions (push/swap/pop), the reserved labels (especially implicit null for PHP), and the stack model. The rest of MPLS is mechanics built on these foundations. Bookmark this article alongside the MPLS cluster pillar and the LDP article.