Remove policy scripts
Rhai made a decision about a route cost one to three microseconds, some two hundred times what the same costs in Rust. That was bearable where a function is asked once for an UPDATE, and is not where every route is weighed against every peer, as it is when routes are passed on. What is wanted of a policy (mark routes by where they came from, mark what is announced, let communities say who is told what) needs no language; it is to be configuration, done natively. Kept from that work: route selection goes by a LOCAL_PREF that policy set on a route from an external peer, and the lab's configuration can be added to by a phase. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
cbf0df1eef
commit
9367c38907
48 files changed
+21
-3435
No files matched your search
+1
-72
@@ -29,7 +29,7 @@ cd "$(dirname "$0")/../.."
|
||||
bgp="${CARGO_TARGET_DIR:-target}/release/bgp"
|
||||
work=/tmp/ferrix-lab
|
||||
pathspace=ferrixlab
|
||||
all_phases="basics roles rpki refresh flaps restart scale limits hijacks nexthops policy v6only linklocal"
|
||||
all_phases="basics roles rpki refresh flaps restart scale limits hijacks nexthops v6only linklocal"
|
||||
phases="${PHASES:-$all_phases}"
|
||||
scale_routes="${SCALE_ROUTES:-200000}"
|
||||
|
||||
@@ -828,77 +828,6 @@ phase_nexthops() {
|
||||
ok "back to normal"
|
||||
}
|
||||
|
||||
# The operator's own rules, as a script: routes are marked with where
|
||||
# they were learned and ranked by it, which changes which of two routes
|
||||
# is chosen; and what each neighbor is told is decided for each.
|
||||
phase_policy() {
|
||||
cat > "$work/policy.rhai" <<'END'
|
||||
const LEARNED_FROM = #{ peer: "64601:2000", provider: "64601:3000" };
|
||||
|
||||
// Every route on its way in. Here the provider's routes are the ones to
|
||||
// prefer, which is the other way about from what selection would do.
|
||||
fn incoming(route, peer) {
|
||||
route.remove_community("64601:*");
|
||||
route.add_community(LEARNED_FROM[peer.role]);
|
||||
route.local_pref = if peer.role == "provider" { 300 } else { 100 };
|
||||
true
|
||||
}
|
||||
|
||||
fn to_frr(route, peer) {
|
||||
route.add_community("64601:777");
|
||||
route.prepend(2);
|
||||
true
|
||||
}
|
||||
|
||||
// BIRD is not told our IPv4 prefix.
|
||||
fn to_bird(route, peer) { !route.within("10.1.0.0/24") }
|
||||
END
|
||||
dut_down TERM
|
||||
dut_config PEER 2000000 "" \
|
||||
'export { function: "to_frr" }' 'export { function: "to_bird" }' \
|
||||
'policy { path: "policy.rhai" import_function: "incoming" }'
|
||||
"$bgp" --check "$work/dut.textpb" | grep -q "frr4: import incoming, export to_frr" \
|
||||
|| fail "--check does not say which functions are whose: $("$bgp" --check "$work/dut.textpb" 2>&1)"
|
||||
dut_up
|
||||
# A prefix nobody has said anything about in the RPKI, from both; of
|
||||
# the two, FRR's would be chosen.
|
||||
echo "route 10.77.0.0/24 blackhole;" > "$work/bird-both.conf"
|
||||
bird_config "$work/bird-both.conf"
|
||||
bird_ctl configure >/dev/null
|
||||
frr_configure "router bgp 64602" "address-family ipv4 unicast" "network 10.77.0.0/24"
|
||||
wait_for "four sessions" established 4
|
||||
wait_for "FRR's route for it" dut_has 10.77.0.0/24 frr4
|
||||
wait_for "BIRD's route for it" dut_has 10.77.0.0/24 bird4
|
||||
|
||||
# In: marked by where they were learned, and ranked.
|
||||
local marks
|
||||
marks=$(api "/api/routes/received?prefix=10.77.0.0/24" | jq -c '[.routes[] | {peer: .peer_name, marks: (tostring | [scan("64601:[0-9]+")] | unique)}] | sort_by(.peer)')
|
||||
[ "$marks" = '[{"peer":"bird4","marks":["64601:3000"]},{"peer":"frr4","marks":["64601:2000"]}]' ] \
|
||||
|| fail "the routes are marked $marks"
|
||||
wait_for "BIRD's route to be the one chosen" best_is 10.77.0.0/24 bird4
|
||||
wait_for "it in the kernel" dut_kernel -4 "10.77.0.0/24 via 10.9.0.3 dev ix0 metric 20"
|
||||
peer_is frr4 '.import_function == "incoming" and .export_function == "to_frr"' >/dev/null \
|
||||
|| fail "the status does not say which functions are the peer's"
|
||||
ok "routes are marked with where they were learned, and the provider's is chosen and installed"
|
||||
|
||||
# Out: FRR is told our route with a longer path and a mark; BIRD is not
|
||||
# told it at all, and is told the IPv6 one.
|
||||
wait_for "our route at FRR" bash -c "sudo ip netns exec lab-frr vtysh -N $pathspace -c 'show bgp ipv4 unicast 10.1.0.0/24 json' 2>/dev/null | jq -e '.paths[0] | .aspath.string == \"64601 64601 64601\" and (.community.string | contains(\"64601:777\")) and (.community.string | contains(\"64601:100\"))'"
|
||||
wait_for "our IPv6 route at BIRD" bird_has 2001:db8:1::/48
|
||||
sleep 1
|
||||
bird_has 10.1.0.0/24 && fail "BIRD was told the route its function refuses"
|
||||
ok "FRR is told our route with a longer path and a mark; BIRD is not told it"
|
||||
|
||||
frr_configure "router bgp 64602" "address-family ipv4 unicast" "no network 10.77.0.0/24"
|
||||
bird_config
|
||||
bird_ctl configure >/dev/null
|
||||
dut_down TERM
|
||||
dut_config
|
||||
dut_up
|
||||
converged
|
||||
ok "back to normal"
|
||||
}
|
||||
|
||||
# The exchange LAN loses its IPv4 addresses. One session over IPv6 with
|
||||
# each router carries both families, and IPv4 routes have IPv6 next hops
|
||||
# (RFC 8950), in BGP and in the kernel. Run after the rest: the lab stays
|
||||
|
||||
Reference in new issue
Block a user