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,