blob: e5b29606a6bfb98f3e5667b09556d0de45763edf [file] [log] [blame]
mukesh agrawald4ef6772012-02-21 16:28:04 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewart75e89d22011-08-01 10:00:02 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <sys/socket.h>
6#include <linux/rtnetlink.h>
7
8#include <base/logging.h>
9#include <base/stl_util-inl.h>
10#include <gtest/gtest.h>
11#include <gmock/gmock.h>
12
13#include "shill/byte_string.h"
14#include "shill/mock_control.h"
15#include "shill/mock_sockets.h"
16#include "shill/routing_table.h"
17#include "shill/routing_table_entry.h"
18#include "shill/rtnl_handler.h"
19#include "shill/rtnl_message.h"
20
21using testing::_;
22using testing::Return;
23using testing::Test;
24
25namespace shill {
26
27class TestEventDispatcher : public EventDispatcher {
28 public:
Paul Stewart26b327e2011-10-19 11:38:09 -070029 virtual IOHandler *CreateInputHandler(
mukesh agrawal1830fa12011-09-26 14:31:40 -070030 int /*fd*/,
31 Callback1<InputData*>::Type */*callback*/) {
Paul Stewart75e89d22011-08-01 10:00:02 -070032 return NULL;
33 }
34};
35
36class RoutingTableTest : public Test {
37 public:
38 RoutingTableTest() : routing_table_(RoutingTable::GetInstance()) {}
39
40 base::hash_map<int, std::vector<RoutingTableEntry> > *GetRoutingTables() {
41 return &routing_table_->tables_;
42 }
43
Paul Stewart9a908082011-08-31 12:18:48 -070044 void SendRouteMsg(RTNLMessage::Mode mode,
Paul Stewart75e89d22011-08-01 10:00:02 -070045 uint32 interface_index,
46 const RoutingTableEntry &entry);
47
Paul Stewart65c40f52011-08-08 07:27:46 -070048 virtual void TearDown() {
49 RTNLHandler::GetInstance()->Stop();
50 }
51
Paul Stewart75e89d22011-08-01 10:00:02 -070052 protected:
53 static const int kTestSocket;
54 static const uint32 kTestDeviceIndex0;
55 static const uint32 kTestDeviceIndex1;
56 static const char kTestDeviceName0[];
57 static const char kTestNetAddress0[];
58 static const char kTestNetAddress1[];
59
60 void StartRTNLHandler();
61 void StopRTNLHandler();
62
63 MockSockets sockets_;
64 RoutingTable *routing_table_;
65 TestEventDispatcher dispatcher_;
66};
67
68const int RoutingTableTest::kTestSocket = 123;
69const uint32 RoutingTableTest::kTestDeviceIndex0 = 12345;
70const uint32 RoutingTableTest::kTestDeviceIndex1 = 67890;
71const char RoutingTableTest::kTestDeviceName0[] = "test-device0";
72const char RoutingTableTest::kTestNetAddress0[] = "192.168.1.1";
73const char RoutingTableTest::kTestNetAddress1[] = "192.168.1.2";
74
75
76MATCHER_P4(IsRoutingPacket, mode, index, entry, flags, "") {
77 // NB: Matchers don't get passed multiple arguments, so we can
78 // get the address of a Send(), its length, but not both.
79 // We have to punt and assume the length is correct -- which
80 // should already be tested in rtnl_message_unittest.
81 struct nlmsghdr hdr;
82 memcpy(&hdr, arg, sizeof(hdr));
83
84 RTNLMessage msg;
85 if (!msg.Decode(ByteString(reinterpret_cast<const unsigned char *>(arg),
86 hdr.nlmsg_len))) {
87 return false;
88 }
89
90 const RTNLMessage::RouteStatus &status = msg.route_status();
91
92 uint32 oif;
93 uint32 priority;
94
95 return
Paul Stewart9a908082011-08-31 12:18:48 -070096 msg.type() == RTNLMessage::kTypeRoute &&
Paul Stewart75e89d22011-08-01 10:00:02 -070097 msg.family() == entry.gateway.family() &&
Paul Stewarte6132022011-08-16 09:11:02 -070098 msg.flags() == (NLM_F_REQUEST | flags) &&
Paul Stewart75e89d22011-08-01 10:00:02 -070099 status.table == RT_TABLE_MAIN &&
100 status.protocol == RTPROT_BOOT &&
101 status.scope == entry.scope &&
102 status.type == RTN_UNICAST &&
103 msg.HasAttribute(RTA_DST) &&
104 IPAddress(msg.family(),
105 msg.GetAttribute(RTA_DST)).Equals(entry.dst) &&
106 !msg.HasAttribute(RTA_SRC) &&
107 msg.HasAttribute(RTA_GATEWAY) &&
108 IPAddress(msg.family(),
109 msg.GetAttribute(RTA_GATEWAY)).Equals(entry.gateway) &&
110 msg.GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
111 oif == index &&
112 msg.GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&priority) &&
113 priority == entry.metric;
114}
115
Paul Stewart9a908082011-08-31 12:18:48 -0700116void RoutingTableTest::SendRouteMsg(RTNLMessage::Mode mode,
Paul Stewart75e89d22011-08-01 10:00:02 -0700117 uint32 interface_index,
118 const RoutingTableEntry &entry) {
119 RTNLMessage msg(
Paul Stewart9a908082011-08-31 12:18:48 -0700120 RTNLMessage::kTypeRoute,
Paul Stewart75e89d22011-08-01 10:00:02 -0700121 mode,
122 0,
123 0,
124 0,
125 0,
126 entry.dst.family());
127
128 msg.set_route_status(RTNLMessage::RouteStatus(
Paul Stewart9e3fcd72011-08-26 15:46:16 -0700129 entry.dst.prefix(),
130 entry.src.prefix(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700131 RT_TABLE_MAIN,
132 RTPROT_BOOT,
133 entry.scope,
134 RTN_UNICAST,
135 0));
136
137 msg.SetAttribute(RTA_DST, entry.dst.address());
138 if (!entry.src.IsDefault()) {
139 msg.SetAttribute(RTA_SRC, entry.src.address());
140 }
141 if (!entry.gateway.IsDefault()) {
142 msg.SetAttribute(RTA_GATEWAY, entry.gateway.address());
143 }
144 msg.SetAttribute(RTA_PRIORITY, ByteString::CreateFromCPUUInt32(entry.metric));
145 msg.SetAttribute(RTA_OIF, ByteString::CreateFromCPUUInt32(interface_index));
146
147 ByteString msgdata = msg.Encode();
148 EXPECT_NE(0, msgdata.GetLength());
149
150 InputData data(msgdata.GetData(), msgdata.GetLength());
151 RTNLHandler::GetInstance()->ParseRTNL(&data);
152}
153
154void RoutingTableTest::StartRTNLHandler() {
155 EXPECT_CALL(sockets_, Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE))
156 .WillOnce(Return(kTestSocket));
157 EXPECT_CALL(sockets_, Bind(kTestSocket, _, sizeof(sockaddr_nl)))
158 .WillOnce(Return(0));
159 RTNLHandler::GetInstance()->Start(&dispatcher_, &sockets_);
160}
161
162void RoutingTableTest::StopRTNLHandler() {
163 EXPECT_CALL(sockets_, Close(_)).WillOnce(Return(0));
164 RTNLHandler::GetInstance()->Stop();
165}
166
167TEST_F(RoutingTableTest, RouteAddDelete) {
Paul Stewart9a908082011-08-31 12:18:48 -0700168 EXPECT_CALL(sockets_, Send(kTestSocket, _, _, 0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700169 StartRTNLHandler();
170 routing_table_->Start();
171
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800172 // Expect the tables to be empty by default.
Paul Stewart75e89d22011-08-01 10:00:02 -0700173 EXPECT_EQ(0, GetRoutingTables()->size());
174
Paul Stewart7355ce12011-09-02 10:47:01 -0700175 IPAddress default_address(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700176 default_address.SetAddressToDefault();
177
Paul Stewart7355ce12011-09-02 10:47:01 -0700178 IPAddress gateway_address0(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700179 gateway_address0.SetAddressFromString(kTestNetAddress0);
180
181 int metric = 10;
182
183 RoutingTableEntry entry0(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700184 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700185 gateway_address0,
186 metric,
187 RT_SCOPE_UNIVERSE,
188 true);
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800189 // Add a single entry.
Paul Stewart9a908082011-08-31 12:18:48 -0700190 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700191 kTestDeviceIndex0,
192 entry0);
193
194 base::hash_map<int, std::vector<RoutingTableEntry> > *tables =
195 GetRoutingTables();
196
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800197 // We should have a single table, which should in turn have a single entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700198 EXPECT_EQ(1, tables->size());
199 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex0));
200 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
201
202 RoutingTableEntry test_entry = (*tables)[kTestDeviceIndex0][0];
203 EXPECT_TRUE(entry0.Equals(test_entry));
204
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800205 // Add a second entry for a different interface.
Paul Stewart9a908082011-08-31 12:18:48 -0700206 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700207 kTestDeviceIndex1,
208 entry0);
209
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800210 // We should have two tables, which should have a single entry each.
Paul Stewart75e89d22011-08-01 10:00:02 -0700211 EXPECT_EQ(2, tables->size());
212 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex1));
213 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
214 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
215
216 test_entry = (*tables)[kTestDeviceIndex1][0];
217 EXPECT_TRUE(entry0.Equals(test_entry));
218
Paul Stewart7355ce12011-09-02 10:47:01 -0700219 IPAddress gateway_address1(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700220 gateway_address1.SetAddressFromString(kTestNetAddress1);
221
222 RoutingTableEntry entry1(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700223 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700224 gateway_address1,
225 metric,
226 RT_SCOPE_UNIVERSE,
227 true);
228
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800229 // Add a second gateway route to the second interface.
Paul Stewart9a908082011-08-31 12:18:48 -0700230 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700231 kTestDeviceIndex1,
232 entry1);
233
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800234 // We should have two tables, one of which has a single entry, the other has
235 // two.
Paul Stewart75e89d22011-08-01 10:00:02 -0700236 EXPECT_EQ(2, tables->size());
237 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
238 EXPECT_EQ(2, (*tables)[kTestDeviceIndex1].size());
239
240 test_entry = (*tables)[kTestDeviceIndex1][1];
241 EXPECT_TRUE(entry1.Equals(test_entry));
242
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800243 // Remove the first gateway route from the second interface.
Paul Stewart9a908082011-08-31 12:18:48 -0700244 SendRouteMsg(RTNLMessage::kModeDelete,
Paul Stewart75e89d22011-08-01 10:00:02 -0700245 kTestDeviceIndex1,
246 entry0);
247
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800248 // We should be back to having one route per table.
Paul Stewart75e89d22011-08-01 10:00:02 -0700249 EXPECT_EQ(2, tables->size());
250 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
251 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
252
253 test_entry = (*tables)[kTestDeviceIndex1][0];
254 EXPECT_TRUE(entry1.Equals(test_entry));
255
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800256 // Send a duplicate of the second gatway route message, changing the metric.
Paul Stewart75e89d22011-08-01 10:00:02 -0700257 RoutingTableEntry entry2(entry1);
258 entry2.metric++;
Paul Stewart9a908082011-08-31 12:18:48 -0700259 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700260 kTestDeviceIndex1,
261 entry2);
262
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800263 // Routing table size shouldn't change, but the new metric should match.
Paul Stewart75e89d22011-08-01 10:00:02 -0700264 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
265 test_entry = (*tables)[kTestDeviceIndex1][0];
266 EXPECT_TRUE(entry2.Equals(test_entry));
267
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800268 // Find a matching entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700269 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700270 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700271 &test_entry));
272 EXPECT_TRUE(entry2.Equals(test_entry));
273
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800274 // Test that a search for a non-matching family fails.
Paul Stewart75e89d22011-08-01 10:00:02 -0700275 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700276 IPAddress::kFamilyIPv6,
Paul Stewart75e89d22011-08-01 10:00:02 -0700277 &test_entry));
278
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800279 // Remove last entry from an existing interface and test that we now fail.
Paul Stewart9a908082011-08-31 12:18:48 -0700280 SendRouteMsg(RTNLMessage::kModeDelete,
Paul Stewart75e89d22011-08-01 10:00:02 -0700281 kTestDeviceIndex1,
282 entry2);
283
284 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700285 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700286 &test_entry));
287
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800288 // Add a route from an IPConfig entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700289 MockControl control;
290 IPConfigRefPtr ipconfig(new IPConfig(&control, kTestDeviceName0));
291 IPConfig::Properties properties;
Paul Stewart7355ce12011-09-02 10:47:01 -0700292 properties.address_family = IPAddress::kFamilyIPv4;
Paul Stewart75e89d22011-08-01 10:00:02 -0700293 properties.gateway = kTestNetAddress0;
294 properties.address = kTestNetAddress1;
295 ipconfig->UpdateProperties(properties, true);
296
297 EXPECT_CALL(sockets_,
298 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700299 IsRoutingPacket(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700300 kTestDeviceIndex1,
301 entry0,
302 NLM_F_CREATE | NLM_F_EXCL),
303 _,
304 0));
305 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
306 ipconfig,
307 metric));
308
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800309 // The table entry should look much like entry0, except with
310 // from_rtnl = false.
Paul Stewart75e89d22011-08-01 10:00:02 -0700311 RoutingTableEntry entry3(entry0);
312 entry3.from_rtnl = false;
313 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700314 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700315 &test_entry));
316 EXPECT_TRUE(entry3.Equals(test_entry));
317
318 // Setting the same route on the interface with a different metric should
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800319 // push the route with different flags to indicate we are replacing it,
320 // then it should delete the old entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700321 RoutingTableEntry entry4(entry3);
322 entry4.metric += 10;
323 EXPECT_CALL(sockets_,
324 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700325 IsRoutingPacket(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700326 kTestDeviceIndex1,
327 entry4,
328 NLM_F_CREATE | NLM_F_REPLACE),
329 _,
330 0));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800331 EXPECT_CALL(sockets_,
332 Send(kTestSocket,
333 IsRoutingPacket(RTNLMessage::kModeDelete,
334 kTestDeviceIndex1,
335 entry3,
336 0),
337 _,
338 0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700339 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
340 ipconfig,
341 entry4.metric));
342
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800343 // Test that removing the table causes the route to disappear.
Paul Stewart75e89d22011-08-01 10:00:02 -0700344 routing_table_->ResetTable(kTestDeviceIndex1);
345 EXPECT_FALSE(ContainsKey(*tables, kTestDeviceIndex1));
346 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700347 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700348 &test_entry));
349 EXPECT_EQ(1, GetRoutingTables()->size());
350
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800351 // When we set the metric on an existing route, a new add and delete
352 // operation should occur.
Paul Stewart75e89d22011-08-01 10:00:02 -0700353 RoutingTableEntry entry5(entry4);
354 entry5.metric += 10;
355 EXPECT_CALL(sockets_,
356 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700357 IsRoutingPacket(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700358 kTestDeviceIndex0,
359 entry5,
360 NLM_F_CREATE | NLM_F_REPLACE),
361 _,
362 0));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800363 EXPECT_CALL(sockets_,
364 Send(kTestSocket,
365 IsRoutingPacket(RTNLMessage::kModeDelete,
366 kTestDeviceIndex0,
367 entry0,
368 0),
369 _,
370 0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700371 routing_table_->SetDefaultMetric(kTestDeviceIndex0, entry5.metric);
mukesh agrawald4ef6772012-02-21 16:28:04 -0800372 // Furthermore, the routing table should reflect the change in the metric
373 // for the default route for the interface.
374 RoutingTableEntry default_route;
375 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex0,
376 IPAddress::kFamilyIPv4,
377 &default_route));
378 EXPECT_EQ(entry5.metric, default_route.metric);
Paul Stewart75e89d22011-08-01 10:00:02 -0700379
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800380 // Ask to flush table0. We should see a delete message sent.
Paul Stewart75e89d22011-08-01 10:00:02 -0700381 EXPECT_CALL(sockets_,
382 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700383 IsRoutingPacket(RTNLMessage::kModeDelete,
Paul Stewart75e89d22011-08-01 10:00:02 -0700384 kTestDeviceIndex0,
mukesh agrawald4ef6772012-02-21 16:28:04 -0800385 entry5,
Paul Stewart75e89d22011-08-01 10:00:02 -0700386 0),
387 _,
388 0));
389 routing_table_->FlushRoutes(kTestDeviceIndex0);
390
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800391 // Test that the routing table size returns to zero.
Paul Stewart75e89d22011-08-01 10:00:02 -0700392 EXPECT_EQ(1, GetRoutingTables()->size());
393 routing_table_->ResetTable(kTestDeviceIndex0);
394 EXPECT_EQ(0, GetRoutingTables()->size());
395
396 routing_table_->Stop();
397 StopRTNLHandler();
398}
399
400} // namespace shill