2. The network

As said, our network differs a bit from Packetlife's. Being network-people, Packetlife likes to use loopback interfaces, but we have complete virtual machines, so why settle for less?

2.1. Two customers MPLS network


mpls-no-cs.png>

As image I used c3660-jk9o3s-mz.124-17.bin and I put fast-ethernet cards in all slots. The Vagrantfile is:
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
# Vagrant.configure("2") do |config|
#   config.vm.box = "minimal/xenial64"
#   end
#
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
	config.vm.define :xenial1 do |t|
		t.vm.box = "ubuntu/xenial64"
		# t.vm.box_url = "file://links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet1" ]
		end
		t.vm.provision "shell", path: "./setup.xenial1.sh"
	end
	config.vm.define :xenial2 do |t|
		t.vm.box = "ubuntu/xenial64"
		#t.vm.box_url = "file://links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet2" ]
		end
		t.vm.provision "shell", path: "./setup.xenial2.sh"
	end
	config.vm.define :xenial3 do |t|
		t.vm.box = "ubuntu/xenial64"
		#t.vm.box_url = "file://links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet3" ]
		end
		t.vm.provision "shell", path: "./setup.xenial3.sh"
	end
	config.vm.define :xenial4 do |t|
		t.vm.box = "ubuntu/xenial64"
		#t.vm.box_url = "file://links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet4" ]
		end
		t.vm.provision "shell", path: "./setup.xenial4.sh"
	end
	config.vm.define :xenial5 do |t|
		t.vm.box = "ubuntu/xenial64"
		#t.vm.box_url = "file://links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet5" ]
		end
		t.vm.provision "shell", path: "./setup.xenial5.sh"
	end
end

On our P and PE routers, we've enabled MPLS. As a default, LDP is enabled. It runs between the loopback interfaces of the routers. The interfaces can connect because we run OSPF on the MPLS-routers. You can see what OSPF does:
P1#sh ip OSPF DATABASE
            OSPF Router with ID (10.128.128.1) (Process ID 1)
                Router Link States (Area 0)
Link ID         ADV Router      Age         Seq#       Checksum Link count
10.128.128.1    10.128.128.1    20          0x80000003 0x000BAE 3
10.128.128.2    10.128.128.2    20          0x80000003 0x004D66 3
10.128.128.3    10.128.128.3    23          0x80000002 0x00F1E9 2
10.128.128.4    10.128.128.4    24          0x80000002 0x000EC8 2
                Net Link States (Area 0)
Link ID         ADV Router      Age         Seq#       Checksum
10.128.0.2      10.128.128.2    25          0x80000001 0x000186
10.128.1.2      10.128.128.3    23          0x80000001 0x00F98A
10.128.2.2      10.128.128.4    25          0x80000001 0x00017F

and on the wire between P1 and P2, you'll see the OSPF packets:

ospfp1p2.jpg>

You will also notice that the CE-routers are not in the OSPF database.

2.2. Routing on the PE

We defined VRFs on the PE routers for each customer:
ip vrf Customer_A
 rd 65000:1
 route-target export 65000:1
 route-target import 65000:1
 route-target import 65000:99
!
ip vrf Customer_B
 rd 65000:2
 route-target export 65000:2
 route-target import 65000:2
 route-target import 65000:99

We used the same route distinguisher (RD) on both PE routers. Best practice is to use a different RD on each VRF. RDs are used to make routes globally unique. We use the same RD on both PE routers, because we are sure that the routes that are advertised are already unique per customer (A and B). If the network behind the CE routers is more dynamic, do not use the same RDs.

Route-targets and route-distinguishers are used to define the separate customers. With the route-targets we can define which VRF sees which VRF.

We used the format :; customer 99 is for later use.

The VRFs are defined on the interfaces that connect the CE-routers:
!
interface FastEthernet1/0
 ip vrf forwarding Customer_A
 ip address 10.128.10.1 255.255.255.0
 ip ospf 2 area 0
 duplex auto
 speed auto
!
interface FastEthernet2/0
 ip vrf forwarding Customer_B
 ip address 10.128.20.1 255.255.255.0
 ip ospf 3 area 0
 duplex auto
 speed auto
!

And you can see that it works:
PE1#sh ip vrf interfaces 
Interface              IP-Address      VRF                              Protocol
Fa1/0                  10.128.10.1     Customer_A                       up      
Fa2/0                  10.128.20.1     Customer_B                       up

