From 6e7de46eebb4f5f6a4d6438a45a621f75ab63a50 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 26 Dec 2019 17:34:58 +0100 Subject: time-zone: T1906: rename python script to system-timezone.py --- interface-definitions/system-time-zone.xml.in | 2 +- src/conf_mode/system-timezone.py | 55 +++++++++++++++++++++++++++ src/conf_mode/timezone.py | 55 --------------------------- 3 files changed, 56 insertions(+), 56 deletions(-) create mode 100755 src/conf_mode/system-timezone.py delete mode 100755 src/conf_mode/timezone.py diff --git a/interface-definitions/system-time-zone.xml.in b/interface-definitions/system-time-zone.xml.in index 1ef739735..ff815c9d3 100644 --- a/interface-definitions/system-time-zone.xml.in +++ b/interface-definitions/system-time-zone.xml.in @@ -2,7 +2,7 @@ - + Local time zone (default UTC) 100 diff --git a/src/conf_mode/system-timezone.py b/src/conf_mode/system-timezone.py new file mode 100755 index 000000000..d715bd27e --- /dev/null +++ b/src/conf_mode/system-timezone.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . + +import sys +import os + +from copy import deepcopy +from vyos.config import Config +from vyos import ConfigError + +default_config_data = { + 'name': 'UTC' +} + +def get_config(): + tz = deepcopy(default_config_data) + conf = Config() + if conf.exists('system time-zone'): + tz['name'] = conf.return_value('system time-zone') + + return tz + +def verify(tz): + pass + +def generate(tz): + pass + +def apply(tz): + cmd = '/usr/bin/timedatectl set-timezone {}'.format(tz['name']) + os.system(cmd) + pass + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + sys.exit(1) diff --git a/src/conf_mode/timezone.py b/src/conf_mode/timezone.py deleted file mode 100755 index d715bd27e..000000000 --- a/src/conf_mode/timezone.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2019 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 . - -import sys -import os - -from copy import deepcopy -from vyos.config import Config -from vyos import ConfigError - -default_config_data = { - 'name': 'UTC' -} - -def get_config(): - tz = deepcopy(default_config_data) - conf = Config() - if conf.exists('system time-zone'): - tz['name'] = conf.return_value('system time-zone') - - return tz - -def verify(tz): - pass - -def generate(tz): - pass - -def apply(tz): - cmd = '/usr/bin/timedatectl set-timezone {}'.format(tz['name']) - os.system(cmd) - pass - -if __name__ == '__main__': - try: - c = get_config() - verify(c) - generate(c) - apply(c) - except ConfigError as e: - print(e) - sys.exit(1) -- cgit v1.2.3 From 63e787e03129cd799a7fdc6078ff885cdb9b13bf Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 26 Dec 2019 17:12:28 +0100 Subject: ip: migrate 'system ip' subsystem to XML/Python --- interface-definitions/system-ip.xml.in | 58 ++++++++++++++++++++++++ src/conf_mode/system-ip.py | 81 ++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 interface-definitions/system-ip.xml.in create mode 100755 src/conf_mode/system-ip.py diff --git a/interface-definitions/system-ip.xml.in b/interface-definitions/system-ip.xml.in new file mode 100644 index 000000000..14b3b8a07 --- /dev/null +++ b/interface-definitions/system-ip.xml.in @@ -0,0 +1,58 @@ + + + + + + + IPv4 Settings + 400 + + + + + Parameters for ARP cache + + + + + Maximum number of entries to keep in the ARP cache + + 1024 2048 4096 8192 16384 32768 + + + (1024|2048|4096|8192|16384|32768) + + + + + + + + Disable IPv4 forwarding on all interfaces + + + + + + IPv4 multipath settings + + + + + Ignore next hops that are not in the ARP table + + + + + + Use layer 4 information for ECMP hashing + + + + + + + + + + diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py new file mode 100755 index 000000000..335507411 --- /dev/null +++ b/src/conf_mode/system-ip.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . + +import os + +from sys import exit +from copy import deepcopy +from vyos.config import Config +from vyos import ConfigError + +default_config_data = { + 'arp_table': 8192, + 'ipv4_forward': '1', + 'mp_unreach_nexthop': '0', + 'mp_layer4_hashing': '0' +} + +def sysctl(name, value): + os.system('sysctl -wq {}={}'.format(name, value)) + +def get_config(): + ip_opt = deepcopy(default_config_data) + conf = Config() + conf.set_level('system ip') + if conf.exists(''): + if conf.exists('arp table-size'): + ip_opt['arp_table'] = int(conf.return_value('arp table-size')) + + if conf.exists('disable-forwarding'): + ip_opt['ipv4_forward'] = '0' + + if conf.exists('multipath ignore-unreachable-nexthops'): + ip_opt['mp_unreach_nexthop'] = '1' + + if conf.exists('multipath layer4-hashing'): + ip_opt['mp_layer4_hashing'] = '1' + + return ip_opt + +def verify(ip_opt): + pass + +def generate(ip_opt): + pass + +def apply(ip_opt): + # apply ARP threshold values + sysctl('net.ipv4.neigh.default.gc_thresh3', ip_opt['arp_table']) + sysctl('net.ipv4.neigh.default.gc_thresh2', ip_opt['arp_table'] // 2) + sysctl('net.ipv4.neigh.default.gc_thresh1', ip_opt['arp_table'] // 8) + + # enable/disable IPv4 forwarding + with open('/proc/sys/net/ipv4/conf/all/forwarding', 'w') as f: + f.write(ip_opt['ipv4_forward']) + + # configure multipath + sysctl('net.ipv4.fib_multipath_use_neigh', ip_opt['mp_unreach_nexthop']) + sysctl('net.ipv4.fib_multipath_hash_policy', ip_opt['mp_layer4_hashing']) + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) -- cgit v1.2.3 From b8d41c226d70b3cc5a45f6b8dceca323c8e18bb7 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 28 Dec 2019 14:14:02 +0100 Subject: ipv6: migrate 'system ipv6' subsystem to XML/Python --- interface-definitions/system-ipv6.xml.in | 70 +++++++++++++++++ src/conf_mode/system-ipv6.py | 124 +++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 interface-definitions/system-ipv6.xml.in create mode 100755 src/conf_mode/system-ipv6.py diff --git a/interface-definitions/system-ipv6.xml.in b/interface-definitions/system-ipv6.xml.in new file mode 100644 index 000000000..623418100 --- /dev/null +++ b/interface-definitions/system-ipv6.xml.in @@ -0,0 +1,70 @@ + + + + + + + IPv6 Settings + 290 + + + + + Prevent IPv6 Kernel Module from being loaded + + + + + + Disable IPv6 forwarding on all interfaces + + + + + + Disable assignment of IPv6 addresses on all interfaces + + + + + + IPv4 multipath settings + + + + + Use layer 4 information for ECMP hashing + + + + + + + + Parameters for Neighbor cache + + + + + Maximum number of entries to keep in the Neighbor cache + + 1024 2048 4096 8192 16384 32768 + + + (1024|2048|4096|8192|16384|32768) + + + + + + + + Disable IPv6 operation on interface when DAD fails on LL addr + + + + + + + + diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py new file mode 100755 index 000000000..a39d00f9f --- /dev/null +++ b/src/conf_mode/system-ipv6.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . + +import os +import sys + +from sys import exit +from copy import deepcopy +from vyos.config import Config +from vyos import ConfigError + +ipv6_blacklist_file = '/etc/modprobe.d/vyos_blacklist_ipv6.conf' +ipv6_disable_file = '/etc/modprobe.d/vyos_disable_ipv6.conf' + +default_config_data = { + 'blacklist': False, + 'reboot_message': False, + 'ipv6_forward': '1', + 'disable_addr_assignment': False, + 'mp_layer4_hashing': '0', + 'neighbor_cache': 8192, + 'strict_dad': '1' + +} + +def sysctl(name, value): + os.system('sysctl -wq {}={}'.format(name, value)) + +def get_config(): + ip_opt = deepcopy(default_config_data) + conf = Config() + conf.set_level('system ipv6') + if conf.exists(''): + ip_opt['blacklist'] = conf.exists('blacklist') + if conf.exists_effective('blacklist') != conf.exists('blacklist'): + ip_opt['reboot_message'] = True + + ip_opt['disable_addr_assignment'] = conf.exists('disable') + if conf.exists_effective('disable') != conf.exists('disable'): + ip_opt['reboot_message'] = True + + if conf.exists('disable-forwarding'): + ip_opt['ipv6_forward'] = '0' + + if conf.exists('multipath layer4-hashing'): + ip_opt['mp_layer4_hashing'] = '1' + + if conf.exists('neighbor table-size'): + ip_opt['neighbor_cache'] = int(conf.return_value('neighbor table-size')) + + if conf.exists('strict-dad'): + ip_opt['strict_dad'] = 2 + + return ip_opt + +def verify(ip_opt): + pass + +def generate(ip_opt): + pass + +def apply(ip_opt): + # disable IPv6 kernel module + if ip_opt['blacklist']: + with open(ipv6_blacklist_file, 'w') as f: + f.write('blacklist ipv6') + else: + if os.path.exists(ipv6_blacklist_file): + os.unlink(ipv6_blacklist_file) + + # disable IPv6 address assignment + if ip_opt['disable_addr_assignment']: + with open(ipv6_disable_file, 'w') as f: + f.write('options ipv6 disable_ipv6=1') + else: + if os.path.exists(ipv6_disable_file): + os.unlink(ipv6_disable_file) + + if ip_opt['reboot_message']: + print('Changing IPv6 blacklist/disable parameter will only take affect\n' \ + 'when the system is rebooted.') + + # configure multipath + sysctl('net.ipv6.fib_multipath_hash_policy', ip_opt['mp_layer4_hashing']) + + # apply neighbor table threshold values + sysctl('net.ipv6.neigh.default.gc_thresh3', ip_opt['neighbor_cache']) + sysctl('net.ipv6.neigh.default.gc_thresh2', ip_opt['neighbor_cache'] // 2) + sysctl('net.ipv6.neigh.default.gc_thresh1', ip_opt['neighbor_cache'] // 8) + + # enable/disable IPv6 forwarding + with open('/proc/sys/net/ipv6/conf/all/forwarding', 'w') as f: + f.write(ip_opt['ipv6_forward']) + + # configure IPv6 strict-dad + for root, dirs, files in os.walk('/proc/sys/net/ipv6/conf'): + for name in files: + if name == "accept_dad": + print(os.path.join(root, name)) + with open(os.path.join(root, name), 'w') as f: + f.write(str(ip_opt['strict_dad'])) + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) -- cgit v1.2.3 From b0ca6b1fc4c365463837553e925b472dc2d7e7f6 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 28 Dec 2019 14:19:40 +0100 Subject: ipv6: T1912: remove debug print() --- src/conf_mode/system-ipv6.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py index a39d00f9f..cfbbf80ee 100755 --- a/src/conf_mode/system-ipv6.py +++ b/src/conf_mode/system-ipv6.py @@ -109,7 +109,6 @@ def apply(ip_opt): for root, dirs, files in os.walk('/proc/sys/net/ipv6/conf'): for name in files: if name == "accept_dad": - print(os.path.join(root, name)) with open(os.path.join(root, name), 'w') as f: f.write(str(ip_opt['strict_dad'])) -- cgit v1.2.3 From dcc8f87b0e2a442668b7851fb48b665c0394e86a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 28 Dec 2019 20:00:17 +0100 Subject: ipv6: T1915: remove 'system ipv6 blacklist' --- interface-definitions/system-ipv6.xml.in | 6 ----- src/conf_mode/system-ipv6.py | 16 +------------ src/migration-scripts/system/13-to-14 | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100755 src/migration-scripts/system/13-to-14 diff --git a/interface-definitions/system-ipv6.xml.in b/interface-definitions/system-ipv6.xml.in index 623418100..47fbeb4e1 100644 --- a/interface-definitions/system-ipv6.xml.in +++ b/interface-definitions/system-ipv6.xml.in @@ -8,12 +8,6 @@ 290 - - - Prevent IPv6 Kernel Module from being loaded - - - Disable IPv6 forwarding on all interfaces diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py index cfbbf80ee..bd28ec357 100755 --- a/src/conf_mode/system-ipv6.py +++ b/src/conf_mode/system-ipv6.py @@ -22,11 +22,9 @@ from copy import deepcopy from vyos.config import Config from vyos import ConfigError -ipv6_blacklist_file = '/etc/modprobe.d/vyos_blacklist_ipv6.conf' ipv6_disable_file = '/etc/modprobe.d/vyos_disable_ipv6.conf' default_config_data = { - 'blacklist': False, 'reboot_message': False, 'ipv6_forward': '1', 'disable_addr_assignment': False, @@ -44,10 +42,6 @@ def get_config(): conf = Config() conf.set_level('system ipv6') if conf.exists(''): - ip_opt['blacklist'] = conf.exists('blacklist') - if conf.exists_effective('blacklist') != conf.exists('blacklist'): - ip_opt['reboot_message'] = True - ip_opt['disable_addr_assignment'] = conf.exists('disable') if conf.exists_effective('disable') != conf.exists('disable'): ip_opt['reboot_message'] = True @@ -73,14 +67,6 @@ def generate(ip_opt): pass def apply(ip_opt): - # disable IPv6 kernel module - if ip_opt['blacklist']: - with open(ipv6_blacklist_file, 'w') as f: - f.write('blacklist ipv6') - else: - if os.path.exists(ipv6_blacklist_file): - os.unlink(ipv6_blacklist_file) - # disable IPv6 address assignment if ip_opt['disable_addr_assignment']: with open(ipv6_disable_file, 'w') as f: @@ -90,7 +76,7 @@ def apply(ip_opt): os.unlink(ipv6_disable_file) if ip_opt['reboot_message']: - print('Changing IPv6 blacklist/disable parameter will only take affect\n' \ + print('Changing IPv6 disable parameter will only take affect\n' \ 'when the system is rebooted.') # configure multipath diff --git a/src/migration-scripts/system/13-to-14 b/src/migration-scripts/system/13-to-14 new file mode 100755 index 000000000..c055dad1f --- /dev/null +++ b/src/migration-scripts/system/13-to-14 @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# +# Delete 'system ipv6 blacklist' option as the IPv6 module can no longer be +# blacklisted as it is required by e.g. WireGuard and thus will always be +# loaded. + +import os +import sys + +ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf' + +from vyos.configtree import ConfigTree + +if (len(sys.argv) < 1): + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) +ip_base = ['system', 'ipv6'] +if not config.exists(ip_base): + # Nothing to do + sys.exit(0) +else: + # delete 'system ipv6 blacklist' node + if config.exists(ip_base + ['blacklist']): + config.delete(ip_base + ['blacklist']) + if os.path.isfile(ipv6_blacklist_file): + os.unlink(ipv6_blacklist_file) + + try: + with open(file_name, 'w') as f: + f.write(config.to_string()) + except OSError as e: + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) -- cgit v1.2.3 From 22148286648c8e51fa0fa13649907b6112223dad Mon Sep 17 00:00:00 2001 From: zsdc Date: Fri, 27 Dec 2019 23:17:40 +0200 Subject: FRRouting: T1514: Added commands to restart FRRouting daemon It can be restarted the whole FRRouting (all running) daemons or only selected ones. The configuration is saving during the restart process, so after it, the active config should be the same as before. There are no checks for safety, so responsibility for the results of running command is fully on the operator. --- op-mode-definitions/restart-frr.xml | 63 ++++++++++++++++++++++ src/op_mode/restart_frr.py | 103 ++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 op-mode-definitions/restart-frr.xml create mode 100755 src/op_mode/restart_frr.py diff --git a/op-mode-definitions/restart-frr.xml b/op-mode-definitions/restart-frr.xml new file mode 100644 index 000000000..4b649febd --- /dev/null +++ b/op-mode-definitions/restart-frr.xml @@ -0,0 +1,63 @@ + + + + + + + Restart FRRouting daemons + + ${vyos_op_scripts_dir}/restart_frr.py --action restart + + + + Restart Bidirectional Forwarding Detection daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bfdd + + + + Restart Border Gateway Protocol daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bgpd + + + + Restart OSPFv2 daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospfd + + + + Restart OSPFv3 daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospf6d + + + + Restart Routing Information Protocol daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripd + + + + Restart RIPng daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripngd + + + + Restart Static Route daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon staticd + + + + Restart IP routing manager daemon + + ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon zebra + + + + + + diff --git a/src/op_mode/restart_frr.py b/src/op_mode/restart_frr.py new file mode 100755 index 000000000..d94465603 --- /dev/null +++ b/src/op_mode/restart_frr.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . +# + +import sys +import argparse +import subprocess +import logging +from logging.handlers import SysLogHandler + +# some default values +watchfrr = '/usr/lib/frr/watchfrr.sh' +vtysh = '/usr/bin/vtysh' + +# configure logging +logger = logging.getLogger(__name__) +logs_handler = SysLogHandler('/dev/log') +logs_handler.setFormatter(logging.Formatter('%(filename)s: %(message)s')) +logger.addHandler(logs_handler) +logger.setLevel(logging.INFO) + +# write active config to file +def _write_config(): + command = "sudo {} -n -c write ".format(vtysh) + return_code = subprocess.call(command, shell=True) + if not return_code == 0: + logger.error("Failed to save active config: \"{}\" returned exit code: {}".format(command, return_code)) + print("Failed to save active config: \"{}\" returned exit code: {}".format(command, return_code)) + sys.exit(1) + logger.info("Active config saved to /etc/frr/frr.conf") + +# check if daemon is running +def _daemon_check(daemon): + command = "sudo {} print_status {}".format(watchfrr, daemon) + return_code = subprocess.call(command, shell=True) + if not return_code == 0: + logger.error("Daemon \"{}\" is not running".format(daemon)) + return False + + # return True if all checks were passed + return True + +# restart daemon +def _daemon_restart(daemon): + command = "sudo {} restart {}".format(watchfrr, daemon) + return_code = subprocess.call(command, shell=True) + if not return_code == 0: + logger.error("Failed to restart daemon \"{}\"".format(daemon)) + return False + + # return True if restarted sucessfully + logger.info("Daemon \"{}\" restarted".format(daemon)) + return True + +# check all daemons if they are running +def _check_args_daemon(daemons): + for daemon in daemons: + if not _daemon_check(daemon): + return False + return True + +# define program arguments +cmd_args_parser = argparse.ArgumentParser(description='restart frr daemons') +cmd_args_parser.add_argument('--action', choices=['restart'], required=True, help='action to frr daemons') +cmd_args_parser.add_argument('--daemon', choices=['bfdd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'staticd', 'zebra'], required=False, nargs='*', help='select single or multiple daemons') +# parse arguments +cmd_args = cmd_args_parser.parse_args() + + +# main logic +# restart daemon +if cmd_args.action == 'restart': + _write_config() + if cmd_args.daemon: + # check all daemons if they are running + if not _check_args_daemon(cmd_args.daemon): + print("Warning: some of listed daemons are not running") + + # run command to restart daemon + for daemon in cmd_args.daemon: + if not _daemon_restart(daemon): + print("Failed to restart daemon: {}".format(daemon)) + sys.exit(1) + else: + # run command to restart FRR + if not _daemon_restart(''): + print("Failed to restart FRRouting") + sys.exit(1) + +sys.exit(0) -- cgit v1.2.3 From 9196be8fe3a37ee7dd7308243f5b0017e13d08b1 Mon Sep 17 00:00:00 2001 From: zsdc Date: Fri, 27 Dec 2019 23:55:09 +0200 Subject: FRRouting: T1514: Fix in FRRouting restart command Added saving and restoring current frr.conf to avoid reapplying of configuration from it during reboot. --- src/op_mode/restart_frr.py | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/op_mode/restart_frr.py b/src/op_mode/restart_frr.py index d94465603..085b8c355 100755 --- a/src/op_mode/restart_frr.py +++ b/src/op_mode/restart_frr.py @@ -24,6 +24,8 @@ from logging.handlers import SysLogHandler # some default values watchfrr = '/usr/lib/frr/watchfrr.sh' vtysh = '/usr/bin/vtysh' +frrconfig = '/etc/frr/frr.conf' +frrconfig_tmp = '/etc/frr/frr.conf.temporary' # configure logging logger = logging.getLogger(__name__) @@ -32,15 +34,32 @@ logs_handler.setFormatter(logging.Formatter('%(filename)s: %(message)s')) logger.addHandler(logs_handler) logger.setLevel(logging.INFO) +# save or restore current config file +def _save_and_restore(action): + if action == "save": + command = "sudo mv {} {}".format(frrconfig, frrconfig_tmp) + logmsg = "Permanent configuration saved to {}".format(frrconfig_tmp) + if action == "restore": + command = "sudo mv {} {}".format(frrconfig_tmp, frrconfig) + logmsg = "Permanent configuration restored from {}".format(frrconfig_tmp) + + return_code = subprocess.call(command, shell=True) + if not return_code == 0: + logger.error("Failed to rename permanent config: \"{}\" returned exit code: {}".format(command, return_code)) + return False + + logger.info(logmsg) + return True + # write active config to file def _write_config(): command = "sudo {} -n -c write ".format(vtysh) return_code = subprocess.call(command, shell=True) if not return_code == 0: logger.error("Failed to save active config: \"{}\" returned exit code: {}".format(command, return_code)) - print("Failed to save active config: \"{}\" returned exit code: {}".format(command, return_code)) - sys.exit(1) - logger.info("Active config saved to /etc/frr/frr.conf") + return False + logger.info("Active config saved to {}".format(frrconfig)) + return True # check if daemon is running def _daemon_check(daemon): @@ -83,7 +102,16 @@ cmd_args = cmd_args_parser.parse_args() # main logic # restart daemon if cmd_args.action == 'restart': - _write_config() + if not _save_and_restore('save'): + logger.error("Failed to rename permanent comfig") + print("Failed to rename permanent comfig") + sys.exit(1) + + if not _write_config(): + print("Failed to save active config") + _save_and_restore('restore') + sys.exit(1) + if cmd_args.daemon: # check all daemons if they are running if not _check_args_daemon(cmd_args.daemon): @@ -93,11 +121,15 @@ if cmd_args.action == 'restart': for daemon in cmd_args.daemon: if not _daemon_restart(daemon): print("Failed to restart daemon: {}".format(daemon)) + _save_and_restore('restore') sys.exit(1) else: # run command to restart FRR if not _daemon_restart(''): print("Failed to restart FRRouting") + _save_and_restore('restore') sys.exit(1) + _save_and_restore('restore') + sys.exit(0) -- cgit v1.2.3 From 30d0c3c8525b8e39fc7536f5acc424f42d5fe821 Mon Sep 17 00:00:00 2001 From: DmitriyEshenko Date: Sun, 29 Dec 2019 19:02:32 +0000 Subject: l2tp: T1918: Add check and create tunnels folder --- src/conf_mode/ipsec-settings.py | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/conf_mode/ipsec-settings.py b/src/conf_mode/ipsec-settings.py index 331a62316..aab3e9734 100755 --- a/src/conf_mode/ipsec-settings.py +++ b/src/conf_mode/ipsec-settings.py @@ -32,14 +32,15 @@ from vyos import ConfigError ra_conn_name = "remote-access" charon_conf_file = "/etc/strongswan.d/charon.conf" ipsec_secrets_flie = "/etc/ipsec.secrets" -ipsec_ra_conn_file = "/etc/ipsec.d/tunnels/"+ra_conn_name +ipsec_ra_conn_dir = "/etc/ipsec.d/tunnels/" +ipsec_ra_conn_file = ipsec_ra_conn_dir + ra_conn_name ipsec_conf_flie = "/etc/ipsec.conf" -ca_cert_path = '/etc/ipsec.d/cacerts' -server_cert_path = '/etc/ipsec.d/certs' -server_key_path = '/etc/ipsec.d/private' +ca_cert_path = "/etc/ipsec.d/cacerts" +server_cert_path = "/etc/ipsec.d/certs" +server_key_path = "/etc/ipsec.d/private" delim_ipsec_l2tp_begin = "### VyOS L2TP VPN Begin ###" delim_ipsec_l2tp_end = "### VyOS L2TP VPN End ###" -charon_pidfile = '/var/run/charon.pid' +charon_pidfile = "/var/run/charon.pid" l2pt_ipsec_conf = ''' {{delim_ipsec_l2tp_begin}} @@ -147,21 +148,27 @@ def get_config(): ### ipsec secret l2tp def write_ipsec_secrets(c): - tmpl = jinja2.Template(l2pt_ipsec_secrets_conf, trim_blocks=True) - l2pt_ipsec_secrets_txt = tmpl.render(c) - old_umask = os.umask(0o077) - open(ipsec_secrets_flie,'w').write(l2pt_ipsec_secrets_txt) - os.umask(old_umask) - sl.syslog(sl.LOG_NOTICE, ipsec_secrets_flie + ' written') + tmpl = jinja2.Template(l2pt_ipsec_secrets_conf, trim_blocks=True) + l2pt_ipsec_secrets_txt = tmpl.render(c) + old_umask = os.umask(0o077) + open(ipsec_secrets_flie,'w').write(l2pt_ipsec_secrets_txt) + os.umask(old_umask) + sl.syslog(sl.LOG_NOTICE, ipsec_secrets_flie + ' written') ### ipsec remote access connection config def write_ipsec_ra_conn(c): - tmpl = jinja2.Template(l2tp_ipsec_ra_conn_conf, trim_blocks=True) - ipsec_ra_conn_txt = tmpl.render(c) - old_umask = os.umask(0o077) - open(ipsec_ra_conn_file,'w').write(ipsec_ra_conn_txt) - os.umask(old_umask) - sl.syslog(sl.LOG_NOTICE, ipsec_ra_conn_file + ' written') + tmpl = jinja2.Template(l2tp_ipsec_ra_conn_conf, trim_blocks=True) + ipsec_ra_conn_txt = tmpl.render(c) + old_umask = os.umask(0o077) + + # Create tunnels directory if does not exist + if not os.path.exists(ipsec_ra_conn_dir): + os.makedirs(ipsec_ra_conn_dir) + sl.syslog(sl.LOG_NOTICE, ipsec_ra_conn_dir + " created") + + open(ipsec_ra_conn_file,'w').write(ipsec_ra_conn_txt) + os.umask(old_umask) + sl.syslog(sl.LOG_NOTICE, ipsec_ra_conn_file + ' written') ### Remove config from file by delimiter def remove_confs(delim_begin, delim_end, conf_file): -- cgit v1.2.3 From 685e9fb19140d002bcae9f3b78d5bd0f33b172d0 Mon Sep 17 00:00:00 2001 From: DmitriyEshenko Date: Mon, 30 Dec 2019 11:50:15 +0000 Subject: l2tp: T1858: Delete deprecated outside-nexthop --- interface-definitions/l2tp-server.xml.in | 4 ++-- src/conf_mode/accel_l2tp.py | 24 ++++++++++------------- src/migration-scripts/l2tp/1-to-2 | 33 ++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 16 deletions(-) create mode 100755 src/migration-scripts/l2tp/1-to-2 diff --git a/interface-definitions/l2tp-server.xml.in b/interface-definitions/l2tp-server.xml.in index 98c17b8b2..7fc844054 100644 --- a/interface-definitions/l2tp-server.xml.in +++ b/interface-definitions/l2tp-server.xml.in @@ -28,9 +28,9 @@ - + - Nexthop IP address for reaching the VPN clients + Gatway address uses as client tunnel termination point diff --git a/src/conf_mode/accel_l2tp.py b/src/conf_mode/accel_l2tp.py index 37fda2029..a7af9cc68 100755 --- a/src/conf_mode/accel_l2tp.py +++ b/src/conf_mode/accel_l2tp.py @@ -118,15 +118,15 @@ secret={{lns_shared_secret}} {% endfor -%} {% endif %} {% endif %} -{% if outside_nexthop %} -gw-ip-address={{outside_nexthop}} +{% if gateway_address %} +gw-ip-address={{gateway_address}} {% endif %} {% if authentication['mode'] == 'local' %} [chap-secrets] chap-secrets=/etc/accel-ppp/l2tp/chap-secrets -{% if outside_nexthop %} -gw-ip-address={{outside_nexthop}} +{% if gateway_address %} +gw-ip-address={{gateway_address}} {% endif %} {% endif %} @@ -181,7 +181,7 @@ dae-server={{authentication['radiusopt']['dae-srv']['ip-addr']}}:\ {{authentication['radiusopt']['dae-srv']['port']}},\ {{authentication['radiusopt']['dae-srv']['secret']}} {% endif -%} -gw-ip-address={{outside_nexthop}} +gw-ip-address={{gateway_address}} verbose=1 {% endif -%} @@ -290,7 +290,7 @@ def get_config(): 'mppe' : 'prefer' }, 'outside_addr' : '', - 'outside_nexthop' : '10.255.255.0', + 'gateway_address' : '10.255.255.0', 'dns' : [], 'dnsv6' : [], 'wins' : [], @@ -430,17 +430,17 @@ def get_config(): config_data['mtu'] = c.return_value('mtu') ### gateway address - if c.exists('outside-nexthop'): - config_data['outside_nexthop'] = c.return_value('outside-nexthop') + if c.exists('gateway-address'): + config_data['gateway_address'] = c.return_value('gateway-address') else: ### calculate gw-ip-address if c.exists('client-ip-pool start'): ### use start ip as gw-ip-address - config_data['outside_nexthop'] = c.return_value('client-ip-pool start') + config_data['gateway_address'] = c.return_value('client-ip-pool start') elif c.exists('client-ip-pool subnet'): ### use first ip address from first defined pool lst_ip = re.findall("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", c.return_values('client-ip-pool subnet')[0]) - config_data['outside_nexthop'] = lst_ip[0] + config_data['gateway_address'] = lst_ip[0] if c.exists('authentication require'): auth_mods = {'pap' : 'pap','chap' : 'auth_chap_md5', 'mschap' : 'auth_mschap_v1', 'mschap-v2' : 'auth_mschap_v2'} @@ -497,10 +497,6 @@ def verify(c): if not c['client_ip_pool'] and not c['client_ip_subnets']: raise ConfigError("set vpn l2tp remote-access client-ip-pool requires subnet or start/stop IP pool") - if not c['outside_nexthop']: - #raise ConfigError('set vpn l2tp remote-access outside-nexthop required') - print ("WARMING: set vpn l2tp remote-access outside-nexthop required") - ## check ipv6 if 'delegate_prefix' in c['client_ipv6_pool'] and not 'prefix' in c['client_ipv6_pool']: raise ConfigError("\"set vpn l2tp remote-access client-ipv6-pool prefix\" required for delegate-prefix ") diff --git a/src/migration-scripts/l2tp/1-to-2 b/src/migration-scripts/l2tp/1-to-2 new file mode 100755 index 000000000..c46eba8f8 --- /dev/null +++ b/src/migration-scripts/l2tp/1-to-2 @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +# Delete depricated outside-nexthop address + +import sys + +from vyos.configtree import ConfigTree + +if (len(sys.argv) < 1): + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) + +cfg_base = ['vpn', 'l2tp', 'remote-access'] +if not config.exists(cfg_base): + # Nothing to do + sys.exit(0) +else: + if config.exists(cfg_base + ['outside-nexthop']): + config.delete(cfg_base + ['outside-nexthop']) + + try: + with open(file_name, 'w') as f: + f.write(config.to_string()) + except OSError as e: + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) -- cgit v1.2.3 From ef3b8d81fc98a43e6a7605ea807667ad8b674bd9 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 30 Dec 2019 13:00:22 +0100 Subject: list_interfaces: remove duplicate list of wireless interfaces --- src/completion/list_interfaces.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/completion/list_interfaces.py b/src/completion/list_interfaces.py index f336968a6..0ed683074 100755 --- a/src/completion/list_interfaces.py +++ b/src/completion/list_interfaces.py @@ -32,10 +32,9 @@ elif args.bridgeable: bond = vyos.interfaces.list_interfaces_of_type("bonding") l2tpv3 = vyos.interfaces.list_interfaces_of_type("l2tpv3") openvpn = vyos.interfaces.list_interfaces_of_type("openvpn") - vxlan = vyos.interfaces.list_interfaces_of_type("vxlan") wireless = vyos.interfaces.list_interfaces_of_type("wireless") tunnel = vyos.interfaces.list_interfaces_of_type("tunnel") - wireless = vyos.interfaces.list_interfaces_of_type("wireless") + vxlan = vyos.interfaces.list_interfaces_of_type("vxlan") geneve = vyos.interfaces.list_interfaces_of_type("geneve") interfaces = eth + bond + l2tpv3 + openvpn + vxlan + tunnel + wireless + geneve -- cgit v1.2.3 From b9a6dab2d4f162eba59b9eec989b1de1b249f3fd Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 30 Dec 2019 14:42:04 +0100 Subject: options: T1919: migrate 'system options' to XML/Python representation --- Makefile | 1 - interface-definitions/system-options.xml.in | 45 ++++++++++++++++ src/conf_mode/system-options.py | 81 +++++++++++++++++++++++++++++ src/migration-scripts/system/14-to-15 | 38 ++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 interface-definitions/system-options.xml.in create mode 100755 src/conf_mode/system-options.py create mode 100755 src/migration-scripts/system/14-to-15 diff --git a/Makefile b/Makefile index c085872a1..ee0bf3ce9 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,6 @@ interface_definitions: $(BUILD_DIR) $(obj) rm -f $(TMPL_DIR)/protocols/node.def rm -f $(TMPL_DIR)/protocols/static/node.def rm -f $(TMPL_DIR)/system/node.def - rm -f $(TMPL_DIR)/system/options/node.def rm -f $(TMPL_DIR)/vpn/node.def rm -f $(TMPL_DIR)/vpn/ipsec/node.def diff --git a/interface-definitions/system-options.xml.in b/interface-definitions/system-options.xml.in new file mode 100644 index 000000000..5fa0635bd --- /dev/null +++ b/interface-definitions/system-options.xml.in @@ -0,0 +1,45 @@ + + + + + + + System Options + 400 + + + + + Ctrl-Alt-Delete action + + ignore reboot poweroff + + + ignore + Ignore Ctrl-Alt-Delete + + + reboot + Reboot VyOS + + + poweroff + Poweroff VyOS + + + (ignore|reboot|poweroff) + + Must be ignore, reboot, or poweroff + + + + + Reboot system on kernel panic + + + + + + + + diff --git a/src/conf_mode/system-options.py b/src/conf_mode/system-options.py new file mode 100755 index 000000000..4c809d044 --- /dev/null +++ b/src/conf_mode/system-options.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . + +import os + +from sys import exit +from copy import deepcopy +from vyos.config import Config +from vyos import ConfigError + +systemd_ctrl_alt_del = '/lib/systemd/system/ctrl-alt-del.target' + +default_config_data = { + 'ctrl_alt_del': 'ignore', + 'reboot_on_panic': True +} + +def get_config(): + opt = deepcopy(default_config_data) + conf = Config() + conf.set_level('system options') + if conf.exists(''): + if conf.exists('ctrl-alt-del-action'): + opt['ctrl_alt_del'] = conf.return_value('ctrl-alt-del-action') + + opt['reboot_on_panic'] = conf.exists('reboot-on-panic') + + return opt + +def verify(opt): + pass + +def generate(opt): + pass + +def apply(opt): + + # Ctrl-Alt-Delete action + if opt['ctrl_alt_del'] == 'ignore': + os.unlink('/lib/systemd/system/ctrl-alt-del.target') + + elif opt['ctrl_alt_del'] == 'reboot': + if os.path.exists(systemd_ctrl_alt_del): + os.unlink(systemd_ctrl_alt_del) + os.symlink('/lib/systemd/system/reboot.target', systemd_ctrl_alt_del) + + elif opt['ctrl_alt_del'] == 'poweroff': + if os.path.exists(systemd_ctrl_alt_del): + os.unlink(systemd_ctrl_alt_del) + os.symlink('/lib/systemd/system/poweroff.target', systemd_ctrl_alt_del) + + # Reboot system on kernel panic + with open('/proc/sys/kernel/panic', 'w') as f: + if opt['reboot_on_panic']: + f.write('60') + else: + f.write('0') + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) + diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15 new file mode 100755 index 000000000..fd89ae57a --- /dev/null +++ b/src/migration-scripts/system/14-to-15 @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# Make 'system options reboot-on-panic' valueless + +import os +import sys + +from vyos.configtree import ConfigTree + +if (len(sys.argv) < 1): + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) +base = ['system', 'options'] +if not config.exists(base): + # Nothing to do + sys.exit(0) +else: + # delete 'system ipv6 blacklist' node + if config.exists(base + ['reboot-on-panic']): + reboot = config.return_value(base + ['reboot-on-panic']) + config.delete(base + ['reboot-on-panic']) + # create new valueless node if action was true + if reboot == "true": + config.set(base + ['reboot-on-panic']) + + try: + with open(file_name, 'w') as f: + f.write(config.to_string()) + except OSError as e: + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) -- cgit v1.2.3