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

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/>. 

18 

19"""BIRD BGP protocol configuration.""" 

20 

21# pylint: disable=too-many-lines 

22 

23from typing import Dict, List, Optional 

24 

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 

37 

38__all__ = ["ProtocolBGP"] 

39 

40 

41BGPPeersConfig = Dict[str, BGPPeerConfig] 

42BGPPeers = Dict[str, ProtocolBGPPeer] 

43BGPOriginatedRoutes = Dict[str, str] 

44 

45 

46class ProtocolBGP(SectionProtocolBase): # pylint: disable=too-many-public-methods 

47 """BIRD BGP protocol configuration.""" 

48 

49 # BGP protocol attributes 

50 _bgp_attributes: BGPAttributes 

51 # BGP functions 

52 _bgp_functions: BGPFunctions 

53 

54 # BGP peers 

55 _peers: BGPPeers 

56 

57 # Internal config before configuration happens 

58 _originated_routes: BGPOriginatedRoutes 

59 

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) 

65 

66 # Set section name 

67 self._section = "BGP Protocol" 

68 

69 # BGP peers 

70 self._peers = {} 

71 

72 # Routes originated from BGP 

73 self._originated_routes = {} 

74 

75 # Setup BGP attributes 

76 self._bgp_attributes = BGPAttributes() 

77 # Setup BGP functions 

78 self._bgp_functions = BGPFunctions(self.birdconfig_globals, self.functions) 

79 

80 def configure(self) -> None: 

81 """Configure the BGP protocol.""" 

82 super().configure() 

83 

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"] = {} 

88 

89 self._configure_constants_bgp() 

90 self.functions.conf.append(self.bgp_functions, deferred=True) 

91 

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("") 

96 

97 # Setup BGP origination 

98 self._configure_originated_routes() 

99 

100 # BGP to master export filters 

101 self._setup_bgp_to_master_export_filter() 

102 

103 # BGP to master import filters 

104 self._setup_bgp_to_master_import_filter() 

105 

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) 

115 

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) 

143 

144 # Loop with BGP peers and configure them 

145 self.conf.add("") 

146 for _, peer in self.peers.items(): 

147 self.conf.add(peer) 

148 

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 

153 

154 def add_peer(self, peer_name: str, peer_config: BGPPeerConfig) -> None: 

155 """Add peer to BGP.""" 

156 

157 if peer_name in self.peers: 

158 raise BirdPlanError(f"BGP peer '{peer_name}' already exists") 

159 

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 ) 

171 

172 # Add peer to our configured peer list 

173 self.peers[peer_name] = peer 

174 

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] 

180 

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] 

186 

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") 

190 

191 self.constants.conf.append("# Our BGP ASN") 

192 self.constants.conf.append(f"define BGP_ASN = {self.asn};") 

193 self.constants.conf.append("") 

194 

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("") 

215 

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("") 

226 

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("") 

252 

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("];") 

259 

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("];") 

279 

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("];") 

297 

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("];") 

305 

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("];") 

316 

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("") 

324 

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("") 

331 

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("") 

352 

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("") 

358 

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("") 

367 

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("") 

373 

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("") 

382 

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("") 

420 

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") 

432 

433 self.tables.conf.append("# BGP Origination Tables") 

434 

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("") 

445 

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};") 

449 

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("") 

468 

469 self.tables.conf.append("") 

470 

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) 

480 

481 def _setup_bgp_to_master_export_filter(self) -> None: 

482 """BGP main table to master export filters setup.""" 

483 

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("") 

517 

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("") 

551 

552 def _setup_bgp_to_direct_import_filter(self) -> None: 

553 """BGP main table to direct import filters setup.""" 

554 

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("") 

566 

567 # PROPERTIES 

568 

569 @property 

570 def bgp_attributes(self) -> BGPAttributes: 

571 """Return our BGP protocol attributes.""" 

572 return self._bgp_attributes 

573 

574 @property 

575 def bgp_functions(self) -> BGPFunctions: 

576 """Return our BGP protocol functions.""" 

577 return self._bgp_functions 

578 

579 @property 

580 def asn(self) -> Optional[int]: 

581 """Return our ASN.""" 

582 return self.bgp_attributes.asn 

583 

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 

590 

591 @property 

592 def peertype_constraints(self) -> Dict[str, BGPPeertypeConstraints]: 

593 """Return our peertype constraints.""" 

594 return self.bgp_attributes.peertype_constraints 

595 

596 @property 

597 def graceful_shutdown(self) -> bool: 

598 """Return our the value of graceful_shutdown.""" 

599 return self.bgp_attributes.graceful_shutdown 

600 

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 

605 

606 @property 

607 def quarantine(self) -> bool: 

608 """Global BGP peer quarantine state.""" 

609 return self.bgp_attributes.quarantine 

610 

611 @quarantine.setter 

612 def quarantine(self, quarantine: bool) -> None: 

613 """Global BGP peer quarantine state.""" 

614 self.bgp_attributes.quarantine = quarantine 

615 

616 @property 

617 def rr_cluster_id(self) -> Optional[str]: 

618 """Return route reflector cluster ID.""" 

619 return self.bgp_attributes.rr_cluster_id 

620 

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 

625 

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 

630 

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 

635 

636 @property 

637 def peers(self) -> BGPPeers: 

638 """BGP peers.""" 

639 return self._peers 

640 

641 @property 

642 def originated_routes(self) -> BGPOriginatedRoutes: 

643 """Return our originated routes.""" 

644 return self._originated_routes