Coverage for src/birdplan/bird_config/sections/protocols/ospf/area/interface/__init__.py: 99%

111 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-04 10:19 +0000

1# 

2# SPDX-License-Identifier: GPL-3.0-or-later 

3# 

4# Copyright (c) 2015-2025, 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 OSPF area interface configuration.""" 

20 

21# pylint: disable=too-many-lines 

22 

23import fnmatch 

24 

25from ......globals import BirdConfigGlobals 

26from .....bird_attributes import SectionBirdAttributes 

27from .....constants import SectionConstants 

28from .....functions import SectionFunctions 

29from .....tables import SectionTables 

30from ....base import SectionProtocolBase 

31from ..area_attributes import OSPFAreaAttributes 

32from .interface_attributes import OSPFAreaInterfaceAttributes 

33from .ospf_area_interface_types import OSPFAreaInterfaceConfig 

34 

35__all__ = ["ProtocolOSPFAreaInterface"] 

36 

37 

38class ProtocolOSPFAreaInterface(SectionProtocolBase): # pylint: disable=too-many-public-methods,too-many-instance-attributes 

39 """BIRD OSPF area interface configuration.""" 

40 

41 # OSPF area attributes 

42 _area_attributes: OSPFAreaAttributes 

43 

44 # OSPF area interface attributes 

45 _interface_attributes: OSPFAreaInterfaceAttributes 

46 

47 def __init__( # noqa: C901,PLR0912,PLR0913 

48 self, 

49 birdconfig_globals: BirdConfigGlobals, 

50 birdattributes: SectionBirdAttributes, 

51 constants: SectionConstants, 

52 functions: SectionFunctions, 

53 tables: SectionTables, 

54 area_attributes: OSPFAreaAttributes, 

55 interface_name: str, 

56 interface_config: OSPFAreaInterfaceConfig, 

57 ) -> None: 

58 """Initialize the object.""" 

59 super().__init__(birdconfig_globals, birdattributes, constants, functions, tables) 

60 

61 # Setup the OSPF area attributes 

62 self._area_attributes = area_attributes 

63 

64 # Setup OSPF area interface attributes 

65 self._interface_attributes = OSPFAreaInterfaceAttributes() 

66 

67 # Set our interface name 

68 self.name = interface_name 

69 

70 # Check if we have a interface cost 

71 if "cost" in interface_config: 

72 self.cost = interface_config["cost"] 

73 

74 # Check if we have an interface ECMP weight 

75 if "ecmp_weight" in interface_config: 

76 self.ecmp_weight = interface_config["ecmp_weight"] 

77 

78 # Check if we have a interface hello 

79 if "hello" in interface_config: 

80 self.hello = interface_config["hello"] 

81 

82 # Check if we have a interface wait 

83 if "wait" in interface_config: 

84 self.wait = interface_config["wait"] 

85 

86 # Check if this interface is a stub 

87 if "stub" in interface_config: 

88 self.stub = interface_config["stub"] 

89 

90 # Check if we have a interface setting overrides 

91 if ( 

92 "ospf" in self.birdconfig_globals.state 

93 and "areas" in self.birdconfig_globals.state["ospf"] 

94 and self.area_attributes.name in self.birdconfig_globals.state["ospf"]["areas"] 

95 and "+interfaces" in self.birdconfig_globals.state["ospf"]["areas"][self.area_attributes.name] 

96 ): 

97 # Make things easier below 

98 interface_overrides = self.birdconfig_globals.state["ospf"]["areas"][self.area_attributes.name]["+interfaces"] 

99 

100 # Check if this interface is in the override structure 

101 if self.name in interface_overrides: 

102 # Check if we have a cost override 

103 if "cost" in interface_overrides[self.name]: 

104 self.cost = interface_overrides[self.name]["cost"] 

105 # Check if we have an ecmp_weight override 

106 if "ecmp_weight" in interface_overrides[self.name]: 

107 self.ecmp_weight = interface_overrides[self.name]["ecmp_weight"] 

108 # If not we process the patterns 

109 else: 

110 for item in sorted(interface_overrides): 

111 # Skip non patterns 

112 if "*" not in item: 

113 continue 

114 # If pattern matches peer name, set the value for quarantine 

115 if fnmatch.fnmatch(self.name, item): 

116 if "cost" in interface_overrides[item]: 

117 self.cost = interface_overrides[item]["cost"] 

118 if "ecmp_weight" in interface_overrides[item]: 

119 self.ecmp_weight = interface_overrides[item]["ecmp_weight"] 

120 

121 def configure(self) -> None: 

122 """Configure the OSPF interface.""" 

123 

124 # Don't re-render the configuration, we're called twice for v4 and V6 

125 if self.conf.items: 

126 return 

127 

128 super().configure() 

129 

130 # Blank the OSPF area interface state 

131 area_interfaces_state = self.birdconfig_globals.state["ospf"]["areas"][self.area_attributes.name]["interfaces"] 

132 if self.name not in area_interfaces_state: 

133 area_interfaces_state[self.name] = {} 

134 

135 # Setup our state 

136 interface_state = area_interfaces_state[self.name] 

137 interface_state["cost"] = self.cost 

138 interface_state["ecmp_weight"] = self.ecmp_weight 

139 

140 # Start interface block 

141 self.conf.add(f' interface "{self.name}" { ') 

142 # Check if we have a cost 

143 if self.cost: 

144 self.conf.add(f" cost {self.cost};") 

145 # Check if we have a ecmp_weight 

146 if self.ecmp_weight: 

147 self.conf.add(f" ecmp weight {self.ecmp_weight};") 

148 # Check if we have a hello 

149 if self.hello: 

150 self.conf.add(f" hello {self.hello};") 

151 # Check if we have a wait 

152 if self.wait: 

153 self.conf.add(f" wait {self.wait};") 

154 # Check our stub option 

155 if self.is_stub: 

156 self.conf.add(" stub;") 

157 # Close off interface block 

158 self.conf.add(" };") 

159 

160 @property 

161 def is_stub(self) -> bool: 

162 """Return if interface is a stub.""" 

163 return self.stub 

164 

165 @property 

166 def area_attributes(self) -> OSPFAreaAttributes: 

167 """OSPF area attributes.""" 

168 return self._area_attributes 

169 

170 @property 

171 def interface_attributes(self) -> OSPFAreaInterfaceAttributes: 

172 """OSPF area interface attributes.""" 

173 return self._interface_attributes 

174 

175 @property 

176 def name(self) -> str: 

177 """Interface name.""" 

178 return self.interface_attributes.name 

179 

180 @name.setter 

181 def name(self, name: str) -> None: 

182 """Interface name.""" 

183 self.interface_attributes.name = name 

184 

185 @property 

186 def cost(self) -> int: 

187 """Interface cost.""" 

188 return self.interface_attributes.cost 

189 

190 @cost.setter 

191 def cost(self, cost: int) -> None: 

192 """Interface cost.""" 

193 self.interface_attributes.cost = cost 

194 

195 @property 

196 def ecmp_weight(self) -> int | None: 

197 """Interface ECMP weight.""" 

198 return self.interface_attributes.ecmp_weight 

199 

200 @ecmp_weight.setter 

201 def ecmp_weight(self, ecmp_weight: int) -> None: 

202 """Interface ECMP weight.""" 

203 self.interface_attributes.ecmp_weight = ecmp_weight 

204 

205 @property 

206 def hello(self) -> int | None: 

207 """Interface hello.""" 

208 return self.interface_attributes.hello 

209 

210 @hello.setter 

211 def hello(self, hello: int) -> None: 

212 """Interface hello.""" 

213 self.interface_attributes.hello = hello 

214 

215 @property 

216 def wait(self) -> int | None: 

217 """Interface wait.""" 

218 return self.interface_attributes.wait 

219 

220 @wait.setter 

221 def wait(self, wait: int) -> None: 

222 """Interface wait.""" 

223 self.interface_attributes.wait = wait 

224 

225 @property 

226 def stub(self) -> bool: 

227 """Interface is a stub.""" 

228 return self.interface_attributes.stub 

229 

230 @stub.setter 

231 def stub(self, stub: bool) -> None: 

232 """Interface is a stub.""" 

233 self.interface_attributes.stub = stub