-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement NetAddr::CIDR#allocate_rfc3531 #14
Comments
Hello, thanks for your compliments. I didn't fully understand your example here, would you please go deeper into it? I feel it's an interesting function to add to the library. Best would be to also have some tests to import directly in the code, so I will be sure to meet what you're expecting. Best regards, |
Hi Marco, Basically the above RFC is designed to allow you to slice up your supernets (/21, /20, /19 etc) effectively within an ISP. A few examples of how it works are..; ruby-1.9.2-p180 :001 > require 'netaddr'
=> true
ruby-1.9.2-p180 :002 > cidr = NetAddr::CIDR.create('192.168.0.0/24')
=> 192.168.0.0/24
ruby-1.9.2-p180 :003 > cidr.allocate_rfc3531(25).sort
=> ["192.168.0.0/25", "192.168.0.128/25"]
ruby-1.9.2-p180 :004 > cidr.allocate_rfc3531(26).sort
=> ["192.168.0.0/26", "192.168.0.128/26", "192.168.0.192/26", "192.168.0.64/26"]
ruby-1.9.2-p180 :005 > cidr.allocate_rfc3531(27).sort
=> ["192.168.0.0/27", "192.168.0.128/27", "192.168.0.160/27", "192.168.0.192/27", "192.168.0.224/27", "192.168.0.32/27", "192.168.0.64/27", "192.168.0.96/27"]
ruby-1.9.2-p180 :006 > ruby-1.9.2-p180 :006 > cidr.allocate_rfc3531(28).count
=> 16
ruby-1.9.2-p180 :007 > cidr.allocate_rfc3531(29).count
=> 32
ruby-1.9.2-p180 :008 > |
NetAddr::CIDR#cmp would also be a great feature to implement: http://netaddr.rubyforge.org/classes/NetAddr/CIDR.html#M000062 These are the features we use the most in NetAddr |
Hello Rob, I think you may have a look at IPv4#subnet, as it does quite the same with a different interface. You need to specify the number of subnets rather than the new prefix, but the result is the same: IPAddress("192.168.0.0/24").subnet(4).map {|i| i.to_string}
=> ["192.168.0.0/26", "192.168.0.64/26", "192.168.0.128/26", "192.168.0.192/26"] If you want, you can still specify the new subnet with a workaround irb(main):003:0> a = IPAddress("192.168.0.0/24")
=> #<IPAddress::IPv4:0xb768362c @address="192.168.0.0", @octets=[192, 168, 0, 0], @prefix=24, @u32=3232235520>
irb(main):004:0> a.subnet(2**(26-a.prefix.to_i)).map {|i| i.to_string}
=> ["192.168.0.0/26", "192.168.0.64/26", "192.168.0.128/26", "192.168.0.192/26"] I will maybe include a new method in the next release to be able to specify the new prefix without the workaround. |
Hi Marco, The reason we need to do it the way NetADDR does it, is because we only know what size subnet someone wants (i.e. /29). We therefore take each of our supernets, make as many /29s out of them and loop through the individual subnets until we find one that's free, and then allocate that to the customer. None of the work arounds really do the above functionality. |
Hi Rob, When you say "we", you mean the library (NetADDR) or your application using the library? And again, when you say "until we find one that's free", what does that mean? Thanks for helping me understand better, I'm always interested in adding some nice functionality to IPAddress :) Maybe, if you want, you can provide me with some unit tests that I can integrate in the library. It would me much clearer in this way. Best regards, |
Hi Marco, Sorry, I'll clarify. We have an application which is responsible for allocating subnets to customers. To do this, we assign supernets (/19, /20 etc) to the application. An administrator then selects a customers VLAN, and selects 'Allocate subnet' and requests a paticular size of subnet, i.e. a /29. The code we use for this is as follows.. ## Create a new subnet allocation of the desired size
def allocate_subnet(size)
return false unless size.is_a?(Integer)
Supernet.all.each do |supernet|
allocated_subnets = supernet.subnets.all.map(&:cidr_object) ## Returns an array of NetADDR::CIDR object for each allocated subnet
NetAddr::CIDR.create(supernet.to_s).allocate_rfc3531(size, :Objectify => true).sort.each do |potential_subnet|
free_subnet = true
allocated_subnets.each do |allocated_subnet|
free_subnet = false unless potential_subnet.cmp(allocated_subnet).nil?
end
if free_subnet
return self.subnets.create!(:network => potential_subnet.network, :cidr => size, :supernet => supernet)
end
end
end
return nil
end This basically loops through each Supernet, making as many /29s or whatever subnet size was requested out of it. It then loops through each created subnet and checks whether the network IP address has been used in another subnet. If not, then we deem that subnet to be free and allocate it to the customer. I'm intending to write tests for our application this afternoon, so should be able to provide tests which show the functionality we're after. |
Hello Rob, It seems to me that NetAddr::CIDR#allocate_rfc3531 and IPAddress::IPv4#subnet do exactly the same thing. If you want the same interface, you can do module IPAddress
class IPv4
def allocate_rfc3531(new_prefix)
subnet(2**(new_prefix-prefix.to_i))
end
end
end Then you can call it like you used to do > a = IPAddress("192.168.0.0/24")
=> 192.168.0.0
> a.allocate_rfc3531(26)
=> [192.168.0.0, 192.168.0.64, 192.168.0.128, 192.168.0.192] |
Yep, it's pretty much just a different API, without needing to know how many subnets you want, which is ideal for us. Is this something you'd look to add into your library, or should we just extend it? We'd also like something the same as NetAddr::CIDR#cmp if at all possible, as we use that widely too. |
Hi,
We're currently using the NetAddr gem to provide our software with supernet, subnet and IP Address management. An example of this as follows:
We use the allocate_rfc351 function in NetADDR::CIDR to do this currently, but would like to use your library as it has a lot nicer API. Would you be able to duplicate the functionality in your better API?
Thanks
The text was updated successfully, but these errors were encountered: