Skip to content

Commit

Permalink
Merge branch 'current' into T3202-current
Browse files Browse the repository at this point in the history
  • Loading branch information
natali-rs1985 committed Jun 20, 2024
2 parents 2663b99 + 109e094 commit b9ec469
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 42 deletions.
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ vyshim:
$(MAKE) -C $(SHIM_DIR)

.PHONY: all
all: clean interface_definitions op_mode_definitions check test j2lint vyshim
all: clean interface_definitions op_mode_definitions check test j2lint vyshim check_migration_scripts_executable

.PHONY: check
.ONESHELL:
Expand All @@ -103,6 +103,12 @@ test:
set -e; python3 -m compileall -q -x '/vmware-tools/scripts/, /ppp/' .
PYTHONPATH=python/ python3 -m "nose" --with-xunit src --with-coverage --cover-erase --cover-xml --cover-package src/conf_mode,src/op_mode,src/completion,src/helpers,src/validators,src/tests --verbose

.PHONY: check_migration_scripts_executable
.ONESHELL:
check_migration_scripts_executable:
@echo "Checking if migration scripts have executable bit set..."
find src/migration-scripts -type f -not -executable -print -exec false {} + || sh -c 'echo "Found files that are not executable! Add permissions." && exit 1'

.PHONY: j2lint
j2lint:
ifndef J2LINT
Expand Down
5 changes: 5 additions & 0 deletions data/templates/system/40_usb_autosuspend.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% set autosuspend = "auto" %}
{% if disable_usb_autosuspend is vyos_defined %}
{% set autosuspend = "on" %}
{% endif %}
ACTION=="add", SUBSYSTEM=="usb", TEST=="power/control", ATTR{power/control}="{{ autosuspend }}"
32 changes: 17 additions & 15 deletions data/templates/wifi/hostapd.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -383,23 +383,25 @@ vht_oper_chwidth={{ capabilities.vht.channel_set_width }}
{% for short_gi in capabilities.vht.short_gi if capabilities.vht.short_gi is vyos_defined %}
{% set output.value = output.value ~ '[SHORT-GI-' ~ short_gi | upper ~ ']' %}
{% endfor %}
{% for beamform in capabilities.vht.beamform if capabilities.vht.beamform is vyos_defined %}
{% set output.value = output.value ~ '[SU-BEAMFORMER]' if beamform is vyos_defined('single-user-beamformer') else '' %}
{% set output.value = output.value ~ '[SU-BEAMFORMEE]' if beamform is vyos_defined('single-user-beamformee') else '' %}
{% set output.value = output.value ~ '[MU-BEAMFORMER]' if beamform is vyos_defined('multi-user-beamformer') else '' %}
{% set output.value = output.value ~ '[MU-BEAMFORMEE]' if beamform is vyos_defined('multi-user-beamformee') else '' %}
{% endfor %}
{% if capabilities.vht.antenna_count is vyos_defined and capabilities.vht.antenna_count | int > 1 %}
{% if capabilities.vht.beamform is vyos_defined %}
{% if capabilities.vht.beamform == 'single-user-beamformer' %}
{% if capabilities.vht.beamform is vyos_defined %}
{% for bf in capabilities.vht.beamform %}
{% set output.value = output.value ~ '[SU-BEAMFORMER]' if bf is vyos_defined('single-user-beamformer') else output.value %}
{% set output.value = output.value ~ '[SU-BEAMFORMEE]' if bf is vyos_defined('single-user-beamformee') else output.value %}
{% set output.value = output.value ~ '[MU-BEAMFORMER]' if bf is vyos_defined('multi-user-beamformer') else output.value %}
{% set output.value = output.value ~ '[MU-BEAMFORMEE]' if bf is vyos_defined('multi-user-beamformee') else output.value %}
{% endfor %}
{% if capabilities.vht.antenna_count is vyos_defined and capabilities.vht.antenna_count | int > 1 %}
{% if 'single-user-beamformer' in capabilities.vht.beamform %}
{% if capabilities.vht.antenna_count is vyos_defined and capabilities.vht.antenna_count | int > 1 and capabilities.vht.antenna_count | int < 6 %}
{% set output.value = output.value ~ '[BF-ANTENNA-' ~ capabilities.vht.antenna_count | int -1 ~ ']' %}
{% set output.value = output.value ~ '[SOUNDING-DIMENSION-' ~ capabilities.vht.antenna_count | int -1 ~ ']' %}
{% set dimension = capabilities.vht.antenna_count | int - 1 %}
{% set output.value = output.value ~ '[BF-ANTENNA-' ~ dimension ~ ']' %}
{% set output.value = output.value ~ '[SOUNDING-DIMENSION-' ~ dimension ~ ']' %}
{% endif %}
{% else %}
{% if capabilities.vht.antenna_count is vyos_defined and capabilities.vht.antenna_count | int > 1 and capabilities.vht.antenna_count | int < 5 %}
{% set output.value = output.value ~ '[BF-ANTENNA-' ~ capabilities.vht.antenna_count ~ ']' %}
{% set output.value = output.value ~ '[SOUNDING-DIMENSION-' ~ capabilities.vht.antenna_count ~ ']' %}
{% endif %}
{% endif %}
{% if capabilities.vht.antenna_count is vyos_defined and capabilities.vht.antenna_count | int > 1 and capabilities.vht.antenna_count | int < 5 %}
{% set output.value = output.value ~ '[BF-ANTENNA-' ~ capabilities.vht.antenna_count ~ ']' %}
{% set output.value = output.value ~ '[SOUNDING-DIMENSION-' ~ capabilities.vht.antenna_count ~ ']' %}
{% endif %}
{% endif %}
{% endif %}
Expand Down
6 changes: 6 additions & 0 deletions interface-definitions/system_option.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@
</properties>
<defaultValue>12-hour</defaultValue>
</leafNode>
<leafNode name="disable-usb-autosuspend">
<properties>
<help>Disable autosuspend for all USB devices</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
</children>
Expand Down
2 changes: 1 addition & 1 deletion interface-definitions/vpn_openconnect.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@
<help>SSL Certificate, SSL Key and CA</help>
</properties>
<children>
#include <include/pki/ca-certificate.xml.i>
#include <include/pki/ca-certificate-multi.xml.i>
#include <include/pki/certificate-key.xml.i>
</children>
</node>
Expand Down
2 changes: 1 addition & 1 deletion python/vyos/ifconfig/macsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _create(self):
cmd = 'ip macsec add {ifname} rx port 1 address'.format(**self.config)
cmd += f' {peer_config["mac"]}'
self._cmd(cmd)
# Add the rx-key to the address
# Add the encryption key to the address
cmd += f' sa 0 pn 1 on key 01 {peer_config["key"]}'
self._cmd(cmd)

