LAB: Load sharing internet traffic in a small branch office using PBR

Scenario:
Office network consists of two internet facing SRX firewalls (FW1 and FW2) and L3 main switch (CORE-SW1). Core switch can be from any vendor, in our case, its cisco. Firewalls have uplinks two different ISPs, FW1 is connected to ISP1 and FW2 is connected to FW2. CORE-SW1 has L3 uplinks to each SRX and has a couple of different VLAN L3 interfaces where users live, and a switch is a default gateway for LAN devices.
Both firewalls have IPsecVPN links to the datacenter network, which consists of actually two datacenters connected via 10g DCI. Clients/Users of the remote office need to be able to connect to the internet and also to the datacenter via IPsecVPN. We need to be able to fail over to the secondary ISP should the primary fail. Active/Active scenario is preferred.

 

IP addressing schema:
Loopback interfaces: Core-sw1: 200.126.10.3; FW1: 200.126.10.1; FW2: 200.126.10.2; DC1-FW: 200.100.0.99; DC2-FW: 200.120.0.99
Core-sw1 to FW1: 200.126.253.0/24; Core-sw1 to FW2: 200.126.254.0/24; FW1 to FW2: 200.126.255.0
FW1 to DC1-FW: 200.255.7.0/24; FW2 to DC2-FW: 200.254.7.0/24;

DC1-R1 and DC2-R1 have few loopbacks configured, representing DC1 network:
DC1-R1: 200.100.100.1/32, 200.100.101.1/32;
DC2-R1: 200.120.200.1/32, 200.120.201.1/32

FW1 internet link: 11.11.11.2/24, default gw: 11.11.11.1/24
FW2 internet link: 22.22.22.2/24, default gw: 22.22.22.1/24.

Configuration.
Core-Sw1 configuration is very straight forward - vlans, vlan interfaces and ospf. In our case, we don't have vlan configured, instead we will have loopback interfaces to source the traffic from during the test:

CORE-SW1#sh ip int br | include up Ethernet0/0 10.126.253.11 YES NVRAM up up Ethernet0/1 10.126.254.11 YES NVRAM up up Loopback0 10.126.10.3 YES NVRAM up up Loopback11 10.126.11.1 YES manual up up Loopback12 10.126.12.1 YES manual up up CORE-SW1#
CORE-SW1#sh running-config Building configuration... hostname CORE-SW1 no ip domain lookup ip cef no ipv6 cef interface Loopback0 ip address 10.126.10.3 255.255.255.0 ! interface Loopback11 ip address 10.126.11.1 255.255.255.255 ! interface Loopback12 ip address 10.126.12.1 255.255.255.255 ! interface Ethernet0/0 ip address 10.126.253.11 255.255.255.0 ! interface Ethernet0/1 ip address 10.126.254.11 255.255.255.0 ip ospf cost 50 ! router ospf 1 network 10.0.0.0 0.255.255.255 area 0 ! ip forward-protocol nd ! end CORE-SW1#



SRX firewalls configuration:
We will define the following zones: UNTRUST (internet interface - ge-0/0/2), TRUST (internal interface - ge-0/0/1 and inter-firewall ge-0/0/0), VPN (ipsecvpn interface to the datacenter - ge-0/0/3).
* for the simplicity we will not be building IPSecVPN tunnel to the datacenter, instead we will just use a regular link.
 

