Coverage for src/birdplan/bird_config/sections/protocols/pipe.py: 100%
81 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-25 07:38 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-25 07:38 +0000
1#
2# SPDX-License-Identifier: GPL-3.0-or-later
3#
4# Copyright (c) 2019-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 pipe protocol configuration."""
21from collections.abc import Callable
22from enum import Enum
24from ...globals import BirdConfigGlobals
25from ..base import SectionBase
27__all__ = ["ProtocolPipe", "ProtocolPipeFilterType"]
30PipeTableNameType = str | Callable[[str], str]
33class ProtocolPipeFilterType(Enum):
34 """
35 Pipe protocol filter name type.
37 NO_FILTER - No filter will be applied.
38 VERSIONED - Filter will be IP versioned.
39 UNVERSIONED - Filter will not be IP versioned.
41 """
43 NO_FILTER = 0
44 VERSIONED = 1
45 UNVERSIONED = 2
48# This class cannot be a decendant of the SectionProtocolBase class or we'll have circular imports
49class ProtocolPipe(SectionBase): # pylint: disable=too-many-instance-attributes
50 """BIRD pipe protocol configuration."""
52 _name_suffix: str
54 _table_from: PipeTableNameType
55 _table_to: PipeTableNameType
56 _table_export: str
57 _table_import: str
58 _export_filter_type: ProtocolPipeFilterType
59 _import_filter_type: ProtocolPipeFilterType
61 # IP versions we're creating a pipe for
62 _ipversions: list[str]
64 def __init__( # noqa: PLR0913,PLR0917
65 self,
66 birdconfig_globals: BirdConfigGlobals,
67 table_from: PipeTableNameType,
68 table_to: PipeTableNameType,
69 name: str = "",
70 table_export: str = "none",
71 table_import: str = "none",
72 export_filter_type: ProtocolPipeFilterType = ProtocolPipeFilterType.NO_FILTER,
73 import_filter_type: ProtocolPipeFilterType = ProtocolPipeFilterType.NO_FILTER,
74 has_ipv4: bool = True, # noqa: FBT001,FBT002
75 has_ipv6: bool = True, # noqa: FBT001,FBT002
76 ) -> None:
77 """Initialize the object."""
78 super().__init__(birdconfig_globals)
80 # Add a suffix if we have a name
81 self._name_suffix = ""
82 if name:
83 self._name_suffix = f"_{name}"
85 # Grab table information
86 self._table_from = table_from
87 self._table_to = table_to
88 self._table_export = table_export
89 self._table_import = table_import
90 self._export_filter_type = export_filter_type
91 self._import_filter_type = import_filter_type
93 # Are we excluding anything?
94 self._ipversions = []
95 if has_ipv4:
96 self._ipversions.append("4")
97 if has_ipv6:
98 self._ipversions.append("6")
100 def configure(self) -> None:
101 """Create a pipe protocol."""
102 super().configure()
104 for ipv in self._ipversions:
105 self.conf.add(f"protocol pipe p_{self.table_from(ipv)}_to_{self.table_to(ipv)}{self.name_suffix} {{")
106 self.conf.add(f' description "Pipe from {self.t_table_from(ipv)} to {self.t_table_to(ipv)}{self.name_suffix}";')
107 self.conf.add("")
108 self.conf.add(f" vrf {self.birdconfig_globals.vrf};")
109 self.conf.add("")
110 self.conf.add(f" table {self.t_table_from(ipv)};")
111 self.conf.add(f" peer table {self.t_table_to(ipv)}{self.name_suffix};")
112 self.conf.add("")
114 # Check if we're doing export filtering
115 if self.export_filter_type == ProtocolPipeFilterType.VERSIONED:
116 self.conf.add(f" export filter f_{self.table_from(ipv)}_{self.table_to(ipv)}_export;")
117 elif self.export_filter_type == ProtocolPipeFilterType.UNVERSIONED:
118 self.conf.add(f" export filter f_{self.table_from()}_{self.table_to()}_export;")
119 # If not add per normal
120 else:
121 self.conf.add(f" export {self.table_export};")
123 # Check if we're doing import filtering
124 if self.import_filter_type == ProtocolPipeFilterType.VERSIONED:
125 self.conf.add(f" import filter f_{self.table_from(ipv)}_{self.table_to(ipv)}_import;")
126 elif self.import_filter_type == ProtocolPipeFilterType.UNVERSIONED:
127 self.conf.add(f" import filter f_{self.table_from()}_{self.table_to()}_import;")
128 # If not add per normal
129 else:
130 self.conf.add(f" import {self.table_import};")
132 self.conf.add("};")
133 self.conf.add("")
135 def table_from(self, ipv: str = "") -> str:
136 """Return table_from with IP version included."""
138 # If the table is callable, call it and get the name
139 table_from = self._table_from(ipv) if callable(self._table_from) else f"{self._table_from}{ipv}"
141 # If it starts with t_, we need to remove t_ for now
142 return table_from.removeprefix("t_")
144 def table_to(self, ipv: str = "") -> str:
145 """Return table_to with IP version included."""
147 # If the table is callable, call it and get the name
148 table_to = self._table_to(ipv) if callable(self._table_to) else f"{self._table_to}{ipv}"
150 # If it starts with t_, we need to remove t_ for now
151 return table_to.removeprefix("t_")
153 def t_table_from(self, ipv: str) -> str:
154 r"""Return table_from, some tables don't have t\_ prefixes."""
155 table_name = self.table_from(ipv)
156 # If it is not a master table, add t_
157 if not table_name.startswith("master"):
158 table_name = "t_" + table_name
159 return table_name
161 def t_table_to(self, ipv: str) -> str:
162 r"""Return table_to, some tables don't have t\_ prefixes."""
163 table_name = self.table_to(ipv)
164 # If it is not a master table, add t_
165 if not table_name.startswith("master"):
166 table_name = "t_" + table_name
167 return table_name
169 @property
170 def name_suffix(self) -> str:
171 """Return our name suffix."""
172 return self._name_suffix
174 @property
175 def table_export(self) -> str:
176 """Return that state of us exporting the table."""
177 return self._table_export
179 @property
180 def table_import(self) -> str:
181 """Return that state of us importing the table."""
182 return self._table_import
184 @property
185 def export_filter_type(self) -> ProtocolPipeFilterType:
186 """Return that state of us exporting the table filtered."""
187 return self._export_filter_type
189 @property
190 def import_filter_type(self) -> ProtocolPipeFilterType:
191 """Return that state of us importing the table filtered."""
192 return self._import_filter_type