shill: Add IP Address tracking to DeviceInfo

Subscribe to IP Address messages in DeviceInfo, and create a
per-device list of assigned IP Addresses.  Provide a method
to flush all globally scoped addresses from a device.

As a result, we can now flush assigned IP addresses when a
Connection is terminated.  There is also some incidental cleanup
in RTNLHandler to remove some vestiges of hand-baked RTNL
message encoding.

BUG=chromium-os:19744
TEST=Run new unit tests.  Test using ethernet on a netbook to make sure
addresses are added and removed correctly.

Change-Id: I63fd09088e71c43cb1f11a89a8ef15e11074976c
Reviewed-on: http://gerrit.chromium.org/gerrit/7180
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/connection.cc b/connection.cc
index d788020..847ac4d 100644
--- a/connection.cc
+++ b/connection.cc
@@ -4,6 +4,10 @@
 
 #include "shill/connection.h"
 
+#include <arpa/inet.h>
+#include <linux/rtnetlink.h>
+
+#include "shill/device_info.h"
 #include "shill/resolver.h"
 #include "shill/routing_table.h"
 #include "shill/rtnl_handler.h"
@@ -17,10 +21,13 @@
 // static
 const uint32 Connection::kNonDefaultMetric = 10;
 
-Connection::Connection(int interface_index, const std::string& interface_name)
+Connection::Connection(int interface_index,
+                       const std::string& interface_name,
+                       const DeviceInfo *device_info)
     : is_default_(false),
       interface_index_(interface_index),
       interface_name_(interface_name),
+      device_info_(device_info),
       resolver_(Resolver::GetInstance()),
       routing_table_(RoutingTable::GetInstance()),
       rtnl_handler_(RTNLHandler::GetInstance()) {
@@ -28,18 +35,31 @@
 }
 
 Connection::~Connection() {
-  routing_table_->FlushRoutes(interface_index_);
-  // TODO(pstew): Also flush all addresses when DeviceInfo starts tracking them
   VLOG(2) << __func__;
+
+  routing_table_->FlushRoutes(interface_index_);
+  device_info_->FlushAddresses(interface_index_);
 }
 
 void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
   VLOG(2) << __func__;
 
-  // TODO(pstew): Create a centralized resource (perhaps in DeviceInfo?) to
-  // keep apply and keep track of addresses associated with an interface.
-  // Use this instead of directly setting the address over RTNL.
-  rtnl_handler_->AddInterfaceAddress(interface_index_, *config);
+  const IPConfig::Properties &properties = config->properties();
+  IPAddress local(properties.address_family);
+  if (!local.SetAddressFromString(properties.address)) {
+    LOG(ERROR) << "Local address " << properties.address << " is invalid";
+    return;
+  }
+  local.set_prefix(properties.subnet_cidr);
+
+  IPAddress broadcast(properties.address_family);
+  if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
+    LOG(ERROR) << "Broadcast address " << properties.broadcast_address
+               << " is invalid";
+    return;
+  }
+
+  rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast);
 
   uint32 metric = is_default_ ? kDefaultMetric : kNonDefaultMetric;
   routing_table_->SetDefaultRoute(interface_index_, config, metric);
