Skip to content

Commit 0447d71

Browse files
Merge pull request #4830 from natali-rs1985/T7950
T7950: VPP: Unexpected None interface in CGNAT when ethernet subinterace is removed from vif
2 parents cd958a4 + db494bc commit 0447d71

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

src/conf_mode/interfaces_ethernet.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

1717
import os
18+
import re
1819

1920
from sys import exit
2021

@@ -173,6 +174,13 @@ def get_config(config=None):
173174

174175
ethernet['flowtable_interfaces'] = get_flowtable_interfaces(conf)
175176

177+
ethernet['vpp'] = conf.get_config_dict(
178+
['vpp'],
179+
key_mangling=('-', '_'),
180+
get_first_key=True,
181+
no_tag_node_value_mangle=True,
182+
)
183+
176184
# Protocols static arp dependency
177185
if 'static_arp' in ethernet:
178186
set_dependents('static_arp', conf)
@@ -307,8 +315,59 @@ def verify_flowtable(ethernet: dict):
307315
if vifcname in ethernet['flowtable_interfaces']:
308316
raise ConfigError(f'Cannot delete interface "{vifcname}", still referenced on a flowtable')
309317

318+
def verify_vpp_remove_vif(ethernet: dict):
319+
"""Ensure that VIF interfaces being removed are not used by VPP features"""
320+
vpp_paths_pattern = re.compile(
321+
# Known paths that already use VLAN interfaces
322+
r'(nat\.cgnat\.interface\.inside)|'
323+
r'(nat\.cgnat\.interface\.outside)|'
324+
r'(nat44\.interface\.inside)|'
325+
r'(nat44\.interface\.outside)|'
326+
# Potential paths for VLAN interfaces
327+
r'(nat44\.address_pool\.translation\.interface)|'
328+
r'(nat44\.address_pool\.twice_nat\.interface)|'
329+
r'(nat44\.exclude\.rule\.(\d)+\.external_interface)|'
330+
r'(interfaces\.bonding\.bond(\d)+\.member\.interface)|'
331+
r'(interfaces\.bridge\.br(\d)+\.member\.interface)|'
332+
r'(interfaces\.xconnect\.xcon(\d)+\.member\.interface)|'
333+
r'(acl\.ip\.interface)|'
334+
r'(acl\.macip\.interface)'
335+
)
336+
ifname = ethernet['ifname']
337+
338+
vlan_names = [
339+
f'{ifname}.{vif_id}'
340+
for vif_group in ['vif_remove', 'vif_s_remove']
341+
for vif_id in ethernet.get(vif_group, [])
342+
]
343+
344+
if not vlan_names:
345+
return
346+
347+
vpp_flat = dict_to_paths_values(ethernet.get('vpp', {}))
348+
349+
candidate_keys = []
350+
for key, value in vpp_flat.items():
351+
# Normalize values to list for consistent processing
352+
values = value if isinstance(value, list) else [value]
353+
if any(vlan in values for vlan in vlan_names):
354+
candidate_keys.append((key, values))
355+
356+
if not candidate_keys:
357+
return
358+
359+
for key, values in candidate_keys:
360+
if vpp_paths_pattern.fullmatch(key):
361+
used_vlans = [v for v in vlan_names if v in values]
362+
if used_vlans:
363+
raise ConfigError(
364+
f'Cannot delete interface "{used_vlans[0]}", '
365+
f'it is still in use by "vpp {key.replace(".", " ")}"'
366+
)
367+
310368
def verify(ethernet):
311369
verify_flowtable(ethernet)
370+
verify_vpp_remove_vif(ethernet)
312371

313372
if 'deleted' in ethernet:
314373
return None

0 commit comments

Comments
 (0)