Ondřej Svoboda has uploaded a new change for review.
Change subject: api: support multiple 'ipv6addrs' per network and deprecate
'ipv6addr'
......................................................................
api: support multiple 'ipv6addrs' per network and deprecate 'ipv6addr'
Next, the 'ipv6' hook will be extended to understand a whitespace-separated
list of IPv6 addresses and also testStaticNetworkConfig will learn to pass
multiple IPv6 addresses to VDSM.
IPv4 support is planned but needs discussion (should we accept netmasks or
just CIDR notation?).
Change-Id: I8d16083781919fe5e5d9c75e9dd4ab744afe45be
Signed-off-by: Ondřej Svoboda <osvoboda(a)redhat.com>
---
M vdsm/network/api.py
M vdsm/network/configurators/ifcfg.py
M vdsm/network/configurators/iproute2.py
M vdsm/network/configurators/pyroute_two.py
M vdsm/network/models.py
5 files changed, 45 insertions(+), 24 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/39307/1
diff --git a/vdsm/network/api.py b/vdsm/network/api.py
index de92fbf..096f89f 100755
--- a/vdsm/network/api.py
+++ b/vdsm/network/api.py
@@ -82,7 +82,7 @@
def _objectivizeNetwork(bridge=None, vlan=None, bonding=None,
bondingOptions=None, nics=None, mtu=None, ipaddr=None,
netmask=None, gateway=None, bootproto=None,
- ipv6addr=None, ipv6gateway=None, ipv6autoconf=None,
+ ipv6addrs=None, ipv6gateway=None, ipv6autoconf=None,
dhcpv6=None, defaultRoute=None, _netinfo=None,
configurator=None, blockingdhcp=None,
implicitBonding=None, opts=None):
@@ -100,7 +100,7 @@
:param netmask: IPv4 mask in dotted decimal format.
:param gateway: IPv4 address in dotted decimal format.
:param bootproto: protocol for getting IP config for the net, e.g., 'dhcp'
- :param ipv6addr: IPv6 address in format address[/prefixlen].
+ :param ipv6addrs: list of IPv6 addresses in the format address[/prefixlen]
:param ipv6gateway: IPv6 address in format address[/prefixlen].
:param ipv6autoconf: whether to use IPv6's stateless autoconfiguration.
:param dhcpv6: whether to use DHCPv6.
@@ -162,7 +162,7 @@
raise ConfigNetworkError(ne.ERR_BAD_PARAMS, 'Network defined without '
'devices.')
ipv4 = IPv4(ipaddr, netmask, gateway, defaultRoute)
- ipv6 = IPv6(ipv6addr, ipv6gateway, defaultRoute)
+ ipv6 = IPv6(ipv6addrs, ipv6gateway, defaultRoute)
blockingdhcp = configurator._inRollback or utils.tobool(blockingdhcp)
topNetDev.ipconfig = IpConfig(
ipv4=ipv4, ipv6=ipv6, bootproto=bootproto, blockingdhcp=blockingdhcp,
@@ -249,6 +249,7 @@
@_alterRunningConfig
def _addNetwork(network, vlan=None, bonding=None, nics=None, ipaddr=None,
netmask=None, prefix=None, mtu=None, gateway=None, dhcpv6=None,
+ ipv6addrs=None,
ipv6addr=None, ipv6gateway=None, ipv6autoconf=None,
force=False, configurator=None, bondingOptions=None,
bridged=True, _netinfo=None, hostQos=None,
@@ -279,6 +280,12 @@
except ValueError as ve:
raise ConfigNetworkError(ne.ERR_BAD_ADDR, "Bad prefix: %s" %
ve)
+ if ipv6addr:
+ if ipv6addrs:
+ raise ConfigNetworkError(ne.ERR_BAD_PARAMS,
+ 'Both ipv6addrs and ipv6addr supplied')
+ else:
+ ipv6addrs = [ipv6addr]
if not utils.tobool(force):
logging.debug('validating network...')
@@ -312,7 +319,8 @@
bridge=network if bridged else None, vlan=vlan, bonding=bonding,
bondingOptions=bondingOptions, nics=nics, mtu=mtu, ipaddr=ipaddr,
netmask=netmask, gateway=gateway, bootproto=bootproto, dhcpv6=dhcpv6,
- blockingdhcp=blockingdhcp, ipv6addr=ipv6addr, ipv6gateway=ipv6gateway,
+ blockingdhcp=blockingdhcp, ipv6addrs=ipv6addrs,
+ ipv6gateway=ipv6gateway,
ipv6autoconf=ipv6autoconf, defaultRoute=defaultRoute,
_netinfo=_netinfo, configurator=configurator, opts=options)
@@ -783,7 +791,8 @@
netmask="<ipv4>"
gateway="<ipv4>"
bootproto="..."
- ipv6addr="<ipv6>[/<prefixlen>]"
+ ipv6addrs=["<ipv6>[/<prefixlen>]", ...]
+ ipv6addr="<ipv6>[/<prefixlen>]"
(deprecated)
ipv6gateway="<ipv6>"
ipv6autoconf="0|1"
dhcpv6="0|1"
diff --git a/vdsm/network/configurators/ifcfg.py b/vdsm/network/configurators/ifcfg.py
index 866ade8..f228306 100644
--- a/vdsm/network/configurators/ifcfg.py
+++ b/vdsm/network/configurators/ifcfg.py
@@ -584,10 +584,13 @@
if ipv4.defaultRoute is not None:
cfg += 'DEFROUTE=%s\n' % _to_ifcfg_bool(ipv4.defaultRoute)
cfg += 'NM_CONTROLLED=no\n'
- if ipv6.address or ipconfig.ipv6autoconf or ipconfig.dhcpv6:
+ if ipv6.addresses or ipconfig.ipv6autoconf or ipconfig.dhcpv6:
cfg += 'IPV6INIT=yes\n'
- if ipv6.address is not None:
- cfg += 'IPV6ADDR=%s\n' % pipes.quote(ipv6.address)
+ if ipv6.addresses:
+ cfg += 'IPV6ADDR=%s\n' % pipes.quote(ipv6.addresses[0])
+ if len(ipv6.addresses) > 1:
+ cfg += 'IPV6ADDR_SECONDARIES=%s\n' % pipes.quote(
+ ' '.join(ipv6.addresses[1:]))
if ipv6.gateway is not None:
cfg += 'IPV6_DEFAULTGW=%s\n' % pipes.quote(ipv6.gateway)
elif ipconfig.dhcpv6:
@@ -701,7 +704,10 @@
if ipv4.defaultRoute is None and confParams.get('DEFROUTE'):
ipv4.defaultRoute = _from_ifcfg_bool(confParams['DEFROUTE'])
if confParams.get('IPV6INIT') == 'yes':
- ipv6.address = confParams.get('IPV6ADDR')
+ ipv6addr = confParams.get('IPV6ADDR')
+ ipv6addrs = confParams.get('IPV6ADDR_SECONDARIES')
+ ipv6.addresses = ([ipv6addr] if ipv6addr else []) + (
+ ipv6addrs.split() if ipv6addrs else [])
ipv6.gateway = confParams.get('IPV6_DEFAULTGW')
ipconfig.ipv6autoconf = (
confParams.get('IPV6_AUTOCONF') == 'yes')
diff --git a/vdsm/network/configurators/iproute2.py
b/vdsm/network/configurators/iproute2.py
index 1cde1cc..045ed66 100644
--- a/vdsm/network/configurators/iproute2.py
+++ b/vdsm/network/configurators/iproute2.py
@@ -225,16 +225,17 @@
ipconfig = iface.ipconfig
ipv4 = ipconfig.ipv4
ipv6 = ipconfig.ipv6
- if ipv4.address or ipv6.address:
+ if ipv4.address or ipv6.addresses:
self.removeIpConfig(iface)
if ipv4.address:
ipwrapper.addrAdd(iface.name, ipv4.address,
ipv4.netmask)
if ipv4.gateway and ipv4.defaultRoute:
ipwrapper.routeAdd(['default', 'via', ipv4.gateway])
- if ipv6.address:
- ipv6addr, ipv6netmask = ipv6.address.split('/')
- ipwrapper.addrAdd(iface.name, ipv6addr, ipv6netmask, family=6)
+ if ipv6.addresses:
+ for address in ipv6.addresses:
+ ipv6addr, ipv6netmask = address.split('/')
+ ipwrapper.addrAdd(iface.name, ipv6addr, ipv6netmask, family=6)
if ipv6.gateway:
ipwrapper.routeAdd(['default', 'via', ipv6.gateway],
dev=iface.name, family=6)
diff --git a/vdsm/network/configurators/pyroute_two.py
b/vdsm/network/configurators/pyroute_two.py
index 221e142..a6833d5 100644
--- a/vdsm/network/configurators/pyroute_two.py
+++ b/vdsm/network/configurators/pyroute_two.py
@@ -59,7 +59,7 @@
ipconfig = iface.ipconfig
ipv4 = ipconfig.ipv4
ipv6 = ipconfig.ipv6
- if ipv4.address or ipv6.address:
+ if ipv4.address or ipv6.addresses:
self.removeIpConfig(iface)
if ipv4.address:
with self.ip.interfaces[iface.name] as i:
@@ -67,9 +67,10 @@
if ipv4.gateway and ipv4.defaultRoute:
self.ip.routes.add({'dst': 'default',
'gateway': ipv4.gateway}).commit()
- if ipv6.address:
+ if ipv6.addresses:
with self.ip.interfaces[iface.name] as i:
- i.add_ip(ipv6.address)
+ for address in ipv6.addresses:
+ i.add_ip(address)
if ipv6.gateway:
self.ip.routes.add({'dst': 'default',
'gateway': ipv6.gateway}).commit()
diff --git a/vdsm/network/models.py b/vdsm/network/models.py
index 1d34c88..2c577de 100644
--- a/vdsm/network/models.py
+++ b/vdsm/network/models.py
@@ -410,20 +410,24 @@
class IPv6(object):
- def __init__(self, address=None, gateway=None, defaultRoute=None):
- if address:
- self.validateAddress(address)
+ def __init__(self, addresses=None, gateway=None, defaultRoute=None):
+ if addresses:
+ # TODO: Do we want this?
+ # if isinstance(addresses, str):
+ # addresses = addresses.split()
+ for address in addresses:
+ self.validateAddress(address)
if gateway:
self.validateGateway(gateway)
elif gateway:
raise ConfigNetworkError(ne.ERR_BAD_ADDR, 'Specified gateway but '
'not ip address.')
- self.address = address
+ self.addresses = addresses
self.gateway = gateway
self.defaultRoute = defaultRoute
def __repr__(self):
- return 'IPv6(%s, %s, %s)' % (self.address, self.gateway,
+ return 'IPv6(%s, %s, %s)' % (self.addresses, self.gateway,
self.defaultRoute)
@classmethod
@@ -465,7 +469,7 @@
if ipv6 is None:
ipv6 = IPv6()
if (ipv4.address and bootproto == 'dhcp') or \
- (ipv6.address and (ipv6autoconf or dhcpv6)):
+ (ipv6.addresses and (ipv6autoconf or dhcpv6)):
raise ConfigNetworkError(ne.ERR_BAD_ADDR, 'Static and dynamic IP '
'configurations are mutually exclusive.')
self.ipv4 = ipv4
@@ -477,8 +481,8 @@
def __nonzero__(self):
# iproute2 and pyroute_two check that IP configuration is not empty
- return bool(self.ipv4.address or self.ipv6.address or self.bootproto or
- self.ipv6autoconf or self.dhcpv6)
+ return bool(self.ipv4.address or self.ipv6.addresses or self.bootproto
+ or self.ipv6autoconf or self.dhcpv6)
def __repr__(self):
return 'IpConfig(%r, %r, %s, %s, %s)' % (self.ipv4, self.ipv6,
--
To view, visit
https://gerrit.ovirt.org/39307
To unsubscribe, visit
https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8d16083781919fe5e5d9c75e9dd4ab744afe45be
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ondřej Svoboda <osvoboda(a)redhat.com>