Skip to content

Commit b1dcbed

Browse files
author
Johannes Erwerle
committed
Bugfixes in the claim_net algorithm
1 parent 29e5676 commit b1dcbed

File tree

3 files changed

+66
-14
lines changed

3 files changed

+66
-14
lines changed

minipam/server.py

+28-11
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def get_net(net, depth=-1):
7272
c = db_conn.cursor()
7373
c.execute("SELECT net, address, netmask FROM networks "
7474
"WHERE netmask >= ? AND address >= ? AND "
75-
"address <= ? ORDER BY netmask, address ASC",
75+
"address <= ? ORDER BY address ASC, netmask ASC",
7676
(network.prefixlen,
7777
network_address_to_int(network),
7878
network_broadcast_to_int(network)))
@@ -81,7 +81,7 @@ def get_net(net, depth=-1):
8181
# raise_fault("NetworkNotInDatabase")
8282

8383
if len(results) == 0 or results[0]["net"] != str(network):
84-
ret = { "address": network.network_address,
84+
ret = { "address": str(network.network_address),
8585
"cidr" : str(network),
8686
"netmask": network.prefixlen,
8787
"children": list(),
@@ -177,21 +177,32 @@ def claim_net(net, size):
177177
network = ip_network(net)
178178
required_gap = 2**(network.max_prefixlen - size)
179179

180-
if size > network.max_prefixlen - network.prefixlen:
180+
if size < network.prefixlen:
181181
raise_fault("NoMatchingGapAvailable")
182182

183183
nets = get_net(net, depth=1)
184184

185185
if len(nets["children"]) == 0:
186-
add_net(net)
187-
return get_net(net, depth=0)
186+
network_string = str(network.network_address) + "/" + str(size)
187+
add_net(network_string)
188+
return get_net(network_string, depth=0)
188189
else: #at least one child exists.
190+
191+
def next_start_address(net, size):
192+
if size >= net.prefixlen:
193+
start_addr = network_broadcast_to_int(net) + 1
194+
else:
195+
size_diff = net.prefixlen - size
196+
supernet = net.supernet(size_diff)
197+
start_addr = int(supernet.network_address) + 2**(supernet.max_prefixlen-supernet.prefixlen)
198+
return start_addr
199+
189200
smallest_gap = None
201+
190202
# start and end gaps
191203
first_block = ip_network(nets["children"][0]["cidr"])
192-
last_block = ip_network(nets["children"][-1]["cidr"])
193204
first_gap = network_address_to_int(first_block) - network_address_to_int(network)
194-
last_gap = network_broadcast_to_int(network) - network_broadcast_to_int(last_block) -1
205+
195206
if first_gap >= required_gap:
196207
smallest_gap = { "address" : network.network_address,
197208
"length" : first_gap }
@@ -200,12 +211,18 @@ def claim_net(net, size):
200211
for i, n in enumerate(nets["children"][:-1]):
201212
net1 = ip_network(n["cidr"])
202213
net2 = ip_network(nets["children"][i+1]["cidr"])
203-
gap = network_address_to_int(net2) - network_broadcast_to_int(net1) - 1
214+
start_addr = next_start_address(net1, size)
215+
gap = network_address_to_int(net2) - start_addr
204216
if gap >= required_gap and (smallest_gap is None or gap < smallest_gap["length"]):
205-
smallest_gap = {"address" : ip_address(network_broadcast_to_int(net1) + 1),
217+
smallest_gap = {"address" : ip_address(start_addr),
206218
"length": gap}
207-
if last_gap > required_gap and (smallest_gap is None or last_gap < smallest_gap["length"]):
208-
smallest_gap = { "address" : ip_address(network_broadcast_to_int(last_block) + 1),
219+
220+
# the last gap
221+
last_block = ip_network(nets["children"][-1]["cidr"])
222+
last_gap_start = next_start_address(last_block, size)
223+
last_gap = network_broadcast_to_int(network) - last_gap_start + 1
224+
if last_gap >= required_gap and (smallest_gap is None or last_gap < smallest_gap["length"]):
225+
smallest_gap = { "address" : ip_address(last_gap_start),
209226
"length" :last_gap}
210227

211228
if smallest_gap is None:

run.py

-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
if __name__ == "__main__":
44
start_database_connection()
5-
add_net("192.168.0.0/16")
6-
add_tag("192.168.0.0/16", "name", "lan network")
7-
add_tag("192.168.0.0/16", "name", "lan network2")
85
setup_xmlrpc_server()
96

107

test/net_methods.py

+38
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,15 @@ def tearDown(self):
159159
close_database_connection()
160160
remove("test.db")
161161

162+
#@unittest.skip("")
163+
def test_claim_normal_empty_subnet(self):
164+
claimed = claim_net("127.0.0.0/8", 16)
165+
result = get_net("127.0.0.0/8")
166+
self.assertEqual(claimed["cidr"], "127.0.0.0/16")
167+
self.assertEqual(len(result["children"]), 1)
168+
self.assertEqual(result["children"][0]["cidr"], "127.0.0.0/16")
169+
170+
#@unittest.skip("")
162171
def test_claim_normal(self):
163172
add_net("127.0.0.0/16")
164173
add_net("127.2.0.0/16")
@@ -170,6 +179,7 @@ def test_claim_normal(self):
170179
for i in range(3):
171180
self.assertEqual(result["children"][i]["address"], "127.%d.0.0" % i)
172181

182+
#@unittest.skip("")
173183
def test_claim_first_gap(self):
174184
add_net("127.1.0.0/16")
175185
add_net("127.2.0.0/16")
@@ -180,6 +190,7 @@ def test_claim_first_gap(self):
180190
for i in range(3):
181191
self.assertEqual(result["children"][i]["address"], "127.%d.0.0" % i)
182192

193+
#@unittest.skip("")
183194
def test_claim_last_gap(self):
184195
add_net("127.0.0.0/16")
185196
add_net("127.1.0.0/16")
@@ -190,6 +201,25 @@ def test_claim_last_gap(self):
190201
for i in range(3):
191202
self.assertEqual(result["children"][i]["address"], "127.%d.0.0" % i)
192203

204+
#@unittest.skip("")
205+
def test_claim_only_last_gap_remaining(self):
206+
add_net("127.0.0.0/16")
207+
add_net("127.0.0.0/18")
208+
add_net("127.0.64.0/18")
209+
add_net("127.0.128.0/18")
210+
claim_net("127.0.0.0/16", 18)
211+
result = get_net("127.0.0.0/16")
212+
self.assertEqual(result["cidr"] , "127.0.0.0/16")
213+
self.assertEqual(len(result["children"]), 4)
214+
for i in range(4):
215+
self.assertEqual(result["children"][i]["address"], "127.0.%s.0" % str(i*64))
216+
217+
def test_claim_last_gap_with_offset(self):
218+
add_net("1.0.0.0/8")
219+
add_net("1.2.3.0/24")
220+
result = claim_net("1.0.0.0/8", 9)
221+
self.assertEqual(result["cidr"], "1.128.0.0/9")
222+
193223
def test_claim_no_matching_gap(self):
194224
add_net("127.0.0.0/9")
195225
add_net("127.128.0.0/9")
@@ -201,3 +231,11 @@ def test_claim_host_bits_set(self):
201231
with self.assertRaises(Fault) as cm:
202232
claim_net("127.0.0.1/8", 16)
203233
self.assertEqual(cm.exception.faultString, "InvalidNetworkDescription")
234+
235+
def test_claim_no_matching_gap_at_start(self):
236+
add_net("1.0.0.0/8")
237+
add_net("1.2.3.0/24")
238+
add_net("1.128.0.0/9")
239+
with self.assertRaises(Fault) as cm:
240+
claim_net("1.0.0.0/8", 9)
241+
self.assertEqual(cm.exception.faultString, "NoMatchingGapAvailable")

0 commit comments

Comments
 (0)