0

0

使用Netmiko自动化Cisco路由器配置与故障排除

碧海醫心

碧海醫心

发布时间:2025-10-14 09:39:21

|

577人浏览过

|

来源于php中文网

原创

使用Netmiko自动化Cisco路由器配置与故障排除

本文详细介绍了如何利用python的netmiko库自动化配置cisco路由器,包括ssh连接建立、接口配置(如loopback和物理接口)、ospf路由协议配置以及acl设置。文章重点解析了netmiko `send_config_set` 方法的内部机制,强调无需手动输入 `enable` 和 `configure terminal` 命令,并提供了配置保存、差异比较及常见故障排除的实用指南。

1. Netmiko简介与自动化优势

Netmiko是一个强大的Python库,基于Paramiko构建,专门用于简化网络设备的SSH/Telnet连接和配置管理。它抽象了底层连接细节,提供了统一的API来发送命令、配置设备、获取输出等,极大地提高了网络自动化脚本的开发效率和可维护性。通过Netmiko,工程师可以轻松实现批量配置、配置审计、状态收集等任务,减少手动操作的错误率,并加速网络部署和故障排除。

2. NetSSH连接设置与故障排除

成功自动化配置的第一步是建立稳定的SSH连接。Netmiko通过 ConnectHandler 类管理连接。

2.1 建立连接参数

以下是建立连接所需的基本参数字典:

device = {
    'device_type': 'cisco_ios',  # 指定设备类型为Cisco IOS
    'host': '192.168.56.101',     # 目标设备的IP地址
    'username': 'your_username', # 登录用户名
    'password': 'your_password', # 登录密码
    'secret': 'cisco',           # enable模式密码
    'port': 22,                  # SSH默认端口
    'timeout': 30,               # 连接超时时间(秒)
}
  • device_type: 关键参数,Netmiko会根据此参数加载相应的驱动,自动处理设备特定的提示符和命令。对于Cisco IOS设备,通常使用 'cisco_ios'。如果需要Telnet,则使用 'cisco_ios_telnet'。
  • secret: 用于进入特权模式(enable 模式)的密码。Netmiko在需要时会自动使用此密码。
  • timeout: 连接或读取数据时的超时时间。如果遇到 Timed-out reading channel, data not available 错误,可能是网络延迟或设备响应慢导致,可以适当增加此值,但过高可能导致脚本长时间阻塞。

2.2 连接过程与异常处理

使用 with 语句管理 ConnectHandler 实例是最佳实践,它能确保连接在任务完成后自动关闭,即使发生异常。

from netmiko import ConnectHandler
import getpass
import logging

logging.basicConfig(level=logging.INFO)

def main():
    host = '192.168.56.101'
    username = input('请输入您的用户名: ')
    password = getpass.getpass('请输入您的密码: ')
    secret = 'cisco' # enable模式密码

    device = {
        'device_type': 'cisco_ios',
        'host': host,
        'username': username,
        'password': password,
        'secret': secret,
        'port': 22,
        'timeout': 30, # 适当调整超时时间
    }

    try:
        with ConnectHandler(**device) as net_connect:
            logging.info('连接已建立')
            # 后续配置操作
            # ...
    except Exception as e:
        logging.error(f'发生错误: {e}')
    logging.info('连接已结束')

if __name__ == "__main__":
    main()

故障排除提示:

  • Timed-out reading channel, data not available.: 检查网络连通性、设备SSH服务是否开启、防火墙是否阻挡。尝试增加 timeout 参数值。
  • Authentication (password) successful! 后仍超时: 这通常意味着Netmiko成功登录,但在尝试进入特权模式或读取初始提示符时遇到问题。确保 secret 密码正确,并且设备没有额外的登录提示。
  • net_connect.disconnect() 未定义: 如果使用 with ConnectHandler(...) as net_connect: 结构,Netmiko会自动处理连接关闭,无需显式调用 net_connect.disconnect()。在 with 块外部调用 net_connect.disconnect() 会导致 NameError。

3. Cisco路由器配置:核心机制与实践

Netmiko的 send_config_set() 方法是发送配置命令的核心。

3.1 核心问题解析:Netmiko的配置模式处理

关键点: 使用 net_connect.send_config_set() 方法时,Netmiko会自动处理进入和退出特权模式 (enable) 和全局配置模式 (configure terminal) 的过程。因此,在配置命令列表中,无需包含 en 或 conf t 等命令

