summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/container.xml.in1
-rw-r--r--interface-definitions/include/version/qos-version.xml.i2
-rw-r--r--interface-definitions/qos.xml.in111
-rw-r--r--python/vyos/ifconfig/wireguard.py3
-rw-r--r--python/vyos/qos/cake.py47
-rwxr-xr-xsmoketest/scripts/cli/test_container.py16
-rwxr-xr-xsmoketest/scripts/cli/test_qos.py63
-rwxr-xr-xsrc/conf_mode/container.py6
-rwxr-xr-xsrc/conf_mode/interfaces_wireguard.py36
-rw-r--r--src/migration-scripts/qos/2-to-334
10 files changed, 217 insertions, 102 deletions
diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in
index 3dd1b3249..bd2ff820d 100644
--- a/interface-definitions/container.xml.in
+++ b/interface-definitions/container.xml.in
@@ -501,6 +501,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
+ #include <include/interface/mtu-68-16000.xml.i>
<leafNode name="prefix">
<properties>
<help>Prefix which allocated to that network</help>
diff --git a/interface-definitions/include/version/qos-version.xml.i b/interface-definitions/include/version/qos-version.xml.i
index c67e61e91..127f771a9 100644
--- a/interface-definitions/include/version/qos-version.xml.i
+++ b/interface-definitions/include/version/qos-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/qos-version.xml.i -->
-<syntaxVersion component='qos' version='2'></syntaxVersion>
+<syntaxVersion component='qos' version='3'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/qos.xml.in b/interface-definitions/qos.xml.in
index 907fd5e4c..c6ecb742e 100644
--- a/interface-definitions/qos.xml.in
+++ b/interface-definitions/qos.xml.in
@@ -85,78 +85,67 @@
<children>
#include <include/generic-description.xml.i>
#include <include/qos/bandwidth.xml.i>
- <node name="flow-isolation">
+ <leafNode name="flow-isolation">
<properties>
<help>Flow isolation settings</help>
+ <completionHelp>
+ <list>blind src-host dst-host host flow dual-src-host dual-dst-host triple-isolate</list>
+ </completionHelp>
+ <valueHelp>
+ <format>blind</format>
+ <description>Disables flow isolation, all traffic passes through a single queue</description>
+ </valueHelp>
+ <valueHelp>
+ <format>src-host</format>
+ <description>Flows are defined only by source address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dst-host</format>
+ <description>Flows are defined only by destination address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>host</format>
+ <description>Flows are defined by source-destination host pairs</description>
+ </valueHelp>
+ <valueHelp>
+ <format>flow</format>
+ <description>Flows are defined by the entire 5-tuple</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dual-src-host</format>
+ <description>Flows are defined by the 5-tuple, fairness is applied first over source addresses, then over individual flows</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dual-dst-host</format>
+ <description>Flows are defined by the 5-tuple, fairness is applied first over destination addresses, then over individual flows</description>
+ </valueHelp>
+ <valueHelp>
+ <format>triple-isolate</format>
+ <description>Flows are defined by the 5-tuple, fairness is applied over source and destination addresses and also over individual flows (default)</description>
+ </valueHelp>
+ <constraint>
+ <regex>(blind|src-host|dst-host|host|flow|dual-src-host|dual-dst-host|triple-isolate)</regex>
+ </constraint>
</properties>
- <children>
- <leafNode name="blind">
- <properties>
- <help>Disables flow isolation, all traffic passes through a single queue</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="src-host">
- <properties>
- <help>Flows are defined only by source address</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="dst-host">
- <properties>
- <help>Flows are defined only by destination address</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="host">
- <properties>
- <help>Flows are defined by source-destination host pairs</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="flow">
- <properties>
- <help>Flows are defined by the entire 5-tuple</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="dual-src-host">
- <properties>
- <help>Flows are defined by the 5-tuple, fairness is applied first over source addresses, then over individual flows</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="dual-dst-host">
- <properties>
- <help>Flows are defined by the 5-tuple, fairness is applied first over destination addresses, then over individual flows</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="triple-isolate">
- <properties>
- <help>Flows are defined by the 5-tuple, fairness is applied over source and destination addresses and also over individual flows (default)</help>
- <valueless/>
- </properties>
- </leafNode>
- <leafNode name="nat">
- <properties>
- <help>Perform NAT lookup before applying flow-isolation rules</help>
- <valueless/>
- </properties>
- </leafNode>
- </children>
- </node>
+ <defaultValue>triple-isolate</defaultValue>
+ </leafNode>
+ <leafNode name="flow-isolation-nat">
+ <properties>
+ <help>Perform NAT lookup before applying flow-isolation rules</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="rtt">
<properties>
<help>Round-Trip-Time for Active Queue Management (AQM)</help>
<valueHelp>
- <format>u32:1-3600000</format>
+ <format>u32:1-1000000000</format>
<description>RTT in ms</description>
</valueHelp>
<constraint>
- <validator name="numeric" argument="--range 1-3600000"/>
+ <validator name="numeric" argument="--range 1-1000000000"/>
</constraint>
- <constraintErrorMessage>RTT must be in range 1 to 3600000 milli-seconds</constraintErrorMessage>
+ <constraintErrorMessage>RTT must be in range 1 to 1000000000 milli-seconds</constraintErrorMessage>
</properties>
<defaultValue>100</defaultValue>
</leafNode>
diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py
index 9030b1302..cccac361d 100644
--- a/python/vyos/ifconfig/wireguard.py
+++ b/python/vyos/ifconfig/wireguard.py
@@ -195,6 +195,9 @@ class WireGuardIf(Interface):
base_cmd += f' private-key {tmp_file.name}'
base_cmd = base_cmd.format(**config)
+ # T6490: execute command to ensure interface configured
+ self._cmd(base_cmd)
+
if 'peer' in config:
for peer, peer_config in config['peer'].items():
# T4702: No need to configure this peer when it was explicitly
diff --git a/python/vyos/qos/cake.py b/python/vyos/qos/cake.py
index 1ee7d0fc3..ca5a26917 100644
--- a/python/vyos/qos/cake.py
+++ b/python/vyos/qos/cake.py
@@ -15,10 +15,25 @@
from vyos.qos.base import QoSBase
+
class CAKE(QoSBase):
+ """
+ https://man7.org/linux/man-pages/man8/tc-cake.8.html
+ """
+
_direction = ['egress']
- # https://man7.org/linux/man-pages/man8/tc-cake.8.html
+ flow_isolation_map = {
+ 'blind': 'flowblind',
+ 'src-host': 'srchost',
+ 'dst-host': 'dsthost',
+ 'dual-dst-host': 'dual-dsthost',
+ 'dual-src-host': 'dual-srchost',
+ 'triple-isolate': 'triple-isolate',
+ 'flow': 'flows',
+ 'host': 'hosts',
+ }
+
def update(self, config, direction):
tmp = f'tc qdisc add dev {self._interface} root handle 1: cake {direction}'
if 'bandwidth' in config:
@@ -30,26 +45,16 @@ class CAKE(QoSBase):
tmp += f' rtt {rtt}ms'
if 'flow_isolation' in config:
- if 'blind' in config['flow_isolation']:
- tmp += f' flowblind'
- if 'dst_host' in config['flow_isolation']:
- tmp += f' dsthost'
- if 'dual_dst_host' in config['flow_isolation']:
- tmp += f' dual-dsthost'
- if 'dual_src_host' in config['flow_isolation']:
- tmp += f' dual-srchost'
- if 'triple_isolate' in config['flow_isolation']:
- tmp += f' triple-isolate'
- if 'flow' in config['flow_isolation']:
- tmp += f' flows'
- if 'host' in config['flow_isolation']:
- tmp += f' hosts'
- if 'nat' in config['flow_isolation']:
- tmp += f' nat'
- if 'src_host' in config['flow_isolation']:
- tmp += f' srchost '
- else:
- tmp += f' nonat'
+ isolation_value = self.flow_isolation_map.get(config['flow_isolation'])
+
+ if isolation_value is not None:
+ tmp += f' {isolation_value}'
+ else:
+ raise ValueError(
+ f'Invalid flow isolation parameter: {config["flow_isolation"]}'
+ )
+
+ tmp += ' nat' if 'flow_isolation_nat' in config else ' nonat'
self._cmd(tmp)
diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py
index c03b9eb44..0541384da 100755
--- a/smoketest/scripts/cli/test_container.py
+++ b/smoketest/scripts/cli/test_container.py
@@ -224,6 +224,22 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
n = cmd_to_json(f'sudo podman network inspect {net_name}')
self.assertEqual(n['dns_enabled'], False)
+ def test_network_mtu(self):
+ prefix = '192.0.2.0/24'
+ base_name = 'ipv4'
+ net_name = 'NET01'
+
+ self.cli_set(base_path + ['network', net_name, 'prefix', prefix])
+ self.cli_set(base_path + ['network', net_name, 'mtu', '1280'])
+
+ name = f'{base_name}-2'
+ self.cli_set(base_path + ['name', name, 'image', cont_image])
+ self.cli_set(base_path + ['name', name, 'network', net_name, 'address', str(ip_interface(prefix).ip + 2)])
+ self.cli_commit()
+
+ n = cmd_to_json(f'sudo podman network inspect {net_name}')
+ self.assertEqual(n['options']['mtu'], '1280')
+
def test_uid_gid(self):
cont_name = 'uid-test'
gid = '100'
diff --git a/smoketest/scripts/cli/test_qos.py b/smoketest/scripts/cli/test_qos.py
index aaeebcdae..9c3e848cd 100755
--- a/smoketest/scripts/cli/test_qos.py
+++ b/smoketest/scripts/cli/test_qos.py
@@ -22,6 +22,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
+from vyos.qos import CAKE
from vyos.utils.process import cmd
base_path = ['qos']
@@ -871,6 +872,68 @@ class TestQoS(VyOSUnitTestSHIM.TestCase):
self.cli_set(['qos', 'traffic-match-group', '3', 'match-group', 'unexpected'])
self.cli_commit()
+ def test_17_cake_updates(self):
+ bandwidth = 1000000
+ rtt = 200
+ interface = self._interfaces[0]
+ policy_name = f'qos-policy-{interface}'
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(
+ base_path + ['policy', 'cake', policy_name, 'bandwidth', str(bandwidth)]
+ )
+ self.cli_set(base_path + ['policy', 'cake', policy_name, 'rtt', str(rtt)])
+
+ # commit changes
+ self.cli_commit()
+
+ tmp = get_tc_qdisc_json(interface)
+
+ self.assertEqual('cake', tmp['kind'])
+ # TC store rates as a 32-bit unsigned integer in bps (Bytes per second)
+ self.assertEqual(int(bandwidth * 125), tmp['options']['bandwidth'])
+ # RTT internally is in us
+ self.assertEqual(int(rtt * 1000), tmp['options']['rtt'])
+ self.assertEqual('triple-isolate', tmp['options']['flowmode'])
+ self.assertFalse(tmp['options']['ingress'])
+ self.assertFalse(tmp['options']['nat'])
+ self.assertTrue(tmp['options']['raw'])
+
+ nat = True
+ for flow_isolation in [
+ 'blind',
+ 'src-host',
+ 'dst-host',
+ 'dual-dst-host',
+ 'dual-src-host',
+ 'triple-isolate',
+ 'flow',
+ 'host',
+ ]:
+ self.cli_set(
+ base_path
+ + ['policy', 'cake', policy_name, 'flow-isolation', flow_isolation]
+ )
+
+ if nat:
+ self.cli_set(
+ base_path + ['policy', 'cake', policy_name, 'flow-isolation-nat']
+ )
+ else:
+ self.cli_delete(
+ base_path + ['policy', 'cake', policy_name, 'flow-isolation-nat']
+ )
+
+ self.cli_commit()
+
+ tmp = get_tc_qdisc_json(interface)
+ self.assertEqual(
+ CAKE.flow_isolation_map.get(flow_isolation), tmp['options']['flowmode']
+ )
+
+ self.assertEqual(nat, tmp['options']['nat'])
+ nat = not nat
+
def test_20_round_robin_policy_default(self):
interface = self._interfaces[0]
policy_name = f'qos-policy-{interface}'
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index 14387cbbf..a7dc33d9d 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -419,12 +419,18 @@ def generate(container):
'dns_enabled': True,
'ipam_options': {
'driver': 'host-local'
+ },
+ 'options': {
+ 'mtu': '1500'
}
}
if 'no_name_server' in network_config:
tmp['dns_enabled'] = False
+ if 'mtu' in network_config:
+ tmp['options']['mtu'] = network_config['mtu']
+
for prefix in network_config['prefix']:
net = {'subnet': prefix, 'gateway': inc_ip(prefix, 1)}
tmp['subnets'].append(net)
diff --git a/src/conf_mode/interfaces_wireguard.py b/src/conf_mode/interfaces_wireguard.py
index 7abdfdbfa..b6fd6b0b2 100755
--- a/src/conf_mode/interfaces_wireguard.py
+++ b/src/conf_mode/interfaces_wireguard.py
@@ -70,9 +70,6 @@ def verify(wireguard):
if 'private_key' not in wireguard:
raise ConfigError('Wireguard private-key not defined')
- if 'peer' not in wireguard:
- raise ConfigError('At least one Wireguard peer is required!')
-
if 'port' in wireguard and 'port_changed' in wireguard:
listen_port = int(wireguard['port'])
if check_port_availability('0.0.0.0', listen_port, 'udp') is not True:
@@ -80,28 +77,29 @@ def verify(wireguard):
'cannot be used for the interface!')
# run checks on individual configured WireGuard peer
- public_keys = []
- for tmp in wireguard['peer']:
- peer = wireguard['peer'][tmp]
+ if 'peer' in wireguard:
+ public_keys = []
+ for tmp in wireguard['peer']:
+ peer = wireguard['peer'][tmp]
- if 'allowed_ips' not in peer:
- raise ConfigError(f'Wireguard allowed-ips required for peer "{tmp}"!')
+ if 'allowed_ips' not in peer:
+ raise ConfigError(f'Wireguard allowed-ips required for peer "{tmp}"!')
- if 'public_key' not in peer:
- raise ConfigError(f'Wireguard public-key required for peer "{tmp}"!')
+ if 'public_key' not in peer:
+ raise ConfigError(f'Wireguard public-key required for peer "{tmp}"!')
- if ('address' in peer and 'port' not in peer) or ('port' in peer and 'address' not in peer):
- raise ConfigError('Both Wireguard port and address must be defined '
- f'for peer "{tmp}" if either one of them is set!')
+ if ('address' in peer and 'port' not in peer) or ('port' in peer and 'address' not in peer):
+ raise ConfigError('Both Wireguard port and address must be defined '
+ f'for peer "{tmp}" if either one of them is set!')
- if peer['public_key'] in public_keys:
- raise ConfigError(f'Duplicate public-key defined on peer "{tmp}"')
+ if peer['public_key'] in public_keys:
+ raise ConfigError(f'Duplicate public-key defined on peer "{tmp}"')
- if 'disable' not in peer:
- if is_wireguard_key_pair(wireguard['private_key'], peer['public_key']):
- raise ConfigError(f'Peer "{tmp}" has the same public key as the interface "{wireguard["ifname"]}"')
+ if 'disable' not in peer:
+ if is_wireguard_key_pair(wireguard['private_key'], peer['public_key']):
+ raise ConfigError(f'Peer "{tmp}" has the same public key as the interface "{wireguard["ifname"]}"')
- public_keys.append(peer['public_key'])
+ public_keys.append(peer['public_key'])
def generate(wireguard):
return None
diff --git a/src/migration-scripts/qos/2-to-3 b/src/migration-scripts/qos/2-to-3
new file mode 100644
index 000000000..284fe828e
--- /dev/null
+++ b/src/migration-scripts/qos/2-to-3
@@ -0,0 +1,34 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+from vyos.configtree import ConfigTree
+
+
+def migrate(config: ConfigTree) -> None:
+ base = ['qos', 'policy', 'cake']
+ if config.exists(base):
+ for policy in config.list_nodes(base):
+ if config.exists(base + [policy, 'flow-isolation']):
+ isolation = None
+ for isol in config.list_nodes(base + [policy, 'flow-isolation']):
+ if isol == 'nat':
+ config.set(base + [policy, 'flow-isolation-nat'])
+ else:
+ isolation = isol
+
+ config.delete(base + [policy, 'flow-isolation'])
+
+ if isolation:
+ config.set(base + [policy, 'flow-isolation'], value=isolation)