Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to install an host with IPv6 management interface #2

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1498,20 +1498,24 @@ def configureNetworking(mounts, admin_iface, admin_bridge, admin_config, hn_conf
mc = open(mgmt_conf_file, 'w')
print >>mc, "LABEL='%s'" % admin_iface
print >>mc, "MODE='%s'" % netinterface.NetInterface.getModeStr(admin_config.mode)
static = False
if admin_config.mode == netinterface.NetInterface.Static:
static = True
print >>mc, "IP='%s'" % admin_config.ipaddr
print >>mc, "NETMASK='%s'" % admin_config.netmask
if admin_config.gateway:
print >>mc, "GATEWAY='%s'" % admin_config.gateway
if manual_nameservers:
print >>mc, "DNS='%s'" % (','.join(nameservers),)
if domain:
print >>mc, "DOMAIN='%s'" % domain
print >>mc, "MODEV6='%s'" % netinterface.NetInterface.getModeStr(admin_config.modev6)
if admin_config.modev6 == netinterface.NetInterface.Static:
static = True
print >>mc, "IPv6='%s'" % admin_config.ipv6addr
if admin_config.ipv6_gateway:
print >>mc, "IPv6_GATEWAY='%s'" % admin_config.ipv6_gateway
if static:
if manual_nameservers:
print >>mc, "DNS='%s'" % (','.join(nameservers),)
if domain:
print >>mc, "DOMAIN='%s'" % domain
if admin_config.vlan:
print >>mc, "VLAN='%d'" % admin_config.vlan
mc.close()
Expand Down Expand Up @@ -1553,12 +1557,18 @@ def configureNetworking(mounts, admin_iface, admin_bridge, admin_config, hn_conf
# now we need to write /etc/sysconfig/network
nfd = open("%s/etc/sysconfig/network" % mounts["root"], "w")
nfd.write("NETWORKING=yes\n")
if admin_config.modev6:
ipv6 = admin_config.modev6 is not None
if ipv6:
nfd.write("NETWORKING_IPV6=yes\n")
util.runCmd2(['chroot', mounts['root'], 'systemctl', 'enable', 'ip6tables'])
else:
nfd.write("NETWORKING_IPV6=no\n")
netutil.disable_ipv6_module(mounts["root"])

with open("%s/etc/sysctl.d/91-net-ipv6.conf" % mounts["root"], "w") as ipv6_conf:
for i in ['all', 'default']:
ipv6_conf.write('net.ipv6.conf.%s.disable_ipv6=%d\n' % (i, int(not ipv6)))

nfd.write("IPV6_AUTOCONF=no\n")
nfd.write('NTPSERVERARGS="iburst prefer"\n')
nfd.close()
Expand Down
82 changes: 69 additions & 13 deletions netinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def getTextOrNone(nodelist):
rc = rc + node.data
return rc == "" and None or rc.strip().encode()

class NetInterface:
class NetInterface(object):
""" Represents the configuration of a network interface. """

Static = 1
Expand Down Expand Up @@ -122,10 +122,18 @@ def valid(self):
return False
return self.mode or self.modev6

def isStatic(self):
""" Returns true if a static interface configuration is represented. """
def isStatic4(self):
""" Returns true if an IPv4 static interface configuration is represented. """
return self.mode == self.Static

def isStatic6(self):
""" Returns true if an IPv6 static interface configuration is represented. """
return self.modev6 == self.Static

def isDynamic(self):
""" Returns true if a dynamic interface configuration is represented. """
return self.mode == self.DHCP or self.modev6 == self.DHCP or self.modev6 == self.Autoconf

def isVlan(self):
return self.vlan is not None

Expand Down Expand Up @@ -164,8 +172,7 @@ def writeRHStyleInterface(self, iface):
""" Write a RedHat-style configuration entry for this interface to
file object f using interface name iface. """

assert self.modev6 is None
assert self.mode
assert self.modev6 or self.mode
iface_vlan = self.getInterfaceName(iface)

f = open('/etc/sysconfig/network-scripts/ifcfg-%s' % iface_vlan, 'w')
Expand All @@ -174,7 +181,7 @@ def writeRHStyleInterface(self, iface):
if self.mode == self.DHCP:
f.write("BOOTPROTO=dhcp\n")
f.write("PERSISTENT_DHCLIENT=1\n")
else:
elif self.mode == self.Static:
# CA-11825: broadcast needs to be determined for non-standard networks
bcast = self.getBroadcast()
f.write("BOOTPROTO=none\n")
Expand All @@ -184,20 +191,44 @@ def writeRHStyleInterface(self, iface):
f.write("NETMASK=%s\n" % self.netmask)
if self.gateway:
f.write("GATEWAY=%s\n" % self.gateway)

if self.modev6:
with open('/etc/sysconfig/network', 'w') as net_conf:
net_conf.write("NETWORKING_IPV6=yes\n")
f.write("IPV6INIT=yes\n")
f.write("IPV6_DEFROUTE=yes\n")
f.write("IPV6_DEFAULTDEV=%s\n" % iface_vlan)
if self.modev6 == self.DHCP:
f.write("DHCPV6C=yes\n")
f.write("PERSISTENT_DHCLIENT_IPV6=yes\n")
f.write("IPV6_FORCE_ACCEPT_RA=yes\n")
f.write("IPV6_AUTOCONF=no\n")
elif self.modev6 == self.Static:
f.write("IPV6ADDR=%s\n" % self.ipv6addr)
if self.ipv6_gateway:
f.write("IPV6_DEFAULTGW=%s\n" % (self.ipv6_gateway))
f.write("IPV6_AUTOCONF=no\n")
elif self.modev6 == self.Autoconf:
f.write("IPV6_AUTOCONF=yes\n")

if self.vlan:
f.write("VLAN=yes\n")
f.close()


def waitUntilUp(self, iface):
if not self.isStatic():
return True
if not self.gateway:
return True
iface_name = self.getInterfaceName(iface)
if self.isStatic4() and self.gateway and util.runCmd2(
['/usr/sbin/arping', '-f', '-w', '120', '-I', iface_name, self.gateway]
):
return False

rc = util.runCmd2(['/usr/sbin/arping', '-f', '-w', '120', '-I',
self.getInterfaceName(iface), self.gateway])
return rc == 0
if self.isStatic6() and self.ipv6_gateway and util.runCmd2(
['/usr/sbin/ndisc6', '-1', '-w', '120', self.ipv6_gateway, iface_name]
):
return False
Comment on lines +226 to +229
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is equivalent to the arping code above but for IPv6 as arping only supports IPv4.
Please note this requires to have ndisc6 installed in host-installer image.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this reflected in the corresponding RPM spec file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know your installer spec file repository is not public so I can't provide a PR to add ndisc6 which is why I commented my code for someone with access to reflect the change. :)


return True

@staticmethod
def getModeStr(mode):
Expand Down Expand Up @@ -348,3 +379,28 @@ def loadFromNetDb(jdata, hwaddr):

nic.addIPv6(modev6, ipv6addr, gatewayv6)
return nic

class NetInterfaceV6(NetInterface):
def __init__(self, mode, hwaddr, ipaddr=None, netmask=None, gateway=None, dns=None, domain=None, vlan=None):
super(NetInterfaceV6, self).__init__(None, hwaddr, None, None, None, None, None, vlan)

ipv6addr = None
if mode == self.Static:
assert ipaddr
assert netmask

ipv6addr = ipaddr + "/" + netmask
if dns == '':
dns = None
elif isinstance(dns, str):
dns = [ dns ]
self.dns = dns
self.domain = domain
elif mode == self.Autoconf:
if dns == '':
dns = None
elif isinstance(dns, str):
dns = [ dns ]
self.dns = dns

self.addIPv6(mode, ipv6addr=ipv6addr, ipv6gw=gateway)
48 changes: 30 additions & 18 deletions netutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import diskutil
import util
import re
import socket
import subprocess
import time
import errno
from xcp import logger
from xcp.net.biosdevname import all_devices_all_names
from socket import inet_ntoa
from struct import pack

class NIC:
Expand Down Expand Up @@ -92,12 +92,11 @@ def writeResolverFile(configuration, filename):

for iface in configuration:
settings = configuration[iface]
if settings.isStatic() and settings.dns:
if settings.dns:
for server in settings.dns:
outfile.write("nameserver %s\n" % server)
if settings.domain:
outfile.write("search %s\n" % settings.domain)
if settings.dns:
for server in settings.dns:
outfile.write("nameserver %s\n" % server)
if settings.domain:
outfile.write("search %s\n" % settings.domain)

outfile.close()

Expand Down Expand Up @@ -137,7 +136,15 @@ def interfaceUp(interface):
if rc != 0:
return False
inets = filter(lambda x: x.startswith(" inet "), out.split("\n"))
return len(inets) == 1
if len(inets) == 1:
return True

inet6s = filter(
# Filter link local addresses as well
lambda x: x.startswith(" inet6 ") and not x.startswith(" inet6 fe80::"),
out.split("\n")
)
return len(inet6s) == 1

# work out if a link is up:
def linkUp(interface):
Expand Down Expand Up @@ -225,16 +232,21 @@ def valid_vlan(vlan):
return False
return True

def valid_ip_addr(addr):
if not re.match('^\d+\.\d+\.\d+\.\d+$', addr):
return False
els = addr.split('.')
if len(els) != 4:
def valid_ip_address_family(addr, family):
try:
socket.inet_pton(family, addr)
return True
except socket.error:
return False
for el in els:
if int(el) > 255:
return False
return True

def valid_ipv4_addr(addr):
return valid_ip_address_family(addr, socket.AF_INET)

def valid_ipv6_addr(addr):
return valid_ip_address_family(addr, socket.AF_INET6)

def valid_ip_addr(addr):
return valid_ipv4_addr(addr) or valid_ipv6_addr(addr)

def network(ipaddr, netmask):
ip = map(int,ipaddr.split('.',3))
Expand All @@ -246,7 +258,7 @@ def prefix2netmask(mask):
bits = 0
for i in xrange(32-mask, 32):
bits |= (1 << i)
return inet_ntoa(pack('>I', bits))
return socket.inet_ntoa(pack('>I', bits))

class NetDevices:
def __init__(self):
Expand Down
6 changes: 3 additions & 3 deletions tui/installer/screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ def ns_callback((enabled, )):
for entry in [ns1_entry, ns2_entry, ns3_entry]:
entry.setFlags(FLAG_DISABLED, enabled)

hide_rb = answers['net-admin-configuration'].isStatic()
hide_rb = not answers['net-admin-configuration'].isDynamic()

# HOSTNAME:
hn_title = Textbox(len("Hostname Configuration"), 1, "Hostname Configuration")
Expand Down Expand Up @@ -935,7 +935,7 @@ def nsvalue(answers, id):
answers['manual-nameservers'][1].append(ns2_entry.value())
if ns3_entry.value() != '':
answers['manual-nameservers'][1].append(ns3_entry.value())
if 'net-admin-configuration' in answers and answers['net-admin-configuration'].isStatic():
if 'net-admin-configuration' in answers and not answers['net-admin-configuration'].isDynamic():
answers['net-admin-configuration'].dns = answers['manual-nameservers'][1]
else:
answers['manual-nameservers'] = (False, None)
Expand Down Expand Up @@ -1036,7 +1036,7 @@ def dhcp_change():
for x in [ ntp1_field, ntp2_field, ntp3_field ]:
x.setFlags(FLAG_DISABLED, not dhcp_cb.value())

hide_cb = answers['net-admin-configuration'].isStatic()
hide_cb = not answers['net-admin-configuration'].isDynamic()

gf = GridFormHelp(tui.screen, 'NTP Configuration', 'ntpconf', 1, 4)
text = TextboxReflowed(60, "Please specify details of the NTP servers you wish to use (e.g. pool.ntp.org)?")
Expand Down
Loading