[3033731] - Alcatel-Lucent OmniSwich AMAP Support
This commit is contained in:
		| @@ -21,6 +21,7 @@ version 3.00 | ||||
|     * [3323814] - Arp support for Netscreen (David Baldwin) | ||||
|     * [3323821] - Support for Netscreen w/ WLAN (eg SSG5) (David Baldwin) | ||||
|     * [3599277] - Q-BRIDGE Support to collect VLAN in macsuck | ||||
|     * [3033731] - Alcatel-Lucent OmniSwich AMAP Support in new AMAP class | ||||
|     * Support for Avaya VSP 9000 series in L3::Passport | ||||
|     * Support for Avaya VSP 7000 series in L2::Baystack | ||||
|     * Support Avaya (Trapeze) Wireless Controllers in new class L2::NWSS2300 | ||||
|   | ||||
							
								
								
									
										22
									
								
								Info.pm
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								Info.pm
									
									
									
									
									
								
							| @@ -242,6 +242,13 @@ devices based on the Airespace wireless platform. | ||||
|  | ||||
| See documentation in L<SNMP::Info::Airespace> for details. | ||||
|  | ||||
| =item SNMP::Info::AMAP | ||||
|  | ||||
| F<ALCATEL-IND1-INTERSWITCH-PROTOCOL-MIB>.  Alcatel Mapping Adjacency | ||||
| Protocol (AMAP) Support. | ||||
|  | ||||
| See documentation in L<SNMP::Info::AMAP> for details. | ||||
|  | ||||
| =item SNMP::Info::Bridge | ||||
|  | ||||
| F<BRIDGE-MIB> (RFC1286).  F<QBRIDGE-MIB>. Inherited by devices with Layer2 | ||||
| @@ -2330,8 +2337,8 @@ Based upon the manufacturer and software version devices may support some | ||||
| combination of Layer 2 topology protocol information.  SNMP::Info | ||||
| supports querying Link Layer Discovery Protocol (LLDP), Cisco Discovery | ||||
| Protocol (CDP), SynOptics/Bay/Nortel/Avaya Network Management Protocol | ||||
| (SONMP), Foundry/Brocade Discovery Protocol (FDP), and Extreme Discovery | ||||
| Protocol (EDP).  | ||||
| (SONMP), Foundry/Brocade Discovery Protocol (FDP), Extreme Discovery | ||||
| Protocol (EDP), and Alcatel Mapping Adjacency Protocol (AMAP).  | ||||
|  | ||||
| For protocol specific information and implementation: | ||||
|  | ||||
| @@ -2347,6 +2354,8 @@ For protocol specific information and implementation: | ||||
|  | ||||
| =item EDP: See L<SNMP::Info::EDP> for details. | ||||
|  | ||||
| =item AMAP: See L<SNMP::Info::AMAP> for details. | ||||
|  | ||||
| =back | ||||
|  | ||||
| =head3 Topology Capabilities | ||||
| @@ -2359,8 +2368,8 @@ Reports Layer 2 topology protocols which are supported and running on | ||||
| a device. | ||||
|  | ||||
| Returns either a reference to an array of protocols, possible values | ||||
| being: C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp> or C<undef> if no protocols | ||||
| are supported or running. | ||||
| being: C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>, C<amap> or C<undef> if | ||||
| no protocols are supported or running. | ||||
|  | ||||
| =back | ||||
|  | ||||
| @@ -2377,6 +2386,7 @@ sub has_topo { | ||||
|         if $self->can('hasSONMP') && $self->hasSONMP(); | ||||
|     push( @topo_cap, 'fdp' ) if $self->can('hasFDP') && $self->hasFDP(); | ||||
|     push( @topo_cap, 'edp' ) if $self->can('hasEDP') && $self->hasEDP(); | ||||
|     push( @topo_cap, 'amap' ) if $self->can('hasAMAP') && $self->hasAMAP(); | ||||
|  | ||||
|     if (@topo_cap) { | ||||
|         return \@topo_cap; | ||||
| @@ -2396,7 +2406,7 @@ sub _get_topo_data { | ||||
|  | ||||
|     my %t_data; | ||||
|     foreach my $proto (@$topo_cap) { | ||||
|         next unless $proto =~ /(lldp|cdp|sonmp|fdp|edp)/; | ||||
|         next unless $proto =~ /(lldp|cdp|sonmp|fdp|edp|amap)/; | ||||
|         my $method_name = "$proto" . "_$method"; | ||||
|         my $cdp = $self->$method_name($partial) || {}; | ||||
|  | ||||
| @@ -2426,7 +2436,7 @@ first argument. | ||||
|  | ||||
| If a reference to an array is provided as the second argument, those | ||||
| protocols will be queried for information.  The supported array values are: | ||||
| C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>. | ||||
| C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>, C<amap>. | ||||
|  | ||||
| If nothing is passed in as the second argument, the methods will call | ||||
| has_topo() to determine supported and running topology protocols on the | ||||
|   | ||||
							
								
								
									
										341
									
								
								Info/AMAP.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								Info/AMAP.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,341 @@ | ||||
| # SNMP::Info::AMAP | ||||
| # | ||||
| # Copyright (c) 2013 Eric Miller | ||||
| # All rights reserved. | ||||
| # | ||||
| # Redistribution and use in source and binary forms, with or without | ||||
| # modification, are permitted provided that the following conditions are met: | ||||
| # | ||||
| #     * Redistributions of source code must retain the above copyright notice, | ||||
| #       this list of conditions and the following disclaimer. | ||||
| #     * Redistributions in binary form must reproduce the above copyright | ||||
| #       notice, this list of conditions and the following disclaimer in the | ||||
| #       documentation and/or other materials provided with the distribution. | ||||
| #     * Neither the name of the University of California, Santa Cruz nor the | ||||
| #       names of its contributors may be used to endorse or promote products | ||||
| #       derived from this software without specific prior written permission. | ||||
| # | ||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||||
| # LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| # POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| package SNMP::Info::AMAP; | ||||
|  | ||||
| use strict; | ||||
| use Exporter; | ||||
| use SNMP::Info; | ||||
|  | ||||
| @SNMP::Info::LLDP::ISA       = qw/SNMP::Info Exporter/; | ||||
| @SNMP::Info::LLDP::EXPORT_OK = qw//; | ||||
|  | ||||
| use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE/; | ||||
|  | ||||
| $VERSION = '3.00_001'; | ||||
|  | ||||
| %MIBS | ||||
|     = ( 'ALCATEL-IND1-INTERSWITCH-PROTOCOL-MIB' => 'aipAMAPRemDeviceType', ); | ||||
|  | ||||
| %GLOBALS = ( | ||||
|  | ||||
| ); | ||||
|  | ||||
| %FUNCS = ( | ||||
|  | ||||
|     # EXTREME-EDP-MIB::extremeEdpTable | ||||
|     'amap_rem_sysname' => 'aipAMAPRemHostname', | ||||
| ); | ||||
|  | ||||
| %MUNGE = ( 'amap_rem_sysname' => \&SNMP::Info::munge_null, ); | ||||
|  | ||||
| sub hasAMAP { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $amap_ip = $amap->aipAMAPIpAddr() || {}; | ||||
|  | ||||
|     return 1 if ( scalar( keys %$amap_ip ) ); | ||||
|  | ||||
|     return; | ||||
| } | ||||
|  | ||||
| # Break up the aipAMAPhostsTable INDEX into MAC and IP address. | ||||
| sub _hosts_table_index { | ||||
|     my $idx  = shift; | ||||
|     my @oids = split( /\./, $idx ); | ||||
|     my $mac  = join( '.', splice( @oids, 0, 6 ) ); | ||||
|  | ||||
|     return ( $mac, join( '.', @oids ) ); | ||||
| } | ||||
|  | ||||
| # Break up the aipAMAPportConnectionTable INDEX and return MAC | ||||
| sub _conn_table_mac { | ||||
|     my $idx       = shift; | ||||
|     my @oids      = split( /\./, $idx ); | ||||
|     my $local_idx = shift @oids; | ||||
|     my $mac       = join( '.', splice( @oids, 0, 6 ) ); | ||||
|  | ||||
|     return ($mac); | ||||
| } | ||||
|  | ||||
| # Since we need to get IP Addresses from the aipAMAPhostsTable which has | ||||
| # a different index (MAC, IP) than the aipAMAPportConnectionTable which holds | ||||
| # the remote device details we create a combined index and skip any | ||||
| # IPs which have an address of 0.0.0.0.  Would like to include only one | ||||
| # address since they should all originate from the same device, but we don't | ||||
| # know if they would all be reachable from the network management application. | ||||
| # | ||||
| # We don't inplement partials since this is private index function | ||||
| sub _amap_index { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $amap_ip    = $amap->aipAMAPIpAddr()    || {}; | ||||
|     my $amap_rport = $amap->aipAMAPLocalPort() || {}; | ||||
|  | ||||
|     my %amap_index; | ||||
|     foreach my $key ( keys %$amap_ip ) { | ||||
|         my ( $mac, $ip ) = _hosts_table_index($key); | ||||
|  | ||||
|         next if ( $ip eq '0.0.0.0' ); | ||||
|         next unless $ip; | ||||
|  | ||||
|         foreach my $idx ( keys %$amap_rport ) { | ||||
|             my $c_mac = _conn_table_mac($idx); | ||||
|  | ||||
|             if ( $mac eq $c_mac ) { | ||||
|                 my $index = "$idx.$ip"; | ||||
|                 $amap_index{$index} = $index; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return \%amap_index; | ||||
| } | ||||
|  | ||||
| # Break up _amap_index INDEX into local index, MAC, remote index, and | ||||
| # IP address | ||||
| sub _amap_index_parts { | ||||
|     my $idx       = shift; | ||||
|     my @oids      = split( /\./, $idx ); | ||||
|     my $local_idx = shift @oids; | ||||
|     my $mac       = join( '.', splice( @oids, 0, 6 ) ); | ||||
|     my $rem_idx   = shift @oids; | ||||
|  | ||||
|     return ( $local_idx, $mac, $rem_idx, join( '.', @oids ) ); | ||||
| } | ||||
|  | ||||
| sub amap_if { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $index  = $amap->_amap_index()         || {}; | ||||
|     my $if_idx = $amap->aipAMAPLocalIfindex() || {}; | ||||
|  | ||||
|     my %amap_if; | ||||
|     foreach my $key ( keys %$index ) { | ||||
|         my ( $local_idx, $mac, $rem_idx, $ip ) = _amap_index_parts($key); | ||||
|         my $if_key = "$local_idx.$mac.$rem_idx"; | ||||
|  | ||||
|         if ( $key =~ /^$if_key/ ) { | ||||
|             my $if = $if_idx->{$if_key}; | ||||
|             $amap_if{$key} = $if; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return \%amap_if; | ||||
| } | ||||
|  | ||||
| sub amap_ip { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $index = $amap->_amap_index() || {}; | ||||
|  | ||||
|     my %amap_ip; | ||||
|     foreach my $key ( keys %$index ) { | ||||
|         my ( $local_idx, $mac, $rem_idx, $ip ) = _amap_index_parts($key); | ||||
|  | ||||
|         # MIB says should only be IPv4 | ||||
|         next unless ( $ip =~ /\d+(\.\d+){3}/ ); | ||||
|         $amap_ip{$key} = $ip; | ||||
|     } | ||||
|     return \%amap_ip; | ||||
| } | ||||
|  | ||||
| sub amap_port { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $index      = $amap->_amap_index()      || {}; | ||||
|     my $amap_rport = $amap->aipAMAPLocalPort() || {}; | ||||
|     my $amap_rslot = $amap->aipAMAPLocalSlot() || {}; | ||||
|  | ||||
|     my %amap_port; | ||||
|     foreach my $key ( sort keys %$index ) { | ||||
|         my ( $local_idx, $mac, $rem_idx, $ip ) = _amap_index_parts($key); | ||||
|         my $p_key = "$local_idx.$mac.$rem_idx"; | ||||
|  | ||||
|         if ( $key =~ /^$p_key/ ) { | ||||
|             my $port = $amap_rport->{$p_key}; | ||||
|             my $slot = $amap_rslot->{$p_key} || 0; | ||||
|             next unless $port; | ||||
|             $amap_port{$key} = defined $slot ? "$slot\/$port" : $port; | ||||
|         } | ||||
|     } | ||||
|     return \%amap_port; | ||||
| } | ||||
|  | ||||
| sub amap_id { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $index     = $amap->_amap_index()      || {}; | ||||
|     my $amap_name = $amap->amap_rem_sysname() || {}; | ||||
|  | ||||
|     my %amap_name; | ||||
|     foreach my $key ( sort keys %$index ) { | ||||
|         my ( $local_idx, $mac, $rem_idx, $ip ) = _amap_index_parts($key); | ||||
|         my $id_key = "$local_idx.$mac.$rem_idx"; | ||||
|  | ||||
|         if ( $key =~ /^$id_key/ ) { | ||||
|             my $name = $amap_name->{$id_key} || 0; | ||||
|             next unless $name; | ||||
|             $amap_name{$key} = $name; | ||||
|         } | ||||
|     } | ||||
|     return \%amap_name; | ||||
| } | ||||
|  | ||||
| sub amap_platform { | ||||
|     my $amap = shift; | ||||
|  | ||||
|     my $index              = $amap->_amap_index()          || {}; | ||||
|     my $amap_topo_platform = $amap->aipAMAPRemDeviceType() || {}; | ||||
|  | ||||
|     my %amap_platform; | ||||
|     foreach my $key ( keys %$index ) { | ||||
|         my ( $local_idx, $mac, $rem_idx, $ip ) = _amap_index_parts($key); | ||||
|         my $pf_key = "$local_idx.$mac.$rem_idx"; | ||||
|  | ||||
|         if ( $key =~ /^$pf_key/ ) { | ||||
|             my $platform = $amap_topo_platform->{$pf_key}; | ||||
|             next unless $platform; | ||||
|             $amap_platform{$key} = $platform; | ||||
|         } | ||||
|     } | ||||
|     return \%amap_platform; | ||||
| } | ||||
|  | ||||
| 1; | ||||
| __END__ | ||||
|  | ||||
| =head1 NAME | ||||
|  | ||||
| SNMP::Info::AMAP - SNMP Interface to Alcatel Mapping Adjacency Protocol (AMAP) | ||||
|  | ||||
| =head1 AUTHOR | ||||
|  | ||||
| Eric Miller | ||||
|  | ||||
| =head1 SYNOPSIS | ||||
|  | ||||
|  my $amap = new SNMP::Info (  | ||||
|                              AutoSpecify => 1, | ||||
|                              Debug       => 1, | ||||
|                              DestHost    => 'router',  | ||||
|                              Community   => 'public', | ||||
|                              Version     => 2 | ||||
|                            ); | ||||
|  | ||||
|  my $class = $amap->class(); | ||||
|  print " Using device sub class : $class\n"; | ||||
|  | ||||
|  $hasamap   = $amap->hasAMAP() ? 'yes' : 'no'; | ||||
|  | ||||
|  # Print out a map of device ports with LLDP neighbors: | ||||
|  my $interfaces    = $amap->interfaces(); | ||||
|  my $amap_if       = $amap->amap_if(); | ||||
|  my $amap_ip       = $amap->amap_ip(); | ||||
|  my $amap_port     = $amap->amap_port(); | ||||
|  | ||||
|  foreach my $amap_key (keys %$amap_ip){ | ||||
|     my $iid           = $amap_if->{$amap_key}; | ||||
|     my $port          = $interfaces->{$iid}; | ||||
|     my $neighbor      = $amap_ip->{$amap_key}; | ||||
|     my $neighbor_port = $amap_port->{$amap_key}; | ||||
|     print "Port : $port connected to $neighbor / $neighbor_port\n"; | ||||
|  } | ||||
|  | ||||
| =head1 DESCRIPTION | ||||
|  | ||||
| SNMP::Info::AMAP is a subclass of SNMP::Info that provides an object oriented  | ||||
| interface to Alcatel Mapping Adjacency Protocol (AMAP) information through | ||||
| SNMP. | ||||
|  | ||||
| AMAP is a Layer 2 protocol that allows a network device to advertise its | ||||
| identity and capabilities on the local network providing topology information. | ||||
|  | ||||
| Create or use a device subclass that inherits this class.  Do not use | ||||
| directly. | ||||
|  | ||||
| =head2 Inherited Classes | ||||
|  | ||||
| None. | ||||
|  | ||||
| =head2 Required MIBs | ||||
|  | ||||
| =over | ||||
|  | ||||
| =item F<ALCATEL-IND1-INTERSWITCH-PROTOCOL-MIB> | ||||
|  | ||||
| =back | ||||
|  | ||||
| =head1 GLOBAL METHODS | ||||
|  | ||||
| These are methods that return scalar values from SNMP | ||||
|  | ||||
| =over | ||||
|  | ||||
| =item $amap->hasAMAP() | ||||
|  | ||||
| Is AMAP is active in this device?   | ||||
|  | ||||
| =back | ||||
|  | ||||
| =head1 TABLE METHODS | ||||
|  | ||||
| These are methods that return tables of information in the form of a reference | ||||
| to a hash. | ||||
|  | ||||
| =over | ||||
|  | ||||
| =item $amap->amap_id() | ||||
|  | ||||
| Returns the string value used to identify the remote system. | ||||
|  | ||||
| =item $amap->amap_if() | ||||
|  | ||||
| Returns the mapping to the SNMP Interface Table. | ||||
|  | ||||
| =item  $amap->amap_ip() | ||||
|  | ||||
| Returns remote IPv4 addresses.  Note: AMAP returns all IP addresses associated | ||||
| with the remote device.  It would be preferable to include only one address | ||||
| since they should all originate from the same device, but amap_ip() can not  | ||||
| determine if all addresses are reachable from the network management | ||||
| application therefore all addresses are returned and the calling application | ||||
| must determine which address to use and if they are in fact from the same | ||||
| device. | ||||
|  | ||||
| =item $amap->amap_port() | ||||
|  | ||||
| Returns remote port ID | ||||
|  | ||||
| =item $amap->amap_platform() | ||||
|  | ||||
| Returns remote platform ID | ||||
|  | ||||
| =back | ||||
|  | ||||
| =cut | ||||
| @@ -34,6 +34,7 @@ use strict; | ||||
| use Exporter; | ||||
| use SNMP::Info::Layer3; | ||||
| use SNMP::Info::MAU; | ||||
| use SNMP::Info::AMAP; | ||||
| # Use LLDP | ||||
| # (or at least try.  The versions I've seen have two problems: | ||||
| # 1. they report ifIndex values as 'local'; we don't support ifIndex | ||||
| @@ -42,8 +43,8 @@ use SNMP::Info::MAU; | ||||
| # ) | ||||
| use SNMP::Info::LLDP; | ||||
|  | ||||
| @SNMP::Info::Layer3::AlcatelLucent::ISA = qw/SNMP::Info::LLDP SNMP::Info::MAU | ||||
|     SNMP::Info::Layer3 Exporter/; | ||||
| @SNMP::Info::Layer3::AlcatelLucent::ISA = qw/SNMP::Info::AMAP SNMP::Info::LLDP | ||||
|     SNMP::Info::MAU SNMP::Info::Layer3 Exporter/; | ||||
| @SNMP::Info::Layer3::AlcatelLucent::EXPORT_OK = qw//; | ||||
|  | ||||
| use vars qw/$VERSION %GLOBALS %MIBS %FUNCS %MUNGE/; | ||||
| @@ -54,6 +55,7 @@ $VERSION = '3.00_001'; | ||||
|     %SNMP::Info::Layer3::MIBS, | ||||
|     %SNMP::Info::MAU::MIBS, | ||||
|     %SNMP::Info::LLDP::MIBS, | ||||
|     %SNMP::Info::AMAP::MIBS, | ||||
|     'ALCATEL-IND1-DEVICES'     => 'familyOmniSwitch7000', | ||||
|     'ALCATEL-IND1-CHASSIS-MIB' => 'chasEntPhysOperStatus', | ||||
|     'ALU-POWER-ETHERNET-MIB'   => 'pethPsePortDetectionStatus', | ||||
| @@ -70,17 +72,17 @@ delete $MIBS{'POWER-ETHERNET-MIB'}; | ||||
|  | ||||
| %GLOBALS = ( | ||||
|     %SNMP::Info::Layer3::GLOBALS, %SNMP::Info::MAU::GLOBALS, | ||||
|     %SNMP::Info::LLDP::GLOBALS, | ||||
|     %SNMP::Info::LLDP::GLOBALS, %SNMP::Info::AMAP::GLOBALS, | ||||
| ); | ||||
|  | ||||
| %FUNCS = ( | ||||
|     %SNMP::Info::Layer3::FUNCS, %SNMP::Info::MAU::FUNCS, | ||||
|     %SNMP::Info::LLDP::FUNCS, | ||||
|     %SNMP::Info::LLDP::FUNCS, %SNMP::Info::AMAP::FUNCS, | ||||
| ); | ||||
|  | ||||
| %MUNGE = ( | ||||
|     %SNMP::Info::Layer3::MUNGE, %SNMP::Info::MAU::MUNGE, | ||||
|     %SNMP::Info::LLDP::MUNGE, | ||||
|     %SNMP::Info::LLDP::MUNGE, %SNMP::Info::AMAP::MUNGE, | ||||
| ); | ||||
|  | ||||
| # use MAU-MIB for admin. duplex and admin. speed | ||||
|   | ||||
| @@ -30,6 +30,7 @@ alcatel | ||||
| alteon | ||||
| Altiga | ||||
| altiga | ||||
| AMAP | ||||
| anycast | ||||
| AOS | ||||
| ap | ||||
|   | ||||
| @@ -303,8 +303,8 @@ be assumed working. | ||||
|         protocol is enabled.  SNMP::Info supports querying Link Layer | ||||
|         Discovery Protocol (LLDP), Cisco Discovery Protocol (CDP), | ||||
|         SynOptics/Bay/Nortel/Avaya Network Management Protocol (SONMP), | ||||
|         Foundry/Brocade Discovery Protocol (FDP), and Extreme Discovery | ||||
|         Protocol (EDP).  | ||||
|         Foundry/Brocade Discovery Protocol (FDP), Extreme Discovery | ||||
|         Protocol (EDP), and Alcatel Mapping Adjacency Protocol (AMAP).  | ||||
|     </TD> | ||||
| </TR> | ||||
| <TR> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user