diff --git a/connection.h b/connection.h
index d3d7310..a5305d7 100644
--- a/connection.h
+++ b/connection.h
@@ -15,6 +15,7 @@
 
 namespace shill {
 
+class DeviceInfo;
 class Resolver;
 class RoutingTable;
 class RTNLHandler;
@@ -23,7 +24,9 @@
 // the IP address, routing table and DNS table entries.
 class Connection : public base::RefCounted<Connection> {
  public:
-  Connection(int interface_index, const std::string& interface_name);
+  Connection(int interface_index,
+             const std::string &interface_name,
+             const DeviceInfo *device_info);
   virtual ~Connection();
 
   // Add the contents of an IPConfig reference to the list of managed state.
@@ -52,6 +55,7 @@
   std::vector<std::string> dns_domain_search_;
 
   // Store cached copies of singletons for speed/ease of testing
+  const DeviceInfo *device_info_;
   Resolver *resolver_;
   RoutingTable *routing_table_;
   RTNLHandler *rtnl_handler_;
diff --git a/connection_unittest.cc b/connection_unittest.cc
index 3b47af1..3111db7 100644
--- a/connection_unittest.cc
+++ b/connection_unittest.cc
@@ -2,18 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <arpa/inet.h>
+#include <linux/rtnetlink.h>
+
+#include <vector>
+
+#include <base/memory/scoped_ptr.h>
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
 
 #include "shill/connection.h"
-#include "shill/ip_address.h"
 #include "shill/ipconfig.h"
 #include "shill/mock_control.h"
+#include "shill/mock_device_info.h"
 #include "shill/mock_resolver.h"
 #include "shill/mock_routing_table.h"
 #include "shill/mock_rtnl_handler.h"
 #include "shill/routing_table_entry.h"
 
+using std::vector;
 using testing::_;
 using testing::NiceMock;
 using testing::Return;
@@ -29,6 +36,7 @@
 const int kTestDeviceInterfaceIndex1 = 321;
 const char kIPAddress0[] = "192.168.1.1";
 const char kGatewayAddress0[] = "192.168.1.254";
+const char kBroadcastAddress0[] = "192.168.1.255";
 const char kNameServer0[] = "8.8.8.8";
 const char kNameServer1[] = "8.8.9.9";
 const char kSearchDomain0[] = "chromium.org";
@@ -38,8 +46,14 @@
 class ConnectionTest : public Test {
  public:
   ConnectionTest()
-      : connection_(
-            new Connection(kTestDeviceInterfaceIndex0, kTestDeviceName0)),
+      : device_info_(new StrictMock<MockDeviceInfo>(
+            &control_,
+            static_cast<EventDispatcher*>(NULL),
+            static_cast<Manager*>(NULL))),
+        connection_(new Connection(
+            kTestDeviceInterfaceIndex0,
+            kTestDeviceName0,
+            device_info_.get())),
         ipconfig_(new IPConfig(&control_, kTestDeviceName0)) {}
 
   virtual void SetUp() {
@@ -50,6 +64,7 @@
     IPConfig::Properties properties;
     properties.address = kIPAddress0;
     properties.gateway = kGatewayAddress0;
+    properties.broadcast_address = kBroadcastAddress0;
     properties.dns_servers.push_back(kNameServer0);
     properties.dns_servers.push_back(kNameServer1);
     properties.domain_search.push_back(kSearchDomain0);
@@ -58,7 +73,12 @@
     ipconfig_->UpdateProperties(properties, true);
   }
 
+  virtual void TearDown() {
+    EXPECT_CALL(*device_info_, FlushAddresses(kTestDeviceInterfaceIndex0));
+  }
+
  protected:
+  scoped_ptr<StrictMock<MockDeviceInfo> > device_info_;
   ConnectionRefPtr connection_;
   MockControl control_;
   IPConfigRefPtr ipconfig_;
@@ -75,7 +95,7 @@
 
 TEST_F(ConnectionTest, AddConfig) {
   EXPECT_CALL(rtnl_handler_,
-              AddInterfaceAddress(kTestDeviceInterfaceIndex0, _));
+              AddInterfaceAddress(kTestDeviceInterfaceIndex0, _, _));
   EXPECT_CALL(routing_table_, SetDefaultRoute(kTestDeviceInterfaceIndex0,
                                              ipconfig_,
                                              Connection::kNonDefaultMetric));
@@ -99,12 +119,12 @@
 TEST_F(ConnectionTest, AddConfigReverse) {
   EXPECT_CALL(routing_table_, SetDefaultMetric(kTestDeviceInterfaceIndex0,
                                                Connection::kDefaultMetric));
-  std::vector<std::string> empty_list;
+  vector<std::string> empty_list;
   EXPECT_CALL(resolver_, SetDNSFromLists(empty_list, empty_list));
   connection_->SetDefault(true);
 
   EXPECT_CALL(rtnl_handler_,
-              AddInterfaceAddress(kTestDeviceInterfaceIndex0, _));
+              AddInterfaceAddress(kTestDeviceInterfaceIndex0, _, _));
   EXPECT_CALL(routing_table_, SetDefaultRoute(kTestDeviceInterfaceIndex0,
                                              ipconfig_,
                                              Connection::kDefaultMetric));
@@ -115,9 +135,11 @@
 
 TEST_F(ConnectionTest, Destructor) {
   EXPECT_CALL(routing_table_, FlushRoutes(kTestDeviceInterfaceIndex1));
+  EXPECT_CALL(*device_info_, FlushAddresses(kTestDeviceInterfaceIndex1));
   {
     ConnectionRefPtr connection(new Connection(kTestDeviceInterfaceIndex1,
-                                               kTestDeviceName1));
+                                               kTestDeviceName1,
+                                               device_info_.get()));
     connection->resolver_ = &resolver_;
     connection->routing_table_ = &routing_table_;
     connection->rtnl_handler_ = &rtnl_handler_;
diff --git a/device.cc b/device.cc
index b584ae3..024f3c3 100644
--- a/device.cc
+++ b/device.cc
@@ -222,11 +222,6 @@
 
 void Device::DestroyIPConfig() {
   if (ipconfig_.get()) {
-    // TODO(pstew): Instead we should do this in DestroyConnection(), which
-    // should have a facility at its disposal that returns all addresses
-    // assigned to the interface.
-    RTNLHandler::GetInstance()->RemoveInterfaceAddress(interface_index_,
-                                                       *ipconfig_);
     ipconfig_->ReleaseIP();
     ipconfig_ = NULL;
   }
@@ -267,7 +262,9 @@
 void Device::CreateConnection() {
   VLOG(2) << __func__;
   if (!connection_.get()) {
-    connection_ = new Connection(interface_index_, link_name_);
+    connection_ = new Connection(interface_index_,
+                                 link_name_,
+                                 manager_->device_info());
   }
 }
 
diff --git a/device_info.cc b/device_info.cc
index 638f88f..b905d56 100644
--- a/device_info.cc
+++ b/device_info.cc
@@ -37,6 +37,7 @@
 
 using std::map;
 using std::string;
+using std::vector;
 
 namespace shill {
 
@@ -63,7 +64,10 @@
       dispatcher_(dispatcher),
       manager_(manager),
       link_callback_(NewCallback(this, &DeviceInfo::LinkMsgHandler)),
-      link_listener_(NULL) {
+      address_callback_(NewCallback(this, &DeviceInfo::AddressMsgHandler)),
+      link_listener_(NULL),
+      address_listener_(NULL),
+      rtnl_handler_(RTNLHandler::GetInstance()) {
 }
 
 DeviceInfo::~DeviceInfo() {}
@@ -75,11 +79,15 @@
 void DeviceInfo::Start() {
   link_listener_.reset(
       new RTNLListener(RTNLHandler::kRequestLink, link_callback_.get()));
-  RTNLHandler::GetInstance()->RequestDump(RTNLHandler::kRequestLink);
+  address_listener_.reset(
+      new RTNLListener(RTNLHandler::kRequestAddr, address_callback_.get()));
+  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink |
+                             RTNLHandler::kRequestAddr);
 }
 
 void DeviceInfo::Stop() {
-  link_listener_.reset(NULL);
+  link_listener_.reset();
+  address_listener_.reset();
 }
 
 void DeviceInfo::RegisterDevice(const DeviceRefPtr &device) {
@@ -140,8 +148,8 @@
 }
 
 void DeviceInfo::AddLinkMsgHandler(const RTNLMessage &msg) {
-  DCHECK(msg.type() == RTNLMessage::kMessageTypeLink &&
-         msg.mode() == RTNLMessage::kMessageModeAdd);
+  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
+         msg.mode() == RTNLMessage::kModeAdd);
   int dev_index = msg.interface_index();
   Device::Technology technology = Device::kUnknown;
 
@@ -208,8 +216,8 @@
 void DeviceInfo::DelLinkMsgHandler(const RTNLMessage &msg) {
   VLOG(2) << __func__ << "(index=" << msg.interface_index() << ")";
 
-  DCHECK(msg.type() == RTNLMessage::kMessageTypeLink &&
-         msg.mode() == RTNLMessage::kMessageModeDelete);
+  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
+         msg.mode() == RTNLMessage::kModeDelete);
   VLOG(2) << __func__ << "(index=" << msg.interface_index()
           << std::showbase << std::hex
           << ", flags=" << msg.link_status().flags
@@ -231,6 +239,34 @@
   return true;
 }
 
+bool DeviceInfo::GetAddresses(int interface_index,
+                              vector<AddressData> *addresses) const {
+  const Info *info = GetInfo(interface_index);
+  if (!info) {
+    return false;
+  }
+  *addresses = info->ip_addresses;
+  return true;
+}
+
+void DeviceInfo::FlushAddresses(int interface_index) const {
+  const Info *info = GetInfo(interface_index);
+  if (!info) {
+    return;
+  }
+  const vector<AddressData> &addresses = info->ip_addresses;
+  vector<AddressData>::const_iterator iter;
+  for (iter = addresses.begin(); iter != addresses.end(); ++iter) {
+    if (iter->address.family() == IPAddress::kAddressFamilyIPv4 ||
+        (iter->scope == RT_SCOPE_UNIVERSE &&
+         (iter->flags & ~IFA_F_TEMPORARY) == 0)) {
+      VLOG(2) << __func__ << ": removing ip address from interface "
+              << interface_index;
+      rtnl_handler_->RemoveInterfaceAddress(interface_index, iter->address);
+    }
+  }
+}
+
 bool DeviceInfo::GetFlags(int interface_index, unsigned int *flags) const {
   const Info *info = GetInfo(interface_index);
   if (!info) {
@@ -262,16 +298,50 @@
 }
 
 void DeviceInfo::LinkMsgHandler(const RTNLMessage &msg) {
-  DCHECK(msg.type() == RTNLMessage::kMessageTypeLink);
-  if (msg.mode() == RTNLMessage::kMessageModeAdd) {
+  DCHECK(msg.type() == RTNLMessage::kTypeLink);
+  if (msg.mode() == RTNLMessage::kModeAdd) {
     AddLinkMsgHandler(msg);
-  } else if (msg.mode() == RTNLMessage::kMessageModeDelete) {
+  } else if (msg.mode() == RTNLMessage::kModeDelete) {
     DelLinkMsgHandler(msg);
   } else {
     NOTREACHED();
   }
 }
 
+void DeviceInfo::AddressMsgHandler(const RTNLMessage &msg) {
+  DCHECK(msg.type() == RTNLMessage::kTypeAddress);
+  int interface_index = msg.interface_index();
+  if (!ContainsKey(infos_, interface_index)) {
+    LOG(ERROR) << "Got address type message for unknown index "
+               << interface_index;
+    return;
+  }
+  const RTNLMessage::AddressStatus &status = msg.address_status();
+  IPAddress address(msg.family(),
+                    msg.GetAttribute(IFA_ADDRESS),
+                    status.prefix_len);
+
+  vector<AddressData> &address_list = infos_[interface_index].ip_addresses;
+  vector<AddressData>::iterator iter;
+  for (iter = address_list.begin(); iter != address_list.end(); ++iter) {
+    if (address.Equals(iter->address)) {
+      break;
+    }
+  }
+  if (iter != address_list.end()) {
+    if (msg.mode() == RTNLMessage::kModeDelete) {
+      VLOG(2) << "Delete address for interface " << interface_index;
+      address_list.erase(iter);
+    } else {
+      iter->flags = status.flags;
+      iter->scope = status.scope;
+    }
+  } else if (msg.mode() == RTNLMessage::kModeAdd) {
+    address_list.push_back(AddressData(address, status.flags, status.scope));
+    VLOG(2) << "Add address for interface " << interface_index;
+  }
+}
+
 void DeviceInfo::EnableDeviceIPv6Privacy(const string &iface_name) {
   FilePath priv_file(StringPrintf(kInterfaceIPv6Privacy, iface_name.c_str()));
   LOG_IF(ERROR, file_util::WriteFile(priv_file, "2", 1) != 1)
diff --git a/device_info.h b/device_info.h
index 9cc2e91..ea8b776 100644
--- a/device_info.h
+++ b/device_info.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include <base/callback_old.h>
 #include <base/memory/ref_counted.h>
@@ -16,15 +17,29 @@
 
 #include "shill/byte_string.h"
 #include "shill/device.h"
+#include "shill/ip_address.h"
 #include "shill/rtnl_listener.h"
 
 namespace shill {
 
 class Manager;
+class RTNLHandler;
 class RTNLMessage;
 
 class DeviceInfo {
  public:
+  struct AddressData {
+    AddressData()
+        : address(IPAddress::kAddressFamilyUnknown), flags(0), scope(0) {}
+    AddressData(const IPAddress &address_in,
+                unsigned char flags_in,
+                unsigned char scope_in)
+        : address(address_in), flags(flags_in), scope(scope_in) {}
+    IPAddress address;
+    unsigned char flags;
+    unsigned char scope;
+  };
+
   DeviceInfo(ControlInterface *control_interface,
              EventDispatcher *dispatcher,
              Manager *manager);
@@ -41,6 +56,9 @@
   DeviceRefPtr GetDevice(int interface_index) const;
   virtual bool GetMACAddress(int interface_index, ByteString *address) const;
   virtual bool GetFlags(int interface_index, unsigned int *flags) const;
+  virtual bool GetAddresses(int interface_index,
+                            std::vector<AddressData> *addresses) const;
+  virtual void FlushAddresses(int interface_index) const;
 
  private:
   friend class DeviceInfoTest;
@@ -51,6 +69,7 @@
 
     DeviceRefPtr device;
     ByteString mac_address;
+    std::vector<AddressData> ip_addresses;
     unsigned int flags;
   };
 
@@ -64,6 +83,7 @@
   void AddLinkMsgHandler(const RTNLMessage &msg);
   void DelLinkMsgHandler(const RTNLMessage &msg);
   void LinkMsgHandler(const RTNLMessage &msg);
+  void AddressMsgHandler(const RTNLMessage &msg);
 
   const Info *GetInfo(int interface_index) const;
   void RemoveInfo(int interface_index);
@@ -74,9 +94,14 @@
   Manager *manager_;
   std::map<int, Info> infos_;
   scoped_ptr<Callback1<const RTNLMessage &>::Type> link_callback_;
+  scoped_ptr<Callback1<const RTNLMessage &>::Type> address_callback_;
   scoped_ptr<RTNLListener> link_listener_;
+  scoped_ptr<RTNLListener> address_listener_;
   std::set<std::string> black_list_;
 
+  // Cache copy of singleton
+  RTNLHandler *rtnl_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceInfo);
 };
 
diff --git a/device_info_unittest.cc b/device_info_unittest.cc
index 228bc80..6a0a477 100644
--- a/device_info_unittest.cc
+++ b/device_info_unittest.cc
@@ -18,18 +18,21 @@
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
 
+#include "shill/ip_address.h"
 #include "shill/manager.h"
 #include "shill/mock_control.h"
 #include "shill/mock_glib.h"
 #include "shill/mock_manager.h"
+#include "shill/mock_rtnl_handler.h"
 #include "shill/mock_sockets.h"
-#include "shill/rtnl_handler.h"
 #include "shill/rtnl_message.h"
 
 using std::map;
 using std::string;
+using std::vector;
 using testing::_;
 using testing::Return;
+using testing::StrictMock;
 using testing::Test;
 
 namespace shill {
@@ -50,47 +53,105 @@
         device_info_(&control_interface_, &dispatcher_, &manager_) {
   }
 
+  virtual void SetUp() {
+    device_info_.rtnl_handler_ = &rtnl_handler_;
+    EXPECT_CALL(rtnl_handler_, RequestDump(RTNLHandler::kRequestLink |
+                                           RTNLHandler::kRequestAddr));
+  }
+
  protected:
   static const int kTestDeviceIndex;
   static const char kTestDeviceName[];
-  static const char kTestAddress[];
+  static const char kTestMACAddress[];
+  static const char kTestIPAddress0[];
+  static const int kTestIPAddressPrefix0;
+  static const char kTestIPAddress1[];
+  static const int kTestIPAddressPrefix1;
+  static const char kTestIPAddress2[];
+  static const char kTestIPAddress3[];
+  static const char kTestIPAddress4[];
 
-  RTNLMessage *BuildMessage(RTNLMessage::MessageType type,
-                            RTNLMessage::MessageMode mode);
+  RTNLMessage *BuildLinkMessage(RTNLMessage::Mode mode);
+  RTNLMessage *BuildAddressMessage(RTNLMessage::Mode mode,
+                                   const IPAddress &address,
+                                   unsigned char flags,
+                                   unsigned char scope);
   void SendMessageToDeviceInfo(const RTNLMessage &message);
 
   MockGLib glib_;
   MockControl control_interface_;
-  MockManager manager_;
+  StrictMock<MockManager> manager_;
   DeviceInfo device_info_;
   TestEventDispatcher dispatcher_;
+  StrictMock<MockRTNLHandler> rtnl_handler_;
 };
 
 const int DeviceInfoTest::kTestDeviceIndex = 123456;
 const char DeviceInfoTest::kTestDeviceName[] = "test-device";
-const char DeviceInfoTest::kTestAddress[] = {
+const char DeviceInfoTest::kTestMACAddress[] = {
   0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+const char DeviceInfoTest::kTestIPAddress0[] = "192.168.1.1";
+const int DeviceInfoTest::kTestIPAddressPrefix0 = 24;
+const char DeviceInfoTest::kTestIPAddress1[] = "fe80::1aa9:5ff:abcd:1234";
+const int DeviceInfoTest::kTestIPAddressPrefix1 = 64;
+const char DeviceInfoTest::kTestIPAddress2[] = "fe80::1aa9:5ff:abcd:1235";
+const char DeviceInfoTest::kTestIPAddress3[] = "fe80::1aa9:5ff:abcd:1236";
+const char DeviceInfoTest::kTestIPAddress4[] = "fe80::1aa9:5ff:abcd:1237";
 
-RTNLMessage *DeviceInfoTest::BuildMessage(RTNLMessage::MessageType type,
-                                          RTNLMessage::MessageMode mode) {
-  RTNLMessage *message = new RTNLMessage(type, mode, 0, 0, 0, kTestDeviceIndex,
-                                         IPAddress::kAddressFamilyIPv4);
+RTNLMessage *DeviceInfoTest::BuildLinkMessage(RTNLMessage::Mode mode) {
+  RTNLMessage *message = new RTNLMessage(
+      RTNLMessage::kTypeLink,
+      mode,
+      0,
+      0,
+      0,
+      kTestDeviceIndex,
+      IPAddress::kAddressFamilyIPv4);
   message->SetAttribute(static_cast<uint16>(IFLA_IFNAME),
                         ByteString(kTestDeviceName, true));
-  ByteString test_address(kTestAddress, sizeof(kTestAddress));
+  ByteString test_address(kTestMACAddress, sizeof(kTestMACAddress));
   message->SetAttribute(IFLA_ADDRESS, test_address);
   return message;
 }
 
+RTNLMessage *DeviceInfoTest::BuildAddressMessage(RTNLMessage::Mode mode,
+                                                 const IPAddress &address,
+                                                 unsigned char flags,
+                                                 unsigned char scope) {
+  RTNLMessage *message = new RTNLMessage(
+      RTNLMessage::kTypeAddress,
+      mode,
+      0,
+      0,
+      0,
+      kTestDeviceIndex,
+      address.family());
+  message->SetAttribute(IFA_ADDRESS, address.address());
+  message->set_address_status(
+      RTNLMessage::AddressStatus(address.prefix(), flags, scope));
+  return message;
+}
+
 void DeviceInfoTest::SendMessageToDeviceInfo(const RTNLMessage &message) {
-  device_info_.LinkMsgHandler(message);
+  if (message.type() == RTNLMessage::kTypeLink) {
+    device_info_.LinkMsgHandler(message);
+  } else if (message.type() == RTNLMessage::kTypeAddress) {
+    device_info_.AddressMsgHandler(message);
+  } else {
+    NOTREACHED();
+  }
+}
+
+MATCHER_P(IsIPAddress, address, "") {
+  // NB: IPAddress objects don't support the "==" operator as per style, so
+  // we need a custom matcher.
+  return address.Equals(arg);
 }
 
 TEST_F(DeviceInfoTest, DeviceEnumeration) {
   // Start our own private device_info
   device_info_.Start();
-  scoped_ptr<RTNLMessage> message(BuildMessage(RTNLMessage::kMessageTypeLink,
-                                               RTNLMessage::kMessageModeAdd));
+  scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
   message->set_link_status(RTNLMessage::LinkStatus(0, IFF_LOWER_UP, 0));
   EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
   SendMessageToDeviceInfo(*message);
@@ -101,17 +162,16 @@
   ByteString address;
   EXPECT_TRUE(device_info_.GetMACAddress(kTestDeviceIndex, &address));
   EXPECT_FALSE(address.IsEmpty());
-  EXPECT_TRUE(address.Equals(ByteString(kTestAddress, sizeof(kTestAddress))));
+  EXPECT_TRUE(address.Equals(ByteString(kTestMACAddress,
+                                        sizeof(kTestMACAddress))));
 
-  message.reset(BuildMessage(RTNLMessage::kMessageTypeLink,
-                             RTNLMessage::kMessageModeAdd));
+  message.reset(BuildLinkMessage(RTNLMessage::kModeAdd));
   message->set_link_status(RTNLMessage::LinkStatus(0, IFF_UP | IFF_RUNNING, 0));
   SendMessageToDeviceInfo(*message);
   EXPECT_TRUE(device_info_.GetFlags(kTestDeviceIndex, &flags));
   EXPECT_EQ(IFF_UP | IFF_RUNNING, flags);
 
-  message.reset(BuildMessage(RTNLMessage::kMessageTypeLink,
-                             RTNLMessage::kMessageModeDelete));
+  message.reset(BuildLinkMessage(RTNLMessage::kModeDelete));
   SendMessageToDeviceInfo(*message);
   EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
   EXPECT_FALSE(device_info_.GetFlags(kTestDeviceIndex, NULL));
@@ -122,8 +182,7 @@
 TEST_F(DeviceInfoTest, DeviceBlackList) {
   device_info_.AddDeviceToBlackList(kTestDeviceName);
   device_info_.Start();
-  scoped_ptr<RTNLMessage> message(BuildMessage(RTNLMessage::kMessageTypeLink,
-                                               RTNLMessage::kMessageModeAdd));
+  scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
   SendMessageToDeviceInfo(*message);
 
   DeviceRefPtr device = device_info_.GetDevice(kTestDeviceIndex);
@@ -133,4 +192,116 @@
   device_info_.Stop();
 }
 
+TEST_F(DeviceInfoTest, DeviceAddressList) {
+  device_info_.Start();
+  scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
+  SendMessageToDeviceInfo(*message);
+
+  vector<DeviceInfo::AddressData> addresses;
+  EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
+  EXPECT_TRUE(addresses.empty());
+
+  // Add an address to the device address list
+  IPAddress ip_address0(IPAddress::kAddressFamilyIPv4);
+  EXPECT_TRUE(ip_address0.SetAddressFromString(kTestIPAddress0));
+  ip_address0.set_prefix(kTestIPAddressPrefix0);
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd, ip_address0, 0, 0));
+  SendMessageToDeviceInfo(*message);
+  EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
+  EXPECT_EQ(1, addresses.size());
+  EXPECT_TRUE(ip_address0.Equals(addresses[0].address));
+
+  // Re-adding the same address shouldn't cause the address list to change
+  SendMessageToDeviceInfo(*message);
+  EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
+  EXPECT_EQ(1, addresses.size());
+  EXPECT_TRUE(ip_address0.Equals(addresses[0].address));
+
+  // Adding a new address should expand the list
+  IPAddress ip_address1(IPAddress::kAddressFamilyIPv6);
+  EXPECT_TRUE(ip_address1.SetAddressFromString(kTestIPAddress1));
+  ip_address1.set_prefix(kTestIPAddressPrefix1);
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd, ip_address1, 0, 0));
+  SendMessageToDeviceInfo(*message);
+  EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
+  EXPECT_EQ(2, addresses.size());
+  EXPECT_TRUE(ip_address0.Equals(addresses[0].address));
+  EXPECT_TRUE(ip_address1.Equals(addresses[1].address));
+
+  // Deleting an address should reduce the list
+  message.reset(BuildAddressMessage(RTNLMessage::kModeDelete,
+                                    ip_address0,
+                                    0,
+                                    0));
+  SendMessageToDeviceInfo(*message);
+  EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
+  EXPECT_EQ(1, addresses.size());
+  EXPECT_TRUE(ip_address1.Equals(addresses[0].address));
+
+  // Delete last item
+  message.reset(BuildAddressMessage(RTNLMessage::kModeDelete,
+                                    ip_address1,
+                                    0,
+                                    0));
+  SendMessageToDeviceInfo(*message);
+  EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
+  EXPECT_TRUE(addresses.empty());
+
+  // Delete device
+  message.reset(BuildLinkMessage(RTNLMessage::kModeDelete));
+  SendMessageToDeviceInfo(*message);
+
+  // Should be able to handle message for interface that doesn't exist
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd, ip_address0, 0, 0));
+  SendMessageToDeviceInfo(*message);
+  EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
+
+  device_info_.Stop();
+}
+
+TEST_F(DeviceInfoTest, FlushAddressList) {
+  device_info_.Start();
+  scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
+  SendMessageToDeviceInfo(*message);
+
+  IPAddress address1(IPAddress::kAddressFamilyIPv6);
+  EXPECT_TRUE(address1.SetAddressFromString(kTestIPAddress1));
+  address1.set_prefix(kTestIPAddressPrefix1);
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
+                                    address1,
+                                    0,
+                                    RT_SCOPE_UNIVERSE));
+  SendMessageToDeviceInfo(*message);
+  IPAddress address2(IPAddress::kAddressFamilyIPv6);
+  EXPECT_TRUE(address2.SetAddressFromString(kTestIPAddress2));
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
+                                    address2,
+                                    IFA_F_TEMPORARY,
+                                    RT_SCOPE_UNIVERSE));
+  SendMessageToDeviceInfo(*message);
+  IPAddress address3(IPAddress::kAddressFamilyIPv6);
+  EXPECT_TRUE(address3.SetAddressFromString(kTestIPAddress3));
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
+                                    address3,
+                                    0,
+                                    RT_SCOPE_LINK));
+  SendMessageToDeviceInfo(*message);
+  IPAddress address4(IPAddress::kAddressFamilyIPv6);
+  EXPECT_TRUE(address4.SetAddressFromString(kTestIPAddress4));
+  message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
+                                    address4,
+                                    IFA_F_PERMANENT,
+                                    RT_SCOPE_UNIVERSE));
+  SendMessageToDeviceInfo(*message);
+
+  // DeviceInfo now has 4 addresses associated with it, but only two of
+  // them are valid for flush.
+  EXPECT_CALL(rtnl_handler_, RemoveInterfaceAddress(kTestDeviceIndex,
+                                                    IsIPAddress(address1)));
+  EXPECT_CALL(rtnl_handler_, RemoveInterfaceAddress(kTestDeviceIndex,
+                                                    IsIPAddress(address2)));
+  device_info_.FlushAddresses(kTestDeviceIndex);
+  device_info_.Stop();
+}
+
 }  // namespace shill
diff --git a/mock_device_info.h b/mock_device_info.h
index e179adb..a2b1223 100644
--- a/mock_device_info.h
+++ b/mock_device_info.h
@@ -26,6 +26,8 @@
 
   MOCK_CONST_METHOD2(GetMACAddress, bool(int, ByteString*));
   MOCK_CONST_METHOD2(GetFlags, bool(int, unsigned int*));
+  MOCK_CONST_METHOD2(GetAddresses, bool(int, std::vector<AddressData>*));
+  MOCK_CONST_METHOD1(FlushAddresses, void(int));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockDeviceInfo);
diff --git a/mock_rtnl_handler.h b/mock_rtnl_handler.h
index b4b124b..de96ff8 100644
--- a/mock_rtnl_handler.h
+++ b/mock_rtnl_handler.h
@@ -23,10 +23,11 @@
   MOCK_METHOD3(SetInterfaceFlags, void(int interface_index,
                                        unsigned int flags,
                                        unsigned int change));
-  MOCK_METHOD2(AddInterfaceAddress, bool(int interface_index,
-                                         const IPConfig &config));
+  MOCK_METHOD3(AddInterfaceAddress, bool(int interface_index,
+                                         const IPAddress &local,
+                                         const IPAddress &broadcast));
   MOCK_METHOD2(RemoveInterfaceAddress, bool(int interface_index,
-                                            const IPConfig &config));
+                                            const IPAddress &local));
   MOCK_METHOD1(RequestDump, void(int request_flags));
   MOCK_METHOD1(GetInterfaceIndex, int(const std::string &interface_name));
   MOCK_METHOD1(SendMessage, bool(RTNLMessage *message));