错误示例(不推荐):

loopback_config = [
    'en\n'        # Netmiko会自动处理
    'conf t\n'    # Netmiko会自动处理
    'interface Loopback0\n',
    'ip address 192.168.57.101 255.255.255.0\n',
    'exit\n'
]

这种做法会导致命令重复发送,可能引起设备报错或不必要的延迟。

正确示例:

无线网络修复工具(电脑wifi修复工具) 3.8.5官方版
无线网络修复工具(电脑wifi修复工具) 3.8.5官方版

无线网络修复工具是一款联想出品的小工具,旨在诊断并修复计算机的无线网络问题。它全面检查硬件故障、驱动程序错误、无线开关设置、连接设置和路由器配置。 该工具支持 Windows XP、Win7 和 Win10 系统。请注意,在运行该工具之前,应拔出电脑的网线,以确保准确诊断和修复。 使用此工具,用户可以轻松找出并解决 WiFi 问题,无需手动排查故障。它提供了一键式解决方案,即使对于非技术用户也易于使用。

下载
loopback_config = [
    'interface Loopback0',
    'ip address 192.168.57.101 255.255.255.0',
    'no shutdown' # 确保接口开启
]

send_config_set() 会将这些命令逐一发送到设备,并在必要时自动进入和退出配置模式。

3.2 路由器接口与OSPF协议配置

以下是如何配置Loopback接口、物理接口和OSPF协议的示例。

def configure_device(net_connect):
    """
    向Cisco设备发送一系列配置命令。
    """
    # Loopback接口配置
    loopback_config = [
        'interface Loopback0',
        'ip address 192.168.57.101 255.255.255.0',
        'no shutdown'
    ]

    # 物理接口GigabitEthernet0/0配置
    interface0_config = [
        'interface GigabitEthernet0/0',
        'ip address 192.168.58.101 255.255.255.0',
        'no shutdown'
    ]

    # 物理接口GigabitEthernet0/1配置
    interface1_config = [
        'interface GigabitEthernet0/1',
        'ip address 192.168.59.101 255.255.255.0',
        'no shutdown'
    ]

    # 扩展访问控制列表 (ACL) 配置
    acl_config = [
        'ip access-list extended MY_ACL',
        'permit ip 192.168.56.130 0.0.0.255 any', # 注意:这里是通配符掩码
        'deny ip any any',
        'exit' # 退出ACL配置模式
    ]

    # OSPF协议配置
    # 假设router-id为192.168.57.101 (Loopback0的IP)
    ospf_config = [
        'router ospf 1', # 进程ID为1
        'router-id 192.168.57.101', # 建议使用Loopback接口IP作为Router ID
        'network 192.168.57.0 0.0.0.255 area 0', # 宣告Loopback0所在网络
        'network 192.168.58.0 0.0.0.255 area 0', # 宣告GigabitEthernet0/0所在网络
        'network 192.168.59.0 0.0.0.255 area 0', # 宣告GigabitEthernet0/1所在网络
        'passive-interface Loopback0', # 仅示例,根据实际需求决定是否配置
        'exit' # 退出OSPF配置模式
    ]

    # 合并所有配置命令
    all_configs = loopback_config + interface0_config + interface1_config + acl_config + ospf_config

    logging.info('正在发送配置命令...')
    output = net_connect.send_config_set(all_configs)
    print(output) # 打印设备返回的配置结果
    logging.info('配置命令发送完成。')

注意事项:

  • ACL中的掩码是通配符掩码(wildcard mask),与IP地址的子网掩码不同。例如,255.255.255.0 对应的通配符掩码是 0.0.0.255。
  • OSPF配置中的 network 命令需要指定网络地址和通配符掩码,以及所属的区域ID。
  • no shutdown 命令对于新配置的接口是必不可少的,以确保接口处于激活状态。

4. 配置的保存、验证与差异比较

自动化配置不仅要能发送命令,还要能验证配置是否成功并进行审计。

4.1 获取并保存运行配置

配置完成后,通常需要获取设备的运行配置并保存到本地。

def save_config_to_file(config, filename):
    """将配置内容保存到本地文件。"""
    with open(filename, 'w') as config_file:
        config_file.write(config)
    logging.info(f'配置已保存到 {filename}')