root@FW1> show configuration interfaces | display set set interfaces ge-0/0/0 unit 0 family inet address 200.126.100.1/24 set interfaces ge-0/0/1 unit 0 family inet filter input PBR1 set interfaces ge-0/0/1 unit 0 family inet address 200.126.253.1/24 set interfaces ge-0/0/2 unit 0 family inet address 11.11.11.2/24 set interfaces ge-0/0/3 unit 0 family inet address 200.255.7.1/24 set interfaces lo0 unit 0 family inet address 200.126.10.1/32 set security zones security-zone TRUST host-inbound-traffic system-services all set security zones security-zone TRUST host-inbound-traffic protocols all set security zones security-zone TRUST interfaces ge-0/0/0.255 set security zones security-zone TRUST interfaces ge-0/0/1.0 set security zones security-zone TRUST interfaces lo0.0 set security zones security-zone UNTRUST screen UNTRUST-screen set security zones security-zone UNTRUST interfaces ge-0/0/2.0 set security zones security-zone VPN host-inbound-traffic system-services all set security zones security-zone VPN host-inbound-traffic protocols all set security zones security-zone VPN interfaces ge-0/0/3.0 set security policies from-zone TRUST to-zone TRUST policy default-permit match source-address any set security policies from-zone TRUST to-zone TRUST policy default-permit match destination-address any set security policies from-zone TRUST to-zone TRUST policy default-permit match application any set security policies from-zone TRUST to-zone TRUST policy default-permit then permit set security policies from-zone TRUST to-zone UNTRUST policy default-permit match source-address any set security policies from-zone TRUST to-zone UNTRUST policy default-permit match destination-address any set security policies from-zone TRUST to-zone UNTRUST policy default-permit match application any set security policies from-zone TRUST to-zone UNTRUST policy default-permit then permit set security policies from-zone UNTRUST to-zone TRUST policy default-deny match source-address any set security policies from-zone UNTRUST to-zone TRUST policy default-deny match destination-address any set security policies from-zone UNTRUST to-zone TRUST policy default-deny match application any set security policies from-zone UNTRUST to-zone TRUST policy default-deny then deny set security policies from-zone TRUST to-zone VPN policy PERMIT-ALL match source-address any set security policies from-zone TRUST to-zone VPN policy PERMIT-ALL match destination-address any set security policies from-zone TRUST to-zone VPN policy PERMIT-ALL match application any set security policies from-zone TRUST to-zone VPN policy PERMIT-ALL then permit set security policies from-zone VPN to-zone TRUST policy PERMIT-ALL match source-address any set security policies from-zone VPN to-zone TRUST policy PERMIT-ALL match destination-address any set security policies from-zone VPN to-zone TRUST policy PERMIT-ALL match application any set security policies from-zone VPN to-zone TRUST policy PERMIT-ALL then permit set security policies from-zone TRUST to-zone UNTRUST2 policy PERMIT-ALL match source-address any set security policies from-zone TRUST to-zone UNTRUST2 policy PERMIT-ALL match destination-address any set security policies global policy permit-all match source-address any set security policies global policy permit-all match destination-address any set security policies global policy permit-all match application any set security policies global policy permit-all then permit set security policies default-policy permit-all set routing-options static route 0.0.0.0/0 next-hop 11.11.11.1 set routing-options aggregate route 200.126.0.0/16 set routing-options autonomous-system 64527 set protocols bgp group DC-PEERS type external set protocols bgp group DC-PEERS hold-time 30 set protocols bgp group DC-PEERS export EBGP-POLICY set protocols bgp group DC-PEERS export REJECT-ALL set protocols bgp group DC-PEERS peer-as 64521 set protocols bgp group DC-PEERS neighbor 200.255.7.2 local-address 200.255.7.1 set protocols bgp group IBGP-PEERS type internal set protocols bgp group IBGP-PEERS local-address 200.126.255.1 set protocols bgp group IBGP-PEERS export IBGP-POLICY set protocols bgp group IBGP-PEERS neighbor 200.126.255.2 set protocols ospf export INTO_OSPF set protocols ospf area 0.0.0.0 interface ge-0/0/0.255 set protocols ospf area 0.0.0.0 interface ge-0/0/1.0 set protocols ospf area 0.0.0.0 interface lo0.0 set policy-options prefix-list PBR-EXCEPTION 10.0.0.0/8 set policy-options prefix-list PBR-EXCEPTION 10.120.0.0/16 set policy-options prefix-list PBR-EXCEPTION 172.16.0.0/12 set policy-options prefix-list PBR-EXCEPTION 192.168.0.0/16 set policy-options policy-statement EBGP-POLICY term AGGREGATE from protocol aggregate set policy-options policy-statement EBGP-POLICY term AGGREGATE from route-filter 200.126.0.0/16 exact set policy-options policy-statement EBGP-POLICY term AGGREGATE then accept set policy-options policy-statement EBGP-POLICY term PERMIT-LO from route-filter 200.126.10.1/32 exact set policy-options policy-statement EBGP-POLICY term PERMIT-LO then accept set policy-options policy-statement EBGP-POLICY term PERMIT-PEER-LO from route-filter 200.126.10.2/32 exact set policy-options policy-statement EBGP-POLICY term PERMIT-PEER-LO then metric 50 set policy-options policy-statement EBGP-POLICY term PERMIT-PEER-LO then accept set policy-options policy-statement IBGP-POLICY term NEXT-HOP-SELF then next-hop self set policy-options policy-statement INTO_OSPF term DEFAULT from protocol static set policy-options policy-statement INTO_OSPF term DEFAULT from route-filter 0.0.0.0/0 exact set policy-options policy-statement INTO_OSPF term DEFAULT then accept set policy-options policy-statement REJECT-ALL then reject set security nat source rule-set TO-INTERNET from zone TRUST set security nat source rule-set TO-INTERNET to zone UNTRUST set security nat source rule-set TO-INTERNET rule LAN match source-address 200.126.0.0/16 set security nat source rule-set TO-INTERNET rule LAN then source-nat interface </div></div><div class="sqs-block html-block sqs-block-html" data-block-type="2" id="block-yui_3_17_2_5_1448901401014_14232"><div class="sqs-block-content"> <div class="sqs-html-content"> <p>Config on FW2 looks similar, except internet link address and OSPF metric of the link between Core-sw1 and FW2. Note, that in the configuration of the switch, the ospf cost on interface Ethernet0/1 is 50. FW2 has the same cost for this link:<br /> </p> </div> </div></div><div class="sqs-block code-block sqs-block-code" data-block-type="23" id="block-yui_3_17_2_5_1448901401014_22858"><div class="sqs-block-content"><div style="background-color:#424242; color:#F2F2F2; vertical-align: middle; padding-left:15px; padding-right:15px; "> <xmp style="font-family:Verdana; font-size:10.5px;"> set protocols bgp group DC-PEERS type external set protocols bgp group DC-PEERS hold-time 30 set protocols bgp group DC-PEERS export EBGP-POLICY set protocols bgp group DC-PEERS export REJECT-ALL set protocols bgp group DC-PEERS peer-as 64521 set protocols bgp group DC-PEERS neighbor 10.254.7.2 local-address 10.254.7.1 set protocols bgp group IBGP-PEERS type internal set protocols bgp group IBGP-PEERS local-address 200.126.255.2 set protocols bgp group IBGP-PEERS export IBGP-POLICY set protocols bgp group IBGP-PEERS neighbor 10.126.255.1 set protocols ospf export INTO_OSPF set protocols ospf area 0.0.0.0 interface ge-0/0/0.255 set protocols ospf area 0.0.0.0 interface ge-0/0/1.0 metric 50 set protocols ospf area 0.0.0.0 interface lo0.0

