diff options
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): |