blob: c5dfddd3c55976939b8b29aa165e609a01777d22 [file] [log] [blame]
Chirantan Ekbotebccb4752018-10-31 13:53:08 -07001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/subnet.h"
Chirantan Ekbotebccb4752018-10-31 13:53:08 -07006
7#include <arpa/inet.h>
8#include <stdint.h>
9
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090010#include <string>
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080011#include <utility>
12#include <vector>
13
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070014#include <base/bind.h>
Qijiang Fane90b8792020-03-09 16:15:41 +090015#include <base/bind_helpers.h>
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090016#include <base/strings/string_util.h>
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070017#include <gtest/gtest.h>
18
Garrick Evans3388a032020-03-24 11:25:55 +090019#include "patchpanel/net_util.h"
Hugo Benichi2ac4d072019-05-28 14:51:23 +090020
Garrick Evans3388a032020-03-24 11:25:55 +090021namespace patchpanel {
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070022namespace {
23
Hugo Benichi6c63ae22019-05-29 11:19:15 +090024constexpr size_t kContainerBaseAddress = Ipv4Addr(100, 115, 92, 192);
25constexpr size_t kVmBaseAddress = Ipv4Addr(100, 115, 92, 24);
26constexpr size_t kPluginBaseAddress = Ipv4Addr(100, 115, 92, 128);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070027
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090028constexpr size_t kContainerSubnetPrefixLength = 28;
29constexpr size_t kVmSubnetPrefixLength = 30;
30constexpr size_t kPluginSubnetPrefixLength = 28;
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070031
Hugo Benichi6c63ae22019-05-29 11:19:15 +090032uint32_t AddOffset(uint32_t base_addr_no, uint32_t offset_ho) {
33 return htonl(ntohl(base_addr_no) + offset_ho);
34}
35
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090036// kExpectedAvailableCount[i] == AvailableCount() for subnet with prefix_length
37// i.
Chirantan Ekbote7e4aa422018-11-05 12:24:57 -080038constexpr size_t kExpectedAvailableCount[] = {
39 0xfffffffe, 0x7ffffffe, 0x3ffffffe, 0x1ffffffe, 0xffffffe, 0x7fffffe,
40 0x3fffffe, 0x1fffffe, 0xfffffe, 0x7ffffe, 0x3ffffe, 0x1ffffe,
41 0xffffe, 0x7fffe, 0x3fffe, 0x1fffe, 0xfffe, 0x7ffe,
42 0x3ffe, 0x1ffe, 0xffe, 0x7fe, 0x3fe, 0x1fe,
43 0xfe, 0x7e, 0x3e, 0x1e, 0xe, 0x6,
44 0x2, 0x0,
45};
46
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090047// kExpectedNetmask[i] == Netmask() for subnet with prefix_length i.
Chirantan Ekbote7e4aa422018-11-05 12:24:57 -080048constexpr uint32_t kExpectedNetmask[] = {
Hugo Benichi2ac4d072019-05-28 14:51:23 +090049 Ipv4Addr(0, 0, 0, 0), Ipv4Addr(128, 0, 0, 0),
50 Ipv4Addr(192, 0, 0, 0), Ipv4Addr(224, 0, 0, 0),
51 Ipv4Addr(240, 0, 0, 0), Ipv4Addr(248, 0, 0, 0),
52 Ipv4Addr(252, 0, 0, 0), Ipv4Addr(254, 0, 0, 0),
53 Ipv4Addr(255, 0, 0, 0), Ipv4Addr(255, 128, 0, 0),
54 Ipv4Addr(255, 192, 0, 0), Ipv4Addr(255, 224, 0, 0),
55 Ipv4Addr(255, 240, 0, 0), Ipv4Addr(255, 248, 0, 0),
56 Ipv4Addr(255, 252, 0, 0), Ipv4Addr(255, 254, 0, 0),
57 Ipv4Addr(255, 255, 0, 0), Ipv4Addr(255, 255, 128, 0),
58 Ipv4Addr(255, 255, 192, 0), Ipv4Addr(255, 255, 224, 0),
59 Ipv4Addr(255, 255, 240, 0), Ipv4Addr(255, 255, 248, 0),
60 Ipv4Addr(255, 255, 252, 0), Ipv4Addr(255, 255, 254, 0),
61 Ipv4Addr(255, 255, 255, 0), Ipv4Addr(255, 255, 255, 128),
62 Ipv4Addr(255, 255, 255, 192), Ipv4Addr(255, 255, 255, 224),
63 Ipv4Addr(255, 255, 255, 240), Ipv4Addr(255, 255, 255, 248),
64 Ipv4Addr(255, 255, 255, 252), Ipv4Addr(255, 255, 255, 254),
Chirantan Ekbote7e4aa422018-11-05 12:24:57 -080065};
66
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090067// kExpectedPrefix[i] == Prefix() for subnet with 4 * i offset to
68// |kVmBaseAddress|.
69constexpr uint32_t kExpectedPrefix[] = {
Hugo Benichi2ac4d072019-05-28 14:51:23 +090070 Ipv4Addr(100, 115, 92, 24), Ipv4Addr(100, 115, 92, 28),
71 Ipv4Addr(100, 115, 92, 32), Ipv4Addr(100, 115, 92, 36),
72 Ipv4Addr(100, 115, 92, 40), Ipv4Addr(100, 115, 92, 44),
73 Ipv4Addr(100, 115, 92, 48), Ipv4Addr(100, 115, 92, 52),
74 Ipv4Addr(100, 115, 92, 56), Ipv4Addr(100, 115, 92, 60),
75 Ipv4Addr(100, 115, 92, 64), Ipv4Addr(100, 115, 92, 68),
76 Ipv4Addr(100, 115, 92, 72), Ipv4Addr(100, 115, 92, 76),
77 Ipv4Addr(100, 115, 92, 80), Ipv4Addr(100, 115, 92, 84),
78 Ipv4Addr(100, 115, 92, 88), Ipv4Addr(100, 115, 92, 92),
79 Ipv4Addr(100, 115, 92, 96), Ipv4Addr(100, 115, 92, 100),
80 Ipv4Addr(100, 115, 92, 104), Ipv4Addr(100, 115, 92, 108),
81 Ipv4Addr(100, 115, 92, 112), Ipv4Addr(100, 115, 92, 116),
82 Ipv4Addr(100, 115, 92, 120), Ipv4Addr(100, 115, 92, 124),
83 Ipv4Addr(100, 115, 92, 128), Ipv4Addr(100, 115, 92, 132),
84 Ipv4Addr(100, 115, 92, 136), Ipv4Addr(100, 115, 92, 140),
85 Ipv4Addr(100, 115, 92, 144), Ipv4Addr(100, 115, 92, 148),
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090086};
87
88// kExpectedCidrString[i] == ToCidrString() for subnet with 4 * i offset to
89// |kVmBaseAddress|.
90const char* kExpectedCidrString[] = {
91 "100.115.92.24/30", "100.115.92.28/30", "100.115.92.32/30",
92 "100.115.92.36/30", "100.115.92.40/30", "100.115.92.44/30",
93 "100.115.92.48/30", "100.115.92.52/30", "100.115.92.56/30",
94 "100.115.92.60/30", "100.115.92.64/30", "100.115.92.68/30",
95 "100.115.92.72/30", "100.115.92.76/30", "100.115.92.80/30",
96 "100.115.92.84/30", "100.115.92.88/30", "100.115.92.92/30",
97 "100.115.92.96/30", "100.115.92.100/30", "100.115.92.104/30",
98 "100.115.92.108/30", "100.115.92.112/30", "100.115.92.116/30",
99 "100.115.92.120/30", "100.115.92.124/30", "100.115.92.128/30",
100 "100.115.92.132/30", "100.115.92.136/30", "100.115.92.140/30",
101 "100.115.92.144/30", "100.115.92.148/30",
102};
103
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700104class VmSubnetTest : public ::testing::TestWithParam<size_t> {};
105class ContainerSubnetTest : public ::testing::TestWithParam<size_t> {};
106class PrefixTest : public ::testing::TestWithParam<size_t> {};
107
108void DoNothing() {}
109
110void SetTrue(bool* value) {
111 *value = true;
112}
113
114} // namespace
115
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900116TEST_P(VmSubnetTest, Prefix) {
117 size_t index = GetParam();
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900118 Subnet subnet(AddOffset(kVmBaseAddress, index * 4), kVmSubnetPrefixLength,
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900119 base::Bind(&DoNothing));
120
121 EXPECT_EQ(kExpectedPrefix[index], subnet.Prefix());
122}
123
124TEST_P(VmSubnetTest, CidrString) {
125 size_t index = GetParam();
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900126 Subnet subnet(AddOffset(kVmBaseAddress, index * 4), kVmSubnetPrefixLength,
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900127 base::Bind(&DoNothing));
128
129 EXPECT_EQ(std::string(kExpectedCidrString[index]), subnet.ToCidrString());
130 EXPECT_EQ(kExpectedCidrString[index], subnet.ToCidrString());
131}
132
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700133TEST_P(VmSubnetTest, AddressAtOffset) {
134 size_t index = GetParam();
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900135 Subnet subnet(AddOffset(kVmBaseAddress, index * 4), kVmSubnetPrefixLength,
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700136 base::Bind(&DoNothing));
137
138 for (uint32_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900139 uint32_t address = AddOffset(kVmBaseAddress, index * 4 + offset + 1);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700140 EXPECT_EQ(address, subnet.AddressAtOffset(offset));
141 }
142}
143
Jim Pollock2667fca2020-06-11 07:17:59 +0100144INSTANTIATE_TEST_SUITE_P(AllValues,
145 VmSubnetTest,
146 ::testing::Range(size_t{0}, size_t{26}));
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700147
148TEST_P(ContainerSubnetTest, AddressAtOffset) {
149 size_t index = GetParam();
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900150 Subnet subnet(AddOffset(kContainerBaseAddress, index * 16),
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900151 kContainerSubnetPrefixLength, base::Bind(&DoNothing));
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700152
153 for (uint32_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900154 uint32_t address =
155 AddOffset(kContainerBaseAddress, index * 16 + offset + 1);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700156 EXPECT_EQ(address, subnet.AddressAtOffset(offset));
157 }
158}
159
Jim Pollock2667fca2020-06-11 07:17:59 +0100160INSTANTIATE_TEST_SUITE_P(AllValues,
161 ContainerSubnetTest,
162 ::testing::Range(size_t{1}, size_t{4}));
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700163
164TEST_P(PrefixTest, AvailableCount) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900165 size_t prefix_length = GetParam();
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700166
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900167 Subnet subnet(0, prefix_length, base::Bind(&DoNothing));
168 EXPECT_EQ(kExpectedAvailableCount[prefix_length], subnet.AvailableCount());
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700169}
170
171TEST_P(PrefixTest, Netmask) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900172 size_t prefix_length = GetParam();
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700173
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900174 Subnet subnet(0, prefix_length, base::Bind(&DoNothing));
Hugo Benichi2ac4d072019-05-28 14:51:23 +0900175 EXPECT_EQ(kExpectedNetmask[prefix_length], subnet.Netmask());
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700176}
177
Jim Pollock2667fca2020-06-11 07:17:59 +0100178INSTANTIATE_TEST_SUITE_P(AllValues,
179 PrefixTest,
180 ::testing::Range(size_t{8}, size_t{32}));
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700181
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900182TEST(SubtnetAddress, StringConversion) {
183 Subnet container_subnet(kContainerBaseAddress, kContainerSubnetPrefixLength,
184 base::Bind(&DoNothing));
185 EXPECT_EQ("100.115.92.192/28", container_subnet.ToCidrString());
186 {
187 EXPECT_EQ("100.115.92.193",
188 container_subnet.AllocateAtOffset(0)->ToIPv4String());
189 EXPECT_EQ("100.115.92.194",
190 container_subnet.AllocateAtOffset(1)->ToIPv4String());
191 EXPECT_EQ("100.115.92.205",
192 container_subnet.AllocateAtOffset(12)->ToIPv4String());
193 EXPECT_EQ("100.115.92.206",
194 container_subnet.AllocateAtOffset(13)->ToIPv4String());
195 }
196 {
197 EXPECT_EQ("100.115.92.193/28",
198 container_subnet.AllocateAtOffset(0)->ToCidrString());
199 EXPECT_EQ("100.115.92.194/28",
200 container_subnet.AllocateAtOffset(1)->ToCidrString());
201 EXPECT_EQ("100.115.92.205/28",
202 container_subnet.AllocateAtOffset(12)->ToCidrString());
203 EXPECT_EQ("100.115.92.206/28",
204 container_subnet.AllocateAtOffset(13)->ToCidrString());
205 }
206
207 Subnet vm_subnet(kVmBaseAddress, kVmSubnetPrefixLength,
208 base::Bind(&DoNothing));
209 EXPECT_EQ("100.115.92.24/30", vm_subnet.ToCidrString());
210 {
211 EXPECT_EQ("100.115.92.25", vm_subnet.AllocateAtOffset(0)->ToIPv4String());
212 EXPECT_EQ("100.115.92.26", vm_subnet.AllocateAtOffset(1)->ToIPv4String());
213 }
214 {
215 EXPECT_EQ("100.115.92.25/30",
216 vm_subnet.AllocateAtOffset(0)->ToCidrString());
217 EXPECT_EQ("100.115.92.26/30",
218 vm_subnet.AllocateAtOffset(1)->ToCidrString());
219 }
220
221 Subnet plugin_subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
222 base::Bind(&DoNothing));
223 EXPECT_EQ("100.115.92.128/28", plugin_subnet.ToCidrString());
224 {
225 EXPECT_EQ("100.115.92.129",
226 plugin_subnet.AllocateAtOffset(0)->ToIPv4String());
227 EXPECT_EQ("100.115.92.130",
228 plugin_subnet.AllocateAtOffset(1)->ToIPv4String());
229 EXPECT_EQ("100.115.92.141",
230 plugin_subnet.AllocateAtOffset(12)->ToIPv4String());
231 EXPECT_EQ("100.115.92.142",
232 plugin_subnet.AllocateAtOffset(13)->ToIPv4String());
233 }
234 {
235 EXPECT_EQ("100.115.92.129/28",
236 plugin_subnet.AllocateAtOffset(0)->ToCidrString());
237 EXPECT_EQ("100.115.92.130/28",
238 plugin_subnet.AllocateAtOffset(1)->ToCidrString());
239 EXPECT_EQ("100.115.92.141/28",
240 plugin_subnet.AllocateAtOffset(12)->ToCidrString());
241 EXPECT_EQ("100.115.92.142/28",
242 plugin_subnet.AllocateAtOffset(13)->ToCidrString());
243 }
244}
245
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700246// Tests that the Subnet runs the provided cleanup callback when it gets
247// destroyed.
248TEST(Subnet, Cleanup) {
249 bool called = false;
250
251 { Subnet subnet(0, 24, base::Bind(&SetTrue, &called)); }
252
253 EXPECT_TRUE(called);
254}
255
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800256// Tests that the subnet rejects attempts to allocate addresses outside its
257// range.
258TEST(PluginSubnet, OutOfBounds) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900259 Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
Qijiang Fane90b8792020-03-09 16:15:41 +0900260 base::DoNothing());
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800261
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900262 EXPECT_FALSE(subnet.Allocate(htonl(ntohl(kPluginBaseAddress) - 1)));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800263 EXPECT_FALSE(subnet.Allocate(kPluginBaseAddress));
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900264 EXPECT_FALSE(subnet.Allocate(AddOffset(
265 kPluginBaseAddress, (1ull << (32 - kPluginSubnetPrefixLength)) - 1)));
266 EXPECT_FALSE(subnet.Allocate(AddOffset(
267 kPluginBaseAddress, (1ull << (32 - kPluginSubnetPrefixLength)))));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800268}
269
270// Tests that the subnet rejects attempts to allocate the same address twice.
271TEST(PluginSubnet, DuplicateAddress) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900272 Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
Qijiang Fane90b8792020-03-09 16:15:41 +0900273 base::DoNothing());
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800274
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900275 auto addr = subnet.Allocate(AddOffset(kPluginBaseAddress, 1));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800276 EXPECT_TRUE(addr);
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900277 EXPECT_FALSE(subnet.Allocate(AddOffset(kPluginBaseAddress, 1)));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800278}
279
280// Tests that the subnet allows allocating all addresses in the subnet's range.
281TEST(PluginSubnet, Allocate) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900282 Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
Qijiang Fane90b8792020-03-09 16:15:41 +0900283 base::DoNothing());
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800284
285 std::vector<std::unique_ptr<SubnetAddress>> addrs;
286 addrs.reserve(subnet.AvailableCount());
287
288 for (size_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
289 // Offset by one since the network id is not allocatable.
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900290 auto addr = subnet.Allocate(AddOffset(kPluginBaseAddress, offset + 1));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800291 EXPECT_TRUE(addr);
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900292 EXPECT_EQ(AddOffset(kPluginBaseAddress, offset + 1), addr->Address());
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800293 addrs.emplace_back(std::move(addr));
294 }
295}
Garrick Evans0dbd4182019-03-07 08:38:38 +0900296// Tests that the subnet allows allocating all addresses in the subnet's range
297// using an offset.
298TEST(PluginSubnet, AllocateAtOffset) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900299 Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
Qijiang Fane90b8792020-03-09 16:15:41 +0900300 base::DoNothing());
Garrick Evans0dbd4182019-03-07 08:38:38 +0900301
302 std::vector<std::unique_ptr<SubnetAddress>> addrs;
303 addrs.reserve(subnet.AvailableCount());
304
305 for (size_t offset = 0; offset < subnet.AvailableCount(); ++offset) {
306 auto addr = subnet.AllocateAtOffset(offset);
307 EXPECT_TRUE(addr);
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900308 EXPECT_EQ(AddOffset(kPluginBaseAddress, offset + 1), addr->Address());
Garrick Evans0dbd4182019-03-07 08:38:38 +0900309 addrs.emplace_back(std::move(addr));
310 }
311}
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800312
313// Tests that the subnet frees addresses when they are destroyed.
314TEST(PluginSubnet, Free) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900315 Subnet subnet(kPluginBaseAddress, kPluginSubnetPrefixLength,
Qijiang Fane90b8792020-03-09 16:15:41 +0900316 base::DoNothing());
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800317
318 {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900319 auto addr = subnet.Allocate(AddOffset(kPluginBaseAddress, 1));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800320 EXPECT_TRUE(addr);
321 }
322
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900323 EXPECT_TRUE(subnet.Allocate(AddOffset(kPluginBaseAddress, 1)));
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800324}
325
Garrick Evans3388a032020-03-24 11:25:55 +0900326} // namespace patchpanel