diff --git a/routing_table.cc b/routing_table.cc
index f7edf03..3d9d1b9 100644
--- a/routing_table.cc
+++ b/routing_table.cc
@@ -64,7 +64,7 @@
   route_listener_.reset(
       new RTNLListener(RTNLHandler::kRequestRoute, route_callback_.get()));
   RTNLHandler::GetInstance()->RequestDump(
-      RTNLHandler::kRequestRoute | RTNLHandler::kRequestRoute6);
+      RTNLHandler::kRequestRoute);
 }
 
 void RoutingTable::Stop() {
@@ -80,7 +80,7 @@
   CHECK(!entry.from_rtnl);
   if (!ApplyRoute(interface_index,
                   entry,
-                  RTNLMessage::kMessageModeAdd,
+                  RTNLMessage::kModeAdd,
                   NLM_F_CREATE | NLM_F_EXCL)) {
     return false;
   }
@@ -131,14 +131,14 @@
     if (old_entry.gateway.Equals(gateway_address)) {
       if (old_entry.metric != metric) {
         old_entry.metric = metric;
-        ApplyRoute(interface_index, old_entry, RTNLMessage::kMessageModeAdd,
+        ApplyRoute(interface_index, old_entry, RTNLMessage::kModeAdd,
                    NLM_F_CREATE | NLM_F_REPLACE);
       }
       return true;
     } else {
       ApplyRoute(interface_index,
                  old_entry,
-                 RTNLMessage::kMessageModeDelete,
+                 RTNLMessage::kModeDelete,
                  0);
     }
   }
@@ -168,7 +168,7 @@
   vector<RoutingTableEntry>::iterator nent;
 
   for (nent = table->second.begin(); nent != table->second.end(); ++nent) {
-    ApplyRoute(interface_index, *nent, RTNLMessage::kMessageModeDelete, 0);
+    ApplyRoute(interface_index, *nent, RTNLMessage::kModeDelete, 0);
   }
 }
 
