blob: 04add74f753f9fbef232ab76bc41eae411eac4f7 [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
Paul Stewart3f68bb12012-03-15 13:33:10 -07008#include <vector>
9
Paul Stewart75e89d22011-08-01 10:00:02 -070010#include <base/logging.h>
Darin Petkov13e6d552012-05-09 14:22:23 +020011#include <base/memory/weak_ptr.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/stl_util.h>
Paul Stewart75e89d22011-08-01 10:00:02 -070013#include <gtest/gtest.h>
14#include <gmock/gmock.h>
15
16#include "shill/byte_string.h"
17#include "shill/mock_control.h"
Paul Stewartf748a362012-03-07 12:01:20 -080018#include "shill/mock_rtnl_handler.h"
Paul Stewart75e89d22011-08-01 10:00:02 -070019#include "shill/routing_table.h"
20#include "shill/routing_table_entry.h"
21#include "shill/rtnl_handler.h"
22#include "shill/rtnl_message.h"
23
Darin Petkovabf6d282012-05-08 15:49:05 +020024using base::Bind;
Eric Shienbrood3e20a232012-02-16 11:35:56 -050025using base::Callback;
Darin Petkovabf6d282012-05-08 15:49:05 +020026using base::Unretained;
Paul Stewarte93b0382012-04-24 13:11:28 -070027using base::hash_map;
Darin Petkovabf6d282012-05-08 15:49:05 +020028using std::deque;
Paul Stewart3f68bb12012-03-15 13:33:10 -070029using std::vector;
Paul Stewart75e89d22011-08-01 10:00:02 -070030using testing::_;
Darin Petkovabf6d282012-05-08 15:49:05 +020031using testing::Field;
Paul Stewartf748a362012-03-07 12:01:20 -080032using testing::Invoke;
Paul Stewart75e89d22011-08-01 10:00:02 -070033using testing::Return;
Paul Stewartf748a362012-03-07 12:01:20 -080034using testing::StrictMock;
Paul Stewart75e89d22011-08-01 10:00:02 -070035using testing::Test;
36
37namespace shill {
38
39class TestEventDispatcher : public EventDispatcher {
40 public:
Paul Stewart26b327e2011-10-19 11:38:09 -070041 virtual IOHandler *CreateInputHandler(
mukesh agrawal1830fa12011-09-26 14:31:40 -070042 int /*fd*/,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050043 const Callback<void(InputData*)> &/*callback*/) {
Paul Stewart75e89d22011-08-01 10:00:02 -070044 return NULL;
45 }
46};
47
48class RoutingTableTest : public Test {
49 public:
Paul Stewarte93b0382012-04-24 13:11:28 -070050 RoutingTableTest() : routing_table_(new RoutingTable()) {}
Paul Stewart75e89d22011-08-01 10:00:02 -070051
Paul Stewartf748a362012-03-07 12:01:20 -080052 virtual void SetUp() {
53 routing_table_->rtnl_handler_ = &rtnl_handler_;
54 ON_CALL(rtnl_handler_, SendMessage(_)).WillByDefault(Return(true));
Paul Stewart75e89d22011-08-01 10:00:02 -070055 }
56
Paul Stewart65c40f52011-08-08 07:27:46 -070057 virtual void TearDown() {
58 RTNLHandler::GetInstance()->Stop();
59 }
60
Paul Stewarte93b0382012-04-24 13:11:28 -070061 hash_map<int, vector<RoutingTableEntry> > *GetRoutingTables() {
Paul Stewartf748a362012-03-07 12:01:20 -080062 return &routing_table_->tables_;
63 }
64
Darin Petkovabf6d282012-05-08 15:49:05 +020065 deque<RoutingTable::Query> *GetQueries() {
Paul Stewarte93b0382012-04-24 13:11:28 -070066 return &routing_table_->route_queries_;
Paul Stewartf748a362012-03-07 12:01:20 -080067 }
68
69 void SendRouteEntry(RTNLMessage::Mode mode,
70 uint32 interface_index,
71 const RoutingTableEntry &entry);
72
73 void SendRouteEntryWithSeqAndProto(RTNLMessage::Mode mode,
74 uint32 interface_index,
75 const RoutingTableEntry &entry,
76 uint32 seq,
77 unsigned char proto);
78
79 void SendRouteMessage(const RTNLMessage &msg);
80
81 bool SetSequenceForMessage(RTNLMessage *message) {
82 message->set_seq(RoutingTableTest::kTestRequestSeq);
83 return true;
84 }
85
Paul Stewart75e89d22011-08-01 10:00:02 -070086 protected:
Paul Stewart75e89d22011-08-01 10:00:02 -070087 static const uint32 kTestDeviceIndex0;
88 static const uint32 kTestDeviceIndex1;
89 static const char kTestDeviceName0[];
Thieu Lecaef8932012-02-28 16:06:59 -080090 static const char kTestDeviceNetAddress4[];
91 static const char kTestForeignNetAddress4[];
92 static const char kTestForeignNetGateway4[];
93 static const char kTestForeignNetAddress6[];
94 static const char kTestForeignNetGateway6[];
Paul Stewartf748a362012-03-07 12:01:20 -080095 static const char kTestGatewayAddress4[];
Paul Stewart75e89d22011-08-01 10:00:02 -070096 static const char kTestNetAddress0[];
97 static const char kTestNetAddress1[];
Paul Stewartf748a362012-03-07 12:01:20 -080098 static const char kTestRemoteAddress4[];
Paul Stewart3f68bb12012-03-15 13:33:10 -070099 static const char kTestRemoteNetmask4[];
100 static const char kTestRemoteNetwork4[];
101 static const int kTestRemotePrefix4;
Paul Stewartf748a362012-03-07 12:01:20 -0800102 static const uint32 kTestRequestSeq;
Paul Stewarte93b0382012-04-24 13:11:28 -0700103 static const int kTestRouteTag;
Paul Stewart75e89d22011-08-01 10:00:02 -0700104
Darin Petkovabf6d282012-05-08 15:49:05 +0200105 class QueryCallbackTarget {
106 public:
107 QueryCallbackTarget()
Darin Petkov13e6d552012-05-09 14:22:23 +0200108 : weak_ptr_factory_(this),
109 mocked_callback_(
110 Bind(&QueryCallbackTarget::MockedTarget, Unretained(this))),
111 unreached_callback_(Bind(&QueryCallbackTarget::UnreachedTarget,
112 weak_ptr_factory_.GetWeakPtr())) {}
Darin Petkovabf6d282012-05-08 15:49:05 +0200113
Darin Petkov13e6d552012-05-09 14:22:23 +0200114 MOCK_METHOD2(MockedTarget,
Darin Petkovabf6d282012-05-08 15:49:05 +0200115 void(int interface_index, const RoutingTableEntry &entry));
Darin Petkov13e6d552012-05-09 14:22:23 +0200116
117 void UnreachedTarget(int interface_index, const RoutingTableEntry &entry) {
118 CHECK(false);
119 }
120
121 const RoutingTable::Query::Callback &mocked_callback() const {
122 return mocked_callback_;
123 }
124
125 const RoutingTable::Query::Callback &unreached_callback() const {
126 return unreached_callback_;
127 }
Darin Petkovabf6d282012-05-08 15:49:05 +0200128
129 private:
Darin Petkov13e6d552012-05-09 14:22:23 +0200130 base::WeakPtrFactory<QueryCallbackTarget> weak_ptr_factory_;
131 const RoutingTable::Query::Callback mocked_callback_;
132 const RoutingTable::Query::Callback unreached_callback_;
Darin Petkovabf6d282012-05-08 15:49:05 +0200133 };
134
Paul Stewart75e89d22011-08-01 10:00:02 -0700135 RoutingTable *routing_table_;
136 TestEventDispatcher dispatcher_;
Paul Stewartf748a362012-03-07 12:01:20 -0800137 StrictMock<MockRTNLHandler> rtnl_handler_;
Paul Stewart75e89d22011-08-01 10:00:02 -0700138};
139
Paul Stewart75e89d22011-08-01 10:00:02 -0700140const uint32 RoutingTableTest::kTestDeviceIndex0 = 12345;
141const uint32 RoutingTableTest::kTestDeviceIndex1 = 67890;
142const char RoutingTableTest::kTestDeviceName0[] = "test-device0";
Thieu Lecaef8932012-02-28 16:06:59 -0800143const char RoutingTableTest::kTestDeviceNetAddress4[] = "192.168.2.0/24";
144const char RoutingTableTest::kTestForeignNetAddress4[] = "192.168.2.2";
145const char RoutingTableTest::kTestForeignNetGateway4[] = "192.168.2.1";
146const char RoutingTableTest::kTestForeignNetAddress6[] = "2000::/3";
147const char RoutingTableTest::kTestForeignNetGateway6[] = "fe80:::::1";
Paul Stewartf748a362012-03-07 12:01:20 -0800148const char RoutingTableTest::kTestGatewayAddress4[] = "192.168.2.254";
Paul Stewart75e89d22011-08-01 10:00:02 -0700149const char RoutingTableTest::kTestNetAddress0[] = "192.168.1.1";
150const char RoutingTableTest::kTestNetAddress1[] = "192.168.1.2";
Paul Stewartf748a362012-03-07 12:01:20 -0800151const char RoutingTableTest::kTestRemoteAddress4[] = "192.168.2.254";
Paul Stewart3f68bb12012-03-15 13:33:10 -0700152const char RoutingTableTest::kTestRemoteNetmask4[] = "255.255.255.0";
153const char RoutingTableTest::kTestRemoteNetwork4[] = "192.168.100.0";
154const int RoutingTableTest::kTestRemotePrefix4 = 24;
Paul Stewartf748a362012-03-07 12:01:20 -0800155const uint32 RoutingTableTest::kTestRequestSeq = 456;
Paul Stewarte93b0382012-04-24 13:11:28 -0700156const int RoutingTableTest::kTestRouteTag = 789;
Paul Stewart75e89d22011-08-01 10:00:02 -0700157
Darin Petkovabf6d282012-05-08 15:49:05 +0200158namespace {
159
Paul Stewart75e89d22011-08-01 10:00:02 -0700160MATCHER_P4(IsRoutingPacket, mode, index, entry, flags, "") {
Paul Stewartf748a362012-03-07 12:01:20 -0800161 const RTNLMessage::RouteStatus &status = arg->route_status();
Paul Stewart75e89d22011-08-01 10:00:02 -0700162
163 uint32 oif;
164 uint32 priority;
165
166 return
Paul Stewartf748a362012-03-07 12:01:20 -0800167 arg->type() == RTNLMessage::kTypeRoute &&
168 arg->family() == entry.gateway.family() &&
169 arg->flags() == (NLM_F_REQUEST | flags) &&
170 status.table == RT_TABLE_MAIN &&
171 status.protocol == RTPROT_BOOT &&
172 status.scope == entry.scope &&
173 status.type == RTN_UNICAST &&
174 arg->HasAttribute(RTA_DST) &&
175 IPAddress(arg->family(),
176 arg->GetAttribute(RTA_DST),
177 status.dst_prefix).Equals(entry.dst) &&
178 !arg->HasAttribute(RTA_SRC) &&
179 arg->HasAttribute(RTA_GATEWAY) &&
180 IPAddress(arg->family(),
181 arg->GetAttribute(RTA_GATEWAY)).Equals(entry.gateway) &&
182 arg->GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
183 oif == index &&
184 arg->GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&priority) &&
185 priority == entry.metric;
Paul Stewart75e89d22011-08-01 10:00:02 -0700186}
187
Darin Petkovabf6d282012-05-08 15:49:05 +0200188} // namespace
189
Paul Stewartf748a362012-03-07 12:01:20 -0800190void RoutingTableTest::SendRouteEntry(RTNLMessage::Mode mode,
191 uint32 interface_index,
192 const RoutingTableEntry &entry) {
193 SendRouteEntryWithSeqAndProto(mode, interface_index, entry, 0, RTPROT_BOOT);
194}
195
196void RoutingTableTest::SendRouteEntryWithSeqAndProto(
197 RTNLMessage::Mode mode,
198 uint32 interface_index,
199 const RoutingTableEntry &entry,
200 uint32 seq,
201 unsigned char proto) {
Paul Stewart75e89d22011-08-01 10:00:02 -0700202 RTNLMessage msg(
Paul Stewart9a908082011-08-31 12:18:48 -0700203 RTNLMessage::kTypeRoute,
Paul Stewart75e89d22011-08-01 10:00:02 -0700204 mode,
205 0,
Paul Stewartf748a362012-03-07 12:01:20 -0800206 seq,
Paul Stewart75e89d22011-08-01 10:00:02 -0700207 0,
208 0,
209 entry.dst.family());
210
211 msg.set_route_status(RTNLMessage::RouteStatus(
Paul Stewart9e3fcd72011-08-26 15:46:16 -0700212 entry.dst.prefix(),
213 entry.src.prefix(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700214 RT_TABLE_MAIN,
Paul Stewartf748a362012-03-07 12:01:20 -0800215 proto,
Paul Stewart75e89d22011-08-01 10:00:02 -0700216 entry.scope,
217 RTN_UNICAST,
218 0));
219
220 msg.SetAttribute(RTA_DST, entry.dst.address());
221 if (!entry.src.IsDefault()) {
222 msg.SetAttribute(RTA_SRC, entry.src.address());
223 }
224 if (!entry.gateway.IsDefault()) {
225 msg.SetAttribute(RTA_GATEWAY, entry.gateway.address());
226 }
227 msg.SetAttribute(RTA_PRIORITY, ByteString::CreateFromCPUUInt32(entry.metric));
228 msg.SetAttribute(RTA_OIF, ByteString::CreateFromCPUUInt32(interface_index));
229
Paul Stewartf748a362012-03-07 12:01:20 -0800230 routing_table_->RouteMsgHandler(msg);
Paul Stewart75e89d22011-08-01 10:00:02 -0700231}
232
Paul Stewartf748a362012-03-07 12:01:20 -0800233void RoutingTableTest::SendRouteMessage(const RTNLMessage &msg) {
234 routing_table_->RouteMsgHandler(msg);
Paul Stewart75e89d22011-08-01 10:00:02 -0700235}
236
Paul Stewartf748a362012-03-07 12:01:20 -0800237TEST_F(RoutingTableTest, Start) {
238 EXPECT_CALL(rtnl_handler_, RequestDump(RTNLHandler::kRequestRoute));
239 routing_table_->Start();
Paul Stewart75e89d22011-08-01 10:00:02 -0700240}
241
242TEST_F(RoutingTableTest, RouteAddDelete) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800243 // Expect the tables to be empty by default.
Paul Stewart75e89d22011-08-01 10:00:02 -0700244 EXPECT_EQ(0, GetRoutingTables()->size());
245
Paul Stewart7355ce12011-09-02 10:47:01 -0700246 IPAddress default_address(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700247 default_address.SetAddressToDefault();
248
Paul Stewart7355ce12011-09-02 10:47:01 -0700249 IPAddress gateway_address0(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700250 gateway_address0.SetAddressFromString(kTestNetAddress0);
251
252 int metric = 10;
253
254 RoutingTableEntry entry0(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700255 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700256 gateway_address0,
257 metric,
258 RT_SCOPE_UNIVERSE,
259 true);
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800260 // Add a single entry.
Paul Stewartf748a362012-03-07 12:01:20 -0800261 SendRouteEntry(RTNLMessage::kModeAdd,
262 kTestDeviceIndex0,
263 entry0);
Paul Stewart75e89d22011-08-01 10:00:02 -0700264
Paul Stewarte93b0382012-04-24 13:11:28 -0700265 hash_map<int, vector<RoutingTableEntry> > *tables =
Paul Stewart75e89d22011-08-01 10:00:02 -0700266 GetRoutingTables();
267
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800268 // We should have a single table, which should in turn have a single entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700269 EXPECT_EQ(1, tables->size());
270 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex0));
271 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
272
273 RoutingTableEntry test_entry = (*tables)[kTestDeviceIndex0][0];
274 EXPECT_TRUE(entry0.Equals(test_entry));
275
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800276 // Add a second entry for a different interface.
Paul Stewartf748a362012-03-07 12:01:20 -0800277 SendRouteEntry(RTNLMessage::kModeAdd,
278 kTestDeviceIndex1,
279 entry0);
Paul Stewart75e89d22011-08-01 10:00:02 -0700280
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800281 // We should have two tables, which should have a single entry each.
Paul Stewart75e89d22011-08-01 10:00:02 -0700282 EXPECT_EQ(2, tables->size());
283 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex1));
284 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
285 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
286
287 test_entry = (*tables)[kTestDeviceIndex1][0];
288 EXPECT_TRUE(entry0.Equals(test_entry));
289
Paul Stewart7355ce12011-09-02 10:47:01 -0700290 IPAddress gateway_address1(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700291 gateway_address1.SetAddressFromString(kTestNetAddress1);
292
293 RoutingTableEntry entry1(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700294 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700295 gateway_address1,
296 metric,
297 RT_SCOPE_UNIVERSE,
298 true);
299
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800300 // Add a second gateway route to the second interface.
Paul Stewartf748a362012-03-07 12:01:20 -0800301 SendRouteEntry(RTNLMessage::kModeAdd,
302 kTestDeviceIndex1,
303 entry1);
Paul Stewart75e89d22011-08-01 10:00:02 -0700304
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800305 // We should have two tables, one of which has a single entry, the other has
306 // two.
Paul Stewart75e89d22011-08-01 10:00:02 -0700307 EXPECT_EQ(2, tables->size());
308 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
309 EXPECT_EQ(2, (*tables)[kTestDeviceIndex1].size());
310
311 test_entry = (*tables)[kTestDeviceIndex1][1];
312 EXPECT_TRUE(entry1.Equals(test_entry));
313
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800314 // Remove the first gateway route from the second interface.
Paul Stewartf748a362012-03-07 12:01:20 -0800315 SendRouteEntry(RTNLMessage::kModeDelete,
316 kTestDeviceIndex1,
317 entry0);
Paul Stewart75e89d22011-08-01 10:00:02 -0700318
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800319 // We should be back to having one route per table.
Paul Stewart75e89d22011-08-01 10:00:02 -0700320 EXPECT_EQ(2, tables->size());
321 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
322 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
323
324 test_entry = (*tables)[kTestDeviceIndex1][0];
325 EXPECT_TRUE(entry1.Equals(test_entry));
326
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700327 // Send a duplicate of the second gateway route message, changing the metric.
Paul Stewart75e89d22011-08-01 10:00:02 -0700328 RoutingTableEntry entry2(entry1);
329 entry2.metric++;
Paul Stewartf748a362012-03-07 12:01:20 -0800330 SendRouteEntry(RTNLMessage::kModeAdd,
331 kTestDeviceIndex1,
332 entry2);
Paul Stewart75e89d22011-08-01 10:00:02 -0700333
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800334 // Routing table size shouldn't change, but the new metric should match.
Paul Stewart75e89d22011-08-01 10:00:02 -0700335 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
336 test_entry = (*tables)[kTestDeviceIndex1][0];
337 EXPECT_TRUE(entry2.Equals(test_entry));
338
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800339 // Find a matching entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700340 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700341 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700342 &test_entry));
343 EXPECT_TRUE(entry2.Equals(test_entry));
344
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800345 // Test that a search for a non-matching family fails.
Paul Stewart75e89d22011-08-01 10:00:02 -0700346 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700347 IPAddress::kFamilyIPv6,
Paul Stewart75e89d22011-08-01 10:00:02 -0700348 &test_entry));
349
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800350 // Remove last entry from an existing interface and test that we now fail.
Paul Stewartf748a362012-03-07 12:01:20 -0800351 SendRouteEntry(RTNLMessage::kModeDelete,
352 kTestDeviceIndex1,
353 entry2);
Paul Stewart75e89d22011-08-01 10:00:02 -0700354
355 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700356 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700357 &test_entry));
358
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700359 // Add a route to a gatway address.
360 IPAddress gateway_address(IPAddress::kFamilyIPv4);
361 EXPECT_TRUE(gateway_address.SetAddressFromString(kTestNetAddress0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700362
Paul Stewartf748a362012-03-07 12:01:20 -0800363 EXPECT_CALL(rtnl_handler_,
364 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
365 kTestDeviceIndex1,
366 entry0,
367 NLM_F_CREATE | NLM_F_EXCL)));
Paul Stewart75e89d22011-08-01 10:00:02 -0700368 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700369 gateway_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700370 metric));
371
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800372 // The table entry should look much like entry0, except with
373 // from_rtnl = false.
Paul Stewart75e89d22011-08-01 10:00:02 -0700374 RoutingTableEntry entry3(entry0);
375 entry3.from_rtnl = false;
376 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700377 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700378 &test_entry));
379 EXPECT_TRUE(entry3.Equals(test_entry));
380
381 // Setting the same route on the interface with a different metric should
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800382 // push the route with different flags to indicate we are replacing it,
383 // then it should delete the old entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700384 RoutingTableEntry entry4(entry3);
385 entry4.metric += 10;
Paul Stewartf748a362012-03-07 12:01:20 -0800386 EXPECT_CALL(rtnl_handler_,
387 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
388 kTestDeviceIndex1,
389 entry4,
390 NLM_F_CREATE | NLM_F_REPLACE)));
391 EXPECT_CALL(rtnl_handler_,
392 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800393 kTestDeviceIndex1,
394 entry3,
Paul Stewartf748a362012-03-07 12:01:20 -0800395 0)));
Paul Stewart75e89d22011-08-01 10:00:02 -0700396 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700397 gateway_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700398 entry4.metric));
399
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800400 // Test that removing the table causes the route to disappear.
Paul Stewart75e89d22011-08-01 10:00:02 -0700401 routing_table_->ResetTable(kTestDeviceIndex1);
402 EXPECT_FALSE(ContainsKey(*tables, kTestDeviceIndex1));
403 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700404 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700405 &test_entry));
406 EXPECT_EQ(1, GetRoutingTables()->size());
407
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800408 // When we set the metric on an existing route, a new add and delete
409 // operation should occur.
Paul Stewart75e89d22011-08-01 10:00:02 -0700410 RoutingTableEntry entry5(entry4);
411 entry5.metric += 10;
Paul Stewartf748a362012-03-07 12:01:20 -0800412 EXPECT_CALL(rtnl_handler_,
413 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
414 kTestDeviceIndex0,
415 entry5,
416 NLM_F_CREATE | NLM_F_REPLACE)));
417 EXPECT_CALL(rtnl_handler_,
418 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
419 kTestDeviceIndex0,
420 entry0,
421 0)));
Paul Stewart75e89d22011-08-01 10:00:02 -0700422 routing_table_->SetDefaultMetric(kTestDeviceIndex0, entry5.metric);
mukesh agrawald4ef6772012-02-21 16:28:04 -0800423 // Furthermore, the routing table should reflect the change in the metric
424 // for the default route for the interface.
425 RoutingTableEntry default_route;
426 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex0,
427 IPAddress::kFamilyIPv4,
428 &default_route));
429 EXPECT_EQ(entry5.metric, default_route.metric);
Paul Stewart75e89d22011-08-01 10:00:02 -0700430
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800431 // Ask to flush table0. We should see a delete message sent.
Paul Stewartf748a362012-03-07 12:01:20 -0800432 EXPECT_CALL(rtnl_handler_,
433 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
434 kTestDeviceIndex0,
435 entry5,
436 0)));
Thieu Lefb46caf2012-03-08 11:57:15 -0800437 routing_table_->FlushRoutes(kTestDeviceIndex0);
438 EXPECT_EQ(0, (*tables)[kTestDeviceIndex0].size());
Paul Stewart75e89d22011-08-01 10:00:02 -0700439
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800440 // Test that the routing table size returns to zero.
Paul Stewartf748a362012-03-07 12:01:20 -0800441 SendRouteEntry(RTNLMessage::kModeAdd,
442 kTestDeviceIndex0,
443 entry5);
Paul Stewart75e89d22011-08-01 10:00:02 -0700444 EXPECT_EQ(1, GetRoutingTables()->size());
445 routing_table_->ResetTable(kTestDeviceIndex0);
446 EXPECT_EQ(0, GetRoutingTables()->size());
447
448 routing_table_->Stop();
Paul Stewartf748a362012-03-07 12:01:20 -0800449}
450
Paul Stewart3f68bb12012-03-15 13:33:10 -0700451TEST_F(RoutingTableTest, ConfigureRoutes) {
452 MockControl control;
453 IPConfigRefPtr ipconfig(new IPConfig(&control, kTestDeviceName0));
454 IPConfig::Properties properties;
455 properties.address_family = IPAddress::kFamilyIPv4;
456 vector<IPConfig::Route> &routes = properties.routes;
457 ipconfig->UpdateProperties(properties, true);
458
459 const int kMetric = 10;
460 EXPECT_TRUE(routing_table_->ConfigureRoutes(kTestDeviceIndex0,
461 ipconfig,
462 kMetric));
463
464 IPConfig::Route route;
465 route.host = kTestRemoteNetwork4;
466 route.netmask = kTestRemoteNetmask4;
467 route.gateway = kTestGatewayAddress4;
468 routes.push_back(route);
469 ipconfig->UpdateProperties(properties, true);
470
471 IPAddress destination_address(IPAddress::kFamilyIPv4);
472 IPAddress source_address(IPAddress::kFamilyIPv4);
473 IPAddress gateway_address(IPAddress::kFamilyIPv4);
474 ASSERT_TRUE(destination_address.SetAddressFromString(kTestRemoteNetwork4));
475 destination_address.set_prefix(kTestRemotePrefix4);
476 ASSERT_TRUE(gateway_address.SetAddressFromString(kTestGatewayAddress4));
477
478 RoutingTableEntry entry(destination_address,
479 source_address,
480 gateway_address,
481 kMetric,
482 RT_SCOPE_UNIVERSE,
483 false);
484
485 EXPECT_CALL(rtnl_handler_,
486 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
487 kTestDeviceIndex0,
488 entry,
489 NLM_F_CREATE | NLM_F_EXCL)));
490 EXPECT_TRUE(routing_table_->ConfigureRoutes(kTestDeviceIndex0,
491 ipconfig,
492 kMetric));
493
494 routes.clear();
495 route.gateway = "xxx"; // Invalid gateway entry -- should be skipped
496 routes.push_back(route);
497 route.host = "xxx"; // Invalid host entry -- should be skipped
498 route.gateway = kTestGatewayAddress4;
499 routes.push_back(route);
500 route.host = kTestRemoteNetwork4;
501 routes.push_back(route);
502 ipconfig->UpdateProperties(properties, true);
503
504 EXPECT_CALL(rtnl_handler_,
505 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
506 kTestDeviceIndex0,
507 entry,
508 NLM_F_CREATE | NLM_F_EXCL)))
509 .Times(1);
510 EXPECT_FALSE(routing_table_->ConfigureRoutes(kTestDeviceIndex0,
511 ipconfig,
512 kMetric));
513}
514
Paul Stewartf748a362012-03-07 12:01:20 -0800515MATCHER_P2(IsRoutingQuery, destination, index, "") {
516 const RTNLMessage::RouteStatus &status = arg->route_status();
517
518 uint32 oif;
519
520 return
521 arg->type() == RTNLMessage::kTypeRoute &&
522 arg->family() == destination.family() &&
523 arg->flags() == NLM_F_REQUEST &&
524 status.table == 0 &&
525 status.protocol == 0 &&
526 status.scope == 0 &&
527 status.type == 0 &&
528 arg->HasAttribute(RTA_DST) &&
529 IPAddress(arg->family(),
530 arg->GetAttribute(RTA_DST),
531 status.dst_prefix).Equals(destination) &&
532 !arg->HasAttribute(RTA_SRC) &&
533 !arg->HasAttribute(RTA_GATEWAY) &&
534 arg->GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
535 oif == index &&
536 !arg->HasAttribute(RTA_PRIORITY);
537
538 return false;
539}
540
541TEST_F(RoutingTableTest, RequestHostRoute) {
542 IPAddress destination_address(IPAddress::kFamilyIPv4);
543 destination_address.SetAddressFromString(kTestRemoteAddress4);
544 destination_address.set_prefix(24);
545
546 EXPECT_CALL(rtnl_handler_,
547 SendMessage(IsRoutingQuery(destination_address,
548 kTestDeviceIndex0)))
549 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200550 EXPECT_TRUE(
551 routing_table_->RequestRouteToHost(destination_address,
552 kTestDeviceIndex0,
553 kTestRouteTag,
554 RoutingTable::Query::Callback()));
Paul Stewartf748a362012-03-07 12:01:20 -0800555
556 IPAddress gateway_address(IPAddress::kFamilyIPv4);
557 gateway_address.SetAddressFromString(kTestGatewayAddress4);
558
559 IPAddress local_address(IPAddress::kFamilyIPv4);
560 local_address.SetAddressFromString(kTestDeviceNetAddress4);
561
562 const int kMetric = 10;
563 RoutingTableEntry entry(destination_address,
564 local_address,
565 gateway_address,
566 kMetric,
567 RT_SCOPE_UNIVERSE,
568 true);
569
570 EXPECT_CALL(rtnl_handler_,
571 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
572 kTestDeviceIndex0,
573 entry,
574 NLM_F_CREATE | NLM_F_EXCL)));
575 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
576 kTestDeviceIndex0,
577 entry,
578 kTestRequestSeq,
579 RTPROT_UNSPEC);
Paul Stewarte93b0382012-04-24 13:11:28 -0700580
Darin Petkovabf6d282012-05-08 15:49:05 +0200581 hash_map<int, vector<RoutingTableEntry> > *tables = GetRoutingTables();
Paul Stewarte93b0382012-04-24 13:11:28 -0700582
583 // We should have a single table, which should in turn have a single entry.
584 EXPECT_EQ(1, tables->size());
585 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex0));
586 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
587
588 // This entry's tag should match the tag we requested.
589 EXPECT_EQ(kTestRouteTag, (*tables)[kTestDeviceIndex0][0].tag);
590
Darin Petkovabf6d282012-05-08 15:49:05 +0200591 EXPECT_TRUE(GetQueries()->empty());
592
Paul Stewarte93b0382012-04-24 13:11:28 -0700593 // Ask to flush routes with our tag. We should see a delete message sent.
594 EXPECT_CALL(rtnl_handler_,
595 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
596 kTestDeviceIndex0,
597 entry,
598 0)));
599
600 routing_table_->FlushRoutesWithTag(kTestRouteTag);
601
602 // After flushing routes for this tag, we should end up with no routes.
603 EXPECT_EQ(0, (*tables)[kTestDeviceIndex0].size());
Paul Stewartf748a362012-03-07 12:01:20 -0800604}
605
Paul Stewartbbed76d2012-04-27 20:02:13 -0700606TEST_F(RoutingTableTest, RequestHostRouteWithoutGateway) {
607 IPAddress destination_address(IPAddress::kFamilyIPv4);
608 destination_address.SetAddressFromString(kTestRemoteAddress4);
609 destination_address.set_prefix(24);
610
611 EXPECT_CALL(rtnl_handler_,
612 SendMessage(IsRoutingQuery(destination_address,
613 kTestDeviceIndex0)))
614 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200615 EXPECT_TRUE(
616 routing_table_->RequestRouteToHost(destination_address,
617 kTestDeviceIndex0,
618 kTestRouteTag,
619 RoutingTable::Query::Callback()));
Paul Stewartbbed76d2012-04-27 20:02:13 -0700620
621 // Don't specify a gateway address.
622 IPAddress gateway_address(IPAddress::kFamilyIPv4);
623
624 IPAddress local_address(IPAddress::kFamilyIPv4);
625 local_address.SetAddressFromString(kTestDeviceNetAddress4);
626
627 const int kMetric = 10;
628 RoutingTableEntry entry(destination_address,
629 local_address,
630 gateway_address,
631 kMetric,
632 RT_SCOPE_UNIVERSE,
633 true);
634
635 // Ensure that without a gateway entry, we don't create a route.
636 EXPECT_CALL(rtnl_handler_, SendMessage(_)).Times(0);
637 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
638 kTestDeviceIndex0,
639 entry,
640 kTestRequestSeq,
641 RTPROT_UNSPEC);
Darin Petkovabf6d282012-05-08 15:49:05 +0200642 EXPECT_TRUE(GetQueries()->empty());
Paul Stewartbbed76d2012-04-27 20:02:13 -0700643}
644
Paul Stewartf748a362012-03-07 12:01:20 -0800645TEST_F(RoutingTableTest, RequestHostRouteBadSequence) {
646 IPAddress destination_address(IPAddress::kFamilyIPv4);
647 destination_address.SetAddressFromString(kTestRemoteAddress4);
Darin Petkovabf6d282012-05-08 15:49:05 +0200648 QueryCallbackTarget target;
Darin Petkov13e6d552012-05-09 14:22:23 +0200649 EXPECT_CALL(target, MockedTarget(_, _)).Times(0);
Paul Stewartf748a362012-03-07 12:01:20 -0800650 EXPECT_CALL(rtnl_handler_, SendMessage(_))
651 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200652 EXPECT_TRUE(
653 routing_table_->RequestRouteToHost(destination_address,
654 kTestDeviceIndex0,
655 kTestRouteTag,
Darin Petkov13e6d552012-05-09 14:22:23 +0200656 target.mocked_callback()));
Paul Stewarte93b0382012-04-24 13:11:28 -0700657 EXPECT_FALSE(GetQueries()->empty());
Paul Stewartf748a362012-03-07 12:01:20 -0800658
659 RoutingTableEntry entry(destination_address,
660 destination_address,
661 destination_address,
662 0,
663 RT_SCOPE_UNIVERSE,
664 true);
665
666 // Try a sequence arriving before the one RoutingTable is looking for.
667 // This should be a no-op.
668 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
669 kTestDeviceIndex0,
670 entry,
Darin Petkovabf6d282012-05-08 15:49:05 +0200671 kTestRequestSeq - 1,
Paul Stewartf748a362012-03-07 12:01:20 -0800672 RTPROT_UNSPEC);
Paul Stewarte93b0382012-04-24 13:11:28 -0700673 EXPECT_FALSE(GetQueries()->empty());
Paul Stewartf748a362012-03-07 12:01:20 -0800674
675 // Try a sequence arriving after the one RoutingTable is looking for.
676 // This should cause the request to be purged.
677 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
678 kTestDeviceIndex0,
679 entry,
Darin Petkovabf6d282012-05-08 15:49:05 +0200680 kTestRequestSeq + 1,
Paul Stewartf748a362012-03-07 12:01:20 -0800681 RTPROT_UNSPEC);
Paul Stewarte93b0382012-04-24 13:11:28 -0700682 EXPECT_TRUE(GetQueries()->empty());
Paul Stewart75e89d22011-08-01 10:00:02 -0700683}
684
Darin Petkovabf6d282012-05-08 15:49:05 +0200685TEST_F(RoutingTableTest, RequestHostRouteWithCallback) {
686 IPAddress destination_address(IPAddress::kFamilyIPv4);
687
688 EXPECT_CALL(rtnl_handler_, SendMessage(_))
689 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
690 QueryCallbackTarget target;
691 EXPECT_TRUE(
692 routing_table_->RequestRouteToHost(
Darin Petkov13e6d552012-05-09 14:22:23 +0200693 destination_address, -1, kTestRouteTag, target.mocked_callback()));
Darin Petkovabf6d282012-05-08 15:49:05 +0200694
695 IPAddress gateway_address(IPAddress::kFamilyIPv4);
696 gateway_address.SetAddressFromString(kTestGatewayAddress4);
Darin Petkovabf6d282012-05-08 15:49:05 +0200697
698 const int kMetric = 10;
699 RoutingTableEntry entry(destination_address,
Darin Petkov13e6d552012-05-09 14:22:23 +0200700 IPAddress(IPAddress::kFamilyIPv4),
Darin Petkovabf6d282012-05-08 15:49:05 +0200701 gateway_address,
702 kMetric,
703 RT_SCOPE_UNIVERSE,
704 true);
705
706 EXPECT_CALL(rtnl_handler_, SendMessage(_));
707 EXPECT_CALL(target,
Darin Petkov13e6d552012-05-09 14:22:23 +0200708 MockedTarget(kTestDeviceIndex0,
709 Field(&RoutingTableEntry::tag, kTestRouteTag)));
Darin Petkovabf6d282012-05-08 15:49:05 +0200710 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
711 kTestDeviceIndex0,
712 entry,
713 kTestRequestSeq,
714 RTPROT_UNSPEC);
715}
716
717TEST_F(RoutingTableTest, RequestHostRouteWithoutGatewayWithCallback) {
718 IPAddress destination_address(IPAddress::kFamilyIPv4);
719
720 EXPECT_CALL(rtnl_handler_, SendMessage(_))
721 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
722 QueryCallbackTarget target;
723 EXPECT_TRUE(
724 routing_table_->RequestRouteToHost(
Darin Petkov13e6d552012-05-09 14:22:23 +0200725 destination_address, -1, kTestRouteTag, target.mocked_callback()));
Darin Petkovabf6d282012-05-08 15:49:05 +0200726
727 const int kMetric = 10;
728 RoutingTableEntry entry(destination_address,
Darin Petkov13e6d552012-05-09 14:22:23 +0200729 IPAddress(IPAddress::kFamilyIPv4),
730 IPAddress(IPAddress::kFamilyIPv4),
Darin Petkovabf6d282012-05-08 15:49:05 +0200731 kMetric,
732 RT_SCOPE_UNIVERSE,
733 true);
734
735 EXPECT_CALL(target,
Darin Petkov13e6d552012-05-09 14:22:23 +0200736 MockedTarget(kTestDeviceIndex0,
737 Field(&RoutingTableEntry::tag, kTestRouteTag)));
Darin Petkovabf6d282012-05-08 15:49:05 +0200738 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
739 kTestDeviceIndex0,
740 entry,
741 kTestRequestSeq,
742 RTPROT_UNSPEC);
743}
744
745TEST_F(RoutingTableTest, CancelQueryCallback) {
746 IPAddress destination_address(IPAddress::kFamilyIPv4);
747 destination_address.SetAddressFromString(kTestRemoteAddress4);
Darin Petkov13e6d552012-05-09 14:22:23 +0200748 scoped_ptr<QueryCallbackTarget> target(new QueryCallbackTarget());
749 EXPECT_CALL(rtnl_handler_, SendMessage(_))
750 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200751 EXPECT_TRUE(
752 routing_table_->RequestRouteToHost(destination_address,
753 kTestDeviceIndex0,
754 kTestRouteTag,
Darin Petkov13e6d552012-05-09 14:22:23 +0200755 target->unreached_callback()));
756 ASSERT_EQ(1, GetQueries()->size());
757 // Cancels the callback by destroying the owner object.
758 target.reset();
759 const int kMetric = 10;
760 RoutingTableEntry entry(IPAddress(IPAddress::kFamilyIPv4),
761 IPAddress(IPAddress::kFamilyIPv4),
762 IPAddress(IPAddress::kFamilyIPv4),
763 kMetric,
764 RT_SCOPE_UNIVERSE,
765 true);
766 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
767 kTestDeviceIndex0,
768 entry,
769 kTestRequestSeq,
770 RTPROT_UNSPEC);
Darin Petkovabf6d282012-05-08 15:49:05 +0200771}
772
Paul Stewart75e89d22011-08-01 10:00:02 -0700773} // namespace shill