IPACM: restore old connections when LTE up again
When LTE backhaul quickly down and up again, the old
UDP connections are taking SW-path. The fix is to cache
all current connection entries on Apps and retore the NAT
entries if LTE comes up with same ipv4 address. Also cache
the flows if IPA-NAT tbl haven't created.
Change-Id: Ie7dbac071d3c977507d9dd18985340c454c48e34
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
index 7c97225..1fb12bf 100644
--- a/ipacm/inc/IPACM_Conntrack_NATApp.h
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -52,6 +52,7 @@
uint32_t target_ip;
uint16_t target_port;
+ uint16_t public_ip;
uint16_t public_port;
u_int8_t protocol;
@@ -74,6 +75,7 @@
nat_table_entry *cache;
nat_table_entry temp[MAX_TEMP_ENTRIES];
uint32_t pub_ip_addr;
+ uint32_t pub_ip_addr_pre;
uint32_t nat_table_hdl;
int curCnt, max_entries;
@@ -118,6 +120,7 @@
void UpdateTcpUdpTo(uint32_t, int proto);
void AddTempEntry(const nat_table_entry *);
+ void CacheEntry(const nat_table_entry *);
void DeleteTempEntry(const nat_table_entry *);
void FlushTempEntries(uint32_t, bool);
};
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index d8fe726..9de5911 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -113,19 +113,6 @@
goto IGNORE;
}
- if(!CtList->isWanUp())
- {
-#ifdef IPACM_DEBUG
- IPACMDBG("Wan is not up, ignoring below connections\n");
- char buf[1024];
- nfct_snprintf(buf, sizeof(buf), ct,
- type, NFCT_O_PLAIN, NFCT_OF_TIME);
- IPACMDBG("%s\n", buf);
- IPACMDBG("\n");
- ParseCTMessage(ct);
-#endif
- goto IGNORE;
- }
#endif
ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index e00f921..9e66a00 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -213,6 +213,7 @@
if(nat_iface_ipv4_addr[j] == 0)
{
nat_iface_ipv4_addr[j] = data->ipv4_addr;
+ nat_inst->ResetPwrSaveIf(data->ipv4_addr);
nat_inst->FlushTempEntries(data->ipv4_addr, true);
break;
}
@@ -702,11 +703,13 @@
{
IPACMDBG("orig src ip:0x%x equal to wan ip\n",orig_src_ip);
status = IPS_SRC_NAT;
+ rule.public_ip = wan_ipaddr;
}
else if(orig_dst_ip == wan_ipaddr)
{
IPACMDBG("orig Dst IP:0x%x equal to wan ip\n",orig_dst_ip);
status = IPS_DST_NAT;
+ rule.public_ip = wan_ipaddr;
}
else
{
@@ -933,7 +936,12 @@
if(TCP_CONNTRACK_ESTABLISHED == tcp_state)
{
IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
- if(isTempEntry)
+ if(!CtList->isWanUp())
+ {
+ IPACMDBG("Wan is not up, cache connections\n");
+ nat_inst->CacheEntry(&rule);
+ }
+ else if(isTempEntry)
{
nat_inst->AddTempEntry(&rule);
}
@@ -973,7 +981,12 @@
if(NFCT_T_NEW == type)
{
IPACMDBG("New UDP connection at time %ld\n", time(NULL));
- if(isTempEntry)
+ if(!CtList->isWanUp())
+ {
+ IPACMDBG("Wan is not up, cache connections\n");
+ nat_inst->CacheEntry(&rule);
+ }
+ else if(isTempEntry)
{
nat_inst->AddTempEntry(&rule);
}
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index c4a7e52..0915fda 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -129,8 +129,19 @@
int NatApp::AddTable(uint32_t pub_ip)
{
int ret;
+ int cnt = 0;
+ ipa_nat_ipv4_rule nat_rule;
IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+ /* Not reset the cache wait it timeout by destroy event */
+#if 0
+ if (pub_ip != pub_ip_addr_pre)
+ {
+ IPACMDBG("Reset the cache because NAT-ipv4 different\n");
+ memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+ curCnt = 0;
+ }
+#endif
ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
if(ret)
{
@@ -138,17 +149,56 @@
return ret;
}
+ /* Add back the cashed NAT-entry */
+ if (pub_ip == pub_ip_addr_pre)
+ {
+ IPACMDBG("Restore the cache to ipa NAT-table\n");
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip !=0)
+ {
+ memset(&nat_rule, 0 , sizeof(nat_rule));
+ nat_rule.private_ip = cache[cnt].private_ip;
+ nat_rule.target_ip = cache[cnt].target_ip;
+ nat_rule.target_port = cache[cnt].target_port;
+ nat_rule.private_port = cache[cnt].private_port;
+ nat_rule.public_port = cache[cnt].public_port;
+ nat_rule.protocol = cache[cnt].protocol;
+
+ if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to add the rule delete from cache\n");
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ continue;
+ }
+ cache[cnt].enabled = true;
+
+ IPACMDBG("On wan-iface reset added below rule successfully\n");
+ iptodot("Private IP", nat_rule.private_ip);
+ iptodot("Target IP", nat_rule.target_ip);
+ IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+ IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+ IPACMDBG("protocol: %d\n", nat_rule.protocol);
+ }
+ }
+ }
+
pub_ip_addr = pub_ip;
return 0;
}
void NatApp::Reset()
{
- memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+ int cnt = 0;
nat_table_hdl = 0;
pub_ip_addr = 0;
- curCnt = 0;
+ /* NAT tbl deleted, reset enabled bit */
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ cache[cnt].enabled ==false;
+ }
}
int NatApp::DeleteTable(uint32_t pub_ip)
@@ -172,6 +222,7 @@
return ret;
}
+ pub_ip_addr_pre = pub_ip_addr;
Reset();
return 0;
}
@@ -208,9 +259,7 @@
int cnt = 0;
IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
- CHK_TBL_HDL();
-
- IPACMDBG("Received below nat entry for deletion\n");
+ IPACMDBG("Received below nat entry for deletion\n");
iptodot("Private IP", rule->private_ip);
iptodot("Target IP", rule->target_ip);
IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
@@ -229,8 +278,7 @@
{
if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
{
- IPACMERR("%s() %d\n", __FUNCTION__, __LINE__);
- return -1;
+ IPACMERR("%s() %d deletion failed\n", __FUNCTION__, __LINE__);
}
IPACMDBG("Deleted Nat entry(%d) Successfully\n", cnt);
@@ -525,7 +573,6 @@
}
}
- CHK_TBL_HDL();
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
@@ -579,6 +626,8 @@
for(cnt = 0; cnt < max_entries; cnt++)
{
+ IPACMDBG("cache (%d): enable %d, ip 0x%x\n", cnt, cache[cnt].enabled, cache[cnt].private_ip);
+
if(cache[cnt].private_ip == client_lan_ip &&
cache[cnt].enabled == false)
{
@@ -704,11 +753,14 @@
{
if(isAdd)
{
- ret = AddEntry(&temp[cnt]);
- if(ret)
+ if(temp[cnt].public_ip == pub_ip_addr)
{
- IPACMERR("unable to add temp entry: %d\n", ret);
- continue;
+ ret = AddEntry(&temp[cnt]);
+ if(ret)
+ {
+ IPACMERR("unable to add temp entry: %d\n", ret);
+ continue;
+ }
}
}
memset(&temp[cnt], 0, sizeof(nat_table_entry));
@@ -729,7 +781,6 @@
return -1;
}
- CHK_TBL_HDL();
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
@@ -741,27 +792,28 @@
}
}
- for(cnt = 0; cnt < max_entries; cnt++)
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == ip_addr)
{
- if(cache[cnt].private_ip == ip_addr)
- {
-
- if(cache[cnt].enabled == true)
- {
+ if(cache[cnt].enabled == true)
+ {
if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to delete the rule\n");
continue;
}
- }
-
- memset(&cache[cnt], 0, sizeof(cache[cnt]));
- curCnt--;
- }
+ else
+ {
+ IPACMDBG("won't delete the rule\n");
+ cache[cnt].enabled = false;
+ }
+ }
+ IPACMDBG("won't delete the rule for entry %d, enabled %d\n",cnt, cache[cnt].enabled);
}
-
+ }
IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
- return 0;
+ return 0;
}
int NatApp::DelEntriesOnSTAClntDiscon(uint32_t ip_addr)
@@ -775,7 +827,6 @@
return -1;
}
- CHK_TBL_HDL();
for(cnt = 0; cnt < max_entries; cnt++)
{
@@ -798,3 +849,61 @@
IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
return 0;
}
+
+void NatApp::CacheEntry(const nat_table_entry *rule)
+{
+ int cnt;
+ if(rule->private_ip == 0 ||
+ rule->target_ip == 0 ||
+ rule->private_port == 0 ||
+ rule->target_port == 0 ||
+ rule->protocol == 0)
+ {
+ IPACMERR("Invalid Connection, ignoring it\n");
+ return;
+ }
+
+ if(!ChkForDup(rule))
+ {
+ for(; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == 0 &&
+ cache[cnt].target_ip == 0 &&
+ cache[cnt].private_port == 0 &&
+ cache[cnt].target_port == 0 &&
+ cache[cnt].protocol == 0)
+ {
+ break;
+ }
+ }
+
+ if(max_entries == cnt)
+ {
+ IPACMERR("Error: Unable to add, reached maximum rules\n");
+ return;
+ }
+ else
+ {
+ cache[cnt].enabled = false;
+ cache[cnt].rule_hdl = 0;
+ cache[cnt].private_ip = rule->private_ip;
+ cache[cnt].target_ip = rule->target_ip;
+ cache[cnt].target_port = rule->target_port;
+ cache[cnt].private_port = rule->private_port;
+ cache[cnt].protocol = rule->protocol;
+ cache[cnt].timestamp = 0;
+ cache[cnt].public_port = rule->public_port;
+ cache[cnt].dst_nat = rule->dst_nat;
+ curCnt++;
+ }
+
+ }
+ else
+ {
+ IPACMERR("Duplicate rule. Ignore it\n");
+ return;
+ }
+
+ IPACMDBG("Cached rule(%d) successfully\n", cnt);
+ return;
+}