blob: c1d22e79c06dda675bad7de6bd4328eb72138d7c [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>
Eric Shienbroodb5c89402012-03-13 08:29:25 -07009#include <base/stl_util-inl.h>
Paul Stewart75e89d22011-08-01 10:00:02 -070010#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*/,
Eric Shienbroodb5c89402012-03-13 08:29:25 -070031 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[];
Thieu Lecaef8932012-02-28 16:06:59 -080057 static const char kTestDeviceNetAddress4[];
58 static const char kTestForeignNetAddress4[];
59 static const char kTestForeignNetGateway4[];
60 static const char kTestForeignNetAddress6[];
61 static const char kTestForeignNetGateway6[];
Paul Stewart75e89d22011-08-01 10:00:02 -070062 static const char kTestNetAddress0[];
63 static const char kTestNetAddress1[];
64
65 void StartRTNLHandler();
66 void StopRTNLHandler();
67
68 MockSockets sockets_;
69 RoutingTable *routing_table_;
70 TestEventDispatcher dispatcher_;
71};
72
73const int RoutingTableTest::kTestSocket = 123;
74const uint32 RoutingTableTest::kTestDeviceIndex0 = 12345;
75const uint32 RoutingTableTest::kTestDeviceIndex1 = 67890;
76const char RoutingTableTest::kTestDeviceName0[] = "test-device0";
Thieu Lecaef8932012-02-28 16:06:59 -080077const char RoutingTableTest::kTestDeviceNetAddress4[] = "192.168.2.0/24";
78const char RoutingTableTest::kTestForeignNetAddress4[] = "192.168.2.2";
79const char RoutingTableTest::kTestForeignNetGateway4[] = "192.168.2.1";
80const char RoutingTableTest::kTestForeignNetAddress6[] = "2000::/3";
81const char RoutingTableTest::kTestForeignNetGateway6[] = "fe80:::::1";
Paul Stewart75e89d22011-08-01 10:00:02 -070082const char RoutingTableTest::kTestNetAddress0[] = "192.168.1.1";
83const char RoutingTableTest::kTestNetAddress1[] = "192.168.1.2";
84
85
86MATCHER_P4(IsRoutingPacket, mode, index, entry, flags, "") {
87 // NB: Matchers don't get passed multiple arguments, so we can
88 // get the address of a Send(), its length, but not both.
89 // We have to punt and assume the length is correct -- which
90 // should already be tested in rtnl_message_unittest.
91 struct nlmsghdr hdr;
92 memcpy(&hdr, arg, sizeof(hdr));
93
94 RTNLMessage msg;
95 if (!msg.Decode(ByteString(reinterpret_cast<const unsigned char *>(arg),
96 hdr.nlmsg_len))) {
97 return false;
98 }
99
100 const RTNLMessage::RouteStatus &status = msg.route_status();
101
102 uint32 oif;
103 uint32 priority;
104
105 return
Paul Stewart9a908082011-08-31 12:18:48 -0700106 msg.type() == RTNLMessage::kTypeRoute &&
Paul Stewart75e89d22011-08-01 10:00:02 -0700107 msg.family() == entry.gateway.family() &&
Paul Stewarte6132022011-08-16 09:11:02 -0700108 msg.flags() == (NLM_F_REQUEST | flags) &&
Paul Stewart75e89d22011-08-01 10:00:02 -0700109 status.table == RT_TABLE_MAIN &&
110 status.protocol == RTPROT_BOOT &&
111 status.scope == entry.scope &&
112 status.type == RTN_UNICAST &&
113 msg.HasAttribute(RTA_DST) &&
114 IPAddress(msg.family(),
115 msg.GetAttribute(RTA_DST)).Equals(entry.dst) &&
116 !msg.HasAttribute(RTA_SRC) &&
117 msg.HasAttribute(RTA_GATEWAY) &&
118 IPAddress(msg.family(),
119 msg.GetAttribute(RTA_GATEWAY)).Equals(entry.gateway) &&
120 msg.GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
121 oif == index &&
122 msg.GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&priority) &&
123 priority == entry.metric;
124}
125
Paul Stewart9a908082011-08-31 12:18:48 -0700126void RoutingTableTest::SendRouteMsg(RTNLMessage::Mode mode,
Paul Stewart75e89d22011-08-01 10:00:02 -0700127 uint32 interface_index,
128 const RoutingTableEntry &entry) {
129 RTNLMessage msg(
Paul Stewart9a908082011-08-31 12:18:48 -0700130 RTNLMessage::kTypeRoute,
Paul Stewart75e89d22011-08-01 10:00:02 -0700131 mode,
132 0,
133 0,
134 0,
135 0,
136 entry.dst.family());
137
138 msg.set_route_status(RTNLMessage::RouteStatus(
Paul Stewart9e3fcd72011-08-26 15:46:16 -0700139 entry.dst.prefix(),
140 entry.src.prefix(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700141 RT_TABLE_MAIN,
142 RTPROT_BOOT,
143 entry.scope,
144 RTN_UNICAST,
145 0));
146
147 msg.SetAttribute(RTA_DST, entry.dst.address());
148 if (!entry.src.IsDefault()) {
149 msg.SetAttribute(RTA_SRC, entry.src.address());
150 }
151 if (!entry.gateway.IsDefault()) {
152 msg.SetAttribute(RTA_GATEWAY, entry.gateway.address());
153 }
154 msg.SetAttribute(RTA_PRIORITY, ByteString::CreateFromCPUUInt32(entry.metric));
155 msg.SetAttribute(RTA_OIF, ByteString::CreateFromCPUUInt32(interface_index));
156
157 ByteString msgdata = msg.Encode();
158 EXPECT_NE(0, msgdata.GetLength());
159
160 InputData data(msgdata.GetData(), msgdata.GetLength());
161 RTNLHandler::GetInstance()->ParseRTNL(&data);
162}
163
164void RoutingTableTest::StartRTNLHandler() {
165 EXPECT_CALL(sockets_, Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE))
166 .WillOnce(Return(kTestSocket));
167 EXPECT_CALL(sockets_, Bind(kTestSocket, _, sizeof(sockaddr_nl)))
168 .WillOnce(Return(0));
169 RTNLHandler::GetInstance()->Start(&dispatcher_, &sockets_);
170}
171
172void RoutingTableTest::StopRTNLHandler() {
173 EXPECT_CALL(sockets_, Close(_)).WillOnce(Return(0));
174 RTNLHandler::GetInstance()->Stop();
175}
176
177TEST_F(RoutingTableTest, RouteAddDelete) {
Paul Stewart9a908082011-08-31 12:18:48 -0700178 EXPECT_CALL(sockets_, Send(kTestSocket, _, _, 0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700179 StartRTNLHandler();
180 routing_table_->Start();
181
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800182 // Expect the tables to be empty by default.
Paul Stewart75e89d22011-08-01 10:00:02 -0700183 EXPECT_EQ(0, GetRoutingTables()->size());
184
Paul Stewart7355ce12011-09-02 10:47:01 -0700185 IPAddress default_address(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700186 default_address.SetAddressToDefault();
187
Paul Stewart7355ce12011-09-02 10:47:01 -0700188 IPAddress gateway_address0(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700189 gateway_address0.SetAddressFromString(kTestNetAddress0);
190
191 int metric = 10;
192
193 RoutingTableEntry entry0(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700194 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700195 gateway_address0,
196 metric,
197 RT_SCOPE_UNIVERSE,
198 true);
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800199 // Add a single entry.
Paul Stewart9a908082011-08-31 12:18:48 -0700200 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700201 kTestDeviceIndex0,
202 entry0);
203
204 base::hash_map<int, std::vector<RoutingTableEntry> > *tables =
205 GetRoutingTables();
206
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800207 // We should have a single table, which should in turn have a single entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700208 EXPECT_EQ(1, tables->size());
209 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex0));
210 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
211
212 RoutingTableEntry test_entry = (*tables)[kTestDeviceIndex0][0];
213 EXPECT_TRUE(entry0.Equals(test_entry));
214
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800215 // Add a second entry for a different interface.
Paul Stewart9a908082011-08-31 12:18:48 -0700216 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700217 kTestDeviceIndex1,
218 entry0);
219
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800220 // We should have two tables, which should have a single entry each.
Paul Stewart75e89d22011-08-01 10:00:02 -0700221 EXPECT_EQ(2, tables->size());
222 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex1));
223 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
224 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
225
226 test_entry = (*tables)[kTestDeviceIndex1][0];
227 EXPECT_TRUE(entry0.Equals(test_entry));
228
Paul Stewart7355ce12011-09-02 10:47:01 -0700229 IPAddress gateway_address1(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700230 gateway_address1.SetAddressFromString(kTestNetAddress1);
231
232 RoutingTableEntry entry1(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700233 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700234 gateway_address1,
235 metric,
236 RT_SCOPE_UNIVERSE,
237 true);
238
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800239 // Add a second gateway route to the second interface.
Paul Stewart9a908082011-08-31 12:18:48 -0700240 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700241 kTestDeviceIndex1,
242 entry1);
243
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800244 // We should have two tables, one of which has a single entry, the other has
245 // two.
Paul Stewart75e89d22011-08-01 10:00:02 -0700246 EXPECT_EQ(2, tables->size());
247 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
248 EXPECT_EQ(2, (*tables)[kTestDeviceIndex1].size());
249
250 test_entry = (*tables)[kTestDeviceIndex1][1];
251 EXPECT_TRUE(entry1.Equals(test_entry));
252
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800253 // Remove the first gateway route from the second interface.
Paul Stewart9a908082011-08-31 12:18:48 -0700254 SendRouteMsg(RTNLMessage::kModeDelete,
Paul Stewart75e89d22011-08-01 10:00:02 -0700255 kTestDeviceIndex1,
256 entry0);
257
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800258 // We should be back to having one route per table.
Paul Stewart75e89d22011-08-01 10:00:02 -0700259 EXPECT_EQ(2, tables->size());
260 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
261 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
262
263 test_entry = (*tables)[kTestDeviceIndex1][0];
264 EXPECT_TRUE(entry1.Equals(test_entry));
265
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800266 // Send a duplicate of the second gatway route message, changing the metric.
Paul Stewart75e89d22011-08-01 10:00:02 -0700267 RoutingTableEntry entry2(entry1);
268 entry2.metric++;
Paul Stewart9a908082011-08-31 12:18:48 -0700269 SendRouteMsg(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700270 kTestDeviceIndex1,
271 entry2);
272
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800273 // Routing table size shouldn't change, but the new metric should match.
Paul Stewart75e89d22011-08-01 10:00:02 -0700274 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
275 test_entry = (*tables)[kTestDeviceIndex1][0];
276 EXPECT_TRUE(entry2.Equals(test_entry));
277
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800278 // Find a matching entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700279 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700280 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700281 &test_entry));
282 EXPECT_TRUE(entry2.Equals(test_entry));
283
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800284 // Test that a search for a non-matching family fails.
Paul Stewart75e89d22011-08-01 10:00:02 -0700285 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700286 IPAddress::kFamilyIPv6,
Paul Stewart75e89d22011-08-01 10:00:02 -0700287 &test_entry));
288
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800289 // Remove last entry from an existing interface and test that we now fail.
Paul Stewart9a908082011-08-31 12:18:48 -0700290 SendRouteMsg(RTNLMessage::kModeDelete,
Paul Stewart75e89d22011-08-01 10:00:02 -0700291 kTestDeviceIndex1,
292 entry2);
293
294 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700295 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700296 &test_entry));
297
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800298 // Add a route from an IPConfig entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700299 MockControl control;
300 IPConfigRefPtr ipconfig(new IPConfig(&control, kTestDeviceName0));
301 IPConfig::Properties properties;
Paul Stewart7355ce12011-09-02 10:47:01 -0700302 properties.address_family = IPAddress::kFamilyIPv4;
Paul Stewart75e89d22011-08-01 10:00:02 -0700303 properties.gateway = kTestNetAddress0;
304 properties.address = kTestNetAddress1;
305 ipconfig->UpdateProperties(properties, true);
306
307 EXPECT_CALL(sockets_,
308 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700309 IsRoutingPacket(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700310 kTestDeviceIndex1,
311 entry0,
312 NLM_F_CREATE | NLM_F_EXCL),
313 _,
314 0));
315 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
316 ipconfig,
317 metric));
318
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800319 // The table entry should look much like entry0, except with
320 // from_rtnl = false.
Paul Stewart75e89d22011-08-01 10:00:02 -0700321 RoutingTableEntry entry3(entry0);
322 entry3.from_rtnl = false;
323 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700324 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700325 &test_entry));
326 EXPECT_TRUE(entry3.Equals(test_entry));
327
328 // Setting the same route on the interface with a different metric should
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800329 // push the route with different flags to indicate we are replacing it,
330 // then it should delete the old entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700331 RoutingTableEntry entry4(entry3);
332 entry4.metric += 10;
333 EXPECT_CALL(sockets_,
334 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700335 IsRoutingPacket(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700336 kTestDeviceIndex1,
337 entry4,
338 NLM_F_CREATE | NLM_F_REPLACE),
339 _,
340 0));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800341 EXPECT_CALL(sockets_,
342 Send(kTestSocket,
343 IsRoutingPacket(RTNLMessage::kModeDelete,
344 kTestDeviceIndex1,
345 entry3,
346 0),
347 _,
348 0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700349 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
350 ipconfig,
351 entry4.metric));
352
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800353 // Test that removing the table causes the route to disappear.
Paul Stewart75e89d22011-08-01 10:00:02 -0700354 routing_table_->ResetTable(kTestDeviceIndex1);
355 EXPECT_FALSE(ContainsKey(*tables, kTestDeviceIndex1));
356 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700357 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700358 &test_entry));
359 EXPECT_EQ(1, GetRoutingTables()->size());
360
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800361 // When we set the metric on an existing route, a new add and delete
362 // operation should occur.
Paul Stewart75e89d22011-08-01 10:00:02 -0700363 RoutingTableEntry entry5(entry4);
364 entry5.metric += 10;
365 EXPECT_CALL(sockets_,
366 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700367 IsRoutingPacket(RTNLMessage::kModeAdd,
Paul Stewart75e89d22011-08-01 10:00:02 -0700368 kTestDeviceIndex0,
369 entry5,
370 NLM_F_CREATE | NLM_F_REPLACE),
371 _,
372 0));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800373 EXPECT_CALL(sockets_,
374 Send(kTestSocket,
375 IsRoutingPacket(RTNLMessage::kModeDelete,
376 kTestDeviceIndex0,
377 entry0,
378 0),
379 _,
380 0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700381 routing_table_->SetDefaultMetric(kTestDeviceIndex0, entry5.metric);
mukesh agrawald4ef6772012-02-21 16:28:04 -0800382 // Furthermore, the routing table should reflect the change in the metric
383 // for the default route for the interface.
384 RoutingTableEntry default_route;
385 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex0,
386 IPAddress::kFamilyIPv4,
387 &default_route));
388 EXPECT_EQ(entry5.metric, default_route.metric);
Paul Stewart75e89d22011-08-01 10:00:02 -0700389
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800390 // Ask to flush table0. We should see a delete message sent.
Paul Stewart75e89d22011-08-01 10:00:02 -0700391 EXPECT_CALL(sockets_,
392 Send(kTestSocket,
Paul Stewart9a908082011-08-31 12:18:48 -0700393 IsRoutingPacket(RTNLMessage::kModeDelete,
Paul Stewart75e89d22011-08-01 10:00:02 -0700394 kTestDeviceIndex0,
mukesh agrawald4ef6772012-02-21 16:28:04 -0800395 entry5,
Paul Stewart75e89d22011-08-01 10:00:02 -0700396 0),
397 _,
398 0));
Thieu Lefb46caf2012-03-08 11:57:15 -0800399 routing_table_->FlushRoutes(kTestDeviceIndex0);
400 EXPECT_EQ(0, (*tables)[kTestDeviceIndex0].size());
Paul Stewart75e89d22011-08-01 10:00:02 -0700401
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800402 // Test that the routing table size returns to zero.
Thieu Lefb46caf2012-03-08 11:57:15 -0800403 SendRouteMsg(RTNLMessage::kModeAdd,
404 kTestDeviceIndex0,
405 entry5);
Paul Stewart75e89d22011-08-01 10:00:02 -0700406 EXPECT_EQ(1, GetRoutingTables()->size());
407 routing_table_->ResetTable(kTestDeviceIndex0);
408 EXPECT_EQ(0, GetRoutingTables()->size());
409
410 routing_table_->Stop();
411 StopRTNLHandler();
412}
413
Paul Stewart75e89d22011-08-01 10:00:02 -0700414} // namespace shill