mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-27 15:23:39 +00:00
Merge pull request #4710 from ashish12pant/ecmp_tests
tests: Add ecmp test cases
This commit is contained in:
commit
db42a62a97
@ -375,7 +375,7 @@ def test_static_routes(request):
|
||||
# Verifying RIB routes
|
||||
dut = 'r3'
|
||||
protocol = 'bgp'
|
||||
next_hop = '10.0.0.2'
|
||||
next_hop = ['10.0.0.2', '10.0.0.5']
|
||||
result = verify_rib(tgen, 'ipv4', dut, input_dict, next_hop=next_hop,
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
|
664
tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json
Executable file
664
tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json
Executable file
@ -0,0 +1,664 @@
|
||||
{
|
||||
"address_types": [
|
||||
"ipv4",
|
||||
"ipv6"
|
||||
],
|
||||
"ipv4base": "10.0.0.0",
|
||||
"ipv4mask": 24,
|
||||
"ipv6base": "fd00::",
|
||||
"ipv6mask": 64,
|
||||
"link_ip_start": {
|
||||
"ipv4": "10.0.0.0",
|
||||
"v4mask": 24,
|
||||
"ipv6": "fd00::",
|
||||
"v6mask": 64
|
||||
},
|
||||
"lo_prefix": {
|
||||
"ipv4": "1.0.",
|
||||
"v4mask": 32,
|
||||
"ipv6": "2001:DB8:F::",
|
||||
"v6mask": 128
|
||||
},
|
||||
"routers": {
|
||||
"r1": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r2-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r2": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r1-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link2": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link3": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link4": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link5": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link6": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link7": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link8": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link9": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link10": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link11": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link12": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link13": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link14": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link15": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link16": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link17": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link18": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link19": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link20": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link21": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link22": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link23": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link24": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link25": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link26": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link27": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link28": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link29": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link30": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link31": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link32": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "200",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link2": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link3": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link4": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link5": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link6": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link7": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link8": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link9": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link10": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link11": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link12": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link13": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link14": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link15": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link16": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link17": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link18": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link19": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link20": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link21": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link22": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link23": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link24": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link25": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link26": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link27": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link28": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link29": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link30": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link31": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link32": {
|
||||
"next_hop_self": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link2": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link3": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link4": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link5": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link6": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link7": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link8": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link9": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link10": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link11": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link12": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link13": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link14": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link15": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link16": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link17": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link18": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link19": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link20": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link21": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link22": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link23": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link24": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link25": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link26": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link27": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link28": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link29": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link30": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link31": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link32": {
|
||||
"next_hop_self": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r2-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link2": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link3": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link4": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link5": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link6": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link7": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link8": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link9": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link10": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link11": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link12": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link13": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link14": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link15": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link16": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link17": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link18": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link19": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link20": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link21": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link22": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link23": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link24": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link25": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link26": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link27": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link28": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link29": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link30": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link31": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link32": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "300",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ebgp": 32
|
||||
},
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {},
|
||||
"r3-link2": {},
|
||||
"r3-link3": {},
|
||||
"r3-link4": {},
|
||||
"r3-link5": {},
|
||||
"r3-link6": {},
|
||||
"r3-link7": {},
|
||||
"r3-link8": {},
|
||||
"r3-link9": {},
|
||||
"r3-link10": {},
|
||||
"r3-link11": {},
|
||||
"r3-link12": {},
|
||||
"r3-link13": {},
|
||||
"r3-link14": {},
|
||||
"r3-link15": {},
|
||||
"r3-link16": {},
|
||||
"r3-link17": {},
|
||||
"r3-link18": {},
|
||||
"r3-link19": {},
|
||||
"r3-link20": {},
|
||||
"r3-link21": {},
|
||||
"r3-link22": {},
|
||||
"r3-link23": {},
|
||||
"r3-link24": {},
|
||||
"r3-link25": {},
|
||||
"r3-link26": {},
|
||||
"r3-link27": {},
|
||||
"r3-link28": {},
|
||||
"r3-link29": {},
|
||||
"r3-link30": {},
|
||||
"r3-link31": {},
|
||||
"r3-link32": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ebgp": 32
|
||||
},
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {},
|
||||
"r3-link2": {},
|
||||
"r3-link3": {},
|
||||
"r3-link4": {},
|
||||
"r3-link5": {},
|
||||
"r3-link6": {},
|
||||
"r3-link7": {},
|
||||
"r3-link8": {},
|
||||
"r3-link9": {},
|
||||
"r3-link10": {},
|
||||
"r3-link11": {},
|
||||
"r3-link12": {},
|
||||
"r3-link13": {},
|
||||
"r3-link14": {},
|
||||
"r3-link15": {},
|
||||
"r3-link16": {},
|
||||
"r3-link17": {},
|
||||
"r3-link18": {},
|
||||
"r3-link19": {},
|
||||
"r3-link20": {},
|
||||
"r3-link21": {},
|
||||
"r3-link22": {},
|
||||
"r3-link23": {},
|
||||
"r3-link24": {},
|
||||
"r3-link25": {},
|
||||
"r3-link26": {},
|
||||
"r3-link27": {},
|
||||
"r3-link28": {},
|
||||
"r3-link29": {},
|
||||
"r3-link30": {},
|
||||
"r3-link31": {},
|
||||
"r3-link32": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
674
tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json
Executable file
674
tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json
Executable file
@ -0,0 +1,674 @@
|
||||
{
|
||||
"address_types": [
|
||||
"ipv4",
|
||||
"ipv6"
|
||||
],
|
||||
"ipv4base": "10.0.0.0",
|
||||
"ipv4mask": 24,
|
||||
"ipv6base": "fd00::",
|
||||
"ipv6mask": 64,
|
||||
"link_ip_start": {
|
||||
"ipv4": "10.0.0.0",
|
||||
"v4mask": 24,
|
||||
"ipv6": "fd00::",
|
||||
"v6mask": 64
|
||||
},
|
||||
"lo_prefix": {
|
||||
"ipv4": "1.0.",
|
||||
"v4mask": 32,
|
||||
"ipv6": "2001:DB8:F::",
|
||||
"v6mask": 128
|
||||
},
|
||||
"routers": {
|
||||
"r1": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r2-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r2": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r1-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link2": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link3": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link4": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link5": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link6": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link7": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link8": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link9": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link10": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link11": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link12": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link13": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link14": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link15": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link16": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link17": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link18": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link19": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link20": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link21": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link22": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link23": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link24": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link25": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link26": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link27": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link28": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link29": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link30": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link31": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link32": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link2": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link3": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link4": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link5": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link6": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link7": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link8": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link9": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link10": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link11": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link12": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link13": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link14": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link15": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link16": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link17": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link18": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link19": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link20": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link21": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link22": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link23": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link24": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link25": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link26": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link27": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link28": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link29": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link30": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link31": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link32": {
|
||||
"next_hop_self": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"redistribute": [
|
||||
{
|
||||
"redist_type": "static"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link2": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link3": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link4": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link5": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link6": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link7": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link8": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link9": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link10": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link11": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link12": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link13": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link14": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link15": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link16": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link17": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link18": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link19": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link20": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link21": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link22": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link23": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link24": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link25": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link26": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link27": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link28": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link29": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link30": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link31": {
|
||||
"next_hop_self": true
|
||||
},
|
||||
"r2-link32": {
|
||||
"next_hop_self": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"redistribute": [
|
||||
{
|
||||
"redist_type": "static"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r2-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link2": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link3": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link4": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link5": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link6": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link7": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link8": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link9": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link10": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link11": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link12": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link13": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link14": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link15": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link16": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link17": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link18": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link19": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link20": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link21": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link22": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link23": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link24": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link25": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link26": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link27": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link28": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link29": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link30": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link31": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r2-link32": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ibgp": 32
|
||||
},
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {},
|
||||
"r3-link2": {},
|
||||
"r3-link3": {},
|
||||
"r3-link4": {},
|
||||
"r3-link5": {},
|
||||
"r3-link6": {},
|
||||
"r3-link7": {},
|
||||
"r3-link8": {},
|
||||
"r3-link9": {},
|
||||
"r3-link10": {},
|
||||
"r3-link11": {},
|
||||
"r3-link12": {},
|
||||
"r3-link13": {},
|
||||
"r3-link14": {},
|
||||
"r3-link15": {},
|
||||
"r3-link16": {},
|
||||
"r3-link17": {},
|
||||
"r3-link18": {},
|
||||
"r3-link19": {},
|
||||
"r3-link20": {},
|
||||
"r3-link21": {},
|
||||
"r3-link22": {},
|
||||
"r3-link23": {},
|
||||
"r3-link24": {},
|
||||
"r3-link25": {},
|
||||
"r3-link26": {},
|
||||
"r3-link27": {},
|
||||
"r3-link28": {},
|
||||
"r3-link29": {},
|
||||
"r3-link30": {},
|
||||
"r3-link31": {},
|
||||
"r3-link32": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ibgp": 32
|
||||
},
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {},
|
||||
"r3-link2": {},
|
||||
"r3-link3": {},
|
||||
"r3-link4": {},
|
||||
"r3-link5": {},
|
||||
"r3-link6": {},
|
||||
"r3-link7": {},
|
||||
"r3-link8": {},
|
||||
"r3-link9": {},
|
||||
"r3-link10": {},
|
||||
"r3-link11": {},
|
||||
"r3-link12": {},
|
||||
"r3-link13": {},
|
||||
"r3-link14": {},
|
||||
"r3-link15": {},
|
||||
"r3-link16": {},
|
||||
"r3-link17": {},
|
||||
"r3-link18": {},
|
||||
"r3-link19": {},
|
||||
"r3-link20": {},
|
||||
"r3-link21": {},
|
||||
"r3-link22": {},
|
||||
"r3-link23": {},
|
||||
"r3-link24": {},
|
||||
"r3-link25": {},
|
||||
"r3-link26": {},
|
||||
"r3-link27": {},
|
||||
"r3-link28": {},
|
||||
"r3-link29": {},
|
||||
"r3-link30": {},
|
||||
"r3-link31": {},
|
||||
"r3-link32": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
817
tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
Executable file
817
tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
Executable file
@ -0,0 +1,817 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2019 by VMware, Inc. ("VMware")
|
||||
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
|
||||
# ("NetDEF") in this file.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
Following tests are covered to test ecmp functionality on EBGP.
|
||||
1. Verify routes installed as per maximum-paths configuration (8/16/32)
|
||||
2. Disable/Shut selected paths nexthops and verify other next are installed in
|
||||
the RIB of DUT. Enable interfaces and verify RIB count.
|
||||
3. Verify BGP table and RIB in DUT after clear BGP routes and neighbors.
|
||||
4. Verify routes are cleared from BGP and RIB table of DUT when
|
||||
redistribute static configuration is removed.
|
||||
5. Shut BGP neigbors one by one and verify BGP and routing table updated
|
||||
accordingly in DUT
|
||||
6. Delete static routes and verify routers are cleared from BGP table and RIB
|
||||
of DUT.
|
||||
7. Verify routes are cleared from BGP and RIB table of DUT when advertise
|
||||
network configuration is removed.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import pytest
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, '../'))
|
||||
sys.path.append(os.path.join(CWD, '../../'))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from mininet.topo import Topo
|
||||
|
||||
from lib.common_config import (
|
||||
start_topology, write_test_header,
|
||||
write_test_footer,
|
||||
verify_rib, create_static_routes, check_address_types,
|
||||
interface_status, reset_config_on_routers
|
||||
)
|
||||
from lib.topolog import logger
|
||||
from lib.bgp import (
|
||||
verify_bgp_convergence, create_router_bgp,
|
||||
clear_bgp_and_verify)
|
||||
from lib.topojson import build_topo_from_json, build_config_from_json
|
||||
|
||||
# Reading the data from JSON File for topology and configuration creation
|
||||
jsonFile = "{}/ebgp_ecmp_topo2.json".format(CWD)
|
||||
|
||||
try:
|
||||
with open(jsonFile, "r") as topoJson:
|
||||
topo = json.load(topoJson)
|
||||
except IOError:
|
||||
assert False, "Could not read file {}".format(jsonFile)
|
||||
|
||||
# Global variables
|
||||
NEXT_HOPS = {"ipv4": [], "ipv6": []}
|
||||
INTF_LIST_R3 = []
|
||||
INTF_LIST_R2 = []
|
||||
NETWORK = {"ipv4": "11.0.20.1/32", "ipv6": "1::/64"}
|
||||
NEXT_HOP_IP = {"ipv4": "10.0.0.1", "ipv6": "fd00::1"}
|
||||
BGP_CONVERGENCE = False
|
||||
|
||||
|
||||
class CreateTopo(Topo):
|
||||
"""
|
||||
Test topology builder.
|
||||
|
||||
* `Topo`: Topology object
|
||||
"""
|
||||
|
||||
def build(self, *_args, **_opts):
|
||||
"""Build function."""
|
||||
tgen = get_topogen(self)
|
||||
|
||||
# Building topology from json file
|
||||
build_topo_from_json(tgen, topo)
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"""
|
||||
Sets up the pytest environment.
|
||||
|
||||
* `mod`: module name
|
||||
"""
|
||||
global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
|
||||
global ADDR_TYPES
|
||||
|
||||
testsuite_run_time = time.asctime(time.localtime(time.time()))
|
||||
logger.info("Testsuite start time: {}".format(testsuite_run_time))
|
||||
logger.info("=" * 40)
|
||||
|
||||
logger.info("Running setup_module to create topology")
|
||||
|
||||
# This function initiates the topology build with Topogen...
|
||||
tgen = Topogen(CreateTopo, mod.__name__)
|
||||
|
||||
# Starting topology, create tmp files which are loaded to routers
|
||||
# to start deamons and then start routers
|
||||
start_topology(tgen)
|
||||
|
||||
# Creating configuration from JSON
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
# Don't run this test if we have any failure.
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
# tgen.mininet_cli()
|
||||
# Api call verify whether BGP is converged
|
||||
ADDR_TYPES = check_address_types()
|
||||
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, ("setup_module :Failed \n Error:"
|
||||
" {}".format(BGP_CONVERGENCE))
|
||||
|
||||
link_data = [val for links, val in
|
||||
topo["routers"]["r2"]["links"].iteritems()
|
||||
if "r3" in links]
|
||||
for adt in ADDR_TYPES:
|
||||
NEXT_HOPS[adt] = [val[adt].split("/")[0] for val in link_data]
|
||||
if adt == "ipv4":
|
||||
NEXT_HOPS[adt] = sorted(
|
||||
NEXT_HOPS[adt], key=lambda x: int(x.split(".")[2]))
|
||||
elif adt == "ipv6":
|
||||
NEXT_HOPS[adt] = sorted(
|
||||
NEXT_HOPS[adt], key=lambda x: int(x.split(':')[-3], 16))
|
||||
|
||||
INTF_LIST_R2 = [val["interface"].split("/")[0] for val in link_data]
|
||||
INTF_LIST_R2 = sorted(INTF_LIST_R2, key=lambda x: int(x.split("eth")[1]))
|
||||
|
||||
link_data = [val for links, val in
|
||||
topo["routers"]["r3"]["links"].iteritems()
|
||||
if "r2" in links]
|
||||
INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
|
||||
INTF_LIST_R3 = sorted(INTF_LIST_R3, key=lambda x: int(x.split("eth")[1]))
|
||||
|
||||
# STATIC_ROUTE = True
|
||||
logger.info("Running setup_module() done")
|
||||
|
||||
|
||||
def teardown_module():
|
||||
"""
|
||||
Teardown the pytest environment.
|
||||
|
||||
* `mod`: module name
|
||||
"""
|
||||
|
||||
logger.info("Running teardown_module to delete topology")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
# Stop toplogy and Remove tmp files
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def static_or_nw(tgen, topo, tc_name, test_type, dut):
|
||||
|
||||
if test_type == "redist_static":
|
||||
input_dict_static = {
|
||||
dut: {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK["ipv4"],
|
||||
"next_hop": NEXT_HOP_IP["ipv4"]
|
||||
},
|
||||
{
|
||||
"network": NETWORK["ipv6"],
|
||||
"next_hop": NEXT_HOP_IP["ipv6"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Configuring static route on router %s", dut)
|
||||
result = create_static_routes(tgen, input_dict_static)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_2 = {
|
||||
dut: {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Configuring redistribute static route on router %s", dut)
|
||||
result = create_router_bgp(tgen, topo, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
elif test_type == "advertise_nw":
|
||||
input_dict_nw = {
|
||||
dut: {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"advertise_networks": [
|
||||
{"network": NETWORK["ipv4"]}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"advertise_networks": [
|
||||
{"network": NETWORK["ipv6"]}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Advertising networks %s %s from router %s",
|
||||
NETWORK["ipv4"], NETWORK["ipv6"], dut)
|
||||
result = create_router_bgp(tgen, topo, input_dict_nw)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
|
||||
@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
|
||||
def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
|
||||
"""
|
||||
Verify routes installed as per maximum-paths
|
||||
configuration (8/16/32).
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, test_type, "r2")
|
||||
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ebgp": ecmp_num,
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ebgp": ecmp_num,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Configuring bgp maximum-paths %s on router r3", ecmp_num)
|
||||
result = create_router_bgp(tgen, topo, input_dict)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_after_clear_bgp(request):
|
||||
""" Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
# Clear bgp
|
||||
result = clear_bgp_and_verify(tgen, topo, dut)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_remove_redistribute_static(request):
|
||||
""" Verify routes are cleared from BGP and RIB table of DUT when
|
||||
redistribute static configuration is removed."""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_2 = {
|
||||
"r2": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static",
|
||||
"delete": True
|
||||
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static",
|
||||
"delete": True
|
||||
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Remove redistribute static")
|
||||
result = create_router_bgp(tgen, topo, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3 are deleted", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=[], protocol=protocol, expected=False)
|
||||
assert result is not True, "Testcase {} : Failed \n Routes still" \
|
||||
" present in RIB".format(tc_name)
|
||||
|
||||
logger.info("Enable redistribute static")
|
||||
input_dict_2 = {
|
||||
"r2": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_shut_bgp_neighbor(request):
|
||||
"""
|
||||
Disable/Shut selected paths nexthops and verify other next are installed in
|
||||
the RIB of DUT. Enable interfaces and verify RIB count.
|
||||
|
||||
Shut BGP neigbors one by one and verify BGP and routing table updated
|
||||
accordingly in DUT
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
logger.info(INTF_LIST_R2)
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for intf_num in range(len(INTF_LIST_R2)+1, 16):
|
||||
intf_val = INTF_LIST_R2[intf_num:intf_num+16]
|
||||
|
||||
input_dict_1 = {
|
||||
"r2": {
|
||||
"interface_list": [intf_val],
|
||||
"status": "down"
|
||||
}
|
||||
}
|
||||
logger.info("Shutting down neighbor interface {} on r2".
|
||||
format(intf_val))
|
||||
result = interface_status(tgen, topo, input_dict_1)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
if intf_num + 16 < 32:
|
||||
check_hops = NEXT_HOPS[addr_type]
|
||||
else:
|
||||
check_hops = []
|
||||
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=check_hops,
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_1 = {
|
||||
"r2": {
|
||||
"interface_list": INTF_LIST_R2,
|
||||
"status": "up"
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Enabling all neighbor interface {} on r2")
|
||||
result = interface_status(tgen, topo, input_dict_1)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_remove_static_route(request):
|
||||
"""
|
||||
Delete static routes and verify routers are cleared from BGP table,
|
||||
and RIB of DUT.
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(
|
||||
tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type], protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_2 = {
|
||||
"r2": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type],
|
||||
"next_hop": NEXT_HOP_IP[addr_type],
|
||||
"delete": True
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Remove static routes")
|
||||
result = create_static_routes(tgen, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
logger.info("Verifying %s routes on r3 are removed", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_2,
|
||||
next_hop=[], protocol=protocol, expected=False)
|
||||
assert result is not True, "Testcase {} : Failed \n Routes still" \
|
||||
" present in RIB".format(tc_name)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Enable static routes
|
||||
input_dict_4 = {
|
||||
"r2": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type],
|
||||
"next_hop": NEXT_HOP_IP[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Enable static route")
|
||||
result = create_static_routes(tgen, input_dict_4)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_4,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
|
||||
def test_ecmp_remove_nw_advertise(request):
|
||||
"""
|
||||
Verify routes are cleared from BGP and RIB table of DUT,
|
||||
when advertise network configuration is removed
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_3 = {
|
||||
"r2": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"advertise_networks": [{
|
||||
"network": NETWORK["ipv4"],
|
||||
"delete": True
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"advertise_networks": [{
|
||||
"network": NETWORK["ipv6"],
|
||||
"delete": True
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Withdraw advertised networks")
|
||||
result = create_router_bgp(tgen, topo, input_dict_3)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=[], protocol=protocol, expected=False)
|
||||
assert result is not True, "Testcase {} : Failed \n Routes still" \
|
||||
" present in RIB".format(tc_name)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
813
tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
Executable file
813
tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
Executable file
@ -0,0 +1,813 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2019 by VMware, Inc. ("VMware")
|
||||
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
|
||||
# ("NetDEF") in this file.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
Following tests are covered to test ecmp functionality on EBGP.
|
||||
1. Verify routes installed as per maximum-paths configuration (8/16/32)
|
||||
2. Disable/Shut selected paths nexthops and verify other next are installed in
|
||||
the RIB of DUT. Enable interfaces and verify RIB count.
|
||||
3. Verify BGP table and RIB in DUT after clear BGP routes and neighbors.
|
||||
4. Verify routes are cleared from BGP and RIB table of DUT when
|
||||
redistribute static configuration is removed.
|
||||
5. Shut BGP neigbors one by one and verify BGP and routing table updated
|
||||
accordingly in DUT
|
||||
6. Delete static routes and verify routers are cleared from BGP table and RIB
|
||||
of DUT.
|
||||
7. Verify routes are cleared from BGP and RIB table of DUT when advertise
|
||||
network configuration is removed.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import pytest
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, '../'))
|
||||
sys.path.append(os.path.join(CWD, '../../'))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from mininet.topo import Topo
|
||||
|
||||
from lib.common_config import (
|
||||
start_topology, write_test_header,
|
||||
write_test_footer,
|
||||
verify_rib, create_static_routes, check_address_types,
|
||||
interface_status, reset_config_on_routers
|
||||
)
|
||||
from lib.topolog import logger
|
||||
from lib.bgp import (
|
||||
verify_bgp_convergence, create_router_bgp,
|
||||
clear_bgp_and_verify)
|
||||
from lib.topojson import build_topo_from_json, build_config_from_json
|
||||
|
||||
# Reading the data from JSON File for topology and configuration creation
|
||||
jsonFile = "{}/ibgp_ecmp_topo2.json".format(CWD)
|
||||
|
||||
try:
|
||||
with open(jsonFile, "r") as topoJson:
|
||||
topo = json.load(topoJson)
|
||||
except IOError:
|
||||
assert False, "Could not read file {}".format(jsonFile)
|
||||
|
||||
# Global variables
|
||||
NEXT_HOPS = {"ipv4": [], "ipv6": []}
|
||||
INTF_LIST_R3 = []
|
||||
INTF_LIST_R2 = []
|
||||
NETWORK = {"ipv4": "11.0.20.1/32", "ipv6": "1::/64"}
|
||||
NEXT_HOP_IP = {"ipv4": "10.0.0.1", "ipv6": "fd00::1"}
|
||||
BGP_CONVERGENCE = False
|
||||
|
||||
|
||||
class CreateTopo(Topo):
|
||||
"""
|
||||
Test topology builder.
|
||||
|
||||
* `Topo`: Topology object
|
||||
"""
|
||||
|
||||
def build(self, *_args, **_opts):
|
||||
"""Build function."""
|
||||
tgen = get_topogen(self)
|
||||
|
||||
# Building topology from json file
|
||||
build_topo_from_json(tgen, topo)
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"""
|
||||
Sets up the pytest environment.
|
||||
|
||||
* `mod`: module name
|
||||
"""
|
||||
global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
|
||||
global ADDR_TYPES
|
||||
|
||||
testsuite_run_time = time.asctime(time.localtime(time.time()))
|
||||
logger.info("Testsuite start time: {}".format(testsuite_run_time))
|
||||
logger.info("=" * 40)
|
||||
|
||||
logger.info("Running setup_module to create topology")
|
||||
|
||||
# This function initiates the topology build with Topogen...
|
||||
tgen = Topogen(CreateTopo, mod.__name__)
|
||||
|
||||
# Starting topology, create tmp files which are loaded to routers
|
||||
# to start deamons and then start routers
|
||||
start_topology(tgen)
|
||||
|
||||
# Creating configuration from JSON
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
# Don't run this test if we have any failure.
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
# tgen.mininet_cli()
|
||||
# Api call verify whether BGP is converged
|
||||
ADDR_TYPES = check_address_types()
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, ("setup_module :Failed \n Error:"
|
||||
" {}".format(BGP_CONVERGENCE))
|
||||
|
||||
link_data = [val for links, val in
|
||||
topo["routers"]["r2"]["links"].iteritems()
|
||||
if "r3" in links]
|
||||
for adt in ADDR_TYPES:
|
||||
NEXT_HOPS[adt] = [val[adt].split("/")[0] for val in link_data]
|
||||
if adt == "ipv4":
|
||||
NEXT_HOPS[adt] = sorted(
|
||||
NEXT_HOPS[adt], key=lambda x: int(x.split(".")[2]))
|
||||
elif adt == "ipv6":
|
||||
NEXT_HOPS[adt] = sorted(
|
||||
NEXT_HOPS[adt], key=lambda x: int(x.split(':')[-3], 16))
|
||||
|
||||
INTF_LIST_R2 = [val["interface"].split("/")[0] for val in link_data]
|
||||
INTF_LIST_R2 = sorted(INTF_LIST_R2, key=lambda x: int(x.split("eth")[1]))
|
||||
|
||||
link_data = [val for links, val in
|
||||
topo["routers"]["r3"]["links"].iteritems()
|
||||
if "r2" in links]
|
||||
INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
|
||||
INTF_LIST_R3 = sorted(INTF_LIST_R3, key=lambda x: int(x.split("eth")[1]))
|
||||
|
||||
# STATIC_ROUTE = True
|
||||
logger.info("Running setup_module() done")
|
||||
|
||||
|
||||
def teardown_module():
|
||||
"""
|
||||
Teardown the pytest environment.
|
||||
|
||||
* `mod`: module name
|
||||
"""
|
||||
|
||||
logger.info("Running teardown_module to delete topology")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
# Stop toplogy and Remove tmp files
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def static_or_nw(tgen, topo, tc_name, test_type, dut):
|
||||
|
||||
if test_type == "redist_static":
|
||||
input_dict_static = {
|
||||
dut: {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK["ipv4"],
|
||||
"next_hop": NEXT_HOP_IP["ipv4"]
|
||||
},
|
||||
{
|
||||
"network": NETWORK["ipv6"],
|
||||
"next_hop": NEXT_HOP_IP["ipv6"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Configuring static route on router %s", dut)
|
||||
result = create_static_routes(tgen, input_dict_static)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_2 = {
|
||||
dut: {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Configuring redistribute static route on router %s", dut)
|
||||
result = create_router_bgp(tgen, topo, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
elif test_type == "advertise_nw":
|
||||
input_dict_nw = {
|
||||
dut: {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"advertise_networks": [
|
||||
{"network": NETWORK["ipv4"]}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"advertise_networks": [
|
||||
{"network": NETWORK["ipv6"]}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Advertising networks %s %s from router %s",
|
||||
NETWORK["ipv4"], NETWORK["ipv6"], dut)
|
||||
result = create_router_bgp(tgen, topo, input_dict_nw)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
|
||||
@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
|
||||
def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
|
||||
"""
|
||||
Verify routes installed as per maximum-paths
|
||||
configuration (8/16/32).
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, test_type, "r2")
|
||||
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ibgp": ecmp_num,
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"maximum_paths": {
|
||||
"ibgp": ecmp_num,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Configuring bgp maximum-paths %s on router r3", ecmp_num)
|
||||
result = create_router_bgp(tgen, topo, input_dict)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_after_clear_bgp(request):
|
||||
""" Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
# Clear bgp
|
||||
result = clear_bgp_and_verify(tgen, topo, dut)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_remove_redistribute_static(request):
|
||||
""" Verify routes are cleared from BGP and RIB table of DUT when
|
||||
redistribute static configuration is removed."""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_2 = {
|
||||
"r2": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static",
|
||||
"delete": True
|
||||
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static",
|
||||
"delete": True
|
||||
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Remove redistribute static")
|
||||
result = create_router_bgp(tgen, topo, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3 are deleted", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=[], protocol=protocol, expected=False)
|
||||
assert result is not True, "Testcase {} : Failed \n Routes still" \
|
||||
" present in RIB".format(tc_name)
|
||||
|
||||
logger.info("Enable redistribute static")
|
||||
input_dict_2 = {
|
||||
"r2": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_shut_bgp_neighbor(request):
|
||||
""" Shut BGP neigbors one by one and verify BGP and routing table updated
|
||||
accordingly in DUT """
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
logger.info(INTF_LIST_R2)
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for intf_num in range(len(INTF_LIST_R2)+1, 16):
|
||||
intf_val = INTF_LIST_R2[intf_num:intf_num+16]
|
||||
|
||||
input_dict_1 = {
|
||||
"r2": {
|
||||
"interface_list": [intf_val],
|
||||
"status": "down"
|
||||
}
|
||||
}
|
||||
logger.info("Shutting down neighbor interface {} on r2".
|
||||
format(intf_val))
|
||||
result = interface_status(tgen, topo, input_dict_1)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
if intf_num + 16 < 32:
|
||||
check_hops = NEXT_HOPS[addr_type]
|
||||
else:
|
||||
check_hops = []
|
||||
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=check_hops,
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_1 = {
|
||||
"r2": {
|
||||
"interface_list": INTF_LIST_R2,
|
||||
"status": "up"
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Enabling all neighbor interface {} on r2")
|
||||
result = interface_status(tgen, topo, input_dict_1)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_remove_static_route(request):
|
||||
"""
|
||||
Delete static routes and verify routers are cleared from BGP table,
|
||||
and RIB of DUT.
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_1 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(
|
||||
tgen, addr_type, dut, input_dict_1,
|
||||
next_hop=NEXT_HOPS[addr_type], protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_2 = {
|
||||
"r2": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type],
|
||||
"next_hop": NEXT_HOP_IP[addr_type],
|
||||
"delete": True
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Remove static routes")
|
||||
result = create_static_routes(tgen, input_dict_2)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
logger.info("Verifying %s routes on r3 are removed", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_2,
|
||||
next_hop=[], protocol=protocol, expected=False)
|
||||
assert result is not True, "Testcase {} : Failed \n Routes still" \
|
||||
" present in RIB".format(tc_name)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Enable static routes
|
||||
input_dict_4 = {
|
||||
"r2": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type],
|
||||
"next_hop": NEXT_HOP_IP[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Enable static route")
|
||||
result = create_static_routes(tgen, input_dict_4)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict_4,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_ecmp_remove_nw_advertise(request):
|
||||
"""
|
||||
Verify routes are cleared from BGP and RIB table of DUT,
|
||||
when advertise network configuration is removed
|
||||
"""
|
||||
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
tgen = get_topogen()
|
||||
|
||||
# Verifying RIB routes
|
||||
dut = "r3"
|
||||
protocol = "bgp"
|
||||
|
||||
reset_config_on_routers(tgen)
|
||||
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
input_dict_3 = {
|
||||
"r2": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"advertise_networks": [{
|
||||
"network": NETWORK["ipv4"],
|
||||
"delete": True
|
||||
}]
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"advertise_networks": [{
|
||||
"network": NETWORK["ipv6"],
|
||||
"delete": True
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Withdraw advertised networks")
|
||||
result = create_router_bgp(tgen, topo, input_dict_3)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=[], protocol=protocol, expected=False)
|
||||
assert result is not True, "Testcase {} : Failed \n Routes still" \
|
||||
" present in RIB".format(tc_name)
|
||||
|
||||
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK[addr_type]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
logger.info("Verifying %s routes on r3", addr_type)
|
||||
result = verify_rib(tgen, addr_type, dut, input_dict,
|
||||
next_hop=NEXT_HOPS[addr_type],
|
||||
protocol=protocol)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -178,7 +178,7 @@ def test_static_routes(request):
|
||||
# Static routes are created as part of initial configuration,
|
||||
# verifying RIB
|
||||
dut = 'r3'
|
||||
next_hop = '10.0.0.1'
|
||||
next_hop = ['10.0.0.1', '10.0.0.5']
|
||||
input_dict = {
|
||||
"r1": {
|
||||
"static_routes": [
|
||||
|
@ -470,9 +470,9 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type,
|
||||
dest_link]["ipv6"].split("/")[0]
|
||||
|
||||
neigh_cxt = "neighbor {}".format(ip_addr)
|
||||
#config_data.append("address-family {} unicast".format(
|
||||
# addr_type
|
||||
#))
|
||||
config_data.append("address-family {} unicast".format(
|
||||
addr_type
|
||||
))
|
||||
if deactivate:
|
||||
config_data.append(
|
||||
"no neighbor {} activate".format(deactivate))
|
||||
|
@ -34,12 +34,14 @@ import ConfigParser
|
||||
import traceback
|
||||
import socket
|
||||
import ipaddr
|
||||
import re
|
||||
|
||||
from lib import topotest
|
||||
|
||||
from functools import partial
|
||||
from lib.topolog import logger, logger_config
|
||||
from lib.topogen import TopoRouter
|
||||
from lib.topotest import interface_set_status
|
||||
|
||||
|
||||
FRRCFG_FILE = "frr_json.conf"
|
||||
@ -513,27 +515,31 @@ def validate_ip_address(ip_address):
|
||||
" address" % ip_address)
|
||||
|
||||
|
||||
def check_address_types(addr_type):
|
||||
def check_address_types(addr_type=None):
|
||||
"""
|
||||
Checks environment variable set and compares with the current address type
|
||||
"""
|
||||
global ADDRESS_TYPES
|
||||
if ADDRESS_TYPES is None:
|
||||
ADDRESS_TYPES = "dual"
|
||||
|
||||
if ADDRESS_TYPES == "dual":
|
||||
ADDRESS_TYPES = ["ipv4", "ipv6"]
|
||||
elif ADDRESS_TYPES == "ipv4":
|
||||
ADDRESS_TYPES = ["ipv4"]
|
||||
elif ADDRESS_TYPES == "ipv6":
|
||||
ADDRESS_TYPES = ["ipv6"]
|
||||
addr_types_env = os.environ.get("ADDRESS_TYPES")
|
||||
if not addr_types_env:
|
||||
addr_types_env = "dual"
|
||||
|
||||
if addr_type not in ADDRESS_TYPES:
|
||||
if addr_types_env == "dual":
|
||||
addr_types = ["ipv4", "ipv6"]
|
||||
elif addr_types_env == "ipv4":
|
||||
addr_types = ["ipv4"]
|
||||
elif addr_types_env == "ipv6":
|
||||
addr_types = ["ipv6"]
|
||||
|
||||
if addr_type is None:
|
||||
return addr_types
|
||||
|
||||
if addr_type not in addr_types:
|
||||
logger.error("{} not in supported/configured address types {}".
|
||||
format(addr_type, ADDRESS_TYPES))
|
||||
format(addr_type, addr_types))
|
||||
return False
|
||||
|
||||
return ADDRESS_TYPES
|
||||
return True
|
||||
|
||||
|
||||
def generate_ips(network, no_of_ips):
|
||||
@ -627,6 +633,54 @@ def write_test_footer(tc_name):
|
||||
logger.info("="*(len(tc_name)+count))
|
||||
|
||||
|
||||
def interface_status(tgen, topo, input_dict):
|
||||
"""
|
||||
Delete ip route maps from device
|
||||
|
||||
* `tgen` : Topogen object
|
||||
* `topo` : json file data
|
||||
* `input_dict` : for which router, route map has to be deleted
|
||||
|
||||
Usage
|
||||
-----
|
||||
input_dict = {
|
||||
"r3": {
|
||||
"interface_list": ['eth1-r1-r2', 'eth2-r1-r3'],
|
||||
"status": "down"
|
||||
}
|
||||
}
|
||||
Returns
|
||||
-------
|
||||
errormsg(str) or True
|
||||
"""
|
||||
logger.debug("Entering lib API: interface_status()")
|
||||
|
||||
try:
|
||||
global frr_cfg
|
||||
for router in input_dict.keys():
|
||||
|
||||
interface_list = input_dict[router]['interface_list']
|
||||
status = input_dict[router].setdefault('status', 'up')
|
||||
for intf in interface_list:
|
||||
rnode = tgen.routers()[router]
|
||||
interface_set_status(rnode, intf, status)
|
||||
|
||||
# Load config to router
|
||||
load_config_to_router(tgen, router)
|
||||
|
||||
except Exception as e:
|
||||
# handle any exception
|
||||
logger.error("Error %s occured. Arguments %s.", e.message, e.args)
|
||||
|
||||
# Traceback
|
||||
errormsg = traceback.format_exc()
|
||||
logger.error(errormsg)
|
||||
return errormsg
|
||||
|
||||
logger.debug("Exiting lib API: interface_status()")
|
||||
return True
|
||||
|
||||
|
||||
def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
|
||||
"""
|
||||
Retries function execution, if return is an errormsg or exception
|
||||
@ -682,6 +736,62 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
|
||||
return _retry
|
||||
|
||||
|
||||
def disable_v6_link_local(tgen, router, intf_name=None):
|
||||
"""
|
||||
Disables ipv6 link local addresses for a particular interface or
|
||||
all interfaces
|
||||
|
||||
* `tgen`: tgen onject
|
||||
* `router` : router for which hightest interface should be
|
||||
calculated
|
||||
* `intf_name` : Interface name for which v6 link local needs to
|
||||
be disabled
|
||||
"""
|
||||
|
||||
router_list = tgen.routers()
|
||||
for rname, rnode in router_list.iteritems():
|
||||
if rname != router:
|
||||
continue
|
||||
|
||||
linklocal = []
|
||||
|
||||
ifaces = router_list[router].run('ip -6 address')
|
||||
|
||||
# Fix newlines (make them all the same)
|
||||
ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines()
|
||||
|
||||
interface = None
|
||||
ll_per_if_count = 0
|
||||
for line in ifaces:
|
||||
# Interface name
|
||||
m = re.search('[0-9]+: ([^:]+)[@if0-9:]+ <', line)
|
||||
if m:
|
||||
interface = m.group(1).split("@")[0]
|
||||
ll_per_if_count = 0
|
||||
|
||||
# Interface ip
|
||||
m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+'
|
||||
':[0-9a-f]+[/0-9]*) scope link', line)
|
||||
if m:
|
||||
local = m.group(1)
|
||||
ll_per_if_count += 1
|
||||
if ll_per_if_count > 1:
|
||||
linklocal += [["%s-%s" % (interface, ll_per_if_count), local]]
|
||||
else:
|
||||
linklocal += [[interface, local]]
|
||||
|
||||
if len(linklocal[0]) > 1:
|
||||
link_local_dict = {item[0]: item[1] for item in linklocal}
|
||||
|
||||
for lname, laddr in link_local_dict.items():
|
||||
|
||||
if intf_name is not None and lname != intf_name:
|
||||
continue
|
||||
|
||||
cmd = "ip addr del {} dev {}".format(laddr, lname)
|
||||
router_list[router].run(cmd)
|
||||
|
||||
|
||||
#############################################
|
||||
# These APIs, will used by testcase
|
||||
#############################################
|
||||
@ -711,6 +821,8 @@ def create_interfaces_cfg(tgen, topo, build=False):
|
||||
interface_name = destRouterLink
|
||||
else:
|
||||
interface_name = data["interface"]
|
||||
if "ipv6" in data:
|
||||
disable_v6_link_local(tgen, c_router, interface_name)
|
||||
interface_data.append("interface {}".format(
|
||||
str(interface_name)
|
||||
))
|
||||
@ -724,6 +836,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
|
||||
interface_data.append("ipv6 address {}".format(
|
||||
intf_addr
|
||||
))
|
||||
|
||||
result = create_common_configuration(tgen, c_router,
|
||||
interface_data,
|
||||
"interface_config",
|
||||
@ -1303,7 +1416,7 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
|
||||
if "no_of_ip" in static_route:
|
||||
no_of_ip = static_route["no_of_ip"]
|
||||
else:
|
||||
no_of_ip = 0
|
||||
no_of_ip = 1
|
||||
|
||||
# Generating IPs for verification
|
||||
ip_list = generate_ips(network, no_of_ip)
|
||||
@ -1321,9 +1434,9 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
|
||||
found_hops = [rib_r["ip"] for rib_r in
|
||||
rib_routes_json[st_rt][0][
|
||||
"nexthops"]]
|
||||
for nh in next_hop:
|
||||
for nh in found_hops:
|
||||
nh_found = False
|
||||
if nh and nh in found_hops:
|
||||
if nh and nh in next_hop:
|
||||
nh_found = True
|
||||
else:
|
||||
errormsg = ("Nexthop {} is Missing for {}"
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Skip pytests example directory
|
||||
[pytest]
|
||||
norecursedirs = .git example-test lib docker
|
||||
norecursedirs = .git example-test example-topojson-test lib docker
|
||||
|
||||
[topogen]
|
||||
# Default configuration values
|
||||
|
Loading…
Reference in New Issue
Block a user