From 1c7d7cbd3963428888068af679946e6329567451 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 7 Jun 2020 14:04:36 +0200 Subject: wwan: T2529: migrate device from ttyUSB to usbXbY.YpZ.Z During testing it was discovered that there is a well known problem (we had for ethernet interfaces) also in the serial port world. They will be enumerated and mapped to /dev/ttyUSBxxx differently from boot to boot. This is especially painful on my development APU4 board which also has a Sierra Wireless MC7710 LTE module installed. The serial port will toggle between ttyUSB2 and ttyUSB5 depending on the amount of serial port extenders attached (FT4232H). The shipped udev rule (/usr/lib/udev/rules.d/60-serial.rules) partly solves this by enumerating the devices into /dev/serial/by-id folder with their name and serial number - it's a very good idea but I've found that not all of the FT4232H dongles have a serial number programmed - this leads to the situation that when you plug in two cables with both having serial number 0 - only one device symlink will appear - the previous one is always overwritten by the latter one. Derive /usr/lib/udev/rules.d/60-serial.rules and create a /dev/serial/by-bus directory and group devices by attached USB root port. vyos@vyos:~$ find /dev/serial/by-bus/ -name usb* -exec basename {} \; | sort usb0b1.3p1.0 usb0b1.3p1.2 usb0b1.3p1.3 usb0b2.4p1.0 usb0b2.4p1.1 usb0b2.4p1.2 usb0b2.4p1.3 So we have USB root 0 with bus 1.3 and port 1.0. The enumeration is constant accross reboots. --- data/templates/wwan/peer.tmpl | 2 +- .../interfaces-wirelessmodem.xml.in | 10 ++-- src/conf_mode/interfaces-wirelessmodem.py | 32 ++++++++++--- src/migration-scripts/interfaces/10-to-11 | 55 ++++++++++++++++++++++ 4 files changed, 89 insertions(+), 10 deletions(-) create mode 100755 src/migration-scripts/interfaces/10-to-11 diff --git a/data/templates/wwan/peer.tmpl b/data/templates/wwan/peer.tmpl index 04ab4f844..b8a7d10ae 100644 --- a/data/templates/wwan/peer.tmpl +++ b/data/templates/wwan/peer.tmpl @@ -10,7 +10,7 @@ linkname {{ intf }} usepeerdns {%- endif %} # physical device -/dev/{{ device }} +{{ device }} lcp-echo-failure 0 115200 debug diff --git a/interface-definitions/interfaces-wirelessmodem.xml.in b/interface-definitions/interfaces-wirelessmodem.xml.in index 91eee56ab..d5f2e04d7 100644 --- a/interface-definitions/interfaces-wirelessmodem.xml.in +++ b/interface-definitions/interfaces-wirelessmodem.xml.in @@ -46,12 +46,16 @@ #include - System device name (default: ttyUSB0) + Serial device - + - ttyXXX + ttySXX + System TTY device name + + + usbXbY.YpZ.Z System TTY device name diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index a13c70990..f16457a7f 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -16,9 +16,10 @@ import os -from sys import exit from copy import deepcopy +from fnmatch import fnmatch from netifaces import interfaces +from sys import exit from vyos.config import Config from vyos.ifconfig import BridgeIf, Section @@ -36,7 +37,7 @@ default_config_data = { 'chat_script': '', 'deleted': False, 'description': '', - 'device': 'ttyUSB0', + 'device': '', 'disable': False, 'disable_link_detect': 1, 'on_demand': False, @@ -56,6 +57,16 @@ def check_kmod(): if call(f'modprobe {module}') != 0: raise ConfigError(f'Loading Kernel module {module} failed') +def find_device_file(device): + """ Recurively search /dev for the given device file and return its full path. + If no device file was found 'None' is returned """ + for root, dirs, files in os.walk('/dev'): + for basename in files: + if fnmatch(basename, device): + return os.path.join(root, basename) + + return None + def get_config(): wwan = deepcopy(default_config_data) conf = Config() @@ -93,7 +104,13 @@ def get_config(): # System device name if conf.exists(['device']): - wwan['device'] = conf.return_value(['device']) + tmp = conf.return_value(['device']) + wwan['device'] = find_device_file(tmp) + # If device file was not found in /dev we will just re-use + # the plain device name, thus we can trigger the exception + # in verify() as it's a non existent file + if wwan['device'] == None: + wwan['device'] = tmp # disable interface if conf.exists('disable'): @@ -131,7 +148,10 @@ def verify(wwan): return None if not wwan['apn']: - raise ConfigError(f"APN for {wwan['intf']} not configured") + raise ConfigError('No APN configured for "{intf}"'.format(**wwan)) + + if not wwan['device']: + 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 @@ -169,7 +189,7 @@ def generate(wwan): script_wwan_ip_up, script_wwan_ip_down] # Always hang-up WWAN connection prior generating new configuration file - cmd(f'systemctl stop ppp@{intf}.service') + call(f'systemctl stop ppp@{intf}.service') if wwan['deleted']: # Delete PPP configuration files @@ -205,9 +225,9 @@ def apply(wwan): if not wwan['disable']: # "dial" WWAN connection intf = wwan['intf'] - cmd(f'systemctl start ppp@{intf}.service') # make logfile owned by root / vyattacfg chown(wwan['logfile'], 'root', 'vyattacfg') + call(f'systemctl start ppp@{intf}.service') # re-add ourselves to any bridge we might have fallen out of # FIXME: wwan isn't under vyos.ifconfig so we can't call diff --git a/src/migration-scripts/interfaces/10-to-11 b/src/migration-scripts/interfaces/10-to-11 new file mode 100755 index 000000000..6b8e49ed9 --- /dev/null +++ b/src/migration-scripts/interfaces/10-to-11 @@ -0,0 +1,55 @@ +#!/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 . + +# rename WWAN (wirelessmodem) serial interface from non persistent ttyUSB2 to +# a bus like name, e.g. "usb0b1.3p1.3" + +import os + +from sys import exit, argv +from vyos.configtree import ConfigTree + +if __name__ == '__main__': + if (len(argv) < 1): + print("Must specify file name!") + exit(1) + + file_name = argv[1] + with open(file_name, 'r') as f: + config_file = f.read() + + config = ConfigTree(config_file) + base = ['interfaces', 'wirelessmodem'] + if not config.exists(base): + # Nothing to do + exit(0) + + for wwan in config.list_nodes(base): + if config.exists(base + [wwan, 'device']): + device = config.return_value(base + [wwan, 'device']) + + for root, dirs, files in os.walk('/dev/serial/by-bus'): + for file in files: + device_file = os.path.realpath(os.path.join(root, file)) + if os.path.basename(device_file) == device: + config.set(base + [wwan, 'device'], value=file, replace=True) + + 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)) + exit(1) -- cgit v1.2.3