blob: c5dfddd3c55976939b8b29aa165e609a01777d22 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "patchpanel/subnet.h"
#include <arpa/inet.h>
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/bind_helpers.h>
#include <base/strings/string_util.h>
#include <gtest/gtest.h>
#include "patchpanel/net_util.h"
namespace patchpanel {
namespace {
constexpr size_t kContainerBaseAddress = Ipv4Addr(100, 115, 92, 192);
constexpr size_t kVmBaseAddress = Ipv4Addr(100, 115, 92, 24);
constexpr size_t kPluginBaseAddress = Ipv4Addr(100, 115, 92, 128);
constexpr size_t kContainerSubnetPrefixLength = 28;
constexpr size_t kVmSubnetPrefixLength = 30;
constexpr size_t kPluginSubnetPrefixLength = 28;
uint32_t AddOffset(uint32_t base_addr_no, uint32_t offset_ho) {
return htonl(ntohl(base_addr_no) + offset_ho);
}
// kExpectedAvailableCount[i] == AvailableCount() for subnet with prefix_length
// i.
constexpr size_t kExpectedAvailableCount[] = {
0xfffffffe, 0x7ffffffe, 0x3ffffffe, 0x1ffffffe, 0xffffffe, 0x7fffffe,
0x3fffffe, 0x1fffffe, 0xfffffe, 0x7ffffe, 0x3ffffe, 0x1ffffe,
0xffffe, 0x7fffe, 0x3fffe, 0x1fffe, 0xfffe, 0x7ffe,
0x3ffe, 0x1ffe, 0xffe, 0x7fe, 0x3fe, 0x1fe,
0xfe, 0x7e, 0x3e, 0x1e, 0xe, 0x6,
0x2, 0x0,
};
// kExpectedNetmask[i] == Netmask() for subnet with prefix_length i.
constexpr uint32_t kExpectedNetmask[] = {
Ipv4Addr(0, 0, 0, 0), Ipv4Addr(128, 0, 0, 0),
Ipv4Addr(192, 0, 0, 0), Ipv4Addr(224, 0, 0, 0),
Ipv4Addr(240, 0, 0, 0), Ipv4Addr(248, 0, 0, 0),
Ipv4Addr(252, 0, 0, 0), Ipv4Addr(254, 0, 0, 0),
Ipv4Addr(255, 0, 0, 0), Ipv4Addr(255, 128, 0, 0),
Ipv4Addr(255, 192, 0, 0), Ipv4Addr(255, 224, 0, 0),
Ipv4Addr(255, 240, 0, 0), Ipv4Addr(255, 248, 0, 0),
Ipv4Addr(255, 252, 0, 0), Ipv4Addr(255, 254, 0, 0),
Ipv4Addr(255, 255, 0, 0), Ipv4Addr(255, 255, 128, 0),
Ipv4Addr(255, 255, 192, 0), Ipv4Addr(255, 255, 224, 0),
Ipv4Addr(255, 255, 240, 0), Ipv4Addr(255, 255, 248, 0),
Ipv4Addr(255, 255, 252, 0), Ipv4Addr(255, 255, 254, 0),
Ipv4Addr(255, 255, 255, 0), Ipv4Addr(255, 255, 255, 128),
Ipv4Addr(255, 255, 255, 192), Ipv4Addr(255, 255, 255, 224),
Ipv4Addr(255, 255, 255, 240), Ipv4Addr(255, 255, 255, 248),
Ipv4Addr(255, 255, 255, 252), Ipv4Addr(255, 255, 255, 254),
};
// kExpectedPrefix[i] == Prefix() for subnet with 4 * i offset to
// |kVmBaseAddress|.
constexpr uint32_t kExpectedPrefix[] = {
Ipv4Addr(100, 115, 92, 24), Ipv4Addr(100, 115, 92, 28),
Ipv4Addr(100, 115, 92, 32), Ipv4Addr(100, 115, 92, 36),
Ipv4Addr(100, 115, 92, 40), Ipv4Addr(100, 115, 92, 44),
Ipv4Addr(100, 115, 92, 48), Ipv4Addr(100, 115, 92, 52),
Ipv4Addr(100, 115, 92, 56), Ipv4Addr(100, 115, 92, 60),
Ipv4Addr(100, 115, 92, 64), Ipv4Addr(100, 115, 92, 68),
Ipv4Addr(100, 115, 92, 72), Ipv4Addr(100, 115, 92, 76),
Ipv4Addr(100, 115, 92, 80), Ipv4Addr(100, 115, 92, 84),
Ipv4Addr(100, 115, 92, 88), Ipv4Addr(100, 115, 92, 92),
Ipv4Addr(100, 115, 92, 96), Ipv4Addr(100, 115, 92, 100),
Ipv4Addr(100, 115, 92, 104), Ipv4Addr(100, 115, 92, 108),
Ipv4Addr(100, 115, 92, 112), Ipv4Addr(100, 115, 92, 116),
Ipv4Addr(100, 115, 92, 120), Ipv4Addr(100, 115, 92, 124),
Ipv4Addr(100, 115, 92, 128), Ipv4Addr(100, 115, 92, 132),
Ipv4Addr(100, 115, 92, 136), Ipv4Addr(100, 115, 92, 140),
Ipv4Addr(100, 115, 92, 144), Ipv4Addr(100, 115, 92, 148),
};
// kExpectedCidrString[i] == ToCidrString() for subnet with 4 * i offset to
// |kVmBaseAddress|.
const char* kExpectedCidrString[] = {
"100.115.92.24/30", "100.115.92.28/30", "100.115.92.32/30",
"100.115.92.36/30", "100.115.92.40/30", "100.115.92.44/30",
"100.115.92.48/30", "100.115.92.52/30", "100.115.92.56/30",
"100.115.92.60/30", "100.115.92.64/30", "100.115.92.68/30",
"100.115.92.72/30", "100.115.92.76/30", "100.115.92.80/30",
"100.115.92.84/30", "100.115.92.88/30", "100.115.92.92/30",
"100.115.92.96/30", "100.115.92.100/30", "100.115.92.104/30",
"100.115.92.108/30", "100.115.92.112/30", "100.115.92.116/30",
"100.115.92.120/30", "100.115.92.124/30", "100.115.92.128/30",
"100.115.92.132/30", "100.115.92.136/30", "100.115.92.140/30",
"100.115.92.144/30", "100.115.92.148/30",
};
class VmSubnetTest : public ::testing::TestWithParam<size_t> {};
class ContainerSubnetTest : public ::testing::TestWithParam<size_t> {};
class PrefixTest : public ::testing::TestWithParam<size_t> {};
void DoNothing() {}
void SetTrue(bool* value) {
*value = true;
}
} // namespace
TEST_P(VmSubnetTest, Prefix) {
size_t index = GetParam();
Subnet subnet(AddOffset(kVmBaseAddress, index * 4), kVmSubnetPrefixLength,
base::Bind(&DoNothing));
EXPECT_EQ(kExpectedPrefix[index], subnet.Prefix());
}
TEST_P(VmSubnetTest, CidrString) {
size_t index = GetParam();
Subnet subnet(AddOffset(kVmBaseAddress, index * 4), kVmSubnetPrefixLength,
base::Bind(&DoNothing));
EXPECT_EQ(std::string(kExpectedCidrString[index]), subnet.ToCidrString());
EXPECT_EQ(kExpectedCidrString[index], subnet.ToCidrString());
}
TEST_P(VmSubnetTest, AddressAtOffset) {
size_t index = GetParam();
Subnet subnet(AddOffset(kVmBaseAddress, index * 4), kVmSubnetPrefixLength,
base::Bind(&DoNothing));
for (uint32_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
uint32_t address = AddOffset(kVmBaseAddress, index * 4 + offset + 1);
EXPECT_EQ(address, subnet.AddressAtOffset(offset));
}
}
INSTANTIATE_TEST_SUITE_P(AllValues,
VmSubnetTest,
::testing::Range(size_t{0}, size_t{26}));
TEST_P(ContainerSubnetTest, AddressAtOffset) {
size_t index = GetParam();
Subnet subnet(AddOffset(kContainerBaseAddress, index * 16),
kContainerSubnetPrefixLength, base::Bind(&DoNothing));
for (uint32_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
uint32_t address =
AddOffset(kContainerBaseAddress, index * 16 + offset + 1);
EXPECT_EQ(address, subnet.AddressAtOffset(offset));
}
}
INSTANTIATE_TEST_SUITE_P(AllValues,
ContainerSubnetTest,
::testing::Range(size_t{1}, size_t{4}));
TEST_P(PrefixTest, AvailableCount) {
size_t prefix_length = GetParam();
Subnet subnet(0, prefix_length, base::Bind(&DoNothing));
EXPECT_EQ(kExpectedAvailableCount[prefix_length], subnet.AvailableCount());
}
TEST_P(PrefixTest, Netmask) {
size_t prefix_length = GetParam();
Subnet subnet(0, prefix_length, base::Bind(&DoNothing));
EXPECT_EQ(kExpectedNetmask[prefix_length], subnet.Netmask());
}
INSTANTIATE_TEST_SUITE_P(AllValues,
PrefixTest,
::testing::Range(size_t{8}, size_t{32}));
TEST(SubtnetAddress, StringConversion) {
Subnet container_subnet(kContainerBaseAddress, kContainerSubnetPrefixLength,
base::Bind(&DoNothing));
EXPECT_EQ("100.115.92.192/28", container_subnet.ToCidrString());
{
EXPECT_EQ("100.115.92.193",
container_subnet.AllocateAtOffset(0)->ToIPv4String());
EXPECT_EQ("100.115.92.194",
container_subnet.AllocateAtOffset(1)->ToIPv4String());
EXPECT_EQ("100.115.92.205",
container_subnet.AllocateAtOffset(12)->ToIPv4String());
EXPECT_EQ("100.115.92.206",
container_subnet.AllocateAtOffset(13)->ToIPv4String());
}
{
EXPECT_EQ("100.115.92.193/28",
container_subnet.AllocateAtOffset(0)->ToCidrString());
EXPECT_EQ("100.115.92.194/28",
container_subnet.AllocateAtOffset(1)->ToCidrString());
EXPECT_EQ("100.115.92.205/28",
container_subnet.AllocateAtOffset(12)->ToCidrString());
EXPECT_EQ("100.115.92.206/28",
container_subnet.AllocateAtOffset(13)->ToCidrString());
}
Subnet vm_subnet(kVmBaseAddress, kVmSubnetPrefixLength,
base::Bind(&DoNothing));
EXPECT_EQ("100.115.92.24/30", vm_subnet.ToCidrString());
{
EXPECT_EQ("100.115.92.25", vm_subnet.AllocateAtOffset(0)->ToIPv4String());
EXPECT_EQ("100.115.92.26", vm_subnet.AllocateAtOffset(1)->ToIPv4String());
}
{
EXPECT_EQ("100.115.92.25/30",
vm_subnet.AllocateAtOffset(0)->ToCidrString());
EXPECT_EQ("100.115.92.26/30",
vm_subnet.AllocateAtOffset(1)->ToCidrString());
}
Subnet plugin_subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
base::Bind(&DoNothing));
EXPECT_EQ("100.115.92.128/28", plugin_subnet.ToCidrString());
{
EXPECT_EQ("100.115.92.129",
plugin_subnet.AllocateAtOffset(0)->ToIPv4String());
EXPECT_EQ("100.115.92.130",
plugin_subnet.AllocateAtOffset(1)->ToIPv4String());
EXPECT_EQ("100.115.92.141",
plugin_subnet.AllocateAtOffset(12)->ToIPv4String());
EXPECT_EQ("100.115.92.142",
plugin_subnet.AllocateAtOffset(13)->ToIPv4String());
}
{
EXPECT_EQ("100.115.92.129/28",
plugin_subnet.AllocateAtOffset(0)->ToCidrString());
EXPECT_EQ("100.115.92.130/28",
plugin_subnet.AllocateAtOffset(1)->ToCidrString());
EXPECT_EQ("100.115.92.141/28",
plugin_subnet.AllocateAtOffset(12)->ToCidrString());
EXPECT_EQ("100.115.92.142/28",
plugin_subnet.AllocateAtOffset(13)->ToCidrString());
}
}
// Tests that the Subnet runs the provided cleanup callback when it gets
// destroyed.
TEST(Subnet, Cleanup) {
bool called = false;
{ Subnet subnet(0, 24, base::Bind(&SetTrue, &called)); }
EXPECT_TRUE(called);
}
// Tests that the subnet rejects attempts to allocate addresses outside its
// range.
TEST(PluginSubnet, OutOfBounds) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
base::DoNothing());
EXPECT_FALSE(subnet.Allocate(htonl(ntohl(kPluginBaseAddress) - 1)));
EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress));
EXPECT_FALSE(subnet.Allocate(AddOffset(
kPluginBaseAddress, (1ull << (32 - kPluginSubnetPrefixLength)) - 1)));
EXPECT_FALSE(subnet.Allocate(AddOffset(
kPluginBaseAddress, (1ull << (32 - kPluginSubnetPrefixLength)))));
}
// Tests that the subnet rejects attempts to allocate the same address twice.
TEST(PluginSubnet, DuplicateAddress) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
base::DoNothing());
auto addr = subnet.Allocate(AddOffset(kPluginBaseAddress, 1));
EXPECT_TRUE(addr);
EXPECT_FALSE(subnet.Allocate(AddOffset(kPluginBaseAddress, 1)));
}
// Tests that the subnet allows allocating all addresses in the subnet's range.
TEST(PluginSubnet, Allocate) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
base::DoNothing());
std::vector<std::unique_ptr<SubnetAddress>> addrs;
addrs.reserve(subnet.AvailableCount());
for (size_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
// Offset by one since the network id is not allocatable.
auto addr = subnet.Allocate(AddOffset(kPluginBaseAddress, offset + 1));
EXPECT_TRUE(addr);
EXPECT_EQ(AddOffset(kPluginBaseAddress, offset + 1), addr->Address());
addrs.emplace_back(std::move(addr));
}
}
// Tests that the subnet allows allocating all addresses in the subnet's range
// using an offset.
TEST(PluginSubnet, AllocateAtOffset) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
base::DoNothing());
std::vector<std::unique_ptr<SubnetAddress>> addrs;
addrs.reserve(subnet.AvailableCount());
for (size_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
auto addr = subnet.AllocateAtOffset(offset);
EXPECT_TRUE(addr);
EXPECT_EQ(AddOffset(kPluginBaseAddress, offset + 1), addr->Address());
addrs.emplace_back(std::move(addr));
}
}
// Tests that the subnet frees addresses when they are destroyed.
TEST(PluginSubnet, Free) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
base::DoNothing());
{
auto addr = subnet.Allocate(AddOffset(kPluginBaseAddress, 1));
EXPECT_TRUE(addr);
}
EXPECT_TRUE(subnet.Allocate(AddOffset(kPluginBaseAddress, 1)));
}
} // namespace patchpanel