diff options
| -rw-r--r-- | data/templates/wwan/ip-down.script.tmpl | 12 | ||||
| -rw-r--r-- | data/templates/wwan/ip-pre-up.script.tmpl | 10 | ||||
| -rw-r--r-- | data/templates/wwan/ip-up.script.tmpl | 12 | ||||
| -rw-r--r-- | data/templates/wwan/peer.tmpl | 21 | ||||
| -rw-r--r-- | interface-definitions/interfaces-wirelessmodem.xml.in | 1 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-wirelessmodem.py | 145 | 
6 files changed, 70 insertions, 131 deletions
| diff --git a/data/templates/wwan/ip-down.script.tmpl b/data/templates/wwan/ip-down.script.tmpl index f7b38cbc5..9dc15ea99 100644 --- a/data/templates/wwan/ip-down.script.tmpl +++ b/data/templates/wwan/ip-down.script.tmpl @@ -11,17 +11,17 @@ fi  # Determine if we are running inside a VRF or not, required for proper routing table  # NOTE: the down script can not be properly templated as we need the VRF name,  # which is not present on deletion, thus we read it from the operating system. -if [ -d /sys/class/net/{{ intf }}/upper_* ]; then +if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then      # Determine upper (VRF) interface -    VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*)) +    VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))      # Remove upper_ prefix from result string      VRF_NAME=${VRF#"upper_"}      # Remove default route from VRF routing table -    vtysh -c "conf t" -c "vrf ${VRF_NAME}" -c "no ip route 0.0.0.0/0 {{ intf }}" +    vtysh -c "conf t" -c "vrf ${VRF_NAME}" -c "no ip route 0.0.0.0/0 {{ ifname }}"  else      # Remove default route from GRT (global routing table) -    vtysh -c "conf t" -c "no ip route 0.0.0.0/0 {{ intf }}" +    vtysh -c "conf t" -c "no ip route 0.0.0.0/0 {{ ifname }}"  fi -DIALER_PID=$(cat /var/run/{{ intf }}.pid) -logger -t pppd[$DIALER_PID] "removed default route via {{ intf }} metric {{ metric }}" +DIALER_PID=$(cat /var/run/{{ ifname }}.pid) +logger -t pppd[$DIALER_PID] "removed default route via {{ ifname }} metric {{ backup.distance }}" diff --git a/data/templates/wwan/ip-pre-up.script.tmpl b/data/templates/wwan/ip-pre-up.script.tmpl index 7a17a1c71..efc065bad 100644 --- a/data/templates/wwan/ip-pre-up.script.tmpl +++ b/data/templates/wwan/ip-pre-up.script.tmpl @@ -7,17 +7,17 @@ ipparam=$6  # device name and metric are received using ipparam  device=`echo "$ipparam"|awk '{ print $1 }'` -if [ "$device" != "{{ intf }}" ]; then +if [ "$device" != "{{ ifname }}" ]; then      exit  fi  # add some info to syslog -DIALER_PID=$(cat /var/run/{{ intf }}.pid) +DIALER_PID=$(cat /var/run/{{ ifname }}.pid)  logger -t pppd[$DIALER_PID] "executing $0" -echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias +echo "{{ description }}" > /sys/class/net/{{ ifname }}/ifalias  {% if vrf -%} -logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} for VRF {{ vrf }}" -ip link set dev {{ intf }} master {{ vrf }} +logger -t pppd[$DIALER_PID] "configuring interface {{ ifname }} for VRF {{ vrf }}" +ip link set dev {{ ifname }} master {{ vrf }}  {% endif %} diff --git a/data/templates/wwan/ip-up.script.tmpl b/data/templates/wwan/ip-up.script.tmpl index 3a7eec800..2603a0286 100644 --- a/data/templates/wwan/ip-up.script.tmpl +++ b/data/templates/wwan/ip-up.script.tmpl @@ -9,17 +9,17 @@ if [ -z $(echo $2 | egrep "(ttyS[0-9]+|usb[0-9]+b.*)$") ]; then  fi  # Determine if we are running inside a VRF or not, required for proper routing table -if [ -d /sys/class/net/{{ intf }}/upper_* ]; then +if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then      # Determine upper (VRF) interface -    VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*)) +    VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))      # Remove upper_ prefix from result string      VRF_NAME=${VRF#"upper_"}      # Remove default route from VRF routing table -    vtysh -c "conf t" -c "vrf ${VRF_NAME}" -c "ip route 0.0.0.0/0 {{ intf }} {{ metric }}" +    vtysh -c "conf t" -c "vrf ${VRF_NAME}" -c "ip route 0.0.0.0/0 {{ ifname }} {{ backup.distance }}"  else      # Remove default route from GRT (global routing table) -    vtysh -c "conf t" -c "ip route 0.0.0.0/0 {{ intf }} {{ metric }}" +    vtysh -c "conf t" -c "ip route 0.0.0.0/0 {{ ifname }} {{ backup.distance }}"  fi -DIALER_PID=$(cat /var/run/{{ intf }}.pid) -logger -t pppd[$DIALER_PID] "added default route via {{ intf }} metric {{ metric }} ${VRF_NAME}" +DIALER_PID=$(cat /var/run/{{ ifname }}.pid) +logger -t pppd[$DIALER_PID] "added default route via {{ ifname }} metric {{ backup.distance }} ${VRF_NAME}" diff --git a/data/templates/wwan/peer.tmpl b/data/templates/wwan/peer.tmpl index 0168283fd..cdedf02ad 100644 --- a/data/templates/wwan/peer.tmpl +++ b/data/templates/wwan/peer.tmpl @@ -1,14 +1,10 @@  ### Autogenerated by interfaces-wirelessmodem.py ### -{% if description %} -# {{ description }} -{% endif %} -ifname {{ intf }} -ipparam {{ intf }} -linkname {{ intf }} -{% if name_server -%} -usepeerdns -{%- endif %} +{{ "# description: " + description if description is defined }} +ifname {{ ifname }} +ipparam {{ ifname }} +linkname {{ ifname }} +{{ "usepeerdns" if no_peer_dns is defined }}  # physical device  {{ device }}  lcp-echo-failure 0 @@ -22,8 +18,7 @@ noauth  crtscts  lock  persist -{% if on_demand -%} -demand -{%- endif %} +{{ "demand" if ondemand is defined }} + +connect '/usr/sbin/chat -v -t6 -f /etc/ppp/peers/chat.{{ ifname }}' -connect '/usr/sbin/chat -v -t6 -f {{ chat_script }}' diff --git a/interface-definitions/interfaces-wirelessmodem.xml.in b/interface-definitions/interfaces-wirelessmodem.xml.in index 8b68594da..d375b808d 100644 --- a/interface-definitions/interfaces-wirelessmodem.xml.in +++ b/interface-definitions/interfaces-wirelessmodem.xml.in @@ -38,6 +38,7 @@                    </constraint>                    <constraintErrorMessage>Must be between (1-255)</constraintErrorMessage>                  </properties> +                <defaultValue>10</defaultValue>                </leafNode>              </children>            </node> diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index 35e3c583c..c2970d252 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -16,37 +16,21 @@  import os -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 +from vyos.configdict import dict_merge +from vyos.configverify import verify_bridge_vrf  from vyos.template import render  from vyos.util import call -from vyos.validate import is_member +from vyos.xml import defaults  from vyos import ConfigError -  from vyos import airbag  airbag.enable() -default_config_data = { -    'apn': '', -    'chat_script': '', -    'deleted': False, -    'description': '', -    'device': '', -    'disable': False, -    'disable_link_detect': 1, -    'on_demand': False, -    'metric': '10', -    'mtu': '1500', -    'name_server': True, -    'is_bridge_member': False, -    'intf': '', -    'vrf': '' -} +# XXX: workaround for https://phabricator.vyos.net/T2660 +default_values = {'backup' : {'distance' : '10'}}  def check_kmod():      modules = ['option', 'usb_wwan', 'usbserial'] @@ -66,115 +50,81 @@ def find_device_file(device):      return None  def get_config(): -    wwan = deepcopy(default_config_data) +    """ Retrive CLI config as dictionary. Dictionary can never be empty, +    as at least the interface name will be added or a deleted flag """      conf = Config()      # determine tagNode instance      if 'VYOS_TAGNODE_VALUE' not in os.environ:          raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') -    wwan['intf'] = os.environ['VYOS_TAGNODE_VALUE'] -    wwan['chat_script'] = f"/etc/ppp/peers/chat.{wwan['intf']}" +    # retrieve interface default values +    base = ['interfaces', 'wirelessmodem'] +    # XXX: workaround for https://phabricator.vyos.net/T2660 +    #default_values = defaults(base) + +    ifname = os.environ['VYOS_TAGNODE_VALUE'] +    base = base + [ifname] +    wwan = conf.get_config_dict(base, key_mangling=('-', '_'))      # Check if interface has been removed -    if not conf.exists('interfaces wirelessmodem ' + wwan['intf']): -        wwan['deleted'] = True -        return wwan - -    # set new configuration level -    conf.set_level('interfaces wirelessmodem ' + wwan['intf']) - -    # get metrick for backup default route -    if conf.exists(['apn']): -        wwan['apn'] = conf.return_value(['apn']) - -    # get metrick for backup default route -    if conf.exists(['backup', 'distance']): -        wwan['metric'] = conf.return_value(['backup', 'distance']) - -    # Retrieve interface description -    if conf.exists(['description']): -        wwan['description'] = conf.return_value(['description']) - -    # System device name -    if conf.exists(['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'): -        wwan['disable'] = True - -    # ignore link state changes -    if conf.exists('disable-link-detect'): -        wwan['disable_link_detect'] = 2 - -    # Do not use DNS servers provided by the peer -    if conf.exists(['mtu']): -        wwan['mtu'] = conf.return_value(['mtu']) - -    # Do not use DNS servers provided by the peer -    if conf.exists(['no-peer-dns']): -        wwan['name_server'] = False - -    # Access concentrator name (only connect to this concentrator) -    if conf.exists(['ondemand']): -        wwan['on_demand'] = True - -    # retrieve VRF instance -    if conf.exists('vrf'): -        wwan['vrf'] = conf.return_value(['vrf']) +    if wwan == {}: +        wwan.update({'deleted' : ''}) + +    # We have gathered the dict representation of the CLI, but there are +    # default options which we need to update into the dictionary +    # retrived. +    wwan = dict_merge(default_values, wwan) + +    # Add interface instance name into dictionary +    wwan.update({'ifname': ifname})      return wwan  def verify(wwan): -    if wwan['deleted']: +    if 'deleted' in wwan.keys():          return None -    if not wwan['apn']: -        raise ConfigError('No APN configured for "{intf}"'.format(**wwan)) +    if not 'apn' in wwan.keys(): +        raise ConfigError('No APN configured for "{ifname}"'.format(**wwan)) -    if not wwan['device']: +    if not 'device' in wwan.keys():          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 -    if not os.path.exists('{device}'.format(**wwan)): +    if not os.path.exists(find_device_file(wwan['device'])):          raise ConfigError('Device "{device}" does not exist'.format(**wwan)) -    if wwan['vrf'] and wwan['vrf'] not in interfaces(): -        raise ConfigError('VRF "{vrf}" does not exist'.format(**wwan)) +    verify_bridge_vrf(wwan)      return None  def generate(wwan):      # set up configuration file path variables where our templates will be      # rendered into -    intf = wwan['intf'] -    config_wwan = f'/etc/ppp/peers/{intf}' -    config_wwan_chat = wwan['chat_script'] -    script_wwan_pre_up = f'/etc/ppp/ip-pre-up.d/1010-vyos-wwan-{intf}' -    script_wwan_ip_up = f'/etc/ppp/ip-up.d/1010-vyos-wwan-{intf}' -    script_wwan_ip_down = f'/etc/ppp/ip-down.d/1010-vyos-wwan-{intf}' +    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@{intf}.service') +    call(f'systemctl stop ppp@{ifname}.service') -    if wwan['deleted']: +    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 @@ -195,20 +145,13 @@ def generate(wwan):      return None  def apply(wwan): -    if wwan['deleted']: +    if 'deleted' in wwan.keys():          # bail out early          return None -    if not wwan['disable']: +    if not 'disable' in wwan.keys():          # "dial" WWAN connection -        intf = wwan['intf'] -        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 -        # Interfaces.add_to_bridge() so STP settings won't get applied -        if wwan['is_bridge_member'] in Section.interfaces('bridge'): -            BridgeIf(wwan['is_bridge_member'], create=False).add_port(wwan['intf']) +        call('systemctl start ppp@{ifname}.service'.format(**wwan))      return None | 
