From 8d310eb3f83bafc03ff35a99bd2157fe8d23ac5e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 2 Apr 2022 14:39:09 +0200 Subject: wwan: T4324: properly start/stop ModemManager and cron helper on interface add/removal (cherry picked from commit c58a03ad76b2a0680a33fcfec3ab7a3545374abb) --- src/conf_mode/interfaces-wwan.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src/conf_mode/interfaces-wwan.py') diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py index a4b033374..57acb866c 100755 --- a/src/conf_mode/interfaces-wwan.py +++ b/src/conf_mode/interfaces-wwan.py @@ -36,7 +36,7 @@ from vyos import airbag airbag.enable() service_name = 'ModemManager.service' -cron_script = '/etc/cron.d/wwan' +cron_script = '/etc/cron.d/vyos-wwan' def get_config(config=None): """ @@ -57,8 +57,8 @@ def get_config(config=None): get_first_key=True, no_tag_node_value_mangle=True) - # This if-clause is just to be sure - it will always evaluate to true ifname = wwan['ifname'] + # This if-clause is just to be sure - it will always evaluate to true if ifname in wwan['other_interfaces']: del wwan['other_interfaces'][ifname] if len(wwan['other_interfaces']) == 0: @@ -82,13 +82,25 @@ def verify(wwan): def generate(wwan): if 'deleted' in wwan: + # We are the last WWAN interface - there are no other ones remaining + # thus the cronjob needs to go away, too + if 'other_interfaces' not in wwan: + if os.path.exists(cron_script): + os.unlink(cron_script) return None + # Install cron triggered helper script to re-dial WWAN interfaces on + # disconnect - e.g. happens during RF signal loss. The script watches every + # WWAN interface - so there is only one instance. if not os.path.exists(cron_script): write_file(cron_script, '*/5 * * * * root /usr/libexec/vyos/vyos-check-wwan.py') + return None def apply(wwan): + # ModemManager is required to dial WWAN connections - one instance is + # required to serve all modems. Activate ModemManager on first invocation + # of any WWAN interface. if not is_systemd_service_active(service_name): cmd(f'systemctl start {service_name}') @@ -111,7 +123,8 @@ def apply(wwan): if 'deleted' in wwan or 'disable' in wwan: w.remove() - # There are no other WWAN interfaces - stop the daemon + # We are the last WWAN interface - there are no other WWAN interfaces + # remaining, thus we can stop ModemManager and free resources. if 'other_interfaces' not in wwan: cmd(f'systemctl stop {service_name}') # Clean CRON helper script which is used for to re-connect when @@ -139,9 +152,6 @@ def apply(wwan): call(command, stdout=DEVNULL) w.update(wwan) - if 'other_interfaces' not in wwan and 'deleted' in wwan: - cmd(f'systemctl start {service_name}') - return None if __name__ == '__main__': -- cgit v1.2.3 From f728e321d1fb781e26bbc103ac9923064ec86086 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 4 Apr 2022 20:24:38 +0200 Subject: wwan: T4338: changing interface description should not trigger reconnect Changing the WWAN interface description will trigger an interface reconnect. Reconnects should only be triggered in changes to the connection parameters like bond interfaces. (cherry picked from commit 76a049c7d30f3e64989b9697d65d15bfd3005316) --- src/conf_mode/interfaces-wwan.py | 75 ++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 23 deletions(-) (limited to 'src/conf_mode/interfaces-wwan.py') diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py index 57acb866c..a1a9360d7 100755 --- a/src/conf_mode/interfaces-wwan.py +++ b/src/conf_mode/interfaces-wwan.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# Copyright (C) 2020-2022 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 @@ -21,6 +21,7 @@ from time import sleep from vyos.config import Config from vyos.configdict import get_interface_dict +from vyos.configdict import leaf_node_changed from vyos.configverify import verify_authentication from vyos.configverify import verify_interface_exists from vyos.configverify import verify_vrf @@ -50,6 +51,32 @@ def get_config(config=None): base = ['interfaces', 'wwan'] wwan = get_interface_dict(conf, base) + # We should only terminate the WWAN session if critical parameters change. + # All parameters that can be changed on-the-fly (like interface description) + # should not lead to a reconnect! + tmp = leaf_node_changed(conf, ['address']) + if tmp: wwan.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['apn']) + if tmp: wwan.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['disable']) + if tmp: wwan.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['vrf']) + # leaf_node_changed() returns a list, as VRF is a non-multi node, there + # will be only one list element + if tmp: wwan.update({'vrf_old': tmp[0]}) + + tmp = leaf_node_changed(conf, ['authentication', 'user']) + if tmp: wwan.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['authentication', 'password']) + if tmp: wwan.update({'shutdown_required': {}}) + + tmp = leaf_node_changed(conf, ['ipv6', 'address', 'autoconf']) + if tmp: wwan.update({'shutdown_required': {}}) + # We need to know the amount of other WWAN interfaces as ModemManager needs # to be started or stopped. conf.set_level(base) @@ -113,11 +140,12 @@ def apply(wwan): break sleep(0.250) - # we only need the modem number. wwan0 -> 0, wwan1 -> 1 - modem = wwan['ifname'].lstrip('wwan') - base_cmd = f'mmcli --modem {modem}' - # Number of bearers is limited - always disconnect first - cmd(f'{base_cmd} --simple-disconnect') + if 'shutdown_required' in wwan: + # we only need the modem number. wwan0 -> 0, wwan1 -> 1 + modem = wwan['ifname'].lstrip('wwan') + base_cmd = f'mmcli --modem {modem}' + # Number of bearers is limited - always disconnect first + cmd(f'{base_cmd} --simple-disconnect') w = WWANIf(wwan['ifname']) if 'deleted' in wwan or 'disable' in wwan: @@ -134,24 +162,25 @@ def apply(wwan): return None - ip_type = 'ipv4' - slaac = dict_search('ipv6.address.autoconf', wwan) != None - if 'address' in wwan: - if 'dhcp' in wwan['address'] and ('dhcpv6' in wwan['address'] or slaac): - ip_type = 'ipv4v6' - elif 'dhcpv6' in wwan['address'] or slaac: - ip_type = 'ipv6' - elif 'dhcp' in wwan['address']: - ip_type = 'ipv4' - - options = f'ip-type={ip_type},apn=' + wwan['apn'] - if 'authentication' in wwan: - options += ',user={user},password={password}'.format(**wwan['authentication']) - - command = f'{base_cmd} --simple-connect="{options}"' - call(command, stdout=DEVNULL) - w.update(wwan) + if 'shutdown_required' in wwan: + ip_type = 'ipv4' + slaac = dict_search('ipv6.address.autoconf', wwan) != None + if 'address' in wwan: + if 'dhcp' in wwan['address'] and ('dhcpv6' in wwan['address'] or slaac): + ip_type = 'ipv4v6' + elif 'dhcpv6' in wwan['address'] or slaac: + ip_type = 'ipv6' + elif 'dhcp' in wwan['address']: + ip_type = 'ipv4' + + options = f'ip-type={ip_type},apn=' + wwan['apn'] + if 'authentication' in wwan: + options += ',user={user},password={password}'.format(**wwan['authentication']) + command = f'{base_cmd} --simple-connect="{options}"' + call(command, stdout=DEVNULL) + + w.update(wwan) return None if __name__ == '__main__': -- cgit v1.2.3