--- /dev/null
+#!/usr/bin/perl
+
+# a working NX-OS connector for RackTables by Dmitry Tejblum
+
+use strict;
+use File::FnMatch qw(:fnmatch);
+use Net::Telnet::Cisco;
+$#ARGV == 2 or die "usage";
+my $endpoint = shift @ARGV;
+my $command = shift @ARGV;
+my $workfile = shift @ARGV;
+
+$0 =~ m,^(.*)/[^/]+$,;
+my $mydir = $1;
+open(SECRETS, "<$mydir/switch.secrets.php") || die "switch.secrets.php: $!";
+my $skip = 1;
+my ($username, $password, $enable_password);
+while (<SECRETS>) {
+ chomp;
+ if ($skip && ($_ eq "# S-T-A-R-T")) {
+ $skip = 0;
+ next;
+ }
+ if (!$skip && ($_ eq "# S-T-O-P")) {
+ $skip = 1;
+ next;
+ }
+ next if ($skip);
+ next if m,^\s*(#.*)?$,;
+ my @f = split;
+ if (fnmatch($f[0], $endpoint)) {
+ $username = $f[4];
+ $password = $f[5];
+ $enable_password = $f[6];
+ last;
+ }
+}
+
+if (!defined($username)) {
+ exit(3);
+}
+
+my $session = Net::Telnet::Cisco->new('Host' => $endpoint,
+ Prompt => ' /(?m:^\015?\000?[\w.-]+(?:\(config[^\)]*\))?\s?[\$#>]\s?)/'
+);
+$session->login($username, $password);
+if ($enable_password ne "-") {
+ $session->enable($enable_password);
+}
+if ($command eq "retrieve") {
+ open(WORKFILE, ">$workfile") || die "$workfile: $!";
+ $session->cmd ('terminal length 0');
+ $session->cmd ('terminal no monitor');
+ $session->cmd ('show running-config vlan 1-4094');
+ $session->cmd ('show running-config interface');
+ my @r = $session->cmd ('show running-config vlan 1-4094');
+ print WORKFILE @r;
+ @r = $session->cmd('show running-config interface');
+ print WORKFILE @r;
+ exit(0);
+}
+if ($command eq "deploy") {
+ open(WORKFILE, "<$workfile") || die "$workfile: $!";
+ while (<WORKFILE>) {
+ $session->put($_);
+ }
+ exit(0);
+}
function nxos4Read8021QConfig ($input)
{
- return $input;
+ $ret = array
+ (
+ 'vlanlist' => array(),
+ 'portdata' => array(),
+ );
+ $procfunc = 'nxos4ScanTopLevel';
+ foreach (explode ("\n", $input) as $line)
+ $procfunc = $procfunc ($ret, $line);
+ return $ret;
+}
+
+function nxos4ScanTopLevel (&$work, $line)
+{
+ $matches = array();
+ switch (TRUE)
+ {
+ case (preg_match ('@^interface ((Ethernet)[[:digit:]]+(/[[:digit:]]+)*)$@', $line, $matches)):
+ $matches[1] = preg_replace ('@^Ethernet(.+)$@', 'e\\1', $matches[1]);
+ $work['current'] = array ('port_name' => $matches[1]);
+ return 'nxos4PickSwitchportCommand';
+ case (preg_match ('@^vlan ([[:digit:]]+)$@', $line, $matches)):
+ $work['vlanlist'][] = $matches[1];
+ return 'nxos4PickVLANs';
+ default:
+ return __FUNCTION__; // continue scan
+ }
+}
+
+function nxos4PickVLANs (&$work, $line)
+{
+ switch (TRUE)
+ {
+ case ($line == ''): // end of VLAN list
+ return 'nxos4ScanTopLevel';
+ case (preg_match ('@^vlan ([[:digit:]]+)$@', $line, $matches)):
+ $work['vlanlist'][] = $matches[1];
+ default: // VLAN name or any other text
+ return __FUNCTION__;
+ }
+}
+
+function nxos4PickSwitchportCommand (&$work, $line)
+{
+ if ($line == '') // end of interface section
+ {
+ // fill in defaults
+ // below assumes "system default switchport" mode set on the device
+ if (!array_key_exists ('mode', $work['current']))
+ $work['current']['mode'] = 'access';
+ // save work, if it makes sense
+ switch ($work['current']['mode'])
+ {
+ case 'access':
+ if (!array_key_exists ('access vlan', $work['current']))
+ $work['current']['access vlan'] = 1;
+ $work['portdata'][$work['current']['port_name']] = array
+ (
+ 'mode' => 'access',
+ 'allowed' => array ($work['current']['access vlan']),
+ 'native' => $work['current']['access vlan'],
+ );
+ break;
+ case 'trunk':
+ if (!array_key_exists ('trunk native vlan', $work['current']))
+ $work['current']['trunk native vlan'] = 1;
+ if (!array_key_exists ('trunk allowed vlan', $work['current']))
+ $work['current']['trunk allowed vlan'] = range (VLAN_MIN_ID, VLAN_MAX_ID);
+ // Having configured VLAN as "native" doesn't mean anything
+ // as long as it's not listed on the "allowed" line.
+ $effective_native = in_array
+ (
+ $work['current']['trunk native vlan'],
+ $work['current']['trunk allowed vlan']
+ ) ? $work['current']['trunk native vlan'] : 0;
+ $work['portdata'][$work['current']['port_name']] = array
+ (
+ 'mode' => 'trunk',
+ 'allowed' => $work['current']['trunk allowed vlan'],
+ 'native' => $effective_native,
+ );
+ break;
+ default:
+ // dot1q-tunnel, dynamic, private-vlan --- skip these
+ }
+ unset ($work['current']);
+ return 'nxos4ScanTopLevel';
+ }
+ // not yet
+ $matches = array();
+ switch (TRUE)
+ {
+ case (preg_match ('@^ switchport mode (.+)$@', $line, $matches)):
+ $work['current']['mode'] = $matches[1];
+ break;
+ case (preg_match ('@^ switchport access vlan (.+)$@', $line, $matches)):
+ $work['current']['access vlan'] = $matches[1];
+ break;
+ case (preg_match ('@^ switchport trunk native vlan (.+)$@', $line, $matches)):
+ $work['current']['trunk native vlan'] = $matches[1];
+ break;
+ case (preg_match ('@^ switchport trunk allowed vlan add (.+)$@', $line, $matches)):
+ $work['current']['trunk allowed vlan'] = array_merge
+ (
+ $work['current']['trunk allowed vlan'],
+ iosParseVLANString ($matches[1])
+ );
+ break;
+ case (preg_match ('@^ switchport trunk allowed vlan (.+)$@', $line, $matches)):
+ $work['current']['trunk allowed vlan'] = iosParseVLANString ($matches[1]);
+ break;
+ default: // suppress warning on irrelevant config clause
+ }
+ return __FUNCTION__;
}
// Scan given array and return the key, which addresses the first item