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 std::string HostStatus::log_prefix()
80 std::stringstream temp;
81 temp << "Stat(" << HostAddress << "): "
82 << PingsFailedCount << " fail," << PingCongestionCount << " cong/"
83 << PingsPerformedCount << " pings/" << ResolvedIpCount << "*"
84 << NParallelPingers << " IPs: ";
88 * @param resolved_ip_count The number of IPs resolved for the host.
90 void HostStatus::set_resolved_ip_count( const int resolved_ip_count )
92 BOOST_ASSERT( 0 <= resolved_ip_count );
94 if (resolved_ip_count != ResolvedIpCount)
95 { // assume that the target has changed --> reset counters
96 reset_ping_counters();
98 ResolvedIpCount = resolved_ip_count;
100 GlobalLogger.debug() << log_prefix() << "#IPs set";
104 * @return true if the amount of failed pings given to the host exceeded the
107 bool HostStatus::exceeded_ping_failed_limit() const
109 return ExceededPingFailedLimit;
113 * @return true if the amount of congested pings given to the host exceeded the
116 bool HostStatus::exceeded_ping_congestion_limit() const
118 return ExceededPingCongestionLimit;
122 * Tells the status analyzer how the last ping went
124 * @param result: status of ping specifying success/failure and reason of fail
125 * @param ping_duration_us duration of ping in micro seconds
127 void HostStatus::update_ping_statistics( const PingStatus &result,
128 const long ping_duration_us )
130 float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.;
132 GlobalLogger.debug() << log_prefix() << "add ping with result "
133 << to_string(result) << " which took " << ping_duration_ms << " ms";
135 BOOST_ASSERT( 1 <= ResolvedIpCount );
136 BOOST_ASSERT( 0 <= PingsPerformedCount );
137 BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
138 BOOST_ASSERT( PingCongestionCount <= PingsPerformedCount );
140 update_fail_stats( result );
141 update_congestion_stats( result, ping_duration_us );
143 // after we tried all IPs resolved for this host, we can analyze how many
145 if ( tried_all_resolved_ip() )
147 analyze_ping_statistics();
149 reset_ping_counters();
152 BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
153 BOOST_ASSERT( PingCongestionCount <= PingsPerformedCount );
157 void HostStatus::update_fail_stats( const PingStatus &result)
159 increase_ping_performed_count();
161 if ( result != PingStatus_SuccessReply
162 && result != PingStatus_SuccessOutdatedIP)
164 increase_ping_failed_count();
167 analyze_ping_failed_count();
171 void HostStatus::update_congestion_stats( const PingStatus &result,
172 const long ping_duration_us )
174 if (ping_duration_us > PingDurationCongestionsThresh)
175 increase_ping_congestion_count();
176 else if ( result == PingStatus_FailureTimeout )
177 increase_ping_congestion_count();
178 // PingStatus_FailureNoIP, PingStatus_SuccessOutdatedIP could also be caused
179 // by congestion, but also by other reasons (e.g. firewall blocking port 53)
181 analyze_ping_congestion_count();
185 bool HostStatus::tried_all_resolved_ip() const
187 BOOST_ASSERT( ( 0 < PingsPerformedCount ) &&
188 ( PingsPerformedCount <= ResolvedIpCount*NParallelPingers ) );
190 return ( PingsPerformedCount == ResolvedIpCount*NParallelPingers );
193 void HostStatus::analyze_ping_statistics()
195 BOOST_ASSERT( !HostAddress.empty() );
196 BOOST_ASSERT( PingsPerformedCount == ResolvedIpCount*NParallelPingers );
198 // notify if the amount of pings that failed exceed the limit
199 if ( exceeded_ping_failed_limit() )
201 GlobalLogger.debug() << log_prefix() << "notify down";
202 LinkAnalyzer->notify_host_down( HostAddress );
206 GlobalLogger.debug() << log_prefix() << "notify up";
207 LinkAnalyzer->notify_host_up( HostAddress );
210 // nothing to do about congestion here, congestion is not forwarded to
211 // central LinkAnalyzer
214 void HostStatus::reset_ping_counters()
216 PingsPerformedCount = 0;
217 PingsFailedCount = 0;
218 PingCongestionCount = 0;
221 void HostStatus::increase_ping_performed_count()
223 ++PingsPerformedCount;
225 BOOST_ASSERT( ( 0 < PingsPerformedCount ) &&
226 ( PingsPerformedCount <= ResolvedIpCount*NParallelPingers ) );
229 void HostStatus::increase_ping_failed_count()
233 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
236 void HostStatus::increase_ping_congestion_count()
238 ++PingCongestionCount;
240 BOOST_ASSERT( ( 0 <= PingCongestionCount )
241 && ( PingCongestionCount <= PingsPerformedCount ) );
244 void HostStatus::analyze_ping_failed_count()
246 BOOST_ASSERT( ( 0 <= PingFailLimitPercentage ) && ( PingFailLimitPercentage <= 100 ) );
247 BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
249 int ping_fail_limit_count = ( ResolvedIpCount * PingFailLimitPercentage
250 * NParallelPingers) / 100;
252 // keep a boolean variable because the PingsFailedCount can be reseted
253 if ( PingsFailedCount > ping_fail_limit_count )
255 ExceededPingFailedLimit = true;
257 GlobalLogger.debug() << log_prefix() << "exceed fail limit="
258 << ping_fail_limit_count;
262 ExceededPingFailedLimit = false;
264 GlobalLogger.debug() << log_prefix() << "below fail limit="
265 << ping_fail_limit_count;
269 void HostStatus::analyze_ping_congestion_count()
271 BOOST_ASSERT( ( 0 <= PingCongestionLimitPercentage )
272 && ( PingCongestionLimitPercentage <= 100 ) );
273 BOOST_ASSERT( ( 0 <= PingCongestionCount )
274 && ( PingCongestionCount <= PingsPerformedCount ) );
276 int ping_congestion_limit_count = ( ResolvedIpCount * NParallelPingers
277 * PingCongestionLimitPercentage ) / 100;
279 // keep a boolean variable because the PingCongestionCount can be reseted
280 if ( PingCongestionCount > ping_congestion_limit_count )
282 ExceededPingCongestionLimit = true;
284 GlobalLogger.debug() << log_prefix() << "exceed congestion limit="
285 << ping_congestion_limit_count;
289 ExceededPingCongestionLimit = false;
291 GlobalLogger.debug() << log_prefix() << "below congestion limit="
292 << ping_congestion_limit_count;