diff options
-rw-r--r-- | data/templates/frr/bgpd.frr.j2 | 4 | ||||
-rw-r--r-- | interface-definitions/include/bgp/afi-redistribute-common-protocols.xml.i | 8 | ||||
-rw-r--r-- | interface-definitions/include/version/bgp-version.xml.i | 2 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireguard.py | 78 | ||||
-rw-r--r-- | smoketest/config-tests/bgp-rpki | 1 | ||||
-rw-r--r-- | smoketest/configs/bgp-rpki | 7 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_bgp.py | 76 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_ipoe-server.py | 22 | ||||
-rwxr-xr-x | src/conf_mode/system_sflow.py | 2 | ||||
-rwxr-xr-x | src/etc/netplug/vyos-netplug-dhcp-client | 13 | ||||
-rw-r--r-- | src/migration-scripts/bgp/5-to-6 | 39 | ||||
-rwxr-xr-x | src/services/vyos-domain-resolver | 12 |
12 files changed, 232 insertions, 32 deletions
diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2 index 2f3719fdf..3b462b4a9 100644 --- a/data/templates/frr/bgpd.frr.j2 +++ b/data/templates/frr/bgpd.frr.j2 @@ -310,8 +310,8 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }} {% if afi_config.redistribute is vyos_defined %} {% for protocol, protocol_config in afi_config.redistribute.items() %} {% if protocol == 'table' %} -{% for table in protocol_config %} - redistribute table-direct {{ table }} +{% for table, table_config in protocol_config.items() %} + redistribute table-direct {{ table }} {{ 'metric ' ~ table_config.metric if table_config.metric is vyos_defined }} {{ 'route-map ' ~ table_config.route_map if table_config.route_map is vyos_defined }} {% endfor %} {% else %} {% set redistribution_protocol = protocol %} diff --git a/interface-definitions/include/bgp/afi-redistribute-common-protocols.xml.i b/interface-definitions/include/bgp/afi-redistribute-common-protocols.xml.i index f4d18bc70..141a704c7 100644 --- a/interface-definitions/include/bgp/afi-redistribute-common-protocols.xml.i +++ b/interface-definitions/include/bgp/afi-redistribute-common-protocols.xml.i @@ -39,14 +39,16 @@ #include <include/bgp/afi-redistribute-metric-route-map.xml.i> </children> </node> -<leafNode name="table"> +<tagNode name="table"> <properties> <help>Redistribute non-main Kernel Routing Table</help> <completionHelp> <path>protocols static table</path> </completionHelp> #include <include/constraint/protocols-static-table.xml.i> - <multi/> </properties> -</leafNode> + <children> + #include <include/bgp/afi-redistribute-metric-route-map.xml.i> + </children> +</tagNode> <!-- include end --> diff --git a/interface-definitions/include/version/bgp-version.xml.i b/interface-definitions/include/version/bgp-version.xml.i index 6bed7189f..c90276151 100644 --- a/interface-definitions/include/version/bgp-version.xml.i +++ b/interface-definitions/include/version/bgp-version.xml.i @@ -1,3 +1,3 @@ <!-- include start from include/version/bgp-version.xml.i --> -<syntaxVersion component='bgp' version='5'></syntaxVersion> +<syntaxVersion component='bgp' version='6'></syntaxVersion> <!-- include end --> diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index fed7a5f84..be9bffd20 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -77,6 +77,84 @@ class WireGuardOperational(Operational): } return output + def show_interface(self): + from vyos.config import Config + + c = Config() + + wgdump = self._dump().get(self.config['ifname'], None) + + c.set_level(['interfaces', 'wireguard', self.config['ifname']]) + description = c.return_effective_value(['description']) + ips = c.return_effective_values(['address']) + hostnames = c.return_effective_values(['host-name']) + + answer = 'interface: {}\n'.format(self.config['ifname']) + if description: + answer += ' description: {}\n'.format(description) + if ips: + answer += ' address: {}\n'.format(', '.join(ips)) + if hostnames: + answer += ' hostname: {}\n'.format(', '.join(hostnames)) + + answer += ' public key: {}\n'.format(wgdump['public_key']) + answer += ' private key: (hidden)\n' + answer += ' listening port: {}\n'.format(wgdump['listen_port']) + answer += '\n' + + for peer in c.list_effective_nodes(['peer']): + if wgdump['peers']: + pubkey = c.return_effective_value(['peer', peer, 'public-key']) + if pubkey in wgdump['peers']: + wgpeer = wgdump['peers'][pubkey] + + answer += ' peer: {}\n'.format(peer) + answer += ' public key: {}\n'.format(pubkey) + + """ figure out if the tunnel is recently active or not """ + status = 'inactive' + if wgpeer['latest_handshake'] is None: + """ no handshake ever """ + status = 'inactive' + else: + if int(wgpeer['latest_handshake']) > 0: + delta = timedelta( + seconds=int(time.time() - wgpeer['latest_handshake']) + ) + answer += ' latest handshake: {}\n'.format(delta) + if time.time() - int(wgpeer['latest_handshake']) < (60 * 5): + """ Five minutes and the tunnel is still active """ + status = 'active' + else: + """ it's been longer than 5 minutes """ + status = 'inactive' + elif int(wgpeer['latest_handshake']) == 0: + """ no handshake ever """ + status = 'inactive' + answer += ' status: {}\n'.format(status) + + if wgpeer['endpoint'] is not None: + answer += ' endpoint: {}\n'.format(wgpeer['endpoint']) + + if wgpeer['allowed_ips'] is not None: + answer += ' allowed ips: {}\n'.format( + ','.join(wgpeer['allowed_ips']).replace(',', ', ') + ) + + if wgpeer['transfer_rx'] > 0 or wgpeer['transfer_tx'] > 0: + rx_size = size(wgpeer['transfer_rx'], system=alternative) + tx_size = size(wgpeer['transfer_tx'], system=alternative) + answer += ' transfer: {} received, {} sent\n'.format( + rx_size, tx_size + ) + + if wgpeer['persistent_keepalive'] is not None: + answer += ' persistent keepalive: every {} seconds\n'.format( + wgpeer['persistent_keepalive'] + ) + answer += '\n' + return answer + def get_latest_handshakes(self): """Get latest handshake time for each peer""" output = {} diff --git a/smoketest/config-tests/bgp-rpki b/smoketest/config-tests/bgp-rpki index 587de67c6..657d4abcc 100644 --- a/smoketest/config-tests/bgp-rpki +++ b/smoketest/config-tests/bgp-rpki @@ -13,6 +13,7 @@ set policy route-map ebgp-transit-rpki rule 30 set local-preference '100' set policy route-map ebgp-transit-rpki rule 40 action 'permit' set policy route-map ebgp-transit-rpki rule 40 set extcommunity rt '192.0.2.100:100' set policy route-map ebgp-transit-rpki rule 40 set extcommunity soo '64500:100' +set protocols bgp address-family ipv4-unicast redistribute table 100 set protocols bgp neighbor 1.2.3.4 address-family ipv4-unicast nexthop-self set protocols bgp neighbor 1.2.3.4 address-family ipv4-unicast route-map import 'ebgp-transit-rpki' set protocols bgp neighbor 1.2.3.4 remote-as '10' diff --git a/smoketest/configs/bgp-rpki b/smoketest/configs/bgp-rpki index 5588f15c9..2d136d545 100644 --- a/smoketest/configs/bgp-rpki +++ b/smoketest/configs/bgp-rpki @@ -46,6 +46,13 @@ policy { } protocols { bgp 64500 { + address-family { + ipv4-unicast { + redistribute { + table 100 + } + } + } neighbor 1.2.3.4 { address-family { ipv4-unicast { diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 0eda52ff6..0c6d36213 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# Copyright (C) 2021-2025 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 @@ -685,14 +685,30 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): 'route_map' : 'redistr-ipv4-static', }, 'table' : { - 'number' : ['10', '20', '30', '40'], + '10' : { + 'metric' : '810', + 'route_map' : 'redistr-ipv4-table-10', + }, + '20' : { + 'metric' : '820', + 'route_map' : 'redistr-ipv4-table-20', + }, + '30' : { + 'metric' : '830', + 'route_map' : 'redistr-ipv4-table-30', + }, }, } for proto, proto_config in redistributes.items(): proto_path = base_path + ['address-family', 'ipv4-unicast', 'redistribute', proto] - if proto == 'table' and 'number' in proto_config: - for number in proto_config['number']: - self.cli_set(proto_path, value=number) + if proto == 'table': + for table, table_config in proto_config.items(): + self.cli_set(proto_path + [table]) + if 'metric' in table_config: + self.cli_set(proto_path + [table, 'metric'], value=table_config['metric']) + if 'route_map' in table_config: + self.cli_set(['policy', 'route-map', table_config['route_map'], 'rule', '10', 'action'], value='permit') + self.cli_set(proto_path + [table, 'route-map'], value=table_config['route_map']) else: self.cli_set(proto_path) if 'metric' in proto_config: @@ -723,9 +739,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(' address-family ipv4 unicast', frrconfig) for proto, proto_config in redistributes.items(): - if proto == 'table' and 'number' in proto_config: - for number in proto_config['number']: - self.assertIn(f' redistribute table-direct {number}', frrconfig) + if proto == 'table': + for table, table_config in proto_config.items(): + tmp = f' redistribute table-direct {table}' + if 'metric' in proto_config: + metric = proto_config['metric'] + tmp += f' metric {metric}' + if 'route_map' in proto_config: + route_map = proto_config['route_map'] + tmp += f' route-map {route_map}' + self.assertIn(tmp, frrconfig) else: tmp = f' redistribute {proto}' if 'metric' in proto_config: @@ -794,14 +817,30 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): 'route_map' : 'redistr-ipv6-static', }, 'table' : { - 'number' : ['100', '120', '130', '140'], + '110' : { + 'metric' : '811', + 'route_map' : 'redistr-ipv6-table-110', + }, + '120' : { + 'metric' : '821', + 'route_map' : 'redistr-ipv6-table-120', + }, + '130' : { + 'metric' : '831', + 'route_map' : 'redistr-ipv6-table-130', + }, }, } for proto, proto_config in redistributes.items(): proto_path = base_path + ['address-family', 'ipv6-unicast', 'redistribute', proto] - if proto == 'table' and 'number' in proto_config: - for number in proto_config['number']: - self.cli_set(proto_path, value=number) + if proto == 'table': + for table, table_config in proto_config.items(): + self.cli_set(proto_path + [table]) + if 'metric' in table_config: + self.cli_set(proto_path + [table, 'metric'], value=table_config['metric']) + if 'route_map' in table_config: + self.cli_set(['policy', 'route-map', table_config['route_map'], 'rule', '10', 'action'], value='permit') + self.cli_set(proto_path + [table, 'route-map'], value=table_config['route_map']) else: self.cli_set(proto_path) if 'metric' in proto_config: @@ -829,9 +868,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(' no bgp ebgp-requires-policy', frrconfig) for proto, proto_config in redistributes.items(): - if proto == 'table' and 'number' in proto_config: - for number in proto_config['number']: - self.assertIn(f' redistribute table-direct {number}', frrconfig) + if proto == 'table': + for table, table_config in proto_config.items(): + tmp = f' redistribute table-direct {table}' + if 'metric' in proto_config: + metric = proto_config['metric'] + tmp += f' metric {metric}' + if 'route_map' in proto_config: + route_map = proto_config['route_map'] + tmp += f' route-map {route_map}' + self.assertIn(tmp, frrconfig) else: # FRR calls this OSPF6 if proto == 'ospfv3': diff --git a/smoketest/scripts/cli/test_service_ipoe-server.py b/smoketest/scripts/cli/test_service_ipoe-server.py index ab0898d17..67e8ca93f 100755 --- a/smoketest/scripts/cli/test_service_ipoe-server.py +++ b/smoketest/scripts/cli/test_service_ipoe-server.py @@ -295,6 +295,28 @@ delegate={delegate_2_prefix},{delegate_mask},name={pool_name}""" tmp = re.findall(regex, tmp) self.assertTrue(tmp) + def test_ipoe_server_start_session(self): + start_session = 'auto' + + # Configuration of local authentication for PPPoE server + self.basic_config() + self.cli_commit() + + # Validate configuration values + conf = ConfigParser(allow_no_value=True, delimiters='=', strict=False) + conf.read(self._config_file) + # if 'start-session' option is not set the default value is 'dhcp' + self.assertIn(f'start=dhcpv4', conf['ipoe']['interface']) + + # change 'start-session' option to 'auto' + self.set(['interface', interface, 'start-session', start_session]) + self.cli_commit() + + # Validate changed configuration values + conf = ConfigParser(allow_no_value=True, delimiters='=', strict=False) + conf.read(self._config_file) + self.assertIn(f'start={start_session}', conf['ipoe']['interface']) + @unittest.skip("PPP is not a part of IPoE") def test_accel_ppp_options(self): pass diff --git a/src/conf_mode/system_sflow.py b/src/conf_mode/system_sflow.py index 41119b494..a22dac36f 100755 --- a/src/conf_mode/system_sflow.py +++ b/src/conf_mode/system_sflow.py @@ -54,7 +54,7 @@ def verify(sflow): # Check if configured sflow agent-address exist in the system if 'agent_address' in sflow: tmp = sflow['agent_address'] - if not is_addr_assigned(tmp): + if not is_addr_assigned(tmp, include_vrf=True): raise ConfigError( f'Configured "sflow agent-address {tmp}" does not exist in the system!' ) diff --git a/src/etc/netplug/vyos-netplug-dhcp-client b/src/etc/netplug/vyos-netplug-dhcp-client index 83fed70f0..4cc824afd 100755 --- a/src/etc/netplug/vyos-netplug-dhcp-client +++ b/src/etc/netplug/vyos-netplug-dhcp-client @@ -19,21 +19,22 @@ import sys from time import sleep -from vyos.configquery import ConfigTreeQuery +from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.ifconfig import Interface from vyos.ifconfig import Section from vyos.utils.boot import boot_configuration_complete from vyos.utils.commit import commit_in_progress from vyos import airbag + airbag.enable() if len(sys.argv) < 3: - airbag.noteworthy("Must specify both interface and link status!") + airbag.noteworthy('Must specify both interface and link status!') sys.exit(1) if not boot_configuration_complete(): - airbag.noteworthy("System bootup not yet finished...") + airbag.noteworthy('System bootup not yet finished...') sys.exit(1) interface = sys.argv[1] @@ -47,8 +48,10 @@ while commit_in_progress(): sleep(1) in_out = sys.argv[2] -config = ConfigTreeQuery() +config = Config() interface_path = ['interfaces'] + Section.get_config_path(interface).split() -_, interface_config = get_interface_dict(config, interface_path[:-1], ifname=interface, with_pki=True) +_, interface_config = get_interface_dict( + config, interface_path[:-1], ifname=interface, with_pki=True +) Interface(interface).update(interface_config) diff --git a/src/migration-scripts/bgp/5-to-6 b/src/migration-scripts/bgp/5-to-6 new file mode 100644 index 000000000..e6fea6574 --- /dev/null +++ b/src/migration-scripts/bgp/5-to-6 @@ -0,0 +1,39 @@ +# Copyright 2025 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/>. + +# T7163: migrate "address-family ipv4|6-unicast redistribute table" from a multi +# leafNode to a tagNode. This is needed to support per table definition of a +# route-map and/or metric + +from vyos.configtree import ConfigTree + +def migrate(config: ConfigTree) -> None: + bgp_base = ['protocols', 'bgp'] + if not config.exists(bgp_base): + return + + for address_family in ['ipv4-unicast', 'ipv6-unicast']: + # there is no non-main routing table beeing redistributed under this addres family + # bail out early and continue with next AFI + table_path = bgp_base + ['address-family', address_family, 'redistribute', 'table'] + if not config.exists(table_path): + continue + + tables = config.return_values(table_path) + config.delete(table_path) + + for table in tables: + config.set(table_path + [table]) + config.set_tag(table_path) diff --git a/src/services/vyos-domain-resolver b/src/services/vyos-domain-resolver index bfc8caa0a..48c6b86d8 100755 --- a/src/services/vyos-domain-resolver +++ b/src/services/vyos-domain-resolver @@ -65,13 +65,15 @@ def get_config(conf, node): node_config = dict_merge(default_values, node_config) - global timeout, cache + if node == base_firewall and 'global_options' in node_config: + global_config = node_config['global_options'] + global timeout, cache - if 'resolver_interval' in node_config: - timeout = int(node_config['resolver_interval']) + if 'resolver_interval' in global_config: + timeout = int(global_config['resolver_interval']) - if 'resolver_cache' in node_config: - cache = True + if 'resolver_cache' in global_config: + cache = True fqdn_config_parse(node_config, node[0]) |