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
« 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/>.
19"""BIRD OSPF area interface configuration."""
21# pylint: disable=too-many-lines
23import fnmatch
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
35__all__ = ["ProtocolOSPFAreaInterface"]
38class ProtocolOSPFAreaInterface(SectionProtocolBase): # pylint: disable=too-many-public-methods,too-many-instance-attributes
39 """BIRD OSPF area interface configuration."""
41 # OSPF area attributes
42 _area_attributes: OSPFAreaAttributes
44 # OSPF area interface attributes
45 _interface_attributes: OSPFAreaInterfaceAttributes
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)
61 # Setup the OSPF area attributes
62 self._area_attributes = area_attributes
64 # Setup OSPF area interface attributes
65 self._interface_attributes = OSPFAreaInterfaceAttributes()
67 # Set our interface name
68 self.name = interface_name
70 # Check if we have a interface cost
71 if "cost" in interface_config:
72 self.cost = interface_config["cost"]
74 # Check if we have an interface ECMP weight
75 if "ecmp_weight" in interface_config:
76 self.ecmp_weight = interface_config["ecmp_weight"]
78 # Check if we have a interface hello
79 if "hello" in interface_config:
80 self.hello = interface_config["hello"]
82 # Check if we have a interface wait
83 if "wait" in interface_config:
84 self.wait = interface_config["wait"]
86 # Check if this interface is a stub
87 if "stub" in interface_config:
88 self.stub = interface_config["stub"]
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"]
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"]
121 def configure(self) -> None:
122 """Configure the OSPF interface."""
124 # Don't re-render the configuration, we're called twice for v4 and V6
125 if self.conf.items:
126 return
128 super().configure()
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] = {}
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
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(" };")
160 @property
161 def is_stub(self) -> bool:
162 """Return if interface is a stub."""
163 return self.stub
165 @property
166 def area_attributes(self) -> OSPFAreaAttributes:
167 """OSPF area attributes."""
168 return self._area_attributes
170 @property
171 def interface_attributes(self) -> OSPFAreaInterfaceAttributes:
172 """OSPF area interface attributes."""
173 return self._interface_attributes
175 @property
176 def name(self) -> str:
177 """Interface name."""
178 return self.interface_attributes.name
180 @name.setter
181 def name(self, name: str) -> None:
182 """Interface name."""
183 self.interface_attributes.name = name
185 @property
186 def cost(self) -> int:
187 """Interface cost."""
188 return self.interface_attributes.cost
190 @cost.setter
191 def cost(self, cost: int) -> None:
192 """Interface cost."""
193 self.interface_attributes.cost = cost
195 @property
196 def ecmp_weight(self) -> int | None:
197 """Interface ECMP weight."""
198 return self.interface_attributes.ecmp_weight
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
205 @property
206 def hello(self) -> int | None:
207 """Interface hello."""
208 return self.interface_attributes.hello
210 @hello.setter
211 def hello(self, hello: int) -> None:
212 """Interface hello."""
213 self.interface_attributes.hello = hello
215 @property
216 def wait(self) -> int | None:
217 """Interface wait."""
218 return self.interface_attributes.wait
220 @wait.setter
221 def wait(self, wait: int) -> None:
222 """Interface wait."""
223 self.interface_attributes.wait = wait
225 @property
226 def stub(self) -> bool:
227 """Interface is a stub."""
228 return self.interface_attributes.stub
230 @stub.setter
231 def stub(self, stub: bool) -> None:
232 """Interface is a stub."""
233 self.interface_attributes.stub = stub