PythonとNAPALMによるネットワーク機器ルーティングテーブル自動取得・解析
はじめに
システムエンジニアやインフラエンジニアの皆様は、日々の運用業務や障害対応において、ネットワーク機器のルーティングテーブルを確認する機会が多くあるかと存じます。特定の宛先への経路確認、設定変更後の経路検証、複数機器間のルーティング情報比較など、ルーティングテーブルの情報はネットワークの状態を把握する上で非常に重要です。
しかし、ネットワーク機器のCLIにログインして手動でコマンドを実行し、その結果を画面上で確認・解析するのは、特に管理対象機器が多い場合や、定期的な確認が必要な場合に多大な労力を伴います。このような定型的な作業は、自動化による効率化が有効です。
本記事では、Pythonとネットワーク自動化ライブラリであるNAPALMを用いて、ネットワーク機器のルーティングテーブルを自動的に取得し、Pythonスクリプト内で解析・活用する方法について解説します。Pythonによるインフラ自動化の経験は豊富でも、ネットワーク機器の操作にはまだ慣れていない、あるいはCLI操作よりもプログラムによる制御を好むといった読者の皆様に、実践的な手法をご紹介いたします。
ルーティングテーブルとは
ルーティングテーブルは、ネットワーク機器(ルーターやL3スイッチなど)がパケットをどの宛先に送信するかを決定するために参照する情報を持ったデータベースです。具体的には、以下の情報が格納されています。
- 宛先ネットワーク/プレフィックス: パケットの宛先IPアドレスが属するネットワークまたはホスト範囲。
- 次ホップ: その宛先へパケットを転送するために次にパケットを送るべきルーターのIPアドレス、または出るべきインターフェース。
- メトリック: その経路の「コスト」を示す値。コストが低い経路が優先されます。
- 管理距離 (Administrative Distance, AD): 異なるルーティングプロトコルから学習した経路の信頼性を示す値。ADが低いプロトコルからの経路が優先されます。(例: Directly Connected < Static < eBGP < OSPF < iBGP など)
- 経路のタイプ: 経路を学習した方法(例: 直接接続、スタティックルート、OSPF、BGPなど)。
ネットワーク機器は、受信したパケットの宛先IPアドレスをルーティングテーブルと照合し、最適な経路情報に基づいてパケットを転送します。
NAPALMの概要と利点
NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) は、複数のネットワークベンダーの機器に対して、共通のAPI(メソッド)で操作を抽象化するためのPythonライブラリです。異なるベンダーの機器であっても、NAPALMが提供するメソッドを使用することで、同じPythonコードで設定の取得、変更、確認などが可能になります。
NAPALMの大きな利点は、機器から取得する設定情報や運用ステータス情報を、構造化されたデータ形式(通常はJSON互換のPythonディクショナリやリスト)で提供することです。これにより、CLIの実行結果(非構造化テキスト)を正規表現などでパースする必要がなくなり、Pythonスクリプトによるデータの解析や後続処理が非常に容易になります。
NAPALMのインストールと基本的な使い方
NAPALMはpipコマンドでインストールできます。特定のベンダー(例えばCisco IOS)に対応するためのドライバも一緒にインストールする必要があります。
pip install napalm
pip install napalm-ios
基本的な使い方は以下のようになります。まず、対象機器のOSタイプを指定してドライバをロードし、機器に接続します。
from napalm import get_network_driver
import json
# 対象機器の情報
hostname = 'your_device_hostname_or_ip'
username = 'your_username'
password = 'your_password'
optional_args = {'secret': 'your_enable_password'} # 必要に応じてenableパスワードなどを指定
# ドライバのロード (例: Cisco IOS)
driver = get_network_driver('ios')
# 機器への接続
try:
print(f"Connecting to {hostname}...")
device = driver(hostname=hostname, username=username, password=password, optional_args=optional_args)
device.open()
print("Connection successful.")
# ここに各種操作コードを記述...
except Exception as e:
print(f"Connection failed: {e}")
finally:
# 接続を閉じる
if 'device' in locals() and device.is_opened():
device.close()
print("Connection closed.")
try...except...finally
構文を使用することで、接続失敗時のエラーハンドリングや、処理完了後の接続クローズを確実に実行できます。これは、実際の運用スクリプトにおいて非常に重要です。
ルーティングテーブルデータの取得
NAPALMでは、get_network_instances()
メソッドを使用して、ルーティングテーブルを含む様々なネットワークインスタンス(VRFなど)の情報を取得できます。デフォルトのグローバルルーティングテーブルは、特別なインスタンス名 'default'
でアクセスします。
以下のコードは、ルーティングテーブルの情報を取得し、JSON形式で表示する例です。
# 上記のNAPALM接続コードの try ブロック内に記述
print("Getting routing table information...")
routing_info = device.get_network_instances()
# デフォルトインスタンスのルーティングテーブルを取得
if 'default' in routing_info and 'routing_table' in routing_info['default']:
routing_table = routing_info['default']['routing_table']
# 取得したデータを整形して表示
print(json.dumps(routing_table, indent=4))
else:
print("Routing table information not found for the default instance.")
get_network_instances()
メソッドは、ネストされた辞書構造を返します。routing_info['default']['routing_table']
にアクセスすることで、グローバルルーティングテーブルの情報が得られます。この情報は、宛先ネットワーク/プレフィックスをキーとし、その経路情報(次ホップ、プロトコルなど)を値とする辞書形式になっています。
取得データの解析と活用
ルーティングテーブルのデータがPythonの辞書として取得できれば、あとはPythonの標準的な辞書やリスト操作、あるいは条件分岐を使って必要な情報を抽出・解析できます。
特定プレフィックスの経路情報を抽出する
例えば、特定の宛先プレフィックス 192.168.1.0/24
への経路情報を確認したい場合、ルーティングテーブル辞書から該当キーの値を参照します。
# 上記のNAPALM接続およびルーティングテーブル取得コードの後ろに追記
target_prefix = '192.168.1.0/24'
if target_prefix in routing_table:
print(f"\nRoute information for {target_prefix}:")
for route in routing_table[target_prefix]:
print(f" Protocol: {route.get('protocol')}")
print(f" Next-Hop: {route.get('next_hop')}")
print(f" Outgoing Interface: {route.get('outgoing_interface')}")
print(f" Metric: {route.get('metric')}")
print(f" Administrative Distance: {route.get('preference')}")
print("-" * 10) # 複数経路がある場合のために区切り線
else:
print(f"\nNo route found for {target_prefix}.")
NAPALMの出力構造はベンダーやNAPALMのバージョンによって微細な違いがある場合があるため、キーが存在するかどうかを .get()
メソッドで確認しながらアクセスすると安全です。
デフォルトルート (0.0.0.0/0) を確認する
デフォルトルートは 0.0.0.0/0
という特別なプレフィックスで表現されます。これも同様に、ルーティングテーブルから該当キーを参照して確認できます。
# 上記のNAPALM接続およびルーティングテーブル取得コードの後ろに追記
default_route_prefix = '0.0.0.0/0'
if default_route_prefix in routing_table:
print(f"\nDefault Route ({default_route_prefix}):")
for route in routing_table[default_route_prefix]:
print(f" Next-Hop: {route.get('next_hop')}")
print(f" Outgoing Interface: {route.get('outgoing_interface')}")
print(f" Protocol: {route.get('protocol')}")
# 他に必要な情報を出力
print("-" * 10)
else:
print(f"\nNo default route found.")
複数機器間でルーティング情報を比較する(応用)
複数の機器から同じプレフィックスの経路情報を取得し、それらを比較することで、経路の冗長性や設定の整合性を検証できます。
この場合、対象となる複数の機器に対して上記のようなスクリプトを実行し、それぞれの機器で取得したルーティング情報を変数に格納します。その後、Pythonのコードでこれらの情報を比較します。例えば、特定のプレフィックスに対して、全ての機器が同じ次ホップを参照しているか、異なる次ホップを参照しているか、といった比較が可能です。
# 複数機器からの取得結果を格納する例(これは概念的なコードです)
# device1_routing_table = get_routing_table_from_device(device1_info)
# device2_routing_table = get_routing_table_from_device(device2_info)
# target_prefix = '192.168.1.0/24'
# if target_prefix in device1_routing_table and target_prefix in device2_routing_table:
# device1_routes = device1_routing_table[target_prefix]
# device2_routes = device2_routing_table[target_prefix]
# # 次ホップを比較する例
# device1_next_hops = [route.get('next_hop') for route in device1_routes if route.get('next_hop')]
# device2_next_hops = [route.get('next_hop') for route in device2_routes if route.get('next_hop')]
# if sorted(device1_next_hops) == sorted(device2_next_hops):
# print(f"Route for {target_prefix} is consistent across devices.")
# else:
# print(f"Route for {target_prefix} differs between devices.")
# print(f" Device 1 Next Hops: {device1_next_hops}")
# print(f" Device 2 Next Hops: {device2_next_hops}")
このような比較処理は、障害発生時の切り分けや、設定変更後の確認自動化に役立ちます。
実践的な考慮事項
- エラーハンドリング: ネットワーク接続エラー、認証エラー、NAPALMドライバのエラーなど、様々なエラーが発生する可能性があります。
try...except
ブロックを適切に使用し、エラー発生時には詳細なログを出力したり、適切な通知を行ったりするようにスクリプトを設計してください。 - 認証情報の管理: スクリプト内にパスワードを直書きするのではなく、環境変数、設定ファイル、あるいは専用の認証情報管理システム(Vaultなど)から安全に読み込むようにしてください。
- パフォーマンス: 大量の機器からルーティング情報を取得する場合、逐次処理では時間がかかることがあります。Pythonのマルチスレッド/マルチプロセス、あるいはNornirのような並列処理フレームワークを利用することで、処理時間を大幅に短縮できます。
- 取得結果の活用: 取得したルーティング情報は、単に表示するだけでなく、ファイルに保存して履歴管理したり、データベースや時系列データストアに格納して可視化したり、他のシステム(監視ツール、構成管理データベースなど)に連携させたりすることで、より価値の高い情報資産となります。
- 定期実行: ルーティング情報の確認を定期的に行いたい場合は、cronやWindowsタスクスケジューラ、あるいはCI/CDツール(Jenkins, GitLab CIなど)の機能を利用して、スクリプトを自動実行するように設定できます。
まとめ
本記事では、PythonとNAPALMライブラリを使用して、ネットワーク機器のルーティングテーブル情報を自動的に取得・解析する基本的な手法を解説しました。NAPALMが提供する構造化データを利用することで、ネットワーク知識が限定的でも、Pythonのスキルを活かしてルーティング情報を効率的に扱うことが可能です。
ルーティングテーブルの自動取得と解析は、ネットワークの運用監視、トラブルシューティング、設定変更後の検証など、様々な場面で役立ちます。今回ご紹介した基本的なスクリプトを基に、特定のニーズに合わせた解析や比較処理を追加することで、日々のネットワーク管理業務を大幅に効率化できるでしょう。
今後は、取得したデータをどのように活用するか(例:差分検出、可視化、他のシステムとの連携)や、より多くの機器を対象とした並列処理など、さらに実践的な応用例についても探求していただければ幸いです。