diff --git a/include/GenericHash.h b/include/GenericHash.h index cbe0a136df..a528c992a1 100644 --- a/include/GenericHash.h +++ b/include/GenericHash.h @@ -99,9 +99,12 @@ class GenericHash { /** * @brief Purge idle hash entries. * + * @param force_idle Forcefully marks all hash_entry_state_active entries to + * hash_entry_state_idle + * * @return Numbers of purged entry, 0 otherwise. */ - u_int purgeIdle(); + u_int purgeIdle(bool force_idle); /** * @brief Purge all hash entries. diff --git a/src/GenericHash.cpp b/src/GenericHash.cpp index ab090a2cb2..64d556b5cf 100644 --- a/src/GenericHash.cpp +++ b/src/GenericHash.cpp @@ -76,13 +76,6 @@ bool GenericHash::add(GenericHashEntry *h, bool do_lock) { if(hasEmptyRoom()) { u_int32_t hash = (h->key() % num_hashes); - if(false) { - char buf[256]; - - ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s(): adding %s/%u", - __FUNCTION__, h->get_string_key(buf, sizeof(buf)), h->key()); - } - if(do_lock) locks[hash]->lock(__FILE__, __LINE__); @@ -176,19 +169,18 @@ bool GenericHash::walk(u_int32_t *begin_slot, Active -> Idle -> Ready to be Purged -> Purged */ -u_int GenericHash::purgeIdle() { +u_int GenericHash::purgeIdle(bool force_idle) { u_int i, num_purged = 0, buckets_checked = 0; time_t now = time(NULL); - - if(ntop->getGlobals()->isShutdown()) - return(0); + /* Visit all entries when force_idle is true */ + u_int visit_fraction = !force_idle ? purge_step : num_hashes; #if WALK_DEBUG - ntop->getTrace()->traceEvent(TRACE_NORMAL, "[%s @ %s] Begin purgeIdle() [begin index: %u][purge step: %u]", - name, iface->get_name(), last_purged_hash, purge_step); + ntop->getTrace()->traceEvent(TRACE_NORMAL, "[%s @ %s] Begin purgeIdle() [begin index: %u][purge step: %u][force_idle: %u]", + name, iface->get_name(), last_purged_hash, visit_fraction, force_idle ? 1 : 0); #endif - for(u_int j = 0; j < purge_step; j++) { + for(u_int j = 0; j < visit_fraction; j++) { if(++last_purged_hash == num_hashes) last_purged_hash = 0; i = last_purged_hash; @@ -224,7 +216,8 @@ u_int GenericHash::purgeIdle() { /* Do the chores */ head->housekeep(now); - if((head_state == hash_entry_state_active) && head->idle()) + if(head_state == hash_entry_state_active + && (head->idle() || force_idle)) head->set_hash_entry_state_idle(); prev = head; diff --git a/src/GenericHashEntry.cpp b/src/GenericHashEntry.cpp index b549f67788..5e51203c82 100644 --- a/src/GenericHashEntry.cpp +++ b/src/GenericHashEntry.cpp @@ -69,11 +69,7 @@ void GenericHashEntry::set_state(HashEntryState s) { /* ***************************************** */ HashEntryState GenericHashEntry::get_state() { - /* When the interface is no longer running it is safe to assume the entry is idle */ - if(iface && (!iface->isRunning())) - set_hash_entry_state_idle(); - - return(hash_entry_state); + return hash_entry_state; }; /* ***************************************** */ diff --git a/src/HTTPstats.cpp b/src/HTTPstats.cpp index eff1241cf5..361d46c916 100644 --- a/src/HTTPstats.cpp +++ b/src/HTTPstats.cpp @@ -560,7 +560,7 @@ void HTTPstats::updateStats(struct timeval *tv) { bool walk_all = true; virtualHosts->walk(&begin_slot, walk_all, update_http_stats, tv); - virtualHosts->purgeIdle(); + virtualHosts->purgeIdle(false); } for(u_int8_t i = 0; i < 2 ; i++) { diff --git a/src/NetworkInterface.cpp b/src/NetworkInterface.cpp index 26ddd89707..281d7cb240 100644 --- a/src/NetworkInterface.cpp +++ b/src/NetworkInterface.cpp @@ -2783,6 +2783,8 @@ void NetworkInterface::shutdown() { if(isRunning()) { running = false; pthread_join(pollLoop, &res); + /* purgeIdle one last time to make sure all entries will be marked as idle */ + purgeIdle(time(NULL)); } } @@ -5181,6 +5183,7 @@ void NetworkInterface::getNetworksStats(lua_State* vm) const { u_int NetworkInterface::purgeIdleFlows() { u_int n = 0; time_t last_packet_time = getTimeLastPktRcvd(); + bool force_idle = !isRunning(); pollQueuedeBPFEvents(); reloadCustomCategories(); @@ -5188,10 +5191,7 @@ u_int NetworkInterface::purgeIdleFlows() { if(!purge_idle_flows_hosts) return(0); - if(next_idle_flow_purge == 0) { - next_idle_flow_purge = last_packet_time + FLOW_PURGE_FREQUENCY; - return(0); - } else if(last_packet_time < next_idle_flow_purge) + if(!force_idle && last_packet_time < next_idle_flow_purge) return(0); /* Too early */ else { /* Time to purge flows */ @@ -5201,7 +5201,7 @@ u_int NetworkInterface::purgeIdleFlows() { "Purging idle flows [ifname: %s] [ifid: %i] [current size: %i]", ifname, id, flows_hash->getCurrentSize()); #endif - n = (flows_hash ? flows_hash->purgeIdle() : 0); + n = (flows_hash ? flows_hash->purgeIdle(force_idle) : 0); next_idle_flow_purge = last_packet_time + FLOW_PURGE_FREQUENCY; return(n); @@ -5272,27 +5272,26 @@ u_int NetworkInterface::getNumArpStatsMatrixElements() { u_int NetworkInterface::purgeIdleHostsMacsASesVlans() { time_t last_packet_time = getTimeLastPktRcvd(); + bool force_idle = !isRunning(); if(!purge_idle_flows_hosts) return(0); - if(next_idle_host_purge == 0) { - next_idle_host_purge = last_packet_time + HOST_PURGE_FREQUENCY; - return(0); - } else if(last_packet_time < next_idle_host_purge) + if(!force_idle && last_packet_time < next_idle_host_purge) return(0); /* Too early */ else { /* Time to purge hosts */ u_int n; + /* If the interface is no longer running it is safe to force all entries as idle */ // ntop->getTrace()->traceEvent(TRACE_INFO, "Purging idle hosts"); - n = (hosts_hash ? hosts_hash->purgeIdle() : 0) - + (macs_hash ? macs_hash->purgeIdle() : 0) - + (ases_hash ? ases_hash->purgeIdle() : 0) - + (countries_hash ? countries_hash->purgeIdle() : 0) - + (vlans_hash ? vlans_hash->purgeIdle() : 0); + n = (hosts_hash ? hosts_hash->purgeIdle(force_idle) : 0) + + (macs_hash ? macs_hash->purgeIdle(force_idle) : 0) + + (ases_hash ? ases_hash->purgeIdle(force_idle) : 0) + + (countries_hash ? countries_hash->purgeIdle(force_idle) : 0) + + (vlans_hash ? vlans_hash->purgeIdle(force_idle) : 0); if(arp_hash_matrix) - n += arp_hash_matrix->purgeIdle(); + n += arp_hash_matrix->purgeIdle(force_idle); next_idle_host_purge = last_packet_time + HOST_PURGE_FREQUENCY; return(n);