Coverage for birdplan/bird_config/sections/protocols/bgp/__init__.py: 96%
416 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-23 03:27 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-23 03:27 +0000
1#
2# SPDX-License-Identifier: GPL-3.0-or-later
3#
4# Copyright (c) 2019-2024, AllWorldIT
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
19"""BIRD BGP protocol configuration."""
21# pylint: disable=too-many-lines
23from typing import Dict, List, Optional
25from .....exceptions import BirdPlanError
26from ....globals import BirdConfigGlobals
27from ...constants import SectionConstants
28from ...functions import SectionFunctions
29from ...tables import SectionTables
30from ..base import SectionProtocolBase
31from ..direct import ProtocolDirect
32from ..pipe import ProtocolPipe, ProtocolPipeFilterType
33from .bgp_attributes import BGPAttributes, BGPPeertypeConstraints, BGPRoutePolicyAccept, BGPRoutePolicyImport
34from .bgp_functions import BGPFunctions
35from .bgp_types import BGPPeerConfig
36from .peer import ProtocolBGPPeer
38__all__ = ["ProtocolBGP"]
41BGPPeersConfig = Dict[str, BGPPeerConfig]
42BGPPeers = Dict[str, ProtocolBGPPeer]
43BGPOriginatedRoutes = Dict[str, str]
46class ProtocolBGP(SectionProtocolBase): # pylint: disable=too-many-public-methods
47 """BIRD BGP protocol configuration."""
49 # BGP protocol attributes
50 _bgp_attributes: BGPAttributes
51 # BGP functions
52 _bgp_functions: BGPFunctions
54 # BGP peers
55 _peers: BGPPeers
57 # Internal config before configuration happens
58 _originated_routes: BGPOriginatedRoutes
60 def __init__(
61 self, birdconfig_globals: BirdConfigGlobals, constants: SectionConstants, functions: SectionFunctions, tables: SectionTables
62 ):
63 """Initialize the object."""
64 super().__init__(birdconfig_globals, constants, functions, tables)
66 # Set section name
67 self._section = "BGP Protocol"
69 # BGP peers
70 self._peers = {}
72 # Routes originated from BGP
73 self._originated_routes = {}
75 # Setup BGP attributes
76 self._bgp_attributes = BGPAttributes()
77 # Setup BGP functions
78 self._bgp_functions = BGPFunctions(self.birdconfig_globals, self.functions)
80 def configure(self) -> None:
81 """Configure the BGP protocol."""
82 super().configure()
84 # Blank the BGP peer state
85 if "bgp" not in self.birdconfig_globals.state:
86 self.birdconfig_globals.state["bgp"] = {}
87 self.birdconfig_globals.state["bgp"]["peers"] = {}
89 self._configure_constants_bgp()
90 self.functions.conf.append(self.bgp_functions, deferred=True)
92 self.tables.conf.append("# BGP Tables")
93 self.tables.conf.append("ipv4 table t_bgp4;")
94 self.tables.conf.append("ipv6 table t_bgp6;")
95 self.tables.conf.append("")
97 # Setup BGP origination
98 self._configure_originated_routes()
100 # BGP to master export filters
101 self._setup_bgp_to_master_export_filter()
103 # BGP to master import filters
104 self._setup_bgp_to_master_import_filter()
106 # Configure pipe from BGP to the master routing table
107 bgp_master_pipe = ProtocolPipe(
108 birdconfig_globals=self.birdconfig_globals,
109 table_from="bgp",
110 table_to="master",
111 export_filter_type=ProtocolPipeFilterType.UNVERSIONED,
112 import_filter_type=ProtocolPipeFilterType.UNVERSIONED,
113 )
114 self.conf.add(bgp_master_pipe)
116 # Check if we're importing connected routes, if we are, create the protocol and pipe
117 if self.route_policy_import.connected:
118 # Create an interface list to feed to our routing table
119 interfaces: List[str] = []
120 if isinstance(self.route_policy_import.connected, list):
121 interfaces = self.route_policy_import.connected
122 # Add direct protocol for redistribution of connected routes
123 bgp_direct_protocol = ProtocolDirect(
124 self.birdconfig_globals,
125 self.constants,
126 self.functions,
127 self.tables,
128 name="bgp",
129 interfaces=interfaces,
130 )
131 self.conf.add(bgp_direct_protocol)
132 # Add pipe
133 self._setup_bgp_to_direct_import_filter()
134 bgp_direct_pipe = ProtocolPipe(
135 self.birdconfig_globals,
136 name="bgp",
137 table_from="bgp",
138 table_to="direct",
139 table_export="none",
140 import_filter_type=ProtocolPipeFilterType.UNVERSIONED,
141 )
142 self.conf.add(bgp_direct_pipe)
144 # Loop with BGP peers and configure them
145 self.conf.add("")
146 for _, peer in self.peers.items():
147 self.conf.add(peer)
149 def add_originated_route(self, route: str) -> None:
150 """Add originated route."""
151 (prefix, route_info) = route.split(" ", 1)
152 self.originated_routes[prefix] = route_info
154 def add_peer(self, peer_name: str, peer_config: BGPPeerConfig) -> None:
155 """Add peer to BGP."""
157 if peer_name in self.peers:
158 raise BirdPlanError(f"BGP peer '{peer_name}' already exists")
160 # Create BGP peer object
161 peer = ProtocolBGPPeer(
162 self.birdconfig_globals,
163 self.constants,
164 self.functions,
165 self.tables,
166 self.bgp_attributes,
167 self.bgp_functions,
168 peer_name,
169 peer_config,
170 )
172 # Add peer to our configured peer list
173 self.peers[peer_name] = peer
175 def peer(self, name: str) -> ProtocolBGPPeer:
176 """Return a BGP peer configuration object."""
177 if name not in self.peers:
178 raise BirdPlanError(f"Peer '{name}' not found")
179 return self.peers[name]
181 def constraints(self, peer_type: str) -> BGPPeertypeConstraints:
182 """Return the prefix limits for a specific peer type."""
183 if peer_type not in self.bgp_attributes.peertype_constraints:
184 raise BirdPlanError(f"Peer type '{peer_type}' has no implemented global prefix limits")
185 return self.bgp_attributes.peertype_constraints[peer_type]
187 def _configure_constants_bgp(self) -> None: # noqa: CFQ001 # pylint: disable=too-many-statements
188 """Configure BGP constants."""
189 self.constants.conf.append_title("BGP Constants")
191 self.constants.conf.append("# Our BGP ASN")
192 self.constants.conf.append(f"define BGP_ASN = {self.asn};")
193 self.constants.conf.append("")
195 self.constants.conf.append("# Ref http://bgpfilterguide.nlnog.net/guides/bogon_asns/")
196 self.constants.conf.append("define BOGON_ASNS = [")
197 self.constants.conf.append(" 0, # RFC 7607")
198 self.constants.conf.append(" 23456, # RFC 4893 AS_TRANS")
199 self.constants.conf.append(" 64496..64511, # RFC 5398 and documentation/example ASNs")
200 if self.birdconfig_globals.test_mode:
201 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: 64512..65534, # RFC 6996 Private ASNs")
202 else:
203 self.constants.conf.append(" 64512..65534, # RFC 6996 Private ASNs")
204 self.constants.conf.append(" 65535, # RFC 7300 Last 16 bit ASN")
205 self.constants.conf.append(" 65536..65551, # RFC 5398 and documentation/example ASNs")
206 self.constants.conf.append(" 65552..131071, # RFC IANA reserved ASNs")
207 if self.birdconfig_globals.test_mode:
208 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: 4200000000..4294967294, # RFC 6996 Private ASNs")
209 self.constants.conf.append(" 4200000000..4294900000, # RFC 6996 Private ASNs - ADJUSTED FOR TESTING")
210 else:
211 self.constants.conf.append(" 4200000000..4294967294, # RFC 6996 Private ASNs")
212 self.constants.conf.append(" 4294967295 # RFC 7300 Last 32 bit ASN")
213 self.constants.conf.append("];")
214 self.constants.conf.append("")
216 self.constants.conf.append("define PRIVATE_ASNS = [")
217 if self.birdconfig_globals.test_mode:
218 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: 64512..65534, # RFC 6996 Private ASNs")
219 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: 4200000000..4294967294, # RFC 6996 Private ASNs")
220 self.constants.conf.append(" 4200000000..4294900000 # RFC 6996 Private ASNs - ADJUSTED FOR TESTING")
221 else:
222 self.constants.conf.append(" 64512..65534, # RFC 6996 Private ASNs")
223 self.constants.conf.append(" 4200000000..4294967294 # RFC 6996 Private ASNs")
224 self.constants.conf.append("];")
225 self.constants.conf.append("")
227 self.constants.conf.append("# Ref http://bgpfilterguide.nlnog.net/guides/no_transit_leaks")
228 self.constants.conf.append("define BGP_ASNS_TRANSIT = [")
229 self.constants.conf.append(" 174, # Cogent")
230 self.constants.conf.append(" 209, # Qwest (HE carries this on IXPs IPv6 (Jul 12 2018))")
231 self.constants.conf.append(" 701, # UUNET")
232 self.constants.conf.append(" 702, # UUNET")
233 self.constants.conf.append(" 1239, # Sprint")
234 self.constants.conf.append(" 1299, # Telia")
235 self.constants.conf.append(" 2914, # NTT Communications")
236 self.constants.conf.append(" 3257, # GTT Backbone")
237 self.constants.conf.append(" 3320, # Deutsche Telekom AG (DTAG)")
238 self.constants.conf.append(" 3356, # Level3")
239 self.constants.conf.append(" 3491, # PCCW")
240 self.constants.conf.append(" 3549, # Level3")
241 self.constants.conf.append(" 3561, # Savvis / CenturyLink")
242 self.constants.conf.append(" 4134, # Chinanet")
243 self.constants.conf.append(" 5511, # Chinanet")
244 self.constants.conf.append(" 5511, # Orange opentransit")
245 self.constants.conf.append(" 6453, # Tata Communications")
246 self.constants.conf.append(" 6461, # Zayo Bandwidth")
247 self.constants.conf.append(" 6762, # Seabone / Telecom Italia")
248 self.constants.conf.append(" 6830, # Liberty Global")
249 self.constants.conf.append(" 7018 # AT&T")
250 self.constants.conf.append("];")
251 self.constants.conf.append("")
253 # NK: IMPORTANT IF THE ABOVE CHANGES UPDATE THE BELOW
254 self.constants.conf.append("# Community stripping")
255 self.constants.conf.append("define BGP_COMMUNITY_STRIP = [ ")
256 self.constants.conf.append(" (23456, *),")
257 self.constants.conf.append(" (64496..64511, *)") # Documentation
258 self.constants.conf.append("];")
260 # This is used for stripping large communities from customers mostly
261 self.constants.conf.append("define BGP_LC_STRIP = [ ")
262 self.constants.conf.append(" (23456, *, *),")
263 self.constants.conf.append(" (64496..64511, *, *),") # Documentation
264 self.constants.conf.append(" (65552..131071, *, *),") # Reserved
265 self.constants.conf.append(" (BGP_ASN, 1..3, *),") # Strip route learned functions
266 # Allow client traffic engineering: 4, 5, 6, 7, 8
267 self.constants.conf.append(" (BGP_ASN, 9..60, *),") # Strip unused
268 self.constants.conf.append(" (BGP_ASN, 64..70, *),") # Strip unused
269 self.constants.conf.append(" (BGP_ASN, 74..665, *),") # Strip unsed
270 self.constants.conf.append(" (BGP_ASN, 667..4294967295, *),") # Strip unsed + rest (incl. 1000 - info, 1101 - filter)
271 # These functions should never be used on our own ASN
272 self.constants.conf.append(" (BGP_ASN, 4, BGP_ASN),")
273 self.constants.conf.append(" (BGP_ASN, 6, BGP_ASN),")
274 self.constants.conf.append(" (BGP_ASN, 61, BGP_ASN),")
275 self.constants.conf.append(" (BGP_ASN, 62, BGP_ASN),")
276 self.constants.conf.append(" (BGP_ASN, 63, BGP_ASN),")
277 self.constants.conf.append(" (BGP_ASN, 666, BGP_ASN)")
278 self.constants.conf.append("];")
280 # Strip communities mostly for peers and transit providers
281 self.constants.conf.append("define BGP_COMMUNITY_STRIP_ALL = [")
282 # This is first because of the , we need
283 if self.asn and self.asn < 65535:
284 self.constants.conf.append(" (BGP_ASN, *),")
285 else:
286 self.constants.conf.append(" # (BGP_ASN, *), # Not stripping due to 4-byte ASN")
287 self.constants.conf.append(" (23456, *),")
288 self.constants.conf.append(" (64496..64511, *)") # Documentation
289 self.constants.conf.append("];")
290 # This is used for stripping large communities from peers and transit providers
291 self.constants.conf.append("define BGP_LC_STRIP_ALL = [")
292 self.constants.conf.append(" (23456, *, *),")
293 self.constants.conf.append(" (64496..64511, *, *),") # Documentation
294 self.constants.conf.append(" (65552..131071, *, *),") # Reserved
295 self.constants.conf.append(" (BGP_ASN, *, *)")
296 self.constants.conf.append("];")
298 # Stripping private communities
299 self.constants.conf.append("define BGP_COMMUNITY_STRIP_PRIVATE = [")
300 if self.birdconfig_globals.test_mode:
301 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: (64512..65534, *)") # Private
302 else:
303 self.constants.conf.append(" (64512..65534, *)") # Private
304 self.constants.conf.append("];")
306 self.constants.conf.append("define BGP_LC_STRIP_PRIVATE = [")
307 # Don't strip the lower private ASN range during testing
308 if self.birdconfig_globals.test_mode:
309 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: (64512..65534, *, *)") # Private
310 self.constants.conf.append(" # EXCLUDING DUE TO TESTING: (4200000000..4294967294, *, *)")
311 self.constants.conf.append(" (4200000000..4294900000, *, *) # ADJUSTED FOR TESTING")
312 else:
313 self.constants.conf.append(" (64512..65534, *, *),") # Private
314 self.constants.conf.append(" (4200000000..4294967294, *, *)")
315 self.constants.conf.append("];")
317 self.constants.conf.append("# BGP Route Preferences")
318 self.constants.conf.append("define BGP_PREF_OWN = 950;") # -20 = Originate, -10 = static, -5 = kernel
319 self.constants.conf.append("define BGP_PREF_CUSTOMER = 750;")
320 self.constants.conf.append("define BGP_PREF_PEER = 470;")
321 self.constants.conf.append("define BGP_PREF_ROUTESERVER = 450;")
322 self.constants.conf.append("define BGP_PREF_TRANSIT = 150;")
323 self.constants.conf.append("")
325 self.constants.conf.append("# Well known communities")
326 self.constants.conf.append("define BGP_COMMUNITY_GRACEFUL_SHUTDOWN = (65535, 0);")
327 self.constants.conf.append("define BGP_COMMUNITY_BLACKHOLE = (65535, 666);")
328 self.constants.conf.append("define BGP_COMMUNITY_NOEXPORT = (65535, 65281);")
329 self.constants.conf.append("define BGP_COMMUNITY_NOADVERTISE = (65535, 65282);")
330 self.constants.conf.append("")
332 self.constants.conf.append("# Large community functions")
333 # NK: IMPORTANT IF YOU CHANGE THE BELOW, UPDATE BGP_LC_STRIP
334 self.constants.conf.append("define BGP_LC_FUNCTION_LOCATION_ISO3166 = 1;")
335 self.constants.conf.append("define BGP_LC_FUNCTION_LOCATION_UNM49 = 2;")
336 self.constants.conf.append("define BGP_LC_FUNCTION_RELATION = 3;")
337 self.constants.conf.append("define BGP_LC_FUNCTION_NOEXPORT = 4;")
338 self.constants.conf.append("define BGP_LC_FUNCTION_NOEXPORT_LOCATION = 5;")
339 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_ONE = 6;")
340 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_ONE_2 = 61;")
341 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_TWO = 62;")
342 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_THREE = 63;")
343 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_LOCATION_ONE = 7;")
344 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_LOCATION_ONE_2 = 71;")
345 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_LOCATION_TWO = 72;")
346 self.constants.conf.append("define BGP_LC_FUNCTION_PREPEND_LOCATION_THREE = 73;")
347 self.constants.conf.append("define BGP_LC_FUNCTION_LOCALPREF = 8;")
348 self.constants.conf.append("define BGP_LC_FUNCTION_INFORMATION = 1000;")
349 self.constants.conf.append("define BGP_LC_FUNCTION_FILTERED = 1101;")
350 self.constants.conf.append("define BGP_LC_FUNCTION_ACTION = 1200;")
351 self.constants.conf.append("")
353 self.constants.conf.append("# Large community noexport")
354 self.constants.conf.append("define BGP_LC_EXPORT_NOTRANSIT = (BGP_ASN, BGP_LC_FUNCTION_NOEXPORT, 65412);")
355 self.constants.conf.append("define BGP_LC_EXPORT_NOPEER = (BGP_ASN, BGP_LC_FUNCTION_NOEXPORT, 65413);")
356 self.constants.conf.append("define BGP_LC_EXPORT_NOCUSTOMER = (BGP_ASN, BGP_LC_FUNCTION_NOEXPORT, 65414);")
357 self.constants.conf.append("")
359 self.constants.conf.append("# Large community relations")
360 self.constants.conf.append("define BGP_LC_RELATION = [(BGP_ASN, BGP_LC_FUNCTION_RELATION, 1..5)];")
361 self.constants.conf.append("define BGP_LC_RELATION_OWN = (BGP_ASN, BGP_LC_FUNCTION_RELATION, 1);")
362 self.constants.conf.append("define BGP_LC_RELATION_CUSTOMER = (BGP_ASN, BGP_LC_FUNCTION_RELATION, 2);")
363 self.constants.conf.append("define BGP_LC_RELATION_PEER = (BGP_ASN, BGP_LC_FUNCTION_RELATION, 3);")
364 self.constants.conf.append("define BGP_LC_RELATION_TRANSIT = (BGP_ASN, BGP_LC_FUNCTION_RELATION, 4);")
365 self.constants.conf.append("define BGP_LC_RELATION_ROUTESERVER = (BGP_ASN, BGP_LC_FUNCTION_RELATION, 5);")
366 self.constants.conf.append("")
368 self.constants.conf.append("# Large communities for LOCAL_PREF attribute manipulation")
369 self.constants.conf.append("define BGP_LC_LOCALPREF_MINUS_ONE = (BGP_ASN, BGP_LC_FUNCTION_LOCALPREF, 1);")
370 self.constants.conf.append("define BGP_LC_LOCALPREF_MINUS_TWO = (BGP_ASN, BGP_LC_FUNCTION_LOCALPREF, 2);")
371 self.constants.conf.append("define BGP_LC_LOCALPREF_MINUS_THREE = (BGP_ASN, BGP_LC_FUNCTION_LOCALPREF, 3);")
372 self.constants.conf.append("")
374 self.constants.conf.append("# Large community information")
375 self.constants.conf.append("define BGP_LC_INFORMATION_STRIPPED_COMMUNITY = (BGP_ASN, BGP_LC_FUNCTION_INFORMATION, 1);")
376 self.constants.conf.append(
377 "define BGP_LC_INFORMATION_STRIPPED_COMMUNITY_PRIVATE = (BGP_ASN, BGP_LC_FUNCTION_INFORMATION, 2);"
378 )
379 self.constants.conf.append("define BGP_LC_INFORMATION_STRIPPED_LC = (BGP_ASN, BGP_LC_FUNCTION_INFORMATION, 3);")
380 self.constants.conf.append("define BGP_LC_INFORMATION_STRIPPED_LC_PRIVATE = (BGP_ASN, BGP_LC_FUNCTION_INFORMATION, 4);")
381 self.constants.conf.append("")
383 self.constants.conf.append("# Large community filtered")
384 self.constants.conf.append("define BGP_LC_FILTERED_PREFIX_LEN_TOO_LONG = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 1);")
385 self.constants.conf.append("define BGP_LC_FILTERED_PREFIX_LEN_TOO_SHORT = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 2);")
386 self.constants.conf.append("define BGP_LC_FILTERED_BOGON = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 3);")
387 self.constants.conf.append("define BGP_LC_FILTERED_BOGON_ASN = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 4);")
388 self.constants.conf.append("define BGP_LC_FILTERED_ASPATH_TOO_LONG = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 5);")
389 self.constants.conf.append("define BGP_LC_FILTERED_ASPATH_TOO_SHORT = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 6);")
390 self.constants.conf.append("define BGP_LC_FILTERED_FIRST_AS_NOT_PEER_AS = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 7);")
391 self.constants.conf.append("define BGP_LC_FILTERED_NEXT_HOP_NOT_PEER_IP = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 8);")
392 self.constants.conf.append("define BGP_LC_FILTERED_PREFIX_FILTERED = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 9);")
393 self.constants.conf.append("define BGP_LC_FILTERED_ORIGIN_AS = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 10);")
394 # self.constants.conf.append('define BGP_LC_FILTERED_PREFIX_NOT_IN_ORIGIN_AS = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 11);')
395 self.constants.conf.append("define BGP_LC_FILTERED_DEFAULT_NOT_ALLOWED = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 12);")
396 self.constants.conf.append("define BGP_LC_FILTERED_RPKI_UNKNOWN = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 13);")
397 self.constants.conf.append("define BGP_LC_FILTERED_RPKI_INVALID = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 14);")
398 self.constants.conf.append("define BGP_LC_FILTERED_TRANSIT_FREE_ASN = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 15);")
399 self.constants.conf.append("define BGP_LC_FILTERED_TOO_MANY_COMMUNITIES = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 16);")
400 self.constants.conf.append("define BGP_LC_FILTERED_ROUTECOLLECTOR = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 17);")
401 self.constants.conf.append("define BGP_LC_FILTERED_QUARANTINED = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 18);")
402 self.constants.conf.append(
403 "define BGP_LC_FILTERED_TOO_MANY_EXTENDED_COMMUNITIES = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 19);"
404 )
405 self.constants.conf.append("define BGP_LC_FILTERED_TOO_MANY_LARGE_COMMUNITIES = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 20);")
406 self.constants.conf.append("define BGP_LC_FILTERED_PEER_AS = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 21);")
407 self.constants.conf.append("define BGP_LC_FILTERED_ASPATH_NOT_ALLOWED = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 22);")
408 self.constants.conf.append("define BGP_LC_FILTERED_NO_RELATION_LC = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 23);")
409 self.constants.conf.append("define BGP_LC_FILTERED_BLACKHOLE_LEN_TOO_LONG = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 24);")
410 self.constants.conf.append("define BGP_LC_FILTERED_BLACKHOLE_LEN_TOO_SHORT = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 25);")
411 self.constants.conf.append("define BGP_LC_FILTERED_BLACKHOLE_NOT_ALLOWED = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 26);")
412 self.constants.conf.append("define BGP_LC_FILTERED_DENY_ORIGIN_AS = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 27);")
413 self.constants.conf.append("define BGP_LC_FILTERED_DENY_ASPATH = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 28);")
414 self.constants.conf.append("define BGP_LC_FILTERED_DENY_PREFIX = (BGP_ASN, BGP_LC_FUNCTION_FILTERED, 29);")
415 self.constants.conf.append("")
416 self.constants.conf.append("# Large community actions")
417 self.constants.conf.append("define BGP_LC_ACTION_REPLACE_ASPATH = (BGP_ASN, BGP_LC_FUNCTION_ACTION, 1);")
418 self.constants.conf.append("define BGP_LC_ACTION_BLACKHOLE_ORIGINATE = (BGP_ASN, BGP_LC_FUNCTION_ACTION, 2);")
419 self.constants.conf.append("")
421 def _configure_originated_routes(self) -> None:
422 # Work out static v4 and v6 routes
423 routes: Dict[str, List[str]] = {"4": [], "6": []}
424 for prefix in sorted(self.originated_routes.keys()):
425 info = self.originated_routes[prefix]
426 if "." in prefix:
427 routes["4"].append(f"{prefix} {info}")
428 elif ":" in prefix:
429 routes["6"].append(f"{prefix} {info}")
430 else:
431 raise BirdPlanError(f"The BGP originate route '{prefix}' is odd")
433 self.tables.conf.append("# BGP Origination Tables")
435 filter_name = "f_bgp_originate_import"
436 self.conf.add(f"filter {filter_name}")
437 self.conf.add("string filter_name;")
438 self.conf.add("{")
439 self.conf.add(f' filter_name = "{filter_name}";')
440 self.conf.add(" # Origination import")
441 self.conf.add(f" {self.bgp_functions.import_own(20)};")
442 self.conf.add(" accept;")
443 self.conf.add("};")
444 self.conf.add("")
446 # Loop with IPv4 and IPv6
447 for ipv in ["4", "6"]:
448 self.tables.conf.append(f"ipv{ipv} table t_bgp_originate{ipv};")
450 self.conf.add(f"protocol static bgp_originate{ipv} {{")
451 self.conf.add(f' description "BGP route origination for IPv{ipv}";')
452 self.conf.add("")
453 self.conf.add(f" vrf {self.birdconfig_globals.vrf};")
454 self.conf.add("")
455 self.conf.add(f" ipv{ipv} {{")
456 self.conf.add(f" table t_bgp_originate{ipv};")
457 self.conf.add(" export none;")
458 self.conf.add(f" import filter {filter_name};")
459 self.conf.add(" };")
460 # If we have IPv4 routes
461 if routes[ipv]:
462 self.conf.add("")
463 # Output the routes
464 for route in routes[ipv]:
465 self.conf.add(f" route {route};")
466 self.conf.add("};")
467 self.conf.add("")
469 self.tables.conf.append("")
471 # Configure BGP origination route pipe to the bgp table
472 originate_pipe = ProtocolPipe(
473 birdconfig_globals=self.birdconfig_globals,
474 table_from="bgp_originate",
475 table_to="bgp",
476 table_export="all",
477 table_import="none",
478 )
479 self.conf.add(originate_pipe)
481 def _setup_bgp_to_master_export_filter(self) -> None:
482 """BGP main table to master export filters setup."""
484 # Configure export filter to master
485 filter_name = "f_bgp_master_export"
486 self.conf.add("# Export filter FROM BGP table TO master table")
487 self.conf.add(f"filter {filter_name}")
488 self.conf.add("string filter_name;")
489 self.conf.add("{")
490 self.conf.add(f' filter_name = "{filter_name}";')
491 # Accept BGP routes into the master routing table
492 self.conf.add(f" {self.bgp_functions.accept_bgp()};")
493 # Check if we accept customer blackhole routes, if not block it
494 if self.route_policy_accept.bgp_customer_blackhole:
495 self.conf.add(f" {self.bgp_functions.accept_customer_blackhole()};")
496 # Check if we accept our own blackhole routes, if not block it
497 if self.route_policy_accept.bgp_own_blackhole:
498 self.conf.add(f" {self.bgp_functions.accept_own_blackhole()};")
499 # Check if we accept default routes originated from within our federation, if not block it
500 if self.route_policy_accept.bgp_own_default:
501 self.conf.add(f" {self.bgp_functions.accept_bgp_own_default()};")
502 # Check if we accept default routes originated from transit peers, if not block it
503 if self.route_policy_accept.bgp_transit_default:
504 self.conf.add(f" {self.bgp_functions.accept_bgp_transit_default()};")
505 # Check if we accept originated routes, if not block it
506 if self.route_policy_accept.originated:
507 self.conf.add(f" {self.bgp_functions.accept_originated()};")
508 # Check if we accept originated routes, if not block it
509 if self.route_policy_accept.originated_default:
510 self.conf.add(f" {self.bgp_functions.accept_originated_default()};")
511 # Default to reject
512 self.conf.add(" if DEBUG then")
513 self.conf.add(f' print "[{filter_name}] Rejecting ", net, " from t_bgp to master (fallthrough)";')
514 self.conf.add(" reject;")
515 self.conf.add("};")
516 self.conf.add("")
518 def _setup_bgp_to_master_import_filter(self) -> None:
519 """BGP main table to master import filters setup."""
520 # Configure import filter to master
521 filter_name = "f_bgp_master_import"
522 self.conf.add("# Import filter FROM master table TO BGP table")
523 self.conf.add(f"filter {filter_name}")
524 self.conf.add("string filter_name;")
525 self.conf.add("{")
526 self.conf.add(f' filter_name = "{filter_name}";')
527 # BGP importation of kernel routes
528 if self.route_policy_import.kernel:
529 self.conf.add(f" {self.bgp_functions.import_kernel()};")
530 # BGP importation of kernel blackhole routes
531 if self.route_policy_import.kernel_blackhole:
532 self.conf.add(f" {self.bgp_functions.import_kernel_blackhole()};")
533 # BGP importation of kernel default routes
534 if self.route_policy_import.kernel_default:
535 self.conf.add(f" {self.bgp_functions.import_kernel_default()};")
536 # BGP importation of static routes
537 if self.route_policy_import.static:
538 self.conf.add(f" {self.bgp_functions.import_static()};")
539 # BGP importation of static blackhole routes
540 if self.route_policy_import.static_blackhole:
541 self.conf.add(f" {self.bgp_functions.import_static_blackhole()};")
542 # BGP importation of static default routes
543 if self.route_policy_import.static_default:
544 self.conf.add(f" {self.bgp_functions.import_static_default()};")
545 # Else reject
546 self.conf.add(" if DEBUG then")
547 self.conf.add(f' print "[{filter_name}] Rejecting ", net, " from master to t_bgp (fallthrough)";')
548 self.conf.add(" reject;")
549 self.conf.add("};")
550 self.conf.add("")
552 def _setup_bgp_to_direct_import_filter(self) -> None:
553 """BGP main table to direct import filters setup."""
555 filter_name = "f_bgp_direct_import"
556 self.conf.add("# Import filter FROM master table TO BGP table")
557 self.conf.add(f"filter {filter_name}")
558 self.conf.add("string filter_name;")
559 self.conf.add("{")
560 self.conf.add(f' filter_name = "{filter_name}";')
561 self.conf.add(" # Import connected routes")
562 self.conf.add(f" {self.bgp_functions.import_own(10)};")
563 self.conf.add(" accept;")
564 self.conf.add("};")
565 self.conf.add("")
567 # PROPERTIES
569 @property
570 def bgp_attributes(self) -> BGPAttributes:
571 """Return our BGP protocol attributes."""
572 return self._bgp_attributes
574 @property
575 def bgp_functions(self) -> BGPFunctions:
576 """Return our BGP protocol functions."""
577 return self._bgp_functions
579 @property
580 def asn(self) -> Optional[int]:
581 """Return our ASN."""
582 return self.bgp_attributes.asn
584 @asn.setter
585 def asn(self, asn: int) -> None:
586 """Set our ASN."""
587 self.bgp_attributes.asn = asn
588 # Enable bogon constants
589 self.constants.need_bogons = True
591 @property
592 def peertype_constraints(self) -> Dict[str, BGPPeertypeConstraints]:
593 """Return our peertype constraints."""
594 return self.bgp_attributes.peertype_constraints
596 @property
597 def graceful_shutdown(self) -> bool:
598 """Return our the value of graceful_shutdown."""
599 return self.bgp_attributes.graceful_shutdown
601 @graceful_shutdown.setter
602 def graceful_shutdown(self, graceful_shutdown: bool) -> None:
603 """Set the value of graceful_shutdown."""
604 self.bgp_attributes.graceful_shutdown = graceful_shutdown
606 @property
607 def quarantine(self) -> bool:
608 """Global BGP peer quarantine state."""
609 return self.bgp_attributes.quarantine
611 @quarantine.setter
612 def quarantine(self, quarantine: bool) -> None:
613 """Global BGP peer quarantine state."""
614 self.bgp_attributes.quarantine = quarantine
616 @property
617 def rr_cluster_id(self) -> Optional[str]:
618 """Return route reflector cluster ID."""
619 return self.bgp_attributes.rr_cluster_id
621 @rr_cluster_id.setter
622 def rr_cluster_id(self, rr_cluster_id: str) -> None:
623 """Set our route reflector cluster ID."""
624 self.bgp_attributes.rr_cluster_id = rr_cluster_id
626 @property
627 def route_policy_accept(self) -> BGPRoutePolicyAccept:
628 """Return our route policy for accepting of routes from peers into the main BGP table."""
629 return self.bgp_attributes.route_policy_accept
631 @property
632 def route_policy_import(self) -> BGPRoutePolicyImport:
633 """Return our route policy for importing of routes from internal tables."""
634 return self.bgp_attributes.route_policy_import
636 @property
637 def peers(self) -> BGPPeers:
638 """BGP peers."""
639 return self._peers
641 @property
642 def originated_routes(self) -> BGPOriginatedRoutes:
643 """Return our originated routes."""
644 return self._originated_routes