blob: 5c80e40ab67c7e0b80c576c0c395d29801a357f2 [file] [log] [blame]
Chris Masone9be4a9d2011-05-16 15:44:09 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Darin Petkov633ac6f2011-07-08 13:56:13 -07004
Chris Masone2aa97072011-08-09 17:35:08 -07005#include "shill/device_info.h"
6
Chris Masone9be4a9d2011-05-16 15:44:09 -07007#include <glib.h>
Darin Petkov633ac6f2011-07-08 13:56:13 -07008#include <sys/socket.h>
Darin Petkove6193c02011-08-11 12:42:40 -07009#include <linux/if.h>
Darin Petkov633ac6f2011-07-08 13:56:13 -070010#include <linux/netlink.h> // Needs typedefs from sys/socket.h.
11#include <linux/rtnetlink.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070012
13#include <base/callback_old.h>
14#include <base/logging.h>
15#include <base/memory/ref_counted.h>
16#include <base/message_loop.h>
Darin Petkov633ac6f2011-07-08 13:56:13 -070017#include <base/stl_util-inl.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070018#include <gtest/gtest.h>
19#include <gmock/gmock.h>
20
Paul Stewart9a908082011-08-31 12:18:48 -070021#include "shill/ip_address.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070022#include "shill/manager.h"
Chris Masone46eaaf52011-05-24 13:08:30 -070023#include "shill/mock_control.h"
Darin Petkovafa6fc42011-06-21 16:21:08 -070024#include "shill/mock_glib.h"
Chris Masone2ae797d2011-08-23 20:41:00 -070025#include "shill/mock_manager.h"
Paul Stewart9a908082011-08-31 12:18:48 -070026#include "shill/mock_rtnl_handler.h"
Darin Petkov633ac6f2011-07-08 13:56:13 -070027#include "shill/mock_sockets.h"
Chris Masone2aa97072011-08-09 17:35:08 -070028#include "shill/rtnl_message.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070029
Darin Petkove6193c02011-08-11 12:42:40 -070030using std::map;
Darin Petkov633ac6f2011-07-08 13:56:13 -070031using std::string;
Paul Stewart9a908082011-08-31 12:18:48 -070032using std::vector;
Darin Petkov633ac6f2011-07-08 13:56:13 -070033using testing::_;
34using testing::Return;
Paul Stewart9a908082011-08-31 12:18:48 -070035using testing::StrictMock;
Darin Petkov633ac6f2011-07-08 13:56:13 -070036using testing::Test;
37
Chris Masone9be4a9d2011-05-16 15:44:09 -070038namespace shill {
Darin Petkov633ac6f2011-07-08 13:56:13 -070039
40class TestEventDispatcher : public EventDispatcher {
41 public:
42 virtual IOInputHandler *CreateInputHandler(
43 int fd,
44 Callback1<InputData*>::Type *callback) {
45 return NULL;
46 }
47};
Chris Masone9be4a9d2011-05-16 15:44:09 -070048
49class DeviceInfoTest : public Test {
50 public:
51 DeviceInfoTest()
Darin Petkov887f2982011-07-14 16:10:17 -070052 : manager_(&control_interface_, &dispatcher_, &glib_),
Chris Masone2aa97072011-08-09 17:35:08 -070053 device_info_(&control_interface_, &dispatcher_, &manager_) {
Chris Masone9be4a9d2011-05-16 15:44:09 -070054 }
Darin Petkov633ac6f2011-07-08 13:56:13 -070055
Paul Stewart9a908082011-08-31 12:18:48 -070056 virtual void SetUp() {
57 device_info_.rtnl_handler_ = &rtnl_handler_;
58 EXPECT_CALL(rtnl_handler_, RequestDump(RTNLHandler::kRequestLink |
59 RTNLHandler::kRequestAddr));
60 }
61
Paul Stewarta3c56f92011-05-26 07:08:52 -070062 protected:
Chris Masoneb2e326b2011-07-12 13:28:51 -070063 static const int kTestDeviceIndex;
Darin Petkov633ac6f2011-07-08 13:56:13 -070064 static const char kTestDeviceName[];
Paul Stewart9a908082011-08-31 12:18:48 -070065 static const char kTestMACAddress[];
66 static const char kTestIPAddress0[];
67 static const int kTestIPAddressPrefix0;
68 static const char kTestIPAddress1[];
69 static const int kTestIPAddressPrefix1;
70 static const char kTestIPAddress2[];
71 static const char kTestIPAddress3[];
72 static const char kTestIPAddress4[];
Darin Petkov633ac6f2011-07-08 13:56:13 -070073
Paul Stewart9a908082011-08-31 12:18:48 -070074 RTNLMessage *BuildLinkMessage(RTNLMessage::Mode mode);
75 RTNLMessage *BuildAddressMessage(RTNLMessage::Mode mode,
76 const IPAddress &address,
77 unsigned char flags,
78 unsigned char scope);
Chris Masone2aa97072011-08-09 17:35:08 -070079 void SendMessageToDeviceInfo(const RTNLMessage &message);
Darin Petkov633ac6f2011-07-08 13:56:13 -070080
Darin Petkovafa6fc42011-06-21 16:21:08 -070081 MockGLib glib_;
Chris Masone46eaaf52011-05-24 13:08:30 -070082 MockControl control_interface_;
Paul Stewart9a908082011-08-31 12:18:48 -070083 StrictMock<MockManager> manager_;
Chris Masone9be4a9d2011-05-16 15:44:09 -070084 DeviceInfo device_info_;
Darin Petkov633ac6f2011-07-08 13:56:13 -070085 TestEventDispatcher dispatcher_;
Paul Stewart9a908082011-08-31 12:18:48 -070086 StrictMock<MockRTNLHandler> rtnl_handler_;
Chris Masone9be4a9d2011-05-16 15:44:09 -070087};
88
Chris Masoneb2e326b2011-07-12 13:28:51 -070089const int DeviceInfoTest::kTestDeviceIndex = 123456;
Darin Petkov633ac6f2011-07-08 13:56:13 -070090const char DeviceInfoTest::kTestDeviceName[] = "test-device";
Paul Stewart9a908082011-08-31 12:18:48 -070091const char DeviceInfoTest::kTestMACAddress[] = {
Darin Petkove3e1cfa2011-08-11 13:41:17 -070092 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
Paul Stewart9a908082011-08-31 12:18:48 -070093const char DeviceInfoTest::kTestIPAddress0[] = "192.168.1.1";
94const int DeviceInfoTest::kTestIPAddressPrefix0 = 24;
95const char DeviceInfoTest::kTestIPAddress1[] = "fe80::1aa9:5ff:abcd:1234";
96const int DeviceInfoTest::kTestIPAddressPrefix1 = 64;
97const char DeviceInfoTest::kTestIPAddress2[] = "fe80::1aa9:5ff:abcd:1235";
98const char DeviceInfoTest::kTestIPAddress3[] = "fe80::1aa9:5ff:abcd:1236";
99const char DeviceInfoTest::kTestIPAddress4[] = "fe80::1aa9:5ff:abcd:1237";
Chris Masone9be4a9d2011-05-16 15:44:09 -0700100
Paul Stewart9a908082011-08-31 12:18:48 -0700101RTNLMessage *DeviceInfoTest::BuildLinkMessage(RTNLMessage::Mode mode) {
102 RTNLMessage *message = new RTNLMessage(
103 RTNLMessage::kTypeLink,
104 mode,
105 0,
106 0,
107 0,
108 kTestDeviceIndex,
Paul Stewart7355ce12011-09-02 10:47:01 -0700109 IPAddress::kFamilyIPv4);
Chris Masone2aa97072011-08-09 17:35:08 -0700110 message->SetAttribute(static_cast<uint16>(IFLA_IFNAME),
111 ByteString(kTestDeviceName, true));
Paul Stewart9a908082011-08-31 12:18:48 -0700112 ByteString test_address(kTestMACAddress, sizeof(kTestMACAddress));
Chris Masone626719f2011-08-18 16:58:48 -0700113 message->SetAttribute(IFLA_ADDRESS, test_address);
Chris Masone2aa97072011-08-09 17:35:08 -0700114 return message;
Darin Petkov633ac6f2011-07-08 13:56:13 -0700115}
116
Paul Stewart9a908082011-08-31 12:18:48 -0700117RTNLMessage *DeviceInfoTest::BuildAddressMessage(RTNLMessage::Mode mode,
118 const IPAddress &address,
119 unsigned char flags,
120 unsigned char scope) {
121 RTNLMessage *message = new RTNLMessage(
122 RTNLMessage::kTypeAddress,
123 mode,
124 0,
125 0,
126 0,
127 kTestDeviceIndex,
128 address.family());
129 message->SetAttribute(IFA_ADDRESS, address.address());
130 message->set_address_status(
131 RTNLMessage::AddressStatus(address.prefix(), flags, scope));
132 return message;
133}
134
Chris Masone2aa97072011-08-09 17:35:08 -0700135void DeviceInfoTest::SendMessageToDeviceInfo(const RTNLMessage &message) {
Paul Stewart9a908082011-08-31 12:18:48 -0700136 if (message.type() == RTNLMessage::kTypeLink) {
137 device_info_.LinkMsgHandler(message);
138 } else if (message.type() == RTNLMessage::kTypeAddress) {
139 device_info_.AddressMsgHandler(message);
140 } else {
141 NOTREACHED();
142 }
143}
144
145MATCHER_P(IsIPAddress, address, "") {
146 // NB: IPAddress objects don't support the "==" operator as per style, so
147 // we need a custom matcher.
148 return address.Equals(arg);
Darin Petkov633ac6f2011-07-08 13:56:13 -0700149}
150
151TEST_F(DeviceInfoTest, DeviceEnumeration) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700152 // Start our own private device_info
Chris Masone9be4a9d2011-05-16 15:44:09 -0700153 device_info_.Start();
Paul Stewart9a908082011-08-31 12:18:48 -0700154 scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
Darin Petkove6193c02011-08-11 12:42:40 -0700155 message->set_link_status(RTNLMessage::LinkStatus(0, IFF_LOWER_UP, 0));
156 EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
157 SendMessageToDeviceInfo(*message);
158 EXPECT_TRUE(device_info_.GetDevice(kTestDeviceIndex).get());
159 unsigned int flags = 0;
160 EXPECT_TRUE(device_info_.GetFlags(kTestDeviceIndex, &flags));
161 EXPECT_EQ(IFF_LOWER_UP, flags);
Darin Petkove3e1cfa2011-08-11 13:41:17 -0700162 ByteString address;
Paul Stewart32852962011-08-30 14:06:53 -0700163 EXPECT_TRUE(device_info_.GetMACAddress(kTestDeviceIndex, &address));
Darin Petkove3e1cfa2011-08-11 13:41:17 -0700164 EXPECT_FALSE(address.IsEmpty());
Paul Stewart9a908082011-08-31 12:18:48 -0700165 EXPECT_TRUE(address.Equals(ByteString(kTestMACAddress,
166 sizeof(kTestMACAddress))));
Paul Stewarta3c56f92011-05-26 07:08:52 -0700167
Paul Stewart9a908082011-08-31 12:18:48 -0700168 message.reset(BuildLinkMessage(RTNLMessage::kModeAdd));
Darin Petkove6193c02011-08-11 12:42:40 -0700169 message->set_link_status(RTNLMessage::LinkStatus(0, IFF_UP | IFF_RUNNING, 0));
170 SendMessageToDeviceInfo(*message);
171 EXPECT_TRUE(device_info_.GetFlags(kTestDeviceIndex, &flags));
172 EXPECT_EQ(IFF_UP | IFF_RUNNING, flags);
Paul Stewartb50f0b92011-05-16 16:31:42 -0700173
Paul Stewart9a908082011-08-31 12:18:48 -0700174 message.reset(BuildLinkMessage(RTNLMessage::kModeDelete));
Darin Petkove6193c02011-08-11 12:42:40 -0700175 SendMessageToDeviceInfo(*message);
176 EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
177 EXPECT_FALSE(device_info_.GetFlags(kTestDeviceIndex, NULL));
Paul Stewarta3c56f92011-05-26 07:08:52 -0700178
Paul Stewarta3c56f92011-05-26 07:08:52 -0700179 device_info_.Stop();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700180}
181
mukesh agrawal8f317b62011-07-15 11:53:23 -0700182TEST_F(DeviceInfoTest, DeviceBlackList) {
183 device_info_.AddDeviceToBlackList(kTestDeviceName);
184 device_info_.Start();
Paul Stewart9a908082011-08-31 12:18:48 -0700185 scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
Darin Petkove6193c02011-08-11 12:42:40 -0700186 SendMessageToDeviceInfo(*message);
mukesh agrawal8f317b62011-07-15 11:53:23 -0700187
Darin Petkove6193c02011-08-11 12:42:40 -0700188 DeviceRefPtr device = device_info_.GetDevice(kTestDeviceIndex);
189 ASSERT_TRUE(device.get());
190 EXPECT_TRUE(device->TechnologyIs(Device::kBlacklisted));
mukesh agrawal8f317b62011-07-15 11:53:23 -0700191
mukesh agrawal8f317b62011-07-15 11:53:23 -0700192 device_info_.Stop();
193}
194
Paul Stewart9a908082011-08-31 12:18:48 -0700195TEST_F(DeviceInfoTest, DeviceAddressList) {
196 device_info_.Start();
197 scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
198 SendMessageToDeviceInfo(*message);
199
200 vector<DeviceInfo::AddressData> addresses;
201 EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
202 EXPECT_TRUE(addresses.empty());
203
204 // Add an address to the device address list
Paul Stewart7355ce12011-09-02 10:47:01 -0700205 IPAddress ip_address0(IPAddress::kFamilyIPv4);
Paul Stewart9a908082011-08-31 12:18:48 -0700206 EXPECT_TRUE(ip_address0.SetAddressFromString(kTestIPAddress0));
207 ip_address0.set_prefix(kTestIPAddressPrefix0);
208 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd, ip_address0, 0, 0));
209 SendMessageToDeviceInfo(*message);
210 EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
211 EXPECT_EQ(1, addresses.size());
212 EXPECT_TRUE(ip_address0.Equals(addresses[0].address));
213
214 // Re-adding the same address shouldn't cause the address list to change
215 SendMessageToDeviceInfo(*message);
216 EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
217 EXPECT_EQ(1, addresses.size());
218 EXPECT_TRUE(ip_address0.Equals(addresses[0].address));
219
220 // Adding a new address should expand the list
Paul Stewart7355ce12011-09-02 10:47:01 -0700221 IPAddress ip_address1(IPAddress::kFamilyIPv6);
Paul Stewart9a908082011-08-31 12:18:48 -0700222 EXPECT_TRUE(ip_address1.SetAddressFromString(kTestIPAddress1));
223 ip_address1.set_prefix(kTestIPAddressPrefix1);
224 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd, ip_address1, 0, 0));
225 SendMessageToDeviceInfo(*message);
226 EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
227 EXPECT_EQ(2, addresses.size());
228 EXPECT_TRUE(ip_address0.Equals(addresses[0].address));
229 EXPECT_TRUE(ip_address1.Equals(addresses[1].address));
230
231 // Deleting an address should reduce the list
232 message.reset(BuildAddressMessage(RTNLMessage::kModeDelete,
233 ip_address0,
234 0,
235 0));
236 SendMessageToDeviceInfo(*message);
237 EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
238 EXPECT_EQ(1, addresses.size());
239 EXPECT_TRUE(ip_address1.Equals(addresses[0].address));
240
241 // Delete last item
242 message.reset(BuildAddressMessage(RTNLMessage::kModeDelete,
243 ip_address1,
244 0,
245 0));
246 SendMessageToDeviceInfo(*message);
247 EXPECT_TRUE(device_info_.GetAddresses(kTestDeviceIndex, &addresses));
248 EXPECT_TRUE(addresses.empty());
249
250 // Delete device
251 message.reset(BuildLinkMessage(RTNLMessage::kModeDelete));
252 SendMessageToDeviceInfo(*message);
253
254 // Should be able to handle message for interface that doesn't exist
255 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd, ip_address0, 0, 0));
256 SendMessageToDeviceInfo(*message);
257 EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
258
259 device_info_.Stop();
260}
261
262TEST_F(DeviceInfoTest, FlushAddressList) {
263 device_info_.Start();
264 scoped_ptr<RTNLMessage> message(BuildLinkMessage(RTNLMessage::kModeAdd));
265 SendMessageToDeviceInfo(*message);
266
Paul Stewart7355ce12011-09-02 10:47:01 -0700267 IPAddress address1(IPAddress::kFamilyIPv6);
Paul Stewart9a908082011-08-31 12:18:48 -0700268 EXPECT_TRUE(address1.SetAddressFromString(kTestIPAddress1));
269 address1.set_prefix(kTestIPAddressPrefix1);
270 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
271 address1,
272 0,
273 RT_SCOPE_UNIVERSE));
274 SendMessageToDeviceInfo(*message);
Paul Stewart7355ce12011-09-02 10:47:01 -0700275 IPAddress address2(IPAddress::kFamilyIPv6);
Paul Stewart9a908082011-08-31 12:18:48 -0700276 EXPECT_TRUE(address2.SetAddressFromString(kTestIPAddress2));
277 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
278 address2,
279 IFA_F_TEMPORARY,
280 RT_SCOPE_UNIVERSE));
281 SendMessageToDeviceInfo(*message);
Paul Stewart7355ce12011-09-02 10:47:01 -0700282 IPAddress address3(IPAddress::kFamilyIPv6);
Paul Stewart9a908082011-08-31 12:18:48 -0700283 EXPECT_TRUE(address3.SetAddressFromString(kTestIPAddress3));
284 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
285 address3,
286 0,
287 RT_SCOPE_LINK));
288 SendMessageToDeviceInfo(*message);
Paul Stewart7355ce12011-09-02 10:47:01 -0700289 IPAddress address4(IPAddress::kFamilyIPv6);
Paul Stewart9a908082011-08-31 12:18:48 -0700290 EXPECT_TRUE(address4.SetAddressFromString(kTestIPAddress4));
291 message.reset(BuildAddressMessage(RTNLMessage::kModeAdd,
292 address4,
293 IFA_F_PERMANENT,
294 RT_SCOPE_UNIVERSE));
295 SendMessageToDeviceInfo(*message);
296
297 // DeviceInfo now has 4 addresses associated with it, but only two of
298 // them are valid for flush.
299 EXPECT_CALL(rtnl_handler_, RemoveInterfaceAddress(kTestDeviceIndex,
300 IsIPAddress(address1)));
301 EXPECT_CALL(rtnl_handler_, RemoveInterfaceAddress(kTestDeviceIndex,
302 IsIPAddress(address2)));
303 device_info_.FlushAddresses(kTestDeviceIndex);
304 device_info_.Stop();
305}
306
Chris Masone9be4a9d2011-05-16 15:44:09 -0700307} // namespace shill