@@ -650,20 +650,44 @@ class ControlPlaneAclManager(logger.Logger):
650650 iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + ['ip6tables' , '-A' , 'INPUT' , '-p' , 'udp' , '--dport' , '546:547' , '-j' , 'ACCEPT' ])
651651
652652 # Add iptables/ip6tables commands to allow relevant incoming BGP traffic
653+ # TODO: Break this out to a new function to aid writing unit tests
654+ #
655+ # This supports the following configurations:
656+ # - IPv4 neighbors w/ and w/o specified IPv4 source
657+ # - IPv6 neighbors w/ and w/o specified IPv6 source
658+ # - BGP Unnumbered, i.e. interface bound neighbors using link-local IPv6
653659 for key , config in self .config_db_map [namespace ].get_table (self .BGP_NEIGHBOR ).items ():
654- # Format can either be VRF|PeerIP or just PeerIP (older format)
655- # Treat it as a potential CIDR to allow for e.g. dynamic BGP neighbors
656- peer_cidr = key [- 1 ] if isinstance (key , tuple ) else key
657- local_ip = config ['local_addr' ]
660+ # Format can either be VRF|Peer or just Peer (older format)
661+ # Peer can be either a IPv4, IPv6, or an interface name.
662+ # Treat it as a potential CIDR to allow for e.g. dynamic BGP neighbors,
663+ # and if it does not parse then use it as an interface.
664+ peer = key [- 1 ] if isinstance (key , tuple ) else key
658665 name = config .get ('name' , 'unnamed' )
659- peer_network = ipaddress .ip_network (peer_cidr , strict = False )
660- local_address = ipaddress .ip_address (local_ip )
661- if isinstance (peer_network , ipaddress .IPv4Network ) and isinstance (local_address , ipaddress .IPv4Address ):
662- iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + ['iptables' , '-A' , 'INPUT' , '-s' , peer_cidr , '-d' , local_ip , '-p' , 'tcp' , '--dport' , '179' , '-j' , 'ACCEPT' ])
663- elif isinstance (peer_network , ipaddress .IPv6Network ) and isinstance (local_address , ipaddress .IPv6Address ):
664- iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + ['ip6tables' , '-A' , 'INPUT' , '-s' , peer_cidr , '-d' , local_ip , '-p' , 'tcp' , '--dport' , '179' , '-j' , 'ACCEPT' ])
666+ local_ip = config .get ('local_addr' , None )
667+ local_network = None
668+ local_match = []
669+ if local_ip is not None :
670+ # Use network to aid comparision between peer and local network object
671+ local_network = ipaddress .ip_network (local_ip )
672+ local_match = ['-d' , local_ip ]
673+ try :
674+ peer_network = ipaddress .ip_network (peer , strict = False )
675+ if local_network is not None and peer_network .__class__ != local_network .__class__ :
676+ self .log_warning ("Inconsistent IP address types on BGP neighbor '{}'" .format (key ))
677+ continue
678+ # Treat as IPv4/IPv6 address source
679+ peer_match = ['-s' , peer ]
680+ except ValueError :
681+ # Treat as incoming interface for BGP Unnumbered
682+ peer_match = ['-i' , peer ]
683+ local_network = ipaddress .ip_network ('fe80::/10' )
684+ local_match = ['-d' , 'fe80::/10' ]
685+ if isinstance (local_network , ipaddress .IPv4Network ):
686+ iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + ['iptables' , '-A' , 'INPUT' ] + peer_match + local_match + ['-p' , 'tcp' , '--dport' , '179' , '-j' , 'ACCEPT' ])
687+ elif isinstance (local_network , ipaddress .IPv6Network ):
688+ iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + ['ip6tables' , '-A' , 'INPUT' ] + peer_match + local_match + ['-p' , 'tcp' , '--dport' , '179' , '-j' , 'ACCEPT' ])
665689 else :
666- self .log_warning ("Unrecognized or inconsistent IP address type on BGP neighbor '{}'" .format (key ))
690+ self .log_warning ("Unrecognized IP address type on BGP neighbor '{}'" .format (key ))
667691
668692 # TODO: BGP_PEER_RANGE and BGP_PEER_GROUP is not implemented yet, so if they are defined allow BGP from everyone
669693 if self .config_db_map [namespace ].get_table (self .BGP_PEER_RANGE ) or self .config_db_map [namespace ].get_table (self .BGP_PEER_GROUP ):
0 commit comments