SRX OSPF is configured with export policy, which 'redustributes' only a default route to OSPF, which will be received by the core switch. Because switch does not speak BGP and doesn't know about datacenter routes, it is going to use default route to send traffic to the datacenter.  If both uplinks to FW1 and FW1 form the switch have the same OSPF cost, traffic will be load-balanced and we will be seeing asymmetric routing, which is not going to work, because SRX will be dropping packets, which have no session created. This is the reason why we have a higher cost on the link to FW2. 

Routing verification output:

CORE-SW1#show ip route ospf Gateway of last resort is 200.126.253.1 to network 0.0.0.0 O*E2 0.0.0.0/0 [110/0] via 10.126.253.1, 3d01h, Ethernet0/0 10.0.0.0/8 is variably subnetted, 11 subnets, 2 masks O 200.126.10.1/32 [110/10] via 10.126.253.1, 3d01h, Ethernet0/0 O 200.126.10.2/32 [110/11] via 10.126.253.1, 3d01h, Ethernet0/0 O 200.126.255.0/24 [110/11] via 10.126.253.1, 3d01h, Ethernet0/0 CORE-SW1# root@PDX-FW1> show ospf neighbor Address Interface State ID Pri Dead 200.126.255.2 ge-0/0/0.255 Full 200.126.10.2 128 36 200.126.253.11 ge-0/0/1.0 Full 200.126.11.3 1 36 root@PDX-FW1> show bgp summary Groups: 2 Peers: 2 Down peers: 0 Table Tot Paths Act Paths Suppressed History Damp State Pending inet.0 3 2 0 0 0 0 Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped... 200.126.255.2 64527 21826 21832 0 1 6d 19:39:27 1/1/1/0 0/0/0/0 200.255.7.2 64521 54722 54743 0 1 5d 16:56:17 1/2/2/0 0/0/0/0 root@FW1> show route inet.0: 21 destinations, 23 routes (21 active, 0 holddown, 0 hidden) + = Active Route, - = Last Active, * = Both 0.0.0.0/0 *[Static/5] 3d 01:48:03 > to 11.11.11.1 via ge-0/0/2.0 200.100.0.0/16 *[BGP/170] 5d 16:59:19, MED 20, localpref 100 AS path: 64521 I > to 10.255.7.2 via ge-0/0/3.0 200.120.0.0/16 *[BGP/170] 5d 16:27:03, MED 20, localpref 100 AS path: 64521 I > to 200.126.255.2 via ge-0/0/0.255 [BGP/170] 5d 16:59:19, MED 45, localpref 100 AS path: 64521 I > to 10.255.7.2 via ge-0/0/3.0 200.126.0.0/16 *[Aggregate/130] 6d 23:16:07 Reject 200.126.10.1/32 *[Direct/0] 6d 23:16:07 > via lo0.0 200.126.10.2/32 *[OSPF/10] 3d 02:21:12, metric 1 > to 200.126.255.2 via ge-0/0/0.255 200.126.10.3/32 *[OSPF/10] 3d 02:21:54, metric 2 > to 200.126.253.11 via ge-0/0/1.0 200.126.11.1/32 *[OSPF/10] 3d 02:21:54, metric 2 > to 200.126.253.11 via ge-0/0/1.0 200.126.12.1/32 *[OSPF/10] 3d 02:21:54, metric 2 > to 200.126.253.11 via ge-0/0/1.0 200.126.100.0/24 *[Direct/0] 5d 19:21:51 > via ge-0/0/0.100 200.126.100.1/32 *[Local/0] 5d 19:21:51 Local via ge-0/0/0.100 200.126.253.0/24 *[Direct/0] 6d 23:15:43 > via ge-0/0/1.0 200.126.253.1/32 *[Local/0] 6d 23:15:44 Local via ge-0/0/1.0 200.126.254.0/24 *[OSPF/10] 3d 02:21:12, metric 51 to 200.126.253.11 via ge-0/0/1.0 > to 200.126.255.2 via ge-0/0/0.255 200.126.255.0/24 *[Direct/0] 6d 19:44:09 > via ge-0/0/0.255 200.126.255.1/32 *[Local/0] 6d 19:44:09 Local via ge-0/0/0.255 200.255.7.0/24 *[Direct/0] 5d 16:59:21 > via ge-0/0/3.0 200.255.7.1/32 *[Local/0] 6d 23:15:44 Local via ge-0/0/3.0 11.11.11.0/24 *[Direct/0] 3d 01:48:03 > via ge-0/0/2.0 11.11.11.2/32 *[Local/0] 6d 23:15:44 Local via ge-0/0/2.0 224.0.0.5/32 *[OSPF/10] 3d 02:22:09, metric 1 MultiRecv root@FW2> show route table inet.0: 21 destinations, 23 routes (21 active, 0 holddown, 0 hidden) + = Active Route, - = Last Active, * = Both 0.0.0.0/0 *[Static/5] 3d 02:00:29 > to 22.22.22.1 via ge-0/0/2.0 200.100.0.0/16 *[BGP/170] 5d 17:04:02, MED 20, localpref 100 AS path: 64521 I > to 200.126.255.1 via ge-0/0/0.255 [BGP/170] 5d 16:31:46, MED 45, localpref 100 AS path: 64521 I > to 10.254.7.2 via ge-0/0/3.0 200.120.0.0/16 *[BGP/170] 5d 16:31:46, MED 20, localpref 100 AS path: 64521 I > to 10.254.7.2 via ge-0/0/3.0 200.126.0.0/16 *[Aggregate/130] 6d 23:20:48 Reject 200.126.10.1/32 *[OSPF/10] 3d 02:25:55, metric 1 > to 200.126.255.1 via ge-0/0/0.255 200.126.10.2/32 *[Direct/0] 6d 23:20:48 > via lo0.0 200.126.10.3/32 *[OSPF/10] 3d 02:25:55, metric 3 > to 200.126.255.1 via ge-0/0/0.255 200.126.11.1/32 *[OSPF/10] 3d 02:25:55, metric 3 > to 200.126.255.1 via ge-0/0/0.255 200.126.12.1/32 *[OSPF/10] 3d 02:25:55, metric 3 > to 200.126.255.1 via ge-0/0/0.255 200.126.100.0/24 *[Direct/0] 5d 16:36:02 > via ge-0/0/0.100 200.126.100.2/32 *[Local/0] 5d 16:36:02 Local via ge-0/0/0.100 200.126.253.0/24 *[OSPF/10] 3d 02:25:55, metric 2 > to 200.126.255.1 via ge-0/0/0.255 200.126.254.0/24 *[Direct/0] 6d 23:20:24 > via ge-0/0/1.0 200.126.254.1/32 *[Local/0] 6d 23:20:26 Local via ge-0/0/1.0 200.126.255.0/24 *[Direct/0] 6d 19:47:16 > via ge-0/0/0.255 200.126.255.2/32 *[Local/0] 6d 19:47:16 Local via ge-0/0/0.255 10.254.7.0/24 *[Direct/0] 5d 16:31:50 > via ge-0/0/3.0 10.254.7.1/32 *[Local/0] 6d 23:20:26 Local via ge-0/0/3.0 22.22.22.0/24 *[Direct/0] 3d 02:00:29 > via ge-0/0/2.0 22.22.22.2/32 *[Local/0] 6d 23:20:26 Local via ge-0/0/2.0 224.0.0.5/32 *[OSPF/10] 3d 02:26:40, metric 1 MultiRecv root@FW1> show route advertising-protocol bgp 200.255.7.2 inet.0: 21 destinations, 23 routes (21 active, 0 holddown, 0 hidden) Prefix Nexthop MED Lclpref AS path * 200.126.0.0/16 Self I * 200.126.10.1/32 Self I * 200.126.10.2/32 Self 50 I root@FW2> show route advertising-protocol bgp 200.254.7.2 inet.0: 21 destinations, 23 routes (21 active, 0 holddown, 0 hidden) Prefix Nexthop MED Lclpref AS path * 200.126.0.0/16 Self I * 200.126.10.1/32 Self 50 I * 200.126.10.2/32 Self I

 

