FP cache experiment

master
Mark Qvist 2026-08-25 01:41:02 +02:00
parent d044db2931
commit 2d2167140d
No known key found for this signature in database
1 changed files with 65 additions and 22 deletions

View File

@ -134,6 +134,7 @@ class Transport:
PATH_REQUEST_RG = 1.5 # Extra grace time for roaming-mode interfaces to allow more suitable peers to respond first
PATH_REQUEST_MI = 20 # Minimum interval in seconds for automated path requests
USE_FP_CACHE = True
USE_INBOUND_QUEUE = True
USE_OUTBOUND_QUEUE = False
INBOUND_DA_QUEUE_LENGTH = 4096
@ -173,6 +174,7 @@ class Transport:
# Notes on memory usage: 1 megabyte of memory can store approximately
# 55.100 path table entries or approximately 22.300 link table entries.
link_fp_cache = {}
announce_table = {} # A table for storing announces currently waiting to be retransmitted
path_table = {} # A lookup table containing the next hop to a given destination
reverse_table = {} # A lookup table for storing packet hashes used to return proofs and replies
@ -1795,6 +1797,34 @@ class Transport:
packet.receiving_interface = interface
packet.hops += 1
if Transport.USE_FP_CACHE:
fp_entry = Transport.link_fp_cache.get(packet.destination_hash, None)
if fp_entry:
fp_hops = packet.hops
if len(Transport.local_client_interfaces) > 0:
if Transport.is_local_client_interface(packet.receiving_interface): fp_hops -= 1
elif Transport.interface_to_shared_instance(packet.receiving_interface): fp_hops -= 1
if fp_entry[0] and (fp_hops == fp_entry[1] or fp_hops == fp_entry[2]): outbound_interface = fp_entry[3]
elif packet.receiving_interface == fp_entry[3] and fp_hops == fp_entry[1]: outbound_interface = fp_entry[4]
elif packet.receiving_interface == fp_entry[4] and fp_hops == fp_entry[2]: outbound_interface = fp_entry[3]
else: outbound_interface = None
if outbound_interface:
nhops = fp_hops if not fp_entry[5] or fp_entry[5] != outbound_interface else Transport.local_hops_delta
# RNS.log(f"{packet.receiving_interface} -> {outbound_interface} {nhops}")
Transport.add_packet_hash(packet.packet_hash)
new_raw = packet.raw[0:1]
new_raw += struct.pack("!B", nhops)
new_raw += packet.raw[2:]
Transport.transmit(outbound_interface, new_raw)
Transport.link_table[packet.destination_hash][IDX_LT_TIMESTAMP] = time.time()
# RNS.log(f"FP CACHE HIT", RNS.LOG_CRITICAL)
return
# else: RNS.log(f"FP CACHE MISS", RNS.LOG_CRITICAL)
# RNS.log(f"FP CACHE OUTBOUND MISS {packet.hops} {packet.receiving_interface}\n{fp_entry}")
# Ingress limit announces early
if packet.packet_type == RNS.Packet.ANNOUNCE:
if not tc: traffic_class = Transport.TC_ANNOUNCE
@ -2128,11 +2158,13 @@ class Transport:
# the same for this link, direction doesn't
# matter, and we simply repeat the packet.
outbound_interface = None
same_iface = False
if link_entry[IDX_LT_NH_IF] == link_entry[IDX_LT_RCVD_IF]:
# But check that taken hops matches one
# of the expectede values.
if packet.hops == link_entry[IDX_LT_REM_HOPS] or packet.hops == link_entry[IDX_LT_HOPS]:
outbound_interface = link_entry[IDX_LT_NH_IF]
same_iface = True
else:
# If interfaces differ, we transmit on
# the opposite interface of what the
@ -2158,6 +2190,18 @@ class Transport:
Transport.transmit(outbound_interface, new_raw)
Transport.link_table[packet.destination_hash][IDX_LT_TIMESTAMP] = time.time()
if Transport.USE_FP_CACHE and not packet.destination_hash in Transport.link_fp_cache:
if from_local_client and not instance_local_link and Transport.local_hops_delta != 0: mangle_to = outbound_interface
elif to_local_client and not instance_local_link and Transport.local_hops_delta != 0: mangle_to = link_entry[IDX_LT_NH_IF] if outbound_interface != link_entry[IDX_LT_NH_IF] else link_entry[IDX_LT_RCVD_IF]
else: mangle_to = None
RNS.log(f"MANGLING TO: {mangle_to}")
Transport.link_fp_cache[packet.destination_hash] = (same_iface, link_entry[IDX_LT_HOPS], link_entry[IDX_LT_REM_HOPS],
link_entry[IDX_LT_RCVD_IF], link_entry[IDX_LT_NH_IF],
mangle_to)
RNS.log(f"FP-CACHED {RNS.prettyhexrep(packet.destination_hash)}")
else:
RNS.log(f"No-outbound return on link packet from {packet.receiving_interface}", RNS.LOG_WARNING) # TODO: Remove
@ -2577,30 +2621,29 @@ class Transport:
# Handling for local data packets
elif packet.packet_type == RNS.Packet.DATA:
if packet.destination_type == RNS.Destination.LINK:
with Transport.active_links_lock:
link = Transport.active_links_map.get(packet.destination_hash)
if link != None:
if link.attached_interface == packet.receiving_interface:
packet.link = link
if packet.context == RNS.Packet.CACHE_REQUEST:
cached_packet = Transport.get_cached_packet(packet.data)
if cached_packet != None:
if not cached_packet.unpack(): return
RNS.Packet(destination=link, data=cached_packet.data,
packet_type=cached_packet.packet_type, context=cached_packet.context).send()
link = Transport.active_links_map.get(packet.destination_hash)
if link != None:
if link.attached_interface == packet.receiving_interface:
packet.link = link
if packet.context == RNS.Packet.CACHE_REQUEST:
cached_packet = Transport.get_cached_packet(packet.data)
if cached_packet != None:
if not cached_packet.unpack(): return
RNS.Packet(destination=link, data=cached_packet.data,
packet_type=cached_packet.packet_type, context=cached_packet.context).send()
else: link.receive(packet)
else: link.receive(packet)
else:
# In the strange and rare case that an interface
# is partly malfunctioning, and a link-associated
# packet is being received on an interface that
# has failed sending, and transport has failed over
# to another path, we remove this packet hash from
# the filter hashlist so the link can receive the
# packet when it finally arrives over another path.
while packet.packet_hash in Transport.packet_hashlist: Transport.packet_hashlist.remove(packet.packet_hash)
while packet.packet_hash in Transport.packet_hashlist_prev: Transport.packet_hashlist_prev.remove(packet.packet_hash)
else:
# In the strange and rare case that an interface
# is partly malfunctioning, and a link-associated
# packet is being received on an interface that
# has failed sending, and transport has failed over
# to another path, we remove this packet hash from
# the filter hashlist so the link can receive the
# packet when it finally arrives over another path.
while packet.packet_hash in Transport.packet_hashlist: Transport.packet_hashlist.remove(packet.packet_hash)
while packet.packet_hash in Transport.packet_hashlist_prev: Transport.packet_hashlist_prev.remove(packet.packet_hash)
else:
destination = None
with Transport.destinations_map_lock: