I often get questions on MPLS use cases and network designs; when we have such accelerated forwarding in modern-day network equipment with massive, rapid TCAM or general-purpose memory in the case of modern virtualized networks, why do we want label-based forwarding?

The Case for MPLS

While forwarding on labels is at its core a more simplistic way to forward data and should be faster, the fact remains that modern hardware sees no or minimal performance increase from moving to an MPLS network. We then must have a better reason for MPLS forwarding.

Though MPLS is a somewhat “old” in its basis (RFC3031, 2001), the modern use case for a transport protocol with no opinion on what is inside has its strengths. For example, in 2016, MPLS-designed networks allow transport of IPv6 over legacy IPv4-enabled cores without any configuration change outside of edge devices. Further, modern protocols make use of MPLS to get their job done, such as MPLS-TE, which allows for reservation of path’s resources (a blog post to come later about that), L3VPNs which allow customers to have simple connectivity between sites, and VPLS which allows for layer 2 connectivity to traverse a purely layer-3 provider backbone.

The Topology

With a little introduction done, let’s begin on making a basic MPLS network in GNS3; I’ll begin with Mikrotik RouterOS as my platform today, and release my versions with Cisco and Juniper configurations soon.

We’ll start with a simplified provider backbone model:

Screen Shot 2016-08-24 at 1.06.32 PM

We have 2 Core routers, 3 Aggregation routers, and 3 Access routers. The Core and aggregation routers are fully interconnected to provide redundancy and to enable us to demonstrate ECMP in a later blog post.

Configuration

Loopbacks

A well-designed network runs protocols like BGP and LDP (important for MPLS) over loopbacks. This allows for ECMP to take effect and for redundancy to be much simpler to create.

On RouterOS, there are no “loopback” interfaces, so we create a bridge with no member ports. I name mine “lo0” by convention.

On each router, we’ll run:

 

# Create Loopback bridge
/interface bridge add name=lo0 arp=disabled protocol-mode=none

And we have a running loopback interface!

IP Addresses

Next off, let’s assign some IP Addresses. If you’re unfamiliar with RouterOS, I suggest you check out the Mikrotik RouterOS wiki. Keep in mind that GNS3 0-indexes interface names, while RouterOS 1-indexes them, so add 1 to the diagram to get the interface name in RouterOS.

We’ll use the 10.101.0.0/16 as /32s for loopback interfaces we’ve created above.
We’ll use the 10.100.0.0/16 subnet divided into /30s for the point-to-point links between routers.

Core Routers

On Core1:

# Core1 lo0
/ip address add interface=lo0 address=10.101.0.1/32
# Core1 -> Core2
/ip address add interface=ether1 address=10.100.0.1/30
# Core1 -> Agg1
/ip address add interface=ether2 address=10.100.0.5/30
# Core1 -> Agg2
/ip address add interface=ether3 address=10.100.0.9/30
# Core1 -> Agg3
/ip address add interface=ether4 address=10.100.0.13/30

 

On Core2:

# Core2 lo0
/ip address add interface=lo0 address=10.101.0.2/32
# Core2 -> Core1
/ip address add interface=ether1 address=10.100.0.2/30
# Core2 -> Agg1
/ip address add interface=ether2 address=10.100.0.17/30
# Core2 -> Agg2
/ip address add interface=ether3 address=10.100.0.21/30
# Core2 -> Agg3
/ip address add interface=ether4 address=10.100.0.25/30

Aggregation Routers

On Agg1:

# Agg1 lo0
/ip address add interface=lo0 address=10.101.0.3/32
# Agg1 -> Core1
/ip address add interface=ether1 address=10.100.0.6/30
# Agg1 -> Core2
/ip address add interface=ether2 address=10.100.0.18/30
# Agg1 -> Access1
/ip address add interface=ether3 address=10.100.0.29/30

 

On Agg2:

# Agg2 lo0
/ip address add interface=lo0 address=10.101.0.4/32
# Agg2 -> Core1
/ip address add interface=ether1 address=10.100.0.10/30
# Agg2 -> Core2
/ip address add interface=ether2 address=10.100.0.22/30
# Agg2 -> Access1
/ip address add interface=ether3 address=10.100.0.33/30

 