Note, that all outbound traffic from core-sw1 is sent to FW1 and it  has to make a decision what to do with it based on its routing table. If its the internet traffic, its going to use a static default route to send it out to ISP1. If its a DC1 traffic, its going to use BGP routes that point to IPSecVPN link with DC1-FW, if its a DC2 traffic, then its going to hit a BGP route pointing to FW2, because FW2 has a better route to DC2 networks that FW1. Al return traffic will be going via FW1, because of OSPF cost of the link between between FW2 and Core-SW. This way we avoid asymmetrical routing and still have a failover working. If ISP1 becomes unavailable (assuming that physical line went down), than default route on FW1 will get withdrawn and IPSecVPN will go down along with BGP session with DC1-FW. FW1 will be getting all DC routes and a default route from FW2.
What if we need to load share Internet links? There are two ways to achieve that:
-- export BGP routes to OSPF so SW1 receives datacenter routes and remove metric of 50 on the link between Core-Sw1 and FW2. Switch will be sending DC traffic to the proper firewall, based on OSPF metric which will be translated form BGP MED attribute.  Default route on the switch will have the same cost and will be load-balanced. Since Internet traffic is source NAT'd on the firewall, there will be no asymmetric routing happening.
-- configure policy based routing (PBR) on FW1 and use ISP1 orFW2=>ISP2 depending on the source IP address. We can have wired clients using ISP1 and wireless clients using ISP2. This option requires splitting inter-SRX link into two, creating a second VRF for internet traffic destined to ISP2 and creating firewall filter (the actual PBR policy).

