summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/config-mode-dependencies/vyos-vpp.json3
-rw-r--r--python/vyos/vpp/nat/det44.py22
-rwxr-xr-xsmoketest/scripts/cli/test_vpp.py46
-rwxr-xr-xsrc/conf_mode/vpp.py5
-rw-r--r--src/conf_mode/vpp_kernel-interfaces.py6
-rw-r--r--src/conf_mode/vpp_nat_cgnat.py43
6 files changed, 102 insertions, 23 deletions
diff --git a/data/config-mode-dependencies/vyos-vpp.json b/data/config-mode-dependencies/vyos-vpp.json
index 4729ae95c..eac0f56d6 100644
--- a/data/config-mode-dependencies/vyos-vpp.json
+++ b/data/config-mode-dependencies/vyos-vpp.json
@@ -65,6 +65,9 @@
"vpp_nat": ["vpp_nat"],
"vpp_nat_cgnat": ["vpp_nat_cgnat"],
"vpp_kernel_interface": ["vpp_kernel-interfaces"]
+ },
+ "vpp_kernel_interfaces": {
+ "vpp_nat_cgnat": ["vpp_nat_cgnat"]
}
}
diff --git a/python/vyos/vpp/nat/det44.py b/python/vyos/vpp/nat/det44.py
index 70f903086..51ad41dc8 100644
--- a/python/vyos/vpp/nat/det44.py
+++ b/python/vyos/vpp/nat/det44.py
@@ -44,10 +44,10 @@ class Det44:
is_add=True,
)
- def delete_det44_interface_outside(self, interface_out):
+ def delete_det44_interface_outside(self, interface_out_index):
"""Delete DET44 outside interface"""
self.vpp.api.det44_interface_add_del_feature(
- sw_if_index=self.vpp.get_sw_if_index(interface_out),
+ sw_if_index=interface_out_index,
is_inside=False,
is_add=False,
)
@@ -60,10 +60,10 @@ class Det44:
is_add=True,
)
- def delete_det44_interface_inside(self, interface_in):
+ def delete_det44_interface_inside(self, interface_in_index):
"""Delete DET44 inside interface"""
self.vpp.api.det44_interface_add_del_feature(
- sw_if_index=self.vpp.get_sw_if_index(interface_in),
+ sw_if_index=interface_in_index,
is_inside=True,
is_add=False,
)
@@ -104,3 +104,17 @@ class Det44:
tcp_established=tcp_established,
tcp_transitory=tcp_transitory,
)
+
+ def get_det44_interfaces_outside(self):
+ ifaces_outside = []
+ for iface in self.vpp.api.det44_interface_dump():
+ if iface.is_outside:
+ ifaces_outside.append(iface.sw_if_index)
+ return ifaces_outside
+
+ def get_det44_interfaces_inside(self):
+ ifaces_inside = []
+ for iface in self.vpp.api.det44_interface_dump():
+ if iface.is_inside:
+ ifaces_inside.append(iface.sw_if_index)
+ return ifaces_inside
diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py
index 37485bd0d..5a42538c6 100755
--- a/smoketest/scripts/cli/test_vpp.py
+++ b/smoketest/scripts/cli/test_vpp.py
@@ -1256,7 +1256,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
config = read_file(VPP_CONF)
self.assertIn('interface ipip', config)
- def test_15_vpp_cgnat(self):
+ def test_15_1_vpp_cgnat(self):
base_cgnat = base_path + ['nat', 'cgnat']
iface_out = 'eth0'
iface_inside = 'eth1'
@@ -1295,6 +1295,50 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'tcp transitory timeout: {timeout_tcp_trans}sec', out)
self.assertIn(f'icmp timeout: {timeout_icmp}sec', out)
+ def test_15_2_vpp_cgnat_bond_with_vifs(self):
+ base_cgnat = base_path + ['nat', 'cgnat']
+ base_kernel = base_path + ['kernel-interfaces']
+ base_bond = base_path + ['interfaces', 'bonding']
+ iface_kernel = 'vpptun0'
+ iface_bond = 'bond0'
+ vif_1 = '23'
+ vif_2 = '24'
+ iface_out = f'{iface_bond}.{vif_1}'
+ iface_inside = f'{iface_bond}.{vif_2}'
+ address_1 = '100.64.0.23/32'
+ address_2 = '192.0.2.1/32'
+
+ self.cli_set(base_bond + [iface_bond, 'kernel-interface', iface_kernel])
+ self.cli_set(base_bond + [iface_bond, 'member', 'interface', interface])
+
+ self.cli_set(base_kernel + [iface_kernel, 'vif', vif_1, 'address', address_1])
+ self.cli_set(base_kernel + [iface_kernel, 'vif', vif_2, 'address', address_2])
+
+ self.cli_set(base_cgnat + ['interface', 'inside', iface_inside])
+ self.cli_set(base_cgnat + ['interface', 'outside', iface_out])
+ self.cli_set(base_cgnat + ['rule', '100', 'inside-prefix', address_1])
+ self.cli_set(base_cgnat + ['rule', '100', 'outside-prefix', address_2])
+ self.cli_commit()
+
+ # Check interfaces
+ _, out = rc_cmd('sudo vppctl show det44 interfaces')
+ self.assertIn(f'BondEthernet0.{vif_2} in', out)
+ self.assertIn(f'BondEthernet0.{vif_1} out', out)
+
+ # Change bonding interface configuration
+ self.cli_set(base_bond + [iface_bond, 'mode', '802.3ad'])
+ self.cli_commit()
+
+ # Check interfaces
+ _, out = rc_cmd('sudo vppctl show det44 interfaces')
+ self.assertIn(f'BondEthernet0.{vif_2} in', out)
+ self.assertIn(f'BondEthernet0.{vif_1} out', out)
+
+ # Verify only expected interfaces are shown:
+ # header + inside + outside = 3 lines total
+ lines = out.split('\n')
+ self.assertTrue(len(lines) == 3)
+
def test_16_vpp_nat(self):
base_nat = base_path + ['nat44']
base_nat_settings = base_path + ['settings', 'nat44']
diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py
index 81502c0b4..2d8c17e4f 100755
--- a/src/conf_mode/vpp.py
+++ b/src/conf_mode/vpp.py
@@ -373,6 +373,11 @@ def get_config(config=None):
eth_ifaces_persist[iface]['bus_id'] = control_host.get_bus_name(iface)
eth_ifaces_persist[iface]['dev_id'] = control_host.get_dev_id(iface)
+ # kernel-interfaces dependency
+ if effective_config.get('kernel_interfaces'):
+ for iface in config.get('kernel_interfaces', {}):
+ set_dependents('vpp_kernel_interface', conf, iface)
+
# NAT dependency
if conf.exists(['vpp', 'nat44']):
set_dependents('vpp_nat', conf)
diff --git a/src/conf_mode/vpp_kernel-interfaces.py b/src/conf_mode/vpp_kernel-interfaces.py
index 85706094e..d10449eec 100644
--- a/src/conf_mode/vpp_kernel-interfaces.py
+++ b/src/conf_mode/vpp_kernel-interfaces.py
@@ -19,6 +19,7 @@
import os
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.configdict import leaf_node_changed
from vyos.configdict import node_changed
from vyos import ConfigError
@@ -79,6 +80,9 @@ def get_config(config=None) -> dict:
if vlans_removed:
config['vlans_removed'] = vlans_removed
+ if conf.exists(['vpp', 'nat', 'cgnat']):
+ set_dependents('vpp_nat_cgnat', conf)
+
config['ifname'] = ifname
return config
@@ -185,6 +189,8 @@ def apply(config):
lcp_name = vpp_control.lcp_pair_find(kernel_name=ifname).get('vpp_name_kernel')
vpp_control.iface_rxmode(lcp_name, rx_mode)
+ call_dependents()
+
return None
diff --git a/src/conf_mode/vpp_nat_cgnat.py b/src/conf_mode/vpp_nat_cgnat.py
index be2386ba2..56d11b5a1 100644
--- a/src/conf_mode/vpp_nat_cgnat.py
+++ b/src/conf_mode/vpp_nat_cgnat.py
@@ -23,6 +23,15 @@ from vyos.configdiff import Diff
from vyos.vpp.utils import cli_ifaces_list
from vyos.vpp.nat.det44 import Det44
+from vyos.vpp.control_vpp import VPPControl
+
+
+def _vpp_iface_name_transform(iface_name):
+ vpp_iface_name = iface_name
+ if vpp_iface_name.startswith('bond'):
+ # interface name in VPP is BondEthernetX
+ vpp_iface_name = vpp_iface_name.replace('bond', 'BondEthernet')
+ return vpp_iface_name
def get_config(config=None) -> dict:
@@ -120,16 +129,14 @@ def verify(config):
f'Please choose a side for: {", ".join(conflict_ifaces)} '
)
- for interface in config['interface']['inside']:
- if interface not in config['vpp_ifaces']:
- raise ConfigError(
- f'{interface} must be a VPP interface for inside CGNAT interface'
- )
- for interface in config['interface']['outside']:
- if interface not in config['vpp_ifaces']:
- raise ConfigError(
- f'{interface} must be a VPP interface for outside CGNAT interface'
- )
+ vpp = VPPControl()
+ for direction in ['inside', 'outside']:
+ for interface in config['interface'][direction]:
+ vpp_iface_name = _vpp_iface_name_transform(interface)
+ if vpp.get_sw_if_index(vpp_iface_name) is None:
+ raise ConfigError(
+ f'{interface} must be a VPP interface for {direction} CGNAT interface'
+ )
required_keys = {'outside_prefix', 'inside_prefix'}
for rule in config['rule']:
@@ -158,13 +165,11 @@ def apply(config):
if 'effective' in config:
remove_config = config.get('effective')
# Delete inside interfaces
- for interface in remove_config['interface']['inside']:
- if interface not in config.get('interface', {}).get('inside', []):
- cgnat.delete_det44_interface_inside(interface)
+ for interface in cgnat.get_det44_interfaces_inside():
+ cgnat.delete_det44_interface_inside(interface)
# Delete outside interfaces
- for interface in remove_config['interface']['outside']:
- if interface not in config.get('interface', {}).get('outside', []):
- cgnat.delete_det44_interface_outside(interface)
+ for interface in cgnat.get_det44_interfaces_outside():
+ cgnat.delete_det44_interface_outside(interface)
# Delete CGNAT rules
for rule in config['changed_rules']:
if rule in remove_config.get('rule', {}):
@@ -182,10 +187,12 @@ def apply(config):
cgnat.enable_det44_plugin()
# Add inside interfaces
for interface in config['interface']['inside']:
- cgnat.add_det44_interface_inside(interface)
+ vpp_iface_name = _vpp_iface_name_transform(interface)
+ cgnat.add_det44_interface_inside(vpp_iface_name)
# Add outside interfaces
for interface in config['interface']['outside']:
- cgnat.add_det44_interface_outside(interface)
+ vpp_iface_name = _vpp_iface_name_transform(interface)
+ cgnat.add_det44_interface_outside(vpp_iface_name)
# Add CGNAT rules
for rule in config['changed_rules']:
if rule in config.get('rule', {}):