2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-04-23 13:35:57 +00:00

Fix ipv6 netboot support to get to request

A number of mistakes were in
netutil and the advertise needed
to be complete and transmitted.
This commit is contained in:
Jarrod Johnson 2021-09-07 16:13:27 -04:00
parent 10e408559b
commit f3d7a949e6
2 changed files with 88 additions and 12 deletions

View File

@ -38,6 +38,7 @@ import netifaces
import struct
import time
import traceback
import uuid
libc = ctypes.CDLL(ctypes.util.find_library('c'))
@ -529,19 +530,87 @@ def check_reply(node, info, packet, sock, cfg, reqview, addr):
if not httpboot:
log.log({'info': 'IPv6 PXE boot attempt by {0}, but IPv6 PXE is not supported, try IPv6 HTTP boot or IPv4 boot'.format(node)})
return
return reply_dhcp6(node, addr, cfg)
return reply_dhcp6(node, addr, cfg, packet, cfd, profile, sock)
else:
return reply_dhcp4(node, info, packet, cfg, reqview, httpboot, cfd, profile)
def reply_dhcp6(node, addr, cfg):
def reply_dhcp6(node, addr, cfg, packet, cfd, profile, sock):
myaddrs = netutil.get_my_addresses(addr[-1], socket.AF_INET6)
if not myaddrs:
log.log({'info': 'Unable to provide IPv6 boot services to {0} , no viable IPv6 configuration on interface index "{1}" to respond through.'.format(node, addr[-1])})
log.log({'info': 'Unable to provide IPv6 boot services to {0}, no viable IPv6 configuration on interface index "{1}" to respond through.'.format(node, addr[-1])})
return
niccfg = netutil.get_nic_config(cfg, node, ifidx=addr[-1])
ipv6addr = niccfg.get('ipv6_address', None)
ipv6prefix = niccfg.get('ipv6_prefix', None)
ipv6method = niccfg.get('ipv6_method', 'static')
ipv6srvaddr = niccfg.get('deploy_server_v6', None)
if not ipv6srvaddr:
log.log({'info': 'Unable to determine an appropriate ipv6 server ip for {}'.format(node)})
return
insecuremode = cfd.get(node, {}).get('deployment.useinsecureprotocols',
{}).get('value', 'never')
if not insecuremode:
insecuremode = 'never'
proto = 'https' if insecuremode == 'never' else 'http'
bootfile = '{0}://[{1}]/confluent-public/os/{2}/boot.img'.format(
proto, ipv6srvaddr, profile
)
if not isinstance(bootfile, bytes):
bootfile = bootfile.encode('utf8')
ipass = []
if ipv6method not in ('dhcp', 'firmwaredhcp') and ipv6addr:
if not ipv6prefix:
log.log({'info': 'Unable to determine prefix to serve to address {} for node {}'.format(ipv6addr, node)})
return
ipass = bytearray(40)
ipass[:4] = packet[3][:4] # pass iaid back
ipass[4:16] = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x18'
ipass[16:32] = socket.inet_pton(socket.AF_INET6, ipv6addr)
ipass[32:40] = b'\x00\x00\x00\x78\x00\x00\x01\x2c'
#1 msgtype
#3 txid
#22 - server ident
#len(packet[1]) + 4 - client ident
#len(ipass) + 4 or 0
#len(url) + 4
replylen = 50 + len(bootfile) + len(packet[1]) + 4
if len(ipass):
replylen += len(ipass)
reply = bytearray(replylen)
reply[0] = 2
reply[1:4] = packet['txid']
offset = 4
struct.pack_into('!HH', reply, offset, 1, len(packet[1]))
offset += 4
reply[offset:offset+len(packet[1])] = packet[1]
offset += len(packet[1])
struct.pack_into('!HHH', reply, offset, 2, 18, 4)
offset += 6
reply[offset:offset+16] = get_my_duid()
offset += 16
if ipass:
struct.pack_into('!HH', reply, offset, 3, len(ipass))
offset += 4
reply[offset:offset + len(ipass)] = ipass
offset += len(ipass)
struct.pack_into('!HH', reply, offset, 59, len(bootfile))
offset += 4
reply[offset:offset + len(bootfile)] = bootfile
offset += len(bootfile)
# Need the HTTPClient in the vendor class for reply
struct.pack_into('!HHIH', reply, offset, 16, 16, 0, 10)
offset += 10
reply[offset:offset + 10] = b'HTTPClient'
sock.sendto(reply, addr)
_myuuid = None
def get_my_duid():
global _myuuid
if not _myuuid:
_myuuid = uuid.uuid4().bytes
return _myuuid
print(repr(addr))
pass
def reply_dhcp4(node, info, packet, cfg, reqview, httpboot, cfd, profile):
replen = 275 # default is going to be 286

View File

@ -226,10 +226,13 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
ipbynodename = None
ip6bynodename = None
try:
for addr in socket.getaddrinfo(node, 0, 0, socket.SOCK_DGRAM):
if addr[0] == socket.AF_INET:
ipbynodename = addr[-1][0]
elif addr[0] == socket.AF_INET6:
for addr in socket.getaddrinfo(node, 0, socket.AF_INET, socket.SOCK_DGRAM):
ipbynodename = addr[-1][0]
except socket.gaierror:
pass
try:
for addr in socket.getaddrinfo(node, 0, socket.AF_INET6, socket.SOCK_DGRAM):
ip6bynodename = addr[-1][0]
except socket.gaierror:
pass
@ -270,7 +273,7 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
if nver == '4':
cfgdata['prefix'] = prefix
else:
cfgdata['prefix_v{}'.format(nver)] = prefix
cfgdata['ipv{}_prefix'.format(nver)] = prefix
if candip in (ipbynodename, ip6bynodename):
cfgdata['matchesnodename'] = True
return cfgdata
@ -297,6 +300,8 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
else:
bynodename = ip6bynodename
nver = '6'
if not bynodename: # node is missing either ipv6 or ipv4, ignore
continue
ipbynodenamn = socket.inet_pton(fam, bynodename)
if ipn_on_same_subnet(fam, svrip, ipbynodenamn, prefix):
cfgdata['matchesnodename'] = True
@ -305,13 +310,15 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
if nver == '4':
cfgdata['prefix'] = prefix
else:
cfgdata['prefix_v6'] = prefix
cfgdata['ipv{}_prefix'.format(nver)] = prefix
for svr in candsrvs:
fam, svr, prefix = svr
if fam == socket.AF_INET:
bynodename = ipbynodename
elif fam == socket.AF_INET6:
bynodename = ip6bynodename
if not bynodename:
continue # ignore undefined family
bynodenamn = socket.inet_pton(fam, bynodename)
if ipn_on_same_subnet(fam, svr, bynodenamn, prefix):
svrname = socket.inet_ntop(fam, svr)
@ -338,8 +345,8 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
cfgdata['prefix'] = prefix
nver = '4'
else:
cfgdata['prefix_v6'] = prefix
nver = '6'
cfgdata['ipv{}_prefix'.format(nver)] = prefix
for setting in nodenetattribs:
if 'ipv{}_gateway'.format(nver) not in setting:
continue