For this lab, we will go with the second option.

Below, there are configuration snippets of both firewalls.

Interface: inter-firewall link is broken into two tagged links: first one in the default routing instance carrying datacenter traffic routed via FW2 and second - in the routing instance ISP2 carrying internet traffic, which is policy based routed via ISP2 based on source IP.

root@FW1> show configuration vlans v100 { vlan-id 100; } v255 { vlan-id 255; } root@PDX-FW1> show configuration interfaces ge-0/0/0 vlan-tagging; unit 100 { vlan-id 100; family inet { address 200.126.100.1/24; } } unit 255 { vlan-id 255; family inet { address 200.126.255.1/24; } } root@FW2> show configuration interfaces ge-0/0/0 vlan-tagging; unit 100 { vlan-id 100; family inet { address 200.126.100.2/24; } } unit 255 { vlan-id 255; family inet { address 200.126.255.2/24; } }

 

Routing Instance 'ISP2'  has just one interface in vlan 100. There is a static route to the LAN 200.126.0.0/16 pointing to the table inet.0 so internet traffic could make back to the source.  Dynamic protocol OSPF is running inside the instance to deliver a default route from FW2 to FW1 and there is a static default route on FW1 with preference of 200, so if FW2 has issues with internet and the default route stops being propagated to FW1, FW1 will be forwarding internet traffic straight out to ISP1.