# 在主函数中调用
# ...
running_configuration = net_connect.send_command('show running-config')
local_config_file_name = 'running_config_backup.txt'
save_config_to_file(running_configuration, local_config_file_name)
logging.info(f'运行配置已保存到 {local_config_file_name}')
# ...

4.2 配置差异比较

difflib 库可以用来比较两份配置文件的差异,这对于配置审计和故障排除非常有用。

import difflib

def show_differences(config1, config2, name1='配置1', name2='配置2'):
    """显示两份配置之间的差异。"""
    difference = difflib.Differ()
    diff = list(difference.compare(config1.splitlines(), config2.splitlines()))

    logging.warning(f'以下是 {name1} 和 {name2} 之间的差异:')
    for line in diff:
        if line.startswith('- '):
            logging.info(f'- (仅在 {name1} 中): {line[2:]}')
        elif line.startswith('+ '):
            logging.info(f'+ (仅在 {name2} 中): {line[2:]}')
        elif line.startswith('? '):
            pass # 忽略difflib生成的问号行
        else:
            logging.debug(f'  (相同): {line[2:]}') # 相同行只在debug级别显示

将 show_differences 应用于比较当前运行配置和本地保存的配置:

# ... 在主函数中
# 假设我们已经有了 running_configuration 和 local_config
# 例如,可以先保存一份基线配置为 'baseline_config.txt'
# 然后用 'show running-config' 获得的配置与 'baseline_config.txt' 比较

try:
    with open(local_config_file_name, 'r') as local_config_file:
        local_config = local_config_file.read()

    if running_configuration and local_config:
        if running_configuration == local_config:
            logging.info('运行配置与本地配置一致。')
        else:
            logging.warning('运行配置与本地配置不匹配。')
            show_differences(local_config, running_configuration, 
                             name1='本地保存配置', name2='当前运行配置')
    else:
        logging.error('未能获取配置进行比较。')

except FileNotFoundError:
    logging.error(f'本地配置文件 ({local_config_file_name}) 未找到。')
# ...

5. 完整示例代码

结合上述所有功能,以下是一个完整的Netmiko自动化Cisco路由器配置脚本示例:

import logging
import getpass
import difflib
from netmiko import ConnectHandler

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def save_config_to_file(config, filename):
    """将配置内容保存到本地文件。"""
    with open(filename, 'w') as config_file:
        config_file.write(config)
    logging.info(f'配置已保存到 {filename}')

def show_differences(config1, config2, name1='配置1', name2='配置2'):
    """显示两份配置之间的差异。"""
    difference = difflib.Differ()
    diff = list(difference.compare(config1.splitlines(), config2.splitlines()))

    logging.warning(f'以下是 {name1} 和 {name2} 之间的差异:')
    for line in diff:
        if line.startswith('- '):
            logging.info(f'- (仅在 {name1} 中): {line[2:]}')
        elif line.startswith('+ '):
            logging.info(f'+ (仅在 {name2} 中): {line[2:]}')
        elif line.startswith('? '):
            pass # 忽略difflib生成的问号行
        else:
            # logging.debug(f'  (相同): {line[2:]}') # 相同行只在debug级别显示
            pass

def configure_device(net_connect):
    """
    向Cisco设备发送一系列配置命令,包括Loopback、物理接口、ACL和OSPF。
    """
    logging.info('正在准备配置命令...')
    # Loopback接口配置
    loopback_config = [
        'interface Loopback0',
        'ip address 192.168.57.101 255.255.255.0',
        'no shutdown'
    ]

    # 物理接口GigabitEthernet0/0配置
    interface0_config = [
        'interface GigabitEthernet0/0',
        'ip address 192.168.58.101 255.255.255.0',
        'no shutdown'
    ]

    # 物理接口GigabitEthernet0/1配置
    interface1_config = [
        'interface GigabitEthernet0/1',
        'ip address 192.168.59.101 255.255.255.0',
        'no shutdown'
    ]

    # 扩展访问控制列表 (ACL) 配置
    acl_config = [
        'ip access-list extended MY_ACL',
        'permit ip 192.168.56.130 0.0.0.255 any',
        'deny ip any any',
        'exit'
    ]

    # OSPF协议配置
    ospf_config = [
        'router ospf 1',
        'router-id 192.168.57.101',
        'network 192.168.57.0 0.0.0.255 area 0',
        'network 192.168.58.0 0.0.0.255 area 0',
        'network 192.168.59.0 0.0.0.255 area 0',
        # 'passive-interface Loopback0', # 根据实际需求决定是否配置
        'exit'
    ]

    # 合并所有配置命令
    all_configs = loopback_config + interface0_config + interface1_config + acl_config + ospf_config

    logging.info('正在发送配置命令到设备...')
    output = net_connect.send_config_set(all_configs)
    print("--- 设备配置输出开始 ---")
    print(output)
    print("--- 设备配置输出结束 ---")
    logging.info('配置命令发送完成。')

