diff --git a/cfgmgr/natmgr.cpp b/cfgmgr/natmgr.cpp index 4c78d20e8e1b..e8aa07f73b3d 100644 --- a/cfgmgr/natmgr.cpp +++ b/cfgmgr/natmgr.cpp @@ -26,6 +26,7 @@ #include "warm_restart.h" #include "ipaddress.h" #include "ipprefix.h" +#include "notifier.h" using namespace std; using namespace swss; @@ -37,6 +38,8 @@ NatMgr::NatMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, con m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME), m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME), m_stateInterfaceTable(stateDb, STATE_INTERFACE_TABLE_NAME), + m_stateWarmRestartEnableTable(stateDb, STATE_WARM_RESTART_ENABLE_TABLE_NAME), + m_stateWarmRestartTable(stateDb, STATE_WARM_RESTART_TABLE_NAME), m_appNatTableProducer(appDb, APP_NAT_TABLE_NAME), m_appNaptTableProducer(appDb, APP_NAPT_TABLE_NAME), m_appTwiceNatTableProducer(appDb, APP_NAT_TWICE_TABLE_NAME), @@ -68,7 +71,12 @@ NatMgr::NatMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, con SWSS_LOG_ERROR("Command '%s' failed", cmds.c_str()); } - flushNotifier = std::make_shared(appDb, "FLUSHNATREQUEST"); + /* Start the timer to refresh static conntrack entries for every 1 day (86400) */ + SWSS_LOG_INFO("Start the NAT Refresh Timer "); + auto refresh_interval = timespec { .tv_sec = NAT_ENTRY_REFRESH_PERIOD, .tv_nsec = 0 }; + m_natRefreshTimer = new SelectableTimer(refresh_interval); + auto refresh_executor = new ExecutableTimer(m_natRefreshTimer, this, "NAT_ENTRY_REFRESH_TIMER"); + Orch::addExecutor(refresh_executor); } /* To check the port init id done or not */ @@ -327,26 +335,152 @@ void NatMgr::setNaptPoolIpTable(const string &opCmd, const string &ip_range, con } } +/* To check warmboot in progress */ +bool NatMgr::warmBootingInProgress(void) +{ + std::string value; + + m_stateWarmRestartEnableTable.hget("system", "enable", value); + if (value == "true") + { + SWSS_LOG_INFO("Warm reboot enabled"); + m_stateWarmRestartTable.hget("natsyncd", "state", value); + if (value != "reconciled") + { + SWSS_LOG_NOTICE("Nat conntrack state reconciliation not completed yet"); + return true; + } + return false; + } + else + { + SWSS_LOG_INFO("Warm reboot not enabled"); + } + return false; +} + +/* To flush all NAT entries */ +void NatMgr::flushAllNatEntries(void) +{ + std::string res; + const std::string cmds = std::string("") + CONNTRACK_CMD + FLUSH; + int ret = swss::exec(cmds, res); + + if (ret) + { + SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); + } + else + { + SWSS_LOG_INFO("Cleared the All NAT Entries"); + } +} + +/* To Update a conntrack entry for the Dynamic Single NAT entry in the kernel */ +void NatMgr::updateDynamicSingleNatConnTrackTimeout(string key, int timeout) +{ + std::string res; + std::string cmds = std::string("") + CONNTRACK_CMD; + IpAddress ip_address = IpAddress(key); + + cmds += (" -U -s " + ip_address.to_string() + " -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); + int ret = swss::exec(cmds, res); + + if (ret) + { + SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); + } + else + { + SWSS_LOG_INFO("Updated the active NAT conntrack entry with src-ip %s, timeout %u", + ip_address.to_string().c_str(), timeout); + } +} + +/* To Update a conntrack entry for the Dynamic Single NAPT entry in the kernel */ +void NatMgr::updateDynamicSingleNaptConnTrackTimeout(string key, int timeout) +{ + std::string res; + vector keys = tokenize(key, ':'); + IpAddress ip_address = IpAddress(keys[1]); + int l4_port = stoi(keys[2]); + string prototype = ((keys[0] == string("TCP")) ? "tcp" : "udp"); + std::string cmds = std::string("") + CONNTRACK_CMD; + + cmds += (" -U -s " + ip_address.to_string() + " -p " + prototype + " --orig-port-src " + to_string(l4_port) + " -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); + int ret = swss::exec(cmds, res); + + if (ret) + { + SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); + } + else + { + SWSS_LOG_INFO("Updated active NAPT conntrack entry with protocol %s, src-ip %s, src-port %d, timeout %u", + prototype.c_str(), ip_address.to_string().c_str(), l4_port, timeout); + } +} + +/* To Update a conntrack entry for the Dynamic Twice NAT entry in the kernel */ +void NatMgr::updateDynamicTwiceNatConnTrackTimeout(string key, int timeout) +{ + std::string res; + std::string cmd = std::string("") + CONNTRACK_CMD; + vector keys = tokenize(key, ':'); + IpAddress src_ip = IpAddress(keys[1]); + IpAddress dst_ip = IpAddress(keys[1]); + + cmd += (" -U -s " + src_ip.to_string() + " -d " + dst_ip.to_string() + " -t " + std::to_string(timeout) + REDIRECT_TO_DEV_NULL); + + swss::exec(cmd, res); + + SWSS_LOG_INFO("Updated active Twice NAT conntrack entry with src-ip %s, dst-ip %s, timeout %u", + src_ip.to_string().c_str(), dst_ip.to_string().c_str(), timeout); +} + +/* To Update a conntrack entry for the Dynamic Twice NAPT entry in the kernel */ +void NatMgr::updateDynamicTwiceNaptConnTrackTimeout(string key, int timeout) +{ + std::string res; + std::string cmd = std::string("") + CONNTRACK_CMD; + vector keys = tokenize(key, ':'); + IpAddress src_ip = IpAddress(keys[1]); + int src_l4_port = stoi(keys[2]); + IpAddress dst_ip = IpAddress(keys[3]); + int dst_l4_port = stoi(keys[4]); + string prototype = ((keys[0] == string("TCP")) ? "tcp" : "udp"); + + cmd += (" -U -s " + src_ip.to_string() + " -p " + prototype + " --orig-port-src " + to_string(src_l4_port) + + " -d " + dst_ip.to_string() + " --orig-port-dst " + std::to_string(dst_l4_port) + + " -t " + std::to_string(timeout) + REDIRECT_TO_DEV_NULL); + + swss::exec(cmd, res); + + SWSS_LOG_INFO("Updated active Twice NAPT conntrack entry with protocol %s, src-ip %s, src-port %d, dst-ip %s, dst-port %d, timeout %u", + prototype.c_str(), src_ip.to_string().c_str(), src_l4_port, dst_ip.to_string().c_str(), dst_l4_port, timeout); +} + /* To Add a dummy conntrack entry for the Static Single NAT entry in the kernel */ -void NatMgr::addConntrackSingleNatEntry(const string &key) +void NatMgr::addConntrackStaticSingleNatEntry(const string &key) { std::string res, cmds = std::string("") + CONNTRACK_CMD; + int timeout = NAT_TIMEOUT_MAX; if (m_staticNatEntry[key].nat_type == DNAT_NAT_TYPE) { SWSS_LOG_INFO("Add static NAT conntrack entry with src-ip %s, timeout %d", - m_staticNatEntry[key].local_ip.c_str(), m_natTimeout); + m_staticNatEntry[key].local_ip.c_str(), timeout); - cmds += (" -I -n " + key + ":1 -g 127.0.0.1:127" + " -p udp -t " + to_string(m_natTimeout) + - " --src " + m_staticNatEntry[key].local_ip + " --sport 1 --dst 127.0.0.1 --dport 127 -u ASSURED "); + cmds += (" -I -n " + key + ":1 -g 127.0.0.1:127" + " -p udp -t " + to_string(timeout) + + " --src " + m_staticNatEntry[key].local_ip + " --sport 1 --dst 127.0.0.1 --dport 127 -u ASSURED " + REDIRECT_TO_DEV_NULL); } else if (m_staticNatEntry[key].nat_type == SNAT_NAT_TYPE) { SWSS_LOG_INFO("Add static NAT conntrack entry with src-ip %s, timeout %d", - key.c_str(), m_natTimeout); + key.c_str(), timeout); - cmds += (" -I -n " + m_staticNatEntry[key].local_ip + ":1 -g 127.0.0.1:127" + " -p udp -t " + to_string(m_natTimeout) + - " --src " + key + " --sport 1 --dst 127.0.0.1 --dport 127 -u ASSURED "); + cmds += (" -I -n " + m_staticNatEntry[key].local_ip + ":1 -g 127.0.0.1:127" + " -p udp -t " + to_string(timeout) + + " --src " + key + " --sport 1 --dst 127.0.0.1 --dport 127 -u ASSURED " + REDIRECT_TO_DEV_NULL); } int ret = swss::exec(cmds, res); @@ -362,16 +496,17 @@ void NatMgr::addConntrackSingleNatEntry(const string &key) } /* To Add a dummy conntrack entry for the Static Twice NAT entry in the kernel */ -void NatMgr::addConntrackTwiceNatEntry(const string &snatKey, const string &dnatKey) +void NatMgr::addConntrackStaticTwiceNatEntry(const string &snatKey, const string &dnatKey) { std::string res, cmds = std::string("") + CONNTRACK_CMD; + int timeout = NAT_TIMEOUT_MAX; SWSS_LOG_INFO("Add static Twice NAT conntrack entry with src-ip %s, dst-ip %s, timeout %u", - snatKey.c_str(), dnatKey.c_str(), m_natTimeout); + snatKey.c_str(), dnatKey.c_str(), timeout); cmds += (" -I -n " + m_staticNatEntry[snatKey].local_ip + ":1" + " -g " + m_staticNatEntry[dnatKey].local_ip + ":1" - + " -p udp" + " -t " + to_string(m_natTimeout) + " --src " + snatKey + " --sport 1" + " --dst " + dnatKey - + " --dport 1" + " -u ASSURED "); + + " -p udp" + " -t " + to_string(timeout) + " --src " + snatKey + " --sport 1" + " --dst " + dnatKey + + " --dport 1" + " -u ASSURED " + REDIRECT_TO_DEV_NULL); int ret = swss::exec(cmds, res); @@ -387,22 +522,20 @@ void NatMgr::addConntrackTwiceNatEntry(const string &snatKey, const string &dnat /* To Add a dummy conntrack entry for the Static NAPT entry in the kernel, * so that the port number is reserved and the same port is not allocated by the stack for any other dynamic entry */ -void NatMgr::addConntrackSingleNaptEntry(const string &key) +void NatMgr::addConntrackStaticSingleNaptEntry(const string &key) { - int timeout = 0; + int timeout = NAT_TIMEOUT_MAX; std::string res, prototype, state, cmds = std::string("") + CONNTRACK_CMD; vector keys = tokenize(key, config_db_key_delimiter); if (keys[1] == to_upper(IP_PROTOCOL_UDP)) { prototype = IP_PROTOCOL_UDP; - timeout = m_natUdpTimeout; state = ""; } else if (keys[1] == to_upper(IP_PROTOCOL_TCP)) { prototype = IP_PROTOCOL_TCP; - timeout = m_natTcpTimeout; state = " --state ESTABLISHED "; } @@ -413,7 +546,8 @@ void NatMgr::addConntrackSingleNaptEntry(const string &key) prototype.c_str(), m_staticNaptEntry[key].local_ip.c_str(), m_staticNaptEntry[key].local_port.c_str(), timeout); cmds += (" -I -n " + keys[0] + ":" + keys[2] + " -g 127.0.0.1:127" + " -p " + prototype + " -t " + to_string(timeout) + - " --src " + m_staticNaptEntry[key].local_ip + " --sport " + m_staticNaptEntry[key].local_port + " --dst 127.0.0.1 --dport 127 -u ASSURED " + state); + " --src " + m_staticNaptEntry[key].local_ip + " --sport " + m_staticNaptEntry[key].local_port + " --dst 127.0.0.1 --dport 127 -u ASSURED " + + state + REDIRECT_TO_DEV_NULL); } else if (m_staticNaptEntry[key].nat_type == SNAT_NAT_TYPE) { @@ -421,7 +555,7 @@ void NatMgr::addConntrackSingleNaptEntry(const string &key) prototype.c_str(), keys[0].c_str(), keys[2].c_str(), timeout); cmds += (" -I -n " + m_staticNaptEntry[key].local_ip + ":" + m_staticNaptEntry[key].local_port + " -g 127.0.0.1:127" + " -p " + prototype + " -t " + to_string(timeout) + - " --src " + keys[0] + " --sport " + keys[2] + " --dst 127.0.0.1 --dport 127 -u ASSURED " + state); + " --src " + keys[0] + " --sport " + keys[2] + " --dst 127.0.0.1 --dport 127 -u ASSURED " + state + REDIRECT_TO_DEV_NULL); } int ret = swss::exec(cmds, res); @@ -437,9 +571,9 @@ void NatMgr::addConntrackSingleNaptEntry(const string &key) } /* To Add a dummy conntrack entry for the Static Twice NAPT entry in the kernel */ -void NatMgr::addConntrackTwiceNaptEntry(const string &snatKey, const string &dnatKey) +void NatMgr::addConntrackStaticTwiceNaptEntry(const string &snatKey, const string &dnatKey) { - int timeout = 0; + int timeout = NAT_TIMEOUT_MAX; std::string res, prototype, state, cmds = std::string("") + CONNTRACK_CMD; vector snatKeys = tokenize(snatKey, config_db_key_delimiter); vector dnatKeys = tokenize(dnatKey, config_db_key_delimiter); @@ -447,13 +581,11 @@ void NatMgr::addConntrackTwiceNaptEntry(const string &snatKey, const string &dna if (snatKeys[1] == to_upper(IP_PROTOCOL_UDP)) { prototype = IP_PROTOCOL_UDP; - timeout = m_natUdpTimeout; state = ""; } else if (snatKeys[1] == to_upper(IP_PROTOCOL_TCP)) { prototype = IP_PROTOCOL_TCP; - timeout = m_natTcpTimeout; state = " --state ESTABLISHED "; } @@ -462,7 +594,8 @@ void NatMgr::addConntrackTwiceNaptEntry(const string &snatKey, const string &dna cmds += (" -I -n " + m_staticNaptEntry[snatKey].local_ip + ":" + m_staticNaptEntry[snatKey].local_port + " -g " + m_staticNaptEntry[dnatKey].local_ip + ":" + m_staticNaptEntry[dnatKey].local_port + " -p " + prototype + " -t " + to_string(timeout) - + " --src " + snatKeys[0] + " --sport " + snatKeys[2] + " --dst " + dnatKeys[0] + " --dport " + dnatKeys[2] + " -u ASSURED " + state); + + " --src " + snatKeys[0] + " --sport " + snatKeys[2] + " --dst " + dnatKeys[0] + " --dport " + dnatKeys[2] + " -u ASSURED " + + state + REDIRECT_TO_DEV_NULL); int ret = swss::exec(cmds, res); @@ -476,8 +609,108 @@ void NatMgr::addConntrackTwiceNaptEntry(const string &snatKey, const string &dna } } +/* To Update a dummy conntrack entry for the Static Single NAT entry in the kernel */ +void NatMgr::updateConntrackStaticSingleNatEntry(const string &key) +{ + std::string res, cmds = std::string("") + CONNTRACK_CMD; + int timeout = NAT_TIMEOUT_MAX; + + if (m_staticNatEntry[key].nat_type == DNAT_NAT_TYPE) + { + SWSS_LOG_INFO("Update static NAT conntrack entry with src-ip %s, timeout %d", + m_staticNatEntry[key].local_ip.c_str(), timeout); + + cmds += (" -U --src " + m_staticNatEntry[key].local_ip + " -p udp -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); + } + else if (m_staticNatEntry[key].nat_type == SNAT_NAT_TYPE) + { + SWSS_LOG_INFO("Update static NAT conntrack entry with src-ip %s, timeout %d", + key.c_str(), timeout); + + cmds += (" -U --src " + key + " -p udp -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); + } + + swss::exec(cmds, res); +} + +/* To Update a dummy conntrack entry for the Static Twice NAT entry in the kernel */ +void NatMgr::updateConntrackStaticTwiceNatEntry(const string &snatKey, const string &dnatKey) +{ + std::string res, cmds = std::string("") + CONNTRACK_CMD; + int timeout = NAT_TIMEOUT_MAX; + + SWSS_LOG_INFO("Update static Twice NAT conntrack entry with src-ip %s, dst-ip %s, timeout %u", + snatKey.c_str(), dnatKey.c_str(), timeout); + + cmds += (" -U --src " + snatKey + " -p udp -t " + to_string(timeout) + " --dst " + dnatKey + REDIRECT_TO_DEV_NULL); + + swss::exec(cmds, res); +} + +/* To update a dummy conntrack entry for the Static NAPT entry in the kernel */ +void NatMgr::updateConntrackStaticSingleNaptEntry(const string &key) +{ + int timeout = NAT_TIMEOUT_MAX; + std::string res, prototype, cmds = std::string("") + CONNTRACK_CMD; + vector keys = tokenize(key, config_db_key_delimiter); + + if (keys[1] == to_upper(IP_PROTOCOL_UDP)) + { + prototype = IP_PROTOCOL_UDP; + } + else if (keys[1] == to_upper(IP_PROTOCOL_TCP)) + { + prototype = IP_PROTOCOL_TCP; + } + + if (m_staticNaptEntry[key].nat_type == DNAT_NAT_TYPE) + { + + SWSS_LOG_INFO("Update static NAPT conntrack entry with protocol %s, src-ip %s, src-port %s, timeout %d", + prototype.c_str(), m_staticNaptEntry[key].local_ip.c_str(), m_staticNaptEntry[key].local_port.c_str(), timeout); + + cmds += (" -U --src " + m_staticNaptEntry[key].local_ip + " -p " + prototype + " --sport " + m_staticNaptEntry[key].local_port + " -t " + + to_string(timeout) + REDIRECT_TO_DEV_NULL); + } + else if (m_staticNaptEntry[key].nat_type == SNAT_NAT_TYPE) + { + SWSS_LOG_INFO("Update static NAPT conntrack entry with protocol %s, src-ip %s, src-port %s, timeout %d", + prototype.c_str(), keys[0].c_str(), keys[2].c_str(), timeout); + + cmds += (" -U --src " + keys[0] + " -p " + prototype + " --sport " + keys[2] + " -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); + } + + swss::exec(cmds, res); +} + +/* To Update a dummy conntrack entry for the Static Twice NAPT entry in the kernel */ +void NatMgr::updateConntrackStaticTwiceNaptEntry(const string &snatKey, const string &dnatKey) +{ + int timeout = NAT_TIMEOUT_MAX; + std::string res, prototype, cmds = std::string("") + CONNTRACK_CMD; + vector snatKeys = tokenize(snatKey, config_db_key_delimiter); + vector dnatKeys = tokenize(dnatKey, config_db_key_delimiter); + + if (snatKeys[1] == to_upper(IP_PROTOCOL_UDP)) + { + prototype = IP_PROTOCOL_UDP; + } + else if (snatKeys[1] == to_upper(IP_PROTOCOL_TCP)) + { + prototype = IP_PROTOCOL_TCP; + } + + SWSS_LOG_DEBUG("Update static Twice NAPT conntrack entry with protocol %s, src-ip %s, src-port %s, dst-ip %s, dst-port %s, timeout %u", + prototype.c_str(), snatKeys[0].c_str(), snatKeys[2].c_str(), dnatKeys[0].c_str(), dnatKeys[2].c_str(), timeout); + + cmds += (" -U --src " + snatKeys[0] + " --dst " + dnatKeys[0] + " -p udp " + " --sport " + snatKeys[2] + " --dport " + dnatKeys[2] + + " -p udp -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); + + swss::exec(cmds, res); +} + /* To Delete conntrack entry for Static Single NAT entry */ -void NatMgr::deleteConntrackSingleNatEntry(const string &key) +void NatMgr::deleteConntrackStaticSingleNatEntry(const string &key) { std::string res, cmds = std::string("") + CONNTRACK_CMD; @@ -485,13 +718,13 @@ void NatMgr::deleteConntrackSingleNatEntry(const string &key) { SWSS_LOG_INFO("Delete static NAT conntrack entry with src-ip %s", m_staticNatEntry[key].local_ip.c_str()); - cmds += (" -D -s " + m_staticNatEntry[key].local_ip + " -p udp" + " &> /dev/null"); + cmds += (" -D -s " + m_staticNatEntry[key].local_ip + " -p udp" + REDIRECT_TO_DEV_NULL); } else if (m_staticNatEntry[key].nat_type == SNAT_NAT_TYPE) { SWSS_LOG_INFO("Delete static NAT conntrack entry with src-ip %s", key.c_str()); - cmds += (" -D -s " + key + " -p udp" + " &> /dev/null"); + cmds += (" -D -s " + key + " -p udp" + REDIRECT_TO_DEV_NULL); } int ret = swss::exec(cmds, res); @@ -507,13 +740,13 @@ void NatMgr::deleteConntrackSingleNatEntry(const string &key) } /* To Delete conntrack entry for Static Twice NAT entry */ -void NatMgr::deleteConntrackTwiceNatEntry(const string &snatKey, const string &dnatKey) +void NatMgr::deleteConntrackStaticTwiceNatEntry(const string &snatKey, const string &dnatKey) { std::string res, cmds = std::string("") + CONNTRACK_CMD; SWSS_LOG_INFO("Delete static Twice NAT conntrack entry with src-ip %s and dst-ip %s", snatKey.c_str(), dnatKey.c_str()); - cmds += (" -D -s " + snatKey + " -d " + dnatKey + " &> /dev/null"); + cmds += (" -D -s " + snatKey + " -d " + dnatKey + REDIRECT_TO_DEV_NULL); int ret = swss::exec(cmds, res); @@ -528,7 +761,7 @@ void NatMgr::deleteConntrackTwiceNatEntry(const string &snatKey, const string &d } /* To Delete conntrack entry for Static Single NAPT entry */ -void NatMgr::deleteConntrackSingleNaptEntry(const string &key) +void NatMgr::deleteConntrackStaticSingleNaptEntry(const string &key) { std::string res, prototype, cmds = std::string("") + CONNTRACK_CMD; vector keys = tokenize(key, config_db_key_delimiter); @@ -547,14 +780,14 @@ void NatMgr::deleteConntrackSingleNaptEntry(const string &key) SWSS_LOG_INFO("Delete static NAPT conntrack entry with protocol %s, src-ip %s, src-port %s", prototype.c_str(), m_staticNaptEntry[key].local_ip.c_str(), m_staticNaptEntry[key].local_port.c_str()); - cmds += (" -D -s " + m_staticNaptEntry[key].local_ip + " -p " + prototype + " --sport " + m_staticNaptEntry[key].local_port + " &> /dev/null"); + cmds += (" -D -s " + m_staticNaptEntry[key].local_ip + " -p " + prototype + " --sport " + m_staticNaptEntry[key].local_port + REDIRECT_TO_DEV_NULL); } else if (m_staticNaptEntry[key].nat_type == SNAT_NAT_TYPE) { SWSS_LOG_INFO("Delete static NAPT conntrack entry with protocol %s, src-ip %s, src-port %s", prototype.c_str(), keys[0].c_str(), keys[2].c_str()); - cmds += (" -D -s " + keys[0] + " -p " + prototype + " --sport " + keys[2] + " &> /dev/null"); + cmds += (" -D -s " + keys[0] + " -p " + prototype + " --sport " + keys[2] + REDIRECT_TO_DEV_NULL); } int ret = swss::exec(cmds, res); @@ -570,7 +803,7 @@ void NatMgr::deleteConntrackSingleNaptEntry(const string &key) } /* To Delete conntrack entry for Static Twice NAPT entry */ -void NatMgr::deleteConntrackTwiceNaptEntry(const string &snatKey, const string &dnatKey) +void NatMgr::deleteConntrackStaticTwiceNaptEntry(const string &snatKey, const string &dnatKey) { std::string res, prototype, cmds = std::string("") + CONNTRACK_CMD; vector snatKeys = tokenize(snatKey, config_db_key_delimiter); @@ -588,7 +821,7 @@ void NatMgr::deleteConntrackTwiceNaptEntry(const string &snatKey, const string & SWSS_LOG_INFO("Delete static Twice NAPT conntrack entry with protocol %s, src-ip %s, src-port %s, dst-ip %s, dst-port %s", prototype.c_str(), snatKeys[0].c_str(), snatKeys[2].c_str(), dnatKeys[0].c_str(), dnatKeys[2].c_str()); - cmds += (" -D -s " + snatKeys[0] + " -p " + prototype + " --orig-port-src " + snatKeys[2] + " -d " + dnatKeys[0] + " --orig-port-dst " + dnatKeys[2] + " &> /dev/null"); + cmds += (" -D -s " + snatKeys[0] + " -p " + prototype + " --orig-port-src " + snatKeys[2] + " -d " + dnatKeys[0] + " --orig-port-dst " + dnatKeys[2] + REDIRECT_TO_DEV_NULL); int ret = swss::exec(cmds, res); @@ -640,7 +873,7 @@ void NatMgr::deleteConntrackDynamicEntries(const string &ip_range) SWSS_LOG_INFO("Delete dynamic conntrack entry with translated-src-ip %s", ipAddr); - cmds = (std::string("") + CONNTRACK_CMD + " -D -q " + ipAddrString + " &> /dev/null"); + cmds = (std::string("") + CONNTRACK_CMD + " -D -q " + ipAddrString + REDIRECT_TO_DEV_NULL); int ret = swss::exec(cmds, res); @@ -1733,7 +1966,7 @@ void NatMgr::addStaticSingleNatEntry(const string &key) SWSS_LOG_INFO("Added Static NAT %s to APPL_DB", key.c_str()); /* Add a dummy conntrack entry for Static NAT entry */ - addConntrackSingleNatEntry(key); + addConntrackStaticSingleNatEntry(key); /* Add Static NAT iptables rule */ if (!setStaticNatIptablesRules(INSERT, interface, key, m_staticNatEntry[key].local_ip, m_staticNatEntry[key].nat_type)) @@ -1847,12 +2080,12 @@ void NatMgr::addStaticTwiceNatEntry(const string &key) if (((*it).second.nat_type == DNAT_NAT_TYPE) and (m_staticNatEntry[key].nat_type == SNAT_NAT_TYPE)) { - addConntrackTwiceNatEntry(key, (*it).first); + addConntrackStaticTwiceNatEntry(key, (*it).first); } else if (((*it).second.nat_type == SNAT_NAT_TYPE) and (m_staticNatEntry[key].nat_type == DNAT_NAT_TYPE)) { - addConntrackTwiceNatEntry((*it).first, key); + addConntrackStaticTwiceNatEntry((*it).first, key); } /* Add Static NAT iptables rule */ @@ -2023,10 +2256,10 @@ void NatMgr::addStaticSingleNaptEntry(const string &key) SWSS_LOG_INFO("Added Static NAPT %s to APPL_DB", key.c_str()); /* Delete any conntrack entry if exists */ - deleteConntrackSingleNaptEntry(key); + deleteConntrackStaticSingleNaptEntry(key); /* Add a dummy conntrack entry for Static NAPT entry */ - addConntrackSingleNaptEntry(key); + addConntrackStaticSingleNaptEntry(key); /* Add Static NAPT iptables rule */ if (!setStaticNaptIptablesRules(INSERT, interface, prototype, keys[0], keys[2], @@ -2177,19 +2410,19 @@ void NatMgr::addStaticTwiceNaptEntry(const string &key) (m_staticNaptEntry[key].nat_type == SNAT_NAT_TYPE)) { /* Delete any conntrack entry if exists */ - deleteConntrackTwiceNaptEntry(key, (*it).first); + deleteConntrackStaticTwiceNaptEntry(key, (*it).first); /* Add a dummy conntrack entry for Static Twice NAPT entry */ - addConntrackTwiceNaptEntry(key, (*it).first); + addConntrackStaticTwiceNaptEntry(key, (*it).first); } else if (((*it).second.nat_type == SNAT_NAT_TYPE) and (m_staticNaptEntry[key].nat_type == DNAT_NAT_TYPE)) { /* Delete any conntrack entry if exists */ - deleteConntrackTwiceNaptEntry((*it).first, key); + deleteConntrackStaticTwiceNaptEntry((*it).first, key); /* Add a dummy conntrack entry for Static Twice NAPT entry */ - addConntrackTwiceNaptEntry((*it).first, key); + addConntrackStaticTwiceNaptEntry((*it).first, key); } /* Add Static NAPT iptables rule */ @@ -2333,7 +2566,7 @@ void NatMgr::removeStaticSingleNatEntry(const string &key) } /* Delete conntrack entry */ - deleteConntrackSingleNatEntry(key); + deleteConntrackStaticSingleNatEntry(key); /* Delete it from APPL_DB */ m_appNatTableProducer.del(appKeyDnat); @@ -2445,13 +2678,13 @@ void NatMgr::removeStaticTwiceNatEntry(const string &key) (m_staticNatEntry[key].nat_type == SNAT_NAT_TYPE)) { /* Delete any conntrack entry */ - deleteConntrackTwiceNatEntry(key, (*it).first); + deleteConntrackStaticTwiceNatEntry(key, (*it).first); } else if (((*it).second.nat_type == SNAT_NAT_TYPE) and (m_staticNatEntry[key].nat_type == DNAT_NAT_TYPE)) { /* Delete any conntrack entry */ - deleteConntrackTwiceNatEntry((*it).first, key); + deleteConntrackStaticTwiceNatEntry((*it).first, key); } /* Delete it from APPL_DB */ @@ -2620,7 +2853,7 @@ void NatMgr::removeStaticSingleNaptEntry(const string &key) } /* Delete conntrack entry */ - deleteConntrackSingleNaptEntry(key); + deleteConntrackStaticSingleNaptEntry(key); /* Delete it from APPL_DB */ m_appNaptTableProducer.del(appKeyDnat); @@ -2760,13 +2993,13 @@ void NatMgr::removeStaticTwiceNaptEntry(const string &key) (m_staticNaptEntry[key].nat_type == SNAT_NAT_TYPE)) { /* Delete any conntrack entry */ - deleteConntrackTwiceNaptEntry(key, (*it).first); + deleteConntrackStaticTwiceNaptEntry(key, (*it).first); } else if (((*it).second.nat_type == SNAT_NAT_TYPE) and (m_staticNaptEntry[key].nat_type == DNAT_NAT_TYPE)) { /* Delete any conntrack entry */ - deleteConntrackTwiceNaptEntry((*it).first, key); + deleteConntrackStaticTwiceNaptEntry((*it).first, key); } /* Delete it from APPL_DB */ @@ -3852,6 +4085,255 @@ void NatMgr::removeStaticTwiceNaptIptables(const string &key) } } +/* To set conntrack for the Static NAT entries */ +void NatMgr::setStaticNatConntrackEntries(string mode) +{ + bool isEntryModified = false; + + /* Check the NAT is enabled, otherwise return */ + if (!isNatEnabled()) + { + SWSS_LOG_INFO("NAT is not yet enabled, skipping modfiying NAT conntrack entries"); + return; + } + + /* Get all the Static NAT entries */ + for (auto it = m_staticNatEntry.begin(); it != m_staticNatEntry.end(); it++) + { + /* Check interface is not None, otherwise continue */ + if ((*it).second.interface == NONE_STRING) + { + continue; + } + + isEntryModified = true; + + if ((*it).second.twice_nat_id.empty()) + { + /* Set the conntrack for Static Single NAT Entry */ + setStaticSingleNatConntrackEntry((*it).first, mode); + } + else if (((*it).second.twice_nat_added == true)) + { + /* Set the conntrack for Static Twice NAT entry */ + setStaticTwiceNatConntrackEntry((*it).first, mode); + } + } + + if (!isEntryModified) + { + SWSS_LOG_INFO("No Static NAT entries to modify"); + } +} + +/* To set conntrack for the Static Single NAT entry based on Key */ +void NatMgr::setStaticSingleNatConntrackEntry(const string &key, string &mode) +{ + if (mode == "UPDATE") + { + updateConntrackStaticSingleNatEntry(key); + } + else if (mode == "ADD") + { + addConntrackStaticSingleNatEntry(key); + } +} + +/* To set conntrack for the Static Twice NAT entry based on Key */ +void NatMgr::setStaticTwiceNatConntrackEntry(const string &key, string &mode) +{ + /* Get all the Static NAT entries */ + for (auto it = m_staticNatEntry.begin(); it != m_staticNatEntry.end(); it++) + { + vector fvVector, reversefvVector; + + /* Check for other entries, otherwise continue */ + if ((*it).first == key) + { + continue; + } + + /* Check the twice_nat_id is matched, otherwise continue */ + if ((*it).second.twice_nat_id != m_staticNatEntry[key].twice_nat_id) + { + continue; + } + + /* Check the twice NAT is added, otherwise continue */ + if ((!(*it).second.twice_nat_added) or (!m_staticNatEntry[key].twice_nat_added)) + { + continue; + } + + /* Check interface is assigned, means Entry is added, otherwise continue */ + if (((*it).second.interface == NONE_STRING) or (m_staticNatEntry[key].interface == NONE_STRING)) + { + continue; + } + + /* Check the nat type is different, otherwise continue */ + if ((*it).second.nat_type == m_staticNatEntry[key].nat_type) + { + continue; + } + + /* Update a dummy conntrack entry for Static Twice NAT entry */ + if (((*it).second.nat_type == DNAT_NAT_TYPE) and + (m_staticNatEntry[key].nat_type == SNAT_NAT_TYPE)) + { + if (mode == "UPDATE") + { + updateConntrackStaticTwiceNatEntry(key, (*it).first); + } + else if (mode == "ADD") + { + addConntrackStaticTwiceNatEntry(key, (*it).first); + } + } + else if (((*it).second.nat_type == SNAT_NAT_TYPE) and + (m_staticNatEntry[key].nat_type == DNAT_NAT_TYPE)) + { + if (mode == "UPDATE") + { + updateConntrackStaticTwiceNatEntry((*it).first, key); + } + else if (mode == "ADD") + { + addConntrackStaticTwiceNatEntry((*it).first, key); + } + } + break; + } +} + +/* To set the conntrack for Static NAPT entries */ +void NatMgr::setStaticNaptConntrackEntries(string mode) +{ + bool isEntryModified = false; + + /* Check the NAT is enabled, otherwise return */ + if (!isNatEnabled()) + { + SWSS_LOG_INFO("NAT is not yet enabled, skipping modifying NAPT conntrack entries"); + return; + } + + /* Get all the Static NAPT entries */ + for (auto it = m_staticNaptEntry.begin(); it != m_staticNaptEntry.end(); it++) + { + /* Check interface is not None, otherwise continue */ + if ((*it).second.interface == NONE_STRING) + { + continue; + } + + isEntryModified = true; + + if ((*it).second.twice_nat_id.empty()) + { + /* Set the conntrack for Static Single NAPT Entry */ + setStaticSingleNaptConntrackEntry((*it).first, mode); + } + else if (((*it).second.twice_nat_added == true)) + { + /* Set the conntrack for Static Twice NAPT entry */ + setStaticTwiceNaptConntrackEntry((*it).first, mode); + } + } + + if (!isEntryModified) + { + SWSS_LOG_INFO("No Static NAPT entries to modify"); + } +} + +/* To set the conntrack for Static Single NAPT entry based on Key*/ +void NatMgr::setStaticSingleNaptConntrackEntry(const string &key, string &mode) +{ + if (mode == "UPDATE") + { + updateConntrackStaticSingleNaptEntry(key); + } + else if (mode == "ADD") + { + addConntrackStaticSingleNaptEntry(key); + } +} + +/* To set the conntrack for Static Twice NAPT entry based on Key */ +void NatMgr::setStaticTwiceNaptConntrackEntry(const string &key, string &mode) +{ + vector keys = tokenize(key, config_db_key_delimiter); + + /* Get all the Static NAPT entries */ + for (auto it = m_staticNaptEntry.begin(); it != m_staticNaptEntry.end(); it++) + { + vector entry_keys = tokenize((*it).first, config_db_key_delimiter); + + /* Check for other entries, otherwise continue */ + if ((*it).first == key) + { + continue; + } + + /* Check for both protocols are same, otherwise continue */ + if (entry_keys[1] != keys[1]) + { + continue; + } + + /* Check the twice_nat_id is matched, otherwise continue */ + if ((*it).second.twice_nat_id != m_staticNaptEntry[key].twice_nat_id) + { + continue; + } + + /* Check the twice NAT is added, otherwise continue */ + if ((!(*it).second.twice_nat_added) or (!m_staticNaptEntry[key].twice_nat_added)) + { + continue; + } + + /* Check interface is assigned, means Entry is added, otherwise continue */ + if (((*it).second.interface == NONE_STRING) or (m_staticNaptEntry[key].interface == NONE_STRING)) + { + continue; + } + + /* Check the nat type is different, otherwise continue */ + if ((*it).second.nat_type == m_staticNaptEntry[key].nat_type) + { + continue; + } + + if (((*it).second.nat_type == DNAT_NAT_TYPE) and + (m_staticNaptEntry[key].nat_type == SNAT_NAT_TYPE)) + { + if (mode == "UPDATE") + { + updateConntrackStaticTwiceNaptEntry(key, (*it).first); + } + else if (mode == "ADD") + { + addConntrackStaticTwiceNaptEntry(key, (*it).first); + } + } + else if (((*it).second.nat_type == SNAT_NAT_TYPE) and + (m_staticNaptEntry[key].nat_type == DNAT_NAT_TYPE)) + { + if (mode == "UPDATE") + { + updateConntrackStaticTwiceNaptEntry((*it).first, key); + } + else if (mode == "ADD") + { + addConntrackStaticTwiceNaptEntry((*it).first, key); + } + } + break; + } +} + /* To Add or Delete Dynamic NAT/NAPT iptables rules if all valid conditions are met */ void NatMgr::setDynamicAllForwardOrAclbasedRules(const string &opCmd, const string &pool_interface, const string &ip_range, const string &port_range, const string &aclsName, @@ -4565,9 +5047,7 @@ void NatMgr::addDynamicNatRules(const string port, const string ipPrefix) if ((port != NONE_STRING) and (ipPrefix != NONE_STRING)) { - /* Send notification to Orchagent to flush the conntrack entries */ - std::vector entry; - flushNotifier->send("ENTRIES", "ALL", entry); + flushAllNatEntries(); SWSS_LOG_WARN("Added interface is part of Binded NAT Pool range, so it is clearing all the nat translations"); } @@ -4983,6 +5463,16 @@ void NatMgr::enableNatFeature(void) /* Add full-cone PRE-ROUTING DNAT rule in the kernel */ setFullConeDnatIptablesRule(ADD); + + SWSS_LOG_INFO("NAT Refresh timer start "); + m_natRefreshTimer->start(); + + if (! warmBootingInProgress()) + { + SWSS_LOG_NOTICE("Not warm rebooting, so clearing all conntrack Entries on nat feature enable"); + flushAllNatEntries(); + addAllStaticConntrackEntries(); + } } /* To disable the NAT Feature */ @@ -5011,6 +5501,55 @@ void NatMgr::disableNatFeature(void) /* Delete full-cone PRE-ROUTING DNAT rule in the kernel */ setFullConeDnatIptablesRule(DELETE); + + SWSS_LOG_INFO("NAT Refresh timer stop "); + m_natRefreshTimer->stop(); + + SWSS_LOG_INFO("Clear all dynamic NAT Entries "); + flushAllNatEntries(); +} + +/* To set the timout of conntrack entries */ +void NatMgr::doNatRefreshTimerTask() +{ + SWSS_LOG_ENTER(); + + /* Update conntrack static NAT entries */ + SWSS_LOG_INFO("Updating conntrack for Static NAT entries"); + setStaticNatConntrackEntries("UPDATE"); + + /* Update conntrack static NAPT entries */ + SWSS_LOG_INFO("Updating conntrack for Static NAPT entries"); + setStaticNaptConntrackEntries("UPDATE"); +} + +/* To add all conntrack entries */ +void NatMgr::addAllStaticConntrackEntries() +{ + SWSS_LOG_ENTER(); + + /* Add conntrack static NAT entries */ + SWSS_LOG_INFO("Adding conntrack for Static NAT entries"); + setStaticNatConntrackEntries("ADD"); + + /* Add conntrack static NAPT entries */ + SWSS_LOG_INFO("Adding conntrack for Static NAPT entries"); + setStaticNaptConntrackEntries("ADD"); +} + +void NatMgr::doTask(SelectableTimer &timer) +{ + SWSS_LOG_ENTER(); + + if (timer.getFd() == m_natRefreshTimer->getFd()) + { + SWSS_LOG_INFO("Calling doNatRefreshTimerTask"); + doNatRefreshTimerTask(); + } + else + { + SWSS_LOG_INFO("Received unknown selectable timer"); + } } /* To parse the received Static NAT Table and save it to cache */ @@ -7402,3 +7941,71 @@ void NatMgr::doTask(Consumer &consumer) } } +/* To parse the timeout notifications */ +void NatMgr::timeoutNotifications(string op, string data) +{ + SWSS_LOG_ENTER(); + + if (op == "SET-SINGLE-NAT") + { + SWSS_LOG_INFO("Received set single nat timeout notification"); + updateDynamicSingleNatConnTrackTimeout(data, NAT_TIMEOUT_MAX); + } + else if (op == "AGEOUT-SINGLE-NAT") + { + SWSS_LOG_INFO("Received reset single nat timeout notification"); + updateDynamicSingleNatConnTrackTimeout(data, NAT_TIMEOUT_LOW); + } + else if (op == "SET-SINGLE-NAPT") + { + SWSS_LOG_INFO("Received set single napt timeout notification"); + updateDynamicSingleNaptConnTrackTimeout(data, NAT_TIMEOUT_MAX); + } + else if (op == "AGEOUT-SINGLE-NAPT") + { + SWSS_LOG_INFO("Received reset single napt timeout notification"); + updateDynamicSingleNaptConnTrackTimeout(data, NAT_TIMEOUT_LOW); + } + else if (op == "SET-TWICE-NAT") + { + SWSS_LOG_INFO("Received set twice nat timeout notification"); + updateDynamicTwiceNatConnTrackTimeout(data, NAT_TIMEOUT_MAX); + } + else if (op == "AGEOUT-TWICE-NAT") + { + SWSS_LOG_INFO("Received reset twice nat timeout notification"); + updateDynamicTwiceNatConnTrackTimeout(data, NAT_TIMEOUT_LOW); + } + else if (op == "SET-TWICE-NAPT") + { + SWSS_LOG_INFO("Received set twice napt timeout notification"); + updateDynamicTwiceNaptConnTrackTimeout(data, NAT_TIMEOUT_MAX); + } + else if (op == "AGEOUT-TWICE-NAPT") + { + SWSS_LOG_INFO("Received reset twice napt timeout notification"); + updateDynamicTwiceNaptConnTrackTimeout(data, NAT_TIMEOUT_LOW); + } + else + { + SWSS_LOG_ERROR("Received unknown timeout nat request"); + } +} + +/* To parse the flush notifications */ +void NatMgr::flushNotifications(string op, string data) +{ + SWSS_LOG_ENTER(); + + if ((op == "ENTRIES") and (data == "ALL")) + { + SWSS_LOG_INFO("Received flush entries notification"); + flushAllNatEntries(); + addAllStaticConntrackEntries(); + } + else + { + SWSS_LOG_ERROR("Received unknown flush nat request"); + } +} + diff --git a/cfgmgr/natmgr.h b/cfgmgr/natmgr.h index 8f6222a98f87..8e775b91a050 100644 --- a/cfgmgr/natmgr.h +++ b/cfgmgr/natmgr.h @@ -17,10 +17,12 @@ #ifndef __NATMGR__ #define __NATMGR__ +#include "selectabletimer.h" #include "dbconnector.h" #include "producerstatetable.h" #include "orch.h" #include "notificationproducer.h" +#include "timer.h" #include #include #include @@ -60,6 +62,7 @@ namespace swss { #define NAT_TIMEOUT_MIN 300 #define NAT_TIMEOUT_MAX 432000 #define NAT_TIMEOUT_DEFAULT 600 +#define NAT_TIMEOUT_LOW 0 #define NAT_TCP_TIMEOUT "nat_tcp_timeout" #define NAT_TCP_TIMEOUT_MIN 300 #define NAT_TCP_TIMEOUT_MAX 432000 @@ -119,6 +122,9 @@ namespace swss { #define IS_RESERVED_ADDR(ipaddr) (ipaddr >= 0xF0000000) #define IS_ZERO_ADDR(ipaddr) (ipaddr == 0) #define IS_BROADCAST_ADDR(ipaddr) (ipaddr == 0xFFFFFFFF) +#define NAT_ENTRY_REFRESH_PERIOD 86400 // 1 day +#define REDIRECT_TO_DEV_NULL " &> /dev/null" +#define FLUSH " -F" const char ip_address_delimiter = '/'; @@ -234,13 +240,15 @@ class NatMgr : public Orch void cleanupPoolIpTable(); void cleanupMangleIpTables(); bool isPortInitDone(DBConnector *app_db); - + void timeoutNotifications(std::string op, std::string data); + void flushNotifications(std::string op, std::string data); + private: /* Declare APPL_DB, CFG_DB and STATE_DB tables */ ProducerStateTable m_appNatTableProducer, m_appNaptTableProducer, m_appNatGlobalTableProducer; ProducerStateTable m_appTwiceNatTableProducer, m_appTwiceNaptTableProducer; Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateInterfaceTable, m_appNaptPoolIpTable; - std::shared_ptr flushNotifier; + Table m_stateWarmRestartEnableTable, m_stateWarmRestartTable; /* Declare containers to store NAT Info */ int m_natTimeout; @@ -256,9 +264,12 @@ class NatMgr : public Orch natZoneInterface_map_t m_natZoneInterfaceInfo; natAclTable_map_t m_natAclTableInfo; natAclRule_map_t m_natAclRuleInfo; + SelectableTimer *m_natRefreshTimer; /* Declare doTask related fucntions */ void doTask(Consumer &consumer); + void doTask(SelectableTimer &timer); + void doNatRefreshTimerTask(); void doStaticNatTask(Consumer &consumer); void doStaticNaptTask(Consumer &consumer); void doNatPoolTask(Consumer &consumer); @@ -271,15 +282,26 @@ class NatMgr : public Orch /* Declare all NAT functionality member functions*/ void enableNatFeature(void); void disableNatFeature(void); - void addConntrackSingleNatEntry(const std::string &key); - void addConntrackSingleNaptEntry(const std::string &key); - void deleteConntrackSingleNatEntry(const std::string &key); - void deleteConntrackSingleNaptEntry(const std::string &key); - void addConntrackTwiceNatEntry(const std::string &snatKey, const std::string &dnatKey); - void addConntrackTwiceNaptEntry(const std::string &snatKey, const std::string &dnatKey); - void deleteConntrackTwiceNatEntry(const std::string &snatKey, const std::string &dnatKey); - void deleteConntrackTwiceNaptEntry(const std::string &snatKey, const std::string &dnatKey); + bool warmBootingInProgress(void); + void flushAllNatEntries(void); + void addAllStaticConntrackEntries(void); + void addConntrackStaticSingleNatEntry(const std::string &key); + void addConntrackStaticSingleNaptEntry(const std::string &key); + void updateConntrackStaticSingleNatEntry(const std::string &key); + void updateConntrackStaticSingleNaptEntry(const std::string &key); + void deleteConntrackStaticSingleNatEntry(const std::string &key); + void deleteConntrackStaticSingleNaptEntry(const std::string &key); + void addConntrackStaticTwiceNatEntry(const std::string &snatKey, const std::string &dnatKey); + void addConntrackStaticTwiceNaptEntry(const std::string &snatKey, const std::string &dnatKey); + void updateConntrackStaticTwiceNatEntry(const std::string &snatKey, const std::string &dnatKey); + void updateConntrackStaticTwiceNaptEntry(const std::string &snatKey, const std::string &dnatKey); + void deleteConntrackStaticTwiceNatEntry(const std::string &snatKey, const std::string &dnatKey); + void deleteConntrackStaticTwiceNaptEntry(const std::string &snatKey, const std::string &dnatKey); void deleteConntrackDynamicEntries(const std::string &ip_range); + void updateDynamicSingleNatConnTrackTimeout(std::string key, int timeout); + void updateDynamicSingleNaptConnTrackTimeout(std::string key, int timeout); + void updateDynamicTwiceNatConnTrackTimeout(std::string key, int timeout); + void updateDynamicTwiceNaptConnTrackTimeout(std::string key, int timeout); void addStaticNatEntry(const std::string &key); void addStaticNaptEntry(const std::string &key); void addStaticSingleNatEntry(const std::string &key); @@ -308,6 +330,12 @@ class NatMgr : public Orch void addStaticNaptIptables(const std::string port); void removeStaticNatIptables(const std::string port); void removeStaticNaptIptables(const std::string port); + void setStaticNatConntrackEntries(std::string mode); + void setStaticSingleNatConntrackEntry(const std::string &key, std::string &mode); + void setStaticTwiceNatConntrackEntry(const std::string &key, std::string &mode); + void setStaticNaptConntrackEntries(std::string mode); + void setStaticSingleNaptConntrackEntry(const std::string &key, std::string &mode); + void setStaticTwiceNaptConntrackEntry(const std::string &key, std::string &mode); void addDynamicNatRule(const std::string &key); void removeDynamicNatRule(const std::string &key); void addDynamicNatRuleByAcl(const std::string &key, bool isRuleId = false); diff --git a/cfgmgr/natmgrd.cpp b/cfgmgr/natmgrd.cpp index dc8bf1f80f0b..c3bbe41f8d4c 100644 --- a/cfgmgr/natmgrd.cpp +++ b/cfgmgr/natmgrd.cpp @@ -55,6 +55,9 @@ string gRecordFile; mutex gDbMutex; NatMgr *natmgr = NULL; +NotificationConsumer *timeoutNotificationsConsumer = NULL; +NotificationConsumer *flushNotificationsConsumer = NULL; + std::shared_ptr cleanupNotifier; void sigterm_handler(int signo) @@ -142,6 +145,12 @@ int main(int argc, char **argv) s.addSelectables(o->getSelectables()); } + timeoutNotificationsConsumer = new NotificationConsumer(&appDb, "SETTIMEOUTNAT"); + s.addSelectable(timeoutNotificationsConsumer); + + flushNotificationsConsumer = new NotificationConsumer(&appDb, "FLUSHNATENTRIES"); + s.addSelectable(flushNotificationsConsumer); + SWSS_LOG_NOTICE("starting main loop"); while (true) { @@ -154,6 +163,29 @@ int main(int argc, char **argv) SWSS_LOG_NOTICE("Error: %s!", strerror(errno)); continue; } + + if (sel == timeoutNotificationsConsumer) + { + std::string op; + std::string data; + std::vector values; + + timeoutNotificationsConsumer->pop(op, data, values); + natmgr->timeoutNotifications(op, data); + continue; + } + + if (sel == flushNotificationsConsumer) + { + std::string op; + std::string data; + std::vector values; + + flushNotificationsConsumer->pop(op, data, values); + natmgr->flushNotifications(op, data); + continue; + } + if (ret == Select::TIMEOUT) { natmgr->doTask(); diff --git a/natsyncd/natsync.cpp b/natsyncd/natsync.cpp index c8fe3a804163..ec2abf3d50b9 100644 --- a/natsyncd/natsync.cpp +++ b/natsyncd/natsync.cpp @@ -59,6 +59,8 @@ NatSync::NatSync(RedisPipeline *pipelineAppDB, DBConnector *appDb, DBConnector * m_AppRestartAssist->registerAppTable(APP_NAT_TWICE_TABLE_NAME, &m_natTwiceTable); m_AppRestartAssist->registerAppTable(APP_NAPT_TWICE_TABLE_NAME, &m_naptTwiceTable); } + + setTimeoutNotifier = std::make_shared(appDb, "SETTIMEOUTNAT"); } NatSync::~NatSync() @@ -490,6 +492,7 @@ int NatSync::addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFl { m_naptTwiceTable.set(key, fvVector); SWSS_LOG_NOTICE("Twice NAPT entry with key %s added to APP_DB", key.c_str()); + setTimeoutNotifier->send("SET-TWICE-NAPT", key, fvVector); m_naptTwiceTable.set(reverseEntryKey, reverseFvVector); SWSS_LOG_NOTICE("Twice NAPT entry with reverse key %s added to APP_DB", reverseEntryKey.c_str()); } @@ -530,6 +533,7 @@ int NatSync::addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFl { m_natTwiceTable.set(key, fvVector); SWSS_LOG_NOTICE("Twice NAT entry with key %s added to APP_DB", key.c_str()); + setTimeoutNotifier->send("SET-TWICE-NAT", key, fvVector); m_natTwiceTable.set(reverseEntryKey, reverseFvVector); SWSS_LOG_NOTICE("Twice NAT entry with reverse key %s added to APP_DB", reverseEntryKey.c_str()); } @@ -682,6 +686,7 @@ int NatSync::addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFl { m_naptTable.set(key, fvVector); SWSS_LOG_NOTICE("SNAPT entry with key %s added to APP_DB", key.c_str()); + setTimeoutNotifier->send("SET-SINGLE-NAPT", key, fvVector); m_naptTable.set(reverseEntryKey, reverseFvVector); SWSS_LOG_NOTICE("Implicit DNAPT entry with key %s added to APP_DB", reverseEntryKey.c_str()); } @@ -786,6 +791,7 @@ int NatSync::addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFl { m_natTable.set(key, fvVector); SWSS_LOG_NOTICE("SNAT entry with key %s added to APP_DB", key.c_str()); + setTimeoutNotifier->send("SET-SINGLE-NAT", key, fvVector); m_natTable.set(reverseEntryKey, reverseFvVector); SWSS_LOG_NOTICE("Implicit DNAT entry with key %s added to APP_DB", reverseEntryKey.c_str()); } @@ -890,6 +896,7 @@ int NatSync::addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFl { m_naptTable.set(key, fvVector); SWSS_LOG_NOTICE("DNAPT entry with key %s added to APP_DB", key.c_str()); + setTimeoutNotifier->send("SET-SINGLE-NAPT", key, fvVector); m_naptTable.set(reverseEntryKey, reverseFvVector); SWSS_LOG_NOTICE("Implicit SNAPT entry with key %s added to APP_DB", reverseEntryKey.c_str()); } @@ -963,6 +970,7 @@ int NatSync::addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFl { m_natTable.set(key, fvVector); SWSS_LOG_NOTICE("DNAT entry with key %s added to APP_DB", key.c_str()); + setTimeoutNotifier->send("SET-SINGLE-NAT", key, fvVector); m_natTable.set(reverseEntryKey, reverseFvVector); SWSS_LOG_NOTICE("Implicit SNAT entry with key %s added to APP_DB", reverseEntryKey.c_str()); } diff --git a/natsyncd/natsync.h b/natsyncd/natsync.h index 27e4cb9c0d9d..f53e9cba7d8e 100644 --- a/natsyncd/natsync.h +++ b/natsyncd/natsync.h @@ -19,6 +19,7 @@ #include "dbconnector.h" #include "producerstatetable.h" +#include "notificationproducer.h" #include "netmsg.h" #include "warmRestartAssist.h" #include "ipaddress.h" @@ -65,6 +66,8 @@ class NatSync : public NetMsg bool matchingDnaptEntryExists(const naptEntry &entry); int addNatEntry(struct nfnl_ct *ct, struct naptEntry &entry, bool addFlag); + std::shared_ptr setTimeoutNotifier; + ProducerStateTable m_natTable; ProducerStateTable m_naptTable; ProducerStateTable m_natTwiceTable; diff --git a/orchagent/natorch.cpp b/orchagent/natorch.cpp index 8b292748b671..3f4940b07a44 100644 --- a/orchagent/natorch.cpp +++ b/orchagent/natorch.cpp @@ -51,8 +51,6 @@ NatOrch::NatOrch(DBConnector *appDb, DBConnector *stateDb, vector(appDb, "SETTIMEOUTNAT"); #ifdef DEBUG_FRAMEWORK /*Register with debug framework*/ this->m_dbgCompName = "natorch"; @@ -1252,10 +1258,16 @@ bool NatOrch::addHwSnatEntry(const IpAddress &ip_address) sai_nat_entry_t snat_entry; sai_attribute_t nat_entry_attr[5]; sai_status_t status; + struct timespec time_now; SWSS_LOG_ENTER(); SWSS_LOG_INFO("Create SNAT entry for ip %s", ip_address.to_string().c_str()); + if (clock_gettime (CLOCK_MONOTONIC, &time_now) < 0) + { + return false; + } + NatEntryValue entry = m_natEntries[ip_address]; memset(nat_entry_attr, 0, sizeof(nat_entry_attr)); @@ -1294,6 +1306,7 @@ bool NatOrch::addHwSnatEntry(const IpAddress &ip_address) updateNatCounters(ip_address, 0, 0); m_natEntries[ip_address].addedToHw = true; + m_natEntries[ip_address].activeTime = time_now.tv_sec; if (entry.entry_type == "static") { @@ -1318,10 +1331,16 @@ bool NatOrch::addHwTwiceNatEntry(const TwiceNatEntryKey &key) sai_attribute_t nat_entry_attr[8]; sai_status_t status; + struct timespec time_now; SWSS_LOG_ENTER(); SWSS_LOG_INFO("Create Twice NAT entry for src ip %s, dst ip %s", key.src_ip.to_string().c_str(), key.dst_ip.to_string().c_str()); + if (clock_gettime (CLOCK_MONOTONIC, &time_now) < 0) + { + return false; + } + TwiceNatEntryValue value = m_twiceNatEntries[key]; memset(nat_entry_attr, 0, sizeof(nat_entry_attr)); @@ -1369,6 +1388,7 @@ bool NatOrch::addHwTwiceNatEntry(const TwiceNatEntryKey &key) updateTwiceNatCounters(key, 0, 0); m_twiceNatEntries[key].addedToHw = true; + m_twiceNatEntries[key].activeTime = time_now.tv_sec; totalDnatEntries++; updateDnatCounters(totalDnatEntries); @@ -1400,11 +1420,17 @@ bool NatOrch::addHwSnaptEntry(const NaptEntryKey &keyEntry) sai_attribute_t nat_entry_attr[6]; uint8_t ip_protocol = ((keyEntry.prototype == "TCP") ? IPPROTO_TCP : IPPROTO_UDP); sai_status_t status; + struct timespec time_now; SWSS_LOG_ENTER(); SWSS_LOG_INFO("Create SNAPT entry for proto %s, src-ip %s, l4-port %d", keyEntry.prototype.c_str(), keyEntry.ip_address.to_string().c_str(), keyEntry.l4_port); + if (clock_gettime (CLOCK_MONOTONIC, &time_now) < 0) + { + return false; + } + NaptEntryValue entry = m_naptEntries[keyEntry]; memset(nat_entry_attr, 0, sizeof(nat_entry_attr)); @@ -1450,6 +1476,8 @@ bool NatOrch::addHwSnaptEntry(const NaptEntryKey &keyEntry) entry.translated_ip.to_string().c_str(), entry.translated_l4_port); m_naptEntries[keyEntry].addedToHw = true; + m_naptEntries[keyEntry].activeTime = time_now.tv_sec; + updateNaptCounters(keyEntry.prototype.c_str(), keyEntry.ip_address, keyEntry.l4_port, 0, 0); if (entry.entry_type == "static") @@ -1475,12 +1503,18 @@ bool NatOrch::addHwTwiceNaptEntry(const TwiceNaptEntryKey &key) sai_attribute_t nat_entry_attr[10]; uint8_t protoType = ((key.prototype == "TCP") ? IPPROTO_TCP : IPPROTO_UDP); sai_status_t status; + struct timespec time_now; SWSS_LOG_ENTER(); SWSS_LOG_INFO("Create Twice SNAPT entry for proto %s, src-ip %s, src port %d, dst-ip %s, dst port %d", key.prototype.c_str(), key.src_ip.to_string().c_str(), key.src_l4_port, key.dst_ip.to_string().c_str(), key.dst_l4_port); + if (clock_gettime (CLOCK_MONOTONIC, &time_now) < 0) + { + return false; + } + TwiceNaptEntryValue value = m_twiceNaptEntries[key]; memset(nat_entry_attr, 0, sizeof(nat_entry_attr)); @@ -1542,6 +1576,7 @@ bool NatOrch::addHwTwiceNaptEntry(const TwiceNaptEntryKey &key) updateTwiceNaptCounters(key, 0, 0); m_twiceNaptEntries[key].addedToHw = true; + m_twiceNaptEntries[key].activeTime = time_now.tv_sec; totalDnatEntries++; updateDnatCounters(totalDnatEntries); @@ -1747,14 +1782,14 @@ bool NatOrch::addNatEntry(const IpAddress &ip_address, const NatEntryValue &entr { SWSS_LOG_INFO("Reached the max allowed NAT entries in the hardware, dropping new SNAT translation with ip %s and translated ip %s", ip_address.to_string().c_str(), entry.translated_ip.to_string().c_str()); - deleteConnTrackEntry(ip_address); + std::vector fvVector; + std::string natKey = ip_address.to_string(); + setTimeoutNotifier->send("AGEOUT-SINGLE-NAT", natKey, fvVector); return true; } m_natEntries[ip_address] = entry; m_natEntries[ip_address].addedToHw = false; - - updateConnTrackTimeout(ip_address); } else { @@ -1861,15 +1896,15 @@ bool NatOrch::addTwiceNatEntry(const TwiceNatEntryKey &key, const TwiceNatEntryV { SWSS_LOG_INFO("Reached the max allowed NAT entries in the hardware, dropping new Twice NAT translation with src ip %s, dst ip %s and translated src ip %s, dst ip %s", key.src_ip.to_string().c_str(), key.dst_ip.to_string().c_str(), value.translated_src_ip.to_string().c_str(), value.translated_dst_ip.to_string().c_str()); - deleteConnTrackEntry(key); + std::vector fvVector; + std::string twiceNatKey = (key.src_ip.to_string() + ":" + key.dst_ip.to_string()); + setTimeoutNotifier->send("AGEOUT-TWICE-NAT", twiceNatKey, fvVector); return true; } } m_twiceNatEntries[key] = value; m_twiceNatEntries[key].addedToHw = false; - updateConnTrackTimeout(key); - if (!isNatEnabled()) { SWSS_LOG_WARN("NAT Feature is not yet enabled, skipped adding %s Twice NAT entry with src ip %s, dst ip %s and it's translated src ip %s, dst ip %s", @@ -1977,14 +2012,14 @@ bool NatOrch::addNaptEntry(const NaptEntryKey &keyEntry, const NaptEntryValue &e SWSS_LOG_INFO("Reached the max allowed NAT entries in the hardware, dropping new SNAPT translation with ip %s, port %d, prototype %s, translated ip %s, translated port %d", keyEntry.ip_address.to_string().c_str(), keyEntry.l4_port, keyEntry.prototype.c_str(), entry.translated_ip.to_string().c_str(), entry.translated_l4_port); - deleteConnTrackEntry(keyEntry); + std::vector fvVector; + std::string naptKey = (keyEntry.prototype + ":" + keyEntry.ip_address.to_string() + ":" + to_string(keyEntry.l4_port)); + setTimeoutNotifier->send("AGEOUT-SINGLE-NAPT", naptKey, fvVector); return true; } m_naptEntries[keyEntry] = entry; m_naptEntries[keyEntry].addedToHw = false; - - updateConnTrackTimeout(keyEntry); } else { @@ -2145,15 +2180,16 @@ bool NatOrch::addTwiceNaptEntry(const TwiceNaptEntryKey &key, const TwiceNaptEnt SWSS_LOG_INFO("Reached the max allowed NAT entries in the hardware, dropping new Twice SNAPT translation with src ip %s, src port %d, prototype %s, \ dst ip %s, dst port %d", key.src_ip.to_string().c_str(), key.src_l4_port, key.prototype.c_str(), key.dst_ip.to_string().c_str(), key.dst_l4_port); - deleteConnTrackEntry(key); + std::vector fvVector; + std::string twiceNaptKey = (key.prototype + ":" + key.src_ip.to_string() + ":" + to_string(key.src_l4_port) + + ":" + key.dst_ip.to_string() + ":" + to_string(key.dst_l4_port)); + setTimeoutNotifier->send("AGEOUT-TWICE-NAPT", twiceNaptKey, fvVector); return true; } } m_twiceNaptEntries[key] = value; m_twiceNaptEntries[key].addedToHw = false; - updateConnTrackTimeout(key); - if (!isNatEnabled()) { SWSS_LOG_WARN("NAT feature is not yet enabled, skipped adding %s Twice NAPT entry with src ip %s, src port %d, prototype %s, dst ip %s, dst port %d", @@ -2215,22 +2251,6 @@ bool NatOrch::isNatEnabled(void) return false; } -void NatOrch::flushAllNatEntries(void) -{ - std::string res; - const std::string cmds = std::string("") + CONNTRACK + FLUSH; - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Cleared the All NAT Entries"); - } -} - void NatOrch::clearAllDnatEntries(void) { IpAddress dstIp; @@ -2410,29 +2430,6 @@ void NatOrch::cleanupAppDbEntries(void) } } -bool NatOrch::warmBootingInProgress(void) -{ - std::string value; - - m_stateWarmRestartEnableTable.hget("system", "enable", value); - if (value == "true") - { - SWSS_LOG_INFO("Warm reboot enabled"); - m_stateWarmRestartTable.hget("natsyncd", "state", value); - if (value != "reconciled") - { - SWSS_LOG_NOTICE("Nat conntrack state reconciliation not completed yet"); - return true; - } - return false; - } - else - { - SWSS_LOG_INFO("Warm reboot not enabled"); - } - return false; -} - void NatOrch::enableNatFeature(void) { sai_status_t status; @@ -2466,26 +2463,17 @@ void NatOrch::enableNatFeature(void) SWSS_LOG_INFO("NAT Query timer start "); m_natQueryTimer->start(); + SWSS_LOG_INFO("NAT Timeout timer start "); + m_natTimeoutTimer->start(); + if (gNhTrackingSupported == true) { SWSS_LOG_INFO("Attach to Neighbor Orch "); m_neighOrch->attach(this); } - if (! warmBootingInProgress()) - { - SWSS_LOG_NOTICE("Not warm rebooting, so clearing all conntrack Entries on nat feature enable"); - flushAllNatEntries(); - } SWSS_LOG_INFO("Adding NAT Entries "); addAllNatEntries(); - - if (! warmBootingInProgress()) - { - SWSS_LOG_NOTICE("Not warm rebooting, so adding static conntrack Entries"); - addAllStaticConntrackEntries(); - } - } void NatOrch::disableNatFeature(void) @@ -2510,15 +2498,15 @@ void NatOrch::disableNatFeature(void) SWSS_LOG_INFO("NAT Query timer stop "); m_natQueryTimer->stop(); + SWSS_LOG_INFO("NAT Timeout timer stop "); + m_natTimeoutTimer->stop(); + if (gNhTrackingSupported == true) { SWSS_LOG_INFO("Detach to Neighbor Orch "); m_neighOrch->detach(this); } - SWSS_LOG_INFO("Clear all dynamic NAT Entries "); - flushAllNatEntries(); - SWSS_LOG_INFO("Clear all DNAT Entries "); clearAllDnatEntries(); } @@ -2859,17 +2847,14 @@ void NatOrch::doNatGlobalTableTask(Consumer& consumer) else if (fvField(i) == "nat_tcp_timeout") { tcp_timeout = stoi(fvValue(i)); - updateConnTrackTimeout("tcp"); } else if (fvField(i) == "nat_udp_timeout") { udp_timeout = stoi(fvValue(i)); - updateConnTrackTimeout("udp"); } else if (fvField(i) == "nat_timeout") { timeout = stoi(fvValue(i)); - updateConnTrackTimeout("all"); } } @@ -2940,11 +2925,23 @@ void NatOrch::doTask(SelectableTimer &timer) { SWSS_LOG_ENTER(); - if (((natTimerTickCntr++) % NAT_HITBIT_QUERY_MULTIPLE) == 0) + if (timer.getFd() == m_natQueryTimer->getFd()) + { + if (((natTimerTickCntr++) % NAT_HITBIT_QUERY_MULTIPLE) == 0) + { + queryHitBits(); + } + queryCounters(); + } + else if (timer.getFd() == m_natTimeoutTimer->getFd()) { - queryHitBits(); + SWSS_LOG_INFO("Received NatTimeoutTimer"); + updateAllConntrackEntries(); + } + else + { + SWSS_LOG_INFO("Received unknown timer"); } - queryCounters(); } void NatOrch::queryCounters(void) @@ -3133,54 +3130,6 @@ void NatOrch::clearCounters(void) } } -void NatOrch::addAllStaticConntrackEntries(void) -{ - SWSS_LOG_ENTER(); - - NatEntry::iterator natIter = m_natEntries.begin(); - while (natIter != m_natEntries.end()) - { - if (((*natIter).second.entry_type == "static") and - ((*natIter).second.addedToHw == true) and - ((*natIter).second.nat_type == "snat")) - { - addConnTrackEntry((*natIter).first); - } - natIter++; - } - NaptEntry::iterator naptIter = m_naptEntries.begin(); - while (naptIter != m_naptEntries.end()) - { - if (((*naptIter).second.entry_type == "static") and - ((*naptIter).second.addedToHw == true) and - ((*naptIter).second.nat_type == "snat")) - { - addConnTrackEntry((*naptIter).first); - } - naptIter++; - } - TwiceNatEntry::iterator twiceNatIter = m_twiceNatEntries.begin(); - while (twiceNatIter != m_twiceNatEntries.end()) - { - if (((*twiceNatIter).second.entry_type == "static") and - ((*twiceNatIter).second.addedToHw == true)) - { - addConnTrackEntry((*twiceNatIter).first); - } - twiceNatIter++; - } - TwiceNaptEntry::iterator twiceNaptIter = m_twiceNaptEntries.begin(); - while (twiceNaptIter != m_twiceNaptEntries.end()) - { - if (((*twiceNaptIter).second.entry_type == "static") and - ((*twiceNaptIter).second.addedToHw == true)) - { - addConnTrackEntry((*twiceNaptIter).first); - } - twiceNaptIter++; - } -} - void NatOrch::queryHitBits(void) { SWSS_LOG_ENTER(); @@ -3195,15 +3144,27 @@ void NatOrch::queryHitBits(void) /* Remove the NAT entries that are aged out. * Query the NAT entries for their activity in the hardware - * and update the aging timeout. */ + * and update the active timeout. */ NatEntry::iterator natIter = m_natEntries.begin(); while (natIter != m_natEntries.end()) { if (checkIfNatEntryIsActive(natIter, time_now.tv_sec)) { - /* Since the entry is active in the hardware, reset - * the expiry time for the conntrack entry in the kernel. */ - updateConnTrackTimeout(natIter->first); + /* Since the entry is active in the hardware, reset the active time */ + natIter->second.activeTime = time_now.tv_sec; + } + else + { + if ((natIter->second.nat_type == "snat") and (natIter->second.addedToHw == true) and + (natIter->second.entry_type != "static")) + { + if (time_now.tv_sec - natIter->second.activeTime >= timeout) + { + std::vector fvVector; + std::string key = natIter->first.to_string(); + setTimeoutNotifier->send("AGEOUT-SINGLE-NAT", key, fvVector); + } + } } queried_entries++; natIter++; @@ -3211,15 +3172,28 @@ void NatOrch::queryHitBits(void) /* Remove the NAPT entries that are aged out. * Query the NAPT entries for their activity in the hardware - * and update the aging timeout. */ + * and update the active timeout. */ NaptEntry::iterator naptIter = m_naptEntries.begin(); while (naptIter != m_naptEntries.end()) { if (checkIfNaptEntryIsActive(naptIter, time_now.tv_sec)) { - /* Since the entry is active in the hardware, reset - * the expiry time for the conntrack entry in the kernel. */ - updateConnTrackTimeout(naptIter->first); + /* Since the entry is active in the hardware, reset the active time */ + naptIter->second.activeTime = time_now.tv_sec; + } + else + { + if ((naptIter->second.nat_type == "snat") and (naptIter->second.addedToHw == true) and + (naptIter->second.entry_type != "static")) + { + int timeout = naptIter->first.prototype == string("TCP") ? tcp_timeout : udp_timeout; + if (time_now.tv_sec - naptIter->second.activeTime >= timeout) + { + std::vector fvVector; + std::string key = (naptIter->first.prototype + ":" + naptIter->first.ip_address.to_string() + ":" + to_string(naptIter->first.l4_port)); + setTimeoutNotifier->send("AGEOUT-SINGLE-NAPT", key, fvVector); + } + } } queried_entries++; naptIter++; @@ -3227,15 +3201,27 @@ void NatOrch::queryHitBits(void) /* Remove the Twice NAT entries that are aged out. * Query the Twice NAT entries for their activity in the hardware - * and update the aging timeout. */ + * and update the active timeout. */ TwiceNatEntry::iterator twiceNatIter = m_twiceNatEntries.begin(); while (twiceNatIter != m_twiceNatEntries.end()) { if (checkIfTwiceNatEntryIsActive(twiceNatIter, time_now.tv_sec)) { - /* Since the entry is active in the hardware, reset - * the expiry time for the conntrack entry in the kernel. */ - updateConnTrackTimeout(twiceNatIter->first); + /* Since the entry is active in the hardware, reset the active time */ + twiceNatIter->second.activeTime = time_now.tv_sec; + } + else + { + if ((twiceNatIter->second.addedToHw == true) and + (twiceNatIter->second.entry_type != "static")) + { + if (time_now.tv_sec - twiceNatIter->second.activeTime >= timeout) + { + std::vector fvVector; + std::string key = (twiceNatIter->first.src_ip.to_string() + ":" + twiceNatIter->first.dst_ip.to_string()); + setTimeoutNotifier->send("AGEOUT-TWICE-NAT", key, fvVector); + } + } } queried_entries++; twiceNatIter++; @@ -3243,15 +3229,29 @@ void NatOrch::queryHitBits(void) /* Remove the Twice NAPT entries that are aged out. * Query the Twice NAPT entries for their activity in the hardware - * and update the aging timeout. */ + * and update the active timeout. */ TwiceNaptEntry::iterator twiceNaptIter = m_twiceNaptEntries.begin(); while (twiceNaptIter != m_twiceNaptEntries.end()) { if (checkIfTwiceNaptEntryIsActive(twiceNaptIter, time_now.tv_sec)) { - /* Since the entry is active in the hardware, reset - * the expiry time for the conntrack entry in the kernel. */ - updateConnTrackTimeout(twiceNaptIter->first); + /* Since the entry is active in the hardware, reset the active time */ + twiceNaptIter->second.activeTime = time_now.tv_sec; + } + else + { + if ((twiceNaptIter->second.addedToHw == true) and + (twiceNaptIter->second.entry_type != "static")) + { + int timeout = twiceNaptIter->first.prototype == string("TCP") ? tcp_timeout : udp_timeout; + if (time_now.tv_sec - twiceNaptIter->second.activeTime >= timeout) + { + std::vector fvVector; + std::string key = (twiceNaptIter->first.prototype + ":" + twiceNaptIter->first.src_ip.to_string() + ":" + to_string(twiceNaptIter->first.src_l4_port) + + ":" + twiceNaptIter->first.dst_ip.to_string() + ":" + to_string(twiceNaptIter->first.dst_l4_port)); + setTimeoutNotifier->send("AGEOUT-TWICE-NAPT", key, fvVector); + } + } } queried_entries++; twiceNaptIter++; @@ -3269,6 +3269,70 @@ void NatOrch::queryHitBits(void) } } +void NatOrch::updateAllConntrackEntries(void) +{ + SWSS_LOG_ENTER(); + + /* Send notifcations for the Single NAT entries to set timeout */ + NatEntry::iterator natIter = m_natEntries.begin(); + while (natIter != m_natEntries.end()) + { + + if ((natIter->second.nat_type == "snat") and (natIter->second.addedToHw == true) and + (natIter->second.entry_type != "static")) + { + SWSS_LOG_ERROR("Update %s NAT entry [ip %s]", natIter->second.nat_type.c_str(), natIter->first.to_string().c_str()); + std::vector fvVector; + std::string key = natIter->first.to_string(); + setTimeoutNotifier->send("SET-SINGLE-NAT", key, fvVector); + } + natIter++; + } + + /* Send notifcations for the Single NAPT entries to set timeout */ + NaptEntry::iterator naptIter = m_naptEntries.begin(); + while (naptIter != m_naptEntries.end()) + { + if ((naptIter->second.nat_type == "snat") and (naptIter->second.addedToHw == true) and + (naptIter->second.entry_type != "static")) + { + std::vector fvVector; + std::string key = (naptIter->first.prototype + ":" + naptIter->first.ip_address.to_string() + ":" + to_string(naptIter->first.l4_port)); + setTimeoutNotifier->send("SET-SINGLE-NAPT", key, fvVector); + } + naptIter++; + } + + /* Send notifcations for the Twice NAT entries to set timeout */ + TwiceNatEntry::iterator twiceNatIter = m_twiceNatEntries.begin(); + while (twiceNatIter != m_twiceNatEntries.end()) + { + if ((twiceNatIter->second.addedToHw == true) and + (twiceNatIter->second.entry_type != "static")) + { + std::vector fvVector; + std::string key = (twiceNatIter->first.src_ip.to_string() + ":" + twiceNatIter->first.dst_ip.to_string()); + setTimeoutNotifier->send("SET-TWICE-NAT", key, fvVector); + } + twiceNatIter++; + } + + /* Send notifcations for the Twice NAPT entries to set timeout */ + TwiceNaptEntry::iterator twiceNaptIter = m_twiceNaptEntries.begin(); + while (twiceNaptIter != m_twiceNaptEntries.end()) + { + if ((twiceNaptIter->second.addedToHw == true) and + (twiceNaptIter->second.entry_type != "static")) + { + std::vector fvVector; + std::string key = (twiceNaptIter->first.prototype + ":" + twiceNaptIter->first.src_ip.to_string() + ":" + to_string(twiceNaptIter->first.src_l4_port) + + ":" + twiceNaptIter->first.dst_ip.to_string() + ":" + to_string(twiceNaptIter->first.dst_l4_port)); + setTimeoutNotifier->send("SET-TWICE-NAPT", key, fvVector); + } + twiceNaptIter++; + } +} + bool NatOrch::getNatCounters(const NatEntry::iterator &iter) { const IpAddress &ipAddr = iter->first; @@ -3814,82 +3878,6 @@ bool NatOrch::setTwiceNaptCounters(const TwiceNaptEntry::iterator &iter) return 0; } -void NatOrch::deleteConnTrackEntry(const IpAddress &ipAddr) -{ - std::string res; - std::string cmds = std::string("") + CONNTRACK + DELETE; - - cmds += (" -s " + ipAddr.to_string()); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Deleted the NAT conntrack entry"); - } -} - -void NatOrch::deleteConnTrackEntry(const NaptEntryKey &key) -{ - std::string res; - std::string prototype = ((key.prototype == string("TCP")) ? "tcp" : "udp"); - std::string cmds = std::string("") + CONNTRACK + DELETE; - - cmds += (" -s " + key.ip_address.to_string() + " -p " + prototype + " --orig-port-src " + to_string(key.l4_port)); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Deleted the NAPT conntrack entry"); - } -} - -void NatOrch::deleteConnTrackEntry(const TwiceNatEntryKey &key) -{ - std::string res; - std::string cmds = std::string("") + CONNTRACK + DELETE; - - cmds += (" -s " + key.src_ip.to_string()); - cmds += (" -d " + key.dst_ip.to_string()); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Deleted the Twice NAT conntrack entry"); - } -} - -void NatOrch::deleteConnTrackEntry(const TwiceNaptEntryKey &key) -{ - std::string res; - std::string prototype = ((key.prototype == string("TCP")) ? "tcp" : "udp"); - std::string cmds = std::string("") + CONNTRACK + DELETE; - - cmds += (" -s " + key.src_ip.to_string() + " -p " + prototype + " --orig-port-src " + to_string(key.src_l4_port)); - cmds += (" -d " + key.dst_ip.to_string() + " --orig-port-dst " + to_string(key.dst_l4_port)); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Deleted the Twice NAPT conntrack entry"); - } -} - void NatOrch::updateNatCounters(const IpAddress &ipAddr, uint64_t nat_translations_pkts, uint64_t nat_translations_bytes) { @@ -4295,230 +4283,6 @@ bool NatOrch::checkIfTwiceNaptEntryIsActive(const TwiceNaptEntry::iterator &iter return 0; } -void NatOrch::updateConnTrackTimeout(string prototype) -{ - if (prototype == "all") - { - NatEntry::iterator natIter = m_natEntries.begin(); - while (natIter != m_natEntries.end()) - { - if (((*natIter).second.addedToHw == true) and - ((*natIter).second.nat_type == "snat")) - { - updateConnTrackTimeout((*natIter).first); - } - natIter++; - } - TwiceNatEntry::iterator tnatIter = m_twiceNatEntries.begin(); - while (tnatIter != m_twiceNatEntries.end()) - { - if ((*tnatIter).second.addedToHw == true) - { - updateConnTrackTimeout((*tnatIter).first); - } - tnatIter++; - } - } - else - { - std::string res; - std::string cmds = std::string("") + CONNTRACK + UPDATE; - int timeout = ((prototype == "tcp") ? tcp_timeout : udp_timeout); - - cmds += (" -p " + prototype + " -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); - swss::exec(cmds, res); - - SWSS_LOG_INFO("Updated the %s NAT conntrack entries timeout to %d", prototype.c_str(), timeout); - } -} - -void NatOrch::updateConnTrackTimeout(const IpAddress &sourceIpAddr) -{ - std::string res; - std::string cmds = std::string("") + CONNTRACK + UPDATE; - - cmds += (" -s " + sourceIpAddr.to_string() + " -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Updated the active NAT conntrack entry with src-ip %s, timeout %u", - sourceIpAddr.to_string().c_str(), timeout); - } -} - -void NatOrch::updateConnTrackTimeout(const NaptEntryKey &entry) -{ - uint8_t protoType = ((entry.prototype == string("TCP")) ? IPPROTO_TCP : IPPROTO_UDP); - - std::string res; - std::string prototype = ((entry.prototype == string("TCP")) ? "tcp" : "udp"); - int timeout = ((protoType == IPPROTO_TCP) ? tcp_timeout : udp_timeout); - std::string cmds = std::string("") + CONNTRACK + UPDATE; - - cmds += (" -s " + entry.ip_address.to_string() + " -p " + prototype + " --orig-port-src " + to_string(entry.l4_port) + " -t " + to_string(timeout) + REDIRECT_TO_DEV_NULL); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Updated active NAPT conntrack entry with protocol %s, src-ip %s, src-port %d, timeout %u", - entry.prototype.c_str(), entry.ip_address.to_string().c_str(), - entry.l4_port, ((protoType == IPPROTO_TCP) ? tcp_timeout : udp_timeout)); - } -} - -void NatOrch::updateConnTrackTimeout(const TwiceNatEntryKey &entry) -{ - std::string res; - std::string cmd = std::string("") + CONNTRACK + UPDATE; - - TwiceNatEntryValue value = m_twiceNatEntries[entry]; - - cmd += (" -s " + entry.src_ip.to_string() + " -d " + entry.dst_ip.to_string() + " -t " + std::to_string(timeout) + REDIRECT_TO_DEV_NULL); - - swss::exec(cmd, res); - - SWSS_LOG_INFO("Updated active Twice NAT conntrack entry with src-ip %s, dst-ip %s, timeout %u", - entry.src_ip.to_string().c_str(), entry.dst_ip.to_string().c_str(), timeout); -} - -void NatOrch::updateConnTrackTimeout(const TwiceNaptEntryKey &entry) -{ - uint8_t protoType = ((entry.prototype == string("TCP")) ? IPPROTO_TCP : IPPROTO_UDP); - - std::string res; - std::string prototype = ((entry.prototype == string("TCP")) ? "tcp" : "udp"); - int timeout = ((protoType == IPPROTO_TCP) ? tcp_timeout : udp_timeout); - std::string cmd = std::string("") + CONNTRACK + UPDATE; - - TwiceNaptEntryValue value = m_twiceNaptEntries[entry]; - - cmd += (" -s " + entry.src_ip.to_string() + " -p " + prototype + " --orig-port-src " + to_string(entry.src_l4_port) + - " -d " + entry.dst_ip.to_string() + " --orig-port-dst " + std::to_string(entry.dst_l4_port) + - " -t " + std::to_string(timeout) + REDIRECT_TO_DEV_NULL); - - swss::exec(cmd, res); - - SWSS_LOG_INFO("Updated active Twice NAPT conntrack entry with protocol %s, src-ip %s, src-port %d, dst-ip %s, dst-port %d, timeout %u", - entry.prototype.c_str(), entry.src_ip.to_string().c_str(), entry.src_l4_port, - entry.dst_ip.to_string().c_str(), entry.dst_l4_port, ((protoType == IPPROTO_TCP) ? tcp_timeout : udp_timeout)); -} - -void NatOrch::addConnTrackEntry(const IpAddress &ipAddr) -{ - std::string res; - std::string cmds = std::string("") + CONNTRACK + ADD; - NatEntryValue entry = m_natEntries[ipAddr]; - - cmds += (" -n " + entry.translated_ip.to_string() + ":1 -g 127.0.0.1:127" + " -p udp -t " + to_string(timeout) + - " --src " + ipAddr.to_string() + " --sport 1 --dst 127.0.0.1 --dport 127 -u ASSURED "); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Added static NAT conntrack entry with src-ip %s, timeout %u", - ipAddr.to_string().c_str(), timeout); - } -} - -void NatOrch::addConnTrackEntry(const NaptEntryKey &keyEntry) -{ - std::string cmds = std::string("") + CONNTRACK + ADD; - std::string res, prototype, state; - int timeout = 0; - NaptEntryValue entry = m_naptEntries[keyEntry]; - - if (keyEntry.prototype == string("TCP")) - { - prototype = "tcp"; - timeout = tcp_timeout; - state = " --state ESTABLISHED "; - } - else - { - prototype = "udp"; - timeout = udp_timeout; - state = ""; - } - - cmds += (" -n " + entry.translated_ip.to_string() + ":" + to_string(entry.translated_l4_port) + " -g 127.0.0.1:127" + " -p " + prototype + " -t " + to_string(timeout) + - " --src " + keyEntry.ip_address.to_string() + " --sport " + to_string(keyEntry.l4_port) + " --dst 127.0.0.1 --dport 127 -u ASSURED " + state); - int ret = swss::exec(cmds, res); - - if (ret) - { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmds.c_str(), ret); - } - else - { - SWSS_LOG_INFO("Added static NAPT conntrack entry with protocol %s, src-ip %s, src-port %d, timeout %u", - keyEntry.prototype.c_str(), keyEntry.ip_address.to_string().c_str(), - keyEntry.l4_port, (keyEntry.prototype == string("TCP") ? tcp_timeout : udp_timeout)); - } -} - -void NatOrch::addConnTrackEntry(const TwiceNatEntryKey &keyEntry) -{ - std::string res; - std::string cmds = std::string("") + CONNTRACK + ADD; - TwiceNatEntryValue entry = m_twiceNatEntries[keyEntry]; - - cmds += (" -n " + entry.translated_src_ip.to_string() + ":1" + " -g " + entry.translated_dst_ip.to_string() + - ":1" + " -p udp" + " -t " + to_string(timeout) + - " --src " + keyEntry.src_ip.to_string() + " --sport 1" + " --dst " + keyEntry.dst_ip.to_string() + - " --dport 1" + " -u ASSURED " + REDIRECT_TO_DEV_NULL); - - swss::exec(cmds, res); - - SWSS_LOG_INFO("Added Static Twice NAT conntrack entry with src-ip %s, dst-ip %s, timeout %u", - keyEntry.src_ip.to_string().c_str(), keyEntry.dst_ip.to_string().c_str(), timeout); -} - -void NatOrch::addConnTrackEntry(const TwiceNaptEntryKey &keyEntry) -{ - std::string cmds = std::string("") + CONNTRACK + ADD; - std::string res, prototype, state; - int timeout = 0; - TwiceNaptEntryValue entry = m_twiceNaptEntries[keyEntry]; - - if (keyEntry.prototype == string("TCP")) - { - prototype = "tcp"; - timeout = tcp_timeout; - state = " --state ESTABLISHED "; - } - else - { - prototype = "udp"; - timeout = udp_timeout; - state = ""; - } - - cmds += (" -n " + entry.translated_src_ip.to_string() + ":" + to_string(entry.translated_src_l4_port) + " -g " + entry.translated_dst_ip.to_string() + - ":" + to_string(entry.translated_dst_l4_port) + " -p " + prototype + " -t " + to_string(timeout) + - " --src " + keyEntry.src_ip.to_string() + " --sport " + to_string(keyEntry.src_l4_port) + " --dst " + keyEntry.dst_ip.to_string() + - " --dport " + to_string(keyEntry.dst_l4_port) + " -u ASSURED " + state + REDIRECT_TO_DEV_NULL); - - swss::exec(cmds, res); - - SWSS_LOG_INFO("Added static Twice NAPT conntrack entry with protocol %s, src-ip %s, src-port %d, dst-ip %s, dst-port %d, timeout %u", - keyEntry.prototype.c_str(), keyEntry.src_ip.to_string().c_str(), keyEntry.src_l4_port, - keyEntry.dst_ip.to_string().c_str(), keyEntry.dst_l4_port, (keyEntry.prototype == string("TCP") ? tcp_timeout : udp_timeout)); - -} - void NatOrch::doTask(NotificationConsumer& consumer) { SWSS_LOG_ENTER(); @@ -4533,13 +4297,7 @@ void NatOrch::doTask(NotificationConsumer& consumer) if (&consumer == m_flushNotificationsConsumer) { - if ((op == "ENTRIES") and (data == "ALL")) - { - SWSS_LOG_INFO("Received All Entries notification"); - flushAllNatEntries(); - addAllStaticConntrackEntries(); - } - else if ((op == "STATISTICS") and (data == "ALL")) + if ((op == "STATISTICS") and (data == "ALL")) { SWSS_LOG_INFO("Received All Statistics notification"); clearCounters(); diff --git a/orchagent/natorch.h b/orchagent/natorch.h index b0fb88cd40cf..a58fd64e1bd4 100644 --- a/orchagent/natorch.h +++ b/orchagent/natorch.h @@ -28,25 +28,22 @@ #include "timer.h" #include "routeorch.h" #include "nexthopgroupkey.h" +#include "notificationproducer.h" #ifdef DEBUG_FRAMEWORK #include "debugdumporch.h" #endif #define VALUES "Values" // Global Values Key #define NAT_HITBIT_N_CNTRS_QUERY_PERIOD 5 // 5 secs +#define NAT_CONNTRACK_TIMEOUT_PERIOD 86400 // 1 day #define NAT_HITBIT_QUERY_MULTIPLE 6 // Hit bits are queried every 30 secs -#define CONNTRACK "/usr/sbin/conntrack" -#define REDIRECT_TO_DEV_NULL " &> /dev/null" -#define FLUSH " -F" -#define UPDATE " -U" -#define DELETE " -D" -#define ADD " -I" struct NatEntryValue { IpAddress translated_ip; // Translated IP address string nat_type; // Nat Type - SNAT or DNAT string entry_type; // Entry type - Static or Dynamic + time_t activeTime; // Timestamp in secs when the entry was last seen as active time_t ageOutTime; // Timestamp in secs when the entry expires bool addedToHw; // Boolean to represent added to hardware @@ -74,6 +71,7 @@ struct NaptEntryValue int translated_l4_port; // Translated port address string nat_type; // Nat Type - SNAT or DNAT string entry_type; // Entry type - Static or Dynamic + time_t activeTime; // Timestamp in secs when the entry was last seen as active time_t ageOutTime; // Timestamp in secs when the entry expires bool addedToHw; // Boolean to represent added to hardware @@ -99,6 +97,7 @@ struct TwiceNatEntryValue IpAddress translated_src_ip; IpAddress translated_dst_ip; string entry_type; // Entry type - Static or Dynamic + time_t activeTime; // Timestamp in secs when the entry was last seen as active time_t ageOutTime; // Timestamp in secs when the entry expires bool addedToHw; // Boolean to represent added to hardware @@ -129,6 +128,7 @@ struct TwiceNaptEntryValue IpAddress translated_dst_ip; int translated_dst_l4_port; string entry_type; // Entry type - Static or Dynamic + time_t activeTime; // Timestamp in secs when the entry was last seen as active time_t ageOutTime; // Timestamp in secs when the entry expires bool addedToHw; // Boolean to represent added to hardware @@ -193,21 +193,18 @@ class NatOrch: public Orch, public Subject, public Observer private: - /* Netfilter socket to delete conntrack entries corresponding to aged out NAT entries */ - NfNetlink nfnl; NatEntry m_natEntries; NaptEntry m_naptEntries; TwiceNatEntry m_twiceNatEntries; TwiceNaptEntry m_twiceNaptEntries; SelectableTimer *m_natQueryTimer; + SelectableTimer *m_natTimeoutTimer; DBConnector m_countersDb; Table m_countersNatTable; Table m_countersNaptTable; Table m_countersTwiceNatTable; Table m_countersTwiceNaptTable; Table m_countersGlobalNatTable; - Table m_stateWarmRestartEnableTable; - Table m_stateWarmRestartTable; Table m_natQueryTable; Table m_naptQueryTable; Table m_twiceNatQueryTable; @@ -218,6 +215,8 @@ class NatOrch: public Orch, public Subject, public Observer string m_dbgCompName; IpAddress nullIpv4Addr; + std::shared_ptr setTimeoutNotifier; + /* DNAT/DNAPT entry is cached, to delete and re-add it whenever the direct NextHop (connected neighbor) * or indirect NextHop (via route) to reach the DNAT IP is changed. */ DnatNhResolvCache m_nhResolvCache; @@ -283,31 +282,14 @@ class NatOrch: public Orch, public Subject, public Observer bool removeHwDnatEntry(const IpAddress &dstIp); bool removeHwDnaptEntry(const NaptEntryKey &key); - void addAllStaticConntrackEntries(void); - void addConnTrackEntry(const IpAddress &ipAddr); - void addConnTrackEntry(const NaptEntryKey &key); - void addConnTrackEntry(const TwiceNatEntryKey &key); - void addConnTrackEntry(const TwiceNaptEntryKey &key); - void updateConnTrackTimeout(string prototype); - void updateConnTrackTimeout(const IpAddress &sourceIpAddr); - void updateConnTrackTimeout(const NaptEntryKey &entry); - void updateConnTrackTimeout(const TwiceNatEntryKey &entry); - void updateConnTrackTimeout(const TwiceNaptEntryKey &entry); - void deleteConnTrackEntry(const IpAddress &ipAddr); - void deleteConnTrackEntry(const NaptEntryKey &key); - void deleteConnTrackEntry(const TwiceNatEntryKey &key); - void deleteConnTrackEntry(const TwiceNaptEntryKey &key); - bool checkIfNatEntryIsActive(const NatEntry::iterator &iter, time_t now); bool checkIfNaptEntryIsActive(const NaptEntry::iterator &iter, time_t now); bool checkIfTwiceNatEntryIsActive(const TwiceNatEntry::iterator &iter, time_t now); bool checkIfTwiceNaptEntryIsActive(const TwiceNaptEntry::iterator &iter, time_t now); - bool warmBootingInProgress(void); void enableNatFeature(void); void disableNatFeature(void); void addAllNatEntries(void); - void flushAllNatEntries(void); void clearAllDnatEntries(void); void cleanupAppDbEntries(void); void clearCounters(void); @@ -344,6 +326,8 @@ class NatOrch: public Orch, public Subject, public Observer uint64_t nat_translations_pkts, uint64_t nat_translations_bytes); void updateTwiceNaptCounters(const TwiceNaptEntryKey &key, uint64_t nat_translations_pkts, uint64_t nat_translations_bytes); + + void updateAllConntrackEntries(); }; #endif /* SWSS_NATORCH_H */ diff --git a/tests/test_nat.py b/tests/test_nat.py index 6b89e44e0456..5bfa1a96f380 100644 --- a/tests/test_nat.py +++ b/tests/test_nat.py @@ -277,3 +277,42 @@ def test_DelTwiceNaPtStaticEntry(self, dvs, testlog): # clear interfaces self.clear_interfaces(dvs) + + def test_VerifyConntrackTimeoutForNatEntry(self, dvs, testlog): + # initialize + self.setup_db(dvs) + + # get neighbor and arp entry + dvs.servers[0].runcmd("ping -c 1 18.18.18.2") + + # add a static nat entry + dvs.runcmd("config nat add static basic 67.66.65.1 18.18.18.2") + + # check the conntrack timeout for static entry + output = dvs.runcmd("conntrack -j -L -s 18.18.18.2 -p udp -q 67.66.65.1") + assert len(output) == 2 + + conntrack_list = list(output[1].split(" ")) + + src_exists = dst_exists = proto_exists = False + proto_index = 0 + + for i in conntrack_list: + if i == "src=18.18.18.2": + src_exists = True + elif i == "dst=67.66.65.1": + dst_exists = True + elif i == "udp": + proto_exists = True + proto_index = conntrack_list.index(i) + + assert src_exists == True + assert dst_exists == True + assert proto_exists == True + + if conntrack_list[proto_index + 7] < 432000 and conntrack_list[proto_index + 7] > 431900: + assert False + + # delete a static nat entry + dvs.runcmd("config nat remove static basic 67.66.65.1 18.18.18.2") +