Inbound lookups find the (alias address, alias port, link type) group
with a splay tree and then walk grp->full, a list of every fully
specified link in that group, comparing the remote address and port.
With redirect_addr in front of a busy server, every client connection
to public:443 lands in the same group, so each inbound packet that is
not near the head of the list walks all of it. TCP links live up to
24 hours unless libalias sees a clean close, so the list can grow to
hundreds of thousands of entries and saturate a core at a few hundred
packets per second.
Keep the fully specified links of a group in an RB tree ordered by
(dst_addr, dst_port). Links that share an endpoint are ordered newest
first by a per-instance insertion counter, which keeps the "most recent
link wins" behaviour of the list (tested by 3_natin:2_portoverlap).
The counter is appended at the end of struct libalias because ipfw_nat
and ng_nat access fields of that structure directly.
Lookups with an unknown remote address and a known port still scan the
group. Each link grows by 16 bytes.
With ~170,000 links in one group, LibAliasIn() took 1-2 ms per packet
and one core saturated at ~720 packets/s. With this change it takes
2-4 us per packet and the offered 1,000 packets/s are handled with the
thread nearly idle.
Sponsored by: NLINK