Net::SNMPをつかってCisco機器からCDP情報を収集(3)
先日のつづき
Net::SNMPをつかって取得した値で人間が直接読めない形式で返答してきたoidがある。
例えば、
1.3.6.1.4.1.9.9.23.1.2.1.1.3.1.2 1 1.3.6.1.4.1.9.9.23.1.2.1.1.4.1.2 0xc0a801fc 1.3.6.1.4.1.9.9.23.1.2.1.1.9.1.2 ) 1.3.6.1.4.1.9.9.23.1.2.1.1.12.1.2 3
など。これらについてはそれぞれMIBファイルには(一部省略)
CdpCacheEntry ::= SEQUENCE { cdpCacheAddressType CiscoNetworkProtocol, cdpCacheAddress CiscoNetworkAddress, cdpCacheCapabilities OCTET STRING, cdpCacheDuplex INTEGER, }
CiscoNetworkProtocol,CiscoNetworkAddress,OCTET STRING,INTEGER で値を返すと指定してある。それぞれが何を意味するかは、さらにMIBファイルをたどる必要がある。
- CiscoNetworkProtocol
- CiscoNetworkAddress
これらはCISCO-CDP-MIBファイルのヘッダー部に以下記載あるため、さらに別のMIBファイルをたどらなくてはならない。
CISCO-CDP-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, Integer32, Unsigned32 FROM SNMPv2-SMI MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF TruthValue, DisplayString, TimeStamp FROM SNMPv2-TC ciscoMgmt FROM CISCO-SMI CiscoNetworkProtocol, CiscoNetworkAddress FROM CISCO-TC VlanIndex FROM CISCO-VTP-MIB ifIndex FROM IF-MIB ;
つまりは、CISCO-TC MIBに書いてあるから、そっちを読めってことになる。
こんどは、CISCO-TC MIBファイルをさらに確認する。(一部省略)
CiscoNetworkProtocol ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "Represents the different types of network layer protocols." SYNTAX INTEGER { ip(1), decnet(2), pup(3), (省略) http(25), unknown(65535) } CiscoNetworkAddress ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "Represents a network layer address. The length and format of the address is protocol dependent as follows: ip 4 octets decnet 2 octets (省略) SYNTAX OCTET STRING
なので
1.3.6.1.4.1.9.9.23.1.2.1.1.3.1.2 1 =>(1)なのでIP 1.3.6.1.4.1.9.9.23.1.2.1.1.4.1.2 0xc0a801fc =>4octets(32ビット)表記のIPアドレス192.168.1.252
0xc0a801fc →
0xc0 = 192 , 0xa8 = 168 , 0x01 = 1 , 0xfc = 252
Net::SNMPをつかってCisco機器からCDP情報を収集(2)
前日からのつづき。
今日はPerlからはちょっと離れてMIBファイルについて
oid 1.3.6.1.4.1.9.9.23.1.2.1(cdpCacheTable)のMIBファイル
cdpCacheTable OBJECT-TYPE SYNTAX SEQUENCE OF CdpCacheEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The (conceptual) table containing the cached information obtained via receiving CDP messages." ::= { cdpCache 1 } cdpCacheEntry OBJECT-TYPE SYNTAX CdpCacheEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "An entry (conceptual row) in the cdpCacheTable, containing the information received via CDP on one interface from one device. Entries appear when a CDP advertisement is received from a neighbor device. Entries disappear when CDP is disabled on the interface, or globally." INDEX { cdpCacheIfIndex, cdpCacheDeviceIndex } ::= { cdpCacheTable 1 } CdpCacheEntry ::= SEQUENCE { cdpCacheIfIndex Integer32, cdpCacheDeviceIndex Integer32, cdpCacheAddressType CiscoNetworkProtocol, cdpCacheAddress CiscoNetworkAddress, cdpCacheVersion DisplayString, cdpCacheDeviceId DisplayString, cdpCacheDevicePort DisplayString, cdpCachePlatform DisplayString, cdpCacheCapabilities OCTET STRING, cdpCacheVTPMgmtDomain DisplayString, cdpCacheNativeVLAN VlanIndex, cdpCacheDuplex INTEGER, cdpCacheApplianceID Unsigned32, cdpCacheVlanID Unsigned32, cdpCachePowerConsumption Unsigned32, cdpCacheMTU Unsigned32, cdpCacheSysName DisplayString, cdpCacheSysObjectID OBJECT IDENTIFIER, cdpCachePrimaryMgmtAddrType CiscoNetworkProtocol, cdpCachePrimaryMgmtAddr CiscoNetworkAddress, cdpCacheSecondaryMgmtAddrType CiscoNetworkProtocol, cdpCacheSecondaryMgmtAddr CiscoNetworkAddress, cdpCachePhysLocation DisplayString, cdpCacheLastChange TimeStamp }
先日のPerlの出力結果(見やすくするため一部省略)
同じ色は上記のMIBファイル内の同じEntry項目を示す
1.3.6.1.4.1.9.9.23.1.2.1.1.3.1.2 1 1.3.6.1.4.1.9.9.23.1.2.1.1.3.3.1 1 1.3.6.1.4.1.9.9.23.1.2.1.1.4.1.2 0xc0a801fc 1.3.6.1.4.1.9.9.23.1.2.1.1.4.3.1 0xc0a802fe 1.3.6.1.4.1.9.9.23.1.2.1.1.5.1.2 Cisco IOS Software, C181X Soft 1.3.6.1.4.1.9.9.23.1.2.1.1.5.3.1 Cisco IOS Software, 7200 Soft 1.3.6.1.4.1.9.9.23.1.2.1.1.6.1.2 C1812J 1.3.6.1.4.1.9.9.23.1.2.1.1.6.3.1 R2 1.3.6.1.4.1.9.9.23.1.2.1.1.7.1.2 FastEthernet0 1.3.6.1.4.1.9.9.23.1.2.1.1.7.3.1 FastEthernet1/0 1.3.6.1.4.1.9.9.23.1.2.1.1.8.1.2 Cisco 1812-J 1.3.6.1.4.1.9.9.23.1.2.1.1.8.3.1 Cisco 7206VXR 1.3.6.1.4.1.9.9.23.1.2.1.1.9.1.2 ) 1.3.6.1.4.1.9.9.23.1.2.1.1.9.3.1 0x00000001 1.3.6.1.4.1.9.9.23.1.2.1.1.11.1.2 0 1.3.6.1.4.1.9.9.23.1.2.1.1.11.3.1 0 1.3.6.1.4.1.9.9.23.1.2.1.1.12.1.2 3 1.3.6.1.4.1.9.9.23.1.2.1.1.12.3.1 3
例として
1.3.6.1.4.1.9.9.23.1.2.1.1.8.3.1 は
cdpCacheTable(1.3.6.1.4.1.9.9.23.1.2.1)
cdpCacheEntry(.1)
cdpCachePlatform(.8)
cdpCacheIfIndex(.3)
cdpCacheDeviceIndex(.1)
と読み解く
後ろの(.3.1)がINDEX{ cdpCacheIfIndex, cdpCacheDeviceIndex }に該当する
この行はINDEX(.3.1)のcdpCachePlatform(.8)がCisco 7206VXRであることを示す。
MIBファイル上はcdpCacheTableには24項目のデータが指定されているが、実際に機器が返答しているのはindexを除くと9項目だけとわかる。古いIOSだからしかたがないのかも。最新のIOSを使えばもっと情報が取得できるのかもしれない。
R1#show cdp neighbors Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge S - Switch, H - Host, I - IGMP, r - Repeater Device ID Local Intrfce Holdtme Capability Platform Port ID C1812J Fas 0/0 121 R S I 1812-J Fas 0 R2 Fas 1/0 179 R 7206VXR Fas 1/0 R1#
Local Intrfce→cdpCacheIfIndex
Holdtme→cdpCacheTableでは取得できない様子
Net::SNMPをつかってCisco機器からCDP情報を収集(1)
Net::SNMP のサンプルスクリプトを参考に実行してみた。
CDP情報はoid 1.3.6.1.4.1.9.9.23.1.2.1(cdpCacheTable)にて取得できる。
oid検索にはCisco社のWebサイトSNMP Object Navigator内の「SEARCH」とかで検索。
ついてにCISCO-CDP-MIBファイルもダウンロード。
あとでどのoidが何の値を示しているか確認につかう。
use strict; use warnings; #use utf8; #use Encode; use Net::SNMP qw(:snmp); # oid_lex_sort()を使うためにInport指定 use Data::Dumper; my $OID_cdpCacheTable = '1.3.6.1.4.1.9.9.23.1.2.1'; my ( $session, $error ) = Net::SNMP->session( -hostname => '192.168.1.253', #実際のIPアドレスにあわせる -community => 'public', #実際のCommunity名にあわせる ); if ( !defined $session ) { printf "ERROR: %s.\n", $error; exit 1; } #結果は oid => 値 のハッシュリファレンスが返る my $result = $session->get_table( -baseoid => $OID_cdpCacheTable, ); if ( !defined $result ) { printf "ERROR: %s\n", $session->error(); $session->close(); exit 1; } #print Dumper($result); #print "cdpCacheTable\n$OID_cdpCacheTable\n"; #oid_lex_sort()にてoid値を数字順にソートしてハッシュ内容を表示 foreach my $get_oid ( oid_lex_sort( keys %$result ) ) { print "$get_oid\t\t $result->{$get_oid}\n"; } $session->close();
出力結果
1.3.6.1.4.1.9.9.23.1.2.1.1.3.1.2 1 1.3.6.1.4.1.9.9.23.1.2.1.1.3.3.1 1 1.3.6.1.4.1.9.9.23.1.2.1.1.4.1.2 0xc0a801fc 1.3.6.1.4.1.9.9.23.1.2.1.1.4.3.1 0xc0a802fe 1.3.6.1.4.1.9.9.23.1.2.1.1.5.1.2 Cisco IOS Software, C181X Software (C181X-ADVENTERPRISEK9-M), Version 12.4(22)T, RELEASE SOFTWARE (fc1) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2008 by Cisco Systems, Inc. Compiled Thu 09-Oct-08 20:27 by prod_rel_team 1.3.6.1.4.1.9.9.23.1.2.1.1.5.3.1 Cisco IOS Software, 7200 Software (C7200-IS-M), Version 12.4(21), RELEASE SOFTWARE (fc1) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2008 by Cisco Systems, Inc. Compiled Thu 10-Jul-08 11:36 by prod_rel_team 1.3.6.1.4.1.9.9.23.1.2.1.1.6.1.2 C1812J 1.3.6.1.4.1.9.9.23.1.2.1.1.6.3.1 R2 1.3.6.1.4.1.9.9.23.1.2.1.1.7.1.2 FastEthernet0 1.3.6.1.4.1.9.9.23.1.2.1.1.7.3.1 FastEthernet1/0 1.3.6.1.4.1.9.9.23.1.2.1.1.8.1.2 Cisco 1812-J 1.3.6.1.4.1.9.9.23.1.2.1.1.8.3.1 Cisco 7206VXR 1.3.6.1.4.1.9.9.23.1.2.1.1.9.1.2 ) 1.3.6.1.4.1.9.9.23.1.2.1.1.9.3.1 0x00000001 1.3.6.1.4.1.9.9.23.1.2.1.1.11.1.2 0 1.3.6.1.4.1.9.9.23.1.2.1.1.11.3.1 0 1.3.6.1.4.1.9.9.23.1.2.1.1.12.1.2 3 1.3.6.1.4.1.9.9.23.1.2.1.1.12.3.1 3
R1#show cdp neighbors Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge S - Switch, H - Host, I - IGMP, r - Repeater Device ID Local Intrfce Holdtme Capability Platform Port ID C1812J Fas 0/0 121 R S I 1812-J Fas 0 R2 Fas 1/0 179 R 7206VXR Fas 1/0 R1#
Win32::GUI::GetOpenFileName(ファイルダイアログ)をためす(2)
Win32::GUI::GetOpenFileNameをつかわない例
CLIアプリにも関わらずファイル選択はGUIで行いたい時に使用した。
当時はutf-8フラグなど意識せずshifjisにてファイル保存している。
- Win32::OLEを使用したパターン
use strict; use warnings; use Win32; use Win32::OLE; Win32::MsgBox("使用した\nアドレスリストを選択", 0 | MB_ICONINFORMATION, "Check"); my $filter = 'IPアドレス リスト|*.txt|全てのファイル (*.*)|*.*'; my $IntDir = 'C:\\test'; my $objFD = Win32::OLE->new("UserAccounts.CommonDialog"); $objFD->{'Filter'} = $filter; $objFD->{'InitialDir'} = $IntDir; $objFD->ShowOpen(); my $filename = $objFD->{FileName}; Win32::MsgBox($filename, 0 | MB_ICONINFORMATION, "チェック");
- Tkxを使用したパターン。最近のActive Perlは最初からこのモジュールが入っている
use warnings; use strict; use Tkx; use Encode qw(decode encode); use Win32; BEGIN { if ( $^O eq 'MSWin32' ) { require Win32::Console; Win32::Console::Free(); } } my $jp_sjis = 'テキスト Files'; ## TkxはUTF8でないと文字化けする。 my $jp_utf8 = decode ( 'shiftjis' , $jp_sjis); my $jp_title = decode ( 'shiftjis' , 'チェック'); my $types = [ [$jp_utf8, ['.txt', '.text']], ['MP3 Files', ['.mp3', '.m4a'] ], ['All Files', '*', ], ]; my $mw = Tkx::widget->new("."); $mw->g_wm_withdraw; my $filename = Tkx::tk___getOpenFile(-filetypes=>$types,-parent=>$mw); Tkx::tk___messageBox(-message=> $filename,-title => $jp_title ,-parent => $mw); ## $filenameはUTF8 で戻ってくるので sjisへ変換 $filename = encode ( 'cp932' , $filename ); Win32::MsgBox($filename, 0 | MB_ICONINFORMATION, "チェック");
Tkxは記述方法がよくわからない...
Win32::GUI::GetOpenFileName(ファイルダイアログ)をためす(1)
ファイル名を取得するダイアログ表示のためにWin32::GUI::GetOpenFileNameを使用する
参考にした情報
- 初歩の初歩〜プログミング〜@ ウィキ
- Win32::GUIのdemoフォルダー内BitmapScroll.pl
- Win32::GUI::Reference::MethodsのGetOpenFileName
ファイルダイアログ部分のみ抽出
use Cwd; my $dir_name = cwd; # ファイルパスが '/'で取得される $dir_name =~ s/\//\\/g; # ファイルパスが '/' だとダメなので '\'に変更 my $file = Win32::GUI::GetOpenFileName( -directory => $dir_name, -title => encode( cp932 => "ログファイル選択" ), -filter => [ encode( cp932 => "ログ(*.txt;*.log)" ) => '*.txt;*.log', 'All files' => '*.*', ], -owner => $main, );
以下全部
use strict; use warnings; use utf8; use Encode; use Win32::GUI(); use Cwd; my $DOS = Win32::GUI::GetPerlWindow(); Win32::GUI::Hide($DOS); my $con = 1; my $main = Win32::GUI::Window->new( -name => 'Main', -width => 240, -height => 100, -text => encode( cp932 => "☆ほげほげ" ), ); my $label1 = $main->AddLabel( -name => 'LB1', -text => " ", -width => 240, ); my $label2 = $main->AddLabel( -name => 'LB2', -text => encode( cp932 => "出力" ), -width => 240, -pos => [ 0, 60 ], ); $main->AddButton( -name => "Button1", -text => encode( cp932 => "表示変更" ), -width => 80, -pos => [ 0, 15 ], ); $main->AddButton( -name => "Button2", -text => encode( cp932 => "Log表示" ), -width => 80, -pos => [ 80, 15 ], ); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; } sub Button1_Click { if ($con) { $label1->Change( -text => encode( cp932 => "こんばんわ" ) ); $con = 0; } else { $label1->Change( -text => encode( cp932 => "こんにちわ" ) ); $con = 1; } return 0; } #Log読み込み処理 sub Button2_Click { my $dir_name = cwd; # ファイルパスが '/'で取得される $dir_name =~ s/\//\\/g; # ファイルパスが '/' だとダメなので '\'に変更 my $file = Win32::GUI::GetOpenFileName( -directory => $dir_name, -title => encode( cp932 => "ログファイル選択" ), -filter => [ encode( cp932 => "ログ(*.txt;*.log)" ) => '*.txt;*.log', 'All files' => '*.*', ], -owner => $main, ); #ファイルがなにも選択されなかった場合 if ( !$file ) { return 0; } #ファイル読み込み&表示 open my $fh, '<', $file or die qq/Can't open file "$file" : $!/; while ( my $line = <$fh> ) { $label2->Change( -text => $line ); Win32::GUI::DoEvents(); #重い処理中にウィンドーが固まらないため } $label2->Change( -text => encode( cp932 => "終了" ) ); return 0; }
Win32::GUI::ThreadUtilsコード入力をためす(3)
ThreadUtilsを使っていない例。
The Win32::GUI F.A.Q.には以下記載がある。
Why does my window seem to freeze when my program is in a loop?
Put a call to DoEvents() inside the loop. This will ensure that all queued messages are processed before going on with the loop:
何故か今日はちゃんと動いた。これがうまく動かなかったから、Win32::GUI::ThreadUtilsを使ったのだけど...
use strict; use warnings; use utf8; use Encode; use Win32::GUI(); my $DOS = Win32::GUI::GetPerlWindow(); Win32::GUI::Hide($DOS); my $con = 1; my $main = Win32::GUI::Window->new( -name => 'Main', -width => 240, -height => 100, -text => encode( cp932 => "☆ほげほげ" ), ); my $label1 = $main->AddLabel( -name => 'LB1', -text => " ", -width => 240, ); my $label2 = $main->AddLabel( -name => 'LB2', -text => encode( cp932 => "出力" ), -width => 240, -pos => [ 0, 60 ], ); $main->AddButton( -name => "Button1", -text => encode( cp932 => "表示変更" ), -width => 80, -pos => [ 0, 15 ], ); $main->AddButton( -name => "Button2", -text => encode( cp932 => "実行" ), -width => 80, -pos => [ 80, 15 ], ); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; } #重い処理中もボタンがクリックできる. sub Button1_Click { if ($con) { $label1->Change( -text => encode( cp932 => "こんばんわ" ) ); $con = 0; } else { $label1->Change( -text => encode( cp932 => "こんにちわ" ) ); $con = 1; } return 0; } ##重い処理_開始 sub Button2_Click { #重い処理 my $file = 'test.log'; open my $fh, '<', $file or die qq/Can't open file "$file" : $!/; while ( my $line = <$fh> ) { $label2->Change( -text => $line ); #FAQにしたがって以下追加 Win32::GUI::DoEvents(); } $label2->Change( -text => encode( cp932 => "終了" ) ); return 0; }
Win32::GUI::ThreadUtilsコード入力をためす(2)
別スレッド処理終了後に、親スレッドへ通知するパターン
use strict; use warnings; use utf8; use threads; use Encode; use Win32::GUI(); use Win32::GUI::ThreadUtils; my $DOS = Win32::GUI::GetPerlWindow(); Win32::GUI::Hide($DOS); my $con = 1; my $main = Win32::GUI::Window->new( -name => 'Main', -width => 240, -height => 100, -text => encode( cp932 => "☆ほげほげ" ), ); my $label1 = $main->AddLabel( -name => 'LB1', -text => " ", -width => 240, ); my $label2 = $main->AddLabel( -name => 'LB2', -text => encode( cp932 => "出力" ), -width => 240, -pos => [ 0, 60 ], ); $main->AddButton( -name => "Button1", -text => encode( cp932 => "表示変更" ), -width => 80, -pos => [ 0, 15 ], ); $main->AddButton( -name => "Button2", -text => encode( cp932 => "実行" ), -width => 80, -pos => [ 80, 15 ], ); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; } #重い処理中にも「Button1(表示変更)」が可能 sub Button1_Click { if ($con) { $label1->Change( -text => encode( cp932 => "こんばんわ" ) ); $con = 0; } else { $label1->Change( -text => encode( cp932 => "こんにちわ" ) ); $con = 1; } return 0; } ##重い処理_開始 sub Button2_Click { #処理終了後に実施されるサブルーチンを登録 my $comms = $main->AttachComms( \&boss ); #別スレッド(重い処理)の設定及び実行 my $thr = threads->create( \&worker, $comms ); $thr->detach(); return 0; } #重い(時間掛かる)処理の終了後に呼び出される sub boss { my $self = shift; $self->LB2->Change( -text => encode( cp932 => "終了" ) ); } #重い(時間掛かる)処理(別スレッドにて実施) sub worker { my $SetProgress = shift; # 実際の処理(省略) #処理終了を親スレッドへ通知してる? $SetProgress->Call(); }