PE NAT

Did you know that NAT on IOS can be VRF-aware? You can NAT hosts from multiple VRFs to the same IP address, or pool of IP addresses. This can be used to easily offer internet access to an L3VPN service.

There are two types of PE NAT: Ingress and Egress. As the name suggests, Ingress NAT is when you NAT at the Ingress PE. In this case, the NAT function is potentially distributed among several PEs. Egress NAT is when you NAT at the Egress PE, which is typically only a single PE. (The PE that connects to the external shared service).

The beauty of NAT for L3VPN is that the router handles “remembering” which VRF the source came from, using a pointer in the NAT translation table which we will see in the lab.

The downside of PE NAT is that you must NAT to an interface in the global table. So PE NAT can really only be used if you run your internet routing in the global table. If you want to NAT to another VRF, you cannot use egress PE NAT. Instead you need to use ingress PE NAT and you need to leak routes for the underlying IGP address (which will be used as a NAT) to the target VRF. This is a huge burden, and I believe it is for this reason that we don’t see this feature used much in the real world. More often we will see the CPE doing NAT, with route leaking between VRFs using RTs.

Lab

We will use the following topology:

The setup so far is a standard L3VPN configuration that you are familiar with. CustomerA and CustomerB each have their own VRF. Gi2 on PE2 is in the global table and represents internet connectivity.

Here are the startup configs:

#Internet
hostname Internet
!
int Gi1
 ip address 8.8.8.8 255.255.255.0
 no shut
!
ip route 0.0.0.0 0.0.0.0 8.8.8.1

#PE2
hostname PE2
!
int Gi1
 ip address 10.1.2.2 255.255.255.0
 no shut
 ip ospf network point-to-point
 ip ospf 1 area 0
 mpls ip
!
int Gi2
 ip address 8.8.8.1 255.255.255.0
 no shut
!
int Lo0
 ip address 2.2.2.2 255.255.255.255
 ip ospf 1 area 0
!
router bgp 100
 neighbor 1.1.1.1 remote-as 100
 neighbor 1.1.1.1 update-source Lo0
 !
 address-family vpnv4 unicast
  neighbor 1.1.1.1 activate

#PE1
hostname PE1
!
ip vrf CustA
 rd 1:1
 route-target both 1:1
!
ip vrf CustB
 rd 2:2
 route-target both 2:2
!
int Gi1
 ip address 10.1.2.1 255.255.255.0
 no shut
 ip ospf network point-to-point
 ip ospf 1 area 0
 mpls ip
!
int Gi2
 ip vrf forwarding CustA
 ip address 100.64.0.1 255.255.255.252
 no shut
!
int Gi3
 ip vrf forwarding CustB
 ip address 100.64.0.1 255.255.255.252
 no shut
!
int Lo0
 ip address 1.1.1.1 255.255.255.255
 ip ospf 1 area 0
!
router bgp 100
 neighbor 2.2.2.2 remote-as 100
 neighbor 2.2.2.2 update-source Lo0
 !
 address-family vpnv4 unicast
  neighbor 2.2.2.2 activate
 !
 address-family ipv4 vrf CustA
  neighbor 100.64.0.2 remote-as 65000 
  neighbor 100.64.0.2 activate
 !
 address-family ipv4 vrf CustB
  neighbor 100.64.0.2 remote-as 65000 
  neighbor 100.64.0.2 activate

#CustomerA
hostname CustomerA
!
int Gi1
 ip address 100.64.0.2 255.255.255.252
 no shut
!
int Lo0
 ip address 10.1.1.1 255.255.255.0
!
router bgp 65000
 neighbor 100.64.0.1 remote-as 100
 network 10.1.1.0 mask 255.255.255.0

#CustomerB
hostname CustomerB
!
int Gi1
 ip address 100.64.0.2 255.255.255.252
 no shut
!
int Lo0
 ip address 10.1.1.1 255.255.255.0
!
router bgp 65000
 neighbor 100.64.0.1 remote-as 100
 network 10.1.1.0 mask 255.255.255.0

Egress PE NAT

