From 69b58836f699ee4a6f283ff1f90a5886c6f460ee Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 24 Aug 2021 11:54:13 -0400 Subject: [PATCH] Change to built in neigh fetch Rather than outsource, slowly, to ip neigh for this frequent task, call netlink directly. --- confluent_server/confluent/neighutil.py | 58 +++++++++++++++---------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/confluent_server/confluent/neighutil.py b/confluent_server/confluent/neighutil.py index 90f85c12..9b9dc7c6 100644 --- a/confluent_server/confluent/neighutil.py +++ b/confluent_server/confluent/neighutil.py @@ -19,8 +19,9 @@ # use ip neigh for the moment import confluent.util as util -import eventlet.green.subprocess as subprocess import os +import eventlet.green.socket as socket +import struct neightable = {} neightime = 0 @@ -33,29 +34,40 @@ _validmac = re.compile('..:..:..:..:..:..') def update_neigh(): global neightable global neightime - neightable = {} - if os.name == 'nt': - return - ipn = subprocess.Popen(['ip', 'neigh'], stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (neighdata, err) = ipn.communicate() - neighdata = util.stringify(neighdata) - for entry in neighdata.split('\n'): - entry = entry.split(' ') - if len(entry) < 5 or not entry[4]: - continue - if entry[0] in ('192.168.0.100', '192.168.70.100', '192.168.70.125'): - # Note that these addresses are common static ip addresses - # that are hopelessly ambiguous if there are many - # so ignore such entries and move on - # ideally the system network steers clear of this landmine of - # a subnet, but just in case - continue - if not _validmac.match(entry[4]): - continue - neightable[entry[0]] = entry[4] neightime = os.times()[4] + s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE) + s.bind((0, 0)) + # RTM_GETNEIGH + nlhdr = b'\x1c\x00\x00\x00\x1e\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00' + ndmsg= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + s.sendall(nlhdr + ndmsg) + while True: + pdata = s.recv(65536) + v = memoryview(pdata) + if struct.unpack('H', v[4:6])[0] == 3: + break + while len(v): + length, typ = struct.unpack('IH', v[:6]) + if typ == 28: + hlen = struct.calcsize('BIHBB') + fam, idx, state, flags, typ = struct.unpack('BIHBB', v[16:16+hlen]) + if typ == 1: # only handle unicast entries + curraddr = None + currip = None + rta = v[16+hlen:length] + while len(rta): + rtalen, rtatyp = struct.unpack('HH', rta[:4]) + if rtatyp == 2: # hwaddr + hwlen = rtalen - 4 + curraddr = ':'.join(['{:02x}'.format(x) for x in bytearray(rta[4:rtalen].tobytes())]) + elif rtatyp == 1: # ip address + currip = socket.inet_ntop(fam, rta[4:rtalen].tobytes()) + rta = rta[rtalen:] + if not rtalen: + if curraddr and currip: + neightable[currip] = curraddr + break + v = v[length:] def refresh_neigh():