//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef SHILL_ACTIVE_LINK_MONITOR_H_
#define SHILL_ACTIVE_LINK_MONITOR_H_
#include <time.h>
#include <memory>
#include <string>
#include <base/callback.h>
#include <base/cancelable_callback.h>
#include "shill/metrics.h"
#include "shill/net/byte_string.h"
#include "shill/refptr_types.h"
namespace shill {
class ArpClient;
class DeviceInfo;
class EventDispatcher;
class IOHandler;
class Time;
// ActiveLinkMonitor probes the status of a connection by sending ARP
// messages to the default gateway for a connection. The link will be declared
// as failure if no ARP reply is received for 5 consecutive broadcast ARP
// requests or unicast ARP requests in the case when gateway unicast ARP
// support is established. And active when an ARP reply is received.
// A callback will be invoked when the link is detected as failure or active.
// The active link monitor will automatically stop when the link status is
// determined. It also keeps track of response times which can be an indicator
// of link quality.
class ActiveLinkMonitor {
public:
// FailureCallback takes monitor failure code, broadcast failure count, and
// unicast failure count as arguments.
typedef base::Callback<void(Metrics::LinkMonitorFailure, int, int)>
FailureCallback;
typedef base::Closure SuccessCallback;
// The default number of milliseconds between ARP requests. Needed by Metrics.
static const int kDefaultTestPeriodMilliseconds;
// The number of milliseconds between ARP requests when running a quick test.
// Used when the device just resume from suspend. Also needed by unit tests.
static const int kFastTestPeriodMilliseconds;
// When the sum of consecutive counted unicast and broadcast failures
// equals this value, the failure callback is called, the counters
// are reset, and the link monitoring quiesces. Needed by Metrics.
static const int kFailureThreshold;
ActiveLinkMonitor(const ConnectionRefPtr& connection,
EventDispatcher* dispatcher,
Metrics* metrics,
DeviceInfo* device_info,
const FailureCallback& failure_callback,
const SuccessCallback& success_callback);
virtual ~ActiveLinkMonitor();
// Starts an active link-monitoring cycle on the selected connection, with
// specified |probe_period_millisecond| milliseconds between each ARP
// requests. Returns true if successful, false otherwise.
virtual bool Start(int probe_period_millisecond);
// Stop active link-monitoring on the selected connection. Clears any
// accumulated statistics.
virtual void Stop();
// Return modified cumulative average of the gateway ARP response
// time. Returns zero if no samples are available. For each
// missed ARP response, the sample is assumed to be the full
// test period.
int GetResponseTimeMilliseconds() const;
// Returns true if the ActiveLinkMonitor was ever able to find the default
// gateway via broadcast ARP.
bool IsGatewayFound() const;
virtual const ByteString& gateway_mac_address() const {
return gateway_mac_address_;
}
virtual void set_gateway_mac_address(const ByteString& gateway_mac_address) {
gateway_mac_address_ = gateway_mac_address;
}
virtual bool gateway_supports_unicast_arp() const {
return gateway_supports_unicast_arp_;
}
virtual void set_gateway_supports_unicast_arp(
bool gateway_supports_unicast_arp) {
gateway_supports_unicast_arp_ = gateway_supports_unicast_arp;
}
private:
friend class ActiveLinkMonitorTest;
// The number of samples to compute a "strict" average over. When
// more samples than this number arrive, this determines how "slow"
// our simple low-pass filter works.
static const int kMaxResponseSampleFilterDepth;
// When the sum of consecutive unicast successes equals this value,
// we can assume that in general this gateway supports unicast ARP
// requests, and we will count future unicast failures.
static const int kUnicastReplyReliabilityThreshold;
// Similar to Start, except that the initial probes use
// |probe_period_milliseconds|. After successfully probing with both
// broadcast and unicast ARPs (at least one of each), LinkMonitor
// switches itself to kDefaultTestPeriodMilliseconds.
virtual bool StartInternal(int probe_period_milliseconds);
// Stop the current monitoring cycle. It is called when current monitor cycle
// results in success.
void StopMonitorCycle();
// Add a response time sample to the buffer.
void AddResponseTimeSample(int response_time_milliseconds);
// Start and stop ARP client for sending/receiving ARP requests/replies.
bool StartArpClient();
void StopArpClient();
// Convert a hardware address byte-string to a colon-separated string.
static std::string HardwareAddressToString(const ByteString& address);
// Denote a missed response. Returns true if this loss has caused us
// to exceed the failure threshold.
bool AddMissedResponse();
// This I/O callback is triggered whenever the ARP reception socket
// has data available to be received.
void ReceiveResponse(int fd);
// Send the next ARP request.
void SendRequest();
// The connection on which to perform link monitoring.
ConnectionRefPtr connection_;
// Dispatcher on which to create delayed tasks.
EventDispatcher* dispatcher_;
// Metrics instance on which to post performance results.
Metrics* metrics_;
// DeviceInfo instance for retrieving the MAC address of a device.
DeviceInfo* device_info_;
// Callback methods to call when ActiveLinkMonitor completes a cycle.
FailureCallback failure_callback_;
SuccessCallback success_callback_;
// The MAC address of device associated with this connection.
ByteString local_mac_address_;
// The MAC address of the default gateway.
ByteString gateway_mac_address_;
// ArpClient instance used for performing link tests.
std::unique_ptr<ArpClient> arp_client_;
// How frequently we send an ARP request. This is also the timeout
// for a pending request.
int test_period_milliseconds_;
// The number of consecutive times we have failed in receiving
// responses to broadcast ARP requests.
int broadcast_failure_count_;
// The number of consecutive times we have failed in receiving
// responses to unicast ARP requests.
int unicast_failure_count_;
// The number of consecutive times we have succeeded in receiving
// responses to broadcast ARP requests.
int broadcast_success_count_;
// The number of consecutive times we have succeeded in receiving
// responses to unicast ARP requests.
int unicast_success_count_;
// Whether this iteration of the test was a unicast request
// to the gateway instead of broadcast. The active link monitor
// alternates between unicast and broadcast requests so that
// both types of network traffic is monitored.
bool is_unicast_;
// Whether we have observed that the gateway reliably responds
// to unicast ARP requests.
bool gateway_supports_unicast_arp_;
// Number of response samples received in our rolling averge.
int response_sample_count_;
// The sum of response samples in our rolling average.
int response_sample_bucket_;
// IOCallback that fires when the socket associated with our ArpClient
// has a packet to be received. Calls ReceiveResponse().
std::unique_ptr<IOHandler> receive_response_handler_;
// Callback method used for periodic transmission of ARP requests.
// When the timer expires this will call SendRequest() through the
// void callback function SendRequestTask().
base::CancelableClosure send_request_callback_;
// The time at which the last ARP request was sent.
struct timeval sent_request_at_;
// Time instance for performing GetTimeMonotonic().
Time* time_;
DISALLOW_COPY_AND_ASSIGN(ActiveLinkMonitor);
};
} // namespace shill
#endif // SHILL_ACTIVE_LINK_MONITOR_H_