Control communities: session groups, prepends, and only ours to give

Control communities could say which peers a route goes to, by AS. Now
they can also name sessions by group, and ask for prepends:

  L:11:P .. L:13:P   our AS once to three times more towards AS P
                     (P 0: towards every peer in another AS)
  L:20:G / L:21:G    not to / only to the sessions of group G
  L:31:G .. L:33:G   our AS once to three times more towards group G

A group is a number given to sessions in the configuration (`groups` of
a peer): those at one exchange, or those over one link. The same network
at two exchanges is one AS but two sessions, which is what steering
inbound traffic between exchanges needs. Of several prepends that apply
the most counts, on top of the session's own as_path_prepend. Functions
2 to 9, as the documentation already promised, and 100 and up stay
informational; 10 to 99 are kept for actions to come.

They are acted on where a route leaves our AS, and taken off there; our
informational communities are not. To a peer in our own AS a route goes
with them, unchanged, so that a mark put on at one router is acted on at
another. Before, they were acted on and taken off on internal sessions
too, so a route marked "to nobody" did not even reach our own routers.

And they are ours to give: the communities of our own AS (L:n, L:n:m,
and 0:n where control communities are on) are taken off every route
from a peer in another AS as it comes in, before import marks are put
on. A peer at an exchange could otherwise decide where its routes go
from us, and set our informational marks. A customer that is to steer
its own routes is given import.accept_control_communities. An UPDATE
without any of ours is still taken as it came, without being written
out again.

This changes what a customer that set control communities gets: it now
needs accept_control_communities. The transit example and the interop
lab say so; the lab also has FRR, as a customer, ask for a prepend
towards BIRD's group, and BIRD, as a provider, have its "not to" taken
off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Rayhaan JaufeerallyandClaude Opus 5.5 committed 2026-10-05 16:12:05 +02:00
1 parent 3609451bdc
commit 72444c2706
25 files changed
+833 -120

No files matched your search

+28 -5
View File
@@ -890,23 +890,31 @@ phase_nexthops() {
# Routes are passed on: FRR becomes our customer and BIRD stays our
# provider, so what FRR announces goes up to BIRD with our AS on the path,
# what BIRD announces goes down to FRR marked "only to customer", and
# packets go between their networks through us. A community on one of
# FRR's routes keeps it from BIRD.
# packets go between their networks through us. FRR, as a customer, steers
# its routes with our control communities: one keeps a route from BIRD,
# another has us prepend on the way to BIRD's session group. BIRD, as a
# provider, may not: its "not to FRR" is taken off as its route comes in.
phase_transit() {
dut_down TERM
dut_config CUSTOMER 2000000 "" "" "" \
dut_config CUSTOMER 2000000 "accept_control_communities: true" "" "groups: 7" \
'export { learned_routes: true }
control_communities: true'
echo "route 10.3.8.0/24 blackhole { bgp_large_community.add((64601, 0, 64602)); };" > "$work/bird-transit.conf"
bird_config "$work/bird-transit.conf"
bird_ctl configure >/dev/null
in_ns dut sysctl -qw net.ipv4.ip_forward=1
dut_up
frr_configure "router bgp 64602" "neighbor 10.9.0.1 local-role customer" \
"ip prefix-list KEPT seq 5 permit 10.2.9.0/24" \
"ip prefix-list FAR seq 5 permit 10.2.10.0/24" \
"route-map TO-DUT-TRANSIT permit 10" "match ip address prefix-list KEPT" "set large-community 64601:0:4200000003" \
"route-map TO-DUT-TRANSIT permit 15" "match ip address prefix-list FAR" "set large-community 64601:31:7" \
"route-map TO-DUT-TRANSIT permit 20" \
"router bgp 64602" "address-family ipv4 unicast" \
"neighbor 10.9.0.1 route-map TO-DUT-TRANSIT out" "network 10.2.9.0/24"
"neighbor 10.9.0.1 route-map TO-DUT-TRANSIT out" "network 10.2.9.0/24" "network 10.2.10.0/24"
wait_for "four sessions" established 4
wait_for "FRR's routes at the daemon" dut_has 10.2.9.0/24 frr4
wait_for "FRR's routes at the daemon" dut_has 10.2.10.0/24 frr4
# Up to the provider, with our AS on the path; not the one that says
# not to.
@@ -915,6 +923,19 @@ control_communities: true'
bird_ctl show route for 10.2.9.0/24 all | grep -q "64601 64602" && fail "BIRD was told the route whose community says not to"
ok "the customer's routes reach the provider with our AS on the path; one kept back by its community"
# Prepended once more towards BIRD's group, at the customer's word,
# and the community that asked for it gone.
wait_for "the prepended route at BIRD" bash -c "sudo birdc -s $work/bird.ctl show route for 10.2.10.0/24 all | grep -q 'BGP.as_path: 64601 64601 64602'"
bird_ctl show route for 10.2.10.0/24 all | grep -q "(64601, 31, 7)" && fail "the control community went on to BIRD"
ok "a customer's control community has us prepend towards a session group, and is taken off"
# The provider's "not to FRR" is not ours to act on: taken off as the
# route comes in, and the route goes down to FRR all the same.
wait_for "BIRD's route with our community at FRR" bash -c "sudo ip netns exec lab-frr vtysh -N $pathspace -c 'show bgp ipv4 unicast 10.3.8.0/24 json' 2>/dev/null | jq -e '.paths[0].aspath.string == \"64601 4200000003\"'"
api "/api/routes/received?prefix=10.3.8.0/24" | jq -e '.routes | length > 0 and all(.summary.large_communities | index("64601:0:64602") | not)' >/dev/null \
|| fail "the provider's control community was kept: $(api "/api/routes/received?prefix=10.3.8.0/24")"
ok "a provider's control community is taken off as its route comes in"
# Down to the customer, marked.
wait_for "BIRD's route at FRR, by way of us" bash -c "sudo ip netns exec lab-frr vtysh -N $pathspace -c 'show bgp ipv4 unicast 10.3.0.0/24 json' 2>/dev/null | jq -e '.paths[0].aspath.string == \"64601 4200000003\"'"
# Marked on the way in from the provider, with the provider's AS, and
@@ -928,7 +949,9 @@ control_communities: true'
ok "packets go between the customer's and the provider's networks through us"
frr_configure "router bgp 64602" "neighbor 10.9.0.1 local-role peer" \
"address-family ipv4 unicast" "no network 10.2.9.0/24" "no neighbor 10.9.0.1 route-map TO-DUT-TRANSIT out" "no route-map TO-DUT-TRANSIT"
"address-family ipv4 unicast" "no network 10.2.9.0/24" "no network 10.2.10.0/24" "no neighbor 10.9.0.1 route-map TO-DUT-TRANSIT out" "no route-map TO-DUT-TRANSIT"
bird_config
bird_ctl configure >/dev/null
dut_down TERM
dut_config
dut_up