shill: Connection: Add facility to add host routes

This requires a facility for tracking outstanding RTNL route requests,
and adding routes when they the response arrives.  A few small fixes
to RTNL handling needed to be added.

BUG=chromium-os:27483
TEST=New Unit Tests, manual: Assocated my new Neptune proto to test
network.

Change-Id: I701fa244041ad9e0d0a502a263d83792ab3c9114
Reviewed-on: https://gerrit.chromium.org/gerrit/17889
Commit-Ready: Paul Stewart <pstew@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/connection_unittest.cc b/connection_unittest.cc
index 08d85b9..690c7a7 100644
--- a/connection_unittest.cc
+++ b/connection_unittest.cc
@@ -170,38 +170,36 @@
 }
 
 TEST_F(ConnectionTest, RouteRequest) {
-  {
-    ConnectionRefPtr connection(new Connection(kTestDeviceInterfaceIndex0,
-                                               kTestDeviceName0,
-                                               device_info_.get()));
-    ReplaceSingletons(connection);
-    scoped_refptr<MockDevice> device(new StrictMock<MockDevice>(
-        &control_,
-        reinterpret_cast<EventDispatcher *>(NULL),
-        reinterpret_cast<Metrics *>(NULL),
-        reinterpret_cast<Manager *>(NULL),
-        kTestDeviceName0,
-        string(),
-        kTestDeviceInterfaceIndex0));
-    EXPECT_CALL(*device_info_, GetDevice(kTestDeviceInterfaceIndex0))
-        .WillRepeatedly(Return(device));
-    EXPECT_CALL(*device.get(), DisableReversePathFilter()).Times(1);
-    connection->RequestRouting();
-    connection->RequestRouting();
+  ConnectionRefPtr connection(new Connection(kTestDeviceInterfaceIndex0,
+                                             kTestDeviceName0,
+                                             device_info_.get()));
+  ReplaceSingletons(connection);
+  scoped_refptr<MockDevice> device(new StrictMock<MockDevice>(
+      &control_,
+      reinterpret_cast<EventDispatcher *>(NULL),
+      reinterpret_cast<Metrics *>(NULL),
+      reinterpret_cast<Manager *>(NULL),
+      kTestDeviceName0,
+      string(),
+      kTestDeviceInterfaceIndex0));
+  EXPECT_CALL(*device_info_, GetDevice(kTestDeviceInterfaceIndex0))
+      .WillRepeatedly(Return(device));
+  EXPECT_CALL(*device.get(), DisableReversePathFilter()).Times(1);
+  connection->RequestRouting();
+  connection->RequestRouting();
 
-    // The first release should only decrement the reference counter.
-    connection->ReleaseRouting();
+  // The first release should only decrement the reference counter.
+  connection->ReleaseRouting();
 
-    // Another release will re-enable reverse-path filter.
-    EXPECT_CALL(*device.get(), EnableReversePathFilter());
-    EXPECT_CALL(routing_table_, FlushCache());
-    connection->ReleaseRouting();
+  // Another release will re-enable reverse-path filter.
+  EXPECT_CALL(*device.get(), EnableReversePathFilter());
+  EXPECT_CALL(routing_table_, FlushCache());
+  connection->ReleaseRouting();
 
-    // The destructor will remove the routes and addresses.
-    EXPECT_CALL(routing_table_, FlushRoutes(kTestDeviceInterfaceIndex0));
-    EXPECT_CALL(*device_info_.get(),
-                FlushAddresses(kTestDeviceInterfaceIndex0));
-  }
+  // The destructor will remove the routes and addresses.
+  EXPECT_CALL(routing_table_, FlushRoutes(kTestDeviceInterfaceIndex0));
+  EXPECT_CALL(*device_info_.get(),
+              FlushAddresses(kTestDeviceInterfaceIndex0));
 }
 
 TEST_F(ConnectionTest, Destructor) {
@@ -217,4 +215,29 @@
   }
 }
 
+MATCHER_P2(IsIPAddress, address, prefix, "") {
+  IPAddress match_address(address);
+  match_address.set_prefix(prefix);
+  return match_address.Equals(arg);
+}
+
+TEST_F(ConnectionTest, RequestHostRoute) {
+  ConnectionRefPtr connection(new Connection(kTestDeviceInterfaceIndex0,
+                                             kTestDeviceName0,
+                                             device_info_.get()));
+  ReplaceSingletons(connection);
+  IPAddress address(IPAddress::kFamilyIPv4);
+  ASSERT_TRUE(address.SetAddressFromString(kIPAddress0));
+  size_t prefix_len = address.GetLength() * 8;
+  EXPECT_CALL(routing_table_, RequestRouteToHost(
+      IsIPAddress(address, prefix_len), kTestDeviceInterfaceIndex0))
+      .WillOnce(Return(true));
+  EXPECT_TRUE(connection->RequestHostRoute(address));
+
+  // The destructor will remove the routes and addresses.
+  EXPECT_CALL(routing_table_, FlushRoutes(kTestDeviceInterfaceIndex0));
+  EXPECT_CALL(*device_info_.get(),
+              FlushAddresses(kTestDeviceInterfaceIndex0));
+}
+
 }  // namespace shill