diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb index 88098bc..cda1c1b 100644 --- a/lib/ipaddress/ipv6.rb +++ b/lib/ipaddress/ipv6.rb @@ -549,6 +549,38 @@ def network self.class.parse_u128(network_u128, @prefix) end + # + # This method implements the subnetting function + # similar to the one described in RFC3531. + # + # By specifying a new prefix, the method calculates + # the network number for the given IPv6 object + # and calculates the subnets associated to the new + # prefix. + # + # For example, given the following network: + # + # ip = IPAddress "2001:db8:8:800::/64" + # + # we can calculate the subnets with a /66 prefix + # + # ip.subnets(66).map{&:to_string) + # #=> ["2001:db8:8:800::/66", "2001:db8:8:800:4000::/66", "2001:db8:8:800:8000::/66", + # "2001:db8:8:800:c000::/66"] + # + # The resulting number of subnets will of course always be + # a power of two. + # + + def subnet(subprefix) + unless ((@prefix.to_i)..128).include? subprefix + raise ArgumentError, "New prefix must be between #@prefix and 128" + end + Array.new(2**(subprefix-@prefix.to_i)) do |i| + self.class.parse_u128(network_u128+(i*(2**(128-subprefix))), subprefix) + end + end + # # Extract 16 bits groups from a string # diff --git a/test/ipaddress/ipv6_test.rb b/test/ipaddress/ipv6_test.rb index dcfb601..b558593 100644 --- a/test/ipaddress/ipv6_test.rb +++ b/test/ipaddress/ipv6_test.rb @@ -141,6 +141,18 @@ def test_method_size ip = @klass.new("2001:db8::8:800:200c:417a/124") assert_equal 2**4, ip.size end +####Fill out proper ipv6 values... not sure how to do that math by hand yet. + def test_method_subnet + assert_raises(ArgumentError) {@network.subnet(62)} + assert_raises(ArgumentError) {@network.subnet(129)} + arr = ["2001:db8:8:800::/66", "2001:db8:8:800:4000::/66", "2001:db8:8:800:8000::/66", + "2001:db8:8:800:c000::/66"] + assert_equal arr, @network.subnet(66).map {|s| s.to_string} + arr = ["2001:db8:8:800::/65", "2001:db8:8:800:8000::/65"] + assert_equal arr, @network.subnet(65).map {|s| s.to_string} + arr = ["2001:db8:8:800::/64"] + assert_equal arr, @network.subnet(64).map {|s| s.to_string} + end def test_method_include? assert_equal true, @ip.include?(@ip)