思路:
本文是网络设备集成测试/组网测试自动化配置脚本的示例。
主要诉求是能够自适应拓扑变化和组网方式变化。
例中使用的是cisco模拟器,IOS版本是12.4。
本例中演示了域内MPLS/BGP VPN组网环境中P网络的OSPF和BGP的自动配置。
自适应效果举例:本例中 dut2做PE、dut3做RR,只需修改配置文件,脚本可以自适应。 添加dut4连接到dut2上,做为一个新的PE,只需修改配置文件,脚本可以自适应。
本例中要求设备已经连好线,接口已经up,配置好了接口ip地址,也配置好了loopback地址。
源代码:
auto_config.py:
# python3.8
# coding=utf-8
# author=liuyifan
'''
网络设备集成测试/组网测试自动化配置脚本的示例。本例中使用的是cisco模拟器,IOS版本是12.4。
主要诉求是能够自适应拓扑变化和组网方式变化。
本例中演示了域内MPLS/BGP VPN组网环境中P网络的OSPF和BGP的自动配置。拓扑为dut1-dut2-dut3。
比如本例中
dut2做PE、dut3做RR,只需修改配置文件,脚本可以自适应。
添加dut4连接到dut2上,做为一个新的PE,只需修改配置文件,脚本可以自适应。
本例中要求设备已经连好线,接口已经up,配置好了接口ip地址,也配置好了loopback地址。
'''
import re
import ipaddress
from netmiko import Netmiko
import config
# 字符串表示的dut转换成dut对象。例如将字符串'dut3'转换成列表元素duts[2]
def dut_str_to_dut_list_member(dut_str):
m = re.match(r'^dut(\d+)$', dut_str)
index = int(m.group(1))-1
return eval('duts[%d]' % index)
class DUT():
def __init__(self, dut):
self.c = Netmiko(**dut)
# self.connected_networks是所有直连网络的列表,例如["1.1.0.0/16","1.2.0.0/16"]
self.connected_networks = self.get_networks_from_connected_routes()
# self.loopback是有两个元素的列表,第一个元素是loopback接口的IP地址,第二个元素是loopback接口的编号,比如["1.0.0.1",1]
self.loopback = self.get_loopback_from_connected_routes()
# 返回从show ip route connected的反馈信息中提取出的网络组成的列表,比如["1.1.0.0/16","1.2.0.0/16"]。
def get_networks_from_connected_routes(self):
networks = []
for line in self.c.send_command("show ip route connected").splitlines():
print(line)
m = re.match('^C\s+(\d+\.\d+\.\d+\.\d+/\d+)\s',line)
if m:
networks.append(m.group(1))
return networks
# 返回从show ip route connected的反馈信息中提取出的第一个loopback接口的地址和接口编号,比如["1.0.0.1",1]。
def get_loopback_from_connected_routes(self):
for line in self.c.send_command("show ip route connected").splitlines():
print(line)
m = re.match('^C\s+(\d+\.\d+\.\d+\.\d+/\d+)\s.*Loopback(\d+)$', line)
if m:
return m.group(1).split('/')[0], int(m.group(2))
# 配置ospf
# 这些网络对应的接口启用ospf
def config_ospf(self,process_id=1):
commands = []
commands.append("router ospf %d" % process_id)
loopback_address = self.loopback[0]
commands.append("router-id %s" % loopback_address)
for network in self.connected_networks:
n = ipaddress.IPv4Network(network)
commands.append("network %s %s area 0" % (n.network_address, n.hostmask))
print(self.c.send_config_set(commands))
# 配置bgp邻居。peer是一个DUT的实例
def config_ibgp(self, peer, vpnv4_activate=False, ipv4_rr_client=False, vpnv4_rr_client=False):
commands = []
commands.append("router bgp 1")
local_loopback_address = self.loopback[0]
commands.append("bgp router-id %s" % local_loopback_address)
peer_loopback_address = peer.loopback[0]
commands.append("neighbor %s remote-as 1" % peer_loopback_address)
local_loopback_number = self.loopback[1]
commands.append("neighbor %s update-source Loopback %d" % (peer_loopback_address, local_loopback_number))
if ipv4_rr_client:
commands.append("neighbor %s route-reflector-client" % peer_loopback_address)
if vpnv4_activate:
commands.append("address-family vpnv4 unicast")
commands.append("neighbor %s activate" % peer_loopback_address)
if vpnv4_rr_client:
commands.append("neighbor %s route-reflector-client" % peer_loopback_address)
print(self.c.send_config_set(commands))
if __name__ == '__main__':
duts = []
for i in range(0, config.dut_number):
duts.append(DUT(config.duts[i]))
# 所有设备上配置ospf
for dut in duts:
dut.config_ospf()
# 每一台PE设备上配置到所有RR的ibgp邻居
for pe in config.PE:
pe = dut_str_to_dut_list_member(pe)
for rr in config.RR:
rr = dut_str_to_dut_list_member(rr)
pe.config_ibgp(rr, vpnv4_activate=True)
# 每一台RR设备上配置到所有PE的ibgp邻居
for rr in config.RR:
rr = dut_str_to_dut_list_member(rr)
for pe in config.PE:
pe = dut_str_to_dut_list_member(pe)
rr.config_ibgp(pe, vpnv4_activate=True, vpnv4_rr_client=True, ipv4_rr_client=True)
config.py:
'''
设置设备登陆所需的信息
设置设备在组网环境中的角色
'''
# 设置dut的数目
dut_number=3
# 设置dut登录信息
duts = []
dut1 = {
'ip': '127.0.0.1',
'port': 2001,
'device_type': 'cisco_ios_telnet',
}
duts.append(dut1)
dut2 = {
'ip': '127.0.0.1',
'port': 2002,
'device_type': 'cisco_ios_telnet',
}
duts.append(dut2)
dut3 = {
'ip': '127.0.0.1',
'port': 2003,
'device_type': 'cisco_ios_telnet',
}
duts.append(dut3)
PE = ['dut1', 'dut3']
RR = ['dut2']
执行输出:
50.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C 50.0.1.0/24 is directly connected, FastEthernet1/0
C 50.0.0.1/32 is directly connected, Loopback1
50.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C 50.0.1.0/24 is directly connected, FastEthernet1/0
C 50.0.0.1/32 is directly connected, Loopback1
50.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C 50.0.2.0/24 is directly connected, FastEthernet1/1
C 50.0.0.2/32 is directly connected, Loopback50
C 50.0.3.0/24 is directly connected, FastEthernet2/0
C 50.0.1.0/24 is directly connected, FastEthernet1/0
50.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C 50.0.2.0/24 is directly connected, FastEthernet1/1
C 50.0.0.2/32 is directly connected, Loopback50
50.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C 50.0.2.0/24 is directly connected, FastEthernet1/0
C 50.0.0.3/32 is directly connected, Loopback50
50.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C 50.0.2.0/24 is directly connected, FastEthernet1/0
C 50.0.0.3/32 is directly connected, Loopback50
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
R1(config)#router ospf 1
R1(config-router)#router-id 50.0.0.1
R1(config-router)#network 50.0.1.0 0.0.0.255 area 0
R1(config-router)#network 50.0.0.1 0.0.0.0 area 0
R1(config-router)#end
R1#
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
R2(config)#router ospf 1
R2(config-router)#router-id 50.0.0.2
R2(config-router)#network 50.0.2.0 0.0.0.255 area 0
R2(config-router)#network 50.0.0.2 0.0.0.0 area 0
R2(config-router)#network 50.0.3.0 0.0.0.255 area 0
R2(config-router)#network 50.0.1.0 0.0.0.255 area 0
R2(config-router)#end
R2#
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
R3(config)#router ospf 1
R3(config-router)#router-id 50.0.0.3
R3(config-router)#network 50.0.2.0 0.0.0.255 area 0
R3(config-router)#network 50.0.0.3 0.0.0.0 area 0
R3(config-router)#end
R3#
R1#configure terminal
Enter configuration commands, o
R1(config)#router bgp 1
R1(config-router)#bgp router-id 50.0.0.1
R1(config-router)#neighbor 50.0.0.2 remote-as 1
R1(config-router)#neighbor 50.0.0.2 update-source Loopback 1
R1(config-router)#address-family vpnv4 unicast
R1(config-router-af)#neighbor 50.0.0.2 activate
R1(config-router-af)#end
R1#
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
R3(config)#router bgp 1
R3(config-router)#bgp router-id 50.0.0.3
R3(config-router)#neighbor 50.0.0.2 remote-as 1
R3(config-router)#neighbor 50.0.0.2 update-source Loopback 50
R3(config-router)#address-family vpnv4 unicast
R3(config-router-af)#neighbor 50.0.0.2 activate
R3(config-router-af)#end
R3#
R2#configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
R2(config)#router bgp 1
R2(config-router)#bgp router-id 50.0.0.2
R2(config-router)#neighbor 50.0.0.1 remote-as 1
R2(config-router)#neighbor 50.0.0.1 update-source Loopback 50
R2(config-router)#neighbor 50.0.0.1 route-reflector-client
R2(config-router)#address-family vpnv4 unicast
R2(config-router-af)#neighbor 50.0.0.1 activate
R2(config-router-af)#neighbor 50.0.0.1 route-reflector-client
R2(config-router-af)#end
R2#
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
R2(config)#router bgp 1
R2(config-router)#bgp router-id 50.0.0.2
R2(config-router)#neighbor 50.0.0.3 remote-as 1
R2(config-router)#neighbor 50.0.0.3 update-source Loopback 50
R2(config-router)#neighbor 50.0.0.3 route-reflector-client
R2(config-router)#address-family vpnv4 unicast
R2(config-router-af)#neighbor 50.0.0.3 activate
R2(config-router-af)#neighbor 50.0.0.3 route-reflector-client
R2(config-router-af)#end
R2#