@@ -601,11 +601,73 @@ def bgp_build_advertise_list(node: Box) -> None:
601601 list_name = 'bgp.advertise' if 'vrf' not in intf else f'vrfs.{ intf .vrf } .bgp.advertise'
602602 data .append_to_list (node ,list_name ,af_data ) # And append prefix data to the list
603603
604- if 'originate' in node .bgp : # Next, append originate data to the advertise list
605- for o_pfx in node .bgp .originate :
606- # Convert old-style data (IPv4 string) into prefix
607- af_data = o_pfx if isinstance (o_pfx ,Box ) else {'ipv4' : o_pfx }
608- data .append_to_list (node ,'bgp.advertise' ,af_data )
604+ """
605+ bgp_process_originate:
606+
607+ * Check the device support for dual-stack and VRF 'bgp.originate' attribute
608+ * Append prefixes from 'bgp.originate' list to 'bgp.advertise' list
609+ * Convert 'bgp.originate' list to a list of IPv4-only prefixes for legacy devices
610+ """
611+ DISCARD_NH = data .get_box ({'nexthop.discard' : True })
612+
613+ def bgp_process_originate (node : Box , topology : Box ) -> None :
614+ global DISCARD_NH
615+ features = devices .get_device_features (node ,topology .defaults )
616+
617+ # Second-generation BGP route origination needs advertisement of routing table prefixes
618+ # and discard static routes
619+ #
620+ # VRF BGP route origination needs VRF static routes
621+ #
622+ has_advertise = features .get ('bgp.advertise' ,False )
623+ originate_v2 = has_advertise and features .get ('routing.static.discard' ,False )
624+ originate_vrf = originate_v2 and features .get ('routing.static.vrf' ,False )
625+ has_routing = 'routing' in node .module
626+
627+ for (bgp_data ,_ ,vname ) in _rp_utils .rp_data (node ,'bgp' ):
628+ if 'originate' not in bgp_data : # No prefix origination? Nice, move on.
629+ continue
630+
631+ if vname and not originate_vrf :
632+ log .error (
633+ f'device { node .device } (node { node .name } ) does not support VRF bgp.originate attribute' ,
634+ category = log .IncorrectAttr ,
635+ module = 'bgp' )
636+ continue
637+
638+ if originate_v2 : # Handle next-generation BGP route origination
639+ #
640+ # The second-generation BGP origination append bgp.originate attribute to bgp.advertise
641+ # list and creates corresponding discard static routes
642+ #
643+ for pfx in bgp_data .originate :
644+ data .append_to_list (bgp_data ,'advertise' ,pfx ) # Append originate prefix to advertise list
645+ sr_data = DISCARD_NH + pfx # This will create a new object with discard NH
646+ if vname : # If needed, set the VRF name in static route
647+ sr_data .vrf = vname
648+ data .append_to_list (node ,'routing.static' ,sr_data ) # Add discard static route to node data
649+ if not has_routing : # If needed, add routing module
650+ data .append_to_list (node ,'module' ,'routing' )
651+ has_routing = True
652+
653+ bgp_data .pop ('originate' ,None ) # The bgp.originate attribute has been processed
654+
655+ else : # The device can do only old-style BGP route origination
656+ originate_list = []
657+ for pfx in bgp_data .originate : # Rebuild bgp.originate into old format
658+ # bgp.advertise attribute could be ignored, but doing this does not hurt anyone
659+ # plus we need it for devices that support bgp.advertise but not discard routes
660+ #
661+ data .append_to_list (bgp_data ,'advertise' ,pfx )
662+ if 'ipv6' in pfx : # Old bgp.originate implementations were IPv4 only
663+ log .error (
664+ f'device { node .device } (node { node .name } ) cannot use bgp.originate with IPv6 BGP prefixes' ,
665+ category = log .IncorrectValue ,
666+ module = 'bgp' )
667+ return
668+ elif 'ipv4' in pfx : # Save IPv4 prefix (if it exists) into the old-style
669+ originate_list .append (pfx ['ipv4' ]) # originate list
670+ bgp_data .originate = originate_list # ... and replace bgp.originate attribute
609671
610672"""
611673bgp_set_originate_af: set bgp[af] flags based on prefixes that should be originated
@@ -615,33 +677,12 @@ def bgp_set_originate_af(node: Box, topology: Box) -> None:
615677 if 'bgp' not in node : # Safeguard: skip non-BGP nodes
616678 return
617679
618- if node .get ('bgp.originate' ,[]): # bgp.originate attribute implies IPv4 is active
619- node .bgp .ipv4 = True
620- pfxs = topology .get ('prefix' ,{})
621- for o_idx ,o_value in enumerate (node .bgp .originate ): # Also, replace named prefixes with IPv4 values
622- if o_value in pfxs :
623- if 'ipv4' not in pfxs [o_value ]:
624- log .error (
625- f'Named prefix { o_value } used in bgp.originate in node { node .name } must have IPv4 component' ,
626- category = log .MissingValue ,
627- module = 'bgp' )
628- continue
629- node .bgp .originate [o_idx ] = pfxs [o_value ].ipv4
630-
680+ advertise_list = node .get ('bgp.advertise' ,[]) # Get the list of advertised prefixes
631681 for af in ['ipv4' ,'ipv6' ]:
632682 if node .get (f'bgp.{ af } ' ,False ): # No need for further checks if the AF flag is already set
633683 continue
634-
635- if node .get ('bgp.advertise_loopback' ,True ): # If the router advertises its loopback prefix
636- if af in node .get ('loopback' ,{}): # ... do the AF checks on loopback interface
637- node .bgp [af ] = True
638- continue
639-
640- for intf in node .get ("interfaces" ,[]): # No decision yet, iterate over all interfaces
641- if af in intf and intf [af ]: # Is the address family active on the interface?
642- if intf .get ('bgp.advertise' ,False ): # Is the interface prefix advertised in BGP?
643- if not 'vrf' in intf : # The AF fix is only required for global interfaces
644- node .bgp [af ] = True # ... the stars have aligned, set the BGP AF flag
684+ if any ([ pfx for pfx in advertise_list if af in pfx ]): # Do we advertise any prefix with that AF?
685+ node .bgp [af ] = True
645686
646687"""
647688process_as_list:
@@ -967,12 +1008,13 @@ def node_post_transform(self, node: Box, topology: Box) -> None:
9671008 log .fatal (f"Internal error: node { node .name } has BGP module enabled but no BGP parameters" ,"bgp" )
9681009 return
9691010 build_bgp_sessions (node ,topology )
1011+ check_advertise_data (node ,topology )
9701012 bgp_set_advertise (node ,topology )
971- bgp_set_originate_af (node ,topology )
1013+ bgp_process_originate (node ,topology )
9721014 _routing .remove_vrf_routing_blocks (node ,'bgp' )
9731015 bgp_transform_community_list (node ,topology )
9741016 _routing .check_vrf_protocol_support (node ,'bgp' ,None ,'bgp' ,topology )
9751017 _routing .process_imports (node ,'bgp' ,topology ,global_vars .get_const ('vrf_igp_protocols' ,['connected' ]))
976- check_advertise_data (node ,topology )
9771018 sanitize_bgp_data (node )
9781019 bgp_build_advertise_list (node )
1020+ bgp_set_originate_af (node ,topology )
0 commit comments