|
|
# Policy routing
|
|
|
|
|
|
Here is an example of using multiple routing tables for policy routing with BGP. The example uses local AS with two upstream ISP (A and B) and two clients (C and D). Let A and C be commercial networks, B be publicly funded research backbone and D be public university network. The policy of B is that it works as upstream only for university networks (D), but also accept traffic from commercial networks (C) to its clients. Therefore we need to route traffic from clients C and D differently - C can use only A as upstream, while D can use both A and B as upstreams and has strong preference for B.
|
|
|
|
|
|
We use three routing tables, one global and one for each client. These tables are also synchronized with kernel routing tables by _kernel_ protocols. Global table is used for distribution of routes and also for routing traffic received from upstreams, while a local client table contains routes with applied routing policies for that client and is used for routing of traffic received from that client. BGP protocols to clients (C, D) are connected to client tables, while BGP protocols to uplinks (A, B) are connected directly to the global table. This means that both A and B have to receive the same best routes, but that is probably insignificant limitation. Pipes are used to connect local tables to the global table.
|
|
|
|
|
|
There are generally two places where routing policy can be specified. First, the export filter of a pipe specifies which routes from the global table will be propagated to a local one and therefore how the traffic received from that client will be routed by local AS. Second, the export filters of uplink BGPs (A, B) allows to modify attributes of propagated routes and therefore influence how other ASes would route traffic for these prefixes.
|
|
|
|
|
|
We suppose that uplink B uses BGP community (XXXB, 1) to mark its non-commercial research clients. Therefore, we add this community to prefixes of D propagated to B (so B will propagate these prefixes to the Internet, while unmarked prefixes from C will be propagated just to its clients). Also unmarked (upstream) prefixes from B are not propagated to the local table of C, so C would not use B as its uplink. Preference of D for uplink B is handled as usually - setting higher local preference in the local table of D and by path prepending when propagating prefixes from D to A.
|
|
|
|
|
|
For simplicity, the example ignores the problem of how locally originated traffic would be routed. If some specific policy applies on that, the solution would be to create another local table which would be used for routing locally originated traffic. We also suppose for simplicity that local AS consists of just this router, so we do not have IGP or IBGP here.
|
|
|
|
|
|
Filters used in this example came from [BGP filtering](BGP_filtering), so not all functions and filters are specified here. XXXX is the local ASN, XXXA .. XXXD are ASN of neighbors and X.Y.Z.A .. X.Y.Z.D are IP addresses of their BGP routers. Here is the BIRD config file:
|
|
|
|
|
|
log syslog all;
|
|
|
|
|
|
router id A.B.C.D;
|
|
|
|
|
|
define myas = XXXX;
|
|
|
|
|
|
protocol device
|
|
|
{
|
|
|
scan time 10;
|
|
|
}
|
|
|
|
|
|
protocol kernel
|
|
|
{
|
|
|
export all;
|
|
|
# Perhaps there should be a filter that allows just local and client prefixes.
|
|
|
|
|
|
kernel table 1;
|
|
|
scan time 15;
|
|
|
}
|
|
|
|
|
|
|
|
|
### BGP uplink A
|
|
|
|
|
|
filter bgp_in_uplink_a
|
|
|
{ ... }
|
|
|
|
|
|
filter bgp_out_uplink_a
|
|
|
{
|
|
|
if ! rt_export() then reject;
|
|
|
|
|
|
# Routing policy: penalize routes from client D
|
|
|
if proto = "b_d" then
|
|
|
{
|
|
|
bgp_path.prepend(myas);
|
|
|
bgp_path.prepend(myas);
|
|
|
bgp_path.prepend(myas);
|
|
|
}
|
|
|
|
|
|
accept;
|
|
|
}
|
|
|
|
|
|
protocol bgp b_a
|
|
|
{
|
|
|
import filter bgp_in_uplink_a;
|
|
|
export filter bgp_out_uplink_a;
|
|
|
|
|
|
local as myas;
|
|
|
neighbor X.Y.Z.A as XXXA;
|
|
|
|
|
|
# Routing policy: make routes from uplinks less prefered
|
|
|
default bgp_local_pref 50;
|
|
|
}
|
|
|
|
|
|
|
|
|
### BGP uplink B
|
|
|
|
|
|
filter bgp_in_uplink_b
|
|
|
{ ... }
|
|
|
|
|
|
filter bgp_out_uplink_b
|
|
|
{
|
|
|
if ! rt_export() then reject;
|
|
|
|
|
|
# Routing policy: mark routes from client C
|
|
|
if proto = "b_c" then bgp_community.add((XXXB, 1));
|
|
|
|
|
|
accept;
|
|
|
}
|
|
|
|
|
|
protocol bgp b_b
|
|
|
{
|
|
|
import filter bgp_in_uplink_b;
|
|
|
export filter bgp_out_uplink_b;
|
|
|
|
|
|
local as myas;
|
|
|
neighbor X.Y.Z.B as XXXB;
|
|
|
|
|
|
# Routing policy: make routes from uplinks less prefered
|
|
|
default bgp_local_pref 50;
|
|
|
}
|
|
|
|
|
|
|
|
|
### BGP client C
|
|
|
|
|
|
filter bgp_in_client_c
|
|
|
{ ... }
|
|
|
|
|
|
filter bgp_out_client_c
|
|
|
{
|
|
|
if ! rt_export_all() then reject;
|
|
|
|
|
|
# Routing policy: reject upstream routes from uplink B
|
|
|
if proto = "b_b" && ! (XXXB, 1) ~ bgp_community then reject;
|
|
|
|
|
|
accept;
|
|
|
}
|
|
|
|
|
|
table t_c;
|
|
|
|
|
|
protocol pipe p_c
|
|
|
{
|
|
|
table master;
|
|
|
peer table t_c;
|
|
|
import filter bgp_in_client_c;
|
|
|
export filter bgp_out_client_c;
|
|
|
}
|
|
|
|
|
|
protocol bgp b_c
|
|
|
{
|
|
|
table t_c;
|
|
|
import all;
|
|
|
export all;
|
|
|
|
|
|
local as myas;
|
|
|
neighbor X.Y.Z.C as XXXC;
|
|
|
}
|
|
|
|
|
|
protocol kernel k_c
|
|
|
{
|
|
|
table t_c;
|
|
|
export all;
|
|
|
|
|
|
kernel table 2;
|
|
|
scan time 15;
|
|
|
}
|
|
|
|
|
|
|
|
|
### BGP client D
|
|
|
|
|
|
filter bgp_in_client_d
|
|
|
{ ... }
|
|
|
|
|
|
filter bgp_out_client_d
|
|
|
{
|
|
|
if ! rt_export_all() then reject;
|
|
|
|
|
|
# Routing policy: make routes from uplink B more preferred;
|
|
|
if proto = "b_b" then bgp_local_pref = 70;
|
|
|
|
|
|
accept;
|
|
|
}
|
|
|
|
|
|
table t_d;
|
|
|
|
|
|
protocol pipe p_d
|
|
|
{
|
|
|
table master;
|
|
|
peer table t_d;
|
|
|
import filter bgp_in_client_d;
|
|
|
export filter bgp_out_client_d;
|
|
|
}
|
|
|
|
|
|
protocol bgp b_d
|
|
|
{
|
|
|
table t_d;
|
|
|
import all;
|
|
|
export all;
|
|
|
|
|
|
local as myas;
|
|
|
neighbor X.Y.Z.D as XXXD;
|
|
|
}
|
|
|
|
|
|
protocol kernel k_d
|
|
|
{
|
|
|
table t_d;
|
|
|
export all;
|
|
|
|
|
|
kernel table 3;
|
|
|
scan time 15;
|
|
|
}
|
|
|
|
|
|
|
|
|
We also have to specify how kernel tables 1, 2 and 3 would be used for traffic forwarding. This is OS-specific and it is outside of BIRD. In Linux, this is handled by kernel routing policy database, which can be can be configured by _ip_ tool, specifically _ip rule_. Suppose that we have four different interfaces eth0 .. eth3 and each neighbor (A, B, C and D) has its interface. In that case we could simply configure that received traffic from that interface is routed using appropriate routing table:
|
|
|
|
|
|
ip rule add iif eth0 table 1
|
|
|
ip rule add iif eth1 table 1
|
|
|
ip rule add iif eth2 table 2
|
|
|
ip rule add iif eth3 table 3
|
|
|
|
|
|
If that is not a case, we have to probably use policy routing based on source addresses (_ip rule add from PREFIX table X_). |