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.py211
1 files changed, 89 insertions, 122 deletions
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index 6acb45d5e..353a5a12c 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -18,85 +18,14 @@ import os
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 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, chmod_x, 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
-
-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
-{% endif %}
-{% if service_name -%}
-rp_pppoe_service "{{ service_name }}"
-{% endif %}
-
-"""
-
-PPP_LOGFILE = '/var/log/vyatta/ppp_{}.log'
default_config_data = {
'access_concentrator': '',
@@ -105,7 +34,7 @@ default_config_data = {
'on_demand': False,
'default_route': 'auto',
'deleted': False,
- 'description': '',
+ 'description': '\0',
'disable': False,
'intf': '',
'idle_timeout': '',
@@ -117,24 +46,21 @@ default_config_data = {
'name_server': True,
'remote_address': '',
'service_name': '',
- 'source_interface': ''
+ 'source_interface': '',
+ 'vrf': ''
}
-def subprocess_cmd(command):
- p = Popen(command, stdout=PIPE, shell=True)
- p.communicate()
-
def get_config():
pppoe = deepcopy(default_config_data)
conf = Config()
base_path = ['interfaces', 'pppoe']
# determine tagNode instance
- try:
- pppoe['intf'] = os.environ['VYOS_TAGNODE_VALUE']
- pppoe['logfile'] = PPP_LOGFILE.format(pppoe['intf'])
- except KeyError as E:
- print("Interface not specified")
+ if 'VYOS_TAGNODE_VALUE' not in os.environ:
+ raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified')
+
+ pppoe['intf'] = os.environ['VYOS_TAGNODE_VALUE']
+ pppoe['logfile'] = f"/var/log/vyatta/ppp_{pppoe['intf']}.log"
# Check if interface has been removed
if not conf.exists(base_path + [pppoe['intf']]):
@@ -190,7 +116,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']):
@@ -208,6 +134,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):
@@ -216,32 +146,90 @@ 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")
+
+ vrf_name = pppoe['vrf']
+ if vrf_name and vrf_name not in interfaces():
+ raise ConfigError(f'VRF {vrf_name} does not exist')
- if pppoe['source_interface'] not in interfaces():
- raise ConfigError('PPPoE source interface does not exist')
+ if pppoe['on_demand'] and pppoe['vrf']:
+ raise ConfigError('On-demand dialing and VRF can not be used at the same time')
return None
def generate(pppoe):
- config_file_pppoe = '/etc/ppp/peers/{}'.format(pppoe['intf'])
+ # 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, trim_blocks=True)
+
+ # set up configuration file path variables where our templates will be
+ # rendered into
+ intf = pppoe['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_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:
+ dirname = os.path.dirname(file)
+ if not os.path.isdir(dirname):
+ os.mkdir(dirname)
# Always hang-up PPPoE connection prior generating new configuration file
- cmd = 'systemctl stop ppp@{}.service'.format(pppoe['intf'])
- subprocess_cmd(cmd)
+ cmd(f'systemctl stop ppp@{intf}.service')
if pppoe['deleted']:
# Delete PPP configuration files
- if os.path.exists(config_file_pppoe):
- os.unlink(config_file_pppoe)
+ for file in config_files:
+ if os.path.exists(file):
+ os.unlink(file)
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(config_file_pppoe, 'w') as f:
+ 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(script_pppoe_ip_up, 'w') as f:
+ f.write(config_text)
+
+ # Create script for ip-down.d
+ tmpl = env.get_template('ip-down.script.tmpl')
+ config_text = tmpl.render(pppoe)
+ with open(script_pppoe_ip_down, 'w') as f:
+ f.write(config_text)
+
+ # Create script for ipv6-up.d
+ tmpl = env.get_template('ipv6-up.script.tmpl')
+ config_text = tmpl.render(pppoe)
+ with open(script_pppoe_ipv6_up, 'w') as f:
+ f.write(config_text)
+
+ # make generated script file executable
+ chmod_x(script_pppoe_pre_up)
+ chmod_x(script_pppoe_ip_up)
+ chmod_x(script_pppoe_ip_down)
+ chmod_x(script_pppoe_ipv6_up)
+
return None
def apply(pppoe):
@@ -250,33 +238,12 @@ def apply(pppoe):
return None
if not pppoe['disable']:
- # dial PPPoE connection
- cmd = 'systemctl start ppp@{}.service'.format(pppoe['intf'])
- subprocess_cmd(cmd)
+ # "dial" PPPoE connection
+ intf = pppoe['intf']
+ cmd(f'systemctl start ppp@{intf}.service')
# make logfile owned by root / vyattacfg
- if os.path.isfile(pppoe['logfile']):
- uid = getpwnam('root').pw_uid
- 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
+ chown(pppoe['logfile'], 'root', 'vyattacfg')
return None