mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-27 05:28:51 +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
|
# Verifying RIB routes
|
||||||
dut = 'r3'
|
dut = 'r3'
|
||||||
protocol = 'bgp'
|
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,
|
result = verify_rib(tgen, 'ipv4', dut, input_dict, next_hop=next_hop,
|
||||||
protocol=protocol)
|
protocol=protocol)
|
||||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
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,
|
# Static routes are created as part of initial configuration,
|
||||||
# verifying RIB
|
# verifying RIB
|
||||||
dut = 'r3'
|
dut = 'r3'
|
||||||
next_hop = '10.0.0.1'
|
next_hop = ['10.0.0.1', '10.0.0.5']
|
||||||
input_dict = {
|
input_dict = {
|
||||||
"r1": {
|
"r1": {
|
||||||
"static_routes": [
|
"static_routes": [
|
||||||
|
@ -470,9 +470,9 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type,
|
|||||||
dest_link]["ipv6"].split("/")[0]
|
dest_link]["ipv6"].split("/")[0]
|
||||||
|
|
||||||
neigh_cxt = "neighbor {}".format(ip_addr)
|
neigh_cxt = "neighbor {}".format(ip_addr)
|
||||||
#config_data.append("address-family {} unicast".format(
|
config_data.append("address-family {} unicast".format(
|
||||||
# addr_type
|
addr_type
|
||||||
#))
|
))
|
||||||
if deactivate:
|
if deactivate:
|
||||||
config_data.append(
|
config_data.append(
|
||||||
"no neighbor {} activate".format(deactivate))
|
"no neighbor {} activate".format(deactivate))
|
||||||
|
@ -34,12 +34,14 @@ import ConfigParser
|
|||||||
import traceback
|
import traceback
|
||||||
import socket
|
import socket
|
||||||
import ipaddr
|
import ipaddr
|
||||||
|
import re
|
||||||
|
|
||||||
from lib import topotest
|
from lib import topotest
|
||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from lib.topolog import logger, logger_config
|
from lib.topolog import logger, logger_config
|
||||||
from lib.topogen import TopoRouter
|
from lib.topogen import TopoRouter
|
||||||
|
from lib.topotest import interface_set_status
|
||||||
|
|
||||||
|
|
||||||
FRRCFG_FILE = "frr_json.conf"
|
FRRCFG_FILE = "frr_json.conf"
|
||||||
@ -513,27 +515,31 @@ def validate_ip_address(ip_address):
|
|||||||
" 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
|
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":
|
addr_types_env = os.environ.get("ADDRESS_TYPES")
|
||||||
ADDRESS_TYPES = ["ipv4", "ipv6"]
|
if not addr_types_env:
|
||||||
elif ADDRESS_TYPES == "ipv4":
|
addr_types_env = "dual"
|
||||||
ADDRESS_TYPES = ["ipv4"]
|
|
||||||
elif ADDRESS_TYPES == "ipv6":
|
|
||||||
ADDRESS_TYPES = ["ipv6"]
|
|
||||||
|
|
||||||
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 {}".
|
logger.error("{} not in supported/configured address types {}".
|
||||||
format(addr_type, ADDRESS_TYPES))
|
format(addr_type, addr_types))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return ADDRESS_TYPES
|
return True
|
||||||
|
|
||||||
|
|
||||||
def generate_ips(network, no_of_ips):
|
def generate_ips(network, no_of_ips):
|
||||||
@ -627,6 +633,54 @@ def write_test_footer(tc_name):
|
|||||||
logger.info("="*(len(tc_name)+count))
|
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):
|
def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
|
||||||
"""
|
"""
|
||||||
Retries function execution, if return is an errormsg or exception
|
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
|
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
|
# These APIs, will used by testcase
|
||||||
#############################################
|
#############################################
|
||||||
@ -711,6 +821,8 @@ def create_interfaces_cfg(tgen, topo, build=False):
|
|||||||
interface_name = destRouterLink
|
interface_name = destRouterLink
|
||||||
else:
|
else:
|
||||||
interface_name = data["interface"]
|
interface_name = data["interface"]
|
||||||
|
if "ipv6" in data:
|
||||||
|
disable_v6_link_local(tgen, c_router, interface_name)
|
||||||
interface_data.append("interface {}".format(
|
interface_data.append("interface {}".format(
|
||||||
str(interface_name)
|
str(interface_name)
|
||||||
))
|
))
|
||||||
@ -724,6 +836,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
|
|||||||
interface_data.append("ipv6 address {}".format(
|
interface_data.append("ipv6 address {}".format(
|
||||||
intf_addr
|
intf_addr
|
||||||
))
|
))
|
||||||
|
|
||||||
result = create_common_configuration(tgen, c_router,
|
result = create_common_configuration(tgen, c_router,
|
||||||
interface_data,
|
interface_data,
|
||||||
"interface_config",
|
"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:
|
if "no_of_ip" in static_route:
|
||||||
no_of_ip = static_route["no_of_ip"]
|
no_of_ip = static_route["no_of_ip"]
|
||||||
else:
|
else:
|
||||||
no_of_ip = 0
|
no_of_ip = 1
|
||||||
|
|
||||||
# Generating IPs for verification
|
# Generating IPs for verification
|
||||||
ip_list = generate_ips(network, no_of_ip)
|
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
|
found_hops = [rib_r["ip"] for rib_r in
|
||||||
rib_routes_json[st_rt][0][
|
rib_routes_json[st_rt][0][
|
||||||
"nexthops"]]
|
"nexthops"]]
|
||||||
for nh in next_hop:
|
for nh in found_hops:
|
||||||
nh_found = False
|
nh_found = False
|
||||||
if nh and nh in found_hops:
|
if nh and nh in next_hop:
|
||||||
nh_found = True
|
nh_found = True
|
||||||
else:
|
else:
|
||||||
errormsg = ("Nexthop {} is Missing for {}"
|
errormsg = ("Nexthop {} is Missing for {}"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Skip pytests example directory
|
# Skip pytests example directory
|
||||||
[pytest]
|
[pytest]
|
||||||
norecursedirs = .git example-test lib docker
|
norecursedirs = .git example-test example-topojson-test lib docker
|
||||||
|
|
||||||
[topogen]
|
[topogen]
|
||||||
# Default configuration values
|
# Default configuration values
|
||||||
|
Loading…
Reference in New Issue
Block a user