Page MenuHomeVyOS Platform

DHCPv6 does not work on PPPoE interfaces
Closed, ResolvedPublicBUG

Description

This bug appears to have started somewhere between 1.3-rolling-202006101523 and 1.3.1, but is still there in 1.4.2 and recent rolling releases.

The file /usr/share/vyos/templates/dhcp-client/ipv6.j2 is used as a template to generate the /run/dhcp6c/dhcp6c.pppoeX.conf file.

"set interfaces pppoe pppoeX ipv6 address autoconf" (and other config commands I have tried) does not generate the

" send ia-na 0;" and "id-assoc na 0 {" etc lines required for an ipv6 address on the pppoeX device.

the rest of the dhcp6c.conf config that generates the ipv6 prefix delegation addresses on other devices works.

Manually adjusting the template to generate the appropriate config causes pppoe to work OK.

The forum thread has more info https://forum.vyos.io/t/ipv6-does-not-seem-to-be-working-on-pppoe-interfaces-since-1-3rolling/16602

Details

Version
1.3.1 to current, inc rolling.
Is it a breaking change?
Perfectly compatible
Issue type
Bug (incorrect behavior)
Forum thread
https://forum.vyos.io/t/ipv6-does-not-seem-to-be-working-on-pppoe-interfaces-since-1-3rolling/16602

Event Timeline

Viacheslav triaged this task as Normal priority.May 26 2025, 4:23 PM

I ran into this too! This also ignores rapid-commit etc.

Changing the base template controlling dhcp6c config generation seems to do the trick.
Folowing basic pppoe example provided on Vyos main website :

// config
interfaces {
    ...
    pppoe pppoe0 {
        ...
        dhcpv6-options {
            pd 0 {
                interface eth0 {
                    address "1"
                    sla-id "0"
                }
                length "56"
            }
            rapid-commit
        }
        ipv6 {
            address {
                autoconf
            }
        }
    }
}
### templates/dhcp-client/ipv6.j2
### Autogenerated by interface.py ###

# man https://www.unix.com/man-page/debian/5/dhcp6c.conf/
interface {{ ifname }} {
{% if dhcpv6_options.duid is vyos_defined %}
    send client-id {{ dhcpv6_options.duid }};
{% endif %}
{% if address is vyos_defined and 'dhcpv6' in address %}
    request domain-name-servers;
    request domain-name;
{%     if dhcpv6_options.parameters_only is vyos_defined %}
    information-only;
{%     endif %}
{%     if dhcpv6_options.temporary is not vyos_defined %}
    send ia-na 0; # non-temporary address
{%     endif %}
{%     if dhcpv6_options.rapid_commit is vyos_defined %}
    send rapid-commit; # wait for immediate reply instead of advertisements
{%     endif %}
{% elif 'pppoe' in ifname and ipv6.address is vyos_defined and 'autoconf' in ipv6.address %}
{%     if dhcpv6_options.temporary is not vyos_defined %}
    send ia-na 0; # non-temporary address
{%     endif %}
{%     if dhcpv6_options.rapid_commit is vyos_defined %}
    send rapid-commit; # wait for immediate reply instead of advertisements
{%     endif %}
{% endif %}
{% if dhcpv6_options.pd is vyos_defined %}
{%     for pd in dhcpv6_options.pd %}
    send ia-pd {{ pd }}; # prefix delegation #{{ pd }}
{%     endfor %}
{% endif %}
    script "{{ dhcp6_script_file }}";
};

{% if address is vyos_defined and 'dhcpv6' in address %}
{%     if dhcpv6_options.temporary is not vyos_defined %}
id-assoc na 0 {
    # Identity association for non temporary address
};
{%     endif %}
{% elif 'pppoe' in ifname and ipv6.address is vyos_defined and 'autoconf' in ipv6.address %}
{%     if dhcpv6_options.temporary is not vyos_defined %}
id-assoc na 0 {
    # Identity association for non temporary address
};
{%     endif %}
{% endif %}

