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:

Logical Frame-Relay Network

Logical Frame-Relay network as seen by the Customer

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:

Physical core topology as seen by the Service Provider

Physical core topology as seen by the Service Provider

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!).