diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/interfaces-wirelessmodem.py | 132 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-wwan.py | 86 | ||||
-rwxr-xr-x | src/conf_mode/vpn_ipsec.py | 3 | ||||
-rw-r--r-- | src/etc/systemd/system/ModemManager.service.d/override.conf | 7 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/18-to-19 | 174 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/19-to-20 | 130 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/20-to-21 | 59 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/21-to-22 | 60 | ||||
-rwxr-xr-x | src/op_mode/show_wwan.py | 78 | ||||
-rwxr-xr-x | src/validators/interface-name | 2 | ||||
-rwxr-xr-x | src/validators/vrf-name | 2 |
11 files changed, 440 insertions, 293 deletions
diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py deleted file mode 100755 index 976953b31..000000000 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020 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 vyos.config import Config -from vyos.configdict import get_interface_dict -from vyos.configverify import verify_vrf -from vyos.template import render -from vyos.util import call -from vyos.util import check_kmod -from vyos.util import find_device_file -from vyos import ConfigError -from vyos import airbag -airbag.enable() - -k_mod = ['option', 'usb_wwan', 'usbserial'] - -def get_config(config=None): - """ - Retrive CLI config as dictionary. Dictionary can never be empty, as at least the - interface name will be added or a deleted flag - """ - if config: - conf = config - else: - conf = Config() - base = ['interfaces', 'wirelessmodem'] - wwan = get_interface_dict(conf, base) - - return wwan - -def verify(wwan): - if 'deleted' in wwan: - return None - - if not 'apn' in wwan: - raise ConfigError('No APN configured for "{ifname}"'.format(**wwan)) - - if not 'device' in wwan: - raise ConfigError('Physical "device" must be configured') - - # we can not use isfile() here as Linux device files are no regular files - # thus the check will return False - dev_path = find_device_file(wwan['device']) - if dev_path is None or not os.path.exists(dev_path): - raise ConfigError('Device "{device}" does not exist'.format(**wwan)) - - verify_vrf(wwan) - - return None - -def generate(wwan): - # set up configuration file path variables where our templates will be - # rendered into - ifname = wwan['ifname'] - config_wwan = f'/etc/ppp/peers/{ifname}' - config_wwan_chat = f'/etc/ppp/peers/chat.{ifname}' - script_wwan_pre_up = f'/etc/ppp/ip-pre-up.d/1010-vyos-wwan-{ifname}' - script_wwan_ip_up = f'/etc/ppp/ip-up.d/1010-vyos-wwan-{ifname}' - script_wwan_ip_down = f'/etc/ppp/ip-down.d/1010-vyos-wwan-{ifname}' - - config_files = [config_wwan, config_wwan_chat, script_wwan_pre_up, - script_wwan_ip_up, script_wwan_ip_down] - - # Always hang-up WWAN connection prior generating new configuration file - call(f'systemctl stop ppp@{ifname}.service') - - if 'deleted' in wwan: - # Delete PPP configuration files - for file in config_files: - if os.path.exists(file): - os.unlink(file) - - else: - wwan['device'] = find_device_file(wwan['device']) - - # Create PPP configuration files - render(config_wwan, 'wwan/peer.tmpl', wwan) - # Create PPP chat script - render(config_wwan_chat, 'wwan/chat.tmpl', wwan) - - # generated script file must be executable - - # Create script for ip-pre-up.d - render(script_wwan_pre_up, 'wwan/ip-pre-up.script.tmpl', - wwan, permission=0o755) - # Create script for ip-up.d - render(script_wwan_ip_up, 'wwan/ip-up.script.tmpl', - wwan, permission=0o755) - # Create script for ip-down.d - render(script_wwan_ip_down, 'wwan/ip-down.script.tmpl', - wwan, permission=0o755) - - return None - -def apply(wwan): - if 'deleted' in wwan: - # bail out early - return None - - if not 'disable' in wwan: - # "dial" WWAN connection - call('systemctl start ppp@{ifname}.service'.format(**wwan)) - - return None - -if __name__ == '__main__': - try: - check_kmod(k_mod) - c = get_config() - verify(c) - generate(c) - apply(c) - except ConfigError as e: - print(e) - exit(1) diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py new file mode 100755 index 000000000..02d2c723d --- /dev/null +++ b/src/conf_mode/interfaces-wwan.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020-2021 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 vyos.config import Config +from vyos.configdict import get_interface_dict +from vyos.configverify import verify_interface_exists +from vyos.configverify import verify_vrf +from vyos.ifconfig import WWANIf +from vyos.util import cmd +from vyos.template import render +from vyos import ConfigError +from vyos import airbag +airbag.enable() + +def get_config(config=None): + """ + Retrive CLI config as dictionary. Dictionary can never be empty, as at least the + interface name will be added or a deleted flag + """ + if config: + conf = config + else: + conf = Config() + base = ['interfaces', 'wwan'] + wwan = get_interface_dict(conf, base) + + return wwan + +def verify(wwan): + if 'deleted' in wwan: + return None + + ifname = wwan['ifname'] + if not 'apn' in wwan: + raise ConfigError(f'No APN configured for "{ifname}"!') + + verify_interface_exists(ifname) + verify_vrf(wwan) + + return None + +def generate(wwan): + return None + +def apply(wwan): + # we only need the modem number. wwan0 -> 0, wwan1 -> 1 + modem = wwan['ifname'].replace('wwan','') + base_cmd = f'mmcli --modem {modem}' + + w = WWANIf(wwan['ifname']) + if 'deleted' in wwan or 'disable' in wwan: + w.remove() + cmd(f'{base_cmd} --simple-disconnect') + return None + + cmd(f'{base_cmd} --simple-connect=\"apn={wwan["apn"]}\"') + w.update(wwan) + + return None + +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/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py index 3eaa78a4b..f80a9455a 100755 --- a/src/conf_mode/vpn_ipsec.py +++ b/src/conf_mode/vpn_ipsec.py @@ -25,6 +25,7 @@ from vyos.configverify import verify_interface_exists from vyos.ifconfig import Interface from vyos.template import ip_from_cidr from vyos.template import render +from vyos.validate import is_ipv6_link_local from vyos.util import call from vyos.util import dict_search from vyos.util import get_interface_address @@ -173,7 +174,7 @@ def get_dhcp_address(iface): if not addresses: return None for address in addresses: - if not address.startswith("fe80:"): # Skip link-local ipv6 + if not is_ipv6_link_local(address): return ip_from_cidr(address) return None diff --git a/src/etc/systemd/system/ModemManager.service.d/override.conf b/src/etc/systemd/system/ModemManager.service.d/override.conf new file mode 100644 index 000000000..07a18460e --- /dev/null +++ b/src/etc/systemd/system/ModemManager.service.d/override.conf @@ -0,0 +1,7 @@ +[Unit] +After= +After=vyos-router.service + +[Service] +ExecStart= +ExecStart=/usr/sbin/ModemManager --filter-policy=strict --log-level=INFO --log-timestamps --log-journal diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 index 06e07572f..a12c4a6cd 100755 --- a/src/migration-scripts/interfaces/18-to-19 +++ b/src/migration-scripts/interfaces/18-to-19 @@ -14,65 +14,31 @@ # 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 argv from sys import exit -from vyos.configtree import ConfigTree - -def migrate_ospf(config, path, interface): - path = path + ['ospf'] - if config.exists(path): - new_base = ['protocols', 'ospf', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - - # if "ip ospf" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) - -def migrate_ospfv3(config, path, interface): - path = path + ['ospfv3'] - if config.exists(path): - new_base = ['protocols', 'ospfv3', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - # if "ipv6 ospfv3" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) - -def migrate_rip(config, path, interface): - path = path + ['rip'] - if config.exists(path): - new_base = ['protocols', 'rip', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - - # if "ip rip" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) +from vyos.configtree import ConfigTree -def migrate_ripng(config, path, interface): - path = path + ['ripng'] - if config.exists(path): - new_base = ['protocols', 'ripng', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) +def replace_nat_interfaces(config, old, new): + if not config.exists(['nat']): + return + for direction in ['destination', 'source']: + conf_direction = ['nat', direction, 'rule'] + if not config.exists(conf_direction): + return + for rule in config.list_nodes(conf_direction): + conf_rule = conf_direction + [rule] + if config.exists(conf_rule + ['inbound-interface']): + tmp = config.return_value(conf_rule + ['inbound-interface']) + if tmp == old: + config.set(conf_rule + ['inbound-interface'], value=new) + if config.exists(conf_rule + ['outbound-interface']): + tmp = config.return_value(conf_rule + ['outbound-interface']) + if tmp == old: + config.set(conf_rule + ['outbound-interface'], value=new) - # if "ipv6 ripng" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) if __name__ == '__main__': if (len(argv) < 1): @@ -80,62 +46,58 @@ if __name__ == '__main__': exit(1) file_name = argv[1] + with open(file_name, 'r') as f: config_file = f.read() config = ConfigTree(config_file) - - # - # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" - # - for type in config.list_nodes(['interfaces']): - for interface in config.list_nodes(['interfaces', type]): - ip_base = ['interfaces', type, interface, 'ip'] - ipv6_base = ['interfaces', type, interface, 'ipv6'] - migrate_rip(config, ip_base, interface) - migrate_ripng(config, ipv6_base, interface) - migrate_ospf(config, ip_base, interface) - migrate_ospfv3(config, ipv6_base, interface) - - vif_path = ['interfaces', type, interface, 'vif'] - if config.exists(vif_path): - for vif in config.list_nodes(vif_path): - vif_ip_base = vif_path + [vif, 'ip'] - vif_ipv6_base = vif_path + [vif, 'ipv6'] - ifname = f'{interface}.{vif}' - - migrate_rip(config, vif_ip_base, ifname) - migrate_ripng(config, vif_ipv6_base, ifname) - migrate_ospf(config, vif_ip_base, ifname) - migrate_ospfv3(config, vif_ipv6_base, ifname) - - - vif_s_path = ['interfaces', type, interface, 'vif-s'] - if config.exists(vif_s_path): - for vif_s in config.list_nodes(vif_s_path): - vif_s_ip_base = vif_s_path + [vif_s, 'ip'] - vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] - - # vif-c interfaces MUST be migrated before their parent vif-s - # interface as the migrate_*() functions delete the path! - vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] - if config.exists(vif_c_path): - for vif_c in config.list_nodes(vif_c_path): - vif_c_ip_base = vif_c_path + [vif_c, 'ip'] - vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] - ifname = f'{interface}.{vif_s}.{vif_c}' - - migrate_rip(config, vif_c_ip_base, ifname) - migrate_ripng(config, vif_c_ipv6_base, ifname) - migrate_ospf(config, vif_c_ip_base, ifname) - migrate_ospfv3(config, vif_c_ipv6_base, ifname) - - - ifname = f'{interface}.{vif_s}' - migrate_rip(config, vif_s_ip_base, ifname) - migrate_ripng(config, vif_s_ipv6_base, ifname) - migrate_ospf(config, vif_s_ip_base, ifname) - migrate_ospfv3(config, vif_s_ipv6_base, ifname) + base = ['interfaces', 'wirelessmodem'] + if not config.exists(base): + # Nothing to do + exit(0) + + new_base = ['interfaces', 'wwan'] + config.set(new_base) + config.set_tag(new_base) + for old_interface in config.list_nodes(base): + # convert usb0b1.3p1.2 device identifier and extract 1.3 usb bus id + usb = config.return_value(base + [old_interface, 'device']) + device = usb.split('b')[-1] + busid = device.split('p')[0] + for new_interface in os.listdir('/sys/class/net'): + # we are only interested in interfaces starting with wwan + if not new_interface.startswith('wwan'): + continue + device = os.readlink(f'/sys/class/net/{new_interface}/device') + device = device.split(':')[0] + if busid in device: + config.copy(base + [old_interface], new_base + [new_interface]) + replace_nat_interfaces(config, old_interface, new_interface) + + config.delete(base) + + # Now that we have copied the old wirelessmodem interfaces to wwan + # we can start to migrate also individual config items. + for interface in config.list_nodes(new_base): + # we do no longer need the USB device name + config.delete(new_base + [interface, 'device']) + # set/unset DNS configuration + dns = new_base + [interface, 'no-peer-dns'] + if config.exists(dns): + config.delete(dns) + else: + config.set(['system', 'name-servers-dhcp'], value=interface, replace=False) + + # Backup distance is now handled by DHCP option "default-route-distance" + distance = dns = new_base + [interface, 'backup', 'distance'] + old_default_distance = '10' + if config.exists(distance): + old_default_distance = config.return_value(distance) + config.delete(distance) + config.set(new_base + [interface, 'dhcp-options', 'default-route-distance'], value=old_default_distance) + + # the new wwan interface use regular IP addressing + config.set(new_base + [interface, 'address'], value='dhcp') try: with open(file_name, 'w') as f: diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 index e96663e54..06e07572f 100755 --- a/src/migration-scripts/interfaces/19-to-20 +++ b/src/migration-scripts/interfaces/19-to-20 @@ -18,6 +18,62 @@ from sys import argv from sys import exit from vyos.configtree import ConfigTree +def migrate_ospf(config, path, interface): + path = path + ['ospf'] + if config.exists(path): + new_base = ['protocols', 'ospf', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip ospf" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ospfv3(config, path, interface): + path = path + ['ospfv3'] + if config.exists(path): + new_base = ['protocols', 'ospfv3', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ospfv3" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_rip(config, path, interface): + path = path + ['rip'] + if config.exists(path): + new_base = ['protocols', 'rip', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip rip" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ripng(config, path, interface): + path = path + ['ripng'] + if config.exists(path): + new_base = ['protocols', 'ripng', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ripng" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + if __name__ == '__main__': if (len(argv) < 1): print("Must specify file name!") @@ -29,29 +85,57 @@ if __name__ == '__main__': config = ConfigTree(config_file) - for type in ['tunnel', 'l2tpv3']: - base = ['interfaces', type] - if not config.exists(base): - # Nothing to do - continue - - for interface in config.list_nodes(base): - # Migrate "interface tunnel <tunX> encapsulation gre-bridge" to gretap - encap_path = base + [interface, 'encapsulation'] - if type == 'tunnel' and config.exists(encap_path): - tmp = config.return_value(encap_path) - if tmp == 'gre-bridge': - config.set(encap_path, value='gretap') - - # Migrate "interface tunnel|l2tpv3 <interface> local-ip" to source-address - # Migrate "interface tunnel|l2tpv3 <interface> remote-ip" to remote - local_ip_path = base + [interface, 'local-ip'] - if config.exists(local_ip_path): - config.rename(local_ip_path, 'source-address') - - remote_ip_path = base + [interface, 'remote-ip'] - if config.exists(remote_ip_path): - config.rename(remote_ip_path, 'remote') + # + # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" + # + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + ip_base = ['interfaces', type, interface, 'ip'] + ipv6_base = ['interfaces', type, interface, 'ipv6'] + migrate_rip(config, ip_base, interface) + migrate_ripng(config, ipv6_base, interface) + migrate_ospf(config, ip_base, interface) + migrate_ospfv3(config, ipv6_base, interface) + + vif_path = ['interfaces', type, interface, 'vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_ip_base = vif_path + [vif, 'ip'] + vif_ipv6_base = vif_path + [vif, 'ipv6'] + ifname = f'{interface}.{vif}' + + migrate_rip(config, vif_ip_base, ifname) + migrate_ripng(config, vif_ipv6_base, ifname) + migrate_ospf(config, vif_ip_base, ifname) + migrate_ospfv3(config, vif_ipv6_base, ifname) + + + vif_s_path = ['interfaces', type, interface, 'vif-s'] + if config.exists(vif_s_path): + for vif_s in config.list_nodes(vif_s_path): + vif_s_ip_base = vif_s_path + [vif_s, 'ip'] + vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] + + # vif-c interfaces MUST be migrated before their parent vif-s + # interface as the migrate_*() functions delete the path! + vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] + if config.exists(vif_c_path): + for vif_c in config.list_nodes(vif_c_path): + vif_c_ip_base = vif_c_path + [vif_c, 'ip'] + vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] + ifname = f'{interface}.{vif_s}.{vif_c}' + + migrate_rip(config, vif_c_ip_base, ifname) + migrate_ripng(config, vif_c_ipv6_base, ifname) + migrate_ospf(config, vif_c_ip_base, ifname) + migrate_ospfv3(config, vif_c_ipv6_base, ifname) + + + ifname = f'{interface}.{vif_s}' + migrate_rip(config, vif_s_ip_base, ifname) + migrate_ripng(config, vif_s_ipv6_base, ifname) + migrate_ospf(config, vif_s_ip_base, ifname) + migrate_ospfv3(config, vif_s_ipv6_base, ifname) try: with open(file_name, 'w') as f: diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21 index d1ec2ad3e..e96663e54 100755 --- a/src/migration-scripts/interfaces/20-to-21 +++ b/src/migration-scripts/interfaces/20-to-21 @@ -14,47 +14,48 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported -# having a VTI interface in the CLI but no IPSec configuration - drop VTI -# configuration if this is the case for VyOS 1.4 - -import sys +from sys import argv +from sys import exit from vyos.configtree import ConfigTree if __name__ == '__main__': - if (len(sys.argv) < 1): + if (len(argv) < 1): print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] + exit(1) + file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() config = ConfigTree(config_file) - base = ['interfaces', 'vti'] - if not config.exists(base): - # Nothing to do - sys.exit(0) - - ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] - for interface in config.list_nodes(base): - found = False - if config.exists(ipsec_base): - for peer in config.list_nodes(ipsec_base): - if config.exists(ipsec_base + [peer, 'vti', 'bind']): - tmp = config.return_value(ipsec_base + [peer, 'vti', 'bind']) - if tmp == interface: - # Interface was found and we no longer need to search - # for it in our IPSec peers - found = True - break - if not found: - config.delete(base + [interface]) + + for type in ['tunnel', 'l2tpv3']: + base = ['interfaces', type] + if not config.exists(base): + # Nothing to do + continue + + for interface in config.list_nodes(base): + # Migrate "interface tunnel <tunX> encapsulation gre-bridge" to gretap + encap_path = base + [interface, 'encapsulation'] + if type == 'tunnel' and config.exists(encap_path): + tmp = config.return_value(encap_path) + if tmp == 'gre-bridge': + config.set(encap_path, value='gretap') + + # Migrate "interface tunnel|l2tpv3 <interface> local-ip" to source-address + # Migrate "interface tunnel|l2tpv3 <interface> remote-ip" to remote + local_ip_path = base + [interface, 'local-ip'] + if config.exists(local_ip_path): + config.rename(local_ip_path, 'source-address') + + remote_ip_path = base + [interface, 'remote-ip'] + if config.exists(remote_ip_path): + config.rename(remote_ip_path, 'remote') 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) + exit(1) diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22 new file mode 100755 index 000000000..d1ec2ad3e --- /dev/null +++ b/src/migration-scripts/interfaces/21-to-22 @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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/>. + +# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported +# having a VTI interface in the CLI but no IPSec configuration - drop VTI +# configuration if this is the case for VyOS 1.4 + +import sys +from vyos.configtree import ConfigTree + +if __name__ == '__main__': + 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 = ['interfaces', 'vti'] + if not config.exists(base): + # Nothing to do + sys.exit(0) + + ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] + for interface in config.list_nodes(base): + found = False + if config.exists(ipsec_base): + for peer in config.list_nodes(ipsec_base): + if config.exists(ipsec_base + [peer, 'vti', 'bind']): + tmp = config.return_value(ipsec_base + [peer, 'vti', 'bind']) + if tmp == interface: + # Interface was found and we no longer need to search + # for it in our IPSec peers + found = True + break + if not found: + config.delete(base + [interface]) + + 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) diff --git a/src/op_mode/show_wwan.py b/src/op_mode/show_wwan.py new file mode 100755 index 000000000..249dda2a5 --- /dev/null +++ b/src/op_mode/show_wwan.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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 argparse + +from sys import exit +from vyos.util import cmd + +parser = argparse.ArgumentParser() +parser.add_argument("--model", help="Get module model", action="store_true") +parser.add_argument("--revision", help="Get module revision", action="store_true") +parser.add_argument("--capabilities", help="Get module capabilities", action="store_true") +parser.add_argument("--imei", help="Get module IMEI/ESN/MEID", action="store_true") +parser.add_argument("--imsi", help="Get module IMSI", action="store_true") +parser.add_argument("--msisdn", help="Get module MSISDN", action="store_true") +parser.add_argument("--sim", help="Get SIM card status", action="store_true") +parser.add_argument("--signal", help="Get current RF signal info", action="store_true") +parser.add_argument("--firmware", help="Get current RF signal info", action="store_true") + +required = parser.add_argument_group('Required arguments') +required.add_argument("--interface", help="WWAN interface name, e.g. wwan0", required=True) + +def qmi_cmd(device, command, silent=False): + tmp = cmd(f'qmicli --device={device} --device-open-proxy {command}') + tmp = tmp.replace(f'[{cdc}] ', '') + if not silent: + # skip first line as this only holds the info headline + for line in tmp.splitlines()[1:]: + print(line.lstrip()) + return tmp + +if __name__ == '__main__': + args = parser.parse_args() + + # remove the WWAN prefix from the interface, required for the CDC interface + if_num = args.interface.replace('wwan','') + cdc = f'/dev/cdc-wdm{if_num}' + + if args.model: + qmi_cmd(cdc, '--dms-get-model') + elif args.capabilities: + qmi_cmd(cdc, '--dms-get-capabilities') + qmi_cmd(cdc, '--dms-get-band-capabilities') + elif args.revision: + qmi_cmd(cdc, '--dms-get-revision') + elif args.imei: + qmi_cmd(cdc, '--dms-get-ids') + elif args.imsi: + qmi_cmd(cdc, '--dms-uim-get-imsi') + elif args.msisdn: + qmi_cmd(cdc, '--dms-get-msisdn') + elif args.sim: + qmi_cmd(cdc, '--uim-get-card-status') + elif args.signal: + qmi_cmd(cdc, '--nas-get-signal-info') + qmi_cmd(cdc, '--nas-get-rf-band-info') + elif args.firmware: + tmp = qmi_cmd(cdc, '--dms-get-manufacturer', silent=True) + if 'Sierra Wireless' in tmp: + qmi_cmd(cdc, '--dms-swi-get-current-firmware') + else: + qmi_cmd(cdc, '--dms-get-software-version') + else: + parser.print_help() + exit(1) diff --git a/src/validators/interface-name b/src/validators/interface-name index 5bac671b1..105815eee 100755 --- a/src/validators/interface-name +++ b/src/validators/interface-name @@ -20,7 +20,7 @@ import re from sys import argv from sys import exit -pattern = '^(bond|br|dum|en|ersp|eth|gnv|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|tun|vti|vtun|vxlan|wg|wlan|wlm)[0-9]+(.\d+)?|lo$' +pattern = '^(bond|br|dum|en|ersp|eth|gnv|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|tun|vti|vtun|vxlan|wg|wlan|wwan)[0-9]+(.\d+)?|lo$' if __name__ == '__main__': if len(argv) != 2: diff --git a/src/validators/vrf-name b/src/validators/vrf-name index 7b6313888..c78a80776 100755 --- a/src/validators/vrf-name +++ b/src/validators/vrf-name @@ -34,7 +34,7 @@ if __name__ == '__main__': exit(1) pattern = "^(?!(bond|br|dum|eth|lan|eno|ens|enp|enx|gnv|ipoe|l2tp|l2tpeth|" \ - "vtun|ppp|pppoe|peth|tun|vti|vxlan|wg|wlan|wlm)\d+(\.\d+(v.+)?)?$).*$" + "vtun|ppp|pppoe|peth|tun|vti|vxlan|wg|wlan|wwan)\d+(\.\d+(v.+)?)?$).*$" if not re.match(pattern, vrf): exit(1) |