{% if dhcpv6_options.pd is vyos_defined %}
{%     for pd, pd_config in dhcpv6_options.pd.items() %}
id-assoc pd {{ pd }} {
{#   length got a default value #}
    prefix ::/{{ pd_config.length }} infinity;
{%         set sla_len = 64 - pd_config.length | int %}
{%         set count = namespace(value=0) %}
{%         if pd_config.interface is vyos_defined %}
{%             for interface, interface_config in pd_config.interface.items() if pd_config.interface is vyos_defined %}
    prefix-interface {{ interface }} {
        sla-len {{ sla_len }};
{%                 if interface_config.sla_id is vyos_defined %}
        sla-id {{ interface_config.sla_id }};
{%                 else %}
        sla-id {{ count.value }};
{%                 endif %}
{%                 if interface_config.address is vyos_defined %}
        ifid {{ interface_config.address }};
{%                 endif %}
    };
{%                 set count.value = count.value + 1 %}
{%             endfor %}
{%         endif %}
};
{%     endfor %}
{% endif %}
### Generated /run/dhcp6c/dhcp6c.pppoe0.conf
### Autogenerated by interface.py ###

# man https://www.unix.com/man-page/debian/5/dhcp6c.conf/
interface pppoe0 {
    send ia-na 0; # non-temporary address
    send rapid-commit; # wait for immediate reply instead of advertisements
    send ia-pd 0; # prefix delegation #0
    script "/etc/wide-dhcpv6/dhcp6c.pppoe0.script";
};

id-assoc na 0 {
    # Identity association for non temporary address
};

id-assoc pd 0 {
    prefix ::/56 infinity;
    prefix-interface eth0 {
        sla-len 8;
        sla-id 0;
        ifid 1;
    };
};
Viacheslav changed the task status from Open to In progress.Sep 15 2025, 8:56 AM
Viacheslav assigned this task to nvdx.
c-po moved this task from Need Triage to Completed on the VyOS Rolling board.
c-po subscribed.

Please use: set interfaces pppoe pppoe0 address dhcpv6 to enable IA_NA

This unfortunately doesn't work.
Why is it in the new address node when there is ipv4 address and ipv6 address already? It should be in ipv6 address where the other ipv6 addressing options are too.
Also I get the following error when trying to set it:

script
    script.apply(c)
  File "/usr/libexec/vyos/conf_mode/interfaces_pppoe.py", line 132,
 in apply
    p.update(pppoe)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/pppoe.py", lin
e 124, in update
    super().update(config)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/interface.py",
 line 1831, in update
    self.add_addr(addr, vrf_changed=vrf_changed)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/interface.py",
 line 1286, in add_addr
    elif not is_intf_addr_assigned(self.ifname, addr, netns=netns):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/vyos/utils/network.py", line
 454, in is_intf_addr_assigned
    if ip_interface(addr) == interface or address == addr:
       ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ipaddress.py", line 117, in ip_interfac
e
    raise ValueError(f'{address!r} does not appear to be an IPv4 or
 IPv6 interface')
ValueError: 'd' does not appear to be an IPv4 or IPv6 interface

My original pull request was using the 'dhcpv6' keyword under system interface pppoe pppoeN ipv6 address namespace.
@c-po enhanced that by matching global interface configuration by assigning the keyword to system interface pppoe pppoeN address to be more inline with general VyOS configuration.

Did you test with the lastest nightly https://github.com/vyos/vyos-nightly-build/releases/tag/2025.10.12-0019-rolling ?

Yes I've tested with the latest nightly, the config node didn't exist before.

vyos@vyos# show interfaces pppoe pppoe0 | strip-private
+address dhcpv6
 authentication {
     password xxxxxx
     username xxxxxx
 }
 dhcpv6-options {
     duid xx:xx:xx:xx:xx:12:xx:xx:xx:xx:xx:b9:xx:xx:xx:xx:xx:94
     pd 0 {
         interface bond0.1 {
             address 1
             sla-id 0
         }
         interface bond0.1001 {
             address 1
             sla-id 1
         }
         interface bond0.1002 {
             address 1
             sla-id 2
         }
         interface bond0.1003 {
             address 1
             sla-id 3
         }
         interface bond0.2001 {
             address 1
             sla-id 257
         }
         interface eth2 {
             address 1
             sla-id 4
         }
         interface eth3 {
             address 1
             sla-id 10
         }
         length 48
     }
 }
 ipv6 {
     address {
         autoconf
     }
 }
 mtu 1500
 no-peer-dns
 source-interface bond0.4002
[edit]
vyos@vyos#
[ interfaces pppoe pppoe0 ]
Traceback (most recent call last):
  File "/usr/libexec/vyos/services/vyos-configd", line 156, in run_
script
    script.apply(c)
  File "/usr/libexec/vyos/conf_mode/interfaces_pppoe.py", line 132,
 in apply
    p.update(pppoe)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/pppoe.py", lin
e 124, in update
    super().update(config)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/interface.py",
 line 1831, in update
    self.add_addr(addr, vrf_changed=vrf_changed)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/interface.py",
 line 1286, in add_addr
    elif not is_intf_addr_assigned(self.ifname, addr, netns=netns):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/vyos/utils/network.py", line
 454, in is_intf_addr_assigned
    if ip_interface(addr) == interface or address == addr:
       ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ipaddress.py", line 117, in ip_interfac
e
    raise ValueError(f'{address!r} does not appear to be an IPv4 or
 IPv6 interface')
ValueError: 'd' does not appear to be an IPv4 or IPv6 interface

[[interfaces pppoe pppoe0]] failed
Commit failed
[edit]
vyos@vyos#

Something seems to trigger the next elif branch in interface.py L1284.
Your bug report suggest a malformed string in your set command.
Could you test with a quoted param?

set interfaces pppoe pppoe0 address 'dhcpv6'

martb@rauter# set interfaces pppoe pppoe0 address 'dhcpv6' 
[edit]
martb@rauter# comp
[interfaces pppoe pppoe0]
+ address "dhcpv6"

[edit]
martb@rauter# commit
[ interfaces pppoe pppoe0 ]
Traceback (most recent call last):
  File "/usr/libexec/vyos/services/vyos-configd", line 156, in run_script
    script.apply(c)
  File "/usr/libexec/vyos/conf_mode/interfaces_pppoe.py", line 132, in apply
    p.update(pppoe)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/pppoe.py", line 124, in update
    super().update(config)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/interface.py", line 1831, in update
    self.add_addr(addr, vrf_changed=vrf_changed)
  File "/usr/lib/python3/dist-packages/vyos/ifconfig/interface.py", line 1286, in add_addr
    elif not is_intf_addr_assigned(self.ifname, addr, netns=netns):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/vyos/utils/network.py", line 454, in is_intf_addr_assigned
    if ip_interface(addr) == interface or address == addr:
       ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ipaddress.py", line 117, in ip_interface
    raise ValueError(f'{address!r} does not appear to be an IPv4 or IPv6 interface')
ValueError: 'd' does not appear to be an IPv4 or IPv6 interface

[[interfaces pppoe pppoe0]] failed
Commit failed

Doesnt make a difference

c-po moved this task from Backlog to Finished on the VyOS 1.4 Sagitta (1.4.4) board.
dmbaturin renamed this task from pppoe interfaces do not get assigned an ipv6 address with pppoe ipv6 enabled. ipv6 prefix delegation works. to DHCPv6 does not work on PPPoE interfaces.Thu, Dec 4, 8:21 PM
dmbaturin changed Is it a breaking change? from Behavior change to Perfectly compatible.