| // Copyright 2017 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "patchpanel/subnet_pool.h" | |
| #include <arpa/inet.h> | |
| #include <memory> | |
| #include <string> | |
| #include <utility> | |
| #include <base/check.h> | |
| #include <base/functional/bind.h> | |
| #include <base/logging.h> | |
| #include <base/memory/ptr_util.h> | |
| #include <base/strings/stringprintf.h> | |
| #include "patchpanel/net_util.h" | |
| using std::string; | |
| namespace patchpanel { | |
| // static | |
| std::unique_ptr<SubnetPool> SubnetPool::New(const net_base::IPv4CIDR& base_cidr, | |
| uint32_t num_subnets) { | |
| if (base_cidr.GetPrefixCIDR() != base_cidr) { | |
| LOG(ERROR) << "base_cidr doesn't contain the base address: " << base_cidr; | |
| return nullptr; | |
| } | |
| if (num_subnets > kMaxSubnets) { | |
| LOG(ERROR) << "Maximum subnets supported is " << kMaxSubnets << "; got " | |
| << num_subnets; | |
| return nullptr; | |
| } | |
| return base::WrapUnique(new SubnetPool(base_cidr, num_subnets)); | |
| } | |
| SubnetPool::SubnetPool(const net_base::IPv4CIDR& base_cidr, | |
| uint32_t num_subnets) | |
| : base_cidr_(base_cidr), | |
| num_subnets_(num_subnets), | |
| addr_per_index_(1 << (net_base::IPv4CIDR::kMaxPrefixLength - | |
| base_cidr_.prefix_length())) { | |
| subnets_.set(0); // unused. | |
| } | |
| SubnetPool::~SubnetPool() { | |
| subnets_.reset(0); | |
| if (subnets_.any()) { | |
| LOG(ERROR) << "SubnetPool destroyed with unreleased subnets"; | |
| } | |
| } | |
| std::unique_ptr<Subnet> SubnetPool::Allocate(uint32_t index) { | |
| if (index == 0) { | |
| while (index <= num_subnets_ && subnets_.test(index)) { | |
| ++index; | |
| } | |
| } | |
| if (index > num_subnets_) { | |
| LOG(ERROR) << "Desired index (" << index << ") execeeds number of" | |
| << " available subnets (" << num_subnets_ << ")"; | |
| return nullptr; | |
| } | |
| if (subnets_.test(index)) { | |
| LOG(WARNING) << "Subnet at index (" << index << ") is unavailable"; | |
| return nullptr; | |
| } | |
| subnets_.set(index); | |
| const auto subnet_cidr = *net_base::IPv4CIDR::CreateFromAddressAndPrefix( | |
| AddOffset(base_cidr_.address(), (index - 1) * addr_per_index_), | |
| base_cidr_.prefix_length()); | |
| return std::make_unique<Subnet>( | |
| subnet_cidr, base::BindOnce(&SubnetPool::Release, | |
| weak_ptr_factory_.GetWeakPtr(), index)); | |
| } | |
| void SubnetPool::Release(uint32_t index) { | |
| if (index == 0) { | |
| LOG(DFATAL) << "Invalid index value: 0"; | |
| return; | |
| } | |
| DCHECK(subnets_.test(index)); | |
| subnets_.reset(index); | |
| } | |
| } // namespace patchpanel |