summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/firewall.py26
-rwxr-xr-xsrc/conf_mode/interfaces_bridge.py2
-rwxr-xr-xsrc/conf_mode/interfaces_pseudo-ethernet.py2
-rwxr-xr-xsrc/conf_mode/interfaces_virtual-ethernet.py2
-rwxr-xr-xsrc/conf_mode/interfaces_vti.py2
-rwxr-xr-xsrc/conf_mode/interfaces_wwan.py2
-rwxr-xr-xsrc/conf_mode/policy_route.py47
-rwxr-xr-xsrc/conf_mode/service_dhcp-server.py34
-rwxr-xr-xsrc/conf_mode/system_host-name.py2
-rwxr-xr-xsrc/conf_mode/system_option.py4
-rwxr-xr-xsrc/conf_mode/system_syslog.py2
-rw-r--r--src/etc/dhcp/dhclient-enter-hooks.d/06-vyos-nodefaultroute20
-rw-r--r--src/etc/sysctl.d/30-vyos-router.conf10
-rw-r--r--src/etc/systemd/system/kea-dhcp-ddns-server.service.d/override.conf7
-rwxr-xr-xsrc/helpers/geoip-update.py17
-rwxr-xr-xsrc/init/vyos-router8
-rwxr-xr-xsrc/op_mode/firewall.py3
-rwxr-xr-xsrc/op_mode/image_installer.py4
-rw-r--r--src/op_mode/tech_support.py10
-rw-r--r--src/systemd/vyos.target2
20 files changed, 183 insertions, 23 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index cebe57092..274ca2ce6 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -205,7 +205,7 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
if 'jump' not in rule_conf['action']:
raise ConfigError('jump-target defined, but action jump needed and it is not defined')
target = rule_conf['jump_target']
- if hook != 'name': # This is a bit clumsy, but consolidates a chunk of code.
+ if hook != 'name': # This is a bit clumsy, but consolidates a chunk of code.
verify_jump_target(firewall, hook, target, family, recursive=True)
else:
verify_jump_target(firewall, hook, target, family, recursive=False)
@@ -268,12 +268,12 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
if dict_search_args(rule_conf, 'gre', 'flags', 'checksum') is None:
# There is no builtin match in nftables for the GRE key, so we need to do a raw lookup.
- # The offset of the key within the packet shifts depending on the C-flag.
- # 99% of the time, nobody will have checksums enabled - it's usually a manual config option.
- # We can either assume it is unset unless otherwise directed
+ # The offset of the key within the packet shifts depending on the C-flag.
+ # 99% of the time, nobody will have checksums enabled - it's usually a manual config option.
+ # We can either assume it is unset unless otherwise directed
# (confusing, requires doco to explain why it doesn't work sometimes)
- # or, demand an explicit selection to be made for this specific match rule.
- # This check enforces the latter. The user is free to create rules for both cases.
+ # or, demand an explicit selection to be made for this specific match rule.
+ # This check enforces the latter. The user is free to create rules for both cases.
raise ConfigError('Matching GRE tunnel key requires an explicit checksum flag match. For most cases, use "gre flags checksum unset"')
if dict_search_args(rule_conf, 'gre', 'flags', 'key', 'unset') is not None:
@@ -286,7 +286,7 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
if gre_inner_value < 0 or gre_inner_value > 65535:
raise ConfigError('inner-proto outside valid ethertype range 0-65535')
except ValueError:
- pass # Symbolic constant, pre-validated before reaching here.
+ pass # Symbolic constant, pre-validated before reaching here.
tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
if tcp_flags:
@@ -437,6 +437,16 @@ def verify(firewall):
for ifname in interfaces:
verify_hardware_offload(ifname)
+ if 'offload' in firewall.get('global_options', {}).get('state_policy', {}):
+ offload_path = firewall['global_options']['state_policy']['offload']
+ if 'offload_target' not in offload_path:
+ raise ConfigError('offload-target must be specified')
+
+ offload_target = offload_path['offload_target']
+
+ if not dict_search_args(firewall, 'flowtable', offload_target):
+ raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system')
+
if 'group' in firewall:
for group_type in nested_group_types:
if group_type in firewall['group']:
@@ -627,7 +637,7 @@ def apply(firewall):
# Call helper script to Update set contents
if 'name' in firewall['geoip_updated'] or 'ipv6_name' in firewall['geoip_updated']:
print('Updating GeoIP. Please wait...')
- geoip_update(firewall)
+ geoip_update(firewall=firewall)
return None
diff --git a/src/conf_mode/interfaces_bridge.py b/src/conf_mode/interfaces_bridge.py
index aff93af2a..95dcc543e 100755
--- a/src/conf_mode/interfaces_bridge.py
+++ b/src/conf_mode/interfaces_bridge.py
@@ -25,6 +25,7 @@ from vyos.configdict import has_vlan_subinterface_configured
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import BridgeIf
from vyos.configdict import has_address_configured
from vyos.configdict import has_vrf_configured
@@ -136,6 +137,7 @@ def verify(bridge):
verify_dhcpv6(bridge)
verify_vrf(bridge)
+ verify_mtu_ipv6(bridge)
verify_mirror_redirect(bridge)
ifname = bridge['ifname']
diff --git a/src/conf_mode/interfaces_pseudo-ethernet.py b/src/conf_mode/interfaces_pseudo-ethernet.py
index 446beffd3..b066fd542 100755
--- a/src/conf_mode/interfaces_pseudo-ethernet.py
+++ b/src/conf_mode/interfaces_pseudo-ethernet.py
@@ -27,6 +27,7 @@ from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_source_interface
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_mtu_parent
+from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_mirror_redirect
from vyos.ifconfig import MACVLANIf
from vyos.utils.network import interface_exists
@@ -71,6 +72,7 @@ def verify(peth):
verify_vrf(peth)
verify_address(peth)
verify_mtu_parent(peth, peth['parent'])
+ verify_mtu_ipv6(peth)
verify_mirror_redirect(peth)
# use common function to verify VLAN configuration
verify_vlan_config(peth)
diff --git a/src/conf_mode/interfaces_virtual-ethernet.py b/src/conf_mode/interfaces_virtual-ethernet.py
index cb6104f59..59ce474fc 100755
--- a/src/conf_mode/interfaces_virtual-ethernet.py
+++ b/src/conf_mode/interfaces_virtual-ethernet.py
@@ -23,6 +23,7 @@ from vyos.configdict import get_interface_dict
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import VethIf
from vyos.utils.network import interface_exists
airbag.enable()
@@ -62,6 +63,7 @@ def verify(veth):
return None
verify_vrf(veth)
+ verify_mtu_ipv6(veth)
verify_address(veth)
if 'peer_name' not in veth:
diff --git a/src/conf_mode/interfaces_vti.py b/src/conf_mode/interfaces_vti.py
index 20629c6c1..915bde066 100755
--- a/src/conf_mode/interfaces_vti.py
+++ b/src/conf_mode/interfaces_vti.py
@@ -20,6 +20,7 @@ from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import VTIIf
from vyos import ConfigError
from vyos import airbag
@@ -40,6 +41,7 @@ def get_config(config=None):
def verify(vti):
verify_vrf(vti)
+ verify_mtu_ipv6(vti)
verify_mirror_redirect(vti)
return None
diff --git a/src/conf_mode/interfaces_wwan.py b/src/conf_mode/interfaces_wwan.py
index 230eb14d6..ddbebfb4a 100755
--- a/src/conf_mode/interfaces_wwan.py
+++ b/src/conf_mode/interfaces_wwan.py
@@ -26,6 +26,7 @@ from vyos.configverify import verify_authentication
from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import WWANIf
from vyos.utils.dict import dict_search
from vyos.utils.process import cmd
@@ -98,6 +99,7 @@ def verify(wwan):
verify_interface_exists(wwan, ifname)
verify_authentication(wwan)
verify_vrf(wwan)
+ verify_mtu_ipv6(wwan)
verify_mirror_redirect(wwan)
return None
diff --git a/src/conf_mode/policy_route.py b/src/conf_mode/policy_route.py
index 223175b8a..521764896 100755
--- a/src/conf_mode/policy_route.py
+++ b/src/conf_mode/policy_route.py
@@ -21,13 +21,16 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdiff import get_config_diff, Diff
from vyos.template import render
from vyos.utils.dict import dict_search_args
+from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import cmd
from vyos.utils.process import run
from vyos.utils.network import get_vrf_tableid
from vyos.defaults import rt_global_table
from vyos.defaults import rt_global_vrf
+from vyos.firewall import geoip_update
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -43,6 +46,43 @@ valid_groups = [
'interface_group'
]
+def geoip_updated(conf, policy):
+ diff = get_config_diff(conf)
+ node_diff = diff.get_child_nodes_diff(['policy'], expand_nodes=Diff.DELETE, recursive=True)
+
+ out = {
+ 'name': [],
+ 'ipv6_name': [],
+ 'deleted_name': [],
+ 'deleted_ipv6_name': []
+ }
+ updated = False
+
+ for key, path in dict_search_recursive(policy, 'geoip'):
+ set_name = f'GEOIP_CC_{path[0]}_{path[1]}_{path[3]}'
+ if (path[0] == 'route'):
+ out['name'].append(set_name)
+ elif (path[0] == 'route6'):
+ set_name = f'GEOIP_CC6_{path[0]}_{path[1]}_{path[3]}'
+ out['ipv6_name'].append(set_name)
+
+ updated = True
+
+ if 'delete' in node_diff:
+ for key, path in dict_search_recursive(node_diff['delete'], 'geoip'):
+ set_name = f'GEOIP_CC_{path[0]}_{path[1]}_{path[3]}'
+ if (path[0] == 'route'):
+ out['deleted_name'].append(set_name)
+ elif (path[0] == 'route6'):
+ set_name = f'GEOIP_CC6_{path[0]}_{path[1]}_{path[3]}'
+ out['deleted_ipv6_name'].append(set_name)
+ updated = True
+
+ if updated:
+ return out
+
+ return False
+
def get_config(config=None):
if config:
conf = config
@@ -60,6 +100,7 @@ def get_config(config=None):
if 'dynamic_group' in policy['firewall_group']:
del policy['firewall_group']['dynamic_group']
+ policy['geoip_updated'] = geoip_updated(conf, policy)
return policy
def verify_rule(policy, name, rule_conf, ipv6, rule_id):
@@ -203,6 +244,12 @@ def apply(policy):
apply_table_marks(policy)
+ if policy['geoip_updated']:
+ # Call helper script to Update set contents
+ if 'name' in policy['geoip_updated'] or 'ipv6_name' in policy['geoip_updated']:
+ print('Updating GeoIP. Please wait...')
+ geoip_update(policy=policy)
+
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py
index e46d916fd..99c7e6a1f 100755
--- a/src/conf_mode/service_dhcp-server.py
+++ b/src/conf_mode/service_dhcp-server.py
@@ -43,6 +43,7 @@ airbag.enable()
ctrl_socket = '/run/kea/dhcp4-ctrl-socket'
config_file = '/run/kea/kea-dhcp4.conf'
+config_file_d2 = '/run/kea/kea-dhcp-ddns.conf'
lease_file = '/config/dhcp/dhcp4-leases.csv'
lease_file_glob = '/config/dhcp/dhcp4-leases*'
user_group = '_kea'
@@ -170,6 +171,15 @@ def get_config(config=None):
return dhcp
+def verify_ddns_domain_servers(domain_type, domain):
+ if 'dns_server' in domain:
+ invalid_servers = []
+ for server_no, server_config in domain['dns_server'].items():
+ if 'address' not in server_config:
+ invalid_servers.append(server_no)
+ if len(invalid_servers) > 0:
+ raise ConfigError(f'{domain_type} DNS servers {", ".join(invalid_servers)} in DDNS configuration need to have an IP address')
+ return None
def verify(dhcp):
# bail out early - looks like removal from running config
@@ -422,6 +432,22 @@ def verify(dhcp):
if not interface_exists(interface):
raise ConfigError(f'listen-interface "{interface}" does not exist')
+ if 'dynamic_dns_update' in dhcp:
+ ddns = dhcp['dynamic_dns_update']
+ if 'tsig_key' in ddns:
+ invalid_keys = []
+ for tsig_key_name, tsig_key_config in ddns['tsig_key'].items():
+ if not ('algorithm' in tsig_key_config and 'secret' in tsig_key_config):
+ invalid_keys.append(tsig_key_name)
+ if len(invalid_keys) > 0:
+ raise ConfigError(f'Both algorithm and secret need to be set for TSIG keys: {", ".join(invalid_keys)}')
+
+ if 'forward_domain' in ddns:
+ verify_ddns_domain_servers('Forward', ddns['forward_domain'])
+
+ if 'reverse_domain' in ddns:
+ verify_ddns_domain_servers('Reverse', ddns['reverse_domain'])
+
return None
@@ -485,6 +511,14 @@ def generate(dhcp):
user=user_group,
group=user_group,
)
+ if 'dynamic_dns_update' in dhcp:
+ render(
+ config_file_d2,
+ 'dhcp-server/kea-dhcp-ddns.conf.j2',
+ dhcp,
+ user=user_group,
+ group=user_group
+ )
return None
diff --git a/src/conf_mode/system_host-name.py b/src/conf_mode/system_host-name.py
index fef034d1c..de4accda2 100755
--- a/src/conf_mode/system_host-name.py
+++ b/src/conf_mode/system_host-name.py
@@ -175,7 +175,7 @@ def apply(config):
# Restart services that use the hostname
if hostname_new != hostname_old:
- tmp = systemd_services['rsyslog']
+ tmp = systemd_services['syslog']
call(f'systemctl restart {tmp}')
# If SNMP is running, restart it too
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index b45a9d8a6..3d76a1eaa 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright (C) 2019-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
@@ -136,6 +136,8 @@ def generate(options):
mode = options['kernel']['amd_pstate_driver']
cmdline_options.append(
f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}')
+ if 'quiet' in options['kernel']:
+ cmdline_options.append('quiet')
grub_util.update_kernel_cmdline_options(' '.join(cmdline_options))
return None
diff --git a/src/conf_mode/system_syslog.py b/src/conf_mode/system_syslog.py
index 414bd4b6b..bdab09f3c 100755
--- a/src/conf_mode/system_syslog.py
+++ b/src/conf_mode/system_syslog.py
@@ -35,7 +35,7 @@ rsyslog_conf = '/run/rsyslog/rsyslog.conf'
logrotate_conf = '/etc/logrotate.d/vyos-rsyslog'
systemd_socket = 'syslog.socket'
-systemd_service = systemd_services['rsyslog']
+systemd_service = systemd_services['syslog']
def get_config(config=None):
if config:
diff --git a/src/etc/dhcp/dhclient-enter-hooks.d/06-vyos-nodefaultroute b/src/etc/dhcp/dhclient-enter-hooks.d/06-vyos-nodefaultroute
new file mode 100644
index 000000000..38f674276
--- /dev/null
+++ b/src/etc/dhcp/dhclient-enter-hooks.d/06-vyos-nodefaultroute
@@ -0,0 +1,20 @@
+# Don't add default route if no-default-route is configured for interface
+
+# As configuration is not available to cli-shell-api at the first boot, we must use vyos.config, which contains a workaround for this
+function get_no_default_route {
+python3 - <<PYEND
+from vyos.config import Config
+import os
+
+config = Config()
+if config.exists('interfaces'):
+ iface_types = config.list_nodes('interfaces')
+ for iface_type in iface_types:
+ if config.exists("interfaces {} {} dhcp-options no-default-route".format(iface_type, os.environ['interface'])):
+ print("True")
+PYEND
+}
+
+if [[ "$(get_no_default_route)" == 'True' ]]; then
+ new_routers=""
+fi
diff --git a/src/etc/sysctl.d/30-vyos-router.conf b/src/etc/sysctl.d/30-vyos-router.conf
index 76be41ddc..ef81cebac 100644
--- a/src/etc/sysctl.d/30-vyos-router.conf
+++ b/src/etc/sysctl.d/30-vyos-router.conf
@@ -83,6 +83,16 @@ net.ipv4.conf.default.ignore_routes_with_linkdown=1
net.ipv6.conf.all.ignore_routes_with_linkdown=1
net.ipv6.conf.default.ignore_routes_with_linkdown=1
+# Disable IPv6 interface autoconfigurationnable packet forwarding for IPv6
+net.ipv6.conf.all.autoconf=0
+net.ipv6.conf.default.autoconf=0
+net.ipv6.conf.*.autoconf=0
+
+# Disable IPv6 router advertisements
+net.ipv6.conf.all.accept_ra=0
+net.ipv6.conf.default.accept_ra=0
+net.ipv6.conf.*.accept_ra=0
+
# Enable packet forwarding for IPv6
net.ipv6.conf.all.forwarding=1
diff --git a/src/etc/systemd/system/kea-dhcp-ddns-server.service.d/override.conf b/src/etc/systemd/system/kea-dhcp-ddns-server.service.d/override.conf
new file mode 100644
index 000000000..cdfdea8eb
--- /dev/null
+++ b/src/etc/systemd/system/kea-dhcp-ddns-server.service.d/override.conf
@@ -0,0 +1,7 @@
+[Unit]
+After=
+After=vyos-router.service
+
+[Service]
+ExecStart=
+ExecStart=/usr/sbin/kea-dhcp-ddns -c /run/kea/kea-dhcp-ddns.conf
diff --git a/src/helpers/geoip-update.py b/src/helpers/geoip-update.py
index 34accf2cc..061c95401 100755
--- a/src/helpers/geoip-update.py
+++ b/src/helpers/geoip-update.py
@@ -25,20 +25,19 @@ def get_config(config=None):
conf = config
else:
conf = ConfigTreeQuery()
- base = ['firewall']
- if not conf.exists(base):
- return None
-
- return conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
+ return (
+ conf.get_config_dict(['firewall'], key_mangling=('-', '_'), get_first_key=True,
+ no_tag_node_value_mangle=True) if conf.exists(['firewall']) else None,
+ conf.get_config_dict(['policy'], key_mangling=('-', '_'), get_first_key=True,
+ no_tag_node_value_mangle=True) if conf.exists(['policy']) else None,
+ )
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--force", help="Force update", action="store_true")
args = parser.parse_args()
- firewall = get_config()
-
- if not geoip_update(firewall, force=args.force):
+ firewall, policy = get_config()
+ if not geoip_update(firewall=firewall, policy=policy, force=args.force):
sys.exit(1)
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 081adf214..8584234b3 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -460,6 +460,14 @@ start ()
nfct helper add tns inet6 tcp
nft --file /usr/share/vyos/vyos-firewall-init.conf || log_failure_msg "could not initiate firewall rules"
+ # Ensure rsyslog is the default syslog daemon
+ SYSTEMD_SYSLOG="/etc/systemd/system/syslog.service"
+ SYSTEMD_RSYSLOG="/lib/systemd/system/rsyslog.service"
+ if [ ! -L ${SYSTEMD_SYSLOG} ] || [ "$(readlink -f ${SYSTEMD_SYSLOG})" != "${SYSTEMD_RSYSLOG}" ]; then
+ ln -sf ${SYSTEMD_RSYSLOG} ${SYSTEMD_SYSLOG}
+ systemctl daemon-reload
+ fi
+
# As VyOS does not execute commands that are not present in the CLI we call
# the script by hand to have a single source for the login banner and MOTD
${vyos_conf_scripts_dir}/system_syslog.py || log_failure_msg "could not reset syslog"
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index 086536e4e..ac47e3273 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -598,6 +598,9 @@ def show_firewall_group(name=None):
prefix = 'DA_' if dynamic_type == 'address_group' else 'DA6_'
if dynamic_type in firewall['group']['dynamic_group']:
for dynamic_name, dynamic_conf in firewall['group']['dynamic_group'][dynamic_type].items():
+ if name and name != dynamic_name:
+ continue
+
references = find_references(dynamic_type, dynamic_name)
row = [dynamic_name, textwrap.fill(dynamic_conf.get('description') or '', 50), dynamic_type + '(dynamic)', '\n'.join(references) or 'N/D']
diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py
index 2660309a5..3af2232bb 100755
--- a/src/op_mode/image_installer.py
+++ b/src/op_mode/image_installer.py
@@ -491,6 +491,8 @@ def get_cli_kernel_options(config_file: str) -> list:
config = ConfigTree(read_file(config_file))
config_dict = loads(config.to_json())
kernel_options = dict_search('system.option.kernel', config_dict)
+ if kernel_options is None:
+ kernel_options = {}
cmdline_options = []
# XXX: This code path and if statements must be kept in sync with the Kernel
@@ -504,6 +506,8 @@ def get_cli_kernel_options(config_file: str) -> list:
mode = kernel_options['amd-pstate-driver']
cmdline_options.append(
f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}')
+ if 'quiet' in kernel_options:
+ cmdline_options.append('quiet')
return cmdline_options
diff --git a/src/op_mode/tech_support.py b/src/op_mode/tech_support.py
index 24ac0af1b..c4496dfa3 100644
--- a/src/op_mode/tech_support.py
+++ b/src/op_mode/tech_support.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright (C) 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
@@ -20,6 +20,7 @@ import json
import vyos.opmode
from vyos.utils.process import cmd
+from vyos.base import Warning
def _get_version_data():
from vyos.version import get_version_data
@@ -51,7 +52,12 @@ def _get_storage():
def _get_devices():
devices = {}
devices["pci"] = cmd("lspci")
- devices["usb"] = cmd("lsusb")
+
+ try:
+ devices["usb"] = cmd("lsusb")
+ except OSError:
+ Warning("Could not retrieve information about USB devices")
+ devices["usb"] = {}
return devices
diff --git a/src/systemd/vyos.target b/src/systemd/vyos.target
index c5d04891d..ea1593fe9 100644
--- a/src/systemd/vyos.target
+++ b/src/systemd/vyos.target
@@ -1,3 +1,3 @@
[Unit]
Description=VyOS target
-After=multi-user.target vyos-grub-update.service
+After=multi-user.target vyos-grub-update.service systemd-sysctl.service