Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2015 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/active_link_monitor.h"
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <base/bind.h>
     23 #include <base/strings/stringprintf.h>
     24 #include <base/strings/string_util.h>
     25 
     26 #include "shill/arp_client.h"
     27 #include "shill/arp_packet.h"
     28 #include "shill/connection.h"
     29 #include "shill/device_info.h"
     30 #include "shill/event_dispatcher.h"
     31 #include "shill/logging.h"
     32 #include "shill/metrics.h"
     33 #include "shill/net/ip_address.h"
     34 #include "shill/net/shill_time.h"
     35 
     36 using base::Bind;
     37 using base::Unretained;
     38 using std::string;
     39 
     40 namespace shill {
     41 
     42 namespace Logging {
     43 static auto kModuleLogScope = ScopeLogger::kLink;
     44 static string ObjectID(Connection* c) { return c->interface_name(); }
     45 }
     46 
     47 const int ActiveLinkMonitor::kDefaultTestPeriodMilliseconds = 5000;
     48 const int ActiveLinkMonitor::kFailureThreshold = 5;
     49 const int ActiveLinkMonitor::kFastTestPeriodMilliseconds = 200;
     50 const int ActiveLinkMonitor::kMaxResponseSampleFilterDepth = 5;
     51 const int ActiveLinkMonitor::kUnicastReplyReliabilityThreshold = 10;
     52 
     53 ActiveLinkMonitor::ActiveLinkMonitor(const ConnectionRefPtr& connection,
     54                                      EventDispatcher* dispatcher,
     55                                      Metrics* metrics,
     56                                      DeviceInfo* device_info,
     57                                      const FailureCallback& failure_callback,
     58                                      const SuccessCallback& success_callback)
     59     : connection_(connection),
     60       dispatcher_(dispatcher),
     61       metrics_(metrics),
     62       device_info_(device_info),
     63       failure_callback_(failure_callback),
     64       success_callback_(success_callback),
     65       // Connection is not provided when this is used as a mock for testing
     66       // purpose.
     67       arp_client_(
     68           new ArpClient(connection ? connection->interface_index() : 0)),
     69       test_period_milliseconds_(kDefaultTestPeriodMilliseconds),
     70       broadcast_failure_count_(0),
     71       unicast_failure_count_(0),
     72       broadcast_success_count_(0),
     73       unicast_success_count_(0),
     74       is_unicast_(false),
     75       gateway_supports_unicast_arp_(false),
     76       response_sample_count_(0),
     77       response_sample_bucket_(0),
     78       time_(Time::GetInstance()) {
     79 }
     80 
     81 ActiveLinkMonitor::~ActiveLinkMonitor() {
     82   Stop();
     83 }
     84 
     85 bool ActiveLinkMonitor::Start(int test_period) {
     86   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
     87   StopMonitorCycle();
     88   return StartInternal(test_period);
     89 }
     90 
     91 void ActiveLinkMonitor::Stop() {
     92   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
     93   // Stop current cycle.
     94   StopMonitorCycle();
     95 
     96   // Clear stats accumulated from previous monitor cycles.
     97   local_mac_address_.Clear();
     98   gateway_mac_address_.Clear();
     99   broadcast_success_count_ = 0;
    100   unicast_success_count_ = 0;
    101   broadcast_failure_count_ = 0;
    102   unicast_failure_count_ = 0;
    103   is_unicast_ = false;
    104   gateway_supports_unicast_arp_ = false;
    105   response_sample_bucket_ = 0;
    106   response_sample_count_ = 0;
    107 }
    108 
    109 int ActiveLinkMonitor::GetResponseTimeMilliseconds() const {
    110   return response_sample_count_ ?
    111       response_sample_bucket_ / response_sample_count_ : 0;
    112 }
    113 
    114 bool ActiveLinkMonitor::IsGatewayFound() const {
    115   return !gateway_mac_address_.IsZero();
    116 }
    117 
    118 bool ActiveLinkMonitor::StartInternal(int probe_period_milliseconds) {
    119   test_period_milliseconds_ = probe_period_milliseconds;
    120   if (test_period_milliseconds_ > kDefaultTestPeriodMilliseconds) {
    121     LOG(WARNING) << "Long test period; UMA stats will be truncated.";
    122   }
    123 
    124   if (!device_info_->GetMACAddress(
    125           connection_->interface_index(), &local_mac_address_)) {
    126     LOG(ERROR) << "Could not get local MAC address.";
    127     metrics_->NotifyLinkMonitorFailure(
    128         connection_->technology(),
    129         Metrics::kLinkMonitorMacAddressNotFound,
    130         0, 0, 0);
    131     Stop();
    132     return false;
    133   }
    134 
    135   if (!StartArpClient()) {
    136     LOG(ERROR) << "Failed to start ARP client.";
    137     metrics_->NotifyLinkMonitorFailure(
    138         connection_->technology(),
    139         Metrics::kLinkMonitorClientStartFailure,
    140         0, 0, 0);
    141     Stop();
    142     return false;
    143   }
    144 
    145   if (gateway_mac_address_.IsEmpty()) {
    146     gateway_mac_address_ = ByteString(local_mac_address_.GetLength());
    147   }
    148   send_request_callback_.Reset(
    149       Bind(&ActiveLinkMonitor::SendRequest, Unretained(this)));
    150   // Post a task to send ARP request instead of calling it synchronously, to
    151   // maintain consistent expectation in the case of send failures, which will
    152   // always invoke failure callback.
    153   dispatcher_->PostTask(send_request_callback_.callback());
    154   return true;
    155 }
    156 
    157 void ActiveLinkMonitor::StopMonitorCycle() {
    158   StopArpClient();
    159   send_request_callback_.Cancel();
    160   timerclear(&sent_request_at_);
    161 }
    162 
    163 void ActiveLinkMonitor::AddResponseTimeSample(int response_time_milliseconds) {
    164   SLOG(connection_.get(), 2) << "In " << __func__ << " with sample "
    165                              << response_time_milliseconds << ".";
    166   metrics_->NotifyLinkMonitorResponseTimeSampleAdded(
    167       connection_->technology(), response_time_milliseconds);
    168   response_sample_bucket_ += response_time_milliseconds;
    169   if (response_sample_count_ < kMaxResponseSampleFilterDepth) {
    170     ++response_sample_count_;
    171   } else {
    172     response_sample_bucket_ =
    173         response_sample_bucket_ * kMaxResponseSampleFilterDepth /
    174             (kMaxResponseSampleFilterDepth + 1);
    175   }
    176 }
    177 
    178 // static
    179 string ActiveLinkMonitor::HardwareAddressToString(const ByteString& address) {
    180   std::vector<string> address_parts;
    181   for (size_t i = 0; i < address.GetLength(); ++i) {
    182     address_parts.push_back(
    183         base::StringPrintf("%02x", address.GetConstData()[i]));
    184   }
    185   return base::JoinString(address_parts, ":");
    186 }
    187 
    188 bool ActiveLinkMonitor::StartArpClient() {
    189   if (!arp_client_->StartReplyListener()) {
    190     return false;
    191   }
    192   SLOG(connection_.get(), 4) << "Created ARP client; listening on socket "
    193                              << arp_client_->socket() << ".";
    194   receive_response_handler_.reset(
    195     dispatcher_->CreateReadyHandler(
    196         arp_client_->socket(),
    197         IOHandler::kModeInput,
    198         Bind(&ActiveLinkMonitor::ReceiveResponse, Unretained(this))));
    199   return true;
    200 }
    201 
    202 void ActiveLinkMonitor::StopArpClient() {
    203   arp_client_->Stop();
    204   receive_response_handler_.reset();
    205 }
    206 
    207 bool ActiveLinkMonitor::AddMissedResponse() {
    208   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
    209   AddResponseTimeSample(test_period_milliseconds_);
    210 
    211   if (is_unicast_) {
    212     if (gateway_supports_unicast_arp_) {
    213       ++unicast_failure_count_;
    214     }
    215     unicast_success_count_ = 0;
    216   } else {
    217     ++broadcast_failure_count_;
    218     broadcast_success_count_ = 0;
    219   }
    220 
    221   if (unicast_failure_count_ + broadcast_failure_count_ >= kFailureThreshold) {
    222     LOG(ERROR) << "Link monitor has reached the failure threshold with "
    223                << broadcast_failure_count_
    224                << " broadcast failures and "
    225                << unicast_failure_count_
    226                << " unicast failures.";
    227     failure_callback_.Run(Metrics::kLinkMonitorFailureThresholdReached,
    228                           broadcast_failure_count_,
    229                           unicast_failure_count_);
    230     Stop();
    231     return true;
    232   }
    233   is_unicast_ = !is_unicast_;
    234   return false;
    235 }
    236 
    237 void ActiveLinkMonitor::ReceiveResponse(int fd) {
    238   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
    239   ArpPacket packet;
    240   ByteString sender;
    241   if (!arp_client_->ReceivePacket(&packet, &sender)) {
    242     return;
    243   }
    244 
    245   if (!packet.IsReply()) {
    246     SLOG(connection_.get(), 4) << "This is not a reply packet.  Ignoring.";
    247     return;
    248   }
    249 
    250   if (!connection_->local().address().Equals(
    251            packet.remote_ip_address().address())) {
    252     SLOG(connection_.get(), 4) << "Response is not for our IP address.";
    253     return;
    254   }
    255 
    256   if (!local_mac_address_.Equals(packet.remote_mac_address())) {
    257     SLOG(connection_.get(), 4) << "Response is not for our MAC address.";
    258     return;
    259   }
    260 
    261   if (!connection_->gateway().address().Equals(
    262            packet.local_ip_address().address())) {
    263     SLOG(connection_.get(), 4)
    264         << "Response is not from the gateway IP address.";
    265     return;
    266   }
    267 
    268   struct timeval now, elapsed_time;
    269   time_->GetTimeMonotonic(&now);
    270   timersub(&now, &sent_request_at_, &elapsed_time);
    271 
    272   AddResponseTimeSample(elapsed_time.tv_sec * 1000 +
    273                         elapsed_time.tv_usec / 1000);
    274 
    275   if (is_unicast_) {
    276     ++unicast_success_count_;
    277     unicast_failure_count_ = 0;
    278     if (unicast_success_count_ >= kUnicastReplyReliabilityThreshold) {
    279       SLOG_IF(Link, 2, !gateway_supports_unicast_arp_)
    280           << "Gateway is now considered a reliable unicast responder.  "
    281              "Unicast failures will now count.";
    282       gateway_supports_unicast_arp_ = true;
    283     }
    284   } else {
    285     ++broadcast_success_count_;
    286     broadcast_failure_count_ = 0;
    287   }
    288 
    289   if (!gateway_mac_address_.Equals(packet.local_mac_address())) {
    290     const ByteString& new_mac_address = packet.local_mac_address();
    291     if (!IsGatewayFound()) {
    292       SLOG(connection_.get(), 2) << "Found gateway at "
    293                                  << HardwareAddressToString(new_mac_address);
    294     } else {
    295       SLOG(connection_.get(), 2) << "Gateway MAC address changed.";
    296     }
    297     gateway_mac_address_ = new_mac_address;
    298   }
    299 
    300   is_unicast_ = !is_unicast_;
    301 
    302   // Stop the current cycle, and invoke the success callback. All the
    303   // accumulated stats regarding the gateway are not cleared.
    304   StopMonitorCycle();
    305   success_callback_.Run();
    306 }
    307 
    308 void ActiveLinkMonitor::SendRequest() {
    309   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
    310 
    311   // Timeout waiting for ARP reply and exceed the failure threshold.
    312   if (timerisset(&sent_request_at_) && AddMissedResponse()) {
    313     return;
    314   }
    315 
    316   ByteString destination_mac_address(gateway_mac_address_.GetLength());
    317   if (!IsGatewayFound()) {
    318     // The remote MAC addess is set by convention to be all-zeroes in the
    319     // ARP header if not known.  The ArpClient will translate an all-zeroes
    320     // remote address into a send to the broadcast (all-ones) address in
    321     // the Ethernet frame header.
    322     SLOG_IF(Link, 2, is_unicast_) << "Sending broadcast since "
    323                                   << "gateway MAC is unknown";
    324     is_unicast_ = false;
    325   } else if (is_unicast_) {
    326     destination_mac_address = gateway_mac_address_;
    327   }
    328 
    329   ArpPacket request(connection_->local(), connection_->gateway(),
    330                     local_mac_address_, destination_mac_address);
    331   if (!arp_client_->TransmitRequest(request)) {
    332     LOG(ERROR) << "Failed to send ARP request.  Stopping.";
    333     failure_callback_.Run(Metrics::kLinkMonitorTransmitFailure,
    334                           broadcast_failure_count_,
    335                           unicast_failure_count_);
    336     Stop();
    337     return;
    338   }
    339 
    340   time_->GetTimeMonotonic(&sent_request_at_);
    341 
    342   dispatcher_->PostDelayedTask(send_request_callback_.callback(),
    343                                test_period_milliseconds_);
    344 }
    345 
    346 }  // namespace shill
    347