PE2 will provide NAT and a route to the internet, acting as the egress PE. To do this, PE2 needs to add the customer VRFs and inject a default route into each L3VPN.

#PE2
ip vrf CustA
 rd 1:1
 route-target both 1:1
ip vrf CustB
 rd 2:2
 route-target both 2:2
!
ip route vrf CustA 0.0.0.0 0.0.0.0 8.8.8.8 global
ip route vrf CustB 0.0.0.0 0.0.0.0 8.8.8.8 global
!
router bgp 100
 address-family ipv4 vrf CustA
  network 0.0.0.0
 address-family ipv4 vrf CustB
  network 0.0.0.0

Both CustomerA and CustomerB should now have a default route in their routing table:

CustomerA#show ip route | beg Gateway
Gateway of last resort is 100.64.0.1 to network 0.0.0.0

B*    0.0.0.0/0 [20/0] via 100.64.0.1, 00:01:06
      10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        10.1.1.0/24 is directly connected, Loopback0
L        10.1.1.1/32 is directly connected, Loopback0
      100.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        100.64.0.0/30 is directly connected, GigabitEthernet1
L        100.64.0.2/32 is directly connected, GigabitEthernet1

CustomerB#show ip route | beg Gateway
Gateway of last resort is 100.64.0.1 to network 0.0.0.0

B*    0.0.0.0/0 [20/0] via 100.64.0.1, 00:01:05
      10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        10.1.1.0/24 is directly connected, Loopback0
L        10.1.1.1/32 is directly connected, Loopback0
      100.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        100.64.0.0/30 is directly connected, GigabitEthernet1
L        100.64.0.2/32 is directly connected, GigabitEthernet1

Next, all we need to do is enable NAT on PE2. Gi1 will be the inside interface, and Gi2 will be the outside interface. It may seem a little strange that Gi1, a core interface, is the inside interface, but the router will automatically decipher the VRF the traffic belongs to via the MPLS label. This happens because we specify that the NAT translation is for each VRF.

#PE2
int Gi1
 ip nat inside
!
int Gi2
 ip nat outside
!
access-list 100 permit ip any any
!
ip nat inside source list 100 int Gi2 vrf CustA overload
ip nat inside source list 100 int Gi2 vrf CustB overload

We’ll now ping 8.8.8.8 from both customer routers:

CustomerA#ping 8.8.8.8 source lo0
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds:
Packet sent with a source address of 10.1.1.1 
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 3/3/4 ms

CustomerB#ping 8.8.8.8 source lo0
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds:
Packet sent with a source address of 10.1.1.1 
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 4/8/15 ms

By checking the verbose NAT translations on PE2, we can see how this works:

PE2#show ip nat translations verbose 
Pro  Inside global         Inside local          Outside local         Outside global
icmp 8.8.8.1:8             10.1.1.1:8            8.8.8.8:8             8.8.8.8:8
  create: 12/06/22 14:47:17, use: 12/06/22 14:47:17, timeout: 00:00:27
  RuleID : 6
  Flags: unknown
  ALG Application Type: NA
  WLAN-Flags: unknown
  Mac-Address: 0000.0000.0000    Input-IDB: GigabitEthernet1
  VRF: CustB,  entry-id: 0xe96d3040, use_count:1
  In_pkts: 5 In_bytes: 400, Out_pkts: 5 Out_bytes: 400 
  Output-IDB: GigabitEthernet2 

icmp 8.8.8.1:10            10.1.1.1:10           8.8.8.8:10            8.8.8.8:10
  create: 12/06/22 14:47:21, use: 12/06/22 14:47:21, timeout: 00:00:31
  RuleID : 5
  Flags: unknown
  ALG Application Type: NA
  WLAN-Flags: unknown
  Mac-Address: 0000.0000.0000    Input-IDB: GigabitEthernet1
  VRF: CustA,  entry-id: 0xe96d3180, use_count:1
  In_pkts: 5 In_bytes: 400, Out_pkts: 5 Out_bytes: 400 
  Output-IDB: GigabitEthernet2 

Total number of translations: 2