Expand Down
8 changes: 4 additions & 4 deletions smoketest/scripts/cli/test_interfaces_macsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,11 @@ def test_macsec_static_keys(self):
self.cli_commit()
self.cli_delete(self._base_path + [interface, 'security', 'mka'])

# check validate() - tx-key required
# check validate() - key required
with self.assertRaises(ConfigSessionError):
self.cli_commit()

# check validate() - tx-key length must match cipher
# check validate() - key length must match cipher
self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_2])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
Expand All @@ -239,7 +239,7 @@ def test_macsec_static_keys(self):
with self.assertRaises(ConfigSessionError):
self.cli_commit()

# check validate() - enabled peer must have both rx-key and MAC defined
# check validate() - enabled peer must have both key and MAC defined
self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
Expand All @@ -252,7 +252,7 @@ def test_macsec_static_keys(self):
self.cli_commit()
self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'mac', peer_mac])

# check validate() - peer rx-key length must match cipher
# check validate() - peer key length must match cipher
self.cli_set(self._base_path + [interface, 'security', 'cipher', cipher2])
self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_2])
with self.assertRaises(ConfigSessionError):
Expand Down
140 changes: 139 additions & 1 deletion smoketest/scripts/cli/test_interfaces_wireless.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
# Copyright (C) 2020-2023 VyOS maintainers and contributors
# Copyright (C) 2020-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
Expand Down Expand Up @@ -159,6 +159,144 @@ def test_wireless_hostapd_config(self):
# Check for running process
self.assertTrue(process_named_running('hostapd'))

def test_wireless_hostapd_vht_mu_beamformer_config(self):
# Multi-User-Beamformer
interface = 'wlan1'
ssid = 'vht_mu-beamformer'
antennas = '3'

self.cli_set(self._base_path + [interface, 'ssid', ssid])
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
self.cli_set(self._base_path + [interface, 'channel', '36'])

ht_opt = {
# VyOS CLI option hostapd - ht_capab setting
'channel-set-width ht20' : '[HT20]',
'channel-set-width ht40-' : '[HT40-]',
'channel-set-width ht40+' : '[HT40+]',
'dsss-cck-40' : '[DSSS_CCK-40]',
'short-gi 20' : '[SHORT-GI-20]',
'short-gi 40' : '[SHORT-GI-40]',
'max-amsdu 7935' : '[MAX-AMSDU-7935]',
}
for key in ht_opt:
self.cli_set(self._base_path + [interface, 'capabilities', 'ht'] + key.split())

