Theoretical foundations and architecture

The MPLS shim header (RFC 3032) is a 32-bit field inserted between Layer 2 and Layer 3 headers. It comprises four fields: a 20-bit Label (values 0-15 reserved), a 3-bit Traffic Class (TC/EXP for QoS marking), a 1-bit Bottom of Stack flag (S: set to 1 on the innermost label before the payload, and 0 for outer labels), and an 8-bit TTL (decremented at every LSR for loop prevention). Every label in the stack adds exactly 4 bytes. In modern carrier architectures, label stacks regularly reach 3 to 5 labels (Transport + VPN service + FRR bypass + Entropy/Flow label = 16-20 bytes). This makes MPLS MTU engineering paramount: if the interface MTU stays at 1500 bytes, a 1500-byte IP packet with 8 bytes of labels becomes 1508 bytes and exceeds it: with DF=1 the LSR drops it and returns ICMP Fragmentation Needed (tunneled along the LSP, RFC 3032), while a frame above the L2 limit is dropped silently. The typical symptom is that ping and BGP OPEN work but large packets hang. Core links therefore carry MTU headroom (typically 1530-1548 bytes, jumbo frames).

Label Stack Entry (LSE): 32 bits between L2 and L3

One label stack entry (Label Stack Entry, RFC 3032) occupies exactly 4 bytes and sits between the link-layer header and the IP header, which is why MPLS is sometimes called "layer 2.5". The Ethernet type changes: 0x8847 for unicast and 0x8848 for multicast instead of 0x0800 for IPv4. The fields, counting from the most significant bit:

text
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Label (20)                 | TC (3)|S|   TTL (8)   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 bits 0-19: Label | bits 20-22: TC | bit 23: S | bits 24-31: TTL

The label is 20 bits, i.e. 1,048,576 values, of which 16 (0-15) are reserved, leaving 1,048,560 for dynamic and static allocation. The TC field (Traffic Class, 3 bits, 8 classes) used to be called EXP; RFC 5462 (2009) renamed it because it had long been used for DiffServ rather than experiments. The S bit (Bottom of Stack) is 1 only in the last entry of the stack; an LSR always looks only at the top entry, and S lets it understand, after popping it, that the payload (IP, Ethernet, etc.) follows rather than another label. TTL is 8 bits and serves the same purpose as the IP TTL: loop protection and the basis for traceroute.

Reserved labels 0-15

These values must not be handed out by LDP/RSVP/BGP like ordinary labels. Some of them are used in practice every day, others almost never.

LabelNamePurpose
0IPv4 Explicit NullPop the label and process the packet as IPv4; preserves TC up to the egress when PHP is disabled.
1Router AlertDeliver the packet to the local LSR control plane; not selected as an ordinary forwarding label.
2IPv6 Explicit NullSame as 0, but for IPv6.
3Implicit NullNever appears in a header: the egress advertises it via LDP/RSVP so that the penultimate hop pops the label (PHP).
7ELI (Entropy Label Indicator, RFC 6790)The next stack entry is an entropy label for load balancing; the ELI TTL is usually 0.
13GAL (RFC 5586)Generic Associated Channel Label, used by MPLS-TP OAM.
14OAM Alert (RFC 3429)Service OAM packets (Y.1711); rarely seen in IP/MPLS networks.
15ReservedReserved for extending the special-purpose label space.

Values 4-6 and 8-12 are unassigned. The first "ordinary" value is 16; Cisco IOS-XE hands out LDP labels starting at 16 by default, Junos LDP uses a range around 300000, and SR-MPLS uses SRGB 16000-23999 by default. This explains why labels from different protocols look so different in show mpls forwarding-table.

The stack and its cost in bytes

Every label adds 4 bytes to the frame size. The size that must pass through the core is calculated as follows: for L3 payloads customer IP MTU + 4*N, where N is the number of labels in the stack; for L2 payloads (pseudowire, VPLS, EVPN) customer Ethernet frame size without FCS + 4*N + 4 bytes of control word (if enabled). A customer frame without FCS at IP MTU 1500 is 1514 bytes (1518 with a dot1q tag).

ScenarioLabels in the stackPayloadMinimum core MTU
IP over LDPtransport (1)IP 15001504
L3VPN over LDP or SRtransport + VPN (2)IP 15001508
L3VPN + RSVP-TE, LDP over TEVPN + LDP + TE (3)IP 15001512
L3VPN, TE and active FRR bypassVPN + TE + bypass (3-4)IP 15001512-1516
Inter-AS option CVPN + BGP-LU + IGP (3)IP 15001512
SR-TE policy of 5 SIDs + VPN6IP 15001524
VPWS/VPLS, untagged Ethernettransport + PW + CW (4 bytes)frame 15141526
VPLS, tagged framesameframe 15181530
EVPN: transport, EVPN, ELI+EL4 labelsframe 15141530
EVPN BUM with ESI label5 labelsframe 15141534

Hence the typical recommendation: set the MTU on all core and aggregation links with headroom (1600, or jumbo 9000-9216 if the equipment and the handoffs support it). The lab value 1524 was chosen as "customer 1500 + 6 labels", which is enough for L3VPN, TE with FRR and SR-TE with five SIDs. What matters is that the maximum possible stack depth is determined by the longest combination of services that can occur in the network, not by the usual scenario.

TTL propagation: uniform and pipe

RFC 3443 describes two models. In the uniform model (the default on Cisco, on Huawei for the public network, and on Junos) the ingress LSR copies the IP TTL into the label TTL, every LSR decrements it by 1, and when the last label is popped the value is copied back into the IP TTL. To the operator and the customer this looks like an ordinary L3 network, and traceroute sees every P router. In the pipe model the LSP is treated as a transparent pipe: the ingress writes 255 into the label, transit LSRs decrement only the label, and the customer IP TTL is untouched; the core is hidden from the customer's traceroute.

Key commands: Cisco no mpls ip propagate-ttl, Junos set protocols mpls no-propagate-ttl, MikroTik /mpls/set propagate-ttl=no, Huawei undo ttl propagate public / undo ttl propagate vpn in mpls view. Disabling propagation hides the core topology from the customer and protects the addresses of the P routers; the price is that you can no longer see from the customer traceroute which core hop lost the connection. Enable or disable it the same way on all PEs, otherwise the TTL value at the egress will differ depending on the path.