The next step is the routing of client traffic.
router bgp 65000
 bgp log-neighbor-changes
 neighbor 10.128.128.4 remote-as 65000
 neighbor 10.128.128.4 update-source Loopback0
 neighbor 10.128.128.5 remote-as 65000
 neighbor 10.128.128.5 update-source Loopback0
 no auto-summary
 !
 address-family vpnv4
  neighbor 10.128.128.4 activate
  neighbor 10.128.128.4 send-community extended
  neighbor 10.128.128.5 activate
  neighbor 10.128.128.5 send-community extended
 exit-address-family
 !
 address-family ipv4 vrf Customer_B
  redistribute ospf 3 vrf Customer_B
  no synchronization
 exit-address-family
 !
 address-family ipv4 vrf Customer_A
  redistribute ospf 2 vrf Customer_A
  no synchronization
 exit-address-family
!

So what does that mean?
router bgp 65000
neighbor 10.128.128.4 remote-as 65000

adds the other PE router to the BGP table. Our autonomous system (AS) is 65000, which is often used for private networks.
neighbor 10.128.128.4 update-source Loopback0

we define the loopback interface as the operational interface for the TCP connections.
address-family vpnv4
 neighbor 10.128.128.4 activate
 neighbor 10.128.128.4 send-community extended
 neighbor 10.128.128.5 activate
 neighbor 10.128.128.5 send-community extended
 exit-address-family

This defines the VPNs. The RDs make the routes unique, even if customers use the same address space (e.g. 10.0.0.0/8). We've seen the RDs in the VRF definition above. the router 10.128.128.5 is for later use.
 address-family ipv4 vrf Customer_B
  redistribute ospf 3 vrf Customer_B
  no synchronization
 exit-address-family
 address-family ipv4 vrf Customer_A
  redistribute ospf 2 vrf Customer_A
  no synchronization
 exit-address-family

finaly allows OSPF with the CE routers.

It is important to see that the complete separation of customers is handled by the provider. This has some security implications. If you are a provider, you will need to be in complete control of the separation to fulfill your contractual obligations. As a client, you will want to make sure that your provider takes care of that separation. This can be done through contracts, if you trust your provider enough, or through read rights on the PE-routers. And that could be problematic. A solution would be to have a right to audit, as is often provided by the contracts. You might also do some security monitoring here; IDS could be a valid requirement.

2.3. The resulting network

Now we can ping between xenial1/xenial2 and xenial3/xenial4, but not from xenial1 to xenial3. As an example:
ljm[MPLS_common_services]$ vagrant ssh xenial1 -c 'ping -c2  10.128.66.101'
PING 10.128.66.101 (10.128.66.101) 56(84) bytes of data.
64 bytes from 10.128.66.101: icmp_req=1 ttl=58 time=142 ms
64 bytes from 10.128.66.101: icmp_req=2 ttl=58 time=118 ms
--- 10.128.66.101 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 118.239/130.381/142.524/12.147 ms
Connection to 127.0.0.1 closed.
ljm[MPLS_common_services]$ vagrant ssh xenial1 -c 'ping -c2  10.128.93.101'
PING 10.128.93.101 (10.128.93.101) 56(84) bytes of data.
From 10.128.65.1 icmp_seq=1 Destination Host Unreachable
From 10.128.65.1 icmp_seq=2 Destination Host Unreachable
--- 10.128.93.101 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1001ms
Connection to 127.0.0.1 closed.
ljm[MPLS_common_services]$ vagrant ssh xenial1 -c 'traceroute  10.128.66.101'
traceroute to 10.128.66.101 (10.128.66.101), 30 hops max, 60 byte packets
 1  10.128.65.1 (10.128.65.1)  14.152 ms  14.034 ms  13.952 ms
 2  10.128.10.1 (10.128.10.1)  34.125 ms  34.014 ms  33.926 ms
 3  10.128.1.1 (10.128.1.1)  115.482 ms  115.421 ms  115.344 ms
 4  10.128.0.2 (10.128.0.2)  115.265 ms  115.189 ms  115.111 ms
 5  10.128.30.1 (10.128.30.1)  94.729 ms  94.675 ms  94.598 ms
 6  10.128.30.2 (10.128.30.2)  114.787 ms  103.218 ms  103.113 ms
 7  10.128.66.101 (10.128.66.101)  123.240 ms  117.791 ms  117.928 ms
Connection to 127.0.0.1 closed.

What we see in the traceroute is that all the MPLS routers are seen. This can be hidden with no mpls propagate-ttl. See https://www.cisco.com/c/en/us/support/docs/multiprotocol-label-switching-mpls/mpls/26585-mpls-traceroute.html for details on the traceroute.