vht_opt = {
# VyOS CLI option hostapd - ht_capab setting
'max-mpdu 11454' : '[MAX-MPDU-11454]',
'max-mpdu-exp 2' : '[MAX-A-MPDU-LEN-EXP-2]',
'stbc tx' : '[TX-STBC-2BY1]',
'stbc rx 12' : '[RX-STBC-12]',
'ldpc' : '[RXLDPC]',
'tx-powersave' : '[VHT-TXOP-PS]',
'vht-cf' : '[HTC-VHT]',
'antenna-pattern-fixed' : '[RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]',
'link-adaptation both' : '[VHT-LINK-ADAPT3]',
'short-gi 80' : '[SHORT-GI-80]',
'short-gi 160' : '[SHORT-GI-160]',
'beamform multi-user-beamformer' : '[MU-BEAMFORMER][BF-ANTENNA-3][SOUNDING-DIMENSION-3]',
}

self.cli_set(self._base_path + [interface, 'capabilities', 'vht', 'channel-set-width', '1'])
self.cli_set(self._base_path + [interface, 'capabilities', 'vht', 'center-channel-freq', 'freq-1', '42'])
self.cli_set(self._base_path + [interface, 'capabilities', 'vht', 'antenna-count', antennas])
for key in vht_opt:
self.cli_set(self._base_path + [interface, 'capabilities', 'vht'] + key.split())

self.cli_commit()

#
# Validate Config
#
tmp = get_config_value(interface, 'interface')
self.assertEqual(interface, tmp)

# ssid
tmp = get_config_value(interface, 'ssid')
self.assertEqual(ssid, tmp)

# channel
tmp = get_config_value(interface, 'channel')
self.assertEqual('36', tmp)

tmp = get_config_value(interface, 'ht_capab')
for key, value in ht_opt.items():
self.assertIn(value, tmp)

tmp = get_config_value(interface, 'vht_capab')
for key, value in vht_opt.items():
self.assertIn(value, tmp)

def test_wireless_hostapd_vht_su_beamformer_config(self):
# Single-User-Beamformer
interface = 'wlan1'
ssid = 'vht_su-beamformer'
antennas = '3'

self.cli_set(self._base_path + [interface, 'ssid', ssid])
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
self.cli_set(self._base_path + [interface, 'channel', '36'])

ht_opt = {
# VyOS CLI option hostapd - ht_capab setting
'channel-set-width ht20' : '[HT20]',
'channel-set-width ht40-' : '[HT40-]',
'channel-set-width ht40+' : '[HT40+]',
'dsss-cck-40' : '[DSSS_CCK-40]',
'short-gi 20' : '[SHORT-GI-20]',
'short-gi 40' : '[SHORT-GI-40]',
'max-amsdu 7935' : '[MAX-AMSDU-7935]',
}
for key in ht_opt:
self.cli_set(self._base_path + [interface, 'capabilities', 'ht'] + key.split())

vht_opt = {
# VyOS CLI option hostapd - ht_capab setting
'max-mpdu 11454' : '[MAX-MPDU-11454]',
'max-mpdu-exp 2' : '[MAX-A-MPDU-LEN-EXP-2]',
'stbc tx' : '[TX-STBC-2BY1]',
'stbc rx 12' : '[RX-STBC-12]',
'ldpc' : '[RXLDPC]',
'tx-powersave' : '[VHT-TXOP-PS]',
'vht-cf' : '[HTC-VHT]',
'antenna-pattern-fixed' : '[RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]',
'link-adaptation both' : '[VHT-LINK-ADAPT3]',
'short-gi 80' : '[SHORT-GI-80]',
'short-gi 160' : '[SHORT-GI-160]',
'beamform single-user-beamformer' : '[SU-BEAMFORMER][BF-ANTENNA-2][SOUNDING-DIMENSION-2]',
}

self.cli_set(self._base_path + [interface, 'capabilities', 'vht', 'channel-set-width', '1'])
self.cli_set(self._base_path + [interface, 'capabilities', 'vht', 'center-channel-freq', 'freq-1', '42'])
self.cli_set(self._base_path + [interface, 'capabilities', 'vht', 'antenna-count', antennas])
for key in vht_opt:
self.cli_set(self._base_path + [interface, 'capabilities', 'vht'] + key.split())

self.cli_commit()

#
# Validate Config
#
tmp = get_config_value(interface, 'interface')
self.assertEqual(interface, tmp)

# ssid
tmp = get_config_value(interface, 'ssid')
self.assertEqual(ssid, tmp)