You can see above that the router is able to keep track of which VRF each client belongs to. In this case, both customers are using 10.1.1.1 as the source IP, but they are differentiated based on the MPLS label as traffic arrives from PE1 ingress on Gi1.

On PE1, you can see that the 0/0 route injected by PE2 for each VRF has a different MPLS service label. When traffic arrives on Gi1, PE2 uses this label to figure out which VRF the traffic belongs to.

! RD 1:1 is for CustA
PE1#show bgp vpnv4 uni rd 1:1 0.0.0.0/0 | in label
      mpls labels in/out nolabel/17

! RD 2:2 is for CustB
PE1#show bgp vpnv4 uni rd 2:2 0.0.0.0/0 | in label
      mpls labels in/out nolabel/19

The problem with Egress PE VRF-to-VRF NAT

Now you can understand the problem that occurs if you want to NAT to another VRF using egress PE NAT.

If you use RTs to inject a 0/0 route from another VRF into the customer VRFs, traffic ingressing Gi1 on PE2 will all appear with the same service label, which is for the shared-service VRF. PE2 will not be able to differentiate between the different customer VRFs, because all traffic has the same service label (representing the shared-service VRF).

Let’s try this out to really understand what happens:

#PE2
! Remove the 0/0 route for the customer VRFs
no ip route vrf CustA 0.0.0.0 0.0.0.0 8.8.8.8 global
no ip route vrf CustB 0.0.0.0 0.0.0.0 8.8.8.8 global
!
router bgp 100
 no address-family ipv4 vrf CustA
 no address-family ipv4 vrf CustB

! Move Gi2 to a VRF
ip vrf SHARED
 rd 10:10
 route-target both 10:10

int Gi2
 ip vrf forwarding SHARED
 ip address 8.8.8.1 255.255.255.0

! Inject a default for vrf SHARED
ip route vrf SHARED 0.0.0.0 0.0.0.0 8.8.8.8
!
router bgp 100
 address-family ipv4 vrf SHARED
  network 0.0.0.0

#PE1
! Import routes from vrf SHARED into the customer VRFs
ip vrf CustA
 route-target import 10:10
!
ip vrf CustB
 route-target import 10:10

Of course, we would also need the SHARED vrf to have reachability to the customer VRFs, but this is enough to demonstrate why this doesn’t work in the first place.

The customer routers have a 0/0 route again, but traffic ingressing Gi1 has the same service label for vrf SHARED (label 20) whether traffic comes from CustomerA or CustomerB.

  • Ping from CustomerA

  • Ping from CustomerB

To solve this, we would need to use ingress PE NAT.

Ingress PE NAT

Functionaly, PE NAT for the ingress PE works just like PE NAT for the egress PE. The difference is that you will be NATing to an address that is known in the core IGP. This is a bit ugly. I suppose you would need to have public addressing between core routers for this to work. For this lab, we’ll just pretend that 10.1.2.0/24 is reachable on the internet.

To preform ingress PE NAT on PE1, we use the same configuration as we saw for egress PE NAT on PE2:

access-list 100 permit ip any any
!
int Gi2
 ip nat inside
!
int Gi3
 ip nat inside
!
int Gi1
 ip nat outside
!
ip nat inside source list 100 interface Gi1 vrf CustA overload
ip nat inside source list 100 interface Gi1 vrf CustB overload

Next, PE2 will need to route 10.1.2.0/24 back to the global table on the SHARED VRF. Return traffic from 8.8.8.8 will be destined for 10.1.2.1.

#PE2
ip route vrf SHARED 10.1.2.0 255.255.255.0 10.1.2.1 global

Both customer routers can ping 8.8.8.8 again. They are both being NATed to 10.1.2.2.

CustomerA#ping 8.8.8.8 source lo0         
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds:
Packet sent with a source address of 10.1.1.1 
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 2/2/3 ms

CustomerB#ping 8.8.8.8 source lo0         
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds:
Packet sent with a source address of 10.1.1.1 
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 3/4/5 ms

Further Reading

https://www.cisco.com/c/en/us/support/docs/ip/network-address-translation-nat/112084-ios-nat-mpls-vpn-00.html

Last updated