summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/pppoe/ip-down.script.tmpl26
-rw-r--r--data/templates/pppoe/ip-pre-up.script.tmpl19
-rw-r--r--data/templates/pppoe/ip-up.script.tmpl47
-rw-r--r--data/templates/pppoe/ipv6-up.script.tmpl41
-rw-r--r--data/templates/pppoe/peer.tmpl63
-rw-r--r--data/templates/wwan/chat.tmpl6
-rw-r--r--data/templates/wwan/ip-down.script.tmpl26
-rw-r--r--data/templates/wwan/ip-pre-up.script.tmpl23
-rw-r--r--data/templates/wwan/ip-up.script.tmpl25
-rw-r--r--data/templates/wwan/peer.tmpl30
-rw-r--r--interface-definitions/interfaces-pppoe.xml.in3
-rw-r--r--interface-definitions/interfaces-wireless.xml.in2
-rw-r--r--python/vyos/ifconfig/control.py30
-rw-r--r--python/vyos/ifconfig/ethernet.py27
-rw-r--r--python/vyos/util.py46
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py9
-rwxr-xr-xsrc/conf_mode/interfaces-pppoe.py201
-rwxr-xr-xsrc/conf_mode/interfaces-wireless.py12
-rwxr-xr-xsrc/conf_mode/interfaces-wirelessmodem.py128
-rwxr-xr-xsrc/etc/ppp/ip-down.d/0020-wirelessmodem18
-rwxr-xr-xsrc/etc/ppp/ip-up.d/0020-wirelessmodem18
-rwxr-xr-xsrc/op_mode/show_openvpn.py4
22 files changed, 480 insertions, 324 deletions
diff --git a/data/templates/pppoe/ip-down.script.tmpl b/data/templates/pppoe/ip-down.script.tmpl
new file mode 100644
index 000000000..e76875f12
--- /dev/null
+++ b/data/templates/pppoe/ip-down.script.tmpl
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# As PPPoE is an "on demand" interface we need to re-configure it when it
+# becomes up
+if [ "$6" != "{{ intf }}" ]; then
+ exit
+fi
+
+# add some info to syslog
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "executing $0"
+
+# Determine if we are enslaved to a VRF, this is needed to properly insert
+# the default route
+VRF_NAME=""
+if [ -d /sys/class/net/{{ intf }}/upper_* ]; then
+ # Determine upper (VRF) interface
+ VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*))
+ # Remove upper_ prefix from result string
+ VRF=${VRF#"upper_"}
+ # Populate variable to run in VR context
+ VRF_NAME="vrf ${VRF_NAME}"
+fi
+
+# Always delete default route when interface goes down
+vtysh -c "conf t" ${VRF_NAME} -c "no ip route 0.0.0.0/0 {{ intf }} ${VRF_NAME}"
diff --git a/data/templates/pppoe/ip-pre-up.script.tmpl b/data/templates/pppoe/ip-pre-up.script.tmpl
new file mode 100644
index 000000000..f72781e41
--- /dev/null
+++ b/data/templates/pppoe/ip-pre-up.script.tmpl
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# As PPPoE is an "on demand" interface we need to re-configure it when it
+# becomes up
+
+if [ "$6" != "{{ intf }}" ]; then
+ exit
+fi
+
+# add some info to syslog
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "executing $0"
+
+echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias
+
+{% if vrf -%}
+logger -t pppd[$DIALER_PID] "configuring dialer interface $6 for VRF {{ vrf }}"
+ip link set dev {{ intf }} master {{ vrf }}
+{% endif %}
diff --git a/data/templates/pppoe/ip-up.script.tmpl b/data/templates/pppoe/ip-up.script.tmpl
new file mode 100644
index 000000000..4cc779914
--- /dev/null
+++ b/data/templates/pppoe/ip-up.script.tmpl
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# As PPPoE is an "on demand" interface we need to re-configure it when it
+# becomes up
+if [ "$6" != "{{ intf }}" ]; then
+ exit
+fi
+
+set -x
+
+# add some info to syslog
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "executing $0"
+
+SED_OPT="ip route"
+VRF_NAME=""
+if [ -d /sys/class/net/{{ intf }}/upper_* ]; then
+ # Determine upper (VRF) interface
+ VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*))
+ # Remove upper_ prefix from result string
+ VRF=${VRF#"upper_"}
+ # generate new SED command
+ SED_OPT="vrf ${VRF}"
+ # generate vtysh option
+ VRF_NAME="vrf ${VRF}"
+fi
+
+# Debian PPP version has no support for replacing an existing default route
+# thus we emulate this ba an ip-up script https://phabricator.vyos.net/T2220.
+{% if 'auto' in default_route -%}
+# only insert a new default route if there is no default route configured
+routes=$(vtysh -c "show running-config" | sed -n "/${SED_OPT}/,/!/p" | grep 0.0.0.0/0 | wc -l)
+if [ "$routes" -ne 0 ]; then
+ exit 1
+fi
+
+{% elif 'force' in default_route -%}
+# Retrieve current static default routes and remove it from the routing table
+vtysh -c "show running-config" | sed -n "/${SED_OPT}/,/!/p" | grep 0.0.0.0/0 | while read route ; do
+ vtysh -c "conf t" ${VTY_OPT} -c "no ${route} ${VRF_NAME}"
+done
+{% endif %}
+
+# Add default route to default or VRF routing table
+vtysh -c "conf t" ${VTY_OPT} -c "ip route 0.0.0.0/0 {{ intf }} ${VRF_NAME}"
+logger -t pppd[$DIALER_PID] "added default route via {{ intf }} ${VRF_NAME}"
+
diff --git a/data/templates/pppoe/ipv6-up.script.tmpl b/data/templates/pppoe/ipv6-up.script.tmpl
new file mode 100644
index 000000000..a4b08ddaf
--- /dev/null
+++ b/data/templates/pppoe/ipv6-up.script.tmpl
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# As PPPoE is an "on demand" interface we need to re-configure it when it
+# becomes up
+
+if [ "$6" != "{{ intf }}" ]; then
+ exit
+fi
+
+{% if ipv6_autoconf -%}
+# add some info to syslog
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "executing $0"
+logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} via {{ source_interface }}"
+
+# Configure interface-specific Host/Router behaviour.
+# Note: It is recommended to have the same setting on all interfaces; mixed
+# router/host scenarios are rather uncommon. Possible values are:
+#
+# 0 Forwarding disabled
+# 1 Forwarding enabled
+#
+echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/forwarding
+
+# Accept Router Advertisements; autoconfigure using them.
+#
+# It also determines whether or not to transmit Router
+# Solicitations. If and only if the functional setting is to
+# accept Router Advertisements, Router Solicitations will be
+# transmitted. Possible values are:
+#
+# 0 Do not accept Router Advertisements.
+# 1 Accept Router Advertisements if forwarding is disabled.
+# 2 Overrule forwarding behaviour. Accept Router Advertisements
+# even if forwarding is enabled.
+#
+echo 2 > /proc/sys/net/ipv6/conf/{{ intf }}/accept_ra
+
+# Autoconfigure addresses using Prefix Information in Router Advertisements.
+echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/autoconfigure
+{% endif %}
diff --git a/data/templates/pppoe/peer.tmpl b/data/templates/pppoe/peer.tmpl
new file mode 100644
index 000000000..8651f12a5
--- /dev/null
+++ b/data/templates/pppoe/peer.tmpl
@@ -0,0 +1,63 @@
+### Autogenerated by interfaces-pppoe.py ###
+
+{% if description %}
+# {{ description }}
+{% endif %}
+
+# Require peer to provide the local IP address if it is not
+# specified explicitly in the config file.
+noipdefault
+
+# Don't show the password in logfiles:
+hide-password
+
+# Standard Link Control Protocol (LCP) parameters:
+lcp-echo-interval 20
+lcp-echo-failure 3
+
+# RFC 2516, paragraph 7 mandates that the following options MUST NOT be
+# requested and MUST be rejected if requested by the peer:
+# Address-and-Control-Field-Compression (ACFC)
+noaccomp
+
+# Asynchronous-Control-Character-Map (ACCM)
+default-asyncmap
+
+# Override any connect script that may have been set in /etc/ppp/options.
+connect /bin/true
+
+# Don't try to authenticate the remote node
+noauth
+
+# Don't try to proxy ARP for the remote endpoint. User can set proxy
+# arp entries up manually if they wish. More importantly, having
+# the "proxyarp" parameter set disables the "defaultroute" option.
+noproxyarp
+
+# Unlimited connection attempts
+maxfail 0
+
+plugin rp-pppoe.so
+{{ source_interface }}
+persist
+ifname {{ intf }}
+ipparam {{ intf }}
+debug
+logfile {{ logfile }}
+mtu {{ mtu }}
+mru {{ mtu }}
+user "{{ auth_username }}"
+password "{{ auth_password }}"
+{% if name_server -%}
+usepeerdns
+{% endif %}
+{% if ipv6_enable -%}
++ipv6
+ipv6cp-use-ipaddr
+{% endif %}
+{% if service_name -%}
+rp_pppoe_service "{{ service_name }}"
+{% endif %}
+{% if on_demand %}
+demand
+{% endif %}
diff --git a/data/templates/wwan/chat.tmpl b/data/templates/wwan/chat.tmpl
new file mode 100644
index 000000000..78453bc5b
--- /dev/null
+++ b/data/templates/wwan/chat.tmpl
@@ -0,0 +1,6 @@
+ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT 'NO CARRIER' ABORT DELAYED
+'' AT
+OK ATZ
+OK 'AT+CGDCONT=1,"IP","{{ apn }}"'
+OK ATD*99#
+CONNECT ''
diff --git a/data/templates/wwan/ip-down.script.tmpl b/data/templates/wwan/ip-down.script.tmpl
new file mode 100644
index 000000000..194f8d863
--- /dev/null
+++ b/data/templates/wwan/ip-down.script.tmpl
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+tty=$2
+
+# Only applicable for Wireless Modems (WWAN)
+if [ -z "$(echo $tty | egrep "tty(USB|ACM)")" ]; then
+ exit 0
+fi
+
+# Determine if we are enslaved to a VRF, this is needed to properly insert
+# the default route
+VRF_NAME=""
+if [ -d /sys/class/net/{{ intf }}/upper_* ]; then
+ # Determine upper (VRF) interface
+ VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*))
+ # Remove upper_ prefix from result string
+ VRF=${VRF#"upper_"}
+ # Populate variable to run in VR context
+ VRF_NAME=" -c vrf ${VRF_NAME} "
+fi
+
+# Remove default route to either default or VRF routing table
+vtysh -c "conf t" ${VRF_NAME} -c "no ip route 0.0.0.0/0 {{ intf }} {{ metric }}"
+
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "removed default route via {{ intf }} metric {{ metric }}"
diff --git a/data/templates/wwan/ip-pre-up.script.tmpl b/data/templates/wwan/ip-pre-up.script.tmpl
new file mode 100644
index 000000000..f20c75ea3
--- /dev/null
+++ b/data/templates/wwan/ip-pre-up.script.tmpl
@@ -0,0 +1,23 @@
+#!/bin/sh
+# As WWAN is an "on demand" interface we need to re-configure it when it
+# becomes 'up'
+
+ipparam=$6
+
+# device name and metric are received using ipparam
+device=`echo "$ipparam"|awk '{ print $1 }'`
+
+if [ "$device" != "{{ intf }}" ]; then
+ exit
+fi
+
+# add some info to syslog
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "executing $0"
+
+echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias
+
+{% if vrf -%}
+logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} for VRF {{ vrf }}"
+ip link set dev {{ intf }} master {{ vrf }}
+{% endif %}
diff --git a/data/templates/wwan/ip-up.script.tmpl b/data/templates/wwan/ip-up.script.tmpl
new file mode 100644
index 000000000..89e42a23a
--- /dev/null
+++ b/data/templates/wwan/ip-up.script.tmpl
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+tty=$2
+
+# Only applicable for Wireless Modems (WWAN)
+if [ -z "$(echo $tty | egrep "tty(USB|ACM)")" ]; then
+ exit 0
+fi
+
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+
+# Determine if we are enslaved to a VRF, this is needed to properly insert
+# the default route
+VRF_NAME=""
+if [ -d /sys/class/net/{{ intf }}/upper_* ]; then
+ # Determine upper (VRF) interface
+ VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*))
+ # Remove upper_ prefix from result string
+ VRF=${VRF#"upper_"}
+ VRF_NAME="vrf ${VRF}"
+fi
+
+# Apply default route to either default or VRF routing table
+vtysh -c "conf t" -c "ip route 0.0.0.0/0 {{ intf }} ${VRF_NAME} {{ metric }}"
+logger -t pppd[$DIALER_PID] "added default route via {{ intf }} metric {{ metric }} ${VRF_NAME}"
diff --git a/data/templates/wwan/peer.tmpl b/data/templates/wwan/peer.tmpl
new file mode 100644
index 000000000..04ab4f844
--- /dev/null
+++ b/data/templates/wwan/peer.tmpl
@@ -0,0 +1,30 @@
+### Autogenerated by interfaces-wirelessmodem.py ###
+
+{% if description %}
+# {{ description }}
+{% endif %}
+ifname {{ intf }}
+ipparam {{ intf }}
+linkname {{ intf }}
+{% if name_server -%}
+usepeerdns
+{%- endif %}
+# physical device
+/dev/{{ device }}
+lcp-echo-failure 0
+115200
+debug
+logfile {{ logfile }}
+nodefaultroute
+ipcp-max-failure 4
+ipcp-accept-local
+ipcp-accept-remote
+noauth
+crtscts
+lock
+persist
+{% if on_demand -%}
+demand
+{%- endif %}
+
+connect '/usr/sbin/chat -v -t6 -f {{ chat_script }}'
diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in
index bc7995918..d69e0b42c 100644
--- a/interface-definitions/interfaces-pppoe.xml.in
+++ b/interface-definitions/interfaces-pppoe.xml.in
@@ -8,12 +8,11 @@
<priority>321</priority>
<constraint>
<regex>^pppoe[0-9]+$</regex>
- <validator name="numeric" argument="--range 1-99"/>
</constraint>
<constraintErrorMessage>PPPoE interface must be named pppoeN</constraintErrorMessage>
<valueHelp>
<format>pppoeN</format>
- <description>PPPoE interface name (1-15)</description>
+ <description>PPPoE dialer interface name</description>
</valueHelp>
</properties>
<children>
diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in
index 12736510b..490e63a42 100644
--- a/interface-definitions/interfaces-wireless.xml.in
+++ b/interface-definitions/interfaces-wireless.xml.in
@@ -320,7 +320,7 @@
<properties>
<help>VHT link adaptation capabilities</help>
<completionHelp>
- <list>single-user-beamformer single-user-beamformee multi-user-beamformer multi-user-beamformee</list>
+ <list>unsolicited both</list>
</completionHelp>
<valueHelp>
<format>unsolicited</format>
diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py
index c1a073aef..c7a2fa2d6 100644
--- a/python/vyos/ifconfig/control.py
+++ b/python/vyos/ifconfig/control.py
@@ -15,8 +15,9 @@
import os
-from subprocess import Popen, PIPE, STDOUT
+from vyos.util import debug, debug_msg
+from vyos.util import popen, cmd
from vyos.ifconfig.register import Register
@@ -32,27 +33,18 @@ class Control(Register):
# to prevent this, debugging can be explicitely disabled
# if debug is not explicitely disabled the the config, enable it
- self.debug = kargs.get('debug', True)
+ self.debug = ''
+ if kargs.get('debug', True):
+ self.debug = debug('ifconfig')
- def _debug_msg(self, msg):
- if os.path.isfile('/tmp/vyos.ifconfig.debug') and self.debug:
- print('DEBUG/{:<6} {}'.format(self.config['ifname'], msg))
+ def _debug_msg (self, message):
+ return debug_msg(message, self.debug)
def _popen(self, command):
- p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True)
- tmp = p.communicate()[0].strip()
- self._debug_msg(f"cmd '{command}'")
- decoded = tmp.decode()
- if decoded:
- self._debug_msg(f"returned:\n{decoded}")
- return decoded, p.returncode
+ return popen(command, self.debug)
def _cmd(self, command):
- decoded, code = self._popen(command)
- if code != 0:
- # error code can be recovered with .errno
- raise OSError(code, f'{command}\nreturned: {decoded}')
- return decoded
+ return cmd(command, self.debug)
def _get_command(self, config, name):
"""
@@ -79,6 +71,10 @@ class Control(Register):
if convert:
value = convert(value)
+ possible = self._command_set[name].get('possible', None)
+ if possible and not possible(config['ifname'], value):
+ return False
+
config = {**config, **{'value': value}}
cmd = self._command_set[name]['shellcmd'].format(**config)
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 50552dc71..c18d2e72f 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -18,7 +18,7 @@ import re
from vyos.ifconfig.interface import Interface
from vyos.ifconfig.vlan import VLAN
-
+from vyos.util import popen
from vyos.validate import *
@@ -43,27 +43,36 @@ class EthernetIf(Interface):
}
}
+ @staticmethod
+ def feature(ifname, option, value):
+ out, code = popen(f'/sbin/ethtool -K {ifname} {option} {value}','ifconfig')
+ return False
_command_set = {**Interface._command_set, **{
'gro': {
'validate': lambda v: assert_list(v, ['on', 'off']),
- 'shellcmd': '/sbin/ethtool -K {ifname} gro {value}',
+ 'possible': lambda i, v: EthernetIf.feature(i, 'gro', v),
+ # 'shellcmd': '/sbin/ethtool -K {ifname} gro {value}',
},
'gso': {
'validate': lambda v: assert_list(v, ['on', 'off']),
- 'shellcmd': '/sbin/ethtool -K {ifname} gso {value}',
+ 'possible': lambda i, v: EthernetIf.feature(i, 'gso', v),
+ # 'shellcmd': '/sbin/ethtool -K {ifname} gso {value}',
},
'sg': {
'validate': lambda v: assert_list(v, ['on', 'off']),
- 'shellcmd': '/sbin/ethtool -K {ifname} sg {value}',
+ 'possible': lambda i, v: EthernetIf.feature(i, 'sg', v),
+ # 'shellcmd': '/sbin/ethtool -K {ifname} sg {value}',
},
'tso': {
'validate': lambda v: assert_list(v, ['on', 'off']),
- 'shellcmd': '/sbin/ethtool -K {ifname} tso {value}',
+ 'possible': lambda i, v: EthernetIf.feature(i, 'tso', v),
+ # 'shellcmd': '/sbin/ethtool -K {ifname} tso {value}',
},
'ufo': {
'validate': lambda v: assert_list(v, ['on', 'off']),
- 'shellcmd': '/sbin/ethtool -K {ifname} ufo {value}',
+ 'possible': lambda i, v: EthernetIf.feature(i, 'ufo', v),
+ # 'shellcmd': '/sbin/ethtool -K {ifname} ufo {value}',
},
}}
@@ -245,8 +254,4 @@ class EthernetIf(Interface):
>>> i = EthernetIf('eth0')
>>> i.set_udp_offload('on')
"""
- if state not in ['on', 'off']:
- raise ValueError('state must be "on" or "off"')
-
- cmd = '/sbin/ethtool -K {} ufo {}'.format(self.config['ifname'], state)
- return self._cmd(cmd)
+ return self.set_interface('ufo', state)
diff --git a/python/vyos/util.py b/python/vyos/util.py
index 3970b8bf1..781fd9a2c 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -16,6 +16,52 @@
import os
import re
import sys
+from subprocess import Popen, PIPE, STDOUT
+
+
+# debugging
+
+
+def debug(flag):
+ return flag if os.path.isfile(f'/tmp/vyos.{flag}.debug') else ''
+
+
+def debug_msg(message, section=''):
+ if section:
+ print(f'DEBUG/{section:<6} {message}')
+
+
+# commands
+
+
+def popen(command, section=''):
+ p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True)
+ tmp = p.communicate()[0].strip()
+ debug_msg(f"cmd '{command}'", section)
+ decoded = tmp.decode()
+ if decoded:
+ debug_msg(f"returned:\n{decoded}", section)
+ return decoded, p.returncode
+
+
+def cmd(command, section=''):
+ decoded, code = popen(command, section)
+ if code != 0:
+ # error code can be recovered with .errno
+ raise OSError(code, f'{command}\nreturned: {decoded}')
+ return decoded
+
+
+# file manipulation
+
+
+
+def subprocess_cmd(command):
+ """ execute arbitrary command via Popen """
+ from subprocess import Popen, PIPE
+ p = Popen(command, stdout=PIPE, shell=True)
+ p.communicate()
+
def read_file(path):
""" Read a file to string """
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index fb2d6e6d9..9bac4d759 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -66,6 +66,10 @@ proto {% if 'tcp-active' in protocol -%}tcp-client{% elif 'tcp-passive' in proto
local {{ local_host }}
{% endif %}
+{%- if mode == 'server' and protocol == 'udp' and not local_host %}
+multihome
+{% endif %}
+
{%- if local_port %}
lport {{ local_port }}
{% endif %}
@@ -308,7 +312,7 @@ default_config_data = {
'ncp_ciphers': '',
'options': [],
'persistent_tunnel': False,
- 'protocol': '',
+ 'protocol': 'udp',
'redirect_gateway': '',
'remote_address': '',
'remote_host': [],
@@ -512,8 +516,7 @@ def get_config():
# OpenVPN operation mode
if conf.exists('mode'):
- mode = conf.return_value('mode')
- openvpn['mode'] = mode
+ openvpn['mode'] = conf.return_value('mode')
# Additional OpenVPN options
if conf.exists('openvpn-option'):
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index 9c045534c..37934263c 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -18,153 +18,14 @@ import os
from sys import exit
from copy import deepcopy
-from jinja2 import Template
-from subprocess import Popen, PIPE
+from jinja2 import FileSystemLoader, Environment
+from netifaces import interfaces
from vyos.config import Config
+from vyos.defaults import directories as vyos_data_dir
from vyos.ifconfig import Interface
-from vyos.util import chown_file, chmod_x_file
+from vyos.util import chown_file, chmod_x_file, subprocess_cmd
from vyos import ConfigError
-from netifaces import interfaces
-
-# Please be careful if you edit the template.
-config_pppoe_tmpl = """### Autogenerated by interfaces-pppoe.py ###
-{% if description %}
-# {{ description }}
-{% endif %}
-
-# Require peer to provide the local IP address if it is not
-# specified explicitly in the config file.
-noipdefault
-
-# Don't show the password in logfiles:
-hide-password
-
-# Standard Link Control Protocol (LCP) parameters:
-lcp-echo-interval 20
-lcp-echo-failure 3
-
-# RFC 2516, paragraph 7 mandates that the following options MUST NOT be
-# requested and MUST be rejected if requested by the peer:
-# Address-and-Control-Field-Compression (ACFC)
-noaccomp
-
-# Asynchronous-Control-Character-Map (ACCM)
-default-asyncmap
-
-# Override any connect script that may have been set in /etc/ppp/options.
-connect /bin/true
-
-# Don't try to authenticate the remote node
-noauth
-
-# Don't try to proxy ARP for the remote endpoint. User can set proxy
-# arp entries up manually if they wish. More importantly, having
-# the "proxyarp" parameter set disables the "defaultroute" option.
-noproxyarp
-
-# Unlimited connection attempts
-maxfail 0
-
-plugin rp-pppoe.so
-{{ source_interface }}
-persist
-ifname {{ intf }}
-ipparam {{ intf }}
-debug
-logfile {{ logfile }}
-{% if 'auto' in default_route -%}
-defaultroute
-{% elif 'force' in default_route -%}
-defaultroute
-replacedefaultroute
-{% endif %}
-mtu {{ mtu }}
-mru {{ mtu }}
-user "{{ auth_username }}"
-password "{{ auth_password }}"
-{% if name_server -%}
-usepeerdns
-{% endif %}
-{% if ipv6_enable -%}
-+ipv6
-ipv6cp-use-ipaddr
-{% endif %}
-{% if service_name -%}
-rp_pppoe_service "{{ service_name }}"
-{% endif %}
-{% if on_demand %}
-demand
-{% endif %}
-
-"""
-
-# Please be careful if you edit the template.
-# There must be no blank line at the top pf the script file
-config_pppoe_ipv6_up_tmpl = """#!/bin/sh
-
-# As PPPoE is an "on demand" interface we need to re-configure it when it
-# becomes up
-
-if [ "$6" != "{{ intf }}" ]; then
- exit
-fi
-
-{% if ipv6_autoconf -%}
-# add some info to syslog
-DIALER_PID=$(cat /var/run/{{ intf }}.pid)
-logger -t pppd[$DIALER_PID] "executing $0"
-logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} via $2"
-
-# Configure interface-specific Host/Router behaviour.
-# Note: It is recommended to have the same setting on all interfaces; mixed
-# router/host scenarios are rather uncommon. Possible values are:
-#
-# 0 Forwarding disabled
-# 1 Forwarding enabled
-#
-echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/forwarding
-
-# Accept Router Advertisements; autoconfigure using them.
-#
-# It also determines whether or not to transmit Router
-# Solicitations. If and only if the functional setting is to
-# accept Router Advertisements, Router Solicitations will be
-# transmitted. Possible values are:
-#
-# 0 Do not accept Router Advertisements.
-# 1 Accept Router Advertisements if forwarding is disabled.
-# 2 Overrule forwarding behaviour. Accept Router Advertisements
-# even if forwarding is enabled.
-#
-echo 2 > /proc/sys/net/ipv6/conf/{{ intf }}/accept_ra
-
-# Autoconfigure addresses using Prefix Information in Router Advertisements.
-echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/autoconfigure
-{% endif %}
-"""
-
-config_pppoe_ip_up_tmpl = """#!/bin/sh
-
-# As PPPoE is an "on demand" interface we need to re-configure it when it
-# becomes up
-
-if [ "$6" != "{{ intf }}" ]; then
- exit
-fi
-
-# add some info to syslog
-DIALER_PID=$(cat /var/run/{{ intf }}.pid)
-logger -t pppd[$DIALER_PID] "executing $0"
-
-echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias
-
-{% if vrf -%}
-logger -t pppd[$DIALER_PID] "configuring dialer interface $6 for VRF {{ vrf }}"
-ip link set dev {{ intf }} master {{ vrf }}
-{% endif %}
-
-"""
default_config_data = {
'access_concentrator': '',
@@ -189,10 +50,6 @@ default_config_data = {
'vrf': ''
}
-def subprocess_cmd(command):
- p = Popen(command, stdout=PIPE, shell=True)
- p.communicate()
-
def get_config():
pppoe = deepcopy(default_config_data)
conf = Config()
@@ -301,12 +158,22 @@ def verify(pppoe):
return None
def generate(pppoe):
+ # Prepare Jinja2 template loader from files
+ tmpl_path = os.path.join(vyos_data_dir["data"], "templates", "pppoe")
+ fs_loader = FileSystemLoader(tmpl_path)
+ env = Environment(loader=fs_loader)
+
+ # set up configuration file path variables where our templates will be
+ # rendered into
intf = pppoe['intf']
- config_file_pppoe = f'/etc/ppp/peers/{intf}'
- ip_up_script_file = f'/etc/ppp/ip-up.d/9990-vyos-vrf-{intf}'
- ipv6_if_up_script_file = f'/etc/ppp/ipv6-up.d/9990-vyos-autoconf-{intf}'
+ config_pppoe = f'/etc/ppp/peers/{intf}'
+ script_pppoe_pre_up = f'/etc/ppp/ip-pre-up.d/1000-vyos-pppoe-{intf}'
+ script_pppoe_ip_up = f'/etc/ppp/ip-up.d/1000-vyos-pppoe-{intf}'
+ script_pppoe_ip_down = f'/etc/ppp/ip-down.d/1000-vyos-pppoe-{intf}'
+ script_pppoe_ipv6_up = f'/etc/ppp/ipv6-up.d/1000-vyos-pppoe-{intf}'
- config_files = [config_file_pppoe, ip_up_script_file, ipv6_if_up_script_file]
+ config_files = [config_pppoe, script_pppoe_pre_up, script_pppoe_ip_up,
+ script_pppoe_ip_down, script_pppoe_ipv6_up]
# Ensure directories for config files exist - otherwise create them on demand
for file in config_files:
@@ -326,24 +193,40 @@ def generate(pppoe):
else:
# Create PPP configuration files
- tmpl = Template(config_pppoe_tmpl)
+ tmpl = env.get_template('peer.tmpl')
+ config_text = tmpl.render(pppoe)
+ with open(config_pppoe, 'w') as f:
+ f.write(config_text)
+
+ # Create script for ip-pre-up.d
+ tmpl = env.get_template('ip-pre-up.script.tmpl')
+ config_text = tmpl.render(pppoe)
+ with open(script_pppoe_pre_up, 'w') as f:
+ f.write(config_text)
+
+ # Create script for ip-up.d
+ tmpl = env.get_template('ip-up.script.tmpl')
config_text = tmpl.render(pppoe)
- with open(config_file_pppoe, 'w') as f:
+ with open(script_pppoe_ip_up, 'w') as f:
f.write(config_text)
- tmpl = Template(config_pppoe_ip_up_tmpl)
+ # Create script for ip-down.d
+ tmpl = env.get_template('ip-down.script.tmpl')
config_text = tmpl.render(pppoe)
- with open(ip_up_script_file, 'w') as f:
+ with open(script_pppoe_ip_down, 'w') as f:
f.write(config_text)
- tmpl = Template(config_pppoe_ipv6_up_tmpl)
+ # Create script for ipv6-up.d
+ tmpl = env.get_template('ipv6-up.script.tmpl')
config_text = tmpl.render(pppoe)
- with open(ipv6_if_up_script_file, 'w') as f:
+ with open(script_pppoe_ipv6_up, 'w') as f:
f.write(config_text)
# make generated script file executable
- chmod_x_file(ip_up_script_file)
- chmod_x_file(ipv6_if_up_script_file)
+ chmod_x_file(script_pppoe_pre_up)
+ chmod_x_file(script_pppoe_ip_up)
+ chmod_x_file(script_pppoe_ip_down)
+ chmod_x_file(script_pppoe_ipv6_up)
return None
diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py
index b6e62b0aa..3c20c3025 100755
--- a/src/conf_mode/interfaces-wireless.py
+++ b/src/conf_mode/interfaces-wireless.py
@@ -239,6 +239,10 @@ uapsd_advertisement_enabled=1
require_ht=1
{% endif %}
+{%- if cap_vht_chan_set_width -%}
+vht_oper_chwidth={{ cap_vht_chan_set_width }}
+{%- endif -%}
+
# vht_capab: VHT capabilities (list of flags)
#
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
@@ -369,10 +373,6 @@ vht_capab=
{%- endif -%}
{%- if cap_vht_chan_set_width -%}
-[MAX-A-MPDU-LEN-EXP{{ cap_vht_max_mpdu_exp }}]
-{%- endif -%}
-
-{%- if cap_vht_chan_set_width -%}
{%- if '2' in cap_vht_chan_set_width -%}
[VHT160]
{%- elif '3' in cap_vht_chan_set_width -%}
@@ -799,7 +799,7 @@ default_config_data = {
'cap_vht_center_freq_2' : '',
'cap_vht_chan_set_width' : '',
'cap_vht_ldpc' : False,
- 'cap_vht_link_adaptation' : False,
+ 'cap_vht_link_adaptation' : '',
'cap_vht_max_mpdu_exp' : '',
'cap_vht_max_mpdu' : '',
'cap_vht_short_gi' : [],
@@ -1043,7 +1043,7 @@ def get_config():
# VHT link adaptation capabilities
if conf.exists('capabilities vht link-adaptation'):
wifi['cap_vht'] = True
- wifi['cap_vht_link_adaptation'] = True
+ wifi['cap_vht_link_adaptation'] = conf.return_value('capabilities vht link-adaptation')
# Set the maximum length of A-MPDU pre-EOF padding that the station can receive
if conf.exists('capabilities vht max-mpdu-exp'):
diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py
index 7aee5c9bd..d00259bf5 100755
--- a/src/conf_mode/interfaces-wirelessmodem.py
+++ b/src/conf_mode/interfaces-wirelessmodem.py
@@ -18,84 +18,14 @@ import os
from sys import exit
from copy import deepcopy
-from jinja2 import Template
-from subprocess import Popen, PIPE
+from jinja2 import FileSystemLoader, Environment
from netifaces import interfaces
from vyos.config import Config
-from vyos.util import chown_file, chmod_x_file
+from vyos.defaults import directories as vyos_data_dir
+from vyos.util import chown_file, chmod_x_file, subprocess_cmd
from vyos import ConfigError
-# Please be careful if you edit the template.
-config_wwan_tmpl = """### Autogenerated by interfaces-wirelessmodem.py ###
-{% if description %}
-# {{ description }}
-{% endif %}
-ifname {{ intf }}
-ipparam "{{ intf }} {{ metric }}"
-linkname {{ intf }}
-{% if name_server -%}
-usepeerdns
-{%- endif %}
-# physical device
-/dev/{{ device }}
-lcp-echo-failure 0
-115200
-debug
-logfile {{ logfile }}
-nodefaultroute
-ipcp-max-failure 4
-ipcp-accept-local
-ipcp-accept-remote
-noauth
-crtscts
-lock
-persist
-{% if on_demand -%}
-demand
-{%- endif %}
-
-connect '/usr/sbin/chat -v -t6 -f {{ chat_script }}'
-
-"""
-
-# Please be careful if you edit the template.
-chat_wwan_tmpl = """
-ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT 'NO CARRIER' ABORT DELAYED
-'' AT
-OK ATZ
-OK 'AT+CGDCONT=1,"IP","{{ apn }}"'
-OK ATD*99#
-CONNECT ''
-
-"""
-
-config_wwan_ip_up_tmpl = """#!/bin/sh
-# As WWAN is an "on demand" interface we need to re-configure it when it
-# becomes 'up'
-
-ipparam=$6
-
-# device name and metric are received using ipparam
-device=`echo "$ipparam"|awk '{ print $1 }'`
-
-if [ "$device" != "{{ intf }}" ]; then
- exit
-fi
-
-# add some info to syslog
-DIALER_PID=$(cat /var/run/{{ intf }}.pid)
-logger -t pppd[$DIALER_PID] "executing $0"
-
-echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias
-
-{% if vrf -%}
-logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} for VRF {{ vrf }}"
-ip link set dev {{ intf }} master {{ vrf }}
-{% endif %}
-
-"""
-
default_config_data = {
'address': [],
'apn': '',
@@ -114,10 +44,6 @@ default_config_data = {
'vrf': ''
}
-def subprocess_cmd(command):
- p = Popen(command, stdout=PIPE, shell=True)
- p.communicate()
-
def check_kmod():
modules = ['option', 'usb_wwan', 'usbserial']
for module in modules:
@@ -206,12 +132,22 @@ def verify(wwan):
return None
def generate(wwan):
+ # Prepare Jinja2 template loader from files
+ tmpl_path = os.path.join(vyos_data_dir["data"], "templates", "wwan")
+ fs_loader = FileSystemLoader(tmpl_path)
+ env = Environment(loader=fs_loader)
+
+ # set up configuration file path variables where our templates will be
+ # rendered into
intf = wwan['intf']
- config_file_wwan = f'/etc/ppp/peers/{intf}'
- config_file_wwan_chat = wwan['chat_script']
- ip_up_script_file = f'/etc/ppp/ip-up.d/9991-vyos-vrf-{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}'
- config_files = [config_file_wwan, config_file_wwan_chat, ip_up_script_file]
+ config_files = [config_wwan, config_wwan_chat, script_wwan_pre_up,
+ script_wwan_ip_up, script_wwan_ip_down]
# Ensure directories for config files exist - otherwise create them on demand
for file in config_files:
@@ -231,25 +167,39 @@ def generate(wwan):
else:
# Create PPP configuration files
- tmpl = Template(config_wwan_tmpl)
+ tmpl = env.get_template('peer.tmpl')
config_text = tmpl.render(wwan)
- with open(config_file_wwan, 'w') as f:
+ with open(config_wwan, 'w') as f:
f.write(config_text)
# Create PPP chat script
- tmpl = Template(chat_wwan_tmpl)
+ tmpl = env.get_template('chat.tmpl')
+ config_text = tmpl.render(wwan)
+ with open(config_wwan_chat, 'w') as f:
+ f.write(config_text)
+
+ # Create script for ip-pre-up.d
+ tmpl = env.get_template('ip-pre-up.script.tmpl')
+ config_text = tmpl.render(wwan)
+ with open(script_wwan_pre_up, 'w') as f:
+ f.write(config_text)
+
+ # Create script for ip-up.d
+ tmpl = env.get_template('ip-up.script.tmpl')
config_text = tmpl.render(wwan)
- with open(wwan['chat_script'], 'w') as f:
+ with open(script_wwan_ip_up, 'w') as f:
f.write(config_text)
- # Create ip-pre-up script
- tmpl = Template(config_wwan_ip_up_tmpl)
+ # Create script for ip-down.d
+ tmpl = env.get_template('ip-down.script.tmpl')
config_text = tmpl.render(wwan)
- with open(ip_up_script_file, 'w') as f:
+ with open(script_wwan_ip_down, 'w') as f:
f.write(config_text)
# make generated script file executable
- chmod_x_file(ip_up_script_file)
+ chmod_x_file(script_wwan_pre_up)
+ chmod_x_file(script_wwan_ip_up)
+ chmod_x_file(script_wwan_ip_down)
return None
diff --git a/src/etc/ppp/ip-down.d/0020-wirelessmodem b/src/etc/ppp/ip-down.d/0020-wirelessmodem
deleted file mode 100755
index c93c7cabe..000000000
--- a/src/etc/ppp/ip-down.d/0020-wirelessmodem
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-tty=$2
-ipparam=$6
-
-# Only applicable for Wireless Modems (WWAN)
-if [ -z "$(echo $tty | egrep "tty(USB|ACM)")" ]; then
- exit 0
-fi
-
-# device name and metric are received using ipparam
-device=`echo "$ipparam"|awk '{ print $1 }'`
-metric=`echo "$ipparam"|awk '{ print $2 }'`
-
-vtysh -c "conf t" -c "no ip route 0.0.0.0/0 ${device} ${metric}"
-
-DIALER_PID=$(cat /var/run/${device}.pid)
-logger -t pppd[$DIALER_PID] "removed default route via $device metric $metric"
diff --git a/src/etc/ppp/ip-up.d/0020-wirelessmodem b/src/etc/ppp/ip-up.d/0020-wirelessmodem
deleted file mode 100755
index 95549387b..000000000
--- a/src/etc/ppp/ip-up.d/0020-wirelessmodem
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-tty=$2
-ipparam=$6
-
-# Only applicable for Wireless Modems (WWAN)
-if [ -z "$(echo $tty | egrep "tty(USB|ACM)")" ]; then
- exit 0
-fi
-
-# device name and metric are received using ipparam
-device=`echo "$ipparam"|awk '{ print $1 }'`
-metric=`echo "$ipparam"|awk '{ print $2 }'`
-
-vtysh -c "conf t" -c "ip route 0.0.0.0/0 ${device} ${metric}"
-
-DIALER_PID=$(cat /var/run/${device}.pid)
-logger -t pppd[$DIALER_PID] "added default route via $device metric $metric"
diff --git a/src/op_mode/show_openvpn.py b/src/op_mode/show_openvpn.py
index 06b90296f..32918ddce 100755
--- a/src/op_mode/show_openvpn.py
+++ b/src/op_mode/show_openvpn.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import os
import jinja2
import argparse
@@ -63,6 +64,9 @@ def get_status(mode, interface):
'clients': [],
}
+ if not os.path.exists(status_file):
+ return data
+
with open(status_file, 'r') as f:
lines = f.readlines()
for line_no, line in enumerate(lines):