# channel
tmp = get_config_value(interface, 'channel')
self.assertEqual('36', tmp)

tmp = get_config_value(interface, 'ht_capab')
for key, value in ht_opt.items():
self.assertIn(value, tmp)

tmp = get_config_value(interface, 'vht_capab')
for key, value in vht_opt.items():
self.assertIn(value, tmp)

def test_wireless_hostapd_wpa_config(self):
# Only set the hostapd (access-point) options
interface = 'wlan0'
Expand Down
10 changes: 5 additions & 5 deletions src/conf_mode/interfaces_macsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ def verify(macsec):

# Logic to check static configuration
if dict_search('security.static', macsec) != None:
# tx-key must be defined
# key must be defined
if dict_search('security.static.key', macsec) == None:
raise ConfigError('Static MACsec tx-key must be defined.')
raise ConfigError('Static MACsec key must be defined.')

tx_len = len(dict_search('security.static.key', macsec))

Expand All @@ -119,12 +119,12 @@ def verify(macsec):
if 'peer' not in macsec['security']['static']:
raise ConfigError('Must have at least one peer defined for static MACsec')

# For every enabled peer, make sure a MAC and rx-key is defined
# For every enabled peer, make sure a MAC and key is defined
for peer, peer_config in macsec['security']['static']['peer'].items():
if 'disable' not in peer_config and ('mac' not in peer_config or 'key' not in peer_config):
raise ConfigError('Every enabled MACsec static peer must have a MAC address and rx-key defined.')
raise ConfigError('Every enabled MACsec static peer must have a MAC address and key defined!')

# check rx-key length against cipher suite
# check key length against cipher suite
rx_len = len(peer_config['key'])

if dict_search('security.cipher', macsec) == 'gcm-aes-128' and rx_len != GCM_AES_128_LEN:
Expand Down
51 changes: 51 additions & 0 deletions src/conf_mode/nat_cgnat.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from logging.handlers import SysLogHandler

from vyos.config import Config
from vyos.configdict import is_node_changed
from vyos.template import render
from vyos.utils.process import cmd
from vyos.utils.process import run
Expand Down Expand Up @@ -118,6 +119,41 @@ def convert_prefix_to_list_ips(self) -> list:
+ [self.ip_network.broadcast_address]
]

def get_prefix_by_ip_range(self):
"""Return the common prefix for the address range
Example:
% ip = IPOperations('100.64.0.1-100.64.0.5')
% ip.get_prefix_by_ip_range()
100.64.0.0/29
"""
if '-' in self.ip_prefix:
ip_start, ip_end = self.ip_prefix.split('-')
start_ip = ipaddress.IPv4Address(ip_start.strip())
end_ip = ipaddress.IPv4Address(ip_end.strip())

start_int = int(start_ip)
end_int = int(end_ip)

# XOR to find differing bits
xor = start_int ^ end_int

# Count the number of leading zeros in the XOR result to find the prefix length
prefix_length = 32 - xor.bit_length()

# Calculate the network address
network_int = start_int & (0xFFFFFFFF << (32 - prefix_length))
network_address = ipaddress.IPv4Address(network_int)

return f"{network_address}/{prefix_length}"
return self.ip_prefix


def _delete_conntrack_entries(source_prefixes: list) -> None:
"""Delete all conntrack entries for the list of prefixes"""
for source_prefix in source_prefixes:
run(f'conntrack -D -s {source_prefix}')


def generate_port_rules(
external_hosts: list,
Expand Down Expand Up @@ -188,6 +224,9 @@ def get_config(config=None):
with_recursive_defaults=True,
)

if conf.exists(base) and is_node_changed(conf, base + ['pool']):
config.update({'delete_conntrack_entries': {}})

return config


Expand Down Expand Up @@ -386,6 +425,18 @@ def apply(config):
# Log error message
logger.error(f"Error processing line '{allocation}': {e}")

# Delete conntrack entries
if 'delete_conntrack_entries' in config:
internal_pool_prefix_list = []
for rule, rule_config in config['rule'].items():
internal_pool = rule_config['source']['pool']
internal_ip_ranges: list = config['pool']['internal'][internal_pool]['range']
for internal_range in internal_ip_ranges:
ip_prefix = IPOperations(internal_range).get_prefix_by_ip_range()
internal_pool_prefix_list.append(ip_prefix)
# Deleta required sources for conntrack
_delete_conntrack_entries(internal_pool_prefix_list)


if __name__ == '__main__':
try:
Expand Down
Loading

0 comments on commit b9ec469

Please sign in to comment.