Merge "IPACM: Fix conntrack event comes earlier than new neighbor"
diff --git a/ipacm/inc/IPACM_LanToLan.h b/ipacm/inc/IPACM_LanToLan.h
index 570db14..06d5832 100644
--- a/ipacm/inc/IPACM_LanToLan.h
+++ b/ipacm/inc/IPACM_LanToLan.h
@@ -69,6 +69,7 @@
typedef list<peer_info> peer_info_list;
typedef list<offload_link_info> offload_link_info_list;
+typedef list<ipacm_event_connection> connection_list;
struct client_info
{
@@ -114,6 +115,9 @@
client_table_v4 client_info_v4_;
client_table_v6 client_info_v6_;
+ connection_list connection_v4_;
+ connection_list connection_v6_;
+
static IPACM_LanToLan* p_instance;
void event_callback(ipa_cm_event_id event, void* param);
@@ -158,6 +162,14 @@
bool is_lan2lan_connection(ipacm_event_connection* data);
+ bool is_potential_lan2lan_connection(ipacm_event_connection* new_conn);
+
+ void cache_new_connection(ipacm_event_connection* new_conn);
+
+ void remove_cache_connection(ipacm_event_connection* del_conn);
+
+ void check_cache_connection(ipa_ip_type iptype, client_info* client);
+
};
#endif
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index 448fa8f..d8fe726 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -196,7 +196,7 @@
return -1;
}
IPACMDBG("Interface (%s) address %s\n", ifr.ifr_name, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
- ipv4_addr = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
+ ipv4_addr = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
close(fd);
/* ignore whatever is destined to or originates from broadcast ip address */
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index 239d6f4..ae11d34 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -60,7 +60,6 @@
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, this);
IPACMDBG("creating conntrack threads\n");
- CreateConnTrackThreads();
#ifdef CT_OPT
p_lan2lan = IPACM_LanToLan::getLan2LanInstance();
@@ -94,6 +93,7 @@
case IPA_HANDLE_WAN_UP:
IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ CreateConnTrackThreads();
if(!isWanUp())
{
TriggerWANUp(data);
@@ -116,7 +116,8 @@
IPACMDBG("Received event: %d with ifname: %s and address: 0x%x\n",
evt, ((ipacm_event_iface_up *)data)->ifname,
((ipacm_event_iface_up *)data)->ipv4_addr);
- IPACM_ConntrackClient::UpdateUDPFilters(data, false);
+ CreateConnTrackThreads();
+ IPACM_ConntrackClient::UpdateUDPFilters(data, false);
IPACM_ConntrackClient::UpdateTCPFilters(data, false);
break;
diff --git a/ipacm/src/IPACM_LanToLan.cpp b/ipacm/src/IPACM_LanToLan.cpp
index dcd7a08..dcb95b4 100644
--- a/ipacm/src/IPACM_LanToLan.cpp
+++ b/ipacm/src/IPACM_LanToLan.cpp
@@ -43,6 +43,11 @@
#include "IPACM_LanToLan.h"
#include "IPACM_Wlan.h"
+#define ipv6_multicast_addr 0xff000000
+#define ipv6_multicast_mask 0xff000000
+
+#define max_cache_connection 20
+
IPACM_LanToLan* IPACM_LanToLan::p_instance = NULL;
IPACM_LanToLan::IPACM_LanToLan()
@@ -209,6 +214,7 @@
client_ptr->p_iface = data->p_iface;
generate_new_connection(data->iptype, client_ptr);
+ check_cache_connection(data->iptype, client_ptr);
}
else //the client is found
{
@@ -239,6 +245,7 @@
client_ptr->p_iface = data->p_iface;
generate_new_connection(data->iptype, client_ptr);
+ check_cache_connection(data->iptype, client_ptr);
}
}
else //the client is inactive
@@ -259,6 +266,7 @@
check_potential_link(data->iptype, client_ptr);
generate_new_connection(data->iptype, client_ptr);
+ check_cache_connection(data->iptype, client_ptr);
}
}
IPACMDBG("There are %d clients in v4 table and %d clients in v6 table.\n", client_info_v4_.size(), client_info_v6_.size());
@@ -1288,6 +1296,7 @@
if(is_lan2lan_connection(new_conn) == false)
{
IPACMDBG("The connection is not lan2lan connection.\n");
+ cache_new_connection(new_conn);
return;
}
@@ -1331,6 +1340,7 @@
if(is_lan2lan_connection(new_conn) == false)
{
IPACMDBG("The connection is not lan2lan connection.\n");
+ remove_cache_connection(new_conn);
return;
}
@@ -1393,3 +1403,203 @@
{
return p_instance;
}
+
+bool IPACM_LanToLan::is_potential_lan2lan_connection(ipacm_event_connection* new_conn)
+{
+ int i, num_private_subnet;
+ bool src_is_valid = false;
+ bool dst_is_valid = false;
+
+ if(new_conn->iptype == IPA_IP_v4)
+ {
+ num_private_subnet = IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+ for(i=0; i<num_private_subnet; i++)
+ {
+ if( (new_conn->src_ipv4_addr & IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask)
+ == (IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr & IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask) )
+ {
+ src_is_valid = true;
+ }
+ if( (new_conn->dst_ipv4_addr & IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask)
+ == (IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr & IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask) )
+ {
+ dst_is_valid = true;
+ }
+ }
+
+ if(src_is_valid && dst_is_valid)
+ {
+ IPACMDBG("Both src and dst are potentially in subnet.\n");
+ return true;
+ }
+ }
+ else
+ {
+ if( (new_conn->src_ipv6_addr[0] & ipv6_multicast_mask) != (ipv6_multicast_addr & ipv6_multicast_mask) )
+ {
+ src_is_valid = true;
+ }
+ if( (new_conn->dst_ipv6_addr[0] & ipv6_multicast_mask) != (ipv6_multicast_addr & ipv6_multicast_mask) )
+ {
+ dst_is_valid = true;
+ }
+
+ if(src_is_valid && dst_is_valid)
+ {
+ IPACMDBG("Both src and dst are potentially in subnet.\n");
+ return true;
+ }
+ }
+
+ IPACMDBG("This connection is not a lan2lan connection potentially.\n");
+ return false;
+}
+
+void IPACM_LanToLan::cache_new_connection(ipacm_event_connection* new_conn)
+{
+ if(is_potential_lan2lan_connection(new_conn) == true)
+ {
+ if(new_conn->iptype == IPA_IP_v4)
+ {
+ if(connection_v4_.size() == max_cache_connection)
+ {
+ IPACMDBG("Cached ipv4 connections already reach maximum, clear up the list.\n");
+ connection_v4_.clear();
+ }
+
+ connection_v4_.push_back(*new_conn);
+ IPACMDBG("Cache an ipv4 connection, now the number of ipv4 cache connection is %d.\n", connection_v4_.size());
+ }
+ else
+ {
+ if(connection_v6_.size() == max_cache_connection)
+ {
+ IPACMDBG("Cached ipv6 connections already reach maximum, clear up the list.\n");
+ connection_v6_.clear();
+ }
+
+ connection_v6_.push_back(*new_conn);
+ IPACMDBG("Cache an ipv6 connection, now the number of ipv6 cache connection is %d.\n", connection_v6_.size());
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::remove_cache_connection(ipacm_event_connection* del_conn)
+{
+ connection_list::iterator it;
+ if(is_potential_lan2lan_connection(del_conn) == true)
+ {
+ if(del_conn->iptype == IPA_IP_v4)
+ {
+ for(it = connection_v4_.begin(); it != connection_v4_.end(); it++)
+ {
+ if(it->src_ipv4_addr == del_conn->src_ipv4_addr && it->dst_ipv4_addr == del_conn->dst_ipv4_addr)
+ {
+ IPACMDBG("Find the cached ipv4 connection, remove it from list.\n");
+ connection_v4_.erase(it);
+ IPACMDBG("Now the number of ipv4 cache connection is %d.\n", connection_v4_.size());
+ return;
+ }
+ }
+ IPACMDBG("Do not find the cached ipv4 connection, do nothing.\n");
+ }
+ else
+ {
+ for(it = connection_v6_.begin(); it != connection_v6_.end(); it++)
+ {
+ if(memcmp(it->src_ipv6_addr, del_conn->src_ipv6_addr, 4*sizeof(uint32_t)) == 0
+ && memcmp(it->dst_ipv6_addr, del_conn->dst_ipv6_addr, 4*sizeof(uint32_t)) == 0 )
+ {
+ IPACMDBG("Find the cached ipv6 connection, remove it from list.\n");
+ connection_v6_.erase(it);
+ IPACMDBG("Now the number of ipv6 cache connection is %d.\n", connection_v6_.size());
+ return;
+ }
+ }
+ IPACMDBG("Do not find the cached ipv6 connection, do nothing.\n");
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::check_cache_connection(ipa_ip_type iptype, client_info* client)
+{
+#ifdef CT_OPT
+ connection_list::iterator it;
+ if(iptype == IPA_IP_v4)
+ {
+ it = connection_v4_.begin();
+ while(it != connection_v4_.end())
+ {
+ if( (it->src_ipv4_addr == client->ip.ipv4_addr && client_info_v4_.count(it->dst_ipv4_addr) > 0)
+ || (it->dst_ipv4_addr == client->ip.ipv4_addr && client_info_v4_.count(it->src_ipv4_addr) > 0) )
+ {
+ IPACMDBG("Found a cache connection for src client 0x%08x and dst client 0x%08x.\n", it->src_ipv4_addr, it->dst_ipv4_addr);
+ ipacm_cmd_q_data evt;
+ ipacm_event_connection* conn;
+
+ conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
+ if(conn == NULL)
+ {
+ IPACMERR("Failed to allocate memory for new_connection event.\n");
+ return;
+ }
+ memcpy(conn, &(*it), sizeof(ipacm_event_connection));
+
+ memset(&evt, 0, sizeof(evt));
+ evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION;
+ evt.evt_data = (void*)conn;
+ IPACM_EvtDispatcher::PostEvt(&evt);
+
+ it = connection_v4_.erase(it);
+ IPACMDBG("Now the number of cache connections is %d.\n", connection_v4_.size());
+ }
+ else
+ {
+ it++;
+ }
+ }
+ }
+ else
+ {
+ uint64_t src_v6_addr, dst_v6_addr;
+ it = connection_v6_.begin();
+ while(it != connection_v6_.end())
+ {
+ memcpy(&src_v6_addr, &(it->src_ipv6_addr[2]), sizeof(uint64_t));
+ memcpy(&dst_v6_addr, &(it->dst_ipv6_addr[2]), sizeof(uint64_t));
+ if( (memcmp(it->src_ipv6_addr, client->ip.ipv6_addr, 4*sizeof(uint32_t)) == 0 && client_info_v6_.count(dst_v6_addr) > 0)
+ || (memcmp(it->dst_ipv6_addr, client->ip.ipv6_addr, 4*sizeof(uint32_t)) == 0 && client_info_v6_.count(src_v6_addr) > 0) )
+ {
+ IPACMDBG("Found a cache connection with src client 0x%08x%08x%08x%08x and dst client 0x%08x%08x%08x%08x.\n", it->src_ipv6_addr[0],
+ it->src_ipv6_addr[1], it->src_ipv6_addr[2], it->src_ipv6_addr[3], it->dst_ipv6_addr[0], it->dst_ipv6_addr[1],
+ it->dst_ipv6_addr[2], it->dst_ipv6_addr[3]);
+ ipacm_cmd_q_data evt;
+ ipacm_event_connection* conn;
+
+ conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
+ if(conn == NULL)
+ {
+ IPACMERR("Failed to allocate memory for new_connection event.\n");
+ return;
+ }
+ memcpy(conn, &(*it), sizeof(ipacm_event_connection));
+
+ memset(&evt, 0, sizeof(evt));
+ evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION;
+ evt.evt_data = (void*)conn;
+ IPACM_EvtDispatcher::PostEvt(&evt);
+
+ it = connection_v6_.erase(it);
+ IPACMDBG("Now the number of cache connections is %d.\n", connection_v6_.size());
+ }
+ else
+ {
+ it++;
+ }
+ }
+ }
+#endif
+ return;
+}