Skip to content

Commit dd2b06d

Browse files
committed
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 Signed-off-by: BenjiReis <benjamin.reis@vates.fr>
1 parent 856ce4c commit dd2b06d

File tree

6 files changed

+68
-40
lines changed

6 files changed

+68
-40
lines changed

XSConsoleData.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,21 @@ def ReconfigureManagement(self, inPIF, inMode, inIP, inNetmask, inGateway, in
910910
Auth.Inst().AssertAuthenticated()
911911
try:
912912
self.RequireSession()
913-
self.session.xenapi.PIF.reconfigure_ip(inPIF['opaqueref'], inMode, inIP, inNetmask, inGateway, FirstValue(inDNS, ''))
913+
if inPIF['primary_address_type'].lower() == 'ipv4':
914+
self.session.xenapi.PIF.reconfigure_ip(inPIF['opaqueref'], inMode, inIP, inNetmask, inGateway, FirstValue(inDNS, ''))
915+
if inPIF['ipv6_configuration_mode'].lower() == 'static':
916+
# Update IPv6 DNS as well
917+
self.session.xenapi.PIF.reconfigure_ipv6(
918+
inPIF['opaqueref'], inPIF['ipv6_configuration_mode'], ','.join(inPIF['IPv6']), inPIF['ipv6_gateway'], FirstValue(inDNS, '')
919+
)
920+
else:
921+
inIPv6 = inIP + '/' + inNetmask
922+
self.session.xenapi.PIF.reconfigure_ipv6(inPIF['opaqueref'], inMode, inIPv6, inGateway, FirstValue(inDNS, ''))
923+
if inPIF['ip_configuration_mode'].lower() == 'static':
924+
# Update IPv4 DNS as well
925+
self.session.xenapi.PIF.reconfigure_ip(
926+
inPIF['opaqueref'], inPIF['ip_configuration_mode'], inPIF['IP'], inPIF['netmask'], inPIF['gateway'], FirstValue(inDNS, '')
927+
)
914928
self.session.xenapi.host.management_reconfigure(inPIF['opaqueref'])
915929
status, output = commands.getstatusoutput('%s host-signal-networking-change' % (Config.Inst().XECLIPath()))
916930
if status != 0:
@@ -930,6 +944,7 @@ def DisableManagement(self):
930944
# Disable the PIF that the management interface was using
931945
for pif in self.derived.managementpifs([]):
932946
self.session.xenapi.PIF.reconfigure_ip(pif['opaqueref'], 'None','' ,'' ,'' ,'')
947+
self.session.xenapi.PIF.reconfigure_ipv6(pif['opaqueref'], 'None','' ,'' ,'')
933948
finally:
934949
# Network reconfigured so this link is potentially no longer valid
935950
self.session = Auth.Inst().CloseSession(self.session)
@@ -965,10 +980,12 @@ def ManagementNetmask(self, inDefault = None):
965980

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

9961013
# FIXME: Address should come from API, but not available at present. For DHCP this is just a guess at the gateway address
9971014
for pif in self.derived.managementpifs([]):
998-
if pif['ip_configuration_mode'].lower().startswith('static'):
1015+
ipv6 = pif['primary_address_type'].lower() == 'ipv6'
1016+
configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
1017+
if configuration_mode.lower().startswith('static'):
9991018
# For static IP the API address is correct
1000-
retVal = pif['gateway']
1001-
elif pif['ip_configuration_mode'].lower().startswith('dhcp'):
1019+
retVal = pif['ipv6_gateway'] if ipv6 else pif['gateway']
1020+
elif configuration_mode.lower().startswith('dhcp'):
10021021
# For DHCP, find the gateway address by parsing the output from the 'route' command
10031022
if 'bridge' in pif['network']:
10041023
device = pif['network']['bridge']

XSConsoleUtils.py

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -190,26 +190,13 @@ def DateTimeToSecs(cls, inDateTime):
190190
class IPUtils:
191191
@classmethod
192192
def ValidateIP(cls, text):
193-
rc = re.match("^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$", text)
194-
if not rc: return False
195-
ints = map(int, rc.groups())
196-
largest = 0
197-
for i in ints:
198-
if i > 255: return False
199-
largest = max(largest, i)
200-
if largest is 0: return False
201-
return True
193+
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}'
194+
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]))'
195+
return re.match(ipv4_re, text) or re.match(ipv6_re, text)
202196

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

214201
@classmethod
215202
def AssertValidNetmask(cls, inIP):

