blob: acc93aad3e5d91e3457b44edae367cea83e8404f [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "routing-simulator/route.h"
#include <chromeos/net-base/ip_address.h>
#include <gtest/gtest.h>
namespace routing_simulator {
namespace {
constexpr net_base::IPCIDR kIPv4DefaultPrefix(net_base::IPFamily::kIPv4);
constexpr net_base::IPCIDR kIPv6DefaultPrefix(net_base::IPFamily::kIPv6);
TEST(RouteTest, CreateFromRouteStringIPv4Success) {
// Route with the "local" route type.
const auto route_1 = Route::CreateFromRouteString(
"local 100.115.92.133 dev arc_ns1 proto kernel scope host "
"src 100.115.92.133",
net_base::IPFamily::kIPv4);
ASSERT_TRUE(route_1.has_value());
EXPECT_EQ(route_1->type(), Route::Type::kLocal);
EXPECT_EQ(route_1.value().destination_prefix(),
net_base::IPCIDR::CreateFromCIDRString("100.115.92.133").value());
EXPECT_EQ(route_1->next_hop(), std::nullopt);
EXPECT_EQ(route_1->output_interface(), "arc_ns1");
EXPECT_EQ(route_1->table_id(), "main");
// Route with the next hop and default destination prefix.
const auto route_2 = Route::CreateFromRouteString(
"default via 100.87.84.254 dev eth0 table 1002 metric 65536",
net_base::IPFamily::kIPv4);
ASSERT_TRUE(route_2.has_value());
EXPECT_EQ(route_2->type(), Route::Type::kUnicast);
EXPECT_EQ(route_2->destination_prefix(), kIPv4DefaultPrefix);
EXPECT_EQ(route_2->next_hop(),
net_base::IPAddress::CreateFromString("100.87.84.254").value());
EXPECT_EQ(route_2->output_interface(), "eth0");
EXPECT_EQ(route_2->table_id(), "1002");
// Route with the a certain destination prefix.
const auto route_3 = Route::CreateFromRouteString(
"100.115.92.132/30 dev arc_ns1 proto kernel scope link src "
"100.115.92.133",
net_base::IPFamily::kIPv4);
ASSERT_TRUE(route_3.has_value());
EXPECT_EQ(route_3->type(), Route::Type::kUnicast);
EXPECT_EQ(
route_3->destination_prefix(),
net_base::IPCIDR::CreateFromCIDRString("100.115.92.132/30").value());
EXPECT_EQ(route_3->next_hop(), std::nullopt);
EXPECT_EQ(route_3->output_interface(), "arc_ns1");
EXPECT_EQ(route_3->table_id(), "main");
// Test the special case (e.g. no prefix length in route strings)
const auto route_with_no_prefix_length = Route::CreateFromRouteString(
"local 100.115.92.133 dev arc_ns1 table local proto kernel scope host "
"src 100.115.92.133",
net_base::IPFamily::kIPv4);
const auto prefix =
net_base::IPCIDR::CreateFromCIDRString("100.115.92.133/32").value();
EXPECT_EQ(route_with_no_prefix_length.value().destination_prefix(), prefix);
}
TEST(RouteTest, CreateFromRouteStringIPv6Success) {
// Route with the "unreachable" route type.
const auto route_1 = Route::CreateFromRouteString(
"unreachable default dev lo table 250 metric 1024 pref medium",
net_base::IPFamily::kIPv6);
ASSERT_TRUE(route_1.has_value());
EXPECT_EQ(route_1->type(), Route::Type::kUnreachable);
EXPECT_EQ(route_1->destination_prefix(), kIPv6DefaultPrefix);
EXPECT_EQ(route_1->next_hop(), std::nullopt);
EXPECT_EQ(route_1->output_interface(), "lo");
EXPECT_EQ(route_1->table_id(), "250");
// Route with the next hop.
const auto route_2 = Route::CreateFromRouteString(
"default via fe80::2a00:79e1:abc:f604 dev wlan0 table 1003 proto ra "
"metric 1024 expires 3534sec hoplimit 64 pref medium",
net_base::IPFamily::kIPv6);
ASSERT_TRUE(route_2.has_value());
EXPECT_EQ(route_2->type(), Route::Type::kUnicast);
EXPECT_EQ(route_2->destination_prefix(), kIPv6DefaultPrefix);
EXPECT_EQ(route_2->next_hop(),
net_base::IPAddress::CreateFromString("fe80::2a00:79e1:abc:f604")
.value());
EXPECT_EQ(route_2->output_interface(), "wlan0");
EXPECT_EQ(route_2->table_id(), "1003");
// Route with a certain destination prefix.
const auto route_3 = Route::CreateFromRouteString(
"fe80::/64 dev arc_ns0 proto kernel metric 256 pref medium"
"100.115.92.133",
net_base::IPFamily::kIPv6);
ASSERT_TRUE(route_3.has_value());
EXPECT_EQ(route_3->type(), Route::Type::kUnicast);
EXPECT_EQ(route_3->destination_prefix(),
net_base::IPCIDR::CreateFromCIDRString("fe80::/64").value());
EXPECT_EQ(route_3->next_hop(), std::nullopt);
EXPECT_EQ(route_3->output_interface(), "arc_ns0");
EXPECT_EQ(route_3->table_id(), "main");
// Test the special case (e.g. no prefix length in route strings).
const auto route_with_no_prefix_length = Route::CreateFromRouteString(
"local fe80:: dev arc_ns1 table local proto kernel scope host "
"src 100.115.92.133",
net_base::IPFamily::kIPv6);
const auto prefix =
net_base::IPCIDR::CreateFromCIDRString("fe80::/128").value();
EXPECT_EQ(route_with_no_prefix_length.value().destination_prefix(), prefix);
}
// TODO(b/307460180): Add more cases (e.g. cases when a Route member exists
// without the corresponding identifier or when some identifiers exist
// adjacently).
TEST(RouteTest, CreateFromRouteStringFail) {
// No valid value after an identifier.
EXPECT_EQ(Route::CreateFromRouteString("192.25.25.0/24 dev",
net_base::IPFamily::kIPv4),
std::nullopt);
EXPECT_EQ(Route::CreateFromRouteString("192.25.25.0/24 dev eth0 table",
net_base::IPFamily::kIPv4),
std::nullopt);
EXPECT_EQ(Route::CreateFromRouteString("192.25.25.0/24 dev eth0 via",
net_base::IPFamily::kIPv4),
std::nullopt);
// No destination prefix
EXPECT_EQ(Route::CreateFromRouteString("via 100.87.84.254 dev eth0",
net_base::IPFamily::kIPv4),
std::nullopt);
// Empty strings
EXPECT_EQ(Route::CreateFromRouteString("", net_base::IPFamily::kIPv4),
std::nullopt);
// Input strings only contain route type.
EXPECT_EQ(Route::CreateFromRouteString("local", net_base::IPFamily::kIPv4),
std::nullopt);
}
TEST(RouteTest, CreateFromRouteStringHandleSpaceSuccess) {
const auto prefix =
net_base::IPCIDR::CreateFromCIDRString("192.25.25.0/24").value();
std::string output_interface = "eth1";
for (const auto route_str :
{"192.25.25.0/24 dev eth1", "192.25.25.0/24 dev eth1 "}) {
const auto route =
Route::CreateFromRouteString(route_str, net_base::IPFamily::kIPv4);
ASSERT_TRUE(route.has_value());
EXPECT_EQ(route->destination_prefix(), prefix);
EXPECT_EQ(route->output_interface(), output_interface);
}
}
} // namespace
} // namespace routing_simulator