diff --git a/data/templates/system/40_usb_autosuspend.j2 b/data/templates/system/40_usb_autosuspend.j2 new file mode 100644 index 000000000..01ba86420 --- /dev/null +++ b/data/templates/system/40_usb_autosuspend.j2 @@ -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 }}" diff --git a/interface-definitions/system_option.xml.in b/interface-definitions/system_option.xml.in index fe517d17d..ad423d9d1 100644 --- a/interface-definitions/system_option.xml.in +++ b/interface-definitions/system_option.xml.in @@ -1,190 +1,196 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="system"> <children> <node name="option" owner="${vyos_conf_scripts_dir}/system_option.py"> <properties> <help>System Options</help> <priority>9999</priority> </properties> <children> <leafNode name="ctrl-alt-delete"> <properties> <help>System action on Ctrl-Alt-Delete keystroke</help> <completionHelp> <list>ignore reboot poweroff</list> </completionHelp> <valueHelp> <format>ignore</format> <description>Ignore key sequence</description> </valueHelp> <valueHelp> <format>reboot</format> <description>Reboot system</description> </valueHelp> <valueHelp> <format>poweroff</format> <description>Poweroff system</description> </valueHelp> <constraint> <regex>(ignore|reboot|poweroff)</regex> </constraint> <constraintErrorMessage>Must be ignore, reboot, or poweroff</constraintErrorMessage> </properties> </leafNode> <node name="kernel"> <properties> <help>Kernel boot parameters</help> </properties> <children> <leafNode name="disable-mitigations"> <properties> <help>Disable all optional CPU mitigations</help> <valueless/> </properties> </leafNode> <leafNode name="disable-power-saving"> <properties> <help>Disable CPU power saving mechanisms also known as C states</help> <valueless/> </properties> </leafNode> </children> </node> <leafNode name="keyboard-layout"> <properties> <help>System keyboard layout, type ISO2</help> <completionHelp> <list>us uk fr de es fi jp106 no dk se-latin1 dvorak</list> </completionHelp> <valueHelp> <format>us</format> <description>United States</description> </valueHelp> <valueHelp> <format>uk</format> <description>United Kingdom</description> </valueHelp> <valueHelp> <format>fr</format> <description>France</description> </valueHelp> <valueHelp> <format>de</format> <description>Germany</description> </valueHelp> <valueHelp> <format>es</format> <description>Spain</description> </valueHelp> <valueHelp> <format>fi</format> <description>Finland</description> </valueHelp> <valueHelp> <format>jp106</format> <description>Japan</description> </valueHelp> <valueHelp> <format>no</format> <description>Norway</description> </valueHelp> <valueHelp> <format>dk</format> <description>Denmark</description> </valueHelp> <valueHelp> <format>se-latin1</format> <description>Sweden</description> </valueHelp> <valueHelp> <format>dvorak</format> <description>Dvorak</description> </valueHelp> <constraint> <regex>(us|uk|fr|de|es|fi|jp106|no|dk|se-latin1|dvorak)</regex> </constraint> <constraintErrorMessage>Invalid keyboard layout</constraintErrorMessage> </properties> <defaultValue>us</defaultValue> </leafNode> <leafNode name="performance"> <properties> <help>Tune system performance</help> <completionHelp> <list>throughput latency</list> </completionHelp> <valueHelp> <format>throughput</format> <description>Tune for maximum network throughput</description> </valueHelp> <valueHelp> <format>latency</format> <description>Tune for low network latency</description> </valueHelp> <constraint> <regex>(throughput|latency)</regex> </constraint> </properties> </leafNode> <node name="http-client"> <properties> <help>Global options used for HTTP client</help> </properties> <children> #include <include/source-interface.xml.i> #include <include/source-address-ipv4-ipv6.xml.i> </children> </node> <leafNode name="reboot-on-panic"> <properties> <help>Reboot system on kernel panic</help> <valueless/> </properties> </leafNode> <node name="ssh-client"> <properties> <help>Global options used for SSH client</help> </properties> <children> #include <include/source-address-ipv4-ipv6.xml.i> #include <include/source-interface.xml.i> </children> </node> <leafNode name="startup-beep"> <properties> <help>plays sound via system speaker when you can login</help> <valueless/> </properties> </leafNode> <leafNode name="root-partition-auto-resize"> <properties> <help>Enable root partition auto-extention on system boot</help> <valueless/> </properties> </leafNode> <leafNode name="time-format"> <properties> <help>System time-format</help> <completionHelp> <list>12-hour 24-hour</list> </completionHelp> <valueHelp> <format>12-hour</format> <description>12 hour time format</description> </valueHelp> <valueHelp> <format>24-hour</format> <description>24 hour time format</description> </valueHelp> <constraint> <regex>(12-hour|24-hour)</regex> </constraint> </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> </node> </interfaceDefinition> diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py index a2e5db575..2c31703e9 100755 --- a/src/conf_mode/system_option.py +++ b/src/conf_mode/system_option.py @@ -1,166 +1,171 @@ #!/usr/bin/env python3 # # Copyright (C) 2019-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 # published by the Free Software Foundation. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import os from sys import exit from time import sleep from vyos.config import Config from vyos.configverify import verify_source_interface from vyos.configverify import verify_interface_exists from vyos.system import grub_util from vyos.template import render from vyos.utils.process import cmd from vyos.utils.process import is_systemd_service_running from vyos.utils.network import is_addr_assigned from vyos.utils.network import is_intf_addr_assigned from vyos import ConfigError from vyos import airbag airbag.enable() curlrc_config = r'/etc/curlrc' ssh_config = r'/etc/ssh/ssh_config.d/91-vyos-ssh-client-options.conf' systemd_action_file = '/lib/systemd/system/ctrl-alt-del.target' +usb_autosuspend = r'/etc/udev/rules.d/40-usb-autosuspend.rules' time_format_to_locale = { '12-hour': 'en_US.UTF-8', '24-hour': 'en_GB.UTF-8' } def get_config(config=None): if config: conf = config else: conf = Config() base = ['system', 'option'] options = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, with_recursive_defaults=True) return options def verify(options): if 'http_client' in options: config = options['http_client'] if 'source_interface' in config: verify_interface_exists(config['source_interface']) if {'source_address', 'source_interface'} <= set(config): raise ConfigError('Can not define both HTTP source-interface and source-address') if 'source_address' in config: if not is_addr_assigned(config['source_address']): raise ConfigError('No interface with give address specified!') if 'ssh_client' in options: config = options['ssh_client'] if 'source_address' in config: address = config['source_address'] if not is_addr_assigned(config['source_address']): raise ConfigError('No interface with address "{address}" configured!') if 'source_interface' in config: verify_source_interface(config) if 'source_address' in config: address = config['source_address'] interface = config['source_interface'] if not is_intf_addr_assigned(interface, address): raise ConfigError(f'Address "{address}" not assigned on interface "{interface}"!') return None def generate(options): render(curlrc_config, 'system/curlrc.j2', options) render(ssh_config, 'system/ssh_config.j2', options) + render(usb_autosuspend, 'system/40_usb_autosuspend.j2', options) cmdline_options = [] if 'kernel' in options: if 'disable_mitigations' in options['kernel']: cmdline_options.append('mitigations=off') if 'disable_power_saving' in options['kernel']: cmdline_options.append('intel_idle.max_cstate=0 processor.max_cstate=1') grub_util.update_kernel_cmdline_options(' '.join(cmdline_options)) return None def apply(options): # System bootup beep if 'startup_beep' in options: cmd('systemctl enable vyos-beep.service') else: cmd('systemctl disable vyos-beep.service') # Ctrl-Alt-Delete action if os.path.exists(systemd_action_file): os.unlink(systemd_action_file) if 'ctrl_alt_delete' in options: if options['ctrl_alt_delete'] == 'reboot': os.symlink('/lib/systemd/system/reboot.target', systemd_action_file) elif options['ctrl_alt_delete'] == 'poweroff': os.symlink('/lib/systemd/system/poweroff.target', systemd_action_file) # Configure HTTP client if 'http_client' not in options: if os.path.exists(curlrc_config): os.unlink(curlrc_config) # Configure SSH client if 'ssh_client' not in options: if os.path.exists(ssh_config): os.unlink(ssh_config) # Reboot system on kernel panic timeout = '0' if 'reboot_on_panic' in options: timeout = '60' with open('/proc/sys/kernel/panic', 'w') as f: f.write(timeout) # tuned - performance tuning if 'performance' in options: cmd('systemctl restart tuned.service') # wait until daemon has started before sending configuration while (not is_systemd_service_running('tuned.service')): sleep(0.250) cmd('tuned-adm profile network-{performance}'.format(**options)) else: cmd('systemctl stop tuned.service') # Keyboard layout - there will be always the default key inside the dict # but we check for key existence anyway if 'keyboard_layout' in options: cmd('loadkeys {keyboard_layout}'.format(**options)) # Enable/diable root-partition-auto-resize SystemD service if 'root_partition_auto_resize' in options: cmd('systemctl enable root-partition-auto-resize.service') else: cmd('systemctl disable root-partition-auto-resize.service') # Time format 12|24-hour if 'time_format' in options: time_format = time_format_to_locale.get(options['time_format']) cmd(f'localectl set-locale LC_TIME={time_format}') + cmd('udevadm control --reload-rules') + + if __name__ == '__main__': try: c = get_config() verify(c) generate(c) apply(c) except ConfigError as e: print(e) exit(1)