blob: f76561e9b44f52b390bd305d5b4555ba89bb3ad2 [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
Hugo Benichibd8ec4d2019-05-28 12:52:49 +09009#include <string>
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070010#include <utility>
11
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080012#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090013#include <base/check_op.h>
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070014#include <base/logging.h>
15
Garrick Evans3388a032020-03-24 11:25:55 +090016#include "patchpanel/net_util.h"
Hugo Benichi2ac4d072019-05-28 14:51:23 +090017
Hugo Benichi6c63ae22019-05-29 11:19:15 +090018namespace {
19// Returns the offset from the base address given in network-byte order for
20// the address given in network-byte order, or 0 if the second address is
21// lower than the base address. Returns the offset in host-byte order.
22uint32_t OffsetFromBaseAddress(uint32_t base_no, uint32_t addr_no) {
23 if (ntohl(addr_no) < ntohl(base_no))
24 return 0;
25 return ntohl(addr_no) - ntohl(base_no);
26}
27// Adds a positive offset given in host order to the address given in
28// network byte order. Returns the address in network-byte order.
29uint32_t AddOffset(uint32_t addr_no, uint32_t offset_ho) {
30 return htonl(ntohl(addr_no) + offset_ho);
31}
32} // namespace
33
Garrick Evans3388a032020-03-24 11:25:55 +090034namespace patchpanel {
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070035
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090036SubnetAddress::SubnetAddress(uint32_t addr,
37 uint32_t prefix_length,
Anand K Mistrye1aee762021-10-11 12:28:56 +110038 base::OnceClosure release_cb)
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090039 : addr_(addr),
40 prefix_length_(prefix_length),
41 release_cb_(std::move(release_cb)) {}
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080042
43SubnetAddress::~SubnetAddress() {
Anand K Mistrye1aee762021-10-11 12:28:56 +110044 std::move(release_cb_).Run();
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080045}
46
47uint32_t SubnetAddress::Address() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090048 return addr_;
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080049}
50
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090051std::string SubnetAddress::ToCidrString() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090052 return IPv4AddressToCidrString(addr_, prefix_length_);
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090053}
54
55std::string SubnetAddress::ToIPv4String() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090056 return IPv4AddressToString(addr_);
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090057}
58
Garrick Evansc7ae82c2019-09-04 16:25:10 +090059uint32_t SubnetAddress::Netmask() const {
Garrick Evans6f4fa3a2020-02-10 16:15:09 +090060 return Ipv4Netmask(prefix_length_);
Garrick Evansc7ae82c2019-09-04 16:25:10 +090061}
62
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090063Subnet::Subnet(uint32_t base_addr,
64 uint32_t prefix_length,
Anand K Mistrye1aee762021-10-11 12:28:56 +110065 base::OnceClosure release_cb)
Hugo Benichi6c63ae22019-05-29 11:19:15 +090066 : base_addr_(base_addr),
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090067 prefix_length_(prefix_length),
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080068 release_cb_(std::move(release_cb)),
69 weak_factory_(this) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090070 CHECK_LT(prefix_length, 32);
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080071
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090072 addrs_.resize(1ull << (32 - prefix_length), false);
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080073
Hugo Benichi6c63ae22019-05-29 11:19:15 +090074 // Mark the base address and broadcast address as allocated.
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080075 addrs_.front() = true;
76 addrs_.back() = true;
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070077}
78
79Subnet::~Subnet() {
Anand K Mistrye1aee762021-10-11 12:28:56 +110080 std::move(release_cb_).Run();
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070081}
82
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080083std::unique_ptr<SubnetAddress> Subnet::Allocate(uint32_t addr) {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090084 return AllocateAtOffset(OffsetFromBaseAddress(base_addr_, addr) - 1);
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080085}
86
Garrick Evans0dbd4182019-03-07 08:38:38 +090087std::unique_ptr<SubnetAddress> Subnet::AllocateAtOffset(uint32_t offset) {
88 uint32_t addr = AddressAtOffset(offset);
Hugo Benichi6c63ae22019-05-29 11:19:15 +090089 if (addr == INADDR_ANY) {
90 return nullptr;
91 }
92
93 if (addrs_[offset + 1]) {
94 // Address is already allocated.
95 return nullptr;
96 }
97
98 addrs_[offset + 1] = true;
99 return std::make_unique<SubnetAddress>(
100 addr, prefix_length_,
Anand K Mistrye1aee762021-10-11 12:28:56 +1100101 base::BindOnce(&Subnet::Free, weak_factory_.GetWeakPtr(), offset + 1));
Garrick Evans0dbd4182019-03-07 08:38:38 +0900102}
103
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700104uint32_t Subnet::AddressAtOffset(uint32_t offset) const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900105 if (offset < 0 || offset >= AvailableCount())
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700106 return INADDR_ANY;
107
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900108 // The first usable IP is after the base address.
109 return AddOffset(base_addr_, 1 + offset);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700110}
111
Garrick Evans0dbd4182019-03-07 08:38:38 +0900112uint32_t Subnet::AvailableCount() const {
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700113 // The available IP count is all IPs in a subnet, minus the network ID
114 // and the broadcast address.
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800115 return addrs_.size() - 2;
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700116}
117
Garrick Evans47c19272019-11-21 10:58:21 +0900118uint32_t Subnet::BaseAddress() const {
119 return base_addr_;
120}
121
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700122uint32_t Subnet::Netmask() const {
Garrick Evans6f4fa3a2020-02-10 16:15:09 +0900123 return Ipv4Netmask(prefix_length_);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700124}
125
Garrick Evans0dbd4182019-03-07 08:38:38 +0900126uint32_t Subnet::Prefix() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900127 return base_addr_ & Netmask();
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900128}
129
130uint32_t Subnet::PrefixLength() const {
131 return prefix_length_;
132}
133
134std::string Subnet::ToCidrString() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900135 return IPv4AddressToCidrString(base_addr_, prefix_length_);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700136}
137
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800138void Subnet::Free(uint32_t offset) {
139 DCHECK_NE(offset, 0);
140 DCHECK_LT(offset, addrs_.size() - 1);
141
142 addrs_[offset] = false;
143}
144
Garrick Evans3388a032020-03-24 11:25:55 +0900145} // namespace patchpanel