Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
246 changes: 246 additions & 0 deletions SOURCES/xsconsole-10.1.14-support-ipv6.XCP-ng.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
Handle IPv6

Display IPv6 PIF's fields when primary_address_type is IPv6
Reconfigure management interface with appropriate method
Support network reset in the IPv6 case

Upstream PR: https://github.com/xapi-project/xsconsole/pull/4

diff --git a/XSConsoleData.py b/XSConsoleData.py
index 829ac8d..24798f0 100644
--- a/XSConsoleData.py
+++ b/XSConsoleData.py
@@ -910,7 +910,21 @@ def ReconfigureManagement(self, inPIF, inMode, inIP, inNetmask, inGateway, in
Auth.Inst().AssertAuthenticated()
try:
self.RequireSession()
- self.session.xenapi.PIF.reconfigure_ip(inPIF['opaqueref'], inMode, inIP, inNetmask, inGateway, FirstValue(inDNS, ''))
+ if inPIF['primary_address_type'].lower() == 'ipv4':
+ self.session.xenapi.PIF.reconfigure_ip(inPIF['opaqueref'], inMode, inIP, inNetmask, inGateway, FirstValue(inDNS, ''))
+ if inPIF['ipv6_configuration_mode'].lower() == 'static':
+ # Update IPv6 DNS as well
+ self.session.xenapi.PIF.reconfigure_ipv6(
+ inPIF['opaqueref'], inPIF['ipv6_configuration_mode'], ','.join(inPIF['IPv6']), inPIF['ipv6_gateway'], FirstValue(inDNS, '')
+ )
+ else:
+ inIPv6 = inIP + '/' + inNetmask
+ self.session.xenapi.PIF.reconfigure_ipv6(inPIF['opaqueref'], inMode, inIPv6, inGateway, FirstValue(inDNS, ''))
+ if inPIF['ip_configuration_mode'].lower() == 'static':
+ # Update IPv4 DNS as well
+ self.session.xenapi.PIF.reconfigure_ip(
+ inPIF['opaqueref'], inPIF['ip_configuration_mode'], inPIF['IP'], inPIF['netmask'], inPIF['gateway'], FirstValue(inDNS, '')
+ )
self.session.xenapi.host.management_reconfigure(inPIF['opaqueref'])
status, output = commands.getstatusoutput('%s host-signal-networking-change' % (Config.Inst().XECLIPath()))
if status != 0:
@@ -930,6 +944,7 @@ def DisableManagement(self):
# Disable the PIF that the management interface was using
for pif in self.derived.managementpifs([]):
self.session.xenapi.PIF.reconfigure_ip(pif['opaqueref'], 'None','' ,'' ,'' ,'')
+ self.session.xenapi.PIF.reconfigure_ipv6(pif['opaqueref'], 'None','' ,'' ,'')
finally:
# Network reconfigured so this link is potentially no longer valid
self.session = Auth.Inst().CloseSession(self.session)
@@ -965,10 +980,12 @@ def ManagementNetmask(self, inDefault = None):

# FIXME: Address should come from API, but not available at present. For DHCP this is just a guess at the gateway address
for pif in self.derived.managementpifs([]):
- if pif['ip_configuration_mode'].lower().startswith('static'):
+ ipv6 = pif['primary_address_type'].lower() == 'ipv6'
+ configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
+ if configuration_mode.lower().startswith('static'):
# For static IP the API address is correct
- retVal = pif['netmask']
- elif pif['ip_configuration_mode'].lower().startswith('dhcp'):
+ retVal = pif['IPv6'][0].split('/')[1] if ipv6 else pif['netmask']
+ elif configuration_mode.lower().startswith('dhcp'):
# For DHCP, find the gateway address by parsing the output from the 'route' command
if 'bridge' in pif['network']:
device = pif['network']['bridge']
@@ -995,10 +1012,12 @@ def ManagementGateway(self, inDefault = None):

# FIXME: Address should come from API, but not available at present. For DHCP this is just a guess at the gateway address
for pif in self.derived.managementpifs([]):
- if pif['ip_configuration_mode'].lower().startswith('static'):
+ ipv6 = pif['primary_address_type'].lower() == 'ipv6'
+ configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
+ if configuration_mode.lower().startswith('static'):
# For static IP the API address is correct
- retVal = pif['gateway']
- elif pif['ip_configuration_mode'].lower().startswith('dhcp'):
+ retVal = pif['ipv6_gateway'] if ipv6 else pif['gateway']
+ elif configuration_mode.lower().startswith('dhcp'):
# For DHCP, find the gateway address by parsing the output from the 'route' command
if 'bridge' in pif['network']:
device = pif['network']['bridge']
diff --git a/XSConsoleUtils.py b/XSConsoleUtils.py
index f5a3ad1..271256b 100644
--- a/XSConsoleUtils.py
+++ b/XSConsoleUtils.py
@@ -190,26 +190,13 @@ def DateTimeToSecs(cls, inDateTime):
class IPUtils:
@classmethod
def ValidateIP(cls, text):
- rc = re.match("^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$", text)
- if not rc: return False
- ints = map(int, rc.groups())
- largest = 0
- for i in ints:
- if i > 255: return False
- largest = max(largest, i)
- if largest is 0: return False
- return True
+ ipv4_re = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}'
+ ipv6_re = '^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'
+ return re.match(ipv4_re, text) or re.match(ipv6_re, text)

