Petr Šebek has uploaded a new change for review. Change subject: Add IPv6 support to configNetwork ......................................................................
Add IPv6 support to configNetwork This patch add IPv6 functionality to network configuration. We want to run every device as dual stack device so IPConfig now uses IPv4 AND IPv6(or one of them). This patch was built on Hunt Xu's patch 11741. Change-Id: I8ed056b683f0cb893b2edcf1ae673c64ce5cd18c Signed-off-by: Petr Sebek <pse...@redhat.com> --- M vdsm/configNetwork.py M vdsm/netconf/ifcfg.py M vdsm/netmodels.py 3 files changed, 157 insertions(+), 65 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/84/18284/1 diff --git a/vdsm/configNetwork.py b/vdsm/configNetwork.py index 155d22a..ac458ed 100755 --- a/vdsm/configNetwork.py +++ b/vdsm/configNetwork.py @@ -35,6 +35,7 @@ from netmodels import Bond from netmodels import Bridge from netmodels import IPv4 +from netmodels import IPv6 from netmodels import IpConfig from netmodels import Nic from netmodels import Vlan @@ -45,6 +46,8 @@ 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, + dhcpv6=None, _netinfo=None, configurator=None, blockingdhcp=None, implicitBonding=None, defaultRoute=None, **opts): """ @@ -61,6 +64,10 @@ :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 ipv6gateway: IPv6 address in format address[/prefixlen]. + :param ipv6autoconf: whether to use stateless autoconfiguration. + :param dhcpv6: whether to use DHCPv6. :param _netinfo: network information snapshot. :param configurator: instance to use to apply the network configuration. :param blockingdhcp: whether to acquire dhcp IP config in a synced manner. @@ -103,9 +110,18 @@ if topNetDev is None: raise ConfigNetworkError(ne.ERR_BAD_PARAMS, 'Network defined without' 'devices.') - topNetDev.ip = IpConfig(inet=IPv4(ipaddr, netmask, gateway, defaultRoute), - bootproto=bootproto, - blocking=utils.tobool(blockingdhcp)) + if ipv6addr is not None: + ipv6 = IPv6(ipv6addr, ipv6gateway, defaultRoute) + else: + ipv6 = None + + if ipaddr is not None: + ipv4 = IPv4(ipaddr, netmask, gateway, defaultRoute) + else: + ipv4 = None + topNetDev.ip = IpConfig(inet4=ipv4, inet6=ipv6, bootproto=bootproto, + blocking=utils.tobool(blockingdhcp), + ipv6autoconf=ipv6autoconf, dhcpv6=dhcpv6) return topNetDev @@ -150,7 +166,8 @@ def addNetwork(network, vlan=None, bonding=None, nics=None, ipaddr=None, - netmask=None, prefix=None, mtu=None, gateway=None, force=False, + netmask=None, prefix=None, mtu=None, gateway=None, + ipv6addr=None, ipv6gateway=None, force=False, configurator=None, bondingOptions=None, bridged=True, _netinfo=None, qosInbound=None, qosOutbound=None, **options): nics = nics or () @@ -199,7 +216,8 @@ netEnt = objectivizeNetwork(network if bridged else None, vlan, bonding, bondingOptions, nics, mtu, ipaddr, netmask, - gateway, bootproto, _netinfo, configurator, + gateway, bootproto, ipv6addr, ipv6gateway, + _netinfo=_netinfo, configurator=configurator, defaultRoute=defaultRoute, **options) netEnt.configure(**options) diff --git a/vdsm/netconf/ifcfg.py b/vdsm/netconf/ifcfg.py index 8fafbd0..0d50a06 100644 --- a/vdsm/netconf/ifcfg.py +++ b/vdsm/netconf/ifcfg.py @@ -446,7 +446,8 @@ return 'yes' if defaultRoute else 'no' def _createConfFile(self, conf, name, ipaddr=None, netmask=None, - gateway=None, bootproto=None, mtu=None, + gateway=None, bootproto=None, mtu=None, ipv6addr=None, + ipv6gateway=None, ipv6autoconf=None, dhcpv6=None, defaultRoute=None, onboot='yes', **kwargs): """ Create ifcfg-* file with proper fields per device """ cfg = self.CONFFILE_HEADER + '\n' @@ -470,6 +471,18 @@ if defaultRoute: cfg = cfg + 'DEFROUTE=%s\n' % defaultRoute cfg += 'NM_CONTROLLED=no\n' + if ipv6addr or ipv6gateway or ipv6autoconf or dhcpv6: + cfg += 'IPV6INIT=yes\n' + ipv6autoconf = 'no' + if ipv6addr is not None: + cfg += 'IPV6ADDR=%s\n' % pipes.quote(ipv6addr) + if ipv6gateway is not None: + cfg += 'IPV6_DEFAULTGW=%s\n' % pipes.quote(ipv6gateway) + elif dhcpv6: + cfg += 'DHCPV6C=yes\n' + if ipv6autoconf: + ipv6autoconf = 'yes' + cfg += 'IPV6_AUTOCONF=%s\n' % pipes.quote(ipv6autoconf) BLACKLIST = ['TYPE', 'NAME', 'DEVICE', 'bondingOptions', 'force', 'blockingdhcp', 'connectivityCheck', 'connectivityTimeout', @@ -484,24 +497,26 @@ def addBridge(self, bridge, **opts): """ Create ifcfg-* file with proper fields for bridge """ - ipaddr, netmask, gateway, bootproto, _, defaultRoute = \ - bridge.ipConfig + ipconfig = bridge.ipConfig conf = 'TYPE=Bridge\nDELAY=%s\n' % bridge.forwardDelay - self._createConfFile(conf, bridge.name, ipaddr, netmask, gateway, - bootproto, bridge.mtu, - self._toIfcfgFormat(defaultRoute), **opts) + self._createConfFile(conf, bridge.name, ipconfig.ipaddr, + ipconfig.netmask, ipconfig.gateway, + ipconfig.bootproto, bridge.mtu, + self._toIfcfgFormat(self.defaultRoute), + **opts) def addVlan(self, vlan, **opts): """ Create ifcfg-* file with proper fields for VLAN """ - ipaddr, netmask, gateway, bootproto, _, defaultRoute = \ - vlan.ipConfig + ipconfig = vlan.ipConfig conf = 'VLAN=yes\n' if vlan.bridge: conf += 'BRIDGE=%s\n' % pipes.quote(vlan.bridge.name) - self._createConfFile(conf, vlan.name, ipaddr, netmask, gateway, - bootproto, vlan.mtu, - self._toIfcfgFormat(defaultRoute), **opts) + self._createConfFile(conf, vlan.name, ipconfig.ipaddr, + ipconfig.netmask, ipconfig.gateway, + ipconfig.bootproto, vlan.mtu, + self._toIfcfgFormat(ipconfig.defaultRoute), + **opts) def addBonding(self, bond, **opts): """ Create ifcfg-* file with proper fields for bond """ @@ -509,10 +524,9 @@ if bond.bridge: conf += 'BRIDGE=%s\n' % pipes.quote(bond.bridge.name) - ipaddr, netmask, gateway, bootproto, mtu, defaultRoute = \ - self._getIfaceConfValues(bond, netinfo.NetInfo()) - self._createConfFile(conf, bond.name, ipaddr, netmask, gateway, - bootproto, mtu, defaultRoute, **opts) + confValues = self._getIfaceConfValues(bond, netinfo.NetInfo()) + opts.update(confValues) + self._createConfFile(conf, bond.name, **opts) # create the bonding device to avoid initscripts noise if bond.name not in open(netinfo.BONDING_MASTERS).read().split(): @@ -530,31 +544,36 @@ if nic.bond: conf += 'MASTER=%s\nSLAVE=yes\n' % pipes.quote(nic.bond.name) - ipaddr, netmask, gateway, bootproto, mtu, defaultRoute = \ - self._getIfaceConfValues(nic, _netinfo) - self._createConfFile(conf, nic.name, ipaddr, netmask, gateway, - bootproto, mtu, defaultRoute, **opts) + confValues = self._getIfaceConfValues(nic, _netinfo) + opts.update(confValues) + self._createConfFile(conf, nic.name, **opts) @staticmethod def _getIfaceConfValues(iface, _netinfo): - ipaddr, netmask, gateway, bootproto, _, defaultRoute = \ - iface.ipConfig - defaultRoute = ConfigWriter._toIfcfgFormat(defaultRoute) + ipconfig = iface.ipConfig + defaultRoute = ConfigWriter._toIfcfgFormat(ipconfig.defaultRoute) mtu = iface.mtu + conf = {} if _netinfo.ifaceUsers(iface.name): confParams = netinfo.getIfaceCfg(iface.name) - if not ipaddr and bootproto != 'dhcp': - ipaddr = confParams.get('IPADDR', None) - netmask = confParams.get('NETMASK', None) - gateway = confParams.get('GATEWAY', None) - bootproto = confParams.get('BOOTPROTO', None) + if not ipconfig.inet4.ipaddr and ipconfig.bootproto != 'dhcp': + conf['ipaddr'] = confParams.get('IPADDR', None) + conf['netmask'] = confParams.get('NETMASK', None) + conf['gateway'] = confParams.get('GATEWAY', None) + conf['bootproto'] = confParams.get('BOOTPROTO', None) if defaultRoute is None: - defaultRoute = confParams.get('DEFROUTE', None) + conf['defaultRoute'] = confParams.get('DEFROUTE', None) if not iface.mtu: mtu = confParams.get('MTU', None) if mtu: - mtu = int(mtu) - return ipaddr, netmask, gateway, bootproto, mtu, defaultRoute + conf['mtu'] = int(mtu) + if confParams.get('IPV6INIT', 'no') == 'yes': + conf['ipv6autoconf'] = (confParams.get('IPV6_AUTOCONF', 'no') + == 'yes') + conf['ipv6gateway'] = confParams.get('IPV6_DEFAULTGW', None) + conf['dhcpv6'] = (confParams.get('DHCPV6C', 'no') == 'yes') + conf['ipv6addr'] = confParams.get('IPV6ADDR', None) + return conf def removeNic(self, nic): cf = netinfo.NET_CONF_PREF + nic diff --git a/vdsm/netmodels.py b/vdsm/netmodels.py index aad0c58..0acf456 100644 --- a/vdsm/netmodels.py +++ b/vdsm/netmodels.py @@ -16,7 +16,6 @@ # # Refer to the README and COPYING files for full details of the license # -from collections import namedtuple from contextlib import contextmanager import logging import os @@ -30,9 +29,6 @@ class NetDevice(object): - _ipConfig = namedtuple('ipConfig', ['ipaddr', 'netmask', 'gateway', - 'bootproto', 'async', 'defaultRoute']) - def __init__(self, name, configurator, ipconfig=None, mtu=None): self.name = name self.ip = ipconfig @@ -48,14 +44,7 @@ @property def ipConfig(self): - try: - ipaddr, netmask, gateway, bootproto, async, defaultRoute = \ - self.ip.getConfig() - except AttributeError: - ipaddr = netmask = gateway = bootproto = async = defaultRoute = \ - None - return self._ipConfig(ipaddr, netmask, gateway, bootproto, async, - defaultRoute) + return self.ip.getConfig() @property def bridge(self): @@ -322,25 +311,91 @@ raise -class IpConfig(object): - def __init__(self, inet, bootproto=None, blocking=False): - if inet.address and bootproto == 'dhcp': - raise ConfigNetworkError(ne.ERR_BAD_ADDR, 'Static and dynamic ip ' - 'configurations are mutually exclusive.') - self.inet = inet - self.bootproto = bootproto - self.async = bootproto == 'dhcp' and blocking +class IPv6(object): + def __init__(self, address=None, gateway=None, + defaultRoute=None): + if address: + self.validateAddress(address) + if gateway: + self.validateGateway(gateway) + elif gateway: + raise ConfigNetworkError(ne.ERR_BAD_ADDR, 'Specified prefixlen ' + 'or gateway but not ip address.') + self.address = address + self.gateway = gateway + self.defaultRoute = defaultRoute def __repr__(self): - return 'IpConfig(%r, %s)' % (self.inet, self.bootproto) + return 'IPv6(%s, %s, %s)' % (self.address, self.gateway, + self.defaultRoute) + + @classmethod + def validateAddress(cls, address): + addr = address.split('/', 1) + try: + socket.inet_pton(socket.AF_INET6, addr[0]) + except socket.error: + raise ConfigNetworkError(ne.ERR_BAD_ADDR, '%r is not a valid IPv6 ' + 'address.' % address) + if len(addr) == 2: + cls.validatePrefixlen(addr[1]) + + @classmethod + def validatePrefixlen(cls, prefixlen): + try: + prefixlen = int(prefixlen) + if prefixlen < 0 or prefixlen > 127: + raise ConfigNetworkError(ne.ERR_BAD_ADDR, '%r is not valid ' + 'IPv6 prefixlen.' % prefixlen) + except ValueError: + raise ConfigNetworkError(ne.ERR_BAD_ADDR, '%r is not valid ' + 'IPv6 prefixlen.' % prefixlen) + + @classmethod + def validateGateway(cls, gateway): + try: + cls.validateAddress(gateway) + except ConfigNetworkError as cne: + cne.message = '%r is not a valid IPv6 gateway.' + raise + + +class IpConfig(object): + def __init__(self, inet4=None, inet6=None, bootproto=None, blocking=False, + ipv6autoconf=None, dhcpv6=None): + if inet4 is None and inet6 is None: + raise ConfigNetworkError(ne.ERR_BAD_ADDR, 'You need to specify ' + 'IPv4 or IPv6 or both address.') + if ((inet4 and inet4.address and bootproto == 'dhcp') or + (inet6 and inet6.address and (ipv6autoconf or dhcpv6))): + raise ConfigNetworkError(ne.ERR_BAD_ADDR, 'Static and dynamic ip ' + 'configurations are mutually exclusive.') + self.inet4 = inet4 + self.inet6 = inet6 + self.bootproto = bootproto + self.async = bootproto == 'dhcp' and blocking + self.ipv6autoconf = ipv6autoconf + self.dhcpv6 = dhcpv6 + + def __repr__(self): + return 'IpConfig(%r, %r, %s, %s, %s)' % (self.inet4, self.inet6, + self.bootproto, + self.ipv6autoconf, + self.dhcpv6) def getConfig(self): - try: - ipaddr = self.inet.address - netmask = self.inet.netmask - gateway = self.inet.gateway - defaultRoute = self.inet.defaultRoute - except AttributeError: - ipaddr = netmask = gateway = defaultRoute = None - return ipaddr, netmask, gateway, self.bootproto, self.async, \ - defaultRoute + config = {} + if self.inet4: + config['ipaddr'] = self.inet4.address + config['netmask'] = self.inet4.netmask + config['gateway'] = self.inet4.gateway + config['defaultRoute'] = self.inet4.defaultRoute + if self.inet6: + config['ipv6addr'] = self.inet6.address + config['ipv6gateway'] = self.inet6.gateway + config['ipv6defaultRoute'] = self.inet6.defaultRoute + config['bootproto'] = self.bootproto + config['async'] = self.async + config['ipv6autoconf'] = self.ipv6autoconf + config['dhcpv6'] = self.dhcpv6 + return config -- To view, visit http://gerrit.ovirt.org/18284 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8ed056b683f0cb893b2edcf1ae673c64ce5cd18c Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Petr Šebek <pse...@redhat.com> _______________________________________________ vdsm-patches mailing list vdsm-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches