Skip to content

Commit c112b97

Browse files
thomas-manginclaude
andcommitted
fix: Auto-enable adj-rib-out when route-refresh capability is enabled
Route-refresh requires cached routes to resend. When adj-rib-out is disabled (default), cached_routes() returns empty and no UPDATE is sent after receiving ROUTE-REFRESH. Now ParseNeighbor._post_capa_rr() auto-enables adj-rib-out when route-refresh is configured, with a warning log. Fixes #1151 Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent c9f302b commit c112b97

File tree

2 files changed

+83
-2
lines changed

2 files changed

+83
-2
lines changed

src/exabgp/configuration/neighbor/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,15 @@ def _post_capa_nexthop(self, neighbor: Neighbor, local: dict[str, Any]) -> None:
500500

501501
def _post_capa_rr(self, neighbor: Neighbor) -> None:
502502
if neighbor.capability.route_refresh:
503-
if neighbor.adj_rib_out:
504-
log.debug(lazymsg('neighbor.capability.route_refresh action=enable_adj_rib_out'), 'configuration')
503+
if not neighbor.adj_rib_out:
504+
log.warning(
505+
lazymsg(
506+
'neighbor.route_refresh.adj_rib_out peer={peer} action=auto_enabled reason=route_refresh_requires_cache',
507+
peer=neighbor.session.peer_address,
508+
),
509+
'configuration',
510+
)
511+
neighbor.adj_rib_out = True
505512

506513
def _post_routes(self, neighbor: Neighbor, local: dict[str, Any]) -> None:
507514
# NOTE: this may modify change but does not matter as want to modified
@@ -548,6 +555,7 @@ def post(self) -> bool:
548555
self._post_capa_default(neighbor, local)
549556
self._post_capa_addpath(neighbor, local, families)
550557
self._post_capa_nexthop(neighbor, local)
558+
self._post_capa_rr(neighbor)
551559
self._post_routes(neighbor, local)
552560

553561
neighbor.api = ParseAPI.flatten(local.pop('api', {}))
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Test route-refresh capability auto-enables adj-rib-out.
2+
3+
When route-refresh is enabled, adj-rib-out must be enabled for it to function.
4+
ParseNeighbor._post_capa_rr auto-enables adj-rib-out when route-refresh is configured.
5+
6+
See: https://github.com/Exa-Networks/exabgp/issues/1151
7+
"""
8+
9+
from exabgp.bgp.neighbor.neighbor import Neighbor
10+
from exabgp.protocol.ip import IP
11+
12+
13+
class TestRouteRefreshAdjRibOut:
14+
"""Test that route-refresh capability auto-enables adj-rib-out."""
15+
16+
def _create_neighbor(self) -> Neighbor:
17+
"""Create a minimal Neighbor for testing."""
18+
neighbor = Neighbor()
19+
neighbor.session.peer_address = IP.from_string('192.168.1.1')
20+
return neighbor
21+
22+
def test_adj_rib_out_auto_enabled_when_route_refresh_enabled(self) -> None:
23+
"""When route-refresh is enabled and adj-rib-out is False, auto-enable it."""
24+
from exabgp.configuration.neighbor import ParseNeighbor
25+
26+
neighbor = self._create_neighbor()
27+
neighbor.capability.route_refresh = 2 # REFRESH.NORMAL
28+
neighbor.adj_rib_out = False
29+
30+
# Simulate what ParseNeighbor.post() does
31+
parser = ParseNeighbor.__new__(ParseNeighbor)
32+
parser._post_capa_rr(neighbor)
33+
34+
assert neighbor.adj_rib_out is True
35+
36+
def test_adj_rib_out_unchanged_when_already_enabled(self) -> None:
37+
"""When adj-rib-out is already True, it stays True."""
38+
from exabgp.configuration.neighbor import ParseNeighbor
39+
40+
neighbor = self._create_neighbor()
41+
neighbor.capability.route_refresh = 2 # REFRESH.NORMAL
42+
neighbor.adj_rib_out = True
43+
44+
parser = ParseNeighbor.__new__(ParseNeighbor)
45+
parser._post_capa_rr(neighbor)
46+
47+
assert neighbor.adj_rib_out is True
48+
49+
def test_adj_rib_out_unchanged_when_route_refresh_disabled(self) -> None:
50+
"""When route-refresh is disabled, adj-rib-out is not changed."""
51+
from exabgp.configuration.neighbor import ParseNeighbor
52+
53+
neighbor = self._create_neighbor()
54+
neighbor.capability.route_refresh = 0 # Disabled
55+
neighbor.adj_rib_out = False
56+
57+
parser = ParseNeighbor.__new__(ParseNeighbor)
58+
parser._post_capa_rr(neighbor)
59+
60+
assert neighbor.adj_rib_out is False
61+
62+
def test_enhanced_route_refresh_also_enables_adj_rib_out(self) -> None:
63+
"""Enhanced route-refresh (value 4) also auto-enables adj-rib-out."""
64+
from exabgp.configuration.neighbor import ParseNeighbor
65+
66+
neighbor = self._create_neighbor()
67+
neighbor.capability.route_refresh = 4 # REFRESH.ENHANCED
68+
neighbor.adj_rib_out = False
69+
70+
parser = ParseNeighbor.__new__(ParseNeighbor)
71+
parser._post_capa_rr(neighbor)
72+
73+
assert neighbor.adj_rib_out is True

0 commit comments

Comments
 (0)