blob: 06daa5d5098ab08757fe9d7fcdfdf94b8d5d56c1 [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 "arc/network/subnet.h"
#include <arpa/inet.h>
#include <stdint.h>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <gtest/gtest.h>
namespace arc_networkd {
namespace {
constexpr size_t kContainerBaseAddress = 0x64735cc0; // 100.115.92.192
constexpr size_t kVmBaseAddress = 0x64735c18; // 100.115.92.24
constexpr size_t kPluginBaseAddress = 0x64735c80; // 100.115.92.128
constexpr size_t kContainerSubnetPrefix = 28;
constexpr size_t kVmSubnetPrefix = 30;
constexpr size_t kPluginSubnetPrefix = 28;
// kExpectedAvailableCount[i] == AvailableCount() for subnet with prefix 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 i.
constexpr uint32_t kExpectedNetmask[] = {
0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
0xfffffffc, 0xfffffffe,
};
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, AddressAtOffset) {
size_t index = GetParam();
Subnet subnet(kVmBaseAddress + index * 4, kVmSubnetPrefix,
base::Bind(&DoNothing));
for (uint32_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
uint32_t address = htonl(kVmBaseAddress + index * 4 + offset + 1);
EXPECT_EQ(address, subnet.AddressAtOffset(offset));
}
}
INSTANTIATE_TEST_CASE_P(AllValues,
VmSubnetTest,
::testing::Range(size_t{0}, size_t{26}));
TEST_P(ContainerSubnetTest, AddressAtOffset) {
size_t index = GetParam();
Subnet subnet(kContainerBaseAddress + index * 16, kContainerSubnetPrefix,
base::Bind(&DoNothing));
for (uint32_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
uint32_t address = htonl(kContainerBaseAddress + index * 16 + offset + 1);
EXPECT_EQ(address, subnet.AddressAtOffset(offset));
}
}
INSTANTIATE_TEST_CASE_P(AllValues,
ContainerSubnetTest,
::testing::Range(size_t{1}, size_t{4}));
TEST_P(PrefixTest, AvailableCount) {
size_t prefix = GetParam();
Subnet subnet(0, prefix, base::Bind(&DoNothing));
EXPECT_EQ(kExpectedAvailableCount[prefix], subnet.AvailableCount());
}
TEST_P(PrefixTest, Netmask) {
size_t prefix = GetParam();
Subnet subnet(0, prefix, base::Bind(&DoNothing));
EXPECT_EQ(htonl(kExpectedNetmask[prefix]), subnet.Netmask());
}
INSTANTIATE_TEST_CASE_P(AllValues,
PrefixTest,
::testing::Range(size_t{8}, size_t{32}));
// 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, kPluginSubnetPrefix,
base::Bind(&base::DoNothing));
EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress - 1));
EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress));
EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress +
(1ull << (32 - kPluginSubnetPrefix)) - 1));
EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress +
(1ull << (32 - kPluginSubnetPrefix))));
}
// Tests that the subnet rejects attempts to allocate the same address twice.
TEST(PluginSubnet, DuplicateAddress) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefix,
base::Bind(&base::DoNothing));
auto addr = subnet.Allocate(kPluginBaseAddress + 1);
EXPECT_TRUE(addr);
EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress + 1));
}
// Tests that the subnet allows allocating all addresses in the subnet's range.
TEST(PluginSubnet, Allocate) {
Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefix,
base::Bind(&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(kPluginBaseAddress + offset + 1);
EXPECT_TRUE(addr);
EXPECT_EQ(htonl(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, kPluginSubnetPrefix,
base::Bind(&base::DoNothing));
{
auto addr = subnet.Allocate(kPluginBaseAddress + 1);
EXPECT_TRUE(addr);
}
EXPECT_TRUE(subnet.Allocate(kPluginBaseAddress + 1));
}
} // namespace arc_networkd