Reserve IP Address Specification ================================ Signature ========= NetDB_IPaddress.reserve ( p_op_uid, -- user requesting address(es) p_start, -- starting address or prefix p_count=1, -- number of addresses p_exact=false, -- if TRUE, reservation(s) must start with starting address p_contiguous=false -- reserve continuous block of addresses (unsupported) ); Address Space Diagram ===================== |<----------------- Address Space -------------------------------->| | | |===---------------------------------==--------------------------==| ^ ^ | |^ | |^ ^ | | |<------- balance ------------->|| |<----- balance -------->|| | | | | | | | low reserve mid reserve high reserve | | | network (base) address broadcast address Starting Address / Exact Flag Validity for Ordinary and Privileged Users ======================================================================== address or muggles gods address range starting specific [0] starting specific ---------------- -------- -------- -------- -------- network ok no ok no broadcast no no no no low reserve [3] ok no ok -[1]-> ok mid reserve [2,3] ok no ok -[1]-> ok high reserve [3] no no ok -[1]-> ok balance ok ok ok ok ---------------- -------- -------- -------- -------- [0] starting == exact is FALSE; specific == exact is TRUE [1] When the starting address is in a reserved area, exact is automatically set to TRUE [2] 255, 0, 1 [3] when requesting multiple addresses, reserved addresses are only available when the starting address is a reserved address. ======================================================================== Summary ======= test for ownership access establish starting address based on: . input starting point - network, broadcast, low reserve, high reserve, mid reserve, balance . privileges establish limit search for N free addresses between starting address and limit Details ======= -- initialize a few useful variables start := IP.host(p_start); count := p_count; exact := p_exact; found := false; space := NetDB_IPaddressSpace.containing(start); network := NetDB_IPaddressSpace.get_parent_id (space); isgod := NetDB_Owner.check_access (p_op_uid, network, 'Network') and NetDB_Access.check_access (p_op_uid, 'Network'); -- see if midrange reserve zones are in force midres := NetDB_IPaddressSpace.using_MidRes(); skipres := midres; -- if true, skip midrange reserved addresses -- test for ownership access if not NetDB_Owner.check_access(p_op_uid, NetDB_IPaddessSpace.verify_or_die('',space), 'ipaddressspace') then error -- is the starting address the address space network address? if start = IP.host(space) then if exact then error; start = IP.plus(NetDB_IPaddressSpace.LowRes(space),1); -- is the starting address the address space broadcast address? elsif start = IP.host(IP.broadcast(space)) then error; -- is the starting address in the address space low reserve area? elsif start <= NetDB_IPaddressSpace.LowRes(space) then if isgod then exact := true; skipres := false; else if exact then error; start = IP.plus(NetDB_IPaddressSpace.LowRes(space),1); end if; -- is the starting address in the address space high reserve area? elsif start >= NetDB_IPaddressSpace.HighRes(space) then if not isgod then error; exact := true; skipres := false; -- is the starting address in the address space middle reserve area? elsif midres and NetDB_IPaddressSpace.is_MidRes(start) then if isgod then exact := true; skipres := false; else if exact then error; start := NetDB_IPaddressSpace.after_MidRes(start); end if; -- the starting address must be in the balance of the address space else null; end if; -- establish ending address if isgod and not skipres then limit = IP.broadcast(space); else limit = NetDB_IPaddressSpace.HighRes(space); end if; -- nuke stale reservations so they don't get in the way? delete from IPaddress where reserved is not null -- very important/necessary for speed! and Util.datediff('seconds',reserved) > GlobalDefault.LockTimeOut -- loop through the address space from start to limit looking for count free addresses start := IP.normalize(start); limit := IP.normalize(limit); time := [the current time]; while start < limit and count > 0 loop -- attempt to refresh existing reservation or insert new reserved address if ((update IPaddress set reserved=time where IPaddress=start and reserved_by=p_op_uid and reserved!=null) OR (insert into IPaddress (IPaddress, reserved_by, reserved) values (start, p_op_uid, time ))) then count--; found := true; elsif exact then error; elsif p_contiguous and found then error; end if; exact = false; start++; -- if necessary, adjust for midrange reserved zones if skipres and midres and NetDB_IPaddressSpace.is_MidRes(start) then start := NetDB_IPaddressSpace.after_MidRes(start); end loop; -- did it work? if count > 0 then delete any reserved addresses; error; end if -- return the set of addresses reserved and the reservation timestamp end; Midrange Reserved Zones ======================= Midrange reserved zones may or may not be a good idea. Certainly checking each address against the zone increases to the time it takes to reserve an address. To minimize that time, optimizations will be made. Here are the details: 0) General midrange reserved zones aren't really being implemented, we're just reserving .255, .0, and .1 IPv4 addresses. 1) The 'address' argument to NetDB_IPaddressSpace.is_MidRes(address) must be in familiar form. That means is_MidRes() does not have to pass it through IP.host() before checking it. 2) Ditto for NetDB_IPaddressSpace.after_MidRes(). Implementation details: -- using_MidRes() - return true if midrange reserved zones are in force -- alternate name: MidRes_on() -- is_MidRes() - return true if address is in a midrange reserved zone -- address must be in familiar form [optimization] NetDB_IPaddressSpace.is_MidRes(address) return to_boolean(regexp_instr(address,'\.(0|1|255)$')); -- after_MidRes - return the next address after the midrange reserved zone NetDB_IPaddressSpace.after_MidRes(address) while (is_MidRes (address)) address = IP.plus (address, 1); return address;