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