Service Provider emulation of a frame-relay network using MPLS.
One of the cool things about MPLS is its versatility.
In this post i will show how its possible for a service provider to support legacy frame-relay installations without actually having any frame-relay switches.
I will establish an MPLS core and show how a customer with three sites, one hub site and two spoke sites, will never even know that the core is running MPLS and not end-to-end frame-relay.
The hub site will have a single access-interface with two frame-relay PVC’s, one to each spoke site, where as the spoke sites will only have a connection to the hub site. So a partial mesh topology.
Seen from the customers perspective, it will logically look like this:
In order to accomplish this behavior, i will be using AToM (Any Transport over MPLS), which is configured with pseudo-wires.
This will be configured on the PE routers attached to each site.
Each PE router will then establish a targeted LDP session with the remote PE router and exchange labels for each of them to use.
In practice this means R2 and R3 establishing a targeted session with R1 and R1 having two sessions, one going to each site.
The physical topology will be setup as this:
Its a very simply “core” network, but it suits the needs for this post.
Also note, that each PE router has a loopback not pictured, with R1’s loopback being 1.1.1.1/32, R2’s 2.2.2.2/32 and finally R3’s being 3.3.3.3/32. Sessions will be established between these loopbacks so we dont run into issues with PHP (Penultimate Hop Popping) when establishing our sessions.
The IGP running within the core network is IS-IS level-2.
There are no other routing protocol setup within the core network, so no BGP at each PE either.
Finally each router in the core has been modified so label values are a bit more transparent. R1’s label values will range from 100 to 200, R2’s from 200 to 300 and so on.
Lets take a look at the RIB of R1:
R1#sh ip route | beg Gateway Gateway of last resort is not set 1.0.0.0/32 is subnetted, 1 subnets C 1.1.1.1 is directly connected, Loopback0 2.0.0.0/32 is subnetted, 1 subnets i L2 2.2.2.2 [115/20] via 10.1.4.4, 00:37:28, POS1/0 3.0.0.0/32 is subnetted, 1 subnets i L2 3.3.3.3 [115/20] via 10.1.4.4, 00:37:28, POS1/0 4.0.0.0/32 is subnetted, 1 subnets i L2 4.4.4.4 [115/10] via 10.1.4.4, 00:37:28, POS1/0 10.0.0.0/8 is variably subnetted, 4 subnets, 2 masks C 10.1.4.0/24 is directly connected, POS1/0 L 10.1.4.1/32 is directly connected, POS1/0 i L2 10.2.4.0/24 [115/20] via 10.1.4.4, 00:37:28, POS1/0 i L2 10.3.4.0/24 [115/20] via 10.1.4.4, 00:37:28, POS1/0
And the LFIB for the same router:
R1#sh mpls for Local Outgoing Prefix Bytes Label Outgoing Next Hop Label Label or VC or Tunnel Id Switched interface 100 Pop Label 4.4.4.4/32 0 PO1/0 point2point 101 401 3.3.3.3/32 0 PO1/0 point2point 102 400 2.2.2.2/32 0 PO1/0 point2point 103 Pop Label 10.2.4.0/24 0 PO1/0 point2point 104 Pop Label 10.3.4.0/24 0 PO1/0 point2point
From this output we can see that in order to reach the loopbacks of R2 and R3, R1 must go through R4 with a label of 400 or 401. Lets verify this:
R1#traceroute 2.2.2.2 so loo0 ! 1 10.1.4.4 [MPLS: Label 400 Exp 0] 48 msec 16 msec 24 msec 2 10.2.4.2 12 msec * 16 msec R1#traceroute 3.3.3.3 so loo0 ! 1 10.1.4.4 [MPLS: Label 401 Exp 0] 24 msec 20 msec 44 msec 2 10.3.4.3 12 msec * 12 msec
As expected we are using MPLS to forward the packet along the path. Notice how PHP is in effect on R4. We pop the label for each of the loopbacks on R4 before forwarding them to the end destination.
Lets proceed with the frame-relay part of the configuration on R1, R2 and R3.
We need to enable local frame-relay switching, so the routers can put the FR L2 portion onto the pseudowire as well as offer the DLCI to the local attachment circuit. So the global command “frame-relay switching” must be enabled on all PE routers:
Rx(config)#frame-relay switching
On top of that, we need to specify the frame-relay interface-type on each attachment circuit as well, since we are being the “frame-relay switch”. This means we are the frame-relay DCE (not related to the clocking) part of the connection.
Rx(config)#int s2/0 Rx(config-if)#frame-relay intf-type dce
Next up is the simple task of configuring the pseudowire-class. All we have to specify in this class is the type of encapsulation we want (MPLS or L2TPv3(2)). We want to utilize our MPLS core, so we select the MPLS encapsulation:
Rx(config)#pseudowire-class FRAME-PW Rx(config-pw-class)# encapsulation mpls Rx(config-pw-class)#exit
Pretty simple huh?
Finally we have to create the targeted LDP session between our PE devices, which is typically done with the Xconnect command set. With frame-relay, we need to perform the xconnect under the connect command in order to get the DLCI switched onto the LSP.
So on R1:
R1(config)#connect CON-TO-R2 Serial2/0 506 l2transport R1(config-fr-pw-switching)# xconnect 2.2.2.2 1001 pw-class FRAME-PW R1(config-xconn)#exit R1(config-fr-pw-switching)#exit R1(config)#connect CON-TO-R3 Serial2/0 507 l2transport R1(config-fr-pw-switching)# xconnect 3.3.3.3 1002 pw-class FRAME-PW R1(config-xconn)#exit R1(config-fr-pw-switching)#exit
The first line in the config uses the connect command set to create a connection (named CON-TO-R2) which uses the serial2/0 interface as the attachment circuit and DLCI 506 as the DLCI to be used by R5 to use the LSP we are creating. The l2transport command tells the frame-relay connection that we want to use AToM (in our case), but could also use L2TPv3.
Under the sub-configuration for the connect command, we use the Xconnect command, which we tell to make a targeted LDP session to 2.2.2.2 with 1001 as Virtual Circuit ID (these must match in both ends) and finally that we want to use the FRAME-PW pseudowire we created previously.
We repeat this task for the second DLCI towards R3. We reuse the FRAME-PW pseudowire, since its simply a definition telling AToM how to create the connection (in our case just the encapsulation to be used).
On R2, we do something very similar:
R2(config)#pseudowire-class FRAME-PW R2(config-pw-class)# encapsulation mpls R2(config-pw-class)#exit
And tie it together with the connect command set:
R2(config)#connect CON-TO-R1 Serial2/0 605 l2transport R2(config-fr-pw-switching)# xconnect 1.1.1.1 1001 pw-class FRAME-PW R2(config-xconn)#exit R2(config-fr-pw-switching)#exit
Again, a connection with a name, using serial2/0 as the attachment circuit and DLCI 605 towards R6. We then do the reverse Xconnect towards R1, but notice we have the same VC on this end as well. Finally use the pseudowire-class FRAME-PW to set the encapsulation.
The same task is done on R3:
R3(config)#pseudowire-class FRAME-PW R3(config-pw-class)# encapsulation mpls R3(config-pw-class)#exit R3(config)#connect CON-TO-R1 Serial2/0 705 l2transport R3(config-fr-pw-switching)# xconnect 1.1.1.1 1002 pw-class FRAME-PW R3(config-xconn)#exit R3(config-fr-pw-switching)#exit
lets verify that we have our targeted LDP sessions up and running:
on R1:
R1#sh mpls ldp neighbor Peer LDP Ident: 4.4.4.4:0; Local LDP Ident 1.1.1.1:0 TCP connection: 4.4.4.4.37222 - 1.1.1.1.646 State: Oper; Msgs sent/rcvd: 321/319; Downstream Up time: 04:30:27 LDP discovery sources: POS1/0, Src IP addr: 10.1.4.4 Addresses bound to peer LDP Ident: 4.4.4.4 10.2.4.4 10.1.4.4 10.3.4.4 Peer LDP Ident: 2.2.2.2:0; Local LDP Ident 1.1.1.1:0 TCP connection: 2.2.2.2.26293 - 1.1.1.1.646 State: Oper; Msgs sent/rcvd: 298/296; Downstream Up time: 04:10:57 LDP discovery sources: Targeted Hello 1.1.1.1 -> 2.2.2.2, active, passive Addresses bound to peer LDP Ident: 2.2.2.2 10.2.4.2 Peer LDP Ident: 3.3.3.3:0; Local LDP Ident 1.1.1.1:0 TCP connection: 3.3.3.3.20815 - 1.1.1.1.646 State: Oper; Msgs sent/rcvd: 293/296; Downstream Up time: 04:09:47 LDP discovery sources: Targeted Hello 1.1.1.1 -> 3.3.3.3, active, passive Addresses bound to peer LDP Ident: 3.3.3.3 10.3.4.3
We can see we have 3 LDP neighbors, two of which is targeted. This is what we would expect with out 2 Xconnects.
R1#sh mpls l2transport vc Local intf Local circuit Dest address VC ID Status
Se2/0 FR DLCI 506 2.2.2.2 1001 UP Se2/0 FR DLCI 507 3.3.3.3 1002 UP
We can also see that we have L2 transports up and running.
Lets check out the labels that we will be using on R1:
R1#sh mpls l2transport binding Destination Address: 2.2.2.2, VC ID: 1001 Local Label: 109 Cbit: 1, VC Type: FR DLCI, GroupID: 0 MTU: 1500, Interface Desc: n/a VCCV: CC Type: CW [1], RA [2] CV Type: LSPV [2] Remote Label: 207 Cbit: 1, VC Type: FR DLCI, GroupID: 0 MTU: 1500, Interface Desc: n/a VCCV: CC Type: CW [1], RA [2] CV Type: LSPV [2] Destination Address: 3.3.3.3, VC ID: 1002 Local Label: 110 Cbit: 1, VC Type: FR DLCI, GroupID: 0 MTU: 1500, Interface Desc: n/a VCCV: CC Type: CW [1], RA [2] CV Type: LSPV [2] Remote Label: 307 Cbit: 1, VC Type: FR DLCI, GroupID: 0 MTU: 1500, Interface Desc: n/a VCCV: CC Type: CW [1], RA [2] CV Type: LSPV [2]
For each Xconnect we have a local LDP binding which is the label we send out to the neighbor, for it to use to send data to us. We also have a remote label, we will use when sending data to it.
For the connection to R2, the local label is 109 and the remote label is 207.
For the connection to R3, the local label is 110 and the remote label is 307.
Lets check out the LFIB on R1 again:
R1#sh mpls for Local Outgoing Prefix Bytes Label Outgoing Next Hop Label Label or VC or Tunnel Id Switched interface 100 Pop Label 4.4.4.4/32 0 PO1/0 point2point 101 401 3.3.3.3/32 0 PO1/0 point2point 102 400 2.2.2.2/32 0 PO1/0 point2point 103 Pop Label 10.2.4.0/24 0 PO1/0 point2point 104 Pop Label 10.3.4.0/24 0 PO1/0 point2point 109 No Label l2ckt(1001) 510 Se2/0 point2point 110 No Label l2ckt(1002) 510 Se2/0 point2point
We can see that we have the two local labels, 109 and 110 in there. Basically telling R1 that when receiving a packet with a label of 109 it is to go out of serial2/0 and use the appropriate encapsulation for this according to the l2transport already setup. With 109 thats the frame-relay encapsulation with the DLCI of 506.
On R2 and R3, we should see something similar:
R2#sh mpls l2transport vc Local intf Local circuit Dest address VC ID Status
Se2/0 FR DLCI 605 1.1.1.1 1001 UP
And R3:
R3#sh mpls l2transport vc Local intf Local circuit Dest address VC ID Status
Se2/0 FR DLCI 705 1.1.1.1 1002 UP
Great, now lets goto the customer side of things, and check what we have configured on R5, our hub:
R5#sh run int s0/0 ! ! interface Serial0/0 ip address 100.100.100.5 255.255.255.0 encapsulation frame-relay ip ospf priority 100 clock rate 2000000 frame-relay map ip 100.100.100.6 506 broadcast frame-relay map ip 100.100.100.7 507 broadcast end R5#sh run | beg router ospf router ospf 1 log-adjacency-changes network 0.0.0.0 255.255.255.255 area 0 neighbor 100.100.100.6 neighbor 100.100.100.7 !
Okay, the customer is running OSPF in a hub and spoke fashion that matches what we have setup L2 wise. Since by default a frame-relay main interface will be treated as a non-broadcast interface, neighbors are set up statically.
And on R6:
R6#sh run int s0/0 Building configuration… Current configuration : 220 bytes ! interface Serial0/0 ip address 100.100.100.6 255.255.255.0 encapsulation frame-relay ip ospf priority 0 clock rate 2000000 frame-relay map ip 100.100.100.7 605 frame-relay map ip 100.100.100.5 605 broadcast end R6#sh run | sec router ospf router ospf 1 log-adjacency-changes network 0.0.0.0 255.255.255.255 area 0
Slightly different here as this is one of the spoke sites. We run OSPF on all interfaces, and we also map the remote spoke’s IP address towards the hub in order to have full reachability in the RIB.
R7 is almost identical:
R7#sh run int s0/0 ! ! interface Serial0/0 ip address 100.100.100.7 255.255.255.0 encapsulation frame-relay ip ospf priority 0 clock rate 2000000 frame-relay map ip 100.100.100.6 705 frame-relay map ip 100.100.100.5 705 broadcast end R7#sh run | sec router ospf router ospf 1 log-adjacency-changes network 0.0.0.0 255.255.255.255 area 0
Same thing except the mapping towards the hub.
So lets actually send traffic across the core network from each of the customer sites:
R5#ping 6.6.6.6 so loo0 Sending 5, 100-byte ICMP Echos to 6.6.6.6, timeout is 2 seconds: Packet sent with a source address of 5.5.5.5 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 4/24/32 ms R5#ping 7.7.7.7 so loo0 Sending 5, 100-byte ICMP Echos to 7.7.7.7, timeout is 2 seconds: Packet sent with a source address of 5.5.5.5 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 24/50/84 ms
On R4, which is the only P router, we can see what happens when R5 pinged R6:
(with debug mpls packet)
*Apr 4 22:17:29.530: MPLS turbo: PO2/0: rx: Len 118 Stack {400 0 255} {207 0 255} CW {0 0 0} *Apr 4 22:17:29.530: MPLS turbo: PO1/0: tx: Len 114 Stack {207 0 254} CW {0 0 0}
R4 receives the packet with two labels, the transport label being 400 and the inner label or AToM label of 207.
When we send it towards R2, we pop the outer label (due to PHP) leaving only the AToM label which R2 can use to goto the correct attachment circuit.
So there we have it.
The customer has a working frame-relay network, that is no different from their point of view, without the service provider having to spend money on legacy frame-switching technology.
I think its a very nice concept that could be used in the real world to allow service providers to keep supporting legacy installations. Depending on the SLA and CIR’s for the connections, the service provider might want to use traffic engineering, but thats a different story.
Until next time, i hope you have fun with AToM (Great name at least!).