summaryrefslogtreecommitdiff
path: root/cloudinit
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit')
-rw-r--r--cloudinit/net/eni.py15
-rw-r--r--cloudinit/net/netplan.py9
-rw-r--r--cloudinit/net/network_state.py21
-rw-r--r--cloudinit/net/sysconfig.py34
-rw-r--r--cloudinit/sources/helpers/openstack.py21
5 files changed, 83 insertions, 17 deletions
diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py
index a9a80c95..70771060 100644
--- a/cloudinit/net/eni.py
+++ b/cloudinit/net/eni.py
@@ -399,6 +399,7 @@ class Renderer(renderer.Renderer):
def _render_iface(self, iface, render_hwaddress=False):
sections = []
subnets = iface.get('subnets', {})
+ accept_ra = iface.pop('accept-ra', None)
if subnets:
for index, subnet in enumerate(subnets):
ipv4_subnet_mtu = None
@@ -415,9 +416,23 @@ class Renderer(renderer.Renderer):
subnet['type'] == 'ipv6_dhcpv6-stateful'):
# Configure network settings using DHCP or DHCPv6
iface['mode'] = 'dhcp'
+ if accept_ra is not None:
+ # Accept router advertisements (0=off, 1=on)
+ iface['accept_ra'] = '1' if accept_ra else '0'
elif subnet['type'] == 'ipv6_dhcpv6-stateless':
# Configure network settings using SLAAC from RAs
iface['mode'] = 'auto'
+ # Use stateless DHCPv6 (0=off, 1=on)
+ iface['dhcp'] = '1'
+ elif subnet['type'] == 'ipv6_slaac':
+ # Configure network settings using SLAAC from RAs
+ iface['mode'] = 'auto'
+ # Use stateless DHCPv6 (0=off, 1=on)
+ iface['dhcp'] = '0'
+ elif subnet_is_ipv6(subnet) and subnet['type'] == 'static':
+ if accept_ra is not None:
+ # Accept router advertisements (0=off, 1=on)
+ iface['accept_ra'] = '1' if accept_ra else '0'
# do not emit multiple 'auto $IFACE' lines as older (precise)
# ifupdown complains
diff --git a/cloudinit/net/netplan.py b/cloudinit/net/netplan.py
index 749d46f8..14d3999f 100644
--- a/cloudinit/net/netplan.py
+++ b/cloudinit/net/netplan.py
@@ -4,7 +4,7 @@ import copy
import os
from . import renderer
-from .network_state import subnet_is_ipv6, NET_CONFIG_TO_V2
+from .network_state import subnet_is_ipv6, NET_CONFIG_TO_V2, IPV6_DYNAMIC_TYPES
from cloudinit import log as logging
from cloudinit import util
@@ -52,7 +52,8 @@ def _extract_addresses(config, entry, ifname, features=None):
'mtu': 1480,
'netmask': 64,
'type': 'static'}],
- 'type: physical'
+ 'type: physical',
+ 'accept-ra': 'true'
}
An entry dictionary looks like:
@@ -95,6 +96,8 @@ def _extract_addresses(config, entry, ifname, features=None):
if sn_type == 'dhcp':
sn_type += '4'
entry.update({sn_type: True})
+ elif sn_type in IPV6_DYNAMIC_TYPES:
+ entry.update({'dhcp6': True})
elif sn_type in ['static']:
addr = "%s" % subnet.get('address')
if 'prefix' in subnet:
@@ -147,6 +150,8 @@ def _extract_addresses(config, entry, ifname, features=None):
ns = entry.get('nameservers', {})
ns.update({'search': searchdomains})
entry.update({'nameservers': ns})
+ if 'accept-ra' in config and config['accept-ra'] is not None:
+ entry.update({'accept-ra': util.is_true(config.get('accept-ra'))})
def _extract_bond_slaves_by_name(interfaces, entry, bond_master):
diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py
index 20b7716b..7d206a1a 100644
--- a/cloudinit/net/network_state.py
+++ b/cloudinit/net/network_state.py
@@ -18,13 +18,17 @@ from cloudinit import util
LOG = logging.getLogger(__name__)
NETWORK_STATE_VERSION = 1
+IPV6_DYNAMIC_TYPES = ['dhcp6',
+ 'ipv6_slaac',
+ 'ipv6_dhcpv6-stateless',
+ 'ipv6_dhcpv6-stateful']
NETWORK_STATE_REQUIRED_KEYS = {
1: ['version', 'config', 'network_state'],
}
NETWORK_V2_KEY_FILTER = [
'addresses', 'dhcp4', 'dhcp4-overrides', 'dhcp6', 'dhcp6-overrides',
'gateway4', 'gateway6', 'interfaces', 'match', 'mtu', 'nameservers',
- 'renderer', 'set-name', 'wakeonlan'
+ 'renderer', 'set-name', 'wakeonlan', 'accept-ra'
]
NET_CONFIG_TO_V2 = {
@@ -342,7 +346,8 @@ class NetworkStateInterpreter(object):
'name': 'eth0',
'subnets': [
{'type': 'dhcp4'}
- ]
+ ],
+ 'accept-ra': 'true'
}
'''
@@ -362,6 +367,9 @@ class NetworkStateInterpreter(object):
self.use_ipv6 = True
break
+ accept_ra = command.get('accept-ra', None)
+ if accept_ra is not None:
+ accept_ra = util.is_true(accept_ra)
iface.update({
'name': command.get('name'),
'type': command.get('type'),
@@ -372,6 +380,7 @@ class NetworkStateInterpreter(object):
'address': None,
'gateway': None,
'subnets': subnets,
+ 'accept-ra': accept_ra
})
self._network_state['interfaces'].update({command.get('name'): iface})
self.dump_network_state()
@@ -615,6 +624,7 @@ class NetworkStateInterpreter(object):
driver: ixgbe
set-name: lom1
dhcp6: true
+ accept-ra: true
switchports:
match:
name: enp2*
@@ -643,7 +653,7 @@ class NetworkStateInterpreter(object):
driver = match.get('driver', None)
if driver:
phy_cmd['params'] = {'driver': driver}
- for key in ['mtu', 'match', 'wakeonlan']:
+ for key in ['mtu', 'match', 'wakeonlan', 'accept-ra']:
if key in cfg:
phy_cmd[key] = cfg[key]
@@ -928,8 +938,9 @@ def is_ipv6_addr(address):
def subnet_is_ipv6(subnet):
"""Common helper for checking network_state subnets for ipv6."""
- # 'static6', 'dhcp6', 'ipv6_dhcpv6-stateful' or 'ipv6_dhcpv6-stateless'
- if subnet['type'].endswith('6') or subnet['type'].startswith('ipv6'):
+ # 'static6', 'dhcp6', 'ipv6_dhcpv6-stateful', 'ipv6_dhcpv6-stateless' or
+ # 'ipv6_slaac'
+ if subnet['type'].endswith('6') or subnet['type'] in IPV6_DYNAMIC_TYPES:
# This is a request for DHCPv6.
return True
elif subnet['type'] == 'static' and is_ipv6_addr(subnet.get('address')):
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index fe0c67ca..310cdf01 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -14,7 +14,7 @@ from configobj import ConfigObj
from . import renderer
from .network_state import (
- is_ipv6_addr, net_prefix_to_ipv4_mask, subnet_is_ipv6)
+ is_ipv6_addr, net_prefix_to_ipv4_mask, subnet_is_ipv6, IPV6_DYNAMIC_TYPES)
LOG = logging.getLogger(__name__)
NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf"
@@ -335,6 +335,9 @@ class Renderer(renderer.Renderer):
continue
iface_cfg[new_key] = old_value
+ if iface['accept-ra'] is not None:
+ iface_cfg['IPV6_FORCE_ACCEPT_RA'] = iface['accept-ra']
+
@classmethod
def _render_subnets(cls, iface_cfg, subnets, has_default_route):
# setting base values
@@ -351,6 +354,15 @@ class Renderer(renderer.Renderer):
iface_cfg['DHCPV6C'] = True
elif subnet_type == 'ipv6_dhcpv6-stateless':
iface_cfg['IPV6INIT'] = True
+ # Configure network settings using SLAAC from RAs and optional
+ # info from dhcp server using DHCPv6
+ iface_cfg['IPV6_AUTOCONF'] = True
+ iface_cfg['DHCPV6C'] = True
+ # Use Information-request to get only stateless configuration
+ # parameters (i.e., without address).
+ iface_cfg['DHCPV6C_OPTIONS'] = '-S'
+ elif subnet_type == 'ipv6_slaac':
+ iface_cfg['IPV6INIT'] = True
# Configure network settings using SLAAC from RAs
iface_cfg['IPV6_AUTOCONF'] = True
elif subnet_type in ['dhcp4', 'dhcp']:
@@ -398,10 +410,15 @@ class Renderer(renderer.Renderer):
# metric may apply to both dhcp and static config
if 'metric' in subnet:
iface_cfg['METRIC'] = subnet['metric']
+ # TODO(hjensas): Including dhcp6 here is likely incorrect. DHCPv6
+ # does not ever provide a default gateway, the default gateway
+ # come from RA's. (https://github.com/openSUSE/wicked/issues/570)
if subnet_type in ['dhcp', 'dhcp4', 'dhcp6']:
if has_default_route and iface_cfg['BOOTPROTO'] != 'none':
iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False
continue
+ elif subnet_type in IPV6_DYNAMIC_TYPES:
+ continue
elif subnet_type == 'static':
if subnet_is_ipv6(subnet):
ipv6_index = ipv6_index + 1
@@ -444,10 +461,14 @@ class Renderer(renderer.Renderer):
@classmethod
def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets):
for _, subnet in enumerate(subnets, start=len(iface_cfg.children)):
+ subnet_type = subnet.get('type')
for route in subnet.get('routes', []):
is_ipv6 = subnet.get('ipv6') or is_ipv6_addr(route['gateway'])
- if _is_default_route(route):
+ # Any dynamic configuration method, slaac, dhcpv6-stateful/
+ # stateless should get router information from router RA's.
+ if (_is_default_route(route) and subnet_type not in
+ IPV6_DYNAMIC_TYPES):
if (
(subnet.get('ipv4') and
route_cfg.has_set_default_ipv4) or
@@ -466,10 +487,17 @@ class Renderer(renderer.Renderer):
# TODO(harlowja): add validation that no other iface has
# also provided the default route?
iface_cfg['DEFROUTE'] = True
+ # TODO(hjensas): Including dhcp6 here is likely incorrect.
+ # DHCPv6 does not ever provide a default gateway, the
+ # default gateway come from RA's.
+ # (https://github.com/openSUSE/wicked/issues/570)
if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4', 'dhcp6'):
+ # NOTE(hjensas): DHCLIENT_SET_DEFAULT_ROUTE is SuSE
+ # only. RHEL, CentOS, Fedora does not implement this
+ # option.
iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = True
if 'gateway' in route:
- if is_ipv6 or is_ipv6_addr(route['gateway']):
+ if is_ipv6:
iface_cfg['IPV6_DEFAULTGW'] = route['gateway']
route_cfg.has_set_default_ipv6 = True
else:
diff --git a/cloudinit/sources/helpers/openstack.py b/cloudinit/sources/helpers/openstack.py
index d1c4601a..0778f45a 100644
--- a/cloudinit/sources/helpers/openstack.py
+++ b/cloudinit/sources/helpers/openstack.py
@@ -584,17 +584,24 @@ def convert_net_json(network_json=None, known_macs=None):
if n['link'] == link['id']]:
subnet = dict((k, v) for k, v in network.items()
if k in valid_keys['subnet'])
- if 'dhcp' in network['type']:
- t = (network['type'] if network['type'].startswith('ipv6')
- else 'dhcp4')
- subnet.update({
- 'type': t,
- })
- else:
+
+ if network['type'] == 'ipv4_dhcp':
+ subnet.update({'type': 'dhcp4'})
+ elif network['type'] == 'ipv6_dhcp':
+ subnet.update({'type': 'dhcp6'})
+ elif network['type'] in ['ipv6_slaac', 'ipv6_dhcpv6-stateless',
+ 'ipv6_dhcpv6-stateful']:
+ subnet.update({'type': network['type']})
+ elif network['type'] in ['ipv4', 'ipv6']:
subnet.update({
'type': 'static',
'address': network.get('ip_address'),
})
+
+ # Enable accept_ra for stateful and legacy ipv6_dhcp types
+ if network['type'] in ['ipv6_dhcpv6-stateful', 'ipv6_dhcp']:
+ cfg.update({'accept-ra': True})
+
if network['type'] == 'ipv4':
subnet['ipv4'] = True
if network['type'] == 'ipv6':