summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/dhcp-client/ipv6.tmpl43
-rw-r--r--data/templates/pppoe/ip-down.script.tmpl5
-rw-r--r--data/templates/pppoe/ipv6-up.script.tmpl5
-rw-r--r--debian/control1
-rw-r--r--interface-definitions/interfaces-pppoe.xml.in53
-rw-r--r--python/vyos/ifconfig/dhcp.py26
-rwxr-xr-xsrc/conf_mode/interfaces-pppoe.py36
-rw-r--r--src/systemd/dhclient6@.service18
-rw-r--r--src/systemd/dhcp6c@.service16
9 files changed, 163 insertions, 40 deletions
diff --git a/data/templates/dhcp-client/ipv6.tmpl b/data/templates/dhcp-client/ipv6.tmpl
index be0235add..6cfe24d3e 100644
--- a/data/templates/dhcp-client/ipv6.tmpl
+++ b/data/templates/dhcp-client/ipv6.tmpl
@@ -1,4 +1,41 @@
# generated by dhcp.py
-interface "{{ ifname }}" {
- request routers, domain-name-servers, domain-name;
-}
+# man https://www.unix.com/man-page/debian/5/dhcp6c.conf/
+
+interface {{ ifname }} {
+ request domain-name-servers;
+ request domain-name;
+{% if dhcpv6_prm_only %}
+ information-only;
+{% endif %}
+{% if not dhcpv6_temporary %}
+ send ia-na 1; # non-temporary address
+{% endif %}
+{% if dhcpv6_pd %}
+ send ia-pd 2; # prefix delegation
+{% endif %}
+};
+
+{% if not dhcpv6_temporary %}
+id-assoc na 1 {
+ # Identity association NA
+};
+{% endif %}
+
+{% if dhcpv6_pd %}
+id-assoc pd 2 {
+{% for intf in dhcpv6_pd %}
+ prefix-interface {{ intf.ifname }} {
+{% if intf.sla_id %}
+ sla-id {{ intf.sla_id }};
+{% endif %}
+{% if intf.sla_len %}
+ sla-len {{ intf.sla_len }};
+{% endif %}
+{% if intf.if_id %}
+ ifid {{ intf.if_id }};
+{% endif %}
+ };
+{% endfor %}
+};
+{% endif %}
+
diff --git a/data/templates/pppoe/ip-down.script.tmpl b/data/templates/pppoe/ip-down.script.tmpl
index a68fc099c..fe8fd7584 100644
--- a/data/templates/pppoe/ip-down.script.tmpl
+++ b/data/templates/pppoe/ip-down.script.tmpl
@@ -26,3 +26,8 @@ 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}"
{% endif %}
+
+{% if dhcpv6_pd %}
+# Start wide dhcpv6 client
+systemctl stop dhcp6c@{{ intf }}.service
+{% endif %}
diff --git a/data/templates/pppoe/ipv6-up.script.tmpl b/data/templates/pppoe/ipv6-up.script.tmpl
index a4b08ddaf..90873229a 100644
--- a/data/templates/pppoe/ipv6-up.script.tmpl
+++ b/data/templates/pppoe/ipv6-up.script.tmpl
@@ -39,3 +39,8 @@ 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 %}
+
+{% if dhcpv6_pd %}
+# Start wide dhcpv6 client
+systemctl start dhcp6c@{{ intf }}.service
+{% endif %}
diff --git a/debian/control b/debian/control
index bd6e445ee..eec2c087e 100644
--- a/debian/control
+++ b/debian/control
@@ -40,6 +40,7 @@ Depends: python3,
tcpdump,
tshark,
isc-dhcp-client,
+ wide-dhcpv6-client,
bmon,
hvinfo,
file,
diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in
index d69e0b42c..4337b6fc7 100644
--- a/interface-definitions/interfaces-pppoe.xml.in
+++ b/interface-definitions/interfaces-pppoe.xml.in
@@ -72,6 +72,59 @@
</valueHelp>
</properties>
</leafNode>
+ <node name="dhcpv6-options">
+ <properties>
+ <help>DHCPv6 options</help>
+ </properties>
+ <children>
+ <tagNode name="delegate">
+ <properties>
+ <help>Delegate IPv6 prefix from provider to this interface</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>
+ </completionHelp>
+ </properties>
+ <children>
+ <leafNode name="interface-id">
+ <properties>
+ <help>Interface address identifier</help>
+ <valueHelp>
+ <format>0-</format>
+ <description>Used to form IPv6 interface address (default: EUI-64)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--non-negative"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="sla-id">
+ <properties>
+ <help>Interface site-Level aggregator (SLA)</help>
+ <valueHelp>
+ <format>0-128</format>
+ <description>Decimal integer which fits in the length of SLA IDs</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-128"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="sla-len">
+ <properties>
+ <help>Site-Level aggregator (SLA) length</help>
+ <valueHelp>
+ <format>0-128</format>
+ <description>Length of delegated prefix</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-128"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
#include <include/interface-description.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
diff --git a/python/vyos/ifconfig/dhcp.py b/python/vyos/ifconfig/dhcp.py
index 57e488cc7..f8fdeb6a9 100644
--- a/python/vyos/ifconfig/dhcp.py
+++ b/python/vyos/ifconfig/dhcp.py
@@ -19,11 +19,10 @@ from vyos.dicts import FixedDict
from vyos.ifconfig.control import Control
from vyos.template import render
-config_base = r'/var/lib/dhcp/dhclient_'
-
class _DHCPv4 (Control):
def __init__(self, ifname):
super().__init__()
+ config_base = r'/var/lib/dhcp/dhclient_'
self.options = FixedDict(**{
'ifname': ifname,
'hostname': '',
@@ -85,13 +84,11 @@ class _DHCPv6 (Control):
super().__init__()
self.options = FixedDict(**{
'ifname': ifname,
- 'conf_file': config_base + f'v6_{ifname}.conf',
- 'options_file': config_base + f'v6_{ifname}.options',
- 'pid_file': config_base + f'v6_{ifname}.pid',
- 'lease_file': config_base + f'v6_{ifname}.leases',
'dhcpv6_prm_only': False,
'dhcpv6_temporary': False,
+ 'dhcpv6_pd': [],
})
+ self._conf_file = f'/run/dhcp6c/dhcp6c.{ifname}.conf'
def set(self):
"""
@@ -111,10 +108,8 @@ class _DHCPv6 (Control):
raise Exception(
'DHCPv6 temporary and parameters-only options are mutually exclusive!')
- render(self.options['options_file'], 'dhcp-client/daemon-options.tmpl', self.options)
- render(self.options['conf_file'], 'dhcp-client/ipv6.tmpl', self.options)
-
- return self._cmd('systemctl restart dhclient6@{ifname}.service'.format(**self.options))
+ render(self._conf_file, 'dhcp-client/ipv6.tmpl', self.options, trim_blocks=True)
+ return self._cmd('systemctl restart dhcp6c@{ifname}.service'.format(**self.options))
def delete(self):
"""
@@ -127,16 +122,11 @@ class _DHCPv6 (Control):
>>> j = Interface('eth0')
>>> j.dhcp.v6.delete()
"""
- if not os.path.isfile(self.options['pid_file']):
- self._debug_msg('No DHCPv6 client PID found')
- return None
-
- self._cmd('systemctl stop dhclient6@{ifname}.service'.format(**self.options))
+ self._cmd('systemctl stop dhcp6c@{ifname}.service'.format(**self.options))
# cleanup old config files
- for name in ('conf_file', 'options_file', 'pid_file', 'lease_file'):
- if os.path.isfile(self.options[name]):
- os.remove(self.options[name])
+ if os.path.isfile(self._conf_file):
+ os.remove(self._conf_file)
class DHCP(object):
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index e72540f66..e46d52d19 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -36,6 +36,7 @@ default_config_data = {
'deleted': False,
'description': '\0',
'disable': False,
+ 'dhcpv6_pd': [],
'intf': '',
'idle_timeout': '',
'ipv6_autoconf': False,
@@ -138,6 +139,27 @@ def get_config():
if conf.exists('vrf'):
pppoe['vrf'] = conf.return_value(['vrf'])
+ if conf.exists(['dhcpv6-options', 'delegate']):
+ for interface in conf.list_nodes(['dhcpv6-options', 'delegate']):
+ pd = {
+ 'ifname': interface,
+ 'sla_id': '',
+ 'sla_len': '',
+ 'if_id': ''
+ }
+ conf.set_level(base_path + [pppoe['intf'], 'dhcpv6-options', 'delegate', interface])
+
+ 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'])
+
+ if conf.exists(['interface-id']):
+ pd['if_id'] = conf.return_value(['interface-id'])
+
+ pppoe['dhcpv6_pd'].append(pd)
+
return pppoe
def verify(pppoe):
@@ -169,9 +191,15 @@ def generate(pppoe):
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'
config_files = [config_pppoe, script_pppoe_pre_up, script_pppoe_ip_up,
- script_pppoe_ip_down, script_pppoe_ipv6_up]
+ script_pppoe_ip_down, script_pppoe_ipv6_up, config_wide_dhcp6c]
+
+ # Shutdown DHCPv6 prefix delegation client
+ if not pppoe['dhcpv6_pd']:
+ cmd(f'systemctl stop dhcp6c@{intf}.service')
+
# Always hang-up PPPoE connection prior generating new configuration file
cmd(f'systemctl stop ppp@{intf}.service')
@@ -201,6 +229,12 @@ def generate(pppoe):
render(script_pppoe_ipv6_up, 'pppoe/ipv6-up.script.tmpl',
pppoe, trim_blocks=True, permission=0o755)
+ if len(pppoe['dhcpv6_pd']) > 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)
+
return None
def apply(pppoe):
diff --git a/src/systemd/dhclient6@.service b/src/systemd/dhclient6@.service
deleted file mode 100644
index fd69e4d48..000000000
--- a/src/systemd/dhclient6@.service
+++ /dev/null
@@ -1,18 +0,0 @@
-[Unit]
-Description=DHCPv6 client on %i
-Documentation=man:dhclient(8)
-ConditionPathExists=/var/lib/dhcp/dhclient_v6_%i.conf
-ConditionPathExists=/var/lib/dhcp/dhclient_v6_%i.options
-After=vyos-router.service
-
-[Service]
-WorkingDirectory=/var/lib/dhcp
-Type=exec
-EnvironmentFile=-/var/lib/dhcp/dhclient_v6_%i.options
-PIDFile=/var/lib/dhcp/dhclient_v6_%i.pid
-ExecStart=/sbin/dhclient -6 $DHCLIENT_OPTS
-ExecStop=/sbin/dhclient -6 $DHCLIENT_OPTS -r
-Restart=always
-
-[Install]
-WantedBy=multi-user.target
diff --git a/src/systemd/dhcp6c@.service b/src/systemd/dhcp6c@.service
new file mode 100644
index 000000000..1a4175461
--- /dev/null
+++ b/src/systemd/dhcp6c@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=WIDE DHCPv6 client on %i
+Documentation=man:dhcp6c(8) man:dhcp6c.conf(5)
+ConditionPathExists=/run/dhcp6c/dhcp6c.%i.conf
+After=vyos-router.service
+
+[Service]
+WorkingDirectory=/run/dhcp6c
+Type=forking
+PIDFile=/run/dhcp6c/dhcp6c.%i.pid
+ExecStart=/usr/sbin/dhcp6c -D -k /run/dhcp6c/dhcp6c.%i.sock -c /run/dhcp6c/dhcp6c.%i.conf -p /run/dhcp6c/dhcp6c.%i.pid %i
+
+Restart=always
+
+[Install]
+WantedBy=multi-user.target