summaryrefslogtreecommitdiff
path: root/src/conf_mode/interfaces-pppoe.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/interfaces-pppoe.py')
-rwxr-xr-xsrc/conf_mode/interfaces-pppoe.py149
1 files changed, 116 insertions, 33 deletions
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index 8ec78bab3..f948070ee 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -20,9 +20,9 @@ from sys import exit
from copy import deepcopy
from jinja2 import Template
from subprocess import Popen, PIPE
-from time import sleep
from pwd import getpwnam
from grp import getgrnam
+from stat import S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH
from vyos.config import Config
from vyos.ifconfig import Interface
@@ -30,9 +30,7 @@ from vyos import ConfigError
from netifaces import interfaces
# Please be careful if you edit the template.
-config_pppoe_tmpl = """
-### Autogenerated by interfaces-pppoe.py ###
-
+config_pppoe_tmpl = """### Autogenerated by interfaces-pppoe.py ###
{% if description %}
# {{ description }}
{% endif %}
@@ -92,14 +90,85 @@ usepeerdns
{% endif %}
{% if ipv6_enable -%}
+ipv6
+ipv6cp-use-ipaddr
{% endif %}
{% if service_name -%}
rp_pppoe_service "{{ service_name }}"
{% endif %}
+{% if on_demand %}
+demand
+{% endif %}
"""
-PPP_LOGFILE = '/var/log/vyatta/ppp_{}.log'
+# 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
+
+# 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 dialer interface $6 via $2"
+
+echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias
+
+{% if ipv6_autoconf -%}
+
+
+# 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_pre_up_tmpl = """#!/bin/sh
+
+# As PPPoE is an "on demand" interface we need to re-configure it when it
+# becomes up
+
+if [ "$6" != "pppoe0" ]; then
+ exit
+fi
+
+# add some info to syslog
+DIALER_PID=$(cat /var/run/{{ intf }}.pid)
+logger -t pppd[$DIALER_PID] "executing $0"
+
+{% 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': '',
@@ -108,7 +177,7 @@ default_config_data = {
'on_demand': False,
'default_route': 'auto',
'deleted': False,
- 'description': '',
+ 'description': '\0',
'disable': False,
'intf': '',
'idle_timeout': '',
@@ -120,7 +189,8 @@ default_config_data = {
'name_server': True,
'remote_address': '',
'service_name': '',
- 'source_interface': ''
+ 'source_interface': '',
+ 'vrf': ''
}
def subprocess_cmd(command):
@@ -137,7 +207,7 @@ def get_config():
raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified')
pppoe['intf'] = os.environ['VYOS_TAGNODE_VALUE']
- pppoe['logfile'] = PPP_LOGFILE.format(pppoe['intf'])
+ pppoe['logfile'] = f"/var/log/vyatta/ppp_{pppoe['intf']}.log"
# Check if interface has been removed
if not conf.exists(base_path + [pppoe['intf']]):
@@ -193,7 +263,7 @@ def get_config():
# Physical Interface used for this PPPoE session
if conf.exists(['source-interface']):
- pppoe['source_interface'] = conf.return_value('source-interface')
+ pppoe['source_interface'] = conf.return_value(['source-interface'])
# Maximum Transmission Unit (MTU)
if conf.exists(['mtu']):
@@ -211,6 +281,10 @@ def get_config():
if conf.exists(['service-name']):
pppoe['service_name'] = conf.return_value(['service-name'])
+ # retrieve VRF instance
+ if conf.exists('vrf'):
+ pppoe['vrf'] = conf.return_value(['vrf'])
+
return pppoe
def verify(pppoe):
@@ -219,18 +293,24 @@ def verify(pppoe):
return None
if not pppoe['source_interface']:
- raise ConfigError('PPPoE source interface is missing')
+ raise ConfigError('PPPoE source interface missing')
+
+ if not pppoe['source_interface'] in interfaces():
+ raise ConfigError(f"PPPoE source interface {pppoe['source_interface']} does not exist")
- if pppoe['source_interface'] not in interfaces():
- raise ConfigError('PPPoE source interface does not exist')
+ vrf_name = pppoe['vrf']
+ if vrf_name and vrf_name not in interfaces():
+ raise ConfigError(f'VRF {vrf_name} does not exist')
return None
def generate(pppoe):
- config_file_pppoe = '/etc/ppp/peers/{}'.format(pppoe['intf'])
+ config_file_pppoe = f"/etc/ppp/peers/{pppoe['intf']}"
+ ip_pre_up_script_file = f"/etc/ppp/ip-pre-up.d/9999-vyos-vrf-{pppoe['intf']}"
+ ipv6_if_up_script_file = f"/etc/ppp/ipv6-up.d/50-vyos-{pppoe['intf']}-autoconf"
# Always hang-up PPPoE connection prior generating new configuration file
- cmd = 'systemctl stop ppp@{}.service'.format(pppoe['intf'])
+ cmd = f"systemctl stop ppp@{pppoe['intf']}.service"
subprocess_cmd(cmd)
if pppoe['deleted']:
@@ -238,6 +318,12 @@ def generate(pppoe):
if os.path.exists(config_file_pppoe):
os.unlink(config_file_pppoe)
+ if os.path.exists(ipv6_if_up_script_file):
+ os.unlink(ipv6_if_up_script_file)
+
+ if os.path.exists(ip_pre_up_script_file):
+ os.unlink(ip_pre_up_script_file)
+
else:
# Create PPP configuration files
tmpl = Template(config_pppoe_tmpl)
@@ -245,6 +331,21 @@ def generate(pppoe):
with open(config_file_pppoe, 'w') as f:
f.write(config_text)
+ tmpl = Template(config_pppoe_ip_pre_up_tmpl)
+ config_text = tmpl.render(pppoe)
+ with open(ip_pre_up_script_file, 'w') as f:
+ f.write(config_text)
+
+ tmpl = Template(config_pppoe_ipv6_up_tmpl)
+ config_text = tmpl.render(pppoe)
+ with open(ipv6_if_up_script_file, 'w') as f:
+ f.write(config_text)
+
+ bitmask = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | \
+ S_IROTH | S_IXOTH
+ os.chmod(ip_pre_up_script_file, bitmask)
+ os.chmod(ipv6_if_up_script_file, bitmask)
+
return None
def apply(pppoe):
@@ -254,7 +355,7 @@ def apply(pppoe):
if not pppoe['disable']:
# dial PPPoE connection
- cmd = 'systemctl start ppp@{}.service'.format(pppoe['intf'])
+ cmd = f"systemctl start ppp@{pppoe['intf']}.service"
subprocess_cmd(cmd)
# make logfile owned by root / vyattacfg
@@ -263,24 +364,6 @@ def apply(pppoe):
gid = getgrnam('vyattacfg').gr_gid
os.chown(pppoe['logfile'], uid, gid)
- # better late then sorry ... but we can only set interface alias after
- # pppd has been launched and created the interface
- cnt = 0
- while pppoe['intf'] not in interfaces():
- cnt += 1
- if cnt == 50:
- break
-
- # sleep 250ms
- sleep(0.250)
-
- try:
- # we need to catch the exception if the interface is not up due to
- # reason stated above
- Interface(pppoe['intf']).set_alias(pppoe['description'])
- except:
- pass
-
return None
if __name__ == '__main__':