@@ -184,14 +184,14 @@
   if (GetDefaultRoute(interface_index, IPAddress::kAddressFamilyIPv4, &entry) &&
       entry.metric != metric) {
     entry.metric = metric;
-    ApplyRoute(interface_index, entry, RTNLMessage::kMessageModeAdd,
+    ApplyRoute(interface_index, entry, RTNLMessage::kModeAdd,
                NLM_F_CREATE | NLM_F_REPLACE);
   }
 
   if (GetDefaultRoute(interface_index, IPAddress::kAddressFamilyIPv6, &entry) &&
       entry.metric != metric) {
     entry.metric = metric;
-    ApplyRoute(interface_index, entry, RTNLMessage::kMessageModeAdd,
+    ApplyRoute(interface_index, entry, RTNLMessage::kModeAdd,
                NLM_F_CREATE | NLM_F_REPLACE);
   }
 }
@@ -199,7 +199,7 @@
 void RoutingTable::RouteMsgHandler(const RTNLMessage &msg) {
   VLOG(2) << __func__;
 
-  if (msg.type() != RTNLMessage::kMessageTypeRoute ||
+  if (msg.type() != RTNLMessage::kTypeRoute ||
       msg.family() == IPAddress::kAddressFamilyUnknown ||
       !msg.HasAttribute(RTA_OIF)) {
     return;
@@ -254,7 +254,7 @@
         nent->src.Equals(entry.src) &&
         nent->gateway.Equals(entry.gateway) &&
         nent->scope == entry.scope) {
-      if (msg.mode() == RTNLMessage::kMessageModeDelete) {
+      if (msg.mode() == RTNLMessage::kModeDelete) {
         table.erase(nent);
       } else {
         nent->from_rtnl = true;
@@ -264,20 +264,20 @@
     }
   }
 
-  if (msg.mode() == RTNLMessage::kMessageModeAdd) {
+  if (msg.mode() == RTNLMessage::kModeAdd) {
     table.push_back(entry);
   }
 }
 
 bool RoutingTable::ApplyRoute(uint32 interface_index,
                               const RoutingTableEntry &entry,
-                              RTNLMessage::MessageMode mode,
+                              RTNLMessage::Mode mode,
                               unsigned int flags) {
   VLOG(2) << base::StringPrintf("%s: index %d mode %d flags 0x%x",
                                 __func__, interface_index, mode, flags);
 
   RTNLMessage msg(
-      RTNLMessage::kMessageTypeRoute,
+      RTNLMessage::kTypeRoute,
       mode,
       NLM_F_REQUEST | flags,
       0,
diff --git a/routing_table.h b/routing_table.h
index ec141d8..5c00d0e 100644
--- a/routing_table.h
+++ b/routing_table.h
@@ -67,7 +67,7 @@
   void RouteMsgHandler(const RTNLMessage &msg);
   bool ApplyRoute(uint32 interface_index,
                   const RoutingTableEntry &entry,
-                  RTNLMessage::MessageMode mode,
+                  RTNLMessage::Mode mode,
                   unsigned int flags);
   bool FlushCache();
 
diff --git a/routing_table_unittest.cc b/routing_table_unittest.cc
index ab9fda6..f38ca67 100644
--- a/routing_table_unittest.cc
+++ b/routing_table_unittest.cc
@@ -41,7 +41,7 @@
     return &routing_table_->tables_;
   }
 
-  void SendRouteMsg(RTNLMessage::MessageMode mode,
+  void SendRouteMsg(RTNLMessage::Mode mode,
                     uint32 interface_index,
                     const RoutingTableEntry &entry);
 
@@ -93,7 +93,7 @@
   uint32 priority;
 
   return
-    msg.type() == RTNLMessage::kMessageTypeRoute &&
+    msg.type() == RTNLMessage::kTypeRoute &&
     msg.family() == entry.gateway.family() &&
     msg.flags() == (NLM_F_REQUEST | flags) &&
     status.table == RT_TABLE_MAIN &&
@@ -113,11 +113,11 @@
     priority == entry.metric;
 }
 
-void RoutingTableTest::SendRouteMsg(RTNLMessage::MessageMode mode,
+void RoutingTableTest::SendRouteMsg(RTNLMessage::Mode mode,
                                     uint32 interface_index,
                                     const RoutingTableEntry &entry) {
   RTNLMessage msg(
-      RTNLMessage::kMessageTypeRoute,
+      RTNLMessage::kTypeRoute,
       mode,
       0,
       0,
@@ -165,7 +165,7 @@
 }
 
 TEST_F(RoutingTableTest, RouteAddDelete) {
-  EXPECT_CALL(sockets_, SendTo(kTestSocket, _, _, 0, _, sizeof(sockaddr_nl)));
+  EXPECT_CALL(sockets_, Send(kTestSocket, _, _, 0));
   StartRTNLHandler();
   routing_table_->Start();
 
@@ -187,7 +187,7 @@
                            RT_SCOPE_UNIVERSE,
                            true);
   // Add a single entry
-  SendRouteMsg(RTNLMessage::kMessageModeAdd,
+  SendRouteMsg(RTNLMessage::kModeAdd,
                kTestDeviceIndex0,
                entry0);
 
@@ -203,7 +203,7 @@
   EXPECT_TRUE(entry0.Equals(test_entry));
 
   // Add a second entry for a different interface
-  SendRouteMsg(RTNLMessage::kMessageModeAdd,
+  SendRouteMsg(RTNLMessage::kModeAdd,
                kTestDeviceIndex1,
                entry0);
 
@@ -227,7 +227,7 @@
                            true);
 
   // Add a second gateway route to the second interface
-  SendRouteMsg(RTNLMessage::kMessageModeAdd,
+  SendRouteMsg(RTNLMessage::kModeAdd,
                kTestDeviceIndex1,
                entry1);
 
@@ -240,7 +240,7 @@
   EXPECT_TRUE(entry1.Equals(test_entry));
 
   // Remove the first gateway route from the second interface
-  SendRouteMsg(RTNLMessage::kMessageModeDelete,
+  SendRouteMsg(RTNLMessage::kModeDelete,
                kTestDeviceIndex1,
                entry0);
 
@@ -255,7 +255,7 @@
   // Send a duplicate of the second gatway route message, changing the metric
   RoutingTableEntry entry2(entry1);
   entry2.metric++;
-  SendRouteMsg(RTNLMessage::kMessageModeAdd,
+  SendRouteMsg(RTNLMessage::kModeAdd,
                kTestDeviceIndex1,
                entry2);
 
@@ -276,7 +276,7 @@
                                                &test_entry));
 
   // Remove last entry from an existing interface and test that we now fail
-  SendRouteMsg(RTNLMessage::kMessageModeDelete,
+  SendRouteMsg(RTNLMessage::kModeDelete,
                kTestDeviceIndex1,
                entry2);
 
@@ -295,7 +295,7 @@
 
   EXPECT_CALL(sockets_,
               Send(kTestSocket,
-                   IsRoutingPacket(RTNLMessage::kMessageModeAdd,
+                   IsRoutingPacket(RTNLMessage::kModeAdd,
                                    kTestDeviceIndex1,
                                    entry0,
                                    NLM_F_CREATE | NLM_F_EXCL),
@@ -319,7 +319,7 @@
   entry4.metric += 10;
   EXPECT_CALL(sockets_,
               Send(kTestSocket,
-                   IsRoutingPacket(RTNLMessage::kMessageModeAdd,
+                   IsRoutingPacket(RTNLMessage::kModeAdd,
                                    kTestDeviceIndex1,
                                    entry4,
                                    NLM_F_CREATE | NLM_F_REPLACE),
@@ -342,7 +342,7 @@
   entry5.metric += 10;
   EXPECT_CALL(sockets_,
               Send(kTestSocket,
-                   IsRoutingPacket(RTNLMessage::kMessageModeAdd,
+                   IsRoutingPacket(RTNLMessage::kModeAdd,
                                    kTestDeviceIndex0,
                                    entry5,
                                    NLM_F_CREATE | NLM_F_REPLACE),
@@ -353,7 +353,7 @@
   // Ask to flush table0.  We should see a delete message sent
   EXPECT_CALL(sockets_,
               Send(kTestSocket,
-                   IsRoutingPacket(RTNLMessage::kMessageModeDelete,
+                   IsRoutingPacket(RTNLMessage::kModeDelete,
                                    kTestDeviceIndex0,
                                    entry0,
                                    0),
diff --git a/rtnl_handler.cc b/rtnl_handler.cc
index ce4447f..dc48c71 100644
--- a/rtnl_handler.cc
+++ b/rtnl_handler.cc
@@ -40,6 +40,7 @@
       rtnl_socket_(-1),
       request_flags_(0),
       request_sequence_(0),
+      last_dump_sequence_(0),
       rtnl_callback_(NewCallback(this, &RTNLHandler::ParseRTNL)) {
   VLOG(2) << "RTNLHandler created";
 }
@@ -68,7 +69,8 @@
 
   memset(&addr, 0, sizeof(addr));
   addr.nl_family = AF_NETLINK;
-  addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
+  addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
+      RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
 
   if (sockets->Bind(rtnl_socket_,
                     reinterpret_cast<struct sockaddr *>(&addr),
@@ -83,7 +85,7 @@
                                                      rtnl_callback_.get()));
   sockets_ = sockets;
 
-  NextRequest(request_sequence_);
+  NextRequest(last_dump_sequence_);
   VLOG(2) << "RTNLHandler started";
 }
 
@@ -153,7 +155,7 @@
           << std::dec << std::noshowbase;
 
   if (!in_request_ && sockets_)
-    NextRequest(request_sequence_);
+    NextRequest(last_dump_sequence_);
 }
 
 void RTNLHandler::DispatchEvent(int type, const RTNLMessage &msg) {
@@ -164,66 +166,43 @@
 }
 
 void RTNLHandler::NextRequest(uint32_t seq) {
-  struct rtnl_request {
-    struct nlmsghdr hdr;
-    struct rtgenmsg msg;
-  } req;
-  struct sockaddr_nl addr;
   int flag = 0;
+  RTNLMessage::Type type;
 
-  VLOG(2) << "RTNLHandler nextrequest " << seq << " " << request_sequence_
+  VLOG(2) << "RTNLHandler nextrequest " << seq << " " << last_dump_sequence_
           << std::showbase << std::hex
           << " " << request_flags_
           << std::dec << std::noshowbase;
 
-  if (seq != request_sequence_)
+  if (seq != last_dump_sequence_)
     return;
 
-  request_sequence_++;
-  memset(&req, 0, sizeof(req));
-
-  req.hdr.nlmsg_len = sizeof(req);
-  req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-  req.hdr.nlmsg_pid = 0;
-  req.hdr.nlmsg_seq = request_sequence_;
-
   if ((request_flags_ & kRequestLink) != 0) {
-    req.msg.rtgen_family = AF_INET;
-    req.hdr.nlmsg_type = RTM_GETLINK;
+    type = RTNLMessage::kTypeLink;
     flag = kRequestLink;
   } else if ((request_flags_ & kRequestAddr) != 0) {
-    req.msg.rtgen_family = AF_INET;
-    req.hdr.nlmsg_type = RTM_GETADDR;
+    type = RTNLMessage::kTypeAddress;
     flag = kRequestAddr;
   } else if ((request_flags_ & kRequestRoute) != 0) {
-    req.msg.rtgen_family = AF_INET;
-    req.hdr.nlmsg_type = RTM_GETROUTE;
+    type = RTNLMessage::kTypeRoute;
     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 {
+    VLOG(2) << "Done with requests";
     in_request_ = false;
     return;
   }
 
-  memset(&addr, 0, sizeof(addr));
-  addr.nl_family = AF_NETLINK;
+  RTNLMessage msg(
+      type,
+      RTNLMessage::kModeGet,
+      0,
+      0,
+      0,
+      0,
+      IPAddress::kAddressFamilyUnknown);
+  CHECK(SendMessage(&msg));
 
-  if (sockets_->SendTo(rtnl_socket_,
-                       &req,
-                       sizeof(req),
-                       0,
-                       reinterpret_cast<struct sockaddr *>(&addr),
-                       sizeof(addr)) < 0) {
-    LOG(ERROR) << "RTNL sendto failed";
-    return;
-  }
+  last_dump_sequence_ = msg.seq();
   request_flags_ &= ~flag;
   in_request_ = true;
 }
@@ -261,13 +240,13 @@
       }
     } else {
       switch (msg.type()) {
-        case RTNLMessage::kMessageTypeLink:
+        case RTNLMessage::kTypeLink:
           DispatchEvent(kRequestLink, msg);
           break;
-        case RTNLMessage::kMessageTypeAddress:
+        case RTNLMessage::kTypeAddress:
           DispatchEvent(kRequestAddr, msg);
           break;
-        case RTNLMessage::kMessageTypeRoute:
+        case RTNLMessage::kTypeRoute:
           DispatchEvent(kRequestRoute, msg);
           break;
         default:
@@ -278,92 +257,54 @@
   }
 }
 
-static bool AddAtribute(struct nlmsghdr *hdr, int max_msg_size, int attr_type,
-                        const void *attr_data, int attr_len) {
-  int len = RTA_LENGTH(attr_len);
-  int new_msg_size = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(len);
-  struct rtattr *rt_attr;
+bool RTNLHandler::AddressRequest(int interface_index,
+                                 RTNLMessage::Mode mode,
+                                 int flags,
+                                 const IPAddress &local,
+                                 const IPAddress &gateway) {
+  CHECK(local.family() == gateway.family());
 
-  if (new_msg_size > max_msg_size)
-    return false;
+  RTNLMessage msg(
+      RTNLMessage::kTypeAddress,
+      mode,
+      NLM_F_REQUEST | flags,
+      0,
+      0,
+      interface_index,
+      local.family());
 
-  rt_attr = reinterpret_cast<struct rtattr *> (reinterpret_cast<unsigned char *>
-                                               (hdr) +
-                                               NLMSG_ALIGN(hdr->nlmsg_len));
-  rt_attr->rta_type = attr_type;
-  rt_attr->rta_len = len;
-  memcpy(RTA_DATA(rt_attr), attr_data, attr_len);
-  hdr->nlmsg_len = new_msg_size;
-  return true;
-}
-
-bool RTNLHandler::AddressRequest(int interface_index, int cmd, int flags,
-                                 const IPConfig &ipconfig) {
-  const IPConfig::Properties &properties = ipconfig.properties();
-  int address_family;
-  int address_size;
-  unsigned char *attrs, *attrs_end;
-  int max_msg_size;
-  struct {
-    struct nlmsghdr   hdr;
-    struct ifaddrmsg  ifa;
-    unsigned char     attrs[256];
-  } req;
-  union {
-    in_addr ip4;
-    in6_addr in6;
-  } addr;
-
-  if (properties.address_family == IPAddress::kAddressFamilyIPv4) {
-    address_family = AF_INET;
-    address_size = sizeof(struct in_addr);
-  } else if (properties.address_family == IPAddress::kAddressFamilyIPv6) {
-    address_family = AF_INET6;
-    address_size = sizeof(struct in6_addr);
-  } else {
-    return false;
-  }
-
-  request_sequence_++;
-  memset(&req, 0, sizeof(req));
-  req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-  req.hdr.nlmsg_flags = NLM_F_REQUEST | flags;
-  req.hdr.nlmsg_type = cmd;
-  req.ifa.ifa_family = address_family;
-  req.ifa.ifa_index = interface_index;
-
-  max_msg_size = req.hdr.nlmsg_len + sizeof(req.attrs);
+  msg.set_address_status(RTNLMessage::AddressStatus(
+      local.prefix(),
+      0,
+      0));
 
   // TODO(pstew): This code only works for Ethernet-like setups,
   //              not with devices that have a peer address like PPP.
-  if (inet_pton(address_family, properties.address.c_str(), &addr) <= 0 ||
-      !AddAtribute(&req.hdr, max_msg_size, IFA_LOCAL, &addr, address_size))
-    return false;
-
-  if (inet_pton(address_family, properties.broadcast_address.c_str(),
-                &addr) <= 0 ||
-      !AddAtribute(&req.hdr, max_msg_size, IFA_BROADCAST, &addr, address_size))
-    return false;
-
-  req.ifa.ifa_prefixlen = properties.subnet_cidr;
-
-  if (sockets_->Send(rtnl_socket_, &req, req.hdr.nlmsg_len, 0) < 0) {
-    LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
-    return false;
+  msg.SetAttribute(IFA_LOCAL, local.address());
+  if (!gateway.IsDefault()) {
+    msg.SetAttribute(IFA_BROADCAST, gateway.address());
   }
 
-  return true;
+  return SendMessage(&msg);
 }
 
 bool RTNLHandler::AddInterfaceAddress(int interface_index,
-                                      const IPConfig &ipconfig) {
-  return AddressRequest(interface_index, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
-                        ipconfig);
+                                      const IPAddress &local,
+                                      const IPAddress &broadcast) {
+    return AddressRequest(interface_index,
+                          RTNLMessage::kModeAdd,
+                          NLM_F_CREATE | NLM_F_EXCL,
+                          local,
+                          broadcast);
 }
 
 bool RTNLHandler::RemoveInterfaceAddress(int interface_index,
-                                         const IPConfig &ipconfig) {
-  return AddressRequest(interface_index, RTM_DELADDR, 0, ipconfig);
+                                         const IPAddress &local) {
+  return AddressRequest(interface_index,
+                        RTNLMessage::kModeDelete,
+                        0,
+                        local,
+                        IPAddress(local.family()));
 }
 
 int RTNLHandler::GetInterfaceIndex(const string &interface_name) {
@@ -401,7 +342,7 @@
   }
 
   if (sockets_->Send(rtnl_socket_,
-                     msgdata.GetData(),
+                     msgdata.GetConstData(),
                      msgdata.GetLength(),
                      0) < 0) {
     PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
diff --git a/rtnl_handler.h b/rtnl_handler.h
index e395d2e..e9d8d77 100644
--- a/rtnl_handler.h
+++ b/rtnl_handler.h
@@ -19,6 +19,7 @@
 
 #include "shill/io_handler.h"
 #include "shill/rtnl_listener.h"
+#include "shill/rtnl_message.h"
 #include "shill/shill_event.h"
 
 struct nlmsghdr;
@@ -26,7 +27,6 @@
 namespace shill {
 
 class IPConfig;
-class RTNLMessage;
 class Sockets;
 
 // This singleton class is responsible for interacting with the RTNL subsystem.
@@ -43,8 +43,6 @@
   static const int kRequestLink = 1;
   static const int kRequestAddr = 2;
   static const int kRequestRoute = 4;
-  static const int kRequestAddr6 = 8;
-  static const int kRequestRoute6 = 16;
 
   virtual ~RTNLHandler();
 
@@ -72,12 +70,14 @@
 
   // Set address of a network interface that has a kernel index of
   // 'interface_index'.
-  virtual bool AddInterfaceAddress(int interface_index, const IPConfig &config);
+  virtual bool AddInterfaceAddress(int interface_index,
+                                   const IPAddress &local,
+                                   const IPAddress &gateway);
 
   // Remove address from a network interface that has a kernel index of
   // 'interface_index'.
   virtual bool RemoveInterfaceAddress(int interface_index,
-                                      const IPConfig &config);
+                                      const IPAddress &local);
 
   // Request that various tables (link, address, routing) tables be
   // exhaustively dumped via RTNL.  As results arrive from the kernel
@@ -117,15 +117,19 @@
   void NextRequest(uint32_t seq);
   // Parse an incoming rtnl message from the kernel
   void ParseRTNL(InputData *data);
-  bool AddressRequest(int interface_index, int cmd, int flags,
-                      const IPConfig &config);
 
+  bool AddressRequest(int interface_index,
+                      RTNLMessage::Mode mode,
+                      int flags,
+                      const IPAddress &local,
+                      const IPAddress &gateway);
   Sockets *sockets_;
   bool in_request_;
 
   int rtnl_socket_;
   uint32_t request_flags_;
   uint32_t request_sequence_;
+  uint32_t last_dump_sequence_;
 
   std::vector<RTNLListener *> listeners_;
   scoped_ptr<Callback1<InputData *>::Type> rtnl_callback_;
diff --git a/rtnl_handler_unittest.cc b/rtnl_handler_unittest.cc
index a715965..2eb36da 100644
--- a/rtnl_handler_unittest.cc
+++ b/rtnl_handler_unittest.cc
@@ -106,8 +106,8 @@
 }
 
 void RTNLHandlerTest::AddLink() {
-  RTNLMessage message(RTNLMessage::kMessageTypeLink,
-                      RTNLMessage::kMessageModeAdd,
+  RTNLMessage message(RTNLMessage::kTypeLink,
+                      RTNLMessage::kModeAdd,
                       0,
                       0,
                       0,
diff --git a/rtnl_message.cc b/rtnl_message.cc
index 92636e4..711a53e 100644
--- a/rtnl_message.cc
+++ b/rtnl_message.cc
@@ -26,14 +26,14 @@
 };
 
 RTNLMessage::RTNLMessage()
-    : type_(kMessageTypeUnknown),
-      mode_(kMessageModeUnknown),
+    : type_(kTypeUnknown),
+      mode_(kModeUnknown),
       flags_(0),
       interface_index_(0),
       family_(IPAddress::kAddressFamilyUnknown) {}
 
-RTNLMessage::RTNLMessage(MessageType type,
-                         MessageMode mode,
+RTNLMessage::RTNLMessage(Type type,
+                         Mode mode,
                          unsigned int flags,
                          uint32 seq,
                          uint32 pid,
@@ -50,8 +50,8 @@
 bool RTNLMessage::Decode(const ByteString &msg) {
   bool ret = DecodeInternal(msg);
   if (!ret) {
-    mode_ = kMessageModeUnknown;
-    type_ = kMessageTypeUnknown;
+    mode_ = kModeUnknown;
+    type_ = kTypeUnknown;
   }
   return ret;
 }
@@ -64,18 +64,18 @@
       msg.GetLength() < hdr->hdr.nlmsg_len)
     return false;
 
-  MessageMode mode = kMessageModeUnknown;
+  Mode mode = kModeUnknown;
   switch (hdr->hdr.nlmsg_type) {
   case RTM_NEWLINK:
   case RTM_NEWADDR:
   case RTM_NEWROUTE:
-    mode = kMessageModeAdd;
+    mode = kModeAdd;
     break;
 
   case RTM_DELLINK:
   case RTM_DELADDR:
   case RTM_DELROUTE:
-    mode = kMessageModeDelete;
+    mode = kModeDelete;
     break;
 
   default:
@@ -130,7 +130,7 @@
 }
 
 bool RTNLMessage::DecodeLink(const RTNLHeader *hdr,
-                             MessageMode mode,
+                             Mode mode,
                              rtattr **attr_data,
                              int *attr_length) {
   if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
@@ -141,7 +141,7 @@
   *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
   *attr_length = IFLA_PAYLOAD(&hdr->hdr);
 
-  type_ = kMessageTypeLink;
+  type_ = kTypeLink;
   family_ = hdr->ifi.ifi_family;
   interface_index_ = hdr->ifi.ifi_index;
   set_link_status(LinkStatus(hdr->ifi.ifi_type,
@@ -151,7 +151,7 @@
 }
 
 bool RTNLMessage::DecodeAddress(const RTNLHeader *hdr,
-                                MessageMode mode,
+                                Mode mode,
                                 rtattr **attr_data,
                                 int *attr_length) {
   if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
@@ -161,7 +161,7 @@
   *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
   *attr_length = IFA_PAYLOAD(&hdr->hdr);
 
-  type_ = kMessageTypeAddress;
+  type_ = kTypeAddress;
   family_ = hdr->ifa.ifa_family;
   interface_index_ = hdr->ifa.ifa_index;
   set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
@@ -171,7 +171,7 @@
 }
 
 bool RTNLMessage::DecodeRoute(const RTNLHeader *hdr,
-                              MessageMode mode,
+                              Mode mode,
                               rtattr **attr_data,
                               int *attr_length) {
   if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
@@ -181,7 +181,7 @@
   *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
   *attr_length = RTM_PAYLOAD(&hdr->hdr);
 
-  type_ = kMessageTypeRoute;
+  type_ = kTypeRoute;
   family_ = hdr->rtm.rtm_family;
   set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
                                hdr->rtm.rtm_src_len,
@@ -194,9 +194,9 @@
 }
 
 ByteString RTNLMessage::Encode() {
-  if (type_ != kMessageTypeLink &&
-      type_ != kMessageTypeAddress &&
-      type_ != kMessageTypeRoute) {
+  if (type_ != kTypeLink &&
+      type_ != kTypeAddress &&
+      type_ != kTypeRoute) {
     return ByteString();
   }
 
@@ -206,27 +206,28 @@
   hdr.hdr.nlmsg_pid = pid_;
   hdr.hdr.nlmsg_seq = 0;
 
-  if (mode_ == kMessageModeGet) {
-    if (type_ == kMessageTypeLink) {
+  if (mode_ == kModeGet) {
+    if (type_ == kTypeLink) {
       hdr.hdr.nlmsg_type = RTM_GETLINK;
-    } else if (type_ == kMessageTypeAddress) {
+    } else if (type_ == kTypeAddress) {
       hdr.hdr.nlmsg_type = RTM_GETADDR;
-    } else if (type_ == kMessageTypeRoute) {
+    } else if (type_ == kTypeRoute) {
       hdr.hdr.nlmsg_type = RTM_GETROUTE;
     }
     hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
+    hdr.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
     hdr.gen.rtgen_family = family_;
   } else {
     switch (type_) {
-    case kMessageTypeLink:
+    case kTypeLink:
       EncodeLink(&hdr);
       break;
 
-    case kMessageTypeAddress:
+    case kTypeAddress:
       EncodeAddress(&hdr);
       break;
 
-    case kMessageTypeRoute:
+    case kTypeRoute:
       EncodeRoute(&hdr);
       break;
 
@@ -261,7 +262,7 @@
 }
 
 void RTNLMessage::EncodeLink(RTNLHeader *hdr) {
-  hdr->hdr.nlmsg_type = (mode_ == kMessageModeAdd) ? RTM_NEWLINK : RTM_DELLINK;
+  hdr->hdr.nlmsg_type = (mode_ == kModeAdd) ? RTM_NEWLINK : RTM_DELLINK;
   hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
   hdr->ifi.ifi_family = family_;
   hdr->ifi.ifi_type = link_status_.type;
@@ -270,7 +271,7 @@
 }
 
 void RTNLMessage::EncodeAddress(RTNLHeader *hdr) {
-  hdr->hdr.nlmsg_type = (mode_ == kMessageModeAdd) ? RTM_NEWADDR : RTM_DELADDR;
+  hdr->hdr.nlmsg_type = (mode_ == kModeAdd) ? RTM_NEWADDR : RTM_DELADDR;
   hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
   hdr->ifa.ifa_family = family_;
   hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
@@ -280,8 +281,7 @@
 }
 
 void RTNLMessage::EncodeRoute(RTNLHeader *hdr) {
-  hdr->hdr.nlmsg_type =
-      (mode_ == kMessageModeAdd) ? RTM_NEWROUTE : RTM_DELROUTE;
+  hdr->hdr.nlmsg_type = (mode_ == kModeAdd) ? RTM_NEWROUTE : RTM_DELROUTE;
   hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
   hdr->rtm.rtm_family = family_;
   hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
diff --git a/rtnl_message.h b/rtnl_message.h
index dff4571..9e8dd0a 100644
--- a/rtnl_message.h
+++ b/rtnl_message.h
@@ -20,18 +20,18 @@
 
 class RTNLMessage {
   public:
-    enum MessageType {
-      kMessageTypeUnknown,
-      kMessageTypeLink,
-      kMessageTypeAddress,
-      kMessageTypeRoute
+    enum Type {
+      kTypeUnknown,
+      kTypeLink,
+      kTypeAddress,
+      kTypeRoute
     };
 
-    enum MessageMode {
-      kMessageModeUnknown,
-      kMessageModeGet,
-      kMessageModeAdd,
-      kMessageModeDelete
+    enum Mode {
+      kModeUnknown,
+      kModeGet,
+      kModeAdd,
+      kModeDelete
     };
 
     struct LinkStatus {
@@ -101,8 +101,8 @@
     // Empty constructor
     RTNLMessage();
     // Build an RTNL message from arguments
-    RTNLMessage(MessageType type,
-                MessageMode mode,
+    RTNLMessage(Type type,
+                Mode mode,
                 unsigned int flags,
                 uint32 seq,
                 uint32 pid,
@@ -115,8 +115,8 @@
     ByteString Encode();
 
     // Getters and setters
-    MessageType type() const { return type_; }
-    MessageMode mode() const { return mode_; }
+    Type type() const { return type_; }
+    Mode mode() const { return mode_; }
     uint16 flags() const { return flags_; }
     uint32 seq() const { return seq_; }
     void set_seq(uint32 seq) { seq_ = seq; }
@@ -125,13 +125,15 @@
     IPAddress::Family family() const { return family_; }
 
     const LinkStatus &link_status() const { return link_status_; }
-    void set_link_status(LinkStatus link_status) { link_status_ = link_status; }
+    void set_link_status(const LinkStatus &link_status) {
+      link_status_ = link_status;
+    }
     const AddressStatus &address_status() const { return address_status_; }
-    void set_address_status(AddressStatus address_status) {
+    void set_address_status(const AddressStatus &address_status) {
       address_status_ = address_status;
     }
     const RouteStatus &route_status() const { return route_status_; }
-    void set_route_status(RouteStatus route_status) {
+    void set_route_status(const RouteStatus &route_status) {
       route_status_ = route_status;
     }
     // GLint hates "unsigned short", and I don't blame it, but that's the
@@ -151,23 +153,23 @@
   private:
     bool DecodeInternal(const ByteString &msg);
     bool DecodeLink(const RTNLHeader *hdr,
-                    MessageMode mode,
+                    Mode mode,
                     rtattr **attr_data,
                     int *attr_length);
     bool DecodeAddress(const RTNLHeader *hdr,
-                       MessageMode mode,
+                       Mode mode,
                        rtattr **attr_data,
                        int *attr_length);
     bool DecodeRoute(const RTNLHeader *hdr,
-                     MessageMode mode,
+                     Mode mode,
                      rtattr **attr_data,
                      int *attr_length);
     void EncodeLink(RTNLHeader *hdr);
     void EncodeAddress(RTNLHeader *hdr);
     void EncodeRoute(RTNLHeader *hdr);
 
-    MessageType type_;
-    MessageMode mode_;
+    Type type_;
+    Mode mode_;
     uint16 flags_;
     uint32 seq_;
     uint32 pid_;
diff --git a/rtnl_message_unittest.cc b/rtnl_message_unittest.cc
index cae6ae1..f74136a 100644
--- a/rtnl_message_unittest.cc
+++ b/rtnl_message_unittest.cc
@@ -333,7 +333,7 @@
 class RTNLMessageTest : public Test {
  protected:
   void TestParseLink(const ByteString &packet,
-                     RTNLMessage::MessageMode mode,
+                     RTNLMessage::Mode mode,
                      int interface_index,
                      unsigned int flags,
                      unsigned int change,
@@ -345,7 +345,7 @@
     RTNLMessage msg;
     EXPECT_TRUE(msg.Decode(packet));
 
-    EXPECT_EQ(RTNLMessage::kMessageTypeLink, msg.type());
+    EXPECT_EQ(RTNLMessage::kTypeLink, msg.type());
     EXPECT_EQ(mode, msg.mode());
     EXPECT_EQ(interface_index, msg.interface_index());
 
@@ -375,14 +375,14 @@
   }
 
   void TestParseAddress(const ByteString &packet,
-                        RTNLMessage::MessageMode mode,
+                        RTNLMessage::Mode mode,
                         int interface_index,
                         const IPAddress &address,
                         unsigned char scope) {
     RTNLMessage msg;
 
     EXPECT_TRUE(msg.Decode(packet));
-    EXPECT_EQ(RTNLMessage::kMessageTypeAddress, msg.type());
+    EXPECT_EQ(RTNLMessage::kTypeAddress, msg.type());
     EXPECT_EQ(mode, msg.mode());
     EXPECT_EQ(interface_index, msg.interface_index());
     EXPECT_EQ(address.family(), msg.family());
@@ -399,7 +399,7 @@
   }
 
   void TestParseRoute(const ByteString &packet,
-                      RTNLMessage::MessageMode mode,
+                      RTNLMessage::Mode mode,
                       IPAddress::Family family,
                       int interface_index,
                       const IPAddress &dst,
@@ -413,7 +413,7 @@
     RTNLMessage msg;
 
     EXPECT_TRUE(msg.Decode(packet));
-    EXPECT_EQ(RTNLMessage::kMessageTypeRoute, msg.type());
+    EXPECT_EQ(RTNLMessage::kTypeRoute, msg.type());
     EXPECT_EQ(0, msg.interface_index());
     EXPECT_EQ(family, msg.family());
 
@@ -465,7 +465,7 @@
 
 TEST_F(RTNLMessageTest, NewLinkWlan0) {
   TestParseLink(ByteString(kNewLinkMessageWlan0, sizeof(kNewLinkMessageWlan0)),
-                RTNLMessage::kMessageModeAdd,
+                RTNLMessage::kModeAdd,
                 kNewLinkMessageWlan0InterfaceIndex,
                 kNewLinkMessageWlan0InterfaceFlags,
                 kNewLinkMessageWlan0InterfaceFlagsChange,
@@ -478,7 +478,7 @@
 
 TEST_F(RTNLMessageTest, DelLinkEth0) {
   TestParseLink(ByteString(kDelLinkMessageEth0, sizeof(kDelLinkMessageEth0)),
-                RTNLMessage::kMessageModeDelete,
+                RTNLMessage::kModeDelete,
                 kDelLinkMessageEth0InterfaceIndex,
                 kDelLinkMessageEth0InterfaceFlags,
                 kDelLinkMessageEth0InterfaceFlagsChange,
@@ -495,7 +495,7 @@
   EXPECT_TRUE(addr.SetAddressFromString(kNewAddrIPV4Address));
   addr.set_prefix(kNewAddrIPV4AddressPrefix);
   TestParseAddress(ByteString(kNewAddrIPV4, sizeof(kNewAddrIPV4)),
-                   RTNLMessage::kMessageModeAdd,
+                   RTNLMessage::kModeAdd,
                    kNewAddrIPV4InterfaceIndex,
                    addr,
                    kNewAddrIPV4Scope);
@@ -512,7 +512,7 @@
   EXPECT_TRUE(gateway.SetAddressFromString(kDelRouteIPV6Address));
 
   TestParseRoute(ByteString(kDelRouteIPV6, sizeof(kDelRouteIPV6)),
-                 RTNLMessage::kMessageModeDelete,
+                 RTNLMessage::kModeDelete,
                  IPAddress::kAddressFamilyIPv6,
                  kDelRouteIPV6InterfaceIndex,
                  dst,
@@ -535,7 +535,7 @@
   EXPECT_TRUE(gateway.SetAddressFromString(kAddRouteIPV4Address));
 
   TestParseRoute(ByteString(kAddRouteIPV4, sizeof(kAddRouteIPV4)),
-                 RTNLMessage::kMessageModeAdd,
+                 RTNLMessage::kModeAdd,
                  IPAddress::kAddressFamilyIPv4,
                  kAddRouteIPV4InterfaceIndex,
                  dst,
@@ -563,8 +563,8 @@
 }
 
 TEST_F(RTNLMessageTest, Encode) {
-  RTNLMessage msg(RTNLMessage::kMessageTypeRoute,
-                  RTNLMessage::kMessageModeAdd,
+  RTNLMessage msg(RTNLMessage::kTypeRoute,
+                  RTNLMessage::kModeAdd,
                   0, 1, 2, 0,
                   IPAddress::kAddressFamilyIPv4);
   IPAddress dst(IPAddress::kAddressFamilyIPv4);
@@ -585,7 +585,7 @@
 
 
   TestParseRoute(msg.Encode(),
-                 RTNLMessage::kMessageModeAdd,
+                 RTNLMessage::kModeAdd,
                  IPAddress::kAddressFamilyIPv4,
                  12,
                  dst,