plugins-base/XSFeatureDNS.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ def StatusUpdateHandler(cls, inPane):
179179
inPane.AddWrappedTextField(str(dns))
180180
inPane.NewLine()
181181
for pif in data.derived.managementpifs([]):
182-
if pif['ip_configuration_mode'].lower().startswith('static'):
182+
ipv6 = pif['primary_address_type'].lower() == 'ipv6'
183+
configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
184+
if configuration_mode.lower().startswith('static'):
183185
inPane.AddKeyHelpField( { Lang("Enter") : Lang("Update DNS Servers") })
184186
break
185187
inPane.AddKeyHelpField( {
@@ -203,7 +205,9 @@ def Register(self):
203205
def ActivateHandler(cls):
204206
data = Data.Inst()
205207
for pif in data.derived.managementpifs([]):
206-
if pif['ip_configuration_mode'].lower().startswith('static'):
208+
ipv6 = pif['primary_address_type'].lower() == 'ipv6'
209+
configuration_mode = pif['ipv6_configuration_mode'] if ipv6 else pif['ip_configuration_mode']
210+
if configuration_mode.lower().startswith('static'):
207211
DialogueUtils.AuthenticatedOnly(lambda: Layout.Inst().PushDialogue(DNSDialogue()))
208212
return
209213

plugins-base/XSFeatureInterface.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,17 @@ def __init__(self):
8383
self.hostname = data.host.hostname('')
8484

8585
if currentPIF is not None:
86-
if 'ip_configuration_mode' in currentPIF: self.mode = currentPIF['ip_configuration_mode']
86+
ipv6 = currentPIF['primary_address_type'].lower() == 'ipv6'
87+
configuration_mode_key = 'ipv6_configuration_mode' if ipv6 else 'ip_configuration_mode'
88+
if configuration_mode_key in currentPIF:
89+
self.mode = currentPIF[configuration_mode_key]
8790
if self.mode.lower().startswith('static'):
88-
if 'IP' in currentPIF: self.IP = currentPIF['IP']
89-
if 'netmask' in currentPIF: self.netmask = currentPIF['netmask']
90-
if 'gateway' in currentPIF: self.gateway = currentPIF['gateway']
91+
if 'IP' in currentPIF:
92+
self.IP = currentPIF['IPv6'][0].split('/')[0] if ipv6 else currentPIF['IP']
93+
if 'netmask' in currentPIF:
94+
self.netmask = currentPIF['IPv6'][0].split('/')[1] if ipv6 else currentPIF['netmask']
95+
if 'gateway' in currentPIF:
96+
self.gateway = currentPIF['ipv6_gateway'] if ipv6 else currentPIF['gateway']
9197

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

462470
inPane.AddStatusField(Lang('IP address', 16), data.ManagementIP(''))
463471
inPane.AddStatusField(Lang('Netmask', 16), data.ManagementNetmask(''))

plugins-base/XSFeatureNetworkReset.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -365,18 +365,23 @@ def Commit(self):
365365
inventory['CURRENT_INTERFACES'] = ''
366366
write_inventory(inventory)
367367

368+
ipv6 = self.IP.find(':') > -1
369+
368370
# Rewrite firstboot management.conf file, which will be picked it by xcp-networkd on restart (if used)
369371
f = open(management_conf, 'w')
370372
try:
371373
f.write("LABEL='" + self.device + "'\n")
372-
f.write("MODE='" + self.mode + "'\n")
374+
f.write(("MODEV6" if ipv6 else "MODE") + "='" + self.mode + "'\n")
373375
if self.vlan != '':
374376
f.write("VLAN='" + self.vlan + "'\n")
375377
if self.mode == 'static':
376-
f.write("IP='" + self.IP + "'\n")
377-
f.write("NETMASK='" + self.netmask + "'\n")
378+
if ipv6:
379+
f.write("IPv6='" + self.IP + "/" + self.netmask + "'\n")
380+
else:
381+
f.write("IP='" + self.IP + "'\n")
382+
f.write("NETMASK='" + self.netmask + "'\n")
378383
if self.gateway != '':
379-
f.write("GATEWAY='" + self.gateway + "'\n")
384+
f.write(("IPv6_GATEWAY" if ipv6 else "GATEWAY") + "='" + self.gateway + "'\n")
380385
if self.dns != '':
381386
f.write("DNS='" + self.dns + "'\n")
382387
finally:
@@ -386,14 +391,17 @@ def Commit(self):
386391
f = open(network_reset, 'w')
387392
try:
388393
f.write('DEVICE=' + self.device + '\n')
389-
f.write('MODE=' + self.mode + '\n')
394+
f.write(('MODE_V6' if ipv6 else 'MODE') + '=' + self.mode + '\n')
390395
if self.vlan != '':
391396
f.write('VLAN=' + self.vlan + '\n')
392397
if self.mode == 'static':
393-
f.write('IP=' + self.IP + '\n')
394-
f.write('NETMASK=' + self.netmask + '\n')
398+
if ipv6:
399+
f.write('IPV6=' + self.IP + '/' + self.netmask + '\n')
400+
else:
401+
f.write('IP=' + self.IP + '\n')
402+
f.write('NETMASK=' + self.netmask + '\n')
395403
if self.gateway != '':
396-
f.write('GATEWAY=' + self.gateway + '\n')
404+
f.write(('GATEWAY_V6' if ipv6 else 'GATEWAY') + '=' + self.gateway + '\n')
397405
if self.dns != '':
398406
f.write('DNS=' + self.dns + '\n')
399407
finally:

plugins-base/XSMenuLayout.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ def UpdateFieldsNETWORK(self, inPane):
6868
ntpState = 'Disabled'
6969

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

7577
inPane.AddStatusField(Lang('IP address', 16), data.ManagementIP(''))
7678
inPane.AddStatusField(Lang('Netmask', 16), data.ManagementNetmask(''))

0 commit comments

Comments
 (0)