2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
20 #include "host/hoststatus.h"
23 #include <logfunc.hpp>
25 #include "boost_assert_handler.h"
28 using I2n::Logger::GlobalLogger;
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
35 * @param host_address The address of the host it has to analyze.
36 * @param ping_fail_percentage_limit The percentage threshold of pings that can
38 * @param ping_congestion_limit_percentage The percentage threshold of pings
39 * that can fail due to line congestion
40 * @param ping_duration_congestion_thresh Threshold in micro seconds that marks
41 * the difference between a "normal" and a congested line
42 * @param n_parallel_pings Number of pings that is sent for each IP
43 * @param link_analyzer The object used to notify the status of the host.
45 HostStatus::HostStatus(
46 const string &host_address,
47 const int ping_fail_limit_percentage,
48 const int ping_congestion_limit_percentage,
49 const int ping_duration_congestion_thresh,
50 const int n_parallel_pings,
51 const LinkStatusItem link_analyzer
53 HostAddress( host_address ),
54 LinkAnalyzer( link_analyzer ),
55 PingFailLimitPercentage( ping_fail_limit_percentage ),
56 PingCongestionLimitPercentage( ping_congestion_limit_percentage ),
57 PingDurationCongestionsThresh( ping_duration_congestion_thresh*1000000 ),
59 PingsPerformedCount( 0 ),
60 PingsFailedCount( 0 ),
61 PingCongestionCount( 0 ),
62 ExceededPingFailedLimit( false ),
63 ExceededPingCongestionLimit( false ),
64 NParallelPingers( n_parallel_pings)
66 BOOST_ASSERT( !HostAddress.empty() );
67 BOOST_ASSERT( ( 0 <= PingFailLimitPercentage )
68 && ( PingFailLimitPercentage <= 100 ) );
69 BOOST_ASSERT( ( 0 <= PingCongestionLimitPercentage )
70 && ( PingCongestionLimitPercentage <= 100 ) );
73 HostStatus::~HostStatus()
78 void HostStatus::set_n_parallel_pings(const int n_parallel_pings)
80 if (NParallelPingers != n_parallel_pings)
82 NParallelPingers = n_parallel_pings;
83 reset_ping_counters();
85 GlobalLogger.debug() << log_prefix() << "#pingers set";
89 std::string HostStatus::log_prefix()
91 std::stringstream temp;
92 temp << "Stat(" << HostAddress << "): "
93 << PingsFailedCount << " fail," << PingCongestionCount << " cong/"
94 << PingsPerformedCount << " pings/" << ResolvedIpCount << "*"
95 << NParallelPingers << " IPs: ";
100 * @param resolved_ip_count The number of IPs resolved for the host.
102 void HostStatus::set_resolved_ip_count( const int resolved_ip_count )
104 BOOST_ASSERT( 0 <= resolved_ip_count );
106 if (resolved_ip_count != ResolvedIpCount)
107 { // assume that the target has changed --> reset counters
108 reset_ping_counters();
110 ResolvedIpCount = resolved_ip_count;
112 GlobalLogger.debug() << log_prefix() << "#IPs set";
116 * @return true if the amount of failed pings given to the host exceeded the
119 bool HostStatus::exceeded_ping_failed_limit() const
121 return ExceededPingFailedLimit;
125 * @return true if the amount of congested pings given to the host exceeded the
128 bool HostStatus::exceeded_ping_congestion_limit() const
130 return ExceededPingCongestionLimit;
134 * Tells the status analyzer how the last ping went
136 * @param result: status of ping specifying success/failure and reason of fail
137 * @param ping_duration_us duration of ping in micro seconds
139 void HostStatus::update_ping_statistics( const PingStatus &result,
140 const long ping_duration_us )
142 float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.0f;
144 GlobalLogger.debug() << log_prefix() << "add ping with result "
145 << to_string(result) << " which took " << ping_duration_ms << " ms";
147 BOOST_ASSERT( 1 <= ResolvedIpCount );
148 BOOST_ASSERT( 0 <= PingsPerformedCount );
149 BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
150 BOOST_ASSERT( PingCongestionCount <= PingsPerformedCount );
152 update_fail_stats( result );
153 update_congestion_stats( result, ping_duration_us );
155 // after we tried all IPs resolved for this host, we can analyze how many
157 if ( tried_all_resolved_ip() )
159 analyze_ping_statistics();
161 reset_ping_counters();
164 BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
165 BOOST_ASSERT( PingCongestionCount <= PingsPerformedCount );
169 void HostStatus::update_fail_stats( const PingStatus &result)
171 increase_ping_performed_count();
173 if ( result != PingStatus_SuccessReply
174 && result != PingStatus_SuccessOutdatedIP)
176 increase_ping_failed_count();
179 analyze_ping_failed_count();
183 void HostStatus::update_congestion_stats( const PingStatus &result,
184 const long ping_duration_us )
186 if (ping_duration_us > PingDurationCongestionsThresh)
187 increase_ping_congestion_count();
188 else if ( result == PingStatus_FailureTimeout )
189 increase_ping_congestion_count();
190 // PingStatus_FailureNoIP, PingStatus_SuccessOutdatedIP could also be caused
191 // by congestion, but also by other reasons (e.g. firewall blocking port 53)
193 analyze_ping_congestion_count();
197 bool HostStatus::tried_all_resolved_ip() const
199 BOOST_ASSERT( ( 0 < PingsPerformedCount ) &&
200 ( PingsPerformedCount <= ResolvedIpCount*NParallelPingers ) );
202 return ( PingsPerformedCount == ResolvedIpCount*NParallelPingers );
205 void HostStatus::analyze_ping_statistics()
207 BOOST_ASSERT( !HostAddress.empty() );
208 BOOST_ASSERT( PingsPerformedCount == ResolvedIpCount*NParallelPingers );
210 // notify if the amount of pings that failed exceed the limit
211 if ( exceeded_ping_failed_limit() )
213 GlobalLogger.debug() << log_prefix() << "notify down";
214 LinkAnalyzer->notify_host_down( HostAddress );
218 GlobalLogger.debug() << log_prefix() << "notify up";
219 LinkAnalyzer->notify_host_up( HostAddress );
222 // nothing to do about congestion here, congestion is not forwarded to
223 // central LinkAnalyzer
226 void HostStatus::reset_ping_counters()
228 PingsPerformedCount = 0;
229 PingsFailedCount = 0;
230 PingCongestionCount = 0;
233 void HostStatus::increase_ping_performed_count()
235 ++PingsPerformedCount;
237 BOOST_ASSERT( ( 0 < PingsPerformedCount ) &&
238 ( PingsPerformedCount <= ResolvedIpCount*NParallelPingers ) );
241 void HostStatus::increase_ping_failed_count()
245 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
248 void HostStatus::increase_ping_congestion_count()
250 ++PingCongestionCount;
252 BOOST_ASSERT( ( 0 <= PingCongestionCount )
253 && ( PingCongestionCount <= PingsPerformedCount ) );
256 void HostStatus::analyze_ping_failed_count()
258 BOOST_ASSERT( ( 0 <= PingFailLimitPercentage ) && ( PingFailLimitPercentage <= 100 ) );
259 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
261 int ping_fail_limit_count = ( ResolvedIpCount * PingFailLimitPercentage
262 * NParallelPingers) / 100;
264 // keep a boolean variable because the PingsFailedCount can be reseted
265 if ( PingsFailedCount > ping_fail_limit_count )
267 ExceededPingFailedLimit = true;
269 GlobalLogger.debug() << log_prefix() << "exceed fail limit="
270 << ping_fail_limit_count;
274 ExceededPingFailedLimit = false;
276 GlobalLogger.debug() << log_prefix() << "below fail limit="
277 << ping_fail_limit_count;
281 void HostStatus::analyze_ping_congestion_count()
283 BOOST_ASSERT( ( 0 <= PingCongestionLimitPercentage )
284 && ( PingCongestionLimitPercentage <= 100 ) );
285 BOOST_ASSERT( ( 0 <= PingCongestionCount )
286 && ( PingCongestionCount <= PingsPerformedCount ) );
288 int ping_congestion_limit_count = ( ResolvedIpCount * NParallelPingers
289 * PingCongestionLimitPercentage ) / 100;
291 // keep a boolean variable because the PingCongestionCount can be reseted
292 if ( PingCongestionCount > ping_congestion_limit_count )
294 ExceededPingCongestionLimit = true;
296 GlobalLogger.debug() << log_prefix() << "exceed congestion limit="
297 << ping_congestion_limit_count;
301 ExceededPingCongestionLimit = false;
303 GlobalLogger.debug() << log_prefix() << "below congestion limit="
304 << ping_congestion_limit_count;