Friday, April 24, 2015

ipv4 over ipv6

I will use the next topology created using gns3.

First, interfaces and OSPFv3 need to be configured. What is really good about IPv6 that you don't have to configure all the addresses by hand. All you need to do is to enable it on any interface and it will use link-local address. Like this:

int Fa0/0
  ipv6 enable
  ipv6 ospf 1 area 0
!

This configuration is enough for OSPFv3 to form adjacency. However to build a tunnel it is better to have a couple of persistent addresses. I used addresses 1::1/128 and 3::3/128 for loopback interfaces on routers R1 and R3 respectfully. Next step is to configure tunnel itself:

interface Tunnel0
  ip address 10.10.10.1 255.255.255.0
  ip ospf 2 area 0
  tunnel source Loopback0
  tunnel destination 3::3
  tunnel mode ipv6
end

This is configuration of R1 tunnel interface, on R3 it is basically the same. Here we have some options about packet encapsulation:

tunnel mode ipv6
uses "Generic packet tunneling in IPv6", which means that IPv4 is simply enveloped in IPv6. Here is a screenshot of ICMP packet delivered through the tunnel:

tunnel mode gre ipv6
is another possible option, which uses GRE encapsulation between IPv4 and IPv6 headers. It can be seen on another captured packet:

Tuesday, April 7, 2015

How to add interface descriptions to Zabbix



For those who are unsatisfied with default Zabbix discoveries. There is a great way to have both interface Name (i.e. Gi1/1/2) and Alias (i.e. Link to SuperServer) together in the name name of an item itself. This solution was tested on Cisco, Extreme Networks, Dlink and Force10 devices. It uses standard SNMP OID so probably would work on every device.

To make this type of discovery it is essential to use external source of discovered data. It can be done using any language, in this case I decided to use perl. The idea of a script is to get information from a device and return it in JSON format, like this:

{
    "data" : [
        {
            "{#ALIAS}" : "server-2",
            "{#NAME}" : "Gi1/0/7",
            "{#INDEX}" : "10107"
        },
        {
            "{#ALIAS}" : "server-1",
            "{#NAME}" : "Gi1/0/2",
            "{#INDEX}" : "10102"
        },
        {
            "{#ALIAS}" : "provider-1",
            "{#NAME}" : "Te1/1/2",
            "{#INDEX}" : "10402"
        }
    ]
}

For Zabbix to use the script it should be located in External scripts directory (check your Zabbix server conf file, it depends on distribution) and, of course, to have an executable bit set. Script should NOT return any additional data, except for a correct JSON. Then create new template with name "Network interfaces" or something like that, and add a discovery with the setting:


External check means that Zabbix will use a script from an external scripts folder;
Key is a name of a script and parameters. In this case there are two parameters: {HOST.IP}, which is global variable and will take the IP address from an interface of a host this template will attached to, and {$SNMP_COMMUNITY1} is a global macros, defined under Administration -> General -> Macros. As a result, the final command Zabbix will call will look something like "interface-discovery.pl 192.168.1.254 public"

Then add items to the new discovery, for Speed, traffic, statuses and so on. There are a lot of useful examples here:



In SNMP OID field you can use numeric OID, if you do not have MIBs installed. Good ideas to monitor:

IF-MIB::ifHCInOctets - 1.3.6.1.2.1.31.1.1.1.6 - incoming traffic
IF-MIB::ifHCOutOctets - 1.3.6.1.2.1.31.1.1.1.10 - outgoing traffic
IF-MIB::ifAdminStatus - 1.3.6.1.2.1.2.2.1.7 - admin status of interface
IF-MIB::ifAlias - 1.3.6.1.2.1.31.1.1.1.18 - description of interface
IF-MIB::ifOperStatus - 1.3.6.1.2.1.2.2.1.8 - operational status of interface
IF-MIB::ifInErrors - 1.3.6.1.2.1.2.2.1.14 - incoming errors on interface
IF-MIB::ifOutErrors - 1.3.6.1.2.1.2.2.1.20 - outgoing errors on interface

Another good suggestions you may find at cisco site.

Just add ".{#INDEX}" in the end of any OID. Here is a list of items I use for my system:





Create triggers with names that would actually mean something to you, and with expressions you like:





And voila! Newly created items will look like this:




New triggers with adequate names:





And, as a bonus, interface names and aliases on graphs:





Of course, descriptions change over time, but it is not a problem, actually. You just need to set up your discovery to run periodically. I use period of 1 day and it works great. Zabbix realizes that its not a new item but the old one with a new name based on the item key, and just changes name, preserving all the history. So this method will work if you will keep keys persistent. For example, I use interface name as a unique part of a key. After periodical discovery finishes, it will update name of items everywhere - in triggers and graphs.

And here is my script. I am not a programmer so it definitely has some problems. Your suggestions are welcome!


#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;
use Net::SNMP;
use JSON;

open(STDERR, '>', '/tmp/int_results_error.log') or warn "Can't open log";

die("Usage: $0 ipaddress community\n") unless ( $#ARGV == 1 ); #we expect to see 2 arguments

my $oid_ifName = '1.3.6.1.2.1.31.1.1.1.1';
my $oid_ifAlias = '1.3.6.1.2.1.31.1.1.1.18';
my $oid_ifType = '1.3.6.1.2.1.2.2.1.3';

my ($session, $error) = Net::SNMP->session(
    -hostname => $ARGV[0],
    -community => $ARGV[1],
    -version => 'snmpv2c',
);

die("ERROR: $error\n") unless ( $session );

my $names = $session->get_table(-baseoid => $oid_ifName,);
die("ERROR getting names: ".$session->error()."\n") unless ( $names );
foreach ( keys %$names) {
    my $new_key;
    ( $new_key = $_ ) =~ s/.*\.//;
    $names->{ $new_key } = delete $names->{$_};
}

my $aliases = $session->get_table(-baseoid => $oid_ifAlias,);
die("ERROR getting aliases: ".$session->error()."\n") unless ( $aliases );
foreach ( keys %$aliases) {
    my $new_key;
    ( $new_key = $_ ) =~ s/.*\.//;
    $aliases->{ $new_key } = delete $aliases->{$_};
    $aliases->{ $new_key } =~ s/[^\x20-\x7E]//g;
}

my $types = $session->get_table(-baseoid => $oid_ifType,);
die("ERROR getting types: ".$session->error()."\n") unless ( $types );
foreach ( keys %$types) {
    my $new_key;
    ( $new_key = $_ ) =~ s/.*\.//;
    $types->{ $new_key } = delete $types->{$_};
}

my @interfaces;
foreach my $index ( keys %$names ) { #for each found port
    no warnings 'uninitialized';

    # hacks
    next if ( $names->{$index} =~ /--(Unc|C)ontrolled/ ); # hack to exempt 4500 strange interfaces
    next if ( $types->{$index} != 6 ); # exempt everything but physical interfaces (type = 6)
    next if ( $names->{$index} =~ /^NDE/ ); #hack to exempt NetFlow interfaces of c6k
    if ( $names->{$index} =~ /^(\d:|)\d{2}$/ ) {
        my $nport;
        ( $nport = $names->{$index} ) =~ s/^(\d:|)(\d+)$/$2/;
        next if ( $nport > 48); # hack to exempt ports 49-62 on extreme switches
    }
    # /hacks

    push(@interfaces, {"{#INDEX}" => $index, "{#NAME}" => $names->{$index}, "{#ALIAS}" => $aliases->{$index}});
}

print JSON::XS->new->utf8->pretty(1)->encode( { "data" => \@interfaces });

END { $session->close() if ( $session ); }