diff options
| -rw-r--r-- | data/templates/dhcp-client/ipv6_new.tmpl | 47 | ||||
| -rw-r--r-- | data/templates/pppoe/ip-down.script.tmpl | 14 | ||||
| -rw-r--r-- | data/templates/pppoe/ip-pre-up.script.tmpl | 8 | ||||
| -rw-r--r-- | data/templates/pppoe/ip-up.script.tmpl | 12 | ||||
| -rw-r--r-- | data/templates/pppoe/ipv6-up.script.tmpl | 24 | ||||
| -rw-r--r-- | data/templates/pppoe/peer.tmpl | 29 | ||||
| -rw-r--r-- | interface-definitions/interfaces-pppoe.xml.in | 1 | ||||
| -rw-r--r-- | python/vyos/configverify.py | 5 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-pppoe.py | 206 | 
9 files changed, 143 insertions, 203 deletions
| diff --git a/data/templates/dhcp-client/ipv6_new.tmpl b/data/templates/dhcp-client/ipv6_new.tmpl new file mode 100644 index 000000000..112431c5f --- /dev/null +++ b/data/templates/dhcp-client/ipv6_new.tmpl @@ -0,0 +1,47 @@ +# generated by dhcp.py +# man https://www.unix.com/man-page/debian/5/dhcp6c.conf/ + +interface {{ ifname }} { +    request domain-name-servers; +    request domain-name; +{% if dhcpv6_options is defined %} +{%   if dhcpv6_options.parameters_only is defined %} +    information-only; +{%    endif %} +{%    if dhcpv6_options.temporary is not defined %} +    send ia-na 1; # non-temporary address +{%    endif %} +{%    if dhcpv6_options.prefix_delegation is defined %} +    send ia-pd 2; # prefix delegation +{%    endif %} +{%  endif %} +}; + +{% if dhcpv6_options is defined %} +{%   if dhcpv6_options.temporary is not defined %} +id-assoc na 1 { +    # Identity association NA +}; +{%   endif %} + +{%   if dhcpv6_options.prefix_delegation is defined %} +id-assoc pd 2 { +{%     if dhcpv6_options.prefix_delegation.length is defined %} +    prefix ::/{{ dhcpv6_options.prefix_delegation.length }} infinity; +{%     endif %} +{%     for interface in dhcpv6_options.prefix_delegation.interface %} +    prefix-interface {{ interface }} { +{%       if dhcpv6_options.prefix_delegation.interface[interface].sla_id is defined %} +        sla-id {{ dhcpv6_options.prefix_delegation.interface[interface].sla_id }}; +{%       endif %} +{%       if dhcpv6_options.prefix_delegation.interface[interface].sla_len is defined %} +        sla-len {{ dhcpv6_options.prefix_delegation.interface[interface].sla_len }}; +{%       endif %} +{%       if dhcpv6_options.prefix_delegation.interface[interface].address is defined %} +        ifid {{ dhcpv6_options.prefix_delegation.interface[interface].address }}; +{%       endif %} +    }; +{%     endfor %} +}; +{%   endif %} +{% endif %} diff --git a/data/templates/pppoe/ip-down.script.tmpl b/data/templates/pppoe/ip-down.script.tmpl index 9e6bd2a8e..f69f9fc1a 100644 --- a/data/templates/pppoe/ip-down.script.tmpl +++ b/data/templates/pppoe/ip-down.script.tmpl @@ -2,21 +2,21 @@  # As PPPoE is an "on demand" interface we need to re-configure it when it  # becomes up -if [ "$6" != "{{ intf }}" ]; then +if [ "$6" != "{{ ifname }}" ]; then      exit  fi  # add some info to syslog -DIALER_PID=$(cat /var/run/{{ intf }}.pid) +DIALER_PID=$(cat /var/run/{{ ifname }}.pid)  logger -t pppd[$DIALER_PID] "executing $0"  {% if not on_demand %}  # See https://phabricator.vyos.net/T2248. 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 +if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then      # Determine upper (VRF) interface -    VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*)) +    VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))      # Remove upper_ prefix from result string      VRF=${VRF#"upper_"}      # Populate variable to run in VR context @@ -24,13 +24,13 @@ if [ -d /sys/class/net/{{ intf }}/upper_* ]; then  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}" +vtysh -c "conf t" ${VRF_NAME} -c "no ip route 0.0.0.0/0 {{ ifname }} ${VRF_NAME}"  {%   if ipv6_enable %} -vtysh -c "conf t" ${VRF_NAME} -c "no ipv6 route ::/0 {{ intf }} ${VRF_NAME}" +vtysh -c "conf t" ${VRF_NAME} -c "no ipv6 route ::/0 {{ ifname }} ${VRF_NAME}"  {%   endif %}  {% endif %}  {% if dhcpv6_pd_interfaces %}  # Start wide dhcpv6 client -systemctl stop dhcp6c@{{ intf }}.service +systemctl stop dhcp6c@{{ ifname }}.service  {% endif %} diff --git a/data/templates/pppoe/ip-pre-up.script.tmpl b/data/templates/pppoe/ip-pre-up.script.tmpl index 6a2d2af94..cf85ed067 100644 --- a/data/templates/pppoe/ip-pre-up.script.tmpl +++ b/data/templates/pppoe/ip-pre-up.script.tmpl @@ -2,17 +2,17 @@  # As PPPoE is an "on demand" interface we need to re-configure it when it  # becomes up -if [ "$6" != "{{ intf }}" ]; then +if [ "$6" != "{{ ifname }}" ]; then      exit  fi  # add some info to syslog -DIALER_PID=$(cat /var/run/{{ intf }}.pid) +DIALER_PID=$(cat /var/run/{{ ifname }}.pid)  logger -t pppd[$DIALER_PID] "executing $0" -echo "{{ description }}" > /sys/class/net/{{ intf }}/ifalias +echo "{{ description }}" > /sys/class/net/{{ ifname }}/ifalias  {% if vrf -%}  logger -t pppd[$DIALER_PID] "configuring dialer interface $6 for VRF {{ vrf }}" -ip link set dev {{ intf }} master {{ vrf }} +ip link set dev {{ ifname }} master {{ vrf }}  {% endif %} diff --git a/data/templates/pppoe/ip-up.script.tmpl b/data/templates/pppoe/ip-up.script.tmpl index a274296b6..6adea4bd7 100644 --- a/data/templates/pppoe/ip-up.script.tmpl +++ b/data/templates/pppoe/ip-up.script.tmpl @@ -2,13 +2,13 @@  # As PPPoE is an "on demand" interface we need to re-configure it when it  # becomes up -if [ "$6" != "{{ intf }}" ]; then +if [ "$6" != "{{ ifname }}" ]; then      exit  fi  {% if not on_demand %}  # add some info to syslog -DIALER_PID=$(cat /var/run/{{ intf }}.pid) +DIALER_PID=$(cat /var/run/{{ ifname }}.pid)  logger -t pppd[$DIALER_PID] "executing $0"  {%   if default_route != 'none' -%} @@ -17,9 +17,9 @@ logger -t pppd[$DIALER_PID] "executing $0"  SED_OPT="^ip route"  VRF_NAME="" -if [ -d /sys/class/net/{{ intf }}/upper_* ]; then +if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then      # Determine upper (VRF) interface -    VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*)) +    VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))      # Remove upper_ prefix from result string      VRF=${VRF#"upper_"}      # generate new SED command @@ -43,7 +43,7 @@ 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}" +vtysh -c "conf t" ${VTY_OPT} -c "ip route 0.0.0.0/0 {{ ifname }} ${VRF_NAME}" +logger -t pppd[$DIALER_PID] "added default route via {{ ifname }} ${VRF_NAME}"  {%   endif %}  {% endif %} diff --git a/data/templates/pppoe/ipv6-up.script.tmpl b/data/templates/pppoe/ipv6-up.script.tmpl index 097f1d4c3..511e288ea 100644 --- a/data/templates/pppoe/ipv6-up.script.tmpl +++ b/data/templates/pppoe/ipv6-up.script.tmpl @@ -3,17 +3,15 @@  # As PPPoE is an "on demand" interface we need to re-configure it when it  # becomes up -if [ "$6" != "{{ intf }}" ]; then +if [ "$6" != "{{ ifname }}" ]; then      exit  fi -set -x -  {% if ipv6_autoconf -%}  # add some info to syslog -DIALER_PID=$(cat /var/run/{{ intf }}.pid) +DIALER_PID=$(cat /var/run/{{ ifname }}.pid)  logger -t pppd[$DIALER_PID] "executing $0" -logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} via {{ source_interface }}" +logger -t pppd[$DIALER_PID] "configuring interface {{ ifname }} via {{ source_interface }}"  # Configure interface-specific Host/Router behaviour.  # Note: It is recommended to have the same setting on all interfaces; mixed @@ -22,7 +20,7 @@ logger -t pppd[$DIALER_PID] "configuring interface {{ intf }} via {{ source_inte  # 0  Forwarding disabled  # 1  Forwarding enabled  # -echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/forwarding +echo 1 > /proc/sys/net/ipv6/conf/{{ ifname }}/forwarding  # Accept Router Advertisements; autoconfigure using them.  # @@ -36,15 +34,15 @@ echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/forwarding  # 2  Overrule forwarding behaviour. Accept Router Advertisements  #    even if forwarding is enabled.  # -echo 2 > /proc/sys/net/ipv6/conf/{{ intf }}/accept_ra +echo 2 > /proc/sys/net/ipv6/conf/{{ ifname }}/accept_ra  # Autoconfigure addresses using Prefix Information in Router Advertisements. -echo 1 > /proc/sys/net/ipv6/conf/{{ intf }}/autoconf +echo 1 > /proc/sys/net/ipv6/conf/{{ ifname }}/autoconf  {% endif %}  {% if dhcpv6_pd_interfaces %}  # Start wide dhcpv6 client -systemctl start dhcp6c@{{ intf }}.service +systemctl start dhcp6c@{{ ifname }}.service  {% endif %} @@ -54,9 +52,9 @@ systemctl start dhcp6c@{{ intf }}.service  SED_OPT="^ipv6 route"  VRF_NAME="" -if [ -d /sys/class/net/{{ intf }}/upper_* ]; then +if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then      # Determine upper (VRF) interface -    VRF=$(basename $(ls -d /sys/class/net/{{ intf }}/upper_*)) +    VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))      # Remove upper_ prefix from result string      VRF=${VRF#"upper_"}      # generate new SED command @@ -80,8 +78,8 @@ done  {%     endif %}  # Add default route to default or VRF routing table -vtysh -c "conf t" ${VTY_OPT} -c "ipv6 route ::/0 {{ intf }} ${VRF_NAME}" -logger -t pppd[$DIALER_PID] "added default route via {{ intf }} ${VRF_NAME}" +vtysh -c "conf t" ${VTY_OPT} -c "ipv6 route ::/0 {{ ifname }} ${VRF_NAME}" +logger -t pppd[$DIALER_PID] "added default route via {{ ifname }} ${VRF_NAME}"  {%   endif %} diff --git a/data/templates/pppoe/peer.tmpl b/data/templates/pppoe/peer.tmpl index fb85265b2..e909843a5 100644 --- a/data/templates/pppoe/peer.tmpl +++ b/data/templates/pppoe/peer.tmpl @@ -40,32 +40,37 @@ maxfail 0  plugin rp-pppoe.so  {{ source_interface }}  persist -ifname {{ intf }} -ipparam {{ intf }} +ifname {{ ifname }} +ipparam {{ ifname }}  debug  mtu {{ mtu }}  mru {{ mtu }} -user "{{ auth_username }}" -password "{{ auth_password }}" -{% if name_server -%} -usepeerdns + +{% if authentication is defined %} +{{ "user " + authentication.user if authentication.user is defined }} +{{ "password " + authentication.password if authentication.password is defined }}  {% endif %} -{% if ipv6_enable -%} + +{{ "usepeerdns" if no_peer_dns is not defined }} + +{% if ipv6 is defined and ipv6.enable is defined -%}  +ipv6  ipv6cp-use-ipaddr  {% endif %} -{% if service_name -%} + +{% if service_name is defined -%}  rp_pppoe_service "{{ service_name }}"  {% endif %} -{% if on_demand %} + +{% if connect_on_demand is defined %}  demand  # See T2249. PPP default route options should only be set when in on-demand  # mode. As soon as we are not in on-demand mode the default-route handling is  # passed to the ip-up.d/ip-down.s scripts which is required for VRF support. -{% if 'auto' in default_route -%} +{%   if 'auto' in default_route -%}  defaultroute -{% elif 'force' in default_route -%} +{%   elif 'force' in default_route -%}  defaultroute  replacedefaultroute -{% endif %} +{%   endif %}  {% endif %} diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in index 3747a2a7e..8a6c61312 100644 --- a/interface-definitions/interfaces-pppoe.xml.in +++ b/interface-definitions/interfaces-pppoe.xml.in @@ -71,6 +71,7 @@                  <description>Replace existing default route</description>                </valueHelp>              </properties> +            <defaultValue>auto</defaultValue>            </leafNode>            #include <include/dhcpv6-options.xml.i>            #include <include/interface-description.xml.i> diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index e2fffeca7..528428e03 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -32,7 +32,6 @@ def verify_bridge_vrf(config):      if 'vrf' in config.keys():          if config['vrf'] not in interfaces():              raise ConfigError('VRF "{vrf}" does not exist'.format(**config)) -          if 'is_bridge_member' in config.keys():              raise ConfigError(                  'Interface "{ifname}" cannot be both a member of VRF "{vrf}" ' @@ -69,6 +68,10 @@ def verify_source_interface(config):      perform recurring validation of the existence of a source-interface      required by e.g. peth/MACvlan, MACsec ...      """ +    from netifaces import interfaces      if not 'source_interface' in config.keys():          raise ConfigError('Physical source-interface required for '                            'interface "{ifname}"'.format(**config)) +    if not config['source_interface'] in interfaces(): +        raise ConfigError(f'Source interface {source_interface} does not ' +                          f'exist'.format(**config)) diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index 611206d84..503a263f8 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2019 VyOS maintainers and contributors +# Copyright (C) 2019-2020 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -15,179 +15,65 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  import os +import jmespath  from sys import exit  from copy import deepcopy  from netifaces import interfaces  from vyos.config import Config -from vyos.configdict import dhcpv6_pd_default_data -from vyos.ifconfig import Interface +from vyos.configdict import dict_merge +from vyos.configverify import verify_source_interface +from vyos.configverify import verify_bridge_vrf  from vyos.template import render -from vyos.util import chown, chmod_755, call +from vyos.util import call +from vyos.xml import defaults  from vyos import ConfigError -  from vyos import airbag  airbag.enable() -default_config_data = { -    **dhcpv6_pd_default_data, -    'access_concentrator': '', -    'auth_username': '', -    'auth_password': '', -    'on_demand': False, -    'default_route': 'auto', -    'deleted': False, -    'description': '\0', -    'disable': False, -    'intf': '', -    'idle_timeout': '', -    'ipv6_autoconf': False, -    'ipv6_enable': False, -    'local_address': '', -    'mtu': '1492', -    'name_server': True, -    'remote_address': '', -    'service_name': '', -    'source_interface': '', -    'vrf': '' -} -  def get_config(): -    pppoe = deepcopy(default_config_data) +    """ Retrive CLI config as dictionary. Dictionary can never be empty, +    as at least the interface name will be added or a deleted flag """      conf = Config() -    base_path = ['interfaces', 'pppoe']      # determine tagNode instance      if 'VYOS_TAGNODE_VALUE' not in os.environ:          raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') -    pppoe['intf'] = os.environ['VYOS_TAGNODE_VALUE'] - -    # Check if interface has been removed -    if not conf.exists(base_path + [pppoe['intf']]): -        pppoe['deleted'] = True -        return pppoe - -    # set new configuration level -    conf.set_level(base_path + [pppoe['intf']]) - -    # Access concentrator name (only connect to this concentrator) -    if conf.exists(['access-concentrator']): -        pppoe['access_concentrator'] = conf.return_values(['access-concentrator']) - -    # Authentication name supplied to PPPoE server -    if conf.exists(['authentication', 'user']): -        pppoe['auth_username'] = conf.return_value(['authentication', 'user']) - -    # Password for authenticating local machine to PPPoE server -    if conf.exists(['authentication', 'password']): -        pppoe['auth_password'] = conf.return_value(['authentication', 'password']) - -    # Access concentrator name (only connect to this concentrator) -    if conf.exists(['connect-on-demand']): -        pppoe['on_demand'] = True - -    # Enable/Disable default route to peer when link comes up -    if conf.exists(['default-route']): -        pppoe['default_route'] = conf.return_value(['default-route']) - -    # Retrieve interface description -    if conf.exists(['description']): -        pppoe['description'] = conf.return_value(['description']) - -    # Disable this interface -    if conf.exists(['disable']): -        pppoe['disable'] = True - -    # Delay before disconnecting idle session (in seconds) -    if conf.exists(['idle-timeout']): -        pppoe['idle_timeout'] = conf.return_value(['idle-timeout']) - -    # Enable Stateless Address Autoconfiguration (SLAAC) -    if conf.exists(['ipv6', 'address', 'autoconf']): -        pppoe['ipv6_autoconf'] = True +    # retrieve interface default values +    base = ['interfaces', 'pppoe'] +    default_values = defaults(base) +    # PPPoE is "special" the default MTU is 1492 - update accordingly +    default_values['mtu'] = '1492' -    # Activate IPv6 support on this connection -    if conf.exists(['ipv6', 'enable']): -        pppoe['ipv6_enable'] = True +    ifname = os.environ['VYOS_TAGNODE_VALUE'] +    base = base + [ifname] -    # IPv4 address of local end of PPPoE link -    if conf.exists(['local-address']): -        pppoe['local_address'] = conf.return_value(['local-address']) - -    # Physical Interface used for this PPPoE session -    if conf.exists(['source-interface']): -        pppoe['source_interface'] = conf.return_value(['source-interface']) - -    # Maximum Transmission Unit (MTU) -    if conf.exists(['mtu']): -        pppoe['mtu'] = conf.return_value(['mtu']) - -    # Do not use DNS servers provided by the peer -    if conf.exists(['no-peer-dns']): -        pppoe['name_server'] = False - -    # IPv4 address for remote end of PPPoE session -    if conf.exists(['remote-address']): -        pppoe['remote_address'] = conf.return_value(['remote-address']) - -    # Service name, only connect to access concentrators advertising this -    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']) - -    if conf.exists(['dhcpv6-options', 'prefix-delegation']): -        dhcpv6_pd_path = base_path + [pppoe['intf'], -                                      'dhcpv6-options', 'prefix-delegation'] -        conf.set_level(dhcpv6_pd_path) - -        # Retrieve DHCPv6-PD prefix helper length as some ISPs only hand out a -        # /64 by default (https://phabricator.vyos.net/T2506) -        if conf.exists(['length']): -            pppoe['dhcpv6_pd_length'] = conf.return_value(['length']) - -        for interface in conf.list_nodes(['interface']): -            conf.set_level(dhcpv6_pd_path + ['interface', interface]) -            pd = { -                'ifname': interface, -                'sla_id': '', -                'sla_len': '', -                'if_id': '' -            } - -            if conf.exists(['sla-id']): -                pd['sla_id'] = conf.return_value(['sla-id']) - -            if conf.exists(['sla-len']): -                pd['sla_len'] = conf.return_value(['sla-len']) +    pppoe = conf.get_config_dict(base, key_mangling=('-', '_')) +    # Check if interface has been removed +    if pppoe == {}: +        pppoe.update({'deleted' : ''}) -            if conf.exists(['address']): -                pd['if_id'] = conf.return_value(['address']) +    # We have gathered the dict representation of the CLI, but there are +    # default options which we need to update into the dictionary +    # retrived. +    pppoe = dict_merge(default_values, pppoe) -            pppoe['dhcpv6_pd_interfaces'].append(pd) +    # Add interface instance name into dictionary +    pppoe.update({'ifname': ifname})      return pppoe  def verify(pppoe): -    if pppoe['deleted']: +    if 'deleted' in pppoe.keys():          # bail out early          return None -    if not pppoe['source_interface']: -        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') +    verify_source_interface(pppoe) +    verify_bridge_vrf(pppoe) -    if pppoe['on_demand'] and pppoe['vrf']: +    if {'connect_on_demand', 'vrf'} <= set(pppoe):          raise ConfigError('On-demand dialing and VRF can not be used at the same time')      return None @@ -195,22 +81,22 @@ def verify(pppoe):  def generate(pppoe):      # 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_wide_dhcp6c = f'/run/dhcp6c/dhcp6c.{intf}.conf' +    ifname = pppoe['ifname'] +    config_pppoe = f'/etc/ppp/peers/{ifname}' +    script_pppoe_pre_up = f'/etc/ppp/ip-pre-up.d/1000-vyos-pppoe-{ifname}' +    script_pppoe_ip_up = f'/etc/ppp/ip-up.d/1000-vyos-pppoe-{ifname}' +    script_pppoe_ip_down = f'/etc/ppp/ip-down.d/1000-vyos-pppoe-{ifname}' +    script_pppoe_ipv6_up = f'/etc/ppp/ipv6-up.d/1000-vyos-pppoe-{ifname}' +    config_wide_dhcp6c = f'/run/dhcp6c/dhcp6c.{ifname}.conf'      config_files = [config_pppoe, script_pppoe_pre_up, script_pppoe_ip_up,                      script_pppoe_ip_down, script_pppoe_ipv6_up, config_wide_dhcp6c] -    if pppoe['deleted']: +    if 'deleted' in pppoe.keys():          # stop DHCPv6-PD client -        call(f'systemctl stop dhcp6c@{intf}.service') +        call(f'systemctl stop dhcp6c@{ifname}.service')          # Hang-up PPPoE connection -        call(f'systemctl stop ppp@{intf}.service') +        call(f'systemctl stop ppp@{ifname}.service')          # Delete PPP configuration files          for file in config_files: @@ -235,22 +121,22 @@ def generate(pppoe):      render(script_pppoe_ipv6_up, 'pppoe/ipv6-up.script.tmpl',             pppoe, trim_blocks=True, permission=0o755) -    if len(pppoe['dhcpv6_pd_interfaces']) > 0: +    tmp = jmespath.search('dhcpv6_options.prefix_delegation.interface', pppoe) +    if tmp and len(tmp) > 0:          # ipv6.tmpl relies on ifname - this should be made consitent in the          # future better then double key-ing the same value -        pppoe['ifname'] = intf -        render(config_wide_dhcp6c, 'dhcp-client/ipv6.tmpl', pppoe, trim_blocks=True) +        render(config_wide_dhcp6c, 'dhcp-client/ipv6_new.tmpl', pppoe, trim_blocks=True)      return None  def apply(pppoe): -    if pppoe['deleted']: +    if 'deleted' in pppoe.keys():          # bail out early          return None -    if not pppoe['disable']: +    if 'disable' not in pppoe.keys():          # Dial PPPoE connection -        call('systemctl restart ppp@{intf}.service'.format(**pppoe)) +        call('systemctl restart ppp@{ifname}.service'.format(**pppoe))      return None | 
