summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNataliia S. <81954790+natali-rs1985@users.noreply.github.com>2025-11-14 11:07:30 +0200
committerGitHub <noreply@github.com>2025-11-14 11:07:30 +0200
commit0447d71a7c77890bbedb105f28fb6ebc067b7778 (patch)
tree0bf170c1f749c60bbb319e88862d1fc9d6a0c915 /src
parentcd958a476099943c87284aa4fa9c00c48f33266c (diff)
parentdb494bc47c9bf2bba363b6b598e475bccdd4c8e6 (diff)
downloadvyos-1x-0447d71a7c77890bbedb105f28fb6ebc067b7778.tar.gz
vyos-1x-0447d71a7c77890bbedb105f28fb6ebc067b7778.zip
Merge pull request #4830 from natali-rs1985/T7950
T7950: VPP: Unexpected None interface in CGNAT when ethernet subinterace is removed from vif
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/interfaces_ethernet.py59
1 files changed, 59 insertions, 0 deletions
diff --git a/src/conf_mode/interfaces_ethernet.py b/src/conf_mode/interfaces_ethernet.py
index 14bda1b3d..edcc6563c 100755
--- a/src/conf_mode/interfaces_ethernet.py
+++ b/src/conf_mode/interfaces_ethernet.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
+import re
from sys import exit
@@ -173,6 +174,13 @@ def get_config(config=None):
ethernet['flowtable_interfaces'] = get_flowtable_interfaces(conf)
+ ethernet['vpp'] = conf.get_config_dict(
+ ['vpp'],
+ key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True,
+ )
+
# Protocols static arp dependency
if 'static_arp' in ethernet:
set_dependents('static_arp', conf)
@@ -307,8 +315,59 @@ def verify_flowtable(ethernet: dict):
if vifcname in ethernet['flowtable_interfaces']:
raise ConfigError(f'Cannot delete interface "{vifcname}", still referenced on a flowtable')
+def verify_vpp_remove_vif(ethernet: dict):
+ """Ensure that VIF interfaces being removed are not used by VPP features"""
+ vpp_paths_pattern = re.compile(
+ # Known paths that already use VLAN interfaces
+ r'(nat\.cgnat\.interface\.inside)|'
+ r'(nat\.cgnat\.interface\.outside)|'
+ r'(nat44\.interface\.inside)|'
+ r'(nat44\.interface\.outside)|'
+ # Potential paths for VLAN interfaces
+ r'(nat44\.address_pool\.translation\.interface)|'
+ r'(nat44\.address_pool\.twice_nat\.interface)|'
+ r'(nat44\.exclude\.rule\.(\d)+\.external_interface)|'
+ r'(interfaces\.bonding\.bond(\d)+\.member\.interface)|'
+ r'(interfaces\.bridge\.br(\d)+\.member\.interface)|'
+ r'(interfaces\.xconnect\.xcon(\d)+\.member\.interface)|'
+ r'(acl\.ip\.interface)|'
+ r'(acl\.macip\.interface)'
+ )
+ ifname = ethernet['ifname']
+
+ vlan_names = [
+ f'{ifname}.{vif_id}'
+ for vif_group in ['vif_remove', 'vif_s_remove']
+ for vif_id in ethernet.get(vif_group, [])
+ ]
+
+ if not vlan_names:
+ return
+
+ vpp_flat = dict_to_paths_values(ethernet.get('vpp', {}))
+
+ candidate_keys = []
+ for key, value in vpp_flat.items():
+ # Normalize values to list for consistent processing
+ values = value if isinstance(value, list) else [value]
+ if any(vlan in values for vlan in vlan_names):
+ candidate_keys.append((key, values))
+
+ if not candidate_keys:
+ return
+
+ for key, values in candidate_keys:
+ if vpp_paths_pattern.fullmatch(key):
+ used_vlans = [v for v in vlan_names if v in values]
+ if used_vlans:
+ raise ConfigError(
+ f'Cannot delete interface "{used_vlans[0]}", '
+ f'it is still in use by "vpp {key.replace(".", " ")}"'
+ )
+
def verify(ethernet):
verify_flowtable(ethernet)
+ verify_vpp_remove_vif(ethernet)
if 'deleted' in ethernet:
return None