|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 |
|
17 | 17 | import os |
| 18 | +import re |
18 | 19 |
|
19 | 20 | from sys import exit |
20 | 21 |
|
@@ -171,6 +172,13 @@ def get_config(config=None): |
171 | 172 |
|
172 | 173 | ethernet['flowtable_interfaces'] = get_flowtable_interfaces(conf) |
173 | 174 |
|
| 175 | + ethernet['vpp'] = conf.get_config_dict( |
| 176 | + ['vpp'], |
| 177 | + key_mangling=('-', '_'), |
| 178 | + get_first_key=True, |
| 179 | + no_tag_node_value_mangle=True, |
| 180 | + ) |
| 181 | + |
174 | 182 | return ethernet |
175 | 183 |
|
176 | 184 | def verify_speed_duplex(ethernet: dict, ethtool: Ethtool): |
@@ -301,8 +309,51 @@ def verify_flowtable(ethernet: dict): |
301 | 309 | if vifcname in ethernet['flowtable_interfaces']: |
302 | 310 | raise ConfigError(f'Cannot delete interface "{vifcname}", still referenced on a flowtable') |
303 | 311 |
|
| 312 | +def verify_vpp_remove_vif(ethernet: dict): |
| 313 | + """Ensure that VIF interfaces being removed are not used by VPP features""" |
| 314 | + possible_vpp_paths = [ |
| 315 | + # Known paths that already use VLAN interfaces |
| 316 | + r'nat.cgnat.interface.inside', |
| 317 | + r'nat.cgnat.interface.outside', |
| 318 | + r'nat44.interface.inside', |
| 319 | + r'nat44.interface.outside', |
| 320 | + # Potential paths for VLAN interfaces |
| 321 | + r'nat44.address_pool.translation.interface', |
| 322 | + r'nat44.address_pool.twice_nat.interface', |
| 323 | + r'nat44.exclude.rule.(\d)+.external_interface', |
| 324 | + r'interfaces.bonding.bond(\d)+.member.interface', |
| 325 | + r'interfaces.bridge.br(\d)+.member.interface', |
| 326 | + r'interfaces.xconnect.xcon(\d)+.member.interface', |
| 327 | + r'acl.ip.interface', |
| 328 | + r'acl.macip.interface', |
| 329 | + ] |
| 330 | + ifname = ethernet['ifname'] |
| 331 | + vpp_flat = dict_to_paths_values(ethernet.get('vpp', {})) |
| 332 | + |
| 333 | + for vif_group in ['vif_remove', 'vif_s_remove']: |
| 334 | + for vif_id in ethernet.get(vif_group, []): |
| 335 | + vif_name = f'{ifname}.{vif_id}' |
| 336 | + |
| 337 | + # Find all VPP paths that reference this VIF |
| 338 | + matching_paths = [ |
| 339 | + key |
| 340 | + for pattern in possible_vpp_paths |
| 341 | + for key, value in vpp_flat.items() |
| 342 | + if re.fullmatch(pattern, key) |
| 343 | + and ( |
| 344 | + value == vif_name or (isinstance(value, list) and vif_name in value) |
| 345 | + ) |
| 346 | + ] |
| 347 | + |
| 348 | + if matching_paths: |
| 349 | + raise ConfigError( |
| 350 | + f'Cannot delete interface "{vif_name}", it is still in use by ' |
| 351 | + f'"vpp {matching_paths[0].replace(".", " ")}"' |
| 352 | + ) |
| 353 | + |
304 | 354 | def verify(ethernet): |
305 | 355 | verify_flowtable(ethernet) |
| 356 | + verify_vpp_remove_vif(ethernet) |
306 | 357 |
|
307 | 358 | if 'deleted' in ethernet: |
308 | 359 | return None |
|
0 commit comments