On Agg3:

# Agg3 lo0
/ip address add interface=lo0 address=10.101.0.5/32
# Agg3 -> Core1
/ip address add interface=ether1 address=10.100.0.14/30
# Agg3 -> Core2
/ip address add interface=ether2 address=10.100.0.26/30
# Agg3 -> Access1
/ip address add interface=ether3 address=10.100.0.37/30

Access Routers

On Access1:

# Access1 lo0
/ip address add interface=lo0 address=10.101.0.6/32
# Access1 -> Agg1
/ip address add interface=ether1 address=10.100.0.30/30

 

On Access2:

# Access2 lo0
/ip address add interface=lo0 address=10.101.0.7/32
# Access2 -> Agg2
/ip address add interface=ether1 address=10.100.0.34/30

 

On Access3:

# Access3 lo0
/ip address add interface=lo0 address=10.101.0.8/32
# Access3 -> Agg3
/ip address add interface=ether1 address=10.100.0.38/30

An IGP (OSPF)

For sanity, we want to run an IGP to configure routing between all these devices. MikroTik has chosen not to support the OSI/ISO standard IS-IS at this time, which leaves us with OSPF or RIP. We’ll use OSPF, as it’s the standard for modern-day networks. For now, we’ll keep everything to Area 0.

In RouterOS, bringing up OSPF is as simple as running the following. We’re going to use some RouterOS scripting magic to get the address of the loopback and set that as our router-id. We’re also going to ignore that we’re leaving customer-facing interfaces not statically set to OSPF passive… In production, make sure OSPF is set to “passive” on customer-facing interfaces

# Assign the Router-ID using RouterOS magic
# Assign $lo0addr to the address of lo0
:global lo0addr [/ip address get [/ip address find where interface=lo0 && netmask=255.255.255.255] network]

# Set the router-id to that address
/routing ospf instance set [/routing ospf instance find default] router-id=$lo0addr

# Enable the loopbacks as OSPF-enabled networks
/routing ospf network add network=10.101.0.0/16 area=backbone
# Enable point-to-points as OSPF-enabled networks
/routing ospf network add network=10.100.0.0/16 area=backbone

Given a few moments, this OSPF network should converge and find the best paths through the network. A peek into the routing table with /ip route print will show you a full table.

MPLS Label Distribution (LDP)

We almost have a running MPLS network! Let’s enable LDP on these routers. LDP is the protocol that tells neighboring routers what labels have been assigned to what.

# Enable LDP using variable from above
/mpls ldp set enabled=yes transport-address=$lo0addr lsr-id=$lo0addr
# Enable LDP on interfaces ether1-4
:for i from=1 to=4 do={/mpls ldp interface add interface="ether$i"}

At this point, let’s perform a traceroute from Access1 to Access3’s Loopback address:

# Trace route to 10.101.0.8 (Access3)
/tool traceroute 10.101.0.8

The output was as follows for me:

# ADDRESS LOSS SENT LAST AVG BEST WORST STD-DEV STATUS
1 10.100.0.29 0% 10 1.5ms 2.7 1.4 12.7 3.3 <MPLS:L=31,E=0>
2 10.100.0.5 0% 10 1.2ms 2.1 1.1 9.2 2.4 <MPLS:L=30,E=0>
3 10.100.0.14 0% 10 1.1ms 1.6 1.1 4.1 0.9 <MPLS:L=31,E=0>
4 10.101.0.8 0% 10 1.2ms 2.3 1.1 10.3 2.7

Here you can see how the packets traversed the network: We hit Agg1, who sent the packet to Core1, who sent the packet to Agg3, who then forwarded to Access3. Looking at the status column, we can see how the packet traversed the MPLS network to reach its destination using Label 31, then 30, then 31.

We’ll continue soon with Part 2: Using our new MPLS network to transport traffic we know and love in novel ways with L3VPN.