summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2020-04-23 20:44:44 +0200
committerGitHub <noreply@github.com>2020-04-23 20:44:44 +0200
commita18d92b2205bd647691c39fde925d05d8d83fa1e (patch)
tree94a358538b8985e9a30ed138c789aac171d7dbb5
parentaf9f033fd19c0c927a2c1555347811bee1a8a964 (diff)
parent2d1dddd1b381676743dc602a321f2fd3146adc08 (diff)
downloadvyos-1x-a18d92b2205bd647691c39fde925d05d8d83fa1e.tar.gz
vyos-1x-a18d92b2205bd647691c39fde925d05d8d83fa1e.zip
Merge pull request #371 from jjakob/ipv6-link-local-fix
interfaces: T2362: IPv6 link-local and EUI64 address fixes
-rw-r--r--debian/vyos-1x.install1
-rw-r--r--interface-definitions/include/ipv6-address.xml.i11
-rw-r--r--python/vyos/configdict.py21
-rw-r--r--python/vyos/ifconfig/interface.py41
-rw-r--r--python/vyos/ifconfig_vlan.py8
-rwxr-xr-xsrc/conf_mode/interfaces-bonding.py39
-rwxr-xr-xsrc/conf_mode/interfaces-bridge.py47
-rwxr-xr-xsrc/conf_mode/interfaces-ethernet.py39
-rwxr-xr-xsrc/conf_mode/interfaces-l2tpv3.py19
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py35
-rwxr-xr-xsrc/conf_mode/interfaces-pseudo-ethernet.py39
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py19
-rwxr-xr-xsrc/conf_mode/interfaces-wireless.py39
-rw-r--r--src/etc/sysctl.d/31-vyos-addr_gen_mode.conf14
14 files changed, 289 insertions, 83 deletions
diff --git a/debian/vyos-1x.install b/debian/vyos-1x.install
index dd8eebc0b..599f3f3f5 100644
--- a/debian/vyos-1x.install
+++ b/debian/vyos-1x.install
@@ -2,6 +2,7 @@ etc/dhcp
etc/ppp
etc/rsyslog.d
etc/systemd
+etc/sysctl.d
etc/udev
etc/vyos
lib/
diff --git a/interface-definitions/include/ipv6-address.xml.i b/interface-definitions/include/ipv6-address.xml.i
index 507d5dcc1..34f54e4c1 100644
--- a/interface-definitions/include/ipv6-address.xml.i
+++ b/interface-definitions/include/ipv6-address.xml.i
@@ -8,14 +8,21 @@
</leafNode>
<leafNode name="eui64">
<properties>
- <help>ssign IPv6 address using EUI-64 based on MAC address</help>
+ <help>Prefix for IPv6 address with MAC-based EUI-64</help>
<valueHelp>
<format>ipv6net</format>
- <description>IPv6 address and prefix length</description>
+ <description>IPv6 network and prefix length</description>
</valueHelp>
<constraint>
<validator name="ipv6-prefix"/>
</constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="no-default-link-local">
+ <properties>
+ <help>Remove the default link-local address from the interface</help>
+ <valueless/>
</properties>
</leafNode>
</children>
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index 24fe174d2..2ce8a795f 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -125,6 +125,8 @@ def vlan_to_dict(conf):
'ip_enable_arp_ignore': 0,
'ip_proxy_arp': 0,
'ipv6_autoconf': 0,
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'ingress_qos': '',
@@ -199,6 +201,22 @@ def vlan_to_dict(conf):
if conf.exists('ipv6 address autoconf'):
vlan['ipv6_autoconf'] = 1
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
+ if conf.exists('ipv6 address eui64'):
+ vlan['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ vlan['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, vlan['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ vlan['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ vlan['ipv6_eui64_prefix'].append('fe80::/64')
+
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
vlan['ipv6_forwarding'] = 0
@@ -210,6 +228,9 @@ def vlan_to_dict(conf):
# Media Access Control (MAC) address
if conf.exists('mac'):
vlan['mac'] = conf.return_value('mac')
+ # always recreate EUI64 addresses if mac is set
+ # I'm not sure how to check if a vlan interface exists or how to get its current mac.
+ vlan['ipv6_eui64_prefix_remove'] += vlan['ipv6_eui64_prefix']
# Maximum Transmission Unit (MTU)
if conf.exists('mtu'):
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 62c30dbf7..a156eddd9 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -419,39 +419,28 @@ class Interface(Control):
"""
return self.set_interface('ipv6_autoconf', autoconf)
- def set_ipv6_eui64_address(self, prefix):
+ def add_ipv6_eui64_address(self, prefix):
"""
Extended Unique Identifier (EUI), as per RFC2373, allows a host to
- assign iteslf a unique IPv6 address based on a given IPv6 prefix.
+ assign itself a unique IPv6 address based on a given IPv6 prefix.
- If prefix is passed address is assigned, if prefix is '' address is
- removed from interface.
+ Calculate the EUI64 from the interface's MAC, then assign it
+ with the given prefix to the interface.
"""
- # if prefix is an empty string convert it to None so mac2eui64 works
- # as expected
- if not prefix:
- prefix = None
eui64 = mac2eui64(self.get_mac(), prefix)
+ prefixlen = prefix.split('/')[1]
+ self.add_addr(f'{eui64}/{prefixlen}')
- if not prefix:
- # if prefix is empty - thus removed - we need to walk through all
- # interface IPv6 addresses and find the one with the calculated
- # EUI-64 identifier. The address is then removed
- for addr in self.get_addr():
- addr_wo_prefix = addr.split('/')[0]
- if is_ipv6(addr_wo_prefix):
- if eui64 in IPv6Address(addr_wo_prefix).exploded:
- self.del_addr(addr)
-
- return None
+ def del_ipv6_eui64_address(self, prefix):
+ """
+ Delete the address based on the interface's MAC-based EUI64
+ combined with the prefix address.
+ """
+ eui64 = mac2eui64(self.get_mac(), prefix)
+ prefixlen = prefix.split('/')[1]
+ self.del_addr(f'{eui64}/{prefixlen}')
- # calculate and add EUI-64 IPv6 address
- if IPv6Network(prefix):
- # we also need to take the subnet length into account
- prefix = prefix.split('/')[1]
- eui64 = f'{eui64}/{prefix}'
- self.add_addr(eui64 )
def set_ipv6_forwarding(self, forwarding):
"""
diff --git a/python/vyos/ifconfig_vlan.py b/python/vyos/ifconfig_vlan.py
index 899fd17da..ee009f7f9 100644
--- a/python/vyos/ifconfig_vlan.py
+++ b/python/vyos/ifconfig_vlan.py
@@ -66,10 +66,18 @@ def apply_vlan_config(vlan, config):
# assign/remove VRF
vlan.set_vrf(config['vrf'])
+ # Delete old IPv6 EUI64 addresses before changing MAC
+ for addr in config['ipv6_eui64_prefix_remove']:
+ vlan.del_ipv6_eui64_address(addr)
+
# Change VLAN interface MAC address
if config['mac']:
vlan.set_mac(config['mac'])
+ # Add IPv6 EUI-based addresses
+ for addr in config['ipv6_eui64_prefix']:
+ vlan.add_ipv6_eui64_address(addr)
+
# enable/disable VLAN interface
if config['disable']:
vlan.set_admin_state('down')
diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py
index 380457772..4aef486b4 100755
--- a/src/conf_mode/interfaces-bonding.py
+++ b/src/conf_mode/interfaces-bonding.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
@@ -20,7 +20,7 @@ from copy import deepcopy
from sys import exit
from netifaces import interfaces
-from vyos.ifconfig import BondIf
+from vyos.ifconfig import BondIf, Section
from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config
from vyos.configdict import list_diff, vlan_to_dict
from vyos.config import Config
@@ -52,7 +52,8 @@ default_config_data = {
'ip_proxy_arp': 0,
'ip_proxy_arp_pvlan': 0,
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'is_bridge_member': False,
@@ -202,9 +203,21 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
bond['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- bond['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ bond['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ bond['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, bond['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ bond['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ bond['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -218,6 +231,12 @@ def get_config():
if conf.exists('mac'):
bond['mac'] = conf.return_value('mac')
+ # Find out if MAC has changed - if so, we need to delete all IPv6 EUI64 addresses
+ # before re-adding them
+ if ( bond['mac'] and bond['intf'] in Section.interfaces(section='bonding')
+ and bond['mac'] != BondIf(bond['intf'], create=False).get_mac() ):
+ bond['ipv6_eui64_prefix_remove'] += bond['ipv6_eui64_prefix']
+
# Bonding mode
if conf.exists('mode'):
act_mode = conf.return_value('mode')
@@ -434,17 +453,23 @@ def apply(bond):
b.set_proxy_arp_pvlan(bond['ip_proxy_arp_pvlan'])
# IPv6 address autoconfiguration
b.set_ipv6_autoconf(bond['ipv6_autoconf'])
- # IPv6 EUI-based address
- b.set_ipv6_eui64_address(bond['ipv6_eui64_prefix'])
# IPv6 forwarding
b.set_ipv6_forwarding(bond['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
b.set_ipv6_dad_messages(bond['ipv6_dup_addr_detect'])
+ # Delete old IPv6 EUI64 addresses before changing MAC
+ for addr in bond['ipv6_eui64_prefix_remove']:
+ b.del_ipv6_eui64_address(addr)
+
# Change interface MAC address
if bond['mac']:
b.set_mac(bond['mac'])
+ # Add IPv6 EUI-based addresses
+ for addr in bond['ipv6_eui64_prefix']:
+ b.add_ipv6_eui64_address(addr)
+
# Maximum Transmission Unit (MTU)
b.set_mtu(bond['mtu'])
diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py
index 93c6db97e..2f92aae09 100755
--- a/src/conf_mode/interfaces-bridge.py
+++ b/src/conf_mode/interfaces-bridge.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
@@ -20,7 +20,7 @@ from copy import deepcopy
from sys import exit
from netifaces import interfaces
-from vyos.ifconfig import BridgeIf
+from vyos.ifconfig import BridgeIf, Section
from vyos.ifconfig.stp import STP
from vyos.configdict import list_diff
from vyos.config import Config
@@ -47,7 +47,8 @@ default_config_data = {
'ip_enable_arp_announce': 0,
'ip_enable_arp_ignore': 0,
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'igmp_querier': 0,
@@ -160,9 +161,21 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
bridge['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- bridge['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ bridge['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ bridge['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, bridge['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ bridge['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ bridge['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -176,6 +189,12 @@ def get_config():
if conf.exists('mac'):
bridge['mac'] = conf.return_value('mac')
+ # Find out if MAC has changed - if so, we need to delete all IPv6 EUI64 addresses
+ # before re-adding them
+ if ( bridge['mac'] and bridge['intf'] in Section.interfaces(section='bridge')
+ and bridge['mac'] != BridgeIf(bridge['intf'], create=False).get_mac() ):
+ bridge['ipv6_eui64_prefix_remove'] += bridge['ipv6_eui64_prefix']
+
# Interval at which neighbor bridges are removed
if conf.exists('max-age'):
bridge['max_age'] = int(conf.return_value('max-age'))
@@ -283,8 +302,6 @@ def apply(bridge):
br.set_arp_ignore(bridge['ip_enable_arp_ignore'])
# IPv6 address autoconfiguration
br.set_ipv6_autoconf(bridge['ipv6_autoconf'])
- # IPv6 EUI-based address
- br.set_ipv6_eui64_address(bridge['ipv6_eui64_prefix'])
# IPv6 forwarding
br.set_ipv6_forwarding(bridge['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
@@ -318,9 +335,10 @@ def apply(bridge):
# assign/remove VRF
br.set_vrf(bridge['vrf'])
- # Change interface MAC address
- if bridge['mac']:
- br.set_mac(bridge['mac'])
+ # Delete old IPv6 EUI64 addresses before changing MAC
+ # (adding members to a fresh bridge changes its MAC too)
+ for addr in bridge['ipv6_eui64_prefix_remove']:
+ br.del_ipv6_eui64_address(addr)
# remove interface from bridge
for intf in bridge['member_remove']:
@@ -330,6 +348,15 @@ def apply(bridge):
for member in bridge['member']:
br.add_port(member['name'])
+ # Change interface MAC address
+ if bridge['mac']:
+ br.set_mac(bridge['mac'])
+
+ # Add IPv6 EUI-based addresses (must be done after adding the
+ # 1st bridge member or setting its MAC)
+ for addr in bridge['ipv6_eui64_prefix']:
+ br.add_ipv6_eui64_address(addr)
+
# up/down interface
if bridge['disable']:
br.set_admin_state('down')
diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py
index 5a977d797..43d97916d 100755
--- a/src/conf_mode/interfaces-ethernet.py
+++ b/src/conf_mode/interfaces-ethernet.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
@@ -20,7 +20,7 @@ from sys import exit
from copy import deepcopy
from netifaces import interfaces
-from vyos.ifconfig import EthernetIf
+from vyos.ifconfig import EthernetIf, Section
from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config
from vyos.configdict import list_diff, vlan_to_dict
from vyos.config import Config
@@ -49,7 +49,8 @@ default_config_data = {
'ip_proxy_arp': 0,
'ip_proxy_arp_pvlan': 0,
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'intf': '',
@@ -175,9 +176,21 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
eth['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- eth['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ eth['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ eth['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, eth['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ eth['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ eth['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -191,6 +204,12 @@ def get_config():
if conf.exists('mac'):
eth['mac'] = conf.return_value('mac')
+ # Find out if MAC has changed - if so, we need to delete all IPv6 EUI64 addresses
+ # before re-adding them
+ if ( eth['mac'] and eth['intf'] in Section.interfaces(section='ethernet')
+ and eth['mac'] != EthernetIf(eth['intf'], create=False).get_mac() ):
+ eth['ipv6_eui64_prefix_remove'] += eth['ipv6_eui64_prefix']
+
# Maximum Transmission Unit (MTU)
if conf.exists('mtu'):
eth['mtu'] = int(conf.return_value('mtu'))
@@ -336,13 +355,15 @@ def apply(eth):
e.set_proxy_arp_pvlan(eth['ip_proxy_arp_pvlan'])
# IPv6 address autoconfiguration
e.set_ipv6_autoconf(eth['ipv6_autoconf'])
- # IPv6 EUI-based address
- e.set_ipv6_eui64_address(eth['ipv6_eui64_prefix'])
# IPv6 forwarding
e.set_ipv6_forwarding(eth['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
e.set_ipv6_dad_messages(eth['ipv6_dup_addr_detect'])
+ # Delete old IPv6 EUI64 addresses before changing MAC
+ for addr in eth['ipv6_eui64_prefix_remove']:
+ e.del_ipv6_eui64_address(addr)
+
# Change interface MAC address - re-set to real hardware address (hw-id)
# if custom mac is removed
if eth['mac']:
@@ -350,6 +371,10 @@ def apply(eth):
elif eth['hw_id']:
e.set_mac(eth['hw_id'])
+ # Add IPv6 EUI-based addresses
+ for addr in eth['ipv6_eui64_prefix']:
+ e.add_ipv6_eui64_address(addr)
+
# Maximum Transmission Unit (MTU)
e.set_mtu(eth['mtu'])
diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py
index 5e495dd4b..33cf62f70 100755
--- a/src/conf_mode/interfaces-l2tpv3.py
+++ b/src/conf_mode/interfaces-l2tpv3.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
@@ -36,7 +36,7 @@ default_config_data = {
'local_port': 5000,
'intf': '',
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'is_bridge_member': False,
@@ -113,9 +113,14 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
l2tpv3['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- l2tpv3['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ l2tpv3['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Remove the default link-local address if set.
+ if not conf.exists('ipv6 address no-default-link-local'):
+ # add the link-local by default to make IPv6 work
+ l2tpv3['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -228,8 +233,6 @@ def apply(l2tpv3):
l.set_mtu(l2tpv3['mtu'])
# IPv6 address autoconfiguration
l.set_ipv6_autoconf(l2tpv3['ipv6_autoconf'])
- # IPv6 EUI-based address
- l.set_ipv6_eui64_address(l2tpv3['ipv6_eui64_prefix'])
# IPv6 forwarding
l.set_ipv6_forwarding(l2tpv3['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
@@ -241,6 +244,10 @@ def apply(l2tpv3):
for addr in l2tpv3['address']:
l.add_addr(addr)
+ # IPv6 EUI-based addresses
+ for addr in l2tpv3['ipv6_eui64_prefix']:
+ l.add_ipv6_eui64_address(addr)
+
# As the interface is always disabled first when changing parameters
# we will only re-enable the interface if it is not administratively
# disabled
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 708ac8f91..029bc1d69 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -25,6 +25,7 @@ from time import sleep
from shutil import rmtree
from vyos.config import Config
+from vyos.configdict import list_diff
from vyos.ifconfig import VTunIf
from vyos.template import render
from vyos.util import call, chown, chmod_600, chmod_755
@@ -50,7 +51,8 @@ default_config_data = {
'hash': '',
'intf': '',
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'ipv6_local_address': [],
@@ -314,9 +316,21 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
openvpn['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- openvpn['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ openvpn['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ openvpn['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, openvpn['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ openvpn['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ openvpn['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -1043,13 +1057,24 @@ def apply(openvpn):
o.set_alias(openvpn['description'])
# IPv6 address autoconfiguration
o.set_ipv6_autoconf(openvpn['ipv6_autoconf'])
- # IPv6 EUI-based address
- o.set_ipv6_eui64_address(openvpn['ipv6_eui64_prefix'])
# IPv6 forwarding
o.set_ipv6_forwarding(openvpn['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
o.set_ipv6_dad_messages(openvpn['ipv6_dup_addr_detect'])
+ # IPv6 EUI-based addresses - only in TAP mode (TUN's have no MAC)
+ # If MAC has changed, old EUI64 addresses won't get deleted,
+ # but this isn't easy to solve, so leave them.
+ # This is even more difficult as openvpn uses a random MAC for the
+ # initial interface creation, unless set by 'lladdr'.
+ # NOTE: right now the interface is always deleted. For future
+ # compatibility when tap's are not deleted, leave the del_ in
+ if openvpn['mode'] == 'tap':
+ for addr in openvpn['ipv6_eui64_prefix_remove']:
+ o.del_ipv6_eui64_address(addr)
+ for addr in openvpn['ipv6_eui64_prefix']:
+ o.add_ipv6_eui64_address(addr)
+
except:
pass
diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py
index d5f308ed3..57b282291 100755
--- a/src/conf_mode/interfaces-pseudo-ethernet.py
+++ b/src/conf_mode/interfaces-pseudo-ethernet.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
@@ -22,7 +22,7 @@ from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import list_diff, vlan_to_dict
-from vyos.ifconfig import MACVLANIf
+from vyos.ifconfig import MACVLANIf, Section
from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config
from vyos.validate import is_bridge_member
from vyos import ConfigError
@@ -48,7 +48,8 @@ default_config_data = {
'ip_proxy_arp': 0,
'ip_proxy_arp_pvlan': 0,
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'is_bridge_member': False,
@@ -157,9 +158,21 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
peth['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- peth['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ peth['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ peth['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, peth['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ peth['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ peth['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -180,6 +193,12 @@ def get_config():
if conf.exists(['mac']):
peth['mac'] = conf.return_value(['mac'])
+ # Find out if MAC has changed - if so, we need to delete all IPv6 EUI64 addresses
+ # before re-adding them
+ if ( peth['mac'] and peth['intf'] in Section.interfaces(section='pseudo-ethernet')
+ and peth['mac'] != MACVLANIf(peth['intf'], create=False).get_mac() ):
+ peth['ipv6_eui64_prefix_remove'] += peth['ipv6_eui64_prefix']
+
# MACvlan mode
if conf.exists(['mode']):
peth['mode'] = conf.return_value(['mode'])
@@ -306,8 +325,6 @@ def apply(peth):
p.set_proxy_arp_pvlan(peth['ip_proxy_arp_pvlan'])
# IPv6 address autoconfiguration
p.set_ipv6_autoconf(peth['ipv6_autoconf'])
- # IPv6 EUI-based address
- p.set_ipv6_eui64_address(peth['ipv6_eui64_prefix'])
# IPv6 forwarding
p.set_ipv6_forwarding(peth['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
@@ -316,10 +333,18 @@ def apply(peth):
# assign/remove VRF
p.set_vrf(peth['vrf'])
+ # Delete old IPv6 EUI64 addresses before changing MAC
+ for addr in peth['ipv6_eui64_prefix_remove']:
+ p.del_ipv6_eui64_address(addr)
+
# Change interface MAC address
if peth['mac']:
p.set_mac(peth['mac'])
+ # Add IPv6 EUI-based addresses
+ for addr in peth['ipv6_eui64_prefix']:
+ p.add_ipv6_eui64_address(addr)
+
# Change interface mode
p.set_mode(peth['mode'])
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index d238ddb57..74eae4281 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.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
@@ -39,7 +39,7 @@ default_config_data = {
'ip_enable_arp_ignore': 0,
'ip_proxy_arp': 0,
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'is_bridge_member': False,
@@ -116,9 +116,14 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
vxlan['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- vxlan['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ vxlan['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Remove the default link-local address if set.
+ if not conf.exists('ipv6 address no-default-link-local'):
+ # add the link-local by default to make IPv6 work
+ vxlan['ipv6_eui64_prefix'].append('fe80::/64')
# Disable IPv6 forwarding on this interface
if conf.exists('ipv6 disable-forwarding'):
@@ -238,8 +243,6 @@ def apply(vxlan):
v.set_proxy_arp(vxlan['ip_proxy_arp'])
# IPv6 address autoconfiguration
v.set_ipv6_autoconf(vxlan['ipv6_autoconf'])
- # IPv6 EUI-based address
- v.set_ipv6_eui64_address(vxlan['ipv6_eui64_prefix'])
# IPv6 forwarding
v.set_ipv6_forwarding(vxlan['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
@@ -251,6 +254,10 @@ def apply(vxlan):
for addr in vxlan['address']:
v.add_addr(addr)
+ # IPv6 EUI-based addresses
+ for addr in vxlan['ipv6_eui64_prefix']:
+ v.add_ipv6_eui64_address(addr)
+
# As the VXLAN interface is always disabled first when changing
# parameters we will only re-enable the interface if it is not
# administratively disabled
diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py
index 42842f9bd..148a7f6e0 100755
--- a/src/conf_mode/interfaces-wireless.py
+++ b/src/conf_mode/interfaces-wireless.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
@@ -25,7 +25,7 @@ from netaddr import EUI, mac_unix_expanded
from vyos.config import Config
from vyos.configdict import list_diff, vlan_to_dict
-from vyos.ifconfig import WiFiIf
+from vyos.ifconfig import WiFiIf, Section
from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config
from vyos.template import render
from vyos.util import chown, call
@@ -88,7 +88,8 @@ default_config_data = {
'ip_enable_arp_announce': 0,
'ip_enable_arp_ignore': 0,
'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': '',
+ 'ipv6_eui64_prefix': [],
+ 'ipv6_eui64_prefix_remove': [],
'ipv6_forwarding': 1,
'ipv6_dup_addr_detect': 1,
'is_bridge_member': False,
@@ -368,9 +369,21 @@ def get_config():
if conf.exists('ipv6 address autoconf'):
wifi['ipv6_autoconf'] = 1
- # Get prefix for IPv6 addressing based on MAC address (EUI-64)
+ # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
if conf.exists('ipv6 address eui64'):
- wifi['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64')
+ wifi['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
+
+ # Determine currently effective EUI64 addresses - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('ipv6 address eui64')
+ wifi['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, wifi['ipv6_eui64_prefix'])
+
+ # Remove the default link-local address if set.
+ if conf.exists('ipv6 address no-default-link-local'):
+ wifi['ipv6_eui64_prefix_remove'].append('fe80::/64')
+ else:
+ # add the link-local by default to make IPv6 work
+ wifi['ipv6_eui64_prefix'].append('fe80::/64')
# ARP enable ignore
if conf.exists('ip enable-arp-ignore'):
@@ -392,6 +405,12 @@ def get_config():
if conf.exists('mac'):
wifi['mac'] = conf.return_value('mac')
+ # Find out if MAC has changed - if so, we need to delete all IPv6 EUI64 addresses
+ # before re-adding them
+ if ( wifi['mac'] and wifi['intf'] in Section.interfaces(section='wireless')
+ and wifi['mac'] != WiFiIf(wifi['intf'], create=False).get_mac() ):
+ wifi['ipv6_eui64_prefix_remove'] += wifi['ipv6_eui64_prefix']
+
# Maximum number of wireless radio stations
if conf.exists('max-stations'):
wifi['max_stations'] = conf.return_value('max-stations')
@@ -696,6 +715,10 @@ def apply(wifi):
# ignore link state changes
w.set_link_detect(wifi['disable_link_detect'])
+ # Delete old IPv6 EUI64 addresses before changing MAC
+ for addr in wifi['ipv6_eui64_prefix_remove']:
+ w.del_ipv6_eui64_address(addr)
+
# Change interface MAC address - re-set to real hardware address (hw-id)
# if custom mac is removed
if wifi['mac']:
@@ -703,6 +726,10 @@ def apply(wifi):
elif wifi['hw_id']:
w.set_mac(wifi['hw_id'])
+ # Add IPv6 EUI-based addresses
+ for addr in wifi['ipv6_eui64_prefix']:
+ w.add_ipv6_eui64_address(addr)
+
# configure ARP filter configuration
w.set_arp_filter(wifi['ip_disable_arp_filter'])
# configure ARP accept
@@ -713,8 +740,6 @@ def apply(wifi):
w.set_arp_ignore(wifi['ip_enable_arp_ignore'])
# IPv6 address autoconfiguration
w.set_ipv6_autoconf(wifi['ipv6_autoconf'])
- # IPv6 EUI-based address
- w.set_ipv6_eui64_address(wifi['ipv6_eui64_prefix'])
# IPv6 forwarding
w.set_ipv6_forwarding(wifi['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
diff --git a/src/etc/sysctl.d/31-vyos-addr_gen_mode.conf b/src/etc/sysctl.d/31-vyos-addr_gen_mode.conf
new file mode 100644
index 000000000..07a0d1584
--- /dev/null
+++ b/src/etc/sysctl.d/31-vyos-addr_gen_mode.conf
@@ -0,0 +1,14 @@
+### Added by vyos-1x ###
+#
+# addr_gen_mode - INTEGER
+# Defines how link-local and autoconf addresses are generated.
+#
+# 0: generate address based on EUI64 (default)
+# 1: do no generate a link-local address, use EUI64 for addresses generated
+# from autoconf
+# 2: generate stable privacy addresses, using the secret from
+# stable_secret (RFC7217)
+# 3: generate stable privacy addresses, using a random secret if unset
+#
+net.ipv6.conf.all.addr_gen_mode = 1
+net.ipv6.conf.default.addr_gen_mode = 1