From a9da1fff283addf077152aa7784b01a1a238d873 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Wed, 21 Dec 2022 20:34:39 +0800 Subject: [PATCH] net/nat: Add auto reclaim logic for NAT entries. Signed-off-by: Zhe Weng --- net/nat/Kconfig | 14 +++++++++ net/nat/ipv4_nat_entry.c | 64 +++++++++++++++++++++++++++++++++++++--- net/nat/nat.h | 2 +- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/net/nat/Kconfig b/net/nat/Kconfig index db7f507e88..0adc09c537 100644 --- a/net/nat/Kconfig +++ b/net/nat/Kconfig @@ -53,3 +53,17 @@ config NET_NAT_ICMP_EXPIRE_SEC Note: The default value 60 is suggested by RFC5508, Section 3.2, Page 8. + +config NET_NAT_ENTRY_RECLAIM_SEC + int "The time to auto reclaim all expired entries" + default 3600 + depends on NET_NAT + ---help--- + The time to auto reclaim all expired entries. A value of zero will + disable auto reclaiming. + + Note: Expired entries will be automatically reclaimed when matching + inbound/outbound entries, so this config does not have significant + impact when NAT is normally used, but very useful when the hashtable + is big and there are only a few connections using NAT (which will + only trigger reclaiming on a few chains in hashtable). diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c index ce82811c5b..31e3badb58 100644 --- a/net/nat/ipv4_nat_entry.c +++ b/net/nat/ipv4_nat_entry.c @@ -352,6 +352,54 @@ static void ipv4_nat_entry_delete(FAR struct ipv4_nat_entry *entry) kmm_free(entry); } +/**************************************************************************** + * Name: ipv4_nat_reclaim_entry + * + * Description: + * Try reclaim all expired NAT entries. + * Only works after every CONFIG_NET_NAT_ENTRY_RECLAIM_SEC (low frequency). + * + * Although expired entries will be automatically reclaimed when matching + * inbound/outbound entries, there might be some situations that entries + * will be kept in memory, e.g. big hashtable with only a few connections. + * + * Assumptions: + * NAT is initialized. + * + ****************************************************************************/ + +#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0 +static void ipv4_nat_reclaim_entry(int32_t current_time) +{ + static int32_t next_reclaim_time = CONFIG_NET_NAT_ENTRY_RECLAIM_SEC; + + if (next_reclaim_time - current_time <= 0) + { + FAR hash_node_t *p; + FAR hash_node_t *tmp; + int count = 0; + int i; + + ninfo("INFO: Reclaiming all expired NAT entries.\n"); + + hashtable_for_every_safe(g_table_inbound, p, tmp, i) + { + FAR struct ipv4_nat_entry *entry = + container_of(p, struct ipv4_nat_entry, hash_inbound); + + if (entry->expire_time - current_time <= 0) + { + ipv4_nat_entry_delete(entry); + count++; + } + } + + ninfo("INFO: %d expired NAT entries reclaimed.\n", count); + next_reclaim_time = current_time + CONFIG_NET_NAT_ENTRY_RECLAIM_SEC; + } +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -378,7 +426,11 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port, { FAR hash_node_t *p; FAR hash_node_t *tmp; - uint32_t current_time = TICK2SEC(clock_systime_ticks()); + int32_t current_time = TICK2SEC(clock_systime_ticks()); + +#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0 + ipv4_nat_reclaim_entry(current_time); +#endif hashtable_for_every_possible_safe(g_table_inbound, p, tmp, ipv4_nat_inbound_key(external_port, protocol)) @@ -388,7 +440,7 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port, /* Remove expired entries. */ - if (entry->expire_time < current_time) + if (entry->expire_time - current_time <= 0) { ipv4_nat_entry_delete(entry); continue; @@ -437,7 +489,11 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, { FAR hash_node_t *p; FAR hash_node_t *tmp; - uint32_t current_time = TICK2SEC(clock_systime_ticks()); + int32_t current_time = TICK2SEC(clock_systime_ticks()); + +#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0 + ipv4_nat_reclaim_entry(current_time); +#endif hashtable_for_every_possible_safe(g_table_outbound, p, tmp, ipv4_nat_outbound_key(local_ip, local_port, protocol)) @@ -447,7 +503,7 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, /* Remove expired entries. */ - if (entry->expire_time < current_time) + if (entry->expire_time - current_time <= 0) { ipv4_nat_entry_delete(entry); continue; diff --git a/net/nat/nat.h b/net/nat/nat.h index f842af119a..c8b2d5c128 100644 --- a/net/nat/nat.h +++ b/net/nat/nat.h @@ -63,7 +63,7 @@ struct ipv4_nat_entry uint16_t external_port; /* The external port of local (private) host. */ uint8_t protocol; /* L4 protocol (TCP, UDP etc). */ - uint32_t expire_time; /* The expiration time of this entry. */ + int32_t expire_time; /* The expiration time of this entry. */ }; /* NAT IP/Port manipulate type, to indicate whether to manipulate source or