Skip to content

Commit

Permalink
Merge pull request #13 from xcp-ng/mrge-ipv6
Browse files Browse the repository at this point in the history
Merge ipv6 support
  • Loading branch information
stormi authored and ydirson committed Dec 15, 2023
2 parents 4362c61 + a469a6b commit 2d1d468
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 160 deletions.
16 changes: 11 additions & 5 deletions backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1548,15 +1548,15 @@ def configureNetworking(mounts, admin_iface, admin_bridge, admin_config, hn_conf
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:
print >>mc, "IPv6='%s'" % admin_config.ipv6addr
if admin_config.ipv6_gateway:
print >>mc, "IPv6_GATEWAY='%s'" % admin_config.ipv6_gateway
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 @@ -1598,12 +1598,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
77 changes: 64 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 All @@ -141,8 +149,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 @@ -151,7 +158,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 @@ -161,20 +168,45 @@ 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

if self.isStatic6() and self.ipv6_gateway and util.runCmd2(
['/usr/sbin/ndisc6', '-1', '-w', '120', self.ipv6_gateway, iface_name]
):
return False

rc = util.runCmd2(['/usr/sbin/arping', '-f', '-w', '120', '-I',
self.getInterfaceName(iface), self.gateway])
return rc == 0
return True

@staticmethod
def getModeStr(mode):
Expand All @@ -185,3 +217,22 @@ def getModeStr(mode):
if mode == NetInterface.Autoconf:
return 'autoconf'
return 'none'

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

self.addIPv6(mode, ipv6addr=ipv6addr, ipv6gw=gateway)
35 changes: 22 additions & 13 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 @@ -73,7 +73,7 @@ def writeResolverFile(configuration, filename):

for iface in configuration:
settings = configuration[iface]
if settings.isStatic() and settings.dns:
if (not settings.isDynamic()) and settings.dns:
if settings.dns:
for server in settings.dns:
outfile.write("nameserver %s\n" % server)
Expand Down Expand Up @@ -118,7 +118,11 @@ 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(lambda x: x.startswith(" inet6 "), out.split("\n"))
return len(inet6s) > 1 # Not just the fe80:: address

# work out if a link is up:
def linkUp(interface):
Expand Down Expand Up @@ -206,16 +210,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 @@ -227,7 +236,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 @@ -896,7 +896,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 @@ -1026,7 +1026,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 @@ -1109,7 +1109,7 @@ def get_time_configuration_method(answers):
default = None
if "ntp-config-method" in answers:
default = selectDefault(answers['ntp-config-method'], entries)
if answers['net-admin-configuration'].isStatic():
if not answers['net-admin-configuration'].isDynamic():
default = ENTRY_DEFAULT_NTP

(button, entry) = ListboxChoiceWindow(
Expand Down
Loading

0 comments on commit 2d1d468

Please sign in to comment.