• David Ahern's avatar
    neighbor: Improve garbage collection · 58956317
    David Ahern authored
    The existing garbage collection algorithm has a number of problems:
    1. The gc algorithm will not evict PERMANENT entries as those entries
       are managed by userspace, yet the existing algorithm walks the entire
       hash table which means it always considers PERMANENT entries when
       looking for entries to evict. In some use cases (e.g., EVPN) there
       can be tens of thousands of PERMANENT entries leading to wasted
       CPU cycles when gc kicks in. As an example, with 32k permanent
       entries, neigh_alloc has been observed taking more than 4 msec per
    2. Currently, when the number of neighbor entries hits gc_thresh2 and
       the last flush for the table was more than 5 seconds ago gc kicks in
       walks the entire hash table evicting *all* entries not in PERMANENT
       or REACHABLE state and not marked as externally learned. There is no
       discriminator on when the neigh entry was created or if it just moved
       from REACHABLE to another NUD_VALID state (e.g., NUD_STALE).
       It is possible for entries to be created or for established neighbor
       entries to be moved to STALE (e.g., an external node sends an ARP
       request) right before the 5 second window lapses:
                t-5         t         t+5
       If that happens those entries are evicted during gc causing unnecessary
       thrashing on neighbor entries and userspace caches trying to track them.
       Further, this contradicts the description of gc_thresh2 which says
       "Entries older than 5 seconds will be cleared".
       One workaround is to make gc_thresh2 == gc_thresh3 but that negates the
       whole point of having separate thresholds.
    3. Clearing *all* neigh non-PERMANENT/REACHABLE/externally learned entries
       when gc_thresh2 is exceeded is over kill and contributes to trashing
       especially during startup.
    This patch addresses these problems as follows:
    1. Use of a separate list_head to track entries that can be garbage
       collected along with a separate counter. PERMANENT entries are not
       added to this list.
       The gc_thresh parameters are only compared to the new counter, not the
       total entries in the table. The forced_gc function is updated to only
       walk this new gc_list looking for entries to evict.
    2. Entries are added to the list head at the tail and removed from the
    3. Entries are only evicted if they were last updated more than 5 seconds
       ago, adhering to the original intent of gc_thresh2.
    4. Forced gc is stopped once the number of gc_entries drops below
    5. Since gc checks do not apply to PERMANENT entries, gc levels are skipped
       when allocating a new neighbor for a PERMANENT entry. By extension this
       means there are no explicit limits on the number of PERMANENT entries
       that can be created, but this is no different than FIB entries or FDB
    Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>