@classmethod
def ValidateNetmask(cls, text):
- rc = re.match("^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$", text)
- if not rc:
- return False
- ints = map(int, rc.groups())
- for i in ints:
- if i > 255:
- return False
- return True
+ return cls.ValidateIP(text) or (int(text) > 4 and int(text) < 128)

@classmethod
def AssertValidNetmask(cls, inIP):
diff --git a/plugins-base/XSFeatureDNS.py b/plugins-base/XSFeatureDNS.py
index 132b209..7840da3 100644
--- a/plugins-base/XSFeatureDNS.py
+++ b/plugins-base/XSFeatureDNS.py
@@ -179,7 +179,9 @@ def StatusUpdateHandler(cls, inPane):
inPane.AddWrappedTextField(str(dns))
inPane.NewLine()
for pif in data.derived.managementpifs([]):
- if pif['ip_configuration_mode'].lower().startswith('static'):
+ ipv6 = pif['primary_address_type'].lower() == 'ipv6'
+ configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
+ if configuration_mode.lower().startswith('static'):
inPane.AddKeyHelpField( { Lang("Enter") : Lang("Update DNS Servers") })
break
inPane.AddKeyHelpField( {
@@ -203,7 +205,9 @@ def Register(self):
def ActivateHandler(cls):
data = Data.Inst()
for pif in data.derived.managementpifs([]):
- if pif['ip_configuration_mode'].lower().startswith('static'):
+ ipv6 = pif['primary_address_type'].lower() == 'ipv6'
+ configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
+ if configuration_mode.lower().startswith('static'):
DialogueUtils.AuthenticatedOnly(lambda: Layout.Inst().PushDialogue(DNSDialogue()))
return

diff --git a/plugins-base/XSFeatureInterface.py b/plugins-base/XSFeatureInterface.py
index 6ea60bc..7091dfc 100644
--- a/plugins-base/XSFeatureInterface.py
+++ b/plugins-base/XSFeatureInterface.py
@@ -83,11 +83,17 @@ def __init__(self):
self.hostname = data.host.hostname('')

if currentPIF is not None:
- if 'ip_configuration_mode' in currentPIF: self.mode = currentPIF['ip_configuration_mode']
+ ipv6 = currentPIF['primary_address_type'].lower() == 'ipv6'
+ configuration_mode_key = 'ipv6_configuration_mode' if ipv6 else 'ip_configuration_mode'
+ if configuration_mode_key in currentPIF:
+ self.mode = currentPIF[configuration_mode_key]
if self.mode.lower().startswith('static'):
- if 'IP' in currentPIF: self.IP = currentPIF['IP']
- if 'netmask' in currentPIF: self.netmask = currentPIF['netmask']
- if 'gateway' in currentPIF: self.gateway = currentPIF['gateway']
+ if 'IP' in currentPIF:
+ self.IP = currentPIF['IPv6'][0].split('/')[0] if ipv6 else currentPIF['IP']
+ if 'netmask' in currentPIF:
+ self.netmask = currentPIF['IPv6'][0].split('/')[1] if ipv6 else currentPIF['netmask']
+ if 'gateway' in currentPIF:
+ self.gateway = currentPIF['ipv6_gateway'] if ipv6 else currentPIF['gateway']

# Make the menu current choices point to our best guess of current choices
if self.nic is not None:
@@ -455,9 +461,11 @@ def StatusUpdateHandler(cls, inPane):
inPane.AddWrappedTextField(Lang("<No interface configured>"))
else:
for pif in data.derived.managementpifs([]):
+ ipv6 = pif['primary_address_type'].lower() == 'ipv6'
+ configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
inPane.AddStatusField(Lang('Device', 16), pif['device'])
inPane.AddStatusField(Lang('MAC Address', 16), pif['MAC'])
- inPane.AddStatusField(Lang('DHCP/Static IP', 16), pif['ip_configuration_mode'])
+ inPane.AddStatusField(Lang('DHCP/Static IP', 16), configuration_mode)

inPane.AddStatusField(Lang('IP address', 16), data.ManagementIP(''))
inPane.AddStatusField(Lang('Netmask', 16), data.ManagementNetmask(''))
diff --git a/plugins-base/XSFeatureNetworkReset.py b/plugins-base/XSFeatureNetworkReset.py
index b20a08c..38d69d3 100644
--- a/plugins-base/XSFeatureNetworkReset.py
+++ b/plugins-base/XSFeatureNetworkReset.py
@@ -365,18 +365,23 @@ def Commit(self):
inventory['CURRENT_INTERFACES'] = ''
write_inventory(inventory)

+ ipv6 = self.IP.find(':') > -1
+
# Rewrite firstboot management.conf file, which will be picked it by xcp-networkd on restart (if used)
f = open(management_conf, 'w')
try:
f.write("LABEL='" + self.device + "'\n")
- f.write("MODE='" + self.mode + "'\n")
+ f.write(("MODEV6" if ipv6 else "MODE") + "='" + self.mode + "'\n")
if self.vlan != '':
f.write("VLAN='" + self.vlan + "'\n")
if self.mode == 'static':
- f.write("IP='" + self.IP + "'\n")
- f.write("NETMASK='" + self.netmask + "'\n")
+ if ipv6:
+ f.write("IPv6='" + self.IP + "/" + self.netmask + "'\n")
+ else:
+ f.write("IP='" + self.IP + "'\n")
+ f.write("NETMASK='" + self.netmask + "'\n")
if self.gateway != '':
- f.write("GATEWAY='" + self.gateway + "'\n")
+ f.write(("IPv6_GATEWAY" if ipv6 else "GATEWAY") + "='" + self.gateway + "'\n")
if self.dns != '':
f.write("DNS='" + self.dns + "'\n")
finally:
@@ -386,14 +391,17 @@ def Commit(self):
f = open(network_reset, 'w')
try:
f.write('DEVICE=' + self.device + '\n')
- f.write('MODE=' + self.mode + '\n')
+ f.write(('MODE_V6' if ipv6 else 'MODE') + '=' + self.mode + '\n')
if self.vlan != '':
f.write('VLAN=' + self.vlan + '\n')
if self.mode == 'static':
- f.write('IP=' + self.IP + '\n')
- f.write('NETMASK=' + self.netmask + '\n')
+ if ipv6:
+ f.write('IPV6=' + self.IP + '/' + self.netmask + '\n')
+ else:
+ f.write('IP=' + self.IP + '\n')
+ f.write('NETMASK=' + self.netmask + '\n')
if self.gateway != '':
- f.write('GATEWAY=' + self.gateway + '\n')
+ f.write(('GATEWAY_V6' if ipv6 else 'GATEWAY') + '=' + self.gateway + '\n')
if self.dns != '':
f.write('DNS=' + self.dns + '\n')
finally:
diff --git a/plugins-base/XSMenuLayout.py b/plugins-base/XSMenuLayout.py
index e284ee9..0899446 100644
--- a/plugins-base/XSMenuLayout.py
+++ b/plugins-base/XSMenuLayout.py
@@ -68,9 +68,11 @@ def UpdateFieldsNETWORK(self, inPane):
ntpState = 'Disabled'

for pif in data.derived.managementpifs([]):
+ ipv6 = pif['primary_address_type'].lower() == 'ipv6'
+ configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
inPane.AddStatusField(Lang('Device', 16), pif['device'])
inPane.AddStatusField(Lang('MAC Address', 16), pif['MAC'])
- inPane.AddStatusField(Lang('DHCP/Static IP', 16), pif['ip_configuration_mode'])
+ inPane.AddStatusField(Lang('DHCP/Static IP', 16), configuration_mode)

inPane.AddStatusField(Lang('IP address', 16), data.ManagementIP(''))
inPane.AddStatusField(Lang('Netmask', 16), data.ManagementNetmask(''))
6 changes: 5 additions & 1 deletion SPECS/xsconsole.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Summary: XCP-ng Host Configuration Console
Name: xsconsole
Version: 10.1.14
Release: 1.1%{?xsrel}%{?dist}
Release: 1.2%{?xsrel}%{?dist}
License: GPL2
Group: Administration/System
Source0: xsconsole-10.1.14.tar.gz
Expand All @@ -18,6 +18,7 @@ Requires(postun): systemd
# XCP-ng patches
Patch1000: xsconsole-10.1.9-rebrand-xsconsole-service.XCP-ng.patch
Patch1001: xsconsole-10.1.13-define-xcp-ng-colors.XCP-ng.patch
Patch1002: xsconsole-10.1.14-support-ipv6.XCP-ng.patch

%description
Console tool for configuring a XCP-ng installation.
Expand Down Expand Up @@ -54,6 +55,9 @@ Console tool for configuring a XCP-ng installation.
%{_unitdir}/xsconsole.service

%changelog
* Wed May 10 2023 Benjamin Reis <[email protected]> - 10.1.14-1.2
- Add xsconsole-10.1.14-support-ipv6.XCP-ng.patch

* Wed Dec 07 2022 Samuel Verschelde <[email protected]> - 10.1.14-1.1
- Update from XS 8.3 pre-release updates
- *** Upstream changelog ***
Expand Down