Class: NetAddr::Tree
- Inherits:
-
Object
- Object
- NetAddr::Tree
- Defined in:
- lib/tree.rb
Overview
Tree
A class & series of methods for creating and manipulating IP-based heirarchical trees. Both IPv4 and IPv6 are supported.
A sample tree would look like: 192.168.1.0/24
192.168.1.0/26
192.168.1.0/27
192.168.1.0/28
192.168.1.16/29
192.168.1.16/30
192.168.1.24/30
192.168.1.25/32
192.168.1.28/30
192.168.1.32/27
192.168.1.64/26
192.168.1.64/27
192.168.1.128/26
192.168.1.192/26
Instance Method Summary collapse
-
#add!(new) ⇒ Object
Synopsis Add a CIDR address or NetAddr::CIDR object to the tree.
-
#ancestors(cidr) ⇒ Object
Synopsis Returns all the ancestors of the provided CIDR addresses.
-
#children(cidr) ⇒ Object
Synopsis Returns all the immediate children of the provided CIDR addresses.
-
#delete!(cidr) ⇒ Object
Synopsis Remove the provided CIDR address from the tree.
-
#descendants(cidr) ⇒ Object
Synopsis Return all descendants of the provided CIDR address.
-
#dump ⇒ Object
Synopsis Dump the contents of this tree.
-
#exists?(cidr) ⇒ Boolean
Synopsis Has a CIDR address already been added to the tree?.
-
#fill_in!(cidr) ⇒ Object
Synopsis Fill in the missing subnets of a particular CIDR.
-
#find(cidr) ⇒ Object
Synopsis Find and return a CIDR from within the tree.
-
#find_space(options) ⇒ Object
Synopsis Find subnets that are of at least size X.
-
#initialize ⇒ Tree
constructor
Synopsis Create a new Tree object.
-
#longest_match(cidr) ⇒ Object
Synopsis Find the longest matching branch of our tree to which a CIDR address belongs.
-
#prune!(cidr) ⇒ Object
Synopsis Remove all subnets of the provided CIDR address.
-
#remove!(cidr) ⇒ Object
Synopsis Remove the provided CIDR address, and all of its subnets from the tree.
-
#resize!(cidr, bits) ⇒ Object
Synopsis Resize the provided CIDR address.
-
#root(cidr) ⇒ Object
Synopsis Returns the root of the provided CIDR address.
-
#show ⇒ Object
Synopsis Print the tree as a formatted string.
-
#siblings(cidr) ⇒ Object
Synopsis Return list of the sibling CIDRs of the provided CIDR address.
-
#summarize_subnets!(cidr) ⇒ Object
(also: #merge_subnets!)
Synopsis Summarize all subnets of the provided CIDR address.
-
#supernets ⇒ Object
Synopsis Return list of the top-level supernets of this tree.
Constructor Details
#initialize ⇒ Tree
Synopsis
Create a new Tree object.
Example: NetAddr::Tree.new()
Arguments:
-
none
45 46 47 48 49 |
# File 'lib/tree.rb', line 45 def initialize() # root of our ordered IP tree @v4_root = NetAddr::CIDRv4.new(0,0,{:Subnets => []}) @v6_root = NetAddr::CIDRv6.new(0,0,{:Subnets => []}) end |
Instance Method Details
#add!(new) ⇒ Object
Synopsis
Add a CIDR address or NetAddr::CIDR object to the tree. Example: tree.add!(‘192.168.1.0/24’) cidr = NetAddr::CIDR.create(‘192.168.1.0/24’, :Tag => => ‘test net’ tree.add!(cidr)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
nil
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/tree.rb', line 68 def add!(new) # validate object if ( !new.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(new) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end else cidr = new.dup end cidr.tag[:Subnets] = [] add_to_tree(cidr) return(nil) end |
#ancestors(cidr) ⇒ Object
Synopsis
Returns all the ancestors of the provided CIDR addresses.
Example: tree.ancestors(‘192.168.1.0/27’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
Array of NetAddr::CIDR objects
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/tree.rb', line 103 def ancestors(cidr) # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end list = [] parent = find_parent(cidr) until (!parent.tag[:Parent]) list.push( NetAddr.cidr_build(parent.version, parent.to_i(:network), parent.to_i(:netmask)) ) parent = parent.tag[:Parent] end return(list) end |
#children(cidr) ⇒ Object
Synopsis
Returns all the immediate children of the provided CIDR addresses.
Example: tree.children(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
Array of NetAddr::CIDR objects
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/tree.rb', line 140 def children(cidr) # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end list = [] me = find_me(cidr) if (me) me.tag[:Subnets].each do |child| list.push( NetAddr.cidr_build(child.version, child.to_i(:network), child.to_i(:netmask)) ) end end return(list) end |
#delete!(cidr) ⇒ Object
Synopsis
Remove the provided CIDR address from the tree.
Example: tree.remove!(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
true on success or false on fail
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/tree.rb', line 218 def delete!(cidr) removed = false # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end # find matching me = find_me(cidr) # remove if (me) parent = me.tag[:Parent] children = me.tag[:Subnets] parent.tag[:Subnets].delete(me) children.each {|x| add_to_parent(x,parent)} removed = true end return(removed) end |
#descendants(cidr) ⇒ Object
Synopsis
Return all descendants of the provided CIDR address.
Example: tree.descendants(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
Array of NetAddr::CIDR objects
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/tree.rb', line 178 def descendants(cidr) list = [] # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me) dump_children(me).each do |x| child = x[:CIDR] list.push( NetAddr.cidr_build(child.version, child.to_i(:network), child.to_i(:netmask)) ) end end return(list) end |
#dump ⇒ Object
Synopsis
Dump the contents of this tree.
Example: tree.dump()
Arguments:
-
none
Returns:
-
ordered array of hashes with the following fields:
:CIDR => NetAddr::CIDR object :Depth => (depth level in tree)
264 265 266 267 268 269 |
# File 'lib/tree.rb', line 264 def dump() list = dump_children(@v4_root) list.concat( dump_children(@v6_root) ) list.each {|x| x[:CIDR] = NetAddr.cidr_build(x[:CIDR].version, x[:CIDR].to_i(:network), x[:CIDR].to_i(:netmask)) } return(list) end |
#exists?(cidr) ⇒ Boolean
Synopsis
Has a CIDR address already been added to the tree?
Example: tree.exists?(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
true or false
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/tree.rb', line 287 def exists?(cidr) found = false # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end found = true if (find_me(cidr)) return(found) end |
#fill_in!(cidr) ⇒ Object
Synopsis
Fill in the missing subnets of a particular CIDR.
Example: tree.fill_in!(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
true or false
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
# File 'lib/tree.rb', line 320 def fill_in!(cidr) filled = false # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me && me.tag[:Subnets].length != 0) me.tag[:Subnets] = NetAddr.cidr_fill_in(me, me.tag[:Subnets]) me.tag[:Subnets].each do |subnet| subnet.tag[:Subnets] = [] if (!subnet.tag.has_key?(:Subnets)) end filled = true end return(filled) end |
#find(cidr) ⇒ Object
Synopsis
Find and return a CIDR from within the tree.
Example: tree.find(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
NetAddr::CIDR object, or nil
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/tree.rb', line 360 def find(cidr) if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me) me = NetAddr.cidr_build(me.version, me.to_i(:network), me.to_i(:netmask)) end return(me) end |
#find_space(options) ⇒ Object
Synopsis
Find subnets that are of at least size X. Only subnets that are not themselves subnetted will be returned. :Subnet takes precedence over :IPCount
Example: tree.find_space(:IPCount => 16)
Arguments:
-
Minimum subnet size in bits, or a Hash with the following keys:
:Subnet - minimum subnet size in bits for returned subnets :IPCount - minimum IP count per subnet required for returned subnets :Version - restrict results to IPvX
Returns:
-
Array of NetAddr::CIDR objects
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/tree.rb', line 398 def find_space() known_args = [:Subnet, :IPCount, :Version] version = nil if (.kind_of? Integer) bits4 = bits6 = elsif (.kind_of? Hash) NetAddr.validate_args(.keys,known_args) if (.has_key?(:Version)) version = [:Version] raise "IP version should be 4 or 6, but was #{version}." if (version != 4 && version !=6) end if (.has_key?(:Subnet)) bits4 = [:Subnet] bits6 = [:Subnet] elsif(.has_key?(:IPCount)) bits4 = NetAddr.minimum_size([:IPCount], :Version => 4) bits6 = NetAddr.minimum_size([:IPCount], :Version => 6) else raise "Missing arguments: :Subnet/:IPCount" end else raise "Integer or Hash expected, but #{.class} provided." end list = [] if (!version || version == 4) dump_children(@v4_root).each do |entry| cidr = entry[:CIDR] if ( (cidr.tag[:Subnets].length == 0) && (cidr.bits <= bits4) ) list.push(cidr) end end end if (!version || version == 6) dump_children(@v6_root).each do |entry| cidr = entry[:CIDR] if ( (cidr.tag[:Subnets].length == 0) && (cidr.bits <= bits6) ) list.push(cidr) end end end new_list = [] list.each {|x| new_list.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )} return(new_list) end |
#longest_match(cidr) ⇒ Object
Synopsis
Find the longest matching branch of our tree to which a CIDR address belongs. Useful for performing ‘routing table’ style lookups.
Example: tree.longest_match(‘192.168.1.1’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
NetAddr::CIDR object
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/tree.rb', line 466 def longest_match(cidr) if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end found = find_me(cidr) found = find_parent(cidr) if !found return( NetAddr.cidr_build(found.version, found.to_i(:network), found.to_i(:netmask)) ) end |
#prune!(cidr) ⇒ Object
Synopsis
Remove all subnets of the provided CIDR address.
Example: tree.prune!(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
true on success or false on fail
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 |
# File 'lib/tree.rb', line 498 def prune!(cidr) pruned = false # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me) me.tag[:Subnets].clear pruned = true end return(pruned) end |
#remove!(cidr) ⇒ Object
Synopsis
Remove the provided CIDR address, and all of its subnets from the tree.
Example: tree.remove!(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
true on success or false on fail
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 |
# File 'lib/tree.rb', line 537 def remove!(cidr) removed = false found = nil # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me) parent = me.tag[:Parent] parent.tag[:Subnets].delete(me) removed = true end return(removed) end |
#resize!(cidr, bits) ⇒ Object
Synopsis
Resize the provided CIDR address.
Example: tree.resize!(‘192.168.1.0/24’, 23)
Arguments:
-
CIDR address as a String or an NetAddr::CIDR object
-
Integer representing the bits of the new netmask
Returns:
-
true on success or false on fail
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/tree.rb', line 579 def resize!(cidr,bits) resized = false # validate cidr if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me) new = me.resize(bits) delete!(me) add!(new) resized = true end return(resized) end |
#root(cidr) ⇒ Object
Synopsis
Returns the root of the provided CIDR address.
Example: tree.root(‘192.168.1.32/27’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
NetAddr::CIDR object
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
# File 'lib/tree.rb', line 620 def root(cidr) # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end parent = find_parent(cidr) if (parent.tag.has_key?(:Parent)) # if parent is not 0/0 while(1) grandparent = parent.tag[:Parent] break if (!grandparent.tag.has_key?(:Parent)) # if grandparent is 0/0 parent = grandparent end end return( NetAddr.cidr_build(parent.version, parent.to_i(:network), parent.to_i(:netmask)) ) end |
#show ⇒ Object
Synopsis
Print the tree as a formatted string.
Example: tree.show()
Arguments:
-
none
Returns:
-
String
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
# File 'lib/tree.rb', line 659 def show() printed = "IPv4 Tree\n---------\n" list4 = dump_children(@v4_root) list6 = dump_children(@v6_root) list4.each do |entry| cidr = entry[:CIDR] depth = entry[:Depth] if (depth == 0) indent = "" else indent = " " * (depth*3) end printed << "#{indent}#{cidr.desc}\n" end printed << "\n\nIPv6 Tree\n---------\n" if (list6.length != 0) list6.each do |entry| cidr = entry[:CIDR] depth = entry[:Depth] if (depth == 0) indent = "" else indent = " " * (depth*3) end printed << "#{indent}#{cidr.desc(:Short => true)}\n" end return(printed) end |
#siblings(cidr) ⇒ Object
Synopsis
Return list of the sibling CIDRs of the provided CIDR address.
Example: tree.siblings(‘192.168.1.0/27’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
Array of NetAddr::CIDR objects
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 |
# File 'lib/tree.rb', line 711 def siblings(cidr) # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end list = [] find_parent(cidr).tag[:Subnets].each do |entry| if (!cidr.cmp(entry)) list.push( NetAddr.cidr_build(entry.version, entry.to_i(:network), entry.to_i(:netmask)) ) end end return(list) end |
#summarize_subnets!(cidr) ⇒ Object Also known as: merge_subnets!
Synopsis
Summarize all subnets of the provided CIDR address. The subnets will be placed under the new summary address within the tree.
Example: tree.summarize_subnets!(‘192.168.1.0/24’)
Arguments:
-
String or NetAddr::CIDR object
Returns:
-
true on success or false on fail
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
# File 'lib/tree.rb', line 749 def summarize_subnets!(cidr) merged = false # validate object if ( !cidr.kind_of?(NetAddr::CIDR) ) begin cidr = NetAddr::CIDR.create(cidr) rescue Exception => error raise ArgumentError, "Provided argument raised the following " + "errors: #{error}" end end me = find_me(cidr) if (me) merged = NetAddr.cidr_summarize(me.tag[:Subnets]) me.tag[:Subnets] = merged merged = true end return(merged) end |
#supernets ⇒ Object
Synopsis
Return list of the top-level supernets of this tree.
Example: tree.supernets()
Arguments:
-
none
Returns:
-
Array of NetAddr::CIDR objects
790 791 792 793 794 795 |
# File 'lib/tree.rb', line 790 def supernets() supernets = [] @v4_root.tag[:Subnets].each {|x| supernets.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )} @v6_root.tag[:Subnets].each {|x| supernets.push( NetAddr.cidr_build(x.version, x.to_i(:network), x.to_i(:netmask)) )} return (supernets) end |