VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.5 KB
Line 
1/* $Id: IPv4Pool.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * DHCP server - A pool of IPv4 addresses.
4 */
5
6/*
7 * Copyright (C) 2017-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "DhcpdInternal.h"
33#include <iprt/errcore.h>
34
35#include "IPv4Pool.h"
36
37
38int IPv4Pool::init(const IPv4Range &aRange) RT_NOEXCEPT
39{
40 AssertReturn(aRange.isValid(), VERR_INVALID_PARAMETER);
41
42 m_range = aRange;
43 try
44 {
45 m_pool.insert(m_range);
46 }
47 catch (std::bad_alloc &)
48 {
49 return VERR_NO_MEMORY;
50 }
51 return VINF_SUCCESS;
52}
53
54
55int IPv4Pool::init(RTNETADDRIPV4 aFirstAddr, RTNETADDRIPV4 aLastAddr) RT_NOEXCEPT
56{
57 return init(IPv4Range(aFirstAddr, aLastAddr));
58}
59
60
61/**
62 * Internal worker for inserting a range into the pool of available addresses.
63 *
64 * @returns IPRT status code (asserted).
65 * @param a_Range The range to insert.
66 */
67int IPv4Pool::i_insert(const IPv4Range &a_Range) RT_NOEXCEPT
68{
69 /*
70 * Check preconditions. Asserting because nobody checks the return code.
71 */
72 AssertReturn(m_range.isValid(), VERR_INVALID_STATE);
73 AssertReturn(a_Range.isValid(), VERR_INVALID_PARAMETER);
74 AssertReturn(m_range.contains(a_Range), VERR_INVALID_PARAMETER);
75
76 /*
77 * Check that the incoming range doesn't overlap with existing ranges in the pool.
78 */
79 it_t itHint = m_pool.upper_bound(IPv4Range(a_Range.LastAddr)); /* successor, insertion hint */
80#if 0 /** @todo r=bird: This code is wrong. It has no end() check for starters. Since the method is
81 * only for internal consumption, I've replaced it with a strict build assertion. */
82 if (itHint != m_pool.begin())
83 {
84 it_t prev(itHint);
85 --prev;
86 if (a_Range.FirstAddr <= prev->LastAddr)
87 {
88 LogRel(("%08x-%08x conflicts with %08x-%08x\n",
89 a_Range.FirstAddr, a_Range.LastAddr,
90 prev->FirstAddr, prev->LastAddr));
91 return VERR_INVALID_PARAMETER;
92 }
93 }
94#endif
95#ifdef VBOX_STRICT
96 for (it_t it2 = m_pool.begin(); it2 != m_pool.end(); ++it2)
97 AssertMsg(it2->LastAddr < a_Range.FirstAddr || it2->FirstAddr > a_Range.LastAddr,
98 ("%08RX32-%08RX32 conflicts with %08RX32-%08RX32\n",
99 a_Range.FirstAddr, a_Range.LastAddr, it2->FirstAddr, it2->LastAddr));
100#endif
101
102 /*
103 * No overlaps, insert it.
104 */
105 try
106 {
107 m_pool.insert(itHint, a_Range);
108 }
109 catch (std::bad_alloc &)
110 {
111 return VERR_NO_MEMORY;
112 }
113 return VINF_SUCCESS;
114}
115
116
117/**
118 * Allocates an available IPv4 address from the pool.
119 *
120 * @returns Non-zero network order IPv4 address on success, zero address
121 * (0.0.0.0) on failure.
122 */
123RTNETADDRIPV4 IPv4Pool::allocate()
124{
125 RTNETADDRIPV4 RetAddr;
126 if (!m_pool.empty())
127 {
128 /* Grab the first address in the pool: */
129 it_t itBeg = m_pool.begin();
130 RetAddr.u = RT_H2N_U32(itBeg->FirstAddr);
131
132 if (itBeg->FirstAddr == itBeg->LastAddr)
133 m_pool.erase(itBeg);
134 else
135 {
136 /* Trim the entry (re-inserting it): */
137 IPv4Range trimmed = *itBeg;
138 trimmed.FirstAddr += 1;
139 Assert(trimmed.FirstAddr <= trimmed.LastAddr);
140 m_pool.erase(itBeg);
141 try
142 {
143 m_pool.insert(trimmed);
144 }
145 catch (std::bad_alloc &)
146 {
147 /** @todo r=bird: Theortically the insert could fail with a bad_alloc and we'd
148 * drop a range of IP address. It would be nice if we could safely modify itBit
149 * without having to re-insert it. The author of this code (not bird) didn't
150 * seem to think this safe?
151 *
152 * If we want to play safe and all that, just use a AVLRU32TREE (or AVLRU64TREE
153 * if lazy) AVL tree from IPRT. Since we know exactly how it's implemented and
154 * works, there will be no uncertanties like this when using it (both here
155 * and in the i_insert validation logic). */
156 LogRelFunc(("Caught bad_alloc! We're truely buggered now!\n"));
157 }
158 }
159 }
160 else
161 RetAddr.u = 0;
162 return RetAddr;
163}
164
165
166/**
167 * Allocate the given address.
168 *
169 * @returns Success indicator.
170 * @param a_Addr The IP address to allocate (network order).
171 */
172bool IPv4Pool::allocate(RTNETADDRIPV4 a_Addr)
173{
174 /*
175 * Find the range containing a_Addr.
176 */
177 it_t it = m_pool.lower_bound(IPv4Range(a_Addr)); /* candidate range */
178 if (it != m_pool.end())
179 {
180 Assert(RT_N2H_U32(a_Addr.u) <= it->LastAddr); /* by definition of < and lower_bound */
181
182 if (it->contains(a_Addr))
183 {
184 /*
185 * Remove a_Addr from the range by way of re-insertion.
186 */
187 const IPV4HADDR haddr = RT_N2H_U32(a_Addr.u);
188 IPV4HADDR first = it->FirstAddr;
189 IPV4HADDR last = it->LastAddr;
190
191 m_pool.erase(it);
192 if (first != last)
193 {
194 if (haddr == first)
195 i_insert(++first, last);
196 else if (haddr == last)
197 i_insert(first, --last);
198 else
199 {
200 i_insert(first, haddr - 1);
201 i_insert(haddr + 1, last);
202 }
203 }
204
205 return true;
206 }
207 }
208 return false;
209}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette