blob: 52c105e39d13fd6ee95f0f0528fe760562657989 [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
Darin Petkov13e6d552012-05-09 14:22:23 +020010#include <base/memory/weak_ptr.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/stl_util.h>
Paul Stewart75e89d22011-08-01 10:00:02 -070012#include <gtest/gtest.h>
13#include <gmock/gmock.h>
14
15#include "shill/byte_string.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070016#include "shill/logging.h"
Paul Stewart75e89d22011-08-01 10:00:02 -070017#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) &&
Paul Stewart4a6748d2012-07-17 14:31:36 -0700178 ((!arg->HasAttribute(RTA_SRC) && entry.src.IsDefault()) ||
179 (arg->HasAttribute(RTA_SRC) && IPAddress(arg->family(),
180 arg->GetAttribute(RTA_SRC),
181 status.src_prefix).Equals(entry.src))) &&
182 ((!arg->HasAttribute(RTA_GATEWAY) && entry.gateway.IsDefault()) ||
183 (arg->HasAttribute(RTA_GATEWAY) && IPAddress(arg->family(),
184 arg->GetAttribute(RTA_GATEWAY)).Equals(entry.gateway))) &&
Paul Stewartf748a362012-03-07 12:01:20 -0800185 arg->GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
186 oif == index &&
187 arg->GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&priority) &&
188 priority == entry.metric;
Paul Stewart75e89d22011-08-01 10:00:02 -0700189}
190
Darin Petkovabf6d282012-05-08 15:49:05 +0200191} // namespace
192
Paul Stewartf748a362012-03-07 12:01:20 -0800193void RoutingTableTest::SendRouteEntry(RTNLMessage::Mode mode,
194 uint32 interface_index,
195 const RoutingTableEntry &entry) {
196 SendRouteEntryWithSeqAndProto(mode, interface_index, entry, 0, RTPROT_BOOT);
197}
198
199void RoutingTableTest::SendRouteEntryWithSeqAndProto(
200 RTNLMessage::Mode mode,
201 uint32 interface_index,
202 const RoutingTableEntry &entry,
203 uint32 seq,
204 unsigned char proto) {
Paul Stewart75e89d22011-08-01 10:00:02 -0700205 RTNLMessage msg(
Paul Stewart9a908082011-08-31 12:18:48 -0700206 RTNLMessage::kTypeRoute,
Paul Stewart75e89d22011-08-01 10:00:02 -0700207 mode,
208 0,
Paul Stewartf748a362012-03-07 12:01:20 -0800209 seq,
Paul Stewart75e89d22011-08-01 10:00:02 -0700210 0,
211 0,
212 entry.dst.family());
213
214 msg.set_route_status(RTNLMessage::RouteStatus(
Paul Stewart9e3fcd72011-08-26 15:46:16 -0700215 entry.dst.prefix(),
216 entry.src.prefix(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700217 RT_TABLE_MAIN,
Paul Stewartf748a362012-03-07 12:01:20 -0800218 proto,
Paul Stewart75e89d22011-08-01 10:00:02 -0700219 entry.scope,
220 RTN_UNICAST,
221 0));
222
223 msg.SetAttribute(RTA_DST, entry.dst.address());
224 if (!entry.src.IsDefault()) {
225 msg.SetAttribute(RTA_SRC, entry.src.address());
226 }
227 if (!entry.gateway.IsDefault()) {
228 msg.SetAttribute(RTA_GATEWAY, entry.gateway.address());
229 }
230 msg.SetAttribute(RTA_PRIORITY, ByteString::CreateFromCPUUInt32(entry.metric));
231 msg.SetAttribute(RTA_OIF, ByteString::CreateFromCPUUInt32(interface_index));
232
Paul Stewartf748a362012-03-07 12:01:20 -0800233 routing_table_->RouteMsgHandler(msg);
Paul Stewart75e89d22011-08-01 10:00:02 -0700234}
235
Paul Stewartf748a362012-03-07 12:01:20 -0800236void RoutingTableTest::SendRouteMessage(const RTNLMessage &msg) {
237 routing_table_->RouteMsgHandler(msg);
Paul Stewart75e89d22011-08-01 10:00:02 -0700238}
239
Paul Stewartf748a362012-03-07 12:01:20 -0800240TEST_F(RoutingTableTest, Start) {
241 EXPECT_CALL(rtnl_handler_, RequestDump(RTNLHandler::kRequestRoute));
242 routing_table_->Start();
Paul Stewart75e89d22011-08-01 10:00:02 -0700243}
244
245TEST_F(RoutingTableTest, RouteAddDelete) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800246 // Expect the tables to be empty by default.
Paul Stewart75e89d22011-08-01 10:00:02 -0700247 EXPECT_EQ(0, GetRoutingTables()->size());
248
Paul Stewart7355ce12011-09-02 10:47:01 -0700249 IPAddress default_address(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700250 default_address.SetAddressToDefault();
251
Paul Stewart7355ce12011-09-02 10:47:01 -0700252 IPAddress gateway_address0(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700253 gateway_address0.SetAddressFromString(kTestNetAddress0);
254
255 int metric = 10;
256
257 RoutingTableEntry entry0(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700258 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700259 gateway_address0,
260 metric,
261 RT_SCOPE_UNIVERSE,
262 true);
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800263 // Add a single entry.
Paul Stewartf748a362012-03-07 12:01:20 -0800264 SendRouteEntry(RTNLMessage::kModeAdd,
265 kTestDeviceIndex0,
266 entry0);
Paul Stewart75e89d22011-08-01 10:00:02 -0700267
Paul Stewarte93b0382012-04-24 13:11:28 -0700268 hash_map<int, vector<RoutingTableEntry> > *tables =
Paul Stewart75e89d22011-08-01 10:00:02 -0700269 GetRoutingTables();
270
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800271 // We should have a single table, which should in turn have a single entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700272 EXPECT_EQ(1, tables->size());
273 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex0));
274 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
275
276 RoutingTableEntry test_entry = (*tables)[kTestDeviceIndex0][0];
277 EXPECT_TRUE(entry0.Equals(test_entry));
278
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800279 // Add a second entry for a different interface.
Paul Stewartf748a362012-03-07 12:01:20 -0800280 SendRouteEntry(RTNLMessage::kModeAdd,
281 kTestDeviceIndex1,
282 entry0);
Paul Stewart75e89d22011-08-01 10:00:02 -0700283
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800284 // We should have two tables, which should have a single entry each.
Paul Stewart75e89d22011-08-01 10:00:02 -0700285 EXPECT_EQ(2, tables->size());
286 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex1));
287 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
288 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
289
290 test_entry = (*tables)[kTestDeviceIndex1][0];
291 EXPECT_TRUE(entry0.Equals(test_entry));
292
Paul Stewart7355ce12011-09-02 10:47:01 -0700293 IPAddress gateway_address1(IPAddress::kFamilyIPv4);
Paul Stewart75e89d22011-08-01 10:00:02 -0700294 gateway_address1.SetAddressFromString(kTestNetAddress1);
295
296 RoutingTableEntry entry1(default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700297 default_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700298 gateway_address1,
299 metric,
300 RT_SCOPE_UNIVERSE,
301 true);
302
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800303 // Add a second gateway route to the second interface.
Paul Stewartf748a362012-03-07 12:01:20 -0800304 SendRouteEntry(RTNLMessage::kModeAdd,
305 kTestDeviceIndex1,
306 entry1);
Paul Stewart75e89d22011-08-01 10:00:02 -0700307
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800308 // We should have two tables, one of which has a single entry, the other has
309 // two.
Paul Stewart75e89d22011-08-01 10:00:02 -0700310 EXPECT_EQ(2, tables->size());
311 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
312 EXPECT_EQ(2, (*tables)[kTestDeviceIndex1].size());
313
314 test_entry = (*tables)[kTestDeviceIndex1][1];
315 EXPECT_TRUE(entry1.Equals(test_entry));
316
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800317 // Remove the first gateway route from the second interface.
Paul Stewartf748a362012-03-07 12:01:20 -0800318 SendRouteEntry(RTNLMessage::kModeDelete,
319 kTestDeviceIndex1,
320 entry0);
Paul Stewart75e89d22011-08-01 10:00:02 -0700321
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800322 // We should be back to having one route per table.
Paul Stewart75e89d22011-08-01 10:00:02 -0700323 EXPECT_EQ(2, tables->size());
324 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
325 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
326
327 test_entry = (*tables)[kTestDeviceIndex1][0];
328 EXPECT_TRUE(entry1.Equals(test_entry));
329
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700330 // Send a duplicate of the second gateway route message, changing the metric.
Paul Stewart75e89d22011-08-01 10:00:02 -0700331 RoutingTableEntry entry2(entry1);
332 entry2.metric++;
Paul Stewartf748a362012-03-07 12:01:20 -0800333 SendRouteEntry(RTNLMessage::kModeAdd,
334 kTestDeviceIndex1,
335 entry2);
Paul Stewart75e89d22011-08-01 10:00:02 -0700336
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800337 // Routing table size shouldn't change, but the new metric should match.
Paul Stewart75e89d22011-08-01 10:00:02 -0700338 EXPECT_EQ(1, (*tables)[kTestDeviceIndex1].size());
339 test_entry = (*tables)[kTestDeviceIndex1][0];
340 EXPECT_TRUE(entry2.Equals(test_entry));
341
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800342 // Find a matching entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700343 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700344 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700345 &test_entry));
346 EXPECT_TRUE(entry2.Equals(test_entry));
347
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800348 // Test that a search for a non-matching family fails.
Paul Stewart75e89d22011-08-01 10:00:02 -0700349 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700350 IPAddress::kFamilyIPv6,
Paul Stewart75e89d22011-08-01 10:00:02 -0700351 &test_entry));
352
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800353 // Remove last entry from an existing interface and test that we now fail.
Paul Stewartf748a362012-03-07 12:01:20 -0800354 SendRouteEntry(RTNLMessage::kModeDelete,
355 kTestDeviceIndex1,
356 entry2);
Paul Stewart75e89d22011-08-01 10:00:02 -0700357
358 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700359 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700360 &test_entry));
361
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700362 // Add a route to a gatway address.
363 IPAddress gateway_address(IPAddress::kFamilyIPv4);
364 EXPECT_TRUE(gateway_address.SetAddressFromString(kTestNetAddress0));
Paul Stewart75e89d22011-08-01 10:00:02 -0700365
Paul Stewartf748a362012-03-07 12:01:20 -0800366 EXPECT_CALL(rtnl_handler_,
367 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
368 kTestDeviceIndex1,
369 entry0,
370 NLM_F_CREATE | NLM_F_EXCL)));
Paul Stewart75e89d22011-08-01 10:00:02 -0700371 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700372 gateway_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700373 metric));
374
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800375 // The table entry should look much like entry0, except with
376 // from_rtnl = false.
Paul Stewart75e89d22011-08-01 10:00:02 -0700377 RoutingTableEntry entry3(entry0);
378 entry3.from_rtnl = false;
379 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700380 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700381 &test_entry));
382 EXPECT_TRUE(entry3.Equals(test_entry));
383
384 // Setting the same route on the interface with a different metric should
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800385 // push the route with different flags to indicate we are replacing it,
386 // then it should delete the old entry.
Paul Stewart75e89d22011-08-01 10:00:02 -0700387 RoutingTableEntry entry4(entry3);
388 entry4.metric += 10;
Paul Stewartf748a362012-03-07 12:01:20 -0800389 EXPECT_CALL(rtnl_handler_,
390 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
391 kTestDeviceIndex1,
392 entry4,
393 NLM_F_CREATE | NLM_F_REPLACE)));
394 EXPECT_CALL(rtnl_handler_,
395 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800396 kTestDeviceIndex1,
397 entry3,
Paul Stewartf748a362012-03-07 12:01:20 -0800398 0)));
Paul Stewart75e89d22011-08-01 10:00:02 -0700399 EXPECT_TRUE(routing_table_->SetDefaultRoute(kTestDeviceIndex1,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700400 gateway_address,
Paul Stewart75e89d22011-08-01 10:00:02 -0700401 entry4.metric));
402
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800403 // Test that removing the table causes the route to disappear.
Paul Stewart75e89d22011-08-01 10:00:02 -0700404 routing_table_->ResetTable(kTestDeviceIndex1);
405 EXPECT_FALSE(ContainsKey(*tables, kTestDeviceIndex1));
406 EXPECT_FALSE(routing_table_->GetDefaultRoute(kTestDeviceIndex1,
Paul Stewart7355ce12011-09-02 10:47:01 -0700407 IPAddress::kFamilyIPv4,
Paul Stewart75e89d22011-08-01 10:00:02 -0700408 &test_entry));
409 EXPECT_EQ(1, GetRoutingTables()->size());
410
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800411 // When we set the metric on an existing route, a new add and delete
412 // operation should occur.
Paul Stewart75e89d22011-08-01 10:00:02 -0700413 RoutingTableEntry entry5(entry4);
414 entry5.metric += 10;
Paul Stewartf748a362012-03-07 12:01:20 -0800415 EXPECT_CALL(rtnl_handler_,
416 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
417 kTestDeviceIndex0,
418 entry5,
419 NLM_F_CREATE | NLM_F_REPLACE)));
420 EXPECT_CALL(rtnl_handler_,
421 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
422 kTestDeviceIndex0,
423 entry0,
424 0)));
Paul Stewart75e89d22011-08-01 10:00:02 -0700425 routing_table_->SetDefaultMetric(kTestDeviceIndex0, entry5.metric);
mukesh agrawald4ef6772012-02-21 16:28:04 -0800426 // Furthermore, the routing table should reflect the change in the metric
427 // for the default route for the interface.
428 RoutingTableEntry default_route;
429 EXPECT_TRUE(routing_table_->GetDefaultRoute(kTestDeviceIndex0,
430 IPAddress::kFamilyIPv4,
431 &default_route));
432 EXPECT_EQ(entry5.metric, default_route.metric);
Paul Stewart75e89d22011-08-01 10:00:02 -0700433
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800434 // Ask to flush table0. We should see a delete message sent.
Paul Stewartf748a362012-03-07 12:01:20 -0800435 EXPECT_CALL(rtnl_handler_,
436 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
437 kTestDeviceIndex0,
438 entry5,
439 0)));
Thieu Lefb46caf2012-03-08 11:57:15 -0800440 routing_table_->FlushRoutes(kTestDeviceIndex0);
441 EXPECT_EQ(0, (*tables)[kTestDeviceIndex0].size());
Paul Stewart75e89d22011-08-01 10:00:02 -0700442
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800443 // Test that the routing table size returns to zero.
Paul Stewartf748a362012-03-07 12:01:20 -0800444 SendRouteEntry(RTNLMessage::kModeAdd,
445 kTestDeviceIndex0,
446 entry5);
Paul Stewart75e89d22011-08-01 10:00:02 -0700447 EXPECT_EQ(1, GetRoutingTables()->size());
448 routing_table_->ResetTable(kTestDeviceIndex0);
449 EXPECT_EQ(0, GetRoutingTables()->size());
450
451 routing_table_->Stop();
Paul Stewartf748a362012-03-07 12:01:20 -0800452}
453
Paul Stewart3f68bb12012-03-15 13:33:10 -0700454TEST_F(RoutingTableTest, ConfigureRoutes) {
455 MockControl control;
456 IPConfigRefPtr ipconfig(new IPConfig(&control, kTestDeviceName0));
457 IPConfig::Properties properties;
458 properties.address_family = IPAddress::kFamilyIPv4;
459 vector<IPConfig::Route> &routes = properties.routes;
460 ipconfig->UpdateProperties(properties, true);
461
462 const int kMetric = 10;
463 EXPECT_TRUE(routing_table_->ConfigureRoutes(kTestDeviceIndex0,
464 ipconfig,
465 kMetric));
466
467 IPConfig::Route route;
468 route.host = kTestRemoteNetwork4;
469 route.netmask = kTestRemoteNetmask4;
470 route.gateway = kTestGatewayAddress4;
471 routes.push_back(route);
472 ipconfig->UpdateProperties(properties, true);
473
474 IPAddress destination_address(IPAddress::kFamilyIPv4);
475 IPAddress source_address(IPAddress::kFamilyIPv4);
476 IPAddress gateway_address(IPAddress::kFamilyIPv4);
477 ASSERT_TRUE(destination_address.SetAddressFromString(kTestRemoteNetwork4));
478 destination_address.set_prefix(kTestRemotePrefix4);
479 ASSERT_TRUE(gateway_address.SetAddressFromString(kTestGatewayAddress4));
480
481 RoutingTableEntry entry(destination_address,
482 source_address,
483 gateway_address,
484 kMetric,
485 RT_SCOPE_UNIVERSE,
486 false);
487
488 EXPECT_CALL(rtnl_handler_,
489 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
490 kTestDeviceIndex0,
491 entry,
492 NLM_F_CREATE | NLM_F_EXCL)));
493 EXPECT_TRUE(routing_table_->ConfigureRoutes(kTestDeviceIndex0,
494 ipconfig,
495 kMetric));
496
497 routes.clear();
498 route.gateway = "xxx"; // Invalid gateway entry -- should be skipped
499 routes.push_back(route);
500 route.host = "xxx"; // Invalid host entry -- should be skipped
501 route.gateway = kTestGatewayAddress4;
502 routes.push_back(route);
503 route.host = kTestRemoteNetwork4;
504 routes.push_back(route);
505 ipconfig->UpdateProperties(properties, true);
506
507 EXPECT_CALL(rtnl_handler_,
508 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
509 kTestDeviceIndex0,
510 entry,
511 NLM_F_CREATE | NLM_F_EXCL)))
512 .Times(1);
513 EXPECT_FALSE(routing_table_->ConfigureRoutes(kTestDeviceIndex0,
514 ipconfig,
515 kMetric));
516}
517
Paul Stewartf748a362012-03-07 12:01:20 -0800518MATCHER_P2(IsRoutingQuery, destination, index, "") {
519 const RTNLMessage::RouteStatus &status = arg->route_status();
520
521 uint32 oif;
522
523 return
524 arg->type() == RTNLMessage::kTypeRoute &&
525 arg->family() == destination.family() &&
526 arg->flags() == NLM_F_REQUEST &&
527 status.table == 0 &&
528 status.protocol == 0 &&
529 status.scope == 0 &&
530 status.type == 0 &&
531 arg->HasAttribute(RTA_DST) &&
532 IPAddress(arg->family(),
533 arg->GetAttribute(RTA_DST),
534 status.dst_prefix).Equals(destination) &&
535 !arg->HasAttribute(RTA_SRC) &&
536 !arg->HasAttribute(RTA_GATEWAY) &&
537 arg->GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
538 oif == index &&
539 !arg->HasAttribute(RTA_PRIORITY);
540
541 return false;
542}
543
544TEST_F(RoutingTableTest, RequestHostRoute) {
545 IPAddress destination_address(IPAddress::kFamilyIPv4);
546 destination_address.SetAddressFromString(kTestRemoteAddress4);
547 destination_address.set_prefix(24);
548
549 EXPECT_CALL(rtnl_handler_,
550 SendMessage(IsRoutingQuery(destination_address,
551 kTestDeviceIndex0)))
552 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200553 EXPECT_TRUE(
554 routing_table_->RequestRouteToHost(destination_address,
555 kTestDeviceIndex0,
556 kTestRouteTag,
557 RoutingTable::Query::Callback()));
Paul Stewartf748a362012-03-07 12:01:20 -0800558
559 IPAddress gateway_address(IPAddress::kFamilyIPv4);
560 gateway_address.SetAddressFromString(kTestGatewayAddress4);
561
562 IPAddress local_address(IPAddress::kFamilyIPv4);
563 local_address.SetAddressFromString(kTestDeviceNetAddress4);
564
565 const int kMetric = 10;
566 RoutingTableEntry entry(destination_address,
567 local_address,
568 gateway_address,
569 kMetric,
570 RT_SCOPE_UNIVERSE,
571 true);
572
573 EXPECT_CALL(rtnl_handler_,
574 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
575 kTestDeviceIndex0,
576 entry,
577 NLM_F_CREATE | NLM_F_EXCL)));
578 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
579 kTestDeviceIndex0,
580 entry,
581 kTestRequestSeq,
582 RTPROT_UNSPEC);
Paul Stewarte93b0382012-04-24 13:11:28 -0700583
Darin Petkovabf6d282012-05-08 15:49:05 +0200584 hash_map<int, vector<RoutingTableEntry> > *tables = GetRoutingTables();
Paul Stewarte93b0382012-04-24 13:11:28 -0700585
586 // We should have a single table, which should in turn have a single entry.
587 EXPECT_EQ(1, tables->size());
588 EXPECT_TRUE(ContainsKey(*tables, kTestDeviceIndex0));
589 EXPECT_EQ(1, (*tables)[kTestDeviceIndex0].size());
590
591 // This entry's tag should match the tag we requested.
592 EXPECT_EQ(kTestRouteTag, (*tables)[kTestDeviceIndex0][0].tag);
593
Darin Petkovabf6d282012-05-08 15:49:05 +0200594 EXPECT_TRUE(GetQueries()->empty());
595
Paul Stewarte93b0382012-04-24 13:11:28 -0700596 // Ask to flush routes with our tag. We should see a delete message sent.
597 EXPECT_CALL(rtnl_handler_,
598 SendMessage(IsRoutingPacket(RTNLMessage::kModeDelete,
599 kTestDeviceIndex0,
600 entry,
601 0)));
602
603 routing_table_->FlushRoutesWithTag(kTestRouteTag);
604
605 // After flushing routes for this tag, we should end up with no routes.
606 EXPECT_EQ(0, (*tables)[kTestDeviceIndex0].size());
Paul Stewartf748a362012-03-07 12:01:20 -0800607}
608
Paul Stewartbbed76d2012-04-27 20:02:13 -0700609TEST_F(RoutingTableTest, RequestHostRouteWithoutGateway) {
610 IPAddress destination_address(IPAddress::kFamilyIPv4);
611 destination_address.SetAddressFromString(kTestRemoteAddress4);
612 destination_address.set_prefix(24);
613
614 EXPECT_CALL(rtnl_handler_,
615 SendMessage(IsRoutingQuery(destination_address,
616 kTestDeviceIndex0)))
617 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200618 EXPECT_TRUE(
619 routing_table_->RequestRouteToHost(destination_address,
620 kTestDeviceIndex0,
621 kTestRouteTag,
622 RoutingTable::Query::Callback()));
Paul Stewartbbed76d2012-04-27 20:02:13 -0700623
624 // Don't specify a gateway address.
625 IPAddress gateway_address(IPAddress::kFamilyIPv4);
626
627 IPAddress local_address(IPAddress::kFamilyIPv4);
628 local_address.SetAddressFromString(kTestDeviceNetAddress4);
629
630 const int kMetric = 10;
631 RoutingTableEntry entry(destination_address,
632 local_address,
633 gateway_address,
634 kMetric,
635 RT_SCOPE_UNIVERSE,
636 true);
637
638 // Ensure that without a gateway entry, we don't create a route.
639 EXPECT_CALL(rtnl_handler_, SendMessage(_)).Times(0);
640 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
641 kTestDeviceIndex0,
642 entry,
643 kTestRequestSeq,
644 RTPROT_UNSPEC);
Darin Petkovabf6d282012-05-08 15:49:05 +0200645 EXPECT_TRUE(GetQueries()->empty());
Paul Stewartbbed76d2012-04-27 20:02:13 -0700646}
647
Paul Stewartf748a362012-03-07 12:01:20 -0800648TEST_F(RoutingTableTest, RequestHostRouteBadSequence) {
649 IPAddress destination_address(IPAddress::kFamilyIPv4);
650 destination_address.SetAddressFromString(kTestRemoteAddress4);
Darin Petkovabf6d282012-05-08 15:49:05 +0200651 QueryCallbackTarget target;
Darin Petkov13e6d552012-05-09 14:22:23 +0200652 EXPECT_CALL(target, MockedTarget(_, _)).Times(0);
Paul Stewartf748a362012-03-07 12:01:20 -0800653 EXPECT_CALL(rtnl_handler_, SendMessage(_))
654 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200655 EXPECT_TRUE(
656 routing_table_->RequestRouteToHost(destination_address,
657 kTestDeviceIndex0,
658 kTestRouteTag,
Darin Petkov13e6d552012-05-09 14:22:23 +0200659 target.mocked_callback()));
Paul Stewarte93b0382012-04-24 13:11:28 -0700660 EXPECT_FALSE(GetQueries()->empty());
Paul Stewartf748a362012-03-07 12:01:20 -0800661
662 RoutingTableEntry entry(destination_address,
663 destination_address,
664 destination_address,
665 0,
666 RT_SCOPE_UNIVERSE,
667 true);
668
669 // Try a sequence arriving before the one RoutingTable is looking for.
670 // This should be a no-op.
671 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
672 kTestDeviceIndex0,
673 entry,
Darin Petkovabf6d282012-05-08 15:49:05 +0200674 kTestRequestSeq - 1,
Paul Stewartf748a362012-03-07 12:01:20 -0800675 RTPROT_UNSPEC);
Paul Stewarte93b0382012-04-24 13:11:28 -0700676 EXPECT_FALSE(GetQueries()->empty());
Paul Stewartf748a362012-03-07 12:01:20 -0800677
678 // Try a sequence arriving after the one RoutingTable is looking for.
679 // This should cause the request to be purged.
680 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
681 kTestDeviceIndex0,
682 entry,
Darin Petkovabf6d282012-05-08 15:49:05 +0200683 kTestRequestSeq + 1,
Paul Stewartf748a362012-03-07 12:01:20 -0800684 RTPROT_UNSPEC);
Paul Stewarte93b0382012-04-24 13:11:28 -0700685 EXPECT_TRUE(GetQueries()->empty());
Paul Stewart75e89d22011-08-01 10:00:02 -0700686}
687
Darin Petkovabf6d282012-05-08 15:49:05 +0200688TEST_F(RoutingTableTest, RequestHostRouteWithCallback) {
689 IPAddress destination_address(IPAddress::kFamilyIPv4);
690
691 EXPECT_CALL(rtnl_handler_, SendMessage(_))
692 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
693 QueryCallbackTarget target;
694 EXPECT_TRUE(
695 routing_table_->RequestRouteToHost(
Darin Petkov13e6d552012-05-09 14:22:23 +0200696 destination_address, -1, kTestRouteTag, target.mocked_callback()));
Darin Petkovabf6d282012-05-08 15:49:05 +0200697
698 IPAddress gateway_address(IPAddress::kFamilyIPv4);
699 gateway_address.SetAddressFromString(kTestGatewayAddress4);
Darin Petkovabf6d282012-05-08 15:49:05 +0200700
701 const int kMetric = 10;
702 RoutingTableEntry entry(destination_address,
Darin Petkov13e6d552012-05-09 14:22:23 +0200703 IPAddress(IPAddress::kFamilyIPv4),
Darin Petkovabf6d282012-05-08 15:49:05 +0200704 gateway_address,
705 kMetric,
706 RT_SCOPE_UNIVERSE,
707 true);
708
709 EXPECT_CALL(rtnl_handler_, SendMessage(_));
710 EXPECT_CALL(target,
Darin Petkov13e6d552012-05-09 14:22:23 +0200711 MockedTarget(kTestDeviceIndex0,
712 Field(&RoutingTableEntry::tag, kTestRouteTag)));
Darin Petkovabf6d282012-05-08 15:49:05 +0200713 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
714 kTestDeviceIndex0,
715 entry,
716 kTestRequestSeq,
717 RTPROT_UNSPEC);
718}
719
720TEST_F(RoutingTableTest, RequestHostRouteWithoutGatewayWithCallback) {
721 IPAddress destination_address(IPAddress::kFamilyIPv4);
722
723 EXPECT_CALL(rtnl_handler_, SendMessage(_))
724 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
725 QueryCallbackTarget target;
726 EXPECT_TRUE(
727 routing_table_->RequestRouteToHost(
Darin Petkov13e6d552012-05-09 14:22:23 +0200728 destination_address, -1, kTestRouteTag, target.mocked_callback()));
Darin Petkovabf6d282012-05-08 15:49:05 +0200729
730 const int kMetric = 10;
731 RoutingTableEntry entry(destination_address,
Darin Petkov13e6d552012-05-09 14:22:23 +0200732 IPAddress(IPAddress::kFamilyIPv4),
733 IPAddress(IPAddress::kFamilyIPv4),
Darin Petkovabf6d282012-05-08 15:49:05 +0200734 kMetric,
735 RT_SCOPE_UNIVERSE,
736 true);
737
738 EXPECT_CALL(target,
Darin Petkov13e6d552012-05-09 14:22:23 +0200739 MockedTarget(kTestDeviceIndex0,
740 Field(&RoutingTableEntry::tag, kTestRouteTag)));
Darin Petkovabf6d282012-05-08 15:49:05 +0200741 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
742 kTestDeviceIndex0,
743 entry,
744 kTestRequestSeq,
745 RTPROT_UNSPEC);
746}
747
748TEST_F(RoutingTableTest, CancelQueryCallback) {
749 IPAddress destination_address(IPAddress::kFamilyIPv4);
750 destination_address.SetAddressFromString(kTestRemoteAddress4);
Darin Petkov13e6d552012-05-09 14:22:23 +0200751 scoped_ptr<QueryCallbackTarget> target(new QueryCallbackTarget());
752 EXPECT_CALL(rtnl_handler_, SendMessage(_))
753 .WillOnce(Invoke(this, &RoutingTableTest::SetSequenceForMessage));
Darin Petkovabf6d282012-05-08 15:49:05 +0200754 EXPECT_TRUE(
755 routing_table_->RequestRouteToHost(destination_address,
756 kTestDeviceIndex0,
757 kTestRouteTag,
Darin Petkov13e6d552012-05-09 14:22:23 +0200758 target->unreached_callback()));
759 ASSERT_EQ(1, GetQueries()->size());
760 // Cancels the callback by destroying the owner object.
761 target.reset();
762 const int kMetric = 10;
763 RoutingTableEntry entry(IPAddress(IPAddress::kFamilyIPv4),
764 IPAddress(IPAddress::kFamilyIPv4),
765 IPAddress(IPAddress::kFamilyIPv4),
766 kMetric,
767 RT_SCOPE_UNIVERSE,
768 true);
769 SendRouteEntryWithSeqAndProto(RTNLMessage::kModeAdd,
770 kTestDeviceIndex0,
771 entry,
772 kTestRequestSeq,
773 RTPROT_UNSPEC);
Darin Petkovabf6d282012-05-08 15:49:05 +0200774}
775
Paul Stewart4a6748d2012-07-17 14:31:36 -0700776TEST_F(RoutingTableTest, CreateLinkRoute) {
777 IPAddress local_address(IPAddress::kFamilyIPv4);
778 ASSERT_TRUE(local_address.SetAddressFromString(kTestNetAddress0));
779 local_address.set_prefix(kTestRemotePrefix4);
780 IPAddress remote_address(IPAddress::kFamilyIPv4);
781 ASSERT_TRUE(remote_address.SetAddressFromString(kTestNetAddress1));
782 IPAddress default_address(IPAddress::kFamilyIPv4);
783 IPAddress remote_address_with_prefix(remote_address);
784 remote_address_with_prefix.set_prefix(
785 IPAddress::GetMaxPrefixLength(remote_address_with_prefix.family()));
786 RoutingTableEntry entry(remote_address_with_prefix,
787 local_address,
788 default_address,
789 0,
790 RT_SCOPE_LINK,
791 false);
792 EXPECT_CALL(rtnl_handler_,
793 SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
794 kTestDeviceIndex0,
795 entry,
796 NLM_F_CREATE | NLM_F_EXCL)))
797 .Times(1);
798 EXPECT_TRUE(routing_table_->CreateLinkRoute(kTestDeviceIndex0,
799 local_address,
800 remote_address));
801
802 ASSERT_TRUE(remote_address.SetAddressFromString(kTestRemoteAddress4));
803 EXPECT_FALSE(routing_table_->CreateLinkRoute(kTestDeviceIndex0,
804 local_address,
805 remote_address));
806}
807
Paul Stewart75e89d22011-08-01 10:00:02 -0700808} // namespace shill