1212_execute_after = [ 'ebgp.utils' , 'bgp.session' ]
1313_requires = [ 'bgp' ]
1414
15- def pre_transform (topology : Box ) -> None :
16- global _config_name
17- session_idx = data .find_in_list (['ebgp.utils' ,'bgp.session' ],topology .plugin )
18- multihop_idx = data .find_in_list ([ _config_name ],topology .plugin )
19-
20- if session_idx is not None and multihop_idx is not None and session_idx > multihop_idx :
21- log .error (
22- 'ebgp.multihop plugin must be included after bgp.session/ebgp.utils plugin' ,
23- log .IncorrectValue ,'ebgp.multihop' )
24-
2515def pre_link_transform (topology : Box ) -> None :
2616 if not 'multihop' in topology .get ('bgp' ,{}):
2717 return
@@ -31,6 +21,7 @@ def pre_link_transform(topology: Box) -> None:
3121
3222 sessions = links .adjust_link_list (topology .bgp .multihop .sessions ,topology .nodes ,'bgp.multihop[{link_cnt}]' )
3323 topology .bgp .multihop .sessions = sessions
24+ next_linkindex = links .get_next_linkindex (topology )
3425 for s in sessions :
3526 for attr in list (s .keys ()): # Change session attributes into BGP link attributes
3627 # Skip internal attributes and BGP/VRF attributes already within BGP namespace
@@ -40,8 +31,9 @@ def pre_link_transform(topology: Box) -> None:
4031 s .pop (attr ,None )
4132
4233 s .type = 'tunnel'
43- s .linkindex = links .get_next_linkindex (topology )
44- s ._bgp_session = True
34+ s .linkindex = next_linkindex
35+ next_linkindex += 1
36+ s ._phantom_link = True
4537
4638 validate_attributes (
4739 data = s , # Validate pseudo-link data
@@ -82,7 +74,8 @@ def pre_link_transform(topology: Box) -> None:
8274 intf .bgp .multihop = 255
8375 if 'vrf' in intf :
8476 intf .bgp ._vrf = intf .vrf
85- intf ._bgp_session = True
77+ intf ._mh_bgp_session = True
78+ intf ._phantom_link = True
8679 intf .ifname = f'_ebgp_multihop_{ s .linkindex } '
8780
8881 topology .links .extend (sessions )
@@ -136,28 +129,17 @@ def augment_af_activation(ndata: Box, topology: Box) -> None:
136129 chg .pop (bgp_af ,None ) # Otherwise remove it
137130
138131'''
139- remove_fake_interfaces: remove all fake interfaces created to build BGP neighbor adjacencies
132+ Check whether a node has EBGP multihop sessions
140133'''
141- def remove_fake_interfaces (ndata : Box , topology : Box ) -> bool :
142- intf_count = len (ndata .interfaces )
143- ndata .interfaces = [ intf for intf in ndata .interfaces if not intf .get ('_bgp_session' ,None ) ]
134+ def ebgp_multihop_sessions (ndata : Box , topology : Box ) -> bool :
135+ mh_intf = [ intf for intf in ndata .interfaces if intf .get ('_mh_bgp_session' ,False ) ]
136+ if not mh_intf : # Do we have any fake interfaces for MH EBGP sessions?
137+ return False
144138
145- return len (ndata .interfaces ) != intf_count
146-
147- '''
148- cleanup_interfaces: remove fake interfaces from global interface list and VRF OSPF interface list
149- '''
150- def cleanup_interfaces (ndata : Box , topology : Box ) -> None :
151- changed = remove_fake_interfaces (ndata ,topology ) # Cleanup global interface list
152- for vname ,vdata in ndata .get ('vrfs' ,{}).items (): # Iterate over VRFs
153- if 'ospf' in vdata : # .. and cleanup OSPF interface list if needed
154- v_chg = remove_fake_interfaces (vdata .ospf ,topology )
155- changed = changed or v_chg
156-
157- if changed : # Did the interface count change?
158- check_multihop_support (ndata ,topology )
159- api .node_config (ndata ,_config_name ) # We must have some multihop sessions, add extra config
160- augment_af_activation (ndata ,topology )
139+ check_multihop_support (ndata ,topology ) # Check that the node supports it
140+ api .node_config (ndata ,_config_name ) # We must have some multihop sessions, add extra config
141+ augment_af_activation (ndata ,topology ) # ... and activate relevant address families on these sessions
142+ return True
161143
162144'''
163145fix_vrf_loopbacks:
@@ -179,7 +161,7 @@ def fix_vrf_loopbacks(ndata: Box, topology: Box) -> None:
179161 if af in lb : # ... removing whatever might have come from the
180162 ngb [af ] = str (ipaddress .ip_interface (lb [af ]).ip ) # ... global loopback
181163
182- if '_src_vrf' in ngb : # Is out endpoint in a VRF?
164+ if '_src_vrf' in ngb : # Is our endpoint in a VRF?
183165 if not isinstance (features .bgp .multihop ,Box ) or features .bgp .multihop .vrf is not True :
184166 log .error (
185167 f'Device { ndata .device } does not support VRF EBGP multihop sessions (node { ndata .name } , VRF { ngb ._src_vrf } )' ,
@@ -211,7 +193,14 @@ def fix_vrf_loopbacks(ndata: Box, topology: Box) -> None:
211193def post_transform (topology : Box ) -> None :
212194 global _config_name
213195 for ndata in topology .nodes .values ():
214- fix_vrf_loopbacks (ndata ,topology )
215- cleanup_interfaces (ndata ,topology )
196+ if ebgp_multihop_sessions (ndata ,topology ):
197+ fix_vrf_loopbacks (ndata ,topology )
198+
199+ '''
200+ Cleanup: remove interfaces and links with _phantom_link flag
201+ '''
202+ def cleanup (topology : Box ) -> None :
203+ for ndata in topology .nodes .values ():
204+ ndata .interfaces = [ intf for intf in ndata .interfaces if not intf .get ('_phantom_link' ,None ) ]
216205
217- topology .links = [ link for link in topology .links if not link .get ('_bgp_session ' ,None ) ]
206+ topology .links = [ link for link in topology .links if not link .get ('_phantom_link ' ,None ) ]
0 commit comments