shill: Add routing table RTNL message handler

Maintain a copy of the routing table state.  This achieved by
a singleton that maintains an in-process copy of the routing
table on a per-interface basis.  It offers the ability for
other modules to make modifications to the routing table,
centered around setting the default route for an interface or
modifying its metric (priority), but also providing more
granular control for services/devices that may need more control,
like VPN.

BUG=chromium-os:17277
TEST=New unittest

Change-Id: Ifcda0ab2cb8775bca677979ca98ac3fcf7adfdde
Reviewed-on: http://gerrit.chromium.org/gerrit/5163
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/rtnl_handler.cc b/rtnl_handler.cc
index 443d1cf..cd4d9f8 100644
--- a/rtnl_handler.cc
+++ b/rtnl_handler.cc
@@ -23,6 +23,7 @@
 #include "shill/ipconfig.h"
 #include "shill/rtnl_handler.h"
 #include "shill/rtnl_listener.h"
+#include "shill/rtnl_message.h"
 #include "shill/shill_event.h"
 #include "shill/sockets.h"
 
@@ -176,17 +177,27 @@
   req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
   req.hdr.nlmsg_pid = 0;
   req.hdr.nlmsg_seq = request_sequence_;
-  req.msg.rtgen_family = AF_INET;
 
   if ((request_flags_ & kRequestLink) != 0) {
+    req.msg.rtgen_family = AF_INET;
     req.hdr.nlmsg_type = RTM_GETLINK;
     flag = kRequestLink;
   } else if ((request_flags_ & kRequestAddr) != 0) {
+    req.msg.rtgen_family = AF_INET;
     req.hdr.nlmsg_type = RTM_GETADDR;
     flag = kRequestAddr;
   } else if ((request_flags_ & kRequestRoute) != 0) {
+    req.msg.rtgen_family = AF_INET;
     req.hdr.nlmsg_type = RTM_GETROUTE;
     flag = kRequestRoute;
+  } else if ((request_flags_ & kRequestAddr6) != 0) {
+    req.msg.rtgen_family = AF_INET6;
+    req.hdr.nlmsg_type = RTM_GETADDR;
+    flag = kRequestAddr6;
+  } else if ((request_flags_ & kRequestRoute6) != 0) {
+    req.msg.rtgen_family = AF_INET6;
+    req.hdr.nlmsg_type = RTM_GETROUTE;
+    flag = kRequestRoute6;
   } else {
     in_request_ = false;
     return;
@@ -291,8 +302,9 @@
   } else if (properties.address_family == IPAddress::kAddressFamilyIPv6) {
     address_family = AF_INET6;
     address_size = sizeof(struct in6_addr);
-  } else
+  } else {
     return false;
+  }
 
   request_sequence_++;
   memset(&req, 0, sizeof(req));
@@ -362,4 +374,23 @@
   return ifr.ifr_ifindex;
 }
 
+bool RTNLHandler::SendMessage(RTNLMessage *message) {
+  message->set_seq(request_sequence_++);
+  ByteString msgdata = message->Encode();
+
+  if (msgdata.GetLength() == 0) {
+    return false;
+  }
+
+  if (sockets_->Send(rtnl_socket_,
+                     msgdata.GetData(),
+                     msgdata.GetLength(),
+                     0) < 0) {
+    PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace shill