diff options
-rw-r--r-- | data/templates/dhcp-client/ipv4.tmpl | 3 | ||||
-rw-r--r-- | debian/vyos-1x.install | 1 | ||||
-rw-r--r-- | op-mode-definitions/show-ip-route.xml.in | 7 | ||||
-rw-r--r-- | python/vyos/ifconfig/wwan.py | 16 | ||||
-rw-r--r-- | python/vyos/util.py | 16 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-wwan.py | 4 | ||||
-rw-r--r-- | src/etc/cron.d/check-wwan | 1 | ||||
-rwxr-xr-x | src/helpers/vyos-check-wwan.py | 37 | ||||
-rwxr-xr-x | src/helpers/vyos_net_name | 14 | ||||
-rwxr-xr-x | src/op_mode/connect_disconnect.py | 68 |
10 files changed, 130 insertions, 37 deletions
diff --git a/data/templates/dhcp-client/ipv4.tmpl b/data/templates/dhcp-client/ipv4.tmpl index 11e961166..b3e74c22b 100644 --- a/data/templates/dhcp-client/ipv4.tmpl +++ b/data/templates/dhcp-client/ipv4.tmpl @@ -2,7 +2,8 @@ option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; timeout 60; -retry 300; +retry 60; +initial-interval 2; interface "{{ ifname }}" { send host-name "{{ dhcp_options.host_name }}"; diff --git a/debian/vyos-1x.install b/debian/vyos-1x.install index 10426260a..29d74390f 100644 --- a/debian/vyos-1x.install +++ b/debian/vyos-1x.install @@ -1,3 +1,4 @@ +etc/cron.d etc/cron.hourly etc/dhcp etc/ipsec.d diff --git a/op-mode-definitions/show-ip-route.xml.in b/op-mode-definitions/show-ip-route.xml.in index 0a24bc45a..fdbb6859d 100644 --- a/op-mode-definitions/show-ip-route.xml.in +++ b/op-mode-definitions/show-ip-route.xml.in @@ -125,16 +125,11 @@ </properties> <command>vtysh -c "show ip route tag $5"</command> </tagNode> - <node name="vrf"> - <properties> - <help>Show IP routes in VRF</help> - </properties> - </node> <tagNode name="vrf"> <properties> <help>Show IP routes in VRF</help> <completionHelp> - <list><vrf></list> + <list>all</list> <path>vrf name</path> </completionHelp> </properties> diff --git a/python/vyos/ifconfig/wwan.py b/python/vyos/ifconfig/wwan.py index f18959a60..295f8bc2e 100644 --- a/python/vyos/ifconfig/wwan.py +++ b/python/vyos/ifconfig/wwan.py @@ -26,3 +26,19 @@ class WWANIf(Interface): 'eternal': 'wwan[0-9]+$', }, } + + def remove(self): + """ + Remove interface from operating system. Removing the interface + deconfigures all assigned IP addresses. + Example: + >>> from vyos.ifconfig import WWANIf + >>> i = WWANIf('wwan0') + >>> i.remove() + """ + + if self.exists(self.ifname): + # interface is always A/D down. It needs to be enabled explicitly + self.set_admin_state('down') + + super().remove() diff --git a/python/vyos/util.py b/python/vyos/util.py index 9c4c29322..9aa1f98d2 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -931,3 +931,19 @@ def install_into_config(conf, config_paths, override_prompt=True): if count > 0: print(f'{count} value(s) installed. Use "compare" to see the pending changes, and "commit" to apply.') + +def is_wwan_connected(interface): + """ Determine if a given WWAN interface, e.g. wwan0 is connected to the + carrier network or not """ + import json + + if not interface.startswith('wwan'): + raise ValueError(f'Specified interface "{interface}" is not a WWAN interface') + + modem = interface.lstrip('wwan') + + tmp = cmd(f'mmcli --modem {modem} --output-json') + tmp = json.loads(tmp) + + # return True/False if interface is in connected state + return dict_search('modem.generic.state', tmp) == 'connected' diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py index faa5eb628..f013e5411 100755 --- a/src/conf_mode/interfaces-wwan.py +++ b/src/conf_mode/interfaces-wwan.py @@ -25,7 +25,9 @@ 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.util import call from vyos.util import dict_search +from vyos.util import DEVNULL from vyos import ConfigError from vyos import airbag airbag.enable() @@ -88,7 +90,7 @@ def apply(wwan): options += ',user={user},password={password}'.format(**wwan['authentication']) command = f'{base_cmd} --simple-connect="{options}"' - cmd(command) + call(command, stdout=DEVNULL) w.update(wwan) return None diff --git a/src/etc/cron.d/check-wwan b/src/etc/cron.d/check-wwan new file mode 100644 index 000000000..28190776f --- /dev/null +++ b/src/etc/cron.d/check-wwan @@ -0,0 +1 @@ +*/5 * * * * root /usr/libexec/vyos/vyos-check-wwan.py diff --git a/src/helpers/vyos-check-wwan.py b/src/helpers/vyos-check-wwan.py new file mode 100755 index 000000000..c6e6c54b7 --- /dev/null +++ b/src/helpers/vyos-check-wwan.py @@ -0,0 +1,37 @@ +#!/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/>. + +from vyos.configquery import VbashOpRun +from vyos.configquery import ConfigTreeQuery + +from vyos.util import is_wwan_connected +from vyos.util import call + +conf = ConfigTreeQuery() +dict = conf.get_config_dict(['interfaces', 'wwan'], key_mangling=('-', '_'), + get_first_key=True) + +for interface, interface_config in dict.items(): + if not is_wwan_connected(interface): + if 'disable' in interface_config: + # do not restart this interface as it's disabled by the user + continue + + #op = VbashOpRun() + #op.run(['connect', 'interface', interface]) + call(f'VYOS_TAGNODE_VALUE={interface} /usr/libexec/vyos/conf_mode/interfaces-wwan.py') + +exit(0) diff --git a/src/helpers/vyos_net_name b/src/helpers/vyos_net_name index 13fb9e31f..e21d8c9ff 100755 --- a/src/helpers/vyos_net_name +++ b/src/helpers/vyos_net_name @@ -144,7 +144,19 @@ def get_configfile_interfaces() -> dict: logging.critical(f"OSError {e}") exit(1) - config = ConfigTree(config_file) + try: + config = ConfigTree(config_file) + except Exception: + logging.debug(f"updating component version string syntax") + try: + # this will update the component version string in place, for + # updates 1.2 --> 1.3/1.4 + os.system(f'/usr/libexec/vyos/run-config-migration.py {config_path} --virtual --set-vintage=vyos') + with open(config_path) as f: + config_file = f.read() + config = ConfigTree(config_file) + except Exception as e: + logging.critical(f"ConfigTree error: {e}") base = ['interfaces', 'ethernet'] if config.exists(base): diff --git a/src/op_mode/connect_disconnect.py b/src/op_mode/connect_disconnect.py index a773aa28e..ffc574362 100755 --- a/src/op_mode/connect_disconnect.py +++ b/src/op_mode/connect_disconnect.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# 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 @@ -17,21 +17,19 @@ import os import argparse -from sys import exit from psutil import process_iter -from time import strftime, localtime, time from vyos.util import call +from vyos.util import DEVNULL +from vyos.util import is_wwan_connected -def check_interface(interface): +def check_ppp_interface(interface): if not os.path.isfile(f'/etc/ppp/peers/{interface}'): - print(f'Interface {interface}: invalid!') + print(f'Interface {interface} does not exist!') exit(1) def check_ppp_running(interface): - """ - Check if ppp process is running in the interface in question - """ + """ Check if PPP process is running in the interface in question """ for p in process_iter(): if "pppd" in p.name(): if interface in p.cmdline(): @@ -40,32 +38,46 @@ def check_ppp_running(interface): return False def connect(interface): - """ - Connect PPP interface - """ - check_interface(interface) + """ Connect dialer interface """ - # Check if interface is already dialed - if os.path.isdir(f'/sys/class/net/{interface}'): - print(f'Interface {interface}: already connected!') - elif check_ppp_running(interface): - print(f'Interface {interface}: connection is beeing established!') + if interface.startswith('ppp'): + check_ppp_interface(interface) + # Check if interface is already dialed + if os.path.isdir(f'/sys/class/net/{interface}'): + print(f'Interface {interface}: already connected!') + elif check_ppp_running(interface): + print(f'Interface {interface}: connection is beeing established!') + else: + print(f'Interface {interface}: connecting...') + call(f'systemctl restart ppp@{interface}.service') + elif interface.startswith('wwan'): + if is_wwan_connected(interface): + print(f'Interface {interface}: already connected!') + else: + call(f'VYOS_TAGNODE_VALUE={interface} /usr/libexec/vyos/conf_mode/interfaces-wwan.py') else: - print(f'Interface {interface}: connecting...') - call(f'systemctl restart ppp@{interface}.service') + print(f'Unknown interface {interface}, can not connect. Aborting!') def disconnect(interface): - """ - Disconnect PPP interface - """ - check_interface(interface) + """ Disconnect dialer interface """ - # Check if interface is already down - if not check_ppp_running(interface): - print(f'Interface {interface}: connection is already down') + if interface.startswith('ppp'): + check_ppp_interface(interface) + + # Check if interface is already down + if not check_ppp_running(interface): + print(f'Interface {interface}: connection is already down') + else: + print(f'Interface {interface}: disconnecting...') + call(f'systemctl stop ppp@{interface}.service') + elif interface.startswith('wwan'): + if not is_wwan_connected(interface): + print(f'Interface {interface}: connection is already down') + else: + modem = interface.lstrip('wwan') + call(f'mmcli --modem {modem} --simple-disconnect', stdout=DEVNULL) else: - print(f'Interface {interface}: disconnecting...') - call(f'systemctl stop ppp@{interface}.service') + print(f'Unknown interface {interface}, can not disconnect. Aborting!') def main(): parser = argparse.ArgumentParser() |