blob: cfb80ec27e1089537d12cde9a8ddfaf68ab5e2b3 [file] [log] [blame]
Chirantan Ekbote1977ea22017-12-08 18:57:03 -08001// Copyright 2017 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_pool.h"
Chirantan Ekbote1977ea22017-12-08 18:57:03 -08006
Hugo Benichi6c63ae22019-05-29 11:19:15 +09007#include <arpa/inet.h>
8
Garrick Evans0dbd4182019-03-07 08:38:38 +09009#include <memory>
Stephen Barber47981a72018-01-25 18:45:14 -080010#include <string>
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080011#include <utility>
12
13#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090014#include <base/check.h>
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080015#include <base/logging.h>
16#include <base/memory/ptr_util.h>
17#include <base/strings/stringprintf.h>
18
19using std::string;
20
Garrick Evans3388a032020-03-24 11:25:55 +090021namespace patchpanel {
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080022
Garrick Evans0dbd4182019-03-07 08:38:38 +090023// static
24std::unique_ptr<SubnetPool> SubnetPool::New(uint32_t base_addr,
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090025 uint32_t prefix_length,
Garrick Evans0dbd4182019-03-07 08:38:38 +090026 uint32_t num_subnets) {
27 if (num_subnets > kMaxSubnets) {
28 LOG(ERROR) << "Maximum subnets supported is " << kMaxSubnets << "; got "
29 << num_subnets;
30 return nullptr;
31 }
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090032 return base::WrapUnique(
33 new SubnetPool(base_addr, prefix_length, num_subnets));
Garrick Evans0dbd4182019-03-07 08:38:38 +090034}
35
36SubnetPool::SubnetPool(uint32_t base_addr,
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090037 uint32_t prefix_length,
Garrick Evans0dbd4182019-03-07 08:38:38 +090038 uint32_t num_subnets)
39 : base_addr_(base_addr),
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090040 prefix_length_(prefix_length),
Garrick Evans0dbd4182019-03-07 08:38:38 +090041 num_subnets_(num_subnets),
Garrick Evans53a2a982020-02-05 10:53:35 +090042 addr_per_index_(1ull << (kMaxSubnets - prefix_length)) {
43 subnets_.set(0); // unused.
44}
Garrick Evans0dbd4182019-03-07 08:38:38 +090045
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080046SubnetPool::~SubnetPool() {
Garrick Evans53a2a982020-02-05 10:53:35 +090047 subnets_.reset(0);
Garrick Evans0dbd4182019-03-07 08:38:38 +090048 if (subnets_.any()) {
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080049 LOG(ERROR) << "SubnetPool destroyed with unreleased subnets";
50 }
51}
52
Garrick Evans53a2a982020-02-05 10:53:35 +090053std::unique_ptr<Subnet> SubnetPool::Allocate(uint32_t index) {
54 if (index == 0) {
55 while (index <= num_subnets_ && subnets_.test(index)) {
Garrick Evans43b4e2d2019-12-11 13:43:08 +090056 ++index;
57 }
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080058 }
59
Garrick Evans53a2a982020-02-05 10:53:35 +090060 if (index > num_subnets_) {
61 LOG(ERROR) << "Desired index (" << index << ") execeeds number of"
62 << " available subnets (" << num_subnets_ << ")";
63 return nullptr;
64 }
65 if (subnets_.test(index)) {
66 LOG(WARNING) << "Subnet at index (" << index << ") is unavailable";
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080067 return nullptr;
68 }
69
Garrick Evans0dbd4182019-03-07 08:38:38 +090070 subnets_.set(index);
Garrick Evans53a2a982020-02-05 10:53:35 +090071 uint32_t subnet_addr =
72 htonl(ntohl(base_addr_) + (index - 1) * addr_per_index_);
Garrick Evans0dbd4182019-03-07 08:38:38 +090073 return std::make_unique<Subnet>(
Hugo Benichi6c63ae22019-05-29 11:19:15 +090074 subnet_addr, prefix_length_,
Garrick Evans0dbd4182019-03-07 08:38:38 +090075 base::Bind(&SubnetPool::Release, weak_ptr_factory_.GetWeakPtr(), index));
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080076}
77
Garrick Evans0dbd4182019-03-07 08:38:38 +090078void SubnetPool::Release(uint32_t index) {
Garrick Evans53a2a982020-02-05 10:53:35 +090079 if (index == 0) {
80 LOG(DFATAL) << "Invalid index value: 0";
81 return;
82 }
Garrick Evans0dbd4182019-03-07 08:38:38 +090083 DCHECK(subnets_.test(index));
84 subnets_.reset(index);
Chirantan Ekbote1977ea22017-12-08 18:57:03 -080085}
86
Garrick Evans3388a032020-03-24 11:25:55 +090087} // namespace patchpanel