root@FW1> show configuration routing-instances ISP2 { instance-type virtual-router; interface ge-0/0/0.100; routing-options { interface-routes { rib-group inet group1; } static { route 200.126.0.0/16 next-table inet.0; route 0.0.0.0/0 { qualified-next-hop 11.11.11.1 { preference 200; } } } } protocols { ospf { area 0.0.0.0 { interface ge-0/0/0.100; } } } } root@FW1> show configuration routing-options interface-routes { rib-group inet group1; } static { route 0.0.0.0/0 next-hop 11.11.11.1; } aggregate { route 200.126.0.0/16; } rib-groups { group1 { import-rib [ inet.0 ISP2.inet.0 ]; } } autonomous-system 64527; root@PDX-FW2> show configuration routing-instances ISP2 { instance-type virtual-router; interface ge-0/0/0.100; routing-options { interface-routes { rib-group inet group1; } static { route 0.0.0.0/0 next-hop 22.22.22.1; route 200.126.0.0/16 next-hop 200.126.100.1; } } protocols { ospf { export INTO_OSPF; area 0.0.0.0 { interface ge-0/0/0.100; } } } }

 

PBR1 firewall filter is defined and should be applied on the FW1 interface connecting core switch. PBR-EXCEPTION  is a prefix list that contains all source networks excluded from PBR, in other termswe define IPs  (in our case  just one) , who's internet traffic we will be routing to ISP2.

root@FW1> show configuration firewall filter PBR1 { term 15 { from { destination-prefix-list { PBR-EXCEPTION; } } then accept; } term 20 { from { source-address { 200.126.12.1/32; } } then { routing-instance ISP2; } } term 50 { then accept; } }

 

For failover, we could use ip-monitoring feature to monitor IPs in the internet (I usually  Level3 and Google DNS servers: 4.2.2.1 and 8.8.8.8). If both probes fail on FW2, we could shutdown interface ge-0/0/0.100 (belongs to routing instance ISP2), then internet traffic will be routed directly out of FW1. If probes fail on FW1, then we could just shutdown interface between FW1 and Core-SW1, so all traffic will naturally be re-routed via FW2 using OSPF.