blob: 8fa6f4b3f71bcff65e49d8f44f495f846e3fe7fe [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>
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070013#include <base/logging.h>
14
Garrick Evans3388a032020-03-24 11:25:55 +090015#include "patchpanel/net_util.h"
Hugo Benichi2ac4d072019-05-28 14:51:23 +090016
Hugo Benichi6c63ae22019-05-29 11:19:15 +090017namespace {
18// Returns the offset from the base address given in network-byte order for
19// the address given in network-byte order, or 0 if the second address is
20// lower than the base address. Returns the offset in host-byte order.
21uint32_t OffsetFromBaseAddress(uint32_t base_no, uint32_t addr_no) {
22 if (ntohl(addr_no) < ntohl(base_no))
23 return 0;
24 return ntohl(addr_no) - ntohl(base_no);
25}
26// Adds a positive offset given in host order to the address given in
27// network byte order. Returns the address in network-byte order.
28uint32_t AddOffset(uint32_t addr_no, uint32_t offset_ho) {
29 return htonl(ntohl(addr_no) + offset_ho);
30}
31} // namespace
32
Garrick Evans3388a032020-03-24 11:25:55 +090033namespace patchpanel {
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070034
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090035SubnetAddress::SubnetAddress(uint32_t addr,
36 uint32_t prefix_length,
37 base::Closure release_cb)
38 : addr_(addr),
39 prefix_length_(prefix_length),
40 release_cb_(std::move(release_cb)) {}
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080041
42SubnetAddress::~SubnetAddress() {
43 release_cb_.Run();
44}
45
46uint32_t SubnetAddress::Address() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090047 return addr_;
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080048}
49
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090050std::string SubnetAddress::ToCidrString() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090051 return IPv4AddressToCidrString(addr_, prefix_length_);
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090052}
53
54std::string SubnetAddress::ToIPv4String() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090055 return IPv4AddressToString(addr_);
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090056}
57
Garrick Evansc7ae82c2019-09-04 16:25:10 +090058uint32_t SubnetAddress::Netmask() const {
Garrick Evans6f4fa3a2020-02-10 16:15:09 +090059 return Ipv4Netmask(prefix_length_);
Garrick Evansc7ae82c2019-09-04 16:25:10 +090060}
61
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090062Subnet::Subnet(uint32_t base_addr,
63 uint32_t prefix_length,
64 base::Closure release_cb)
Hugo Benichi6c63ae22019-05-29 11:19:15 +090065 : base_addr_(base_addr),
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090066 prefix_length_(prefix_length),
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080067 release_cb_(std::move(release_cb)),
68 weak_factory_(this) {
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090069 CHECK_LT(prefix_length, 32);
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080070
Hugo Benichibd8ec4d2019-05-28 12:52:49 +090071 addrs_.resize(1ull << (32 - prefix_length), false);
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080072
Hugo Benichi6c63ae22019-05-29 11:19:15 +090073 // Mark the base address and broadcast address as allocated.
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080074 addrs_.front() = true;
75 addrs_.back() = true;
Chirantan Ekbotebccb4752018-10-31 13:53:08 -070076}
77
78Subnet::~Subnet() {
79 release_cb_.Run();
80}
81
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080082std::unique_ptr<SubnetAddress> Subnet::Allocate(uint32_t addr) {
Hugo Benichi6c63ae22019-05-29 11:19:15 +090083 return AllocateAtOffset(OffsetFromBaseAddress(base_addr_, addr) - 1);
Chirantan Ekbote817b0c22018-11-14 16:55:10 -080084}
85
Garrick Evans0dbd4182019-03-07 08:38:38 +090086std::unique_ptr<SubnetAddress> Subnet::AllocateAtOffset(uint32_t offset) {
87 uint32_t addr = AddressAtOffset(offset);
Hugo Benichi6c63ae22019-05-29 11:19:15 +090088 if (addr == INADDR_ANY) {
89 return nullptr;
90 }
91
92 if (addrs_[offset + 1]) {
93 // Address is already allocated.
94 return nullptr;
95 }
96
97 addrs_[offset + 1] = true;
98 return std::make_unique<SubnetAddress>(
99 addr, prefix_length_,
100 base::Bind(&Subnet::Free, weak_factory_.GetWeakPtr(), offset + 1));
Garrick Evans0dbd4182019-03-07 08:38:38 +0900101}
102
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700103uint32_t Subnet::AddressAtOffset(uint32_t offset) const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900104 if (offset < 0 || offset >= AvailableCount())
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700105 return INADDR_ANY;
106
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900107 // The first usable IP is after the base address.
108 return AddOffset(base_addr_, 1 + offset);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700109}
110
Garrick Evans0dbd4182019-03-07 08:38:38 +0900111uint32_t Subnet::AvailableCount() const {
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700112 // The available IP count is all IPs in a subnet, minus the network ID
113 // and the broadcast address.
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800114 return addrs_.size() - 2;
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700115}
116
Garrick Evans47c19272019-11-21 10:58:21 +0900117uint32_t Subnet::BaseAddress() const {
118 return base_addr_;
119}
120
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700121uint32_t Subnet::Netmask() const {
Garrick Evans6f4fa3a2020-02-10 16:15:09 +0900122 return Ipv4Netmask(prefix_length_);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700123}
124
Garrick Evans0dbd4182019-03-07 08:38:38 +0900125uint32_t Subnet::Prefix() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900126 return base_addr_ & Netmask();
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900127}
128
129uint32_t Subnet::PrefixLength() const {
130 return prefix_length_;
131}
132
133std::string Subnet::ToCidrString() const {
Hugo Benichi6c63ae22019-05-29 11:19:15 +0900134 return IPv4AddressToCidrString(base_addr_, prefix_length_);
Chirantan Ekbotebccb4752018-10-31 13:53:08 -0700135}
136
Chirantan Ekbote817b0c22018-11-14 16:55:10 -0800137void Subnet::Free(uint32_t offset) {
138 DCHECK_NE(offset, 0);
139 DCHECK_LT(offset, addrs_.size() - 1);
140
141 addrs_[offset] = false;
142}
143
Garrick Evans3388a032020-03-24 11:25:55 +0900144} // namespace patchpanel