| // 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 |