2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-08-21 18:50:30 +00:00

Draft work to update pxe and netutil for ipv6 support

This commit is contained in:
Jarrod Johnson
2021-08-25 17:58:36 -04:00
parent ba7ccaa7f2
commit 1b3231377c
2 changed files with 103 additions and 19 deletions

View File

@@ -25,6 +25,7 @@
import confluent.config.configmanager as cfm
import confluent.collective.manager as collective
import confluent.noderange as noderange
import confluent.neighutil as neighutil
import confluent.log as log
import confluent.netutil as netutil
import confluent.util as util
@@ -397,20 +398,32 @@ def snoop(handler, protocol=None, nodeguess=None):
rqv = memoryview(pkt)
rq = bytearray(rqv[:2])
if rq[0] == 1: # dhcpv6 solicit
process_dhcp6req(rqv, addr[0])
process_dhcp6req(handler, rqv, addr, netc, cfg, nodeguess)
except Exception as e:
tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
event=log.Events.stacktrace)
def process_dhcp6req(rqv, addr):
txid = rqv[1:4]
def process_dhcp6req(handler, rqv, addr, net, cfg, nodeguess):
ip = addr[0]
req, disco = v6opts_to_dict(bytearray(rqv[4:]))
if 'uuid' not in disco:
req['txid'] = rqv[1:4]
if not disco.get('uuid', None) or not disco.get('arch', None):
return
print(addr)
print(repr(disco))
mac = neighutil.get_hwaddr(ip.split('%', 1)[0])
if not mac:
net.sendto(b'\x00', addr)
tries = 5
while tries and not mac:
eventlet.sleep(0.01)
tries -= 1
mac = neighutil.get_hwaddr(ip.split('%', 1)[0])
info = {'hwaddr': mac, 'uuid': disco['uuid'],
'architecture': disco['arch'], 'services': ('pxe-client',)}
if ignoredisco.get(mac, 0) + 90 < time.time():
ignoredisco[mac] = time.time()
handler(info)
consider_discover(info, req, net, cfg, None, nodeguess, addr)
def process_dhcp4req(handler, nodeguess, cfg, net4, idx, recv, rqv):
rq = bytearray(rqv)
@@ -501,9 +514,8 @@ def get_deployment_profile(node, cfg, cfd=None):
staticassigns = {}
myipbypeer = {}
def check_reply(node, info, packet, sock, cfg, reqview):
def check_reply(node, info, packet, sock, cfg, reqview, addr):
httpboot = info['architecture'] == 'uefi-httpboot'
replen = 275 # default is going to be 286
cfd = cfg.get_node_attributes(node, ('deployment.*'))
profile = get_deployment_profile(node, cfg, cfd)
if not profile:
@@ -513,6 +525,26 @@ def check_reply(node, info, packet, sock, cfg, reqview):
node, info['uuid'], info['hwaddr']
)})
return
if 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)
else:
return reply_dhcp4(node, info, packet, cfg, reqview, httpboot, cfd, profile)
def reply_dhcp6(node, addr, cfg):
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])})
return
niccfg = netutil.get_nic_config(cfg, node, ifidx=addr[-1])
print(repr(addr))
pass
def reply_dhcp4(node, info, packet, cfg, reqview, httpboot, cfd, profile):
replen = 275 # default is going to be 286
myipn = info['netinfo']['recvip']
myipn = socket.inet_aton(myipn)
@@ -686,11 +718,11 @@ def ack_request(pkt, rq, info):
repview[26:28] = struct.pack('!H', datasum)
send_raw_packet(repview, len(rply), rq, info)
def consider_discover(info, packet, sock, cfg, reqview, nodeguess):
def consider_discover(info, packet, sock, cfg, reqview, nodeguess, addr=None):
if info.get('hwaddr', None) in macmap and info.get('uuid', None):
check_reply(macmap[info['hwaddr']], info, packet, sock, cfg, reqview)
check_reply(macmap[info['hwaddr']], info, packet, sock, cfg, reqview, addr)
elif info.get('uuid', None) in uuidmap:
check_reply(uuidmap[info['uuid']], info, packet, sock, cfg, reqview)
check_reply(uuidmap[info['uuid']], info, packet, sock, cfg, reqview, addr)
elif packet.get(53, None) == b'\x03':
ack_request(packet, reqview, info)
elif info.get('uuid', None) and info.get('hwaddr', None):

View File

@@ -172,20 +172,38 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
None)
cfgdata = {
'ipv4_gateway': None,
'ipv4_broken': True,
'ipv6_broken': True,
'ipv4_address': None,
'ipv4_method': None,
'prefix': None,
'ipv6_prefix': None,
'ipv6_address': None,
'ipv6_method': None,
}
nets = None
needsvrip = False
myaddrs = []
if ifidx is not None:
dhcprequested = False
nets = list(_iftonets(ifidx))
if not nets:
cfgdata['ipv4_broken'] = True
myaddrs = get_my_addresses(ifidx)
for addr in myaddrs:
try:
if addr[0] == socket.AF_INET:
del cfgdata['ipv4_broken']
elif addr[1] == socket.AF_INET6:
del cfgdata['ipv6_broken']
except KeyError:
pass
if serverip is not None:
needsvrip = True
if '.' in serverip:
fam = socket.AF_INET
elif ':' in serverip:
fam = socket.AF_INET6
else:
raise ValueError('"{0}" is not a valid ip argument')
ipbytes = socket.inet_pton(fam, serverip)
dhcprequested = False
myips = [x for x in get_my_addresses() if x[1] == ipbytes]
print(repr(myips))
nets = list(myiptonets(serverip))
genericmethod = 'static'
ipbynodename = None
@@ -194,7 +212,7 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
node, 0, socket.AF_INET, socket.SOCK_DGRAM)[0][-1][0]
except Exception:
ipbynodename = None
if nets is not None:
if nets:
candgws = []
candsrvs = []
for net in nets:
@@ -267,6 +285,40 @@ def get_nic_config(configmanager, node, ip=None, mac=None, ifidx=None,
break
return cfgdata
nlhdrsz = struct.calcsize('IHHII')
ifaddrsz = struct.calcsize('BBBBI')
def get_my_addresses(idx=0, family=0):
# RTM_GETADDR = 22
# nlmsghdr struct: u32 len, u16 type, u16 flags, u32 seq, u32 pid
nlhdr = struct.pack('IHHII', nlhdrsz + ifaddrsz, 22, 0x301, 0, 0)
# ifaddrmsg struct: u8 family, u8 prefixlen, u8 flags, u8 scope, u32 index
ifaddrmsg = struct.pack('BBBBI', family, 0, 0, 0, idx)
s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE)
s.bind((0, 0))
s.sendall(nlhdr + ifaddrmsg)
addrs = []
while True:
pdata = s.recv(65536)
v = memoryview(pdata)
if struct.unpack('H', v[4:6])[0] == 3: # netlink done message
break
while len(v):
length, typ = struct.unpack('IH', v[:6])
if typ == 20:
fam, plen, _, scope, ridx = struct.unpack('BBBBI', v[nlhdrsz:nlhdrsz+ifaddrsz])
if (ridx == idx or not idx) and scope == 0:
rta = v[nlhdrsz+ifaddrsz:length]
while len(rta):
rtalen, rtatyp = struct.unpack('HH', rta[:4])
if rtatyp == 1:
addrs.append((fam, rta[4:rtalen].tobytes(), plen, ridx))
if not rtalen:
break
rta = rta[rtalen:]
v = v[length:]
return addrs
def get_prefix_len_for_ip(ip):
# for now, we'll use the system route table