diff options
Diffstat (limited to 'src/conf_mode/interfaces-pppoe.py')
-rwxr-xr-x | src/conf_mode/interfaces-pppoe.py | 149 |
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__': |