def main():
    host = '192.168.56.101' # 目标Cisco路由器的IP地址
    username = input('请输入您的用户名: ')
    password = getpass.getpass('请输入您的密码: ')
    secret = getpass.getpass('请输入enable模式密码 (通常为cisco): ') # enable模式密码

    choice = input('您想使用telnet还是ssh连接? (telnet/ssh): ').lower()
    if choice == 'telnet':
        device_type = 'cisco_ios_telnet'
        port = 23
    elif choice == 'ssh':
        device_type = 'cisco_ios'
        port = 22
    else:
        logging.error('无效选择 - 请输入 telnet 或 ssh。')
        return

    device = {
        'device_type': device_type,
        'host': host,
        'username': username,
        'password': password,
        'secret': secret,
        'port': port,
        'timeout': 60, # 增加超时时间以应对网络延迟
    }

    try:
        logging.info(f'尝试连接到设备 {host} ({device_type})...')
        with ConnectHandler(**device) as net_connect:
            logging.info('连接已成功建立。')

            # 发送配置命令
            configure_device(net_connect)

            # 获取并保存运行配置
            logging.info('正在获取设备的运行配置...')
            running_configuration = net_connect.send_command('show running-config')
            local_config_file_name = 'running_config_after_automation.txt'
            save_config_to_file(running_configuration, local_config_file_name)

            # 比较配置 (可选,可以与一个基线配置比较)
            # 假设我们有一个名为 'baseline_config.txt' 的文件作为基线
            baseline_config_file_name = 'baseline_config.txt'
            try:
                with open(baseline_config_file_name, 'r') as baseline_file:
                    baseline_config = baseline_file.read()
                logging.info(f'正在将当前运行配置与基线配置 ({baseline_config_file_name}) 进行比较...')
                show_differences(baseline_config, running_configuration, 
                                 name1='基线配置', name2='当前运行配置')
            except FileNotFoundError:
                logging.warning(f'基线配置文件 ({baseline_config_file_name}) 未找到,跳过差异比较。')

            # 也可以再次读取刚刚保存的配置进行比较,验证文件保存是否正确
            try:
                with open(local_config_file_name, 'r') as saved_file:
                    saved_config = saved_file.read()
                if running_configuration == saved_config:
                    logging.info('当前运行配置已成功保存到本地文件并保持一致。')
                else:
                    logging.error('警告:运行配置与保存到本地文件的内容不完全一致。')
            except FileNotFoundError:
                logging.error(f'保存的本地配置文件 ({local_config_file_name}) 未找到

相关文章

路由优化大师
路由优化大师

路由优化大师是一款及简单的路由器设置管理软件,其主要功能是一键设置优化路由、屏广告、防蹭网、路由器全面检测及高级设置等,有需要的小伙伴快来保存下载体验吧!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1179

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

215

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2137

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

27

2026.01.19

Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

248

2025.11.14

golang channel相关教程
golang channel相关教程

本专题整合了golang处理channel相关教程,阅读专题下面的文章了解更多详细内容。

344

2025.11.17

PHP 命令行脚本与自动化任务开发
PHP 命令行脚本与自动化任务开发

本专题系统讲解 PHP 在命令行环境(CLI)下的开发与应用,内容涵盖 PHP CLI 基础、参数解析、文件与目录操作、日志输出、异常处理,以及与 Linux 定时任务(Cron)的结合使用。通过实战示例,帮助开发者掌握使用 PHP 构建 自动化脚本、批处理工具与后台任务程序 的能力。

44

2025.12.13

php环境变量如何设置
php环境变量如何设置

本合集详细讲解PHP环境变量的设置方法,涵盖Windows、Linux及常见服务器环境配置技巧,助你快速掌握环境变量的正确配置。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php图片如何上传
php图片如何上传

本合集涵盖PHP图片上传的核心方法、安全处理及常见问题解决方案,适合初学者与进阶开发者。阅读专题下面的文章了解更多详细内容。

2

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.7万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号