1package Netdot::Model::Interface; 2 3use base 'Netdot::Model'; 4use warnings; 5use strict; 6 7my $MAC = Netdot->get_mac_regex(); 8my $logger = Netdot->log->get_logger('Netdot::Model::Device'); 9 10my %SPEED_MAP = ('1536000' => 'T1', 11 '1544000' => 'T1', 12 '3072000' => 'Dual T1', 13 '3088000' => 'Dual T1', 14 '44210000' => 'T3', 15 '44736000' => 'T3', 16 '45045000' => 'DS3', 17 '46359642' => 'DS3', 18 '149760000' => 'ATM on OC-3', 19 '155000000' => 'OC-3', 20 '155519000' => 'OC-3', 21 '155520000' => 'OC-3', 22 '599040000' => 'ATM on OC-12', 23 '622000000' => 'OC-12', 24 '622080000' => 'OC-12', 25 ); 26 27#Be sure to return 1 281; 29 30=head1 NAME 31 32Netdot::Model::Interface 33 34=head1 CLASS METHODS 35=cut 36 37################################################################ 38 39=head2 insert - Insert Interface object 40 41 We override the insert method for extra functionality 42 43 Arguments: 44 Hash ref with Interface fields 45 Returns: 46 New Interface object 47 Examples: 48 49=cut 50 51sub insert { 52 my ($class, $argv) = @_; 53 $class->isa_class_method('insert'); 54 55 # Set some defaults 56 $argv->{speed} ||= 0; 57 $argv->{doc_status} ||= 'manual'; 58 59 $argv->{snmp_managed} = $class->config->get('IF_SNMP') 60 unless defined $argv->{snmp_managed}; 61 62 $argv->{overwrite_descr} = $class->config->get('IF_OVERWRITE_DESCR') 63 unless defined $argv->{overwrite_descr}; 64 65 $argv->{monitored} = 0 unless defined $argv->{monitored}; 66 67 $argv->{auto_dns} = $class->config->get('UPDATE_DEVICE_IP_NAMES') 68 unless defined $argv->{auto_dns}; 69 70 my $unknown_status = (MonitorStatus->search(name=>"Unknown"))[0]; 71 $argv->{monitorstatus} = ($unknown_status)? $unknown_status->id : undef; 72 73 return $class->SUPER::insert( $argv ); 74} 75 76################################################################ 77 78=head2 - find_duplex_mismatches - Finds pairs of interfaces with duplex and/or speed mismatch 79 80 Arguments: 81 None 82 Returns: 83 Array of arrayrefs containing pairs of interface id's 84 Examples: 85 my @list = Interface->find_duplex_mismatches(); 86=cut 87 88sub find_duplex_mismatches { 89 my ($class) = @_; 90 $class->isa_class_method('find_duplex_mismatches'); 91 my $dbh = $class->db_Main(); 92 my $mismatches = $dbh->selectall_arrayref("SELECT i.id, r.id 93 FROM interface i, interface r 94 WHERE i.id<=r.id 95 AND i.neighbor=r.id 96 AND i.oper_status='up' 97 AND r.oper_status='up' 98 AND i.oper_duplex!='' 99 AND r.oper_duplex!='' 100 AND i.oper_duplex!='unknown' 101 AND r.oper_duplex!='unknown' 102 AND i.oper_duplex!=r.oper_duplex"); 103 104 if ( $mismatches ){ 105 my @pairs = @$mismatches; 106 # 107 # Ignore devices that incorrectly report their settings 108 my @results; 109 if ( my $ignored_list = $class->config->get('IGNORE_DUPLEX') ){ 110 my %ignored; 111 foreach my $id ( @$ignored_list){ 112 $ignored{$id} = 1; 113 } 114 foreach my $pair ( @pairs ){ 115 my $match = 0; 116 foreach my $ifaceid ( @$pair ){ 117 my $iface = Interface->retrieve($ifaceid) 118 || $class->throw_fatal("Model::Interface::find_duplex_mismatches: Cannot retrieve Interface id $ifaceid"); 119 if ( $iface->device && $iface->device->product 120 && $iface->device->product->sysobjectid 121 && exists $ignored{$iface->device->product->sysobjectid} ){ 122 $match = 1; 123 last; 124 } 125 } 126 push @results, $pair unless $match; 127 } 128 }else{ 129 return \@pairs; 130 } 131 return \@results; 132 }else{ 133 return; 134 } 135} 136 137 138################################################################ 139 140=head2 - find_vlan_mismatches 141 142 Use topology information to determine if VLAN memmbership 143 of connected interfaces does not correspond 144 145 Arguments: 146 None 147 Returns: 148 Hasref 149 Examples: 150 my $v = Interface->find_vlan_mismatches(); 151=cut 152 153sub find_vlan_mismatches { 154 my ($class) = @_; 155 my $dbh = $class->db_Main; 156 my $rows = $dbh->selectall_arrayref(" 157 SELECT i1.id, i2.id, v1.vid, v2.vid 158 FROM interface i1, interface i2, 159 interfacevlan iv1, interfacevlan iv2, 160 vlan v1, vlan v2 161 WHERE i1.neighbor=i2.id 162 AND i1.id < i2.id 163 AND iv1.interface=i1.id AND iv2.interface=i2.id 164 AND iv1.vlan=v1.id AND iv2.vlan=v2.id"); 165 166 my %x; my %y; my %lks; 167 168 foreach my $row ( @$rows ){ 169 my ($i1, $i2, $v1, $v2) = @$row; 170 $lks{$i1} = $i2; 171 $lks{$i2} = $i1; 172 $x{$i1}{$v1} = 1; 173 $y{$i2}{$v2} = 1; 174 } 175 176 my %res; my %seen; 177 foreach my $i ( keys %x ){ 178 next if $seen{$i}; 179 my $n = $lks{$i}; 180 $seen{$i} = 1; $seen{$n} = 1; 181 my @l1 = sort { $a <=> $b } keys %{$x{$i}}; 182 my @l2 = sort { $a <=> $b } keys %{$y{$n}}; 183 if ( scalar(@l1) == 1 && scalar(@l2) == 1 ){ 184 # Assume that one vlan on each side 185 # means that they are both the native vlan 186 next; 187 } 188 my $vlx = join ', ', @l1; 189 my $vly = join ', ', @l2; 190 if ( $vlx ne $vly ){ 191 my $i_name = $class->retrieve($i)->get_label; 192 my $n_name = $class->retrieve($n)->get_label; 193 $res{$i}{name} = $i_name; 194 $res{$i}{vlans} = $vlx; 195 $res{$i}{n_id} = $n; 196 $res{$i}{n_name} = $n_name; 197 $res{$i}{n_vlans} = $vly; 198 } 199 } 200 return \%res; 201} 202 203 204################################################################# 205 206=head2 - dev_name_number - Hash all interfaces by device, name and number 207 208 Arguments: 209 None 210 Returns: 211 Hash ref of hash refs 212 Examples: 213 my $map = Interface->dev_name_number(); 214 215=cut 216 217sub dev_name_number { 218 my ($class) = @_; 219 $class->isa_class_method('dev_name_number'); 220 221 # Build the SQL query 222 $logger->debug(sub{ "Interface::dev_name_number: Retrieving all interfaces" }); 223 224 my $dbh = $class->db_Main; 225 my $sth = $dbh->prepare_cached("SELECT i.id, i.number, i.name, d.id 226 FROM device d, interface i 227 WHERE i.device=d.id"); 228 $sth->execute(); 229 my $aref = $sth->fetchall_arrayref; 230 231 # Build the hash 232 my %map; 233 foreach my $row ( @$aref ){ 234 my ($iid, $inum, $iname, $did) = @$row; 235 $map{$did}{number}{$inum} = $iid if defined $inum; 236 $map{$did}{name}{$iname} = $iid if defined $iname; 237 } 238 $logger->debug(sub{ "Interface::dev_name_number ...done" }); 239 240 return \%map; 241 242} 243 244 245=head1 OBJECT METHODS 246=cut 247 248################################################################ 249 250=head2 delete - Delete object 251 252 We override the delete method for extra functionality 253 254 Arguments: 255 None 256 Returns: 257 True if sucessful 258 Examples: 259 $interface->delete(); 260 261=cut 262 263sub delete { 264 my $self = shift; 265 $self->isa_object_method('delete'); 266 267 foreach my $neighbor ( $self->neighbors ){ 268 $neighbor->SUPER::update({neighbor=>undef, neighbor_fixed=>0, neighbor_missed=>0}); 269 } 270 271 return $self->SUPER::delete(); 272} 273 274############################################################################ 275 276=head2 add_neighbor 277 278 Arguments: 279 Hash with following key/value pairs: 280 id - Neighbor's Interface id 281 score - Optional score obtained from Topology discovery code (for logging) 282 fixed - (bool) Whether relationship should be removed by automated processes 283 Returns: 284 True if neighbor was successfully added 285 Example: 286 $interface->add_neighbor($id); 287 288=cut 289 290sub add_neighbor{ 291 my ($self, %argv) = @_; 292 $self->isa_object_method('add_neighbor'); 293 my $nid = $argv{id} || $self->throw_fatal("Model::Interface::add_neighbor: Missing required argument: id"); 294 my $score = $argv{score} || 'n/a'; 295 my $fixed = $argv{fixed} || 0; 296 297 if ( $nid == $self->id ){ 298 $self->throw_user(sprintf("%s: interface cannot be neighbor of itself", $self->get_label)); 299 } 300 301 my $neighbor = Interface->retrieve($nid) 302 || $self->throw_fatal("Model::Interface::add_neighbor: Cannot retrieve Interface id $nid"); 303 304 if ( $self->neighbor && $neighbor->neighbor 305 && $self->neighbor->id == $neighbor->id 306 && $neighbor->neighbor->id == $self->id ){ 307 308 return 1; 309 } 310 311 $logger->debug(sub{sprintf("Adding new neighbors: %s <=> %s, score: %s", 312 $self->get_label, $neighbor->get_label, $score)}); 313 314 if ( $self->neighbor && $self->neighbor_fixed ){ 315 $self->throw_user(sprintf("%s has been manually linked to %s", 316 $self->get_label, $self->neighbor->get_label)); 317 318 }elsif ( $neighbor->neighbor && $neighbor->neighbor_fixed ) { 319 $self->throw_user(sprintf("%s has been manually linked to %s", 320 $neighbor->get_label, $neighbor->neighbor->get_label)); 321 322 }else{ 323 # Make sure all neighbor relationships are cleared before going on 324 $self->remove_neighbor(); 325 $neighbor->remove_neighbor(); 326 327 $self->SUPER::update({neighbor => $neighbor->id, 328 neighbor_fixed => $fixed, 329 neighbor_missed => 0}); 330 331 $neighbor->SUPER::update({neighbor => $self->id, 332 neighbor_fixed => $fixed, 333 neighbor_missed => 0}); 334 335 $logger->info(sprintf("Added new neighbors: %s <=> %s, score: %s", 336 $self->get_label, $neighbor->get_label, $score)); 337 return 1; 338 } 339} 340 341 342############################################################################ 343 344=head2 remove_neighbor 345 346 Arguments: 347 None 348 Returns: 349 See update method 350 Example: 351 $interface->remove_neighbor(); 352 353=cut 354 355sub remove_neighbor{ 356 my ($self) = @_; 357 358 my %args = ( 359 neighbor => undef, 360 neighbor_fixed => 0, 361 neighbor_missed => 0 362 ); 363 364 # Unset neighbor field in all interfaces that have 365 # me as their neighbor 366 map { $_->SUPER::update(\%args) } $self->neighbors; 367 368 # Unset my own neighbor field 369 return $self->SUPER::update(\%args); 370} 371 372############################################################################ 373 374=head2 update - Update Interface 375 376 Arguments: 377 Hash ref with Interface fields 378 Returns: 379 See Class::DBI::update() 380 Example: 381 $interface->update( \%data ); 382 383=cut 384 385sub update { 386 my ($self, $argv) = @_; 387 $self->isa_object_method('update'); 388 my $class = ref($self); 389 390 if ( exists $argv->{neighbor} ){ 391 if ( !$argv->{neighbor} ){ 392 $self->remove_neighbor(); 393 }else{ 394 $self->add_neighbor(id => $argv->{neighbor}, 395 fixed => $argv->{neighbor_fixed}); 396 } 397 } 398 delete $argv->{neighbor}; 399 return $self->SUPER::update($argv); 400} 401 402############################################################################ 403 404=head2 snmp_update - Insert/Update Interface using SNMP info 405 406 Arguments: 407 Hash with the following keys: 408 column - Any of Interface table columns 409 snmp_info - Hash ref with SNMP info about interface 410 add_subnets - Whether to add subnets automatically 411 subs_inherit - Whether subnets should inherit info from the Device 412 stp_instances - Hash ref with device STP info 413 Returns: 414 Interface object 415 Examples: 416 # Instance call 417 $if->snmp_update(snmp_info => $info->{interface}->{$newif}, 418 add_subnets => $add_subnets, 419 subs_inherit => $subs_inherit, 420 ); 421 # Class call 422 my $new = Ipblock->snmp_update(%args, snmp_info=>$info, ...); 423 424=cut 425 426sub snmp_update { 427 my ($self, %args) = @_; 428 my $info = $args{snmp_info}; 429 my %iftmp = (doc_status => 'snmp'); 430 431 # Table column values can be arguments or keys in the snmp_info hash 432 foreach my $field ( $self->meta_data->get_column_names ){ 433 $iftmp{$field} = $args{$field} if exists $args{$field}; 434 $iftmp{$field} = $info->{$field} if exists $info->{$field}; 435 } 436 437 ############################################ 438 # Update PhysAddr 439 if ( $info->{physaddr} && (my $addr = PhysAddr->validate($info->{physaddr})) ){ 440 my $physaddr = PhysAddr->search(address=>$addr)->first; 441 if ( $physaddr ){ 442 $physaddr->update({last_seen=>$self->timestamp, static=>1}); 443 }else{ 444 eval { 445 $physaddr = PhysAddr->insert({address=>$addr, static=>1}); 446 }; 447 if ( my $e = $@ ){ 448 $logger->debug(sub{"$e"}); 449 } 450 } 451 $iftmp{physaddr} = $physaddr->id if $physaddr; 452 }else{ 453 $iftmp{physaddr} = undef; 454 } 455 456 457 ############################################ 458 # Insert/Update 459 my $class; 460 if ( $class = ref($self) ){ 461 462 # Check if description can be overwritten 463 delete $iftmp{description} if !($self->overwrite_descr) ; 464 465 my $r = $self->update( \%iftmp ); 466 my $d = $self->device->get_label; 467 if ( $r && $self->number && $self->name ){ 468 $logger->debug(sub{ sprintf("%s: Interface %s (%s) updated", 469 $d, $self->number, $self->name) }); 470 } 471 }else{ 472 $class = $self; 473 $self = $class->insert(\%iftmp); 474 my $d = $self->device->get_label; 475 $logger->info(sprintf("%s: Interface %s (%s) updated", 476 $d, $self->number, $self->name)); 477 478 } 479 my $label = $self->get_label; 480 481 ############################################## 482 # Update VLANs 483 # 484 # Get our current vlan memberships 485 # InterfaceVlan objects 486 # 487 if ( exists $info->{vlans} ){ 488 my %oldvlans; 489 map { $oldvlans{$_->id} = $_ } $self->vlans(); 490 491 # InterfaceVlan STP fields and their methods 492 my %IVFIELDS = ( stp_des_bridge => 'i_stp_bridge', 493 stp_des_port => 'i_stp_port', 494 stp_state => 'i_stp_state', 495 ); 496 497 foreach my $newvlan ( keys %{ $info->{vlans} } ){ 498 my $vid = $info->{vlans}->{$newvlan}->{vid} || $newvlan; 499 next if $vid == 0; 500 my $vname = $info->{vlans}->{$newvlan}->{vname}; 501 my $vo; 502 my %vdata; 503 $vdata{vid} = $vid; 504 $vdata{name} = $vname if defined $vname; 505 if ( $vo = Vlan->search(vid => $vid)->first ){ 506 # update if name wasn't set (ignore default vlan 1) 507 if ( !defined $vo->name && defined $vdata{name} && $vo->vid ne "1" ){ 508 my $r = $vo->update(\%vdata); 509 $logger->debug(sub{ sprintf("%s: VLAN %s name updated: %s", 510 $label, $vo->vid, $vo->name) }) 511 if $r; 512 } 513 }else{ 514 # create 515 $vo = Vlan->insert(\%vdata); 516 $logger->info(sprintf("%s: Inserted VLAN %s", $label, $vo->vid)); 517 } 518 # Now verify membership 519 # 520 my %ivtmp = ( interface => $self->id, vlan => $vo->id ); 521 my $iv; 522 if ( $iv = InterfaceVlan->search( \%ivtmp )->first ){ 523 delete $oldvlans{$iv->id}; 524 }else { 525 # insert 526 $iv = InterfaceVlan->insert( \%ivtmp ); 527 $logger->debug(sub{sprintf("%s: Assigned Interface %s (%s) to VLAN %s", 528 $label, $self->number, $self->name, $vo->vid)}); 529 } 530 531 # Insert STP information for this interface on this vlan 532 my $stpinst = $info->{vlans}->{$newvlan}->{stp_instance}; 533 unless ( defined $stpinst ){ 534 $logger->debug(sub{sprintf("%s: VLAN %s not mapped to any STP instance", 535 $label, $newvlan)}); 536 next; 537 } 538 539 my $instobj; 540 # In theory, this happens after the STP instances have been updated on this device 541 $instobj = STPInstance->search(device=>$self->device, number=>$stpinst)->first; 542 unless ( $instobj ){ 543 $logger->warn("$label: Cannot find STP instance $stpinst"); 544 next; 545 } 546 my %uargs; 547 foreach my $field ( keys %IVFIELDS ){ 548 my $method = $IVFIELDS{$field}; 549 if ( exists $args{stp_instances}->{$stpinst}->{$method} && 550 (my $v = $args{stp_instances}->{$stpinst}->{$method}->{$info->{number}}) ){ 551 $uargs{$field} = $v; 552 } 553 } 554 if ( %uargs ){ 555 $iv->update({stp_instance=>$instobj, %uargs}); 556 $logger->debug(sub{ sprintf("%s: Updated STP info on VLAN %s", 557 $label, $vo->vid) }); 558 } 559 } 560 # Remove each vlan membership that no longer exists 561 # 562 foreach my $oldvlan ( keys %oldvlans ) { 563 my $iv = $oldvlans{$oldvlan}; 564 $logger->debug(sub{sprintf("%s: membership with VLAN %s no longer exists. Removing.", 565 $label, $iv->vlan->vid)}); 566 $iv->delete(); 567 } 568 } 569 570 ################################################################ 571 # Update IPs 572 # 573 if ( exists( $info->{ips} ) ) { 574 575 # For Subnet->vlan assignments 576 my $vlan = 0; 577 my @ivs = $self->vlans; 578 $vlan = $ivs[0]->vlan if ( scalar(@ivs) == 1 ); 579 580 my $name = $self->name; 581 582 # For layer3 switches with virtual VLAN interfaces 583 if ( !$vlan && $self->device->ipforwarding ){ 584 my $vid; 585 586 if ( $name && $name =~ /Vlan(\d+)/o ){ 587 # This works mostly for Cisco Catalyst stuff 588 $vid = $1; 589 }elsif ( $self->type eq '135' # See IF-MIB 590 && $name && $name =~ /\.(\d+)$/o ){ 591 # This works for Juniper stuff or anything 592 # with sub-interfaces. It assumes that 593 # the sub-interface number matches the VLAN id 594 $vid = $1; 595 } 596 $vlan = Vlan->search(vid=>$vid)->first; 597 } 598 599 foreach my $newip ( keys %{ $info->{ips} } ){ 600 if ( my $address = $info->{ips}->{$newip}->{address} ){ 601 my %iargs = (address => $address, 602 version => $info->{ips}->{$newip}->{version}, 603 subnet => $info->{ips}->{$newip}->{subnet}, 604 add_subnets => $args{add_subnets}, 605 subs_inherit => $args{subs_inherit}, 606 ); 607 $iargs{vlan} = $vlan if $vlan; 608 if ( $self->ignore_ip ){ 609 $logger->debug(sub{sprintf("%s: Ignoring IP information", $label)}); 610 }else{ 611 $self->update_ip(%iargs); 612 } 613 } 614 } 615 } 616 return $self; 617} 618 619############################################################################ 620 621=head2 update_ip - Update IP adddress for this interface 622 623 Arguments: 624 Hash with the following keys: 625 address - Dotted quad ip address 626 version - 4 or 6 627 subnet - Subnet CIDR 628 add_subnets - Flag. Add subnet if necessary (only for routers) 629 subs_inherit - Flag. Have subnet inherit some Device information 630 vlan - Vlan ID (for Subnet to Vlan mapping) 631 632 Returns: 633 Updated Ipblock object 634 Example: 635 636=cut 637 638sub update_ip { 639 my ($self, %args) = @_; 640 $self->isa_object_method('update_ip'); 641 642 my $address = $args{address}; 643 my $version = $args{version}; 644 $self->throw_fatal("Model::Interface::update_ip: Missing required arguments: address, version") 645 unless ( $address && $version ); 646 647 my $label = $self->get_label; 648 649 # Do not bother with loopbacks 650 if ( Ipblock->is_loopback($address) ){ 651 $logger->debug(sub{"$label: IP $address is a loopback. Skipping."}); 652 return; 653 } 654 655 if ( $args{subnet} ){ 656 $logger->debug(sub{sprintf("%s: Subnet configured in interface is %s", 657 $label, $args{subnet})}); 658 } 659 660 # We might have to add a subnet 661 if ( $args{add_subnets} && (my $subnet = $args{subnet}) ){ 662 my ($subnetaddr, $subnetprefix); 663 if ( $subnet =~ /^(.+)\/(\d+)$/ ){ 664 ($subnetaddr, $subnetprefix) = ($1, $2); 665 }else{ 666 $self->throw_fatal("Model::Interface::update_ip: Invalid subnet: $subnet"); 667 } 668 669 $logger->debug(sprintf("%s: Adding or updating subnet %s/%d", 670 $label, $subnetaddr, $subnetprefix)); 671 672 # Make sure we compare the same formatting 673 my $subnet_netaddr = Ipblock->netaddr(address=>$subnetaddr, prefix=>$subnetprefix); 674 my $address_netaddr = Ipblock->netaddr(address=>$address); 675 676 if ( $subnet_netaddr->addr ne $address_netaddr->addr || 677 ($version == 4 && $subnetprefix == 31) ){ 678 my %iargs; 679 $iargs{status} = 'Subnet' ; 680 681 # If we have a VLAN, make the relationship 682 $iargs{vlan} = $args{vlan} if defined $args{vlan}; 683 684 if ( my $subnetobj = Ipblock->search(address => $subnetaddr, 685 version => $version, 686 prefix => $subnetprefix)->first ){ 687 688 $logger->debug(sub{ sprintf("%s: Block %s already exists", 689 $label, $subnetobj->get_label)} ); 690 691 # Skip validation for speed, since the block already exists 692 $iargs{validate} = 0; 693 694 # Add description from interface if not set 695 $iargs{description} = $self->description 696 if ( !defined $subnetobj->description || $subnetobj->description eq "" ); 697 698 $iargs{last_seen} = $self->timestamp; 699 700 $subnetobj->update(\%iargs); # Makes sure that the status is set to subnet 701 702 }else{ 703 $logger->debug(sub{ sprintf("Subnet %s/%s does not exist. Inserting.", 704 $subnetaddr, $subnetprefix) }); 705 706 $iargs{address} = $subnet_netaddr->addr; 707 $iargs{prefix} = $subnet_netaddr->masklen; 708 $iargs{version} = $version; 709 $iargs{description} = $self->description; 710 $iargs{first_seen} = $self->timestamp; 711 $iargs{last_seen} = $iargs{first_seen}; 712 713 # Check if subnet should inherit device info 714 if ( $args{subs_inherit} ){ 715 $iargs{owner} = $self->device->owner; 716 $iargs{used_by} = $self->device->used_by; 717 } 718 719 # Ipblock validation might throw an exception 720 my $newblock; 721 eval { 722 $newblock = Ipblock->insert(\%iargs); 723 }; 724 if ( my $e = $@ ){ 725 $logger->error(sprintf("%s: Could not insert Subnet %s/%s: %s", 726 $label, $subnet_netaddr->addr, $subnet_netaddr->masklen, $e)); 727 }else{ 728 $logger->info(sprintf("%s: Created Subnet %s/%s", 729 $label, $subnetaddr, $subnetprefix)); 730 } 731 } 732 } 733 } 734 735 # Now work on the address itself 736 my $prefix = ($version == 4) ? 32 : 128; 737 my $ipobj; 738 if ( $ipobj = Ipblock->search(address => $address, 739 prefix => $prefix, 740 version => $version)->first ){ 741 742 # update 743 $logger->debug(sub{ sprintf("%s: IP %s/%s exists. Updating", 744 $label, $address, $prefix) }); 745 746 # Notice that this is basically to confirm that the IP belongs 747 # to this interface. 748 # Therefore, it's very unlikely that the object won't pass 749 # validation, so we skip it to speed things up. 750 my %args = (interface => $self, validate => 0, last_seen=>$self->timestamp); 751 if ( !($ipobj->status) || 752 ($ipobj->status->name ne 'Static' && $ipobj->status->name ne 'Dynamic') ){ 753 $args{status} = 'Static'; 754 } 755 $ipobj->update(\%args); 756 }else { 757 # Create a new IP 758 # This could also go wrong, but we don't want to bail out 759 eval { 760 $ipobj = Ipblock->insert({address => $address, prefix => $prefix, 761 status => "Static", interface => $self, 762 version => $version, 763 }); 764 }; 765 if ( my $e = $@ ){ 766 $logger->warn(sprintf("%s: Could not insert IP %s: %s", 767 $label, $address, $e)); 768 return; 769 }else{ 770 $logger->info(sprintf("%s: Inserted new IP %s", $label, $ipobj->address)); 771 my $version = $ipobj->version; 772 } 773 } 774 return $ipobj; 775} 776 777############################################################################ 778 779=head2 speed_pretty - Convert ifSpeed to something more readable 780 781 Arguments: 782 None 783 Returns: 784 Human readable speed string or n/a 785 786=cut 787 788sub speed_pretty { 789 my ($self) = @_; 790 $self->isa_object_method('speed_pretty'); 791 my $speed = $self->speed; 792 793 if ( exists $SPEED_MAP{$speed} ){ 794 return $SPEED_MAP{$speed}; 795 }else{ 796 # ifHighSpeed (already translated to bps) 797 my $fmt = "%d bps"; 798 if ( $speed > 9999999999999 ){ 799 $fmt = "%d Tbps"; 800 $speed /= 1000000000000; 801 } elsif ( $speed > 999999999999 ){ 802 $fmt = "%.1f Tbps"; 803 $speed /= 1000000000000.0; 804 } elsif ( $speed > 9999999999 ){ 805 $fmt = "%d Gbps"; 806 $speed /= 1000000000; 807 } elsif ( $speed > 999999999 ){ 808 $fmt = "%.1f Gbps"; 809 $speed /= 1000000000.0; 810 } elsif ( $speed > 9999999 ){ 811 $fmt = "%d Mbps"; 812 $speed /= 1000000; 813 } elsif ( $speed > 999999 ){ 814 $fmt = "%d Mbps"; 815 $speed /= 1000000.0; 816 } elsif ( $speed > 99999 ){ 817 $fmt = "%d Kbps"; 818 $speed /= 100000; 819 } elsif ( $speed > 9999 ){ 820 $fmt = "%d Kbps"; 821 $speed /= 100000.0; 822 } 823 return sprintf($fmt, $speed); 824 } 825} 826 827############################################################################ 828 829=head2 get_label 830 831 Override get_label from base class 832 833=cut 834 835sub get_label{ 836 my ($self) = @_; 837 $self->isa_object_method('get_label'); 838 return unless ( $self->id && $self->device ); 839 my $name = $self->name || $self->number; 840 my $label = sprintf("%s [%s]", $self->device->get_label, $name); 841 return $label; 842} 843 844=head1 AUTHOR 845 846Carlos Vicente, C<< <cvicente at ns.uoregon.edu> >> 847 848=head1 COPYRIGHT & LICENSE 849 850Copyright 2012 University of Oregon, all rights reserved. 851 852This program is free software; you can redistribute it and/or modify 853it under the terms of the GNU General Public License as published by 854the Free Software Foundation; either version 2 of the License, or 855(at your option) any later version. 856 857This program is distributed in the hope that it will be useful, but 858WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY 859or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 860License for more details. 861 862You should have received a copy of the GNU General Public License 863along with this program; if not, write to the Free Software Foundation, 864Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 865 866=cut 867 868