Reputation: 458
Let's say I want to assign IPv6 addresses to people from the 2001:0DB8::/32 range. Most are given out sequentially, but some are non-sequential. This DB table shows which addresses have already been assigned.
+-----------------------------------------+
| Address |
+-----------------------------------------+
| 2001:0DB8:0000:0000:0000:0000:0000:0001 |
| 2001:0DB8:0000:0000:0000:0000:0000:0002 |
| 2001:0DB8:0000:0000:0000:0000:0000:0003 |
| 2001:0DB8:0000:0000:0000:0000:0000:0009 |
| 2001:0DB8:0000:0000:0000:0000:0F00:0001 |
| 2001:0DB8:0000:0000:0000:0000:0F00:0002 |
+-----------------------------------------+
Notice that it's sparsely filled - the first 3 are taken, then there are 5 available addresses until the next one is taken, then a gap of several million addresses before another one is taken.
What I want to do is assign users the next available address, starting from the beginning of the subnet. In this case it would be easy enough to start at the beginning, discover that there's no record for 2001:0DB8::4 yet, and use that one. But eventually the next available address may be thousands or millions of steps away from the start of the subnet. Walking through the database one address at a time would be a bad idea.
I thought of adding another field to the table so that each address indicates how many available addresses there are between itself and the next one in the list:
+-----------------------------------------+--------------------+
| Address | Steps to next addr |
+-----------------------------------------+--------------------+
| 2001:0DB8:0000:0000:0000:0000:0000:0001 | 1 |
| 2001:0DB8:0000:0000:0000:0000:0000:0002 | 1 |
| 2001:0DB8:0000:0000:0000:0000:0000:0003 | 6 |
| 2001:0DB8:0000:0000:0000:0000:0000:0009 | 15728632 |
| 2001:0DB8:0000:0000:0000:0000:0F00:0001 | 2 |
| 2001:0DB8:0000:0000:0000:0000:0F00:0003 | |
+-----------------------------------------+--------------------+
but I'm not sure that helps me. If an IP address is assigned somewhere in the middle of a sparse section, I'll still have to calculate how many steps there are from that address to the next one in sequence, and then go back to the closet assigned address before the new one and correct its "steps to next addr" as well. Still seems like a slow process.
Is there a better way to do this?
Upvotes: 1
Views: 497
Reputation: 6621
This is solvable by just slightly tweaking your approach here. I'm assuming that the reason why you would like to fill unused gaps here is because you have an existing sparsely populated database that you would like to make better use of.
Keep your original table, but separately store a next_address
field (say, in a Settings
table). When you first deploy your code, the next_address
will begin at 2001:db8::1
.
Your get_next_address()
function would then look something like this:
def initialise_settings():
if not Settings.exists('next_address'):
Settings.set('next_address', IPv6('2001:db8::1'))
def get_next_address():
next = Settings.get('next_address')
# Check for already filled rows -- breaks loop upon finding gap
while Database.row_exists({'Address': next}):
next += 1
Settings.set('next_address', next + 1)
return next
get_next_address() # 2001:db8::4
get_next_address() # 2001:db8::5
get_next_address() # 2001:db8::6
# ...
get_next_address() # 2001:db8::f00:0
get_next_address() # 2001:db8::f00:2
get_next_address() # 2001:db8::f00:4
get_next_address() # 2001:db8::f00:5
Upvotes: 1