Hub-and-Spoke VPN on a Single PE-Router
Yesterday’s blog post discussed the traffic flow and the routing information flow in a hub-and-spoke VPN design (a design in which all traffic between spokes flows through the hub site). It’s time to implement and test it, starting with the simplest possible scenario: a single PE router using inter-VRF route leaking to connect the VRFs.
Here’s the baseline netlab lab topology we’ll use:
defaults.device: eos
provider: clab
groups:
ce:
device: frr
members: [ ce_s1, ce_s2, ce_hub ]
vrfs:
s_1:
links: [ pe-ce_s1 ]
s_2:
links: [ pe-ce_s2 ]
hub_ingress:
links: [ pe-ce_hub ]
hub_egress:
links: [ pe-ce_hub ]
nodes:
pe:
module: [ bgp, vrf ]
bgp.as: 65000
ce_hub:
ce_s1:
ce_s2:
Notes
- We’ll use cEOS as the PE-router (lines 1-2) and FRR containers as the CE-routers (lines 4-7)
- We need four VRFs (s_1, s_2, hub_ingress, hub_egress) and a link in every VRF (lines 9-17)
- We need the VRF and the BGP configuration module on the PE router. We also have to specify the BGP AS number for the PE router (lines 19-22)
Next, let’s add the PE-CE routing protocol. We’ll use BGP to see the nodes (AS numbers) a route traverses. All we have to add to the lab topology is the BGP configuration module on all devices and the BGP AS numbers for the CE routers. netlab will take care of EBGP sessions.
module: [ bgp ]
nodes:
pe:
bgp.as: 65000
ce_hub:
bgp.as: 65100
ce_s1:
bgp.as: 65101
ce_s2:
bgp.as: 65102
Finally, we need route leaking between VRFs. Let’s use the diagram from the previous blog post as a reminder:
In a nutshell:
- All spoke routes must be exported to the
hub_egress
VRF. - Spoke VRFs have to import routes from the
hub_ingress
VRF.
Here’s the relevant lab topology snippet:
vrfs:
s_1:
export: [ hub_egress ]
import: [ hub_ingress ]
s_2:
export: [ hub_egress ]
import: [ hub_ingress ]
Finally, we need the AS-override configured on the EBGP session in the hub_ingress
VRF. We have to add the bgp_session plugin to the lab topology and bgp.as_override to the ce_hub
part of the hub_ingress
link:
plugin: [ bgp.session ]
vrfs:
hub_ingress:
links:
- pe:
ce_hub:
bgp.as_override: True
The complete lab topology is available in the netlab-examples GitHub repository.
Kicking the Tires
Let’s start the lab. The easiest way to do it is to:
- Open the netlab-examples repository in a GitHub Codespace
- Copy the cEOS container into the codespace
- Change directory to
VRF/vrf-hub-spoke
- Execute netlab up
Alternatively, you could execute netlab up -d frr if you don’t want to waste time with Arista cEOS containers.
Done? Let’s look at the results. Here’s the BGP table on CE_S1:
$ netlab connect ce_s1 --show ip bgp
Connecting to container clab-vrf-hub-spok-ce_s1, executing vtysh -c "show ip bgp"
BGP table version is 7, local router ID is 10.0.0.3, vrf id 0
Default local pref 100, local AS 65101
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.2/32 10.1.0.2 0 65000 65100 i
*> 10.0.0.3/32 0.0.0.0(ce_s1) 0 32768 i
*> 10.0.0.4/32 10.1.0.2 0 65000 65100 65100 65102 i
*> 10.1.0.0/30 10.1.0.2 0 65000 i
*> 10.1.0.4/30 10.1.0.2 0 65000 65100 65100 i
*> 10.1.0.8/30 10.1.0.2 0 65000 i
*> 10.1.0.12/30 10.1.0.2 0 65000 65100 65100 i
Knowing the lab addressing scheme would make the decoding process easier, so here it is:
Node/Interface | IPv4 Address | IPv6 Address | Description |
---|---|---|---|
ce_hub | 10.0.0.2/32 | Loopback | |
eth1 | 10.1.0.9/30 | ce_hub -> pe | |
eth2 | 10.1.0.13/30 | ce_hub -> pe | |
ce_s1 | 10.0.0.3/32 | Loopback | |
eth1 | 10.1.0.1/30 | ce_s1 -> pe | |
ce_s2 | 10.0.0.4/32 | Loopback | |
eth1 | 10.1.0.5/30 | ce_s2 -> pe | |
pe | 10.0.0.1/32 | Loopback | |
Ethernet1 | 10.1.0.2/30 | pe -> ce_s1 (VRF: s_1) | |
Ethernet2 | 10.1.0.6/30 | pe -> ce_s2 (VRF: s_2) | |
Ethernet3 | 10.1.0.10/30 | pe -> ce_hub (VRF: hub_ingress) | |
Ethernet4 | 10.1.0.14/30 | pe -> ce_hub (VRF: hub_egress) |
CE_S1 received routes for the loopback addresses of CE_S2 (10.0.0.4/32) and CE_HUB (10.0.0.2/32), as well as the routes for the connecting subnets1. The AS path attached to the CE_S2 prefix contains 65102 (CE_S2), two copies of 65100 (PE AS changed by the CE_HUB plus the CE_HUB AS), and 65000 (PE). The routing information exchange works.
Let’s run traceroute from CE_S1 to CE_S2:
$ netlab connect ce_s1 traceroute ce_s2
Connecting to container clab-vrf-hub-spok-ce_s1, executing traceroute ce_s2
traceroute to ce_s2 (10.0.0.4), 30 hops max, 46 byte packets
1 pe-s_1 (10.1.0.2) 0.003 ms 0.001 ms 0.001 ms
2 ce_hub (10.1.0.13) 0.787 ms 0.139 ms 0.079 ms
3 pe-hub_egress (10.1.0.14) 0.062 ms 0.045 ms 0.043 ms
4 ce_s2 (10.0.0.4) 0.172 ms 0.140 ms 0.135 ms
The printout tells us that the packets traverse s_1
VRF on PE, CE_HUB, and hub_egress
VRF on PE before arriving at CE_S2. Mission accomplished.
We can also trace the propagation of BGP routing information between VRFs on the PE router:
pe>show ip bgp 10.0.0.4/32 vrf all
BGP routing table information for VRF default
Router identifier 10.0.0.1, local AS number 65000
BGP routing table information for VRF hub_egress
Router identifier 10.0.0.1, local AS number 65000
BGP routing table entry for 10.0.0.4/32
Paths: 1 available
65102
10.1.0.5 from 10.1.0.5 (10.0.0.4), imported VPN-IPv4 route, RD 65000:2
Origin IGP, metric 0, localpref 100, IGP metric 0, weight 0, tag 0
Received 00:04:30 ago, valid, external, best
Extended Community: Route-Target-AS:65000:4
Rx SAFI: Unicast
Leaked from VRF s_2
BGP routing table information for VRF hub_ingress
Router identifier 10.0.0.1, local AS number 65000
BGP routing table entry for 10.0.0.4/32
Paths: 1 available
65100 65100 65102
10.1.0.9 from 10.1.0.9 (10.0.0.2)
Origin IGP, metric 0, localpref 100, IGP metric 0, weight 0, tag 0
Received 00:04:29 ago, valid, external, best
Rx SAFI: Unicast
BGP routing table information for VRF s_1
Router identifier 10.0.0.1, local AS number 65000
BGP routing table entry for 10.0.0.4/32
Paths: 1 available
65100 65100 65102
10.1.0.9 from 10.1.0.9 (10.0.0.2), imported VPN-IPv4 route, RD 65000:3
Origin IGP, metric 0, localpref 100, IGP metric 0, weight 0, tag 0
Received 00:04:29 ago, valid, external, best
Extended Community: Route-Target-AS:65000:3
Rx SAFI: Unicast
Leaked from VRF hub_ingress
BGP routing table information for VRF s_2
Router identifier 10.0.0.1, local AS number 65000
BGP routing table entry for 10.0.0.4/32
Paths: 2 available
65102
10.1.0.5 from 10.1.0.5 (10.0.0.4)
Origin IGP, metric 0, localpref 100, IGP metric 0, weight 0, tag 0
Received 00:04:30 ago, valid, external, best
Rx SAFI: Unicast
65100 65100 65102
10.1.0.9 from 10.1.0.9 (10.0.0.2), imported VPN-IPv4 route, RD 65000:3
Origin IGP, metric 0, localpref 100, IGP metric 0, weight 0, tag 0
Received 00:04:29 ago, valid, external
Extended Community: Route-Target-AS:65000:3
Rx SAFI: Unicast
Leaked from VRF hub_ingress
- VRF S_2 has a route for 10.0.0.4/32 that was advertised by CE_S2 (lines 39-43), and another route leaked from the
hub_ingress
VRF (lines 44-50). The route advertised by CE_S2 is better due to a shorter AS path (line 42) - The best route from VRF S_2 is leaked into the
hub_egress
VRF (lines 6-14). - The BGP route in the
hub_egress
VRF is advertised to CE_HUB. - CE_HUB advertises the same route (with a longer AS path) back to the PE router, this time in the
hub_ingress
VRF (lines 17-23). Please note how the BGP next hop has changed from 10.1.0.5 (CE_S2) to 10.1.0.9 (CE_HUB). - The route from the
hub_ingress
VRF is leaked into thes_1
(lines 26-34) ands_2
VRF (lines 44-50). - The route leaked from the
hub_ingress
VRF into thes_1
VRF is the only route for 10.0.0.4/32 in that VRF. It’s selected as the best BGP route (line 31) and advertised to CE_S1.
It’s also interesting to inspect the inter-VRF forwarding information displayed by the show ip route vrf all command. This bit is left as an exercise for the readers who were interested enough to start the lab ;)
Next: EVPN Hub-and-Spoke Layer-3 VPN Continue
Reference Information
This is the relevant part of the PE configuration. It was generated exclusively with netlab configuration templates; all I did was run netlab up and enjoy the results.
vrf instance hub_egress
rd 65000:4
!
vrf instance hub_ingress
rd 65000:3
!
vrf instance s_1
rd 65000:1
!
vrf instance s_2
rd 65000:2
!
interface Ethernet1
description pe -> ce_s1 [external]
vrf s_1
ip address 10.1.0.2/30
!
interface Ethernet2
description pe -> ce_s2 [external]
vrf s_2
ip address 10.1.0.6/30
!
interface Ethernet3
description pe -> ce_hub [external]
vrf hub_ingress
ip address 10.1.0.10/30
!
interface Ethernet4
description pe -> ce_hub [external]
vrf hub_egress
ip address 10.1.0.14/30
!
interface Loopback0
ip address 10.0.0.1/32
!
interface Management0
vrf management
ip address 192.168.121.101/24
no lldp transmit
no lldp receive
!
ip routing
ip routing vrf hub_egress
ip routing vrf hub_ingress
ip routing vrf s_1
ip routing vrf s_2
!
mpls ip
!
router bgp 65000
router-id 10.0.0.1
no bgp default ipv4-unicast
bgp advertise-inactive
network 10.0.0.1/32
!
vrf hub_egress
rd 65000:4
route-target import vpn-ipv4 65000:4
route-target export vpn-ipv4 65000:4
router-id 10.0.0.1
neighbor 10.1.0.13 remote-as 65100
neighbor 10.1.0.13 description ce_hub
neighbor 10.1.0.13 send-community standard large
!
address-family ipv4
neighbor 10.1.0.13 activate
redistribute connected
!
vrf hub_ingress
rd 65000:3
route-target import vpn-ipv4 65000:3
route-target export vpn-ipv4 65000:3
router-id 10.0.0.1
neighbor 10.1.0.9 remote-as 65100
neighbor 10.1.0.9 description ce_hub
neighbor 10.1.0.9 send-community standard large
!
address-family ipv4
neighbor 10.1.0.9 activate
redistribute connected
!
vrf s_1
rd 65000:1
route-target import vpn-ipv4 65000:3
route-target export vpn-ipv4 65000:4
router-id 10.0.0.1
neighbor 10.1.0.1 remote-as 65101
neighbor 10.1.0.1 description ce_s1
neighbor 10.1.0.1 send-community standard large
!
address-family ipv4
neighbor 10.1.0.1 activate
redistribute connected
!
vrf s_2
rd 65000:2
route-target import vpn-ipv4 65000:3
route-target export vpn-ipv4 65000:4
router-id 10.0.0.1
neighbor 10.1.0.5 remote-as 65102
neighbor 10.1.0.5 description ce_s2
neighbor 10.1.0.5 send-community standard large
!
address-family ipv4
neighbor 10.1.0.5 activate
redistribute connected
-
That will come in handy when we run traceroute; figuring out why we need the connecting subnets is left as an exercise for the reader. ↩︎