diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000000..16ed2fad4c0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+# Compiled Python files
+ansible/plugins/filter/*.pyc
diff --git a/ansible/README.deploy.md b/ansible/README.deploy.md
index cfc3def6442..1ee2dd8a336 100644
--- a/ansible/README.deploy.md
+++ b/ansible/README.deploy.md
@@ -12,16 +12,16 @@ and public [sonicdev Docker registry](https://sonicdev-microsoft.azurecr.io/).
## Deploy SONiC
- Update [inventory](/ansible/inventory/) file with correct information for your environment.
- * ansible_host = management ip address
- * sonic_hwsku = Supported Hardware SKU, e.g. Force10-S6000, ACS-MSN2700
+ - ansible_host = management ip address
+ - sonic_hwsku = Supported Hardware SKU, e.g. Force10-S6000, ACS-MSN2700
- Update [group_vars/sonic/vars](/ansible/group_vars/sonic/vars/) file with:
- * Replace ```sonicadmin_user``` and ```ansible_ssh_user``` with the username you built into the baseimage
- * Replace ```sonicadmin_initial_password``` with the password you built into baseimage.
- * Update ```[ntp,syslog,dns]_servers``` with a list of your server IPs for these services.
- * Update APT repository if you are using private repo.
- * Update Docker [registry](/ansible/vars/docker_registry.yml/) if you are using private registry.
+ - Replace `sonicadmin_user` and `ansible_ssh_user` with the username you built into the baseimage
+ - Replace `sonicadmin_initial_password` with the password you built into baseimage.
+ - Update `[ntp,syslog,dns]_servers` with a list of your server IPs for these services.
+ - Update APT repository if you are using private repo.
+ - Update Docker [registry](/ansible/vars/docker_registry.yml/) if you are using private registry.
- Update management IP of switch1
- * Find the ManagementIPInterfaces xml block in [minigraph/switch1.xml](/ansible/minigraph/switch1.xml/) and change both IP addresses.
+ - Find the ManagementIPInterfaces xml block in [minigraph/switch1.xml](/ansible/minigraph/switch1.xml/) and change both IP addresses.
- Run the playbook:
@@ -29,4 +29,4 @@ and public [sonicdev Docker registry](https://sonicdev-microsoft.azurecr.io/).
ansible-playbook deploy_sonic.yml -i inventory --limit switch1 --become -e "bootstrap=yes"
```
-Note: ```-e "bootstrap=yes"``` passes a special flag to update the initial admin password to the permanent password. This is not required after the first run.
+*Note: `-e "bootstrap=yes"` passes a special flag to update the initial admin password to the permanent password. This is not required after the first run.*
diff --git a/ansible/README.md b/ansible/README.md
index 5967a819f23..0e0ad846dab 100644
--- a/ansible/README.md
+++ b/ansible/README.md
@@ -1,6 +1,6 @@
# Overview of SONiC deployment, testbed setup and tests
-This ansible playbook consists following functionalities:
+This ansible playbook consists of the following functionality:
- [Deploy SONiC](README.deploy.md)
- [Setup SONiC testbed](README.testbed.md)
- [Run SONiC tests](README.test.md)
@@ -17,9 +17,9 @@ git submodule update --init --recursive
make
sudo make install
```
-Note: v2.0.0.2 is the currently tested Ansible version. Other versions may not work correctly.
+*Note: v2.0.0.2 is the currently tested Ansible version. Other versions may not work correctly.*
-# Ansible playbood layout
+# Ansible playbook layout
```
# Ansible top level file and directory structure
diff --git a/ansible/README.test.md b/ansible/README.test.md
index 4d3e7ed6532..5c2cae13e09 100644
--- a/ansible/README.test.md
+++ b/ansible/README.test.md
@@ -1,36 +1,87 @@
-# ansible playbooks for SONiC testing
+# Ansible Playbooks for Testing SONiC
## Requirements
- A testbed needed to be set up before hand. See [Testbed](README.testbed.md) for more information.
-- Depending on the test, either a PTF testbed or a VM set testbed might be required.
-## Run Tests
-- Replace {DUT_NAME} in each command line with the host name of switch under test.
+## How to Run Tests
+- Replace {DUT_NAME} in each command line with the host name of switch under test
+- Replace {PTF_HOST} in each command line with the host name or IP of the PTF testbed host
+- Replace {TESTBED_TYPE} in each command line with the type of the testbed being used
-### NTP test
+### ACL tests
```
-ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags ntp
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags acltb_configure --extra-vars "run_dir=/tmp testbed_type={TESTBED_TYPE} ptf_host={PTF_HOST}"
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags acltb_test --extra-vars "run_dir=/tmp testbed_type={TESTBED_TYPE} ptf_host={PTF_HOST}"
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags acltb_cleanup --extra-vars "run_dir=/tmp testbed_type={TESTBED_TYPE} ptf_host={PTF_HOST}"
```
+- Requires switch connected to a PTF testbed
-### Syslog test
+### ARP tests
```
-ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags syslog
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags arp --extra-vars "ptf_host={PTF_HOST}"
```
+- Requires switch connected to a PTF testbed
-### SNMP tests
+### BGP facts verification test
```
-ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags snmp,snmp_cpu,snmp_interfaces
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags bgp_fact
+```
+- Requires switch connected to a VM set testbed
+
+### CoPP test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags copp --extra-vars "ptf_host={PTF_HOST}"
+```
+- Requires switch connected to a PTF testbed
+
+### DHCP relay test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags dhcp_relay --extra-vars "ptf_host={PTF_HOST}"
+```
+- Requires switch connected to a PTF testbed
+
+### FIB test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --tags fib --extra-vars "testbed_type={TESTBED_TYPE} ptf_host={PTF_HOST}"
+```
+- Requires switch connected to a PTF testbed
+
+### Fast-Reboot test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags fast_reboot --extra-vars "ptf_host={PTF_HOST}"
```
+- Requires switch connected to a PTF testbed
### LLDP test
```
ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME},lldp_neighbors --become --tags lldp
```
-- Required switch connected to a VM set testbed.
+- Requires switch connected to a VM set testbed
-### BGP facts verification test
+### Link flap test
```
-ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags bgp_fact
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME}, --become --tags link_flap
+```
+- Requires switch connected to a VM set testbed
+
+### NTP test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags ntp
+```
+
+### SNMP tests
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags snmp,snmp_cpu,snmp_interfaces
+```
+
+### Sensors test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags sensors
+```
+
+### Syslog test
+```
+ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags syslog
```
-- Required switch connected to a VM set testbed.
diff --git a/ansible/README.testbed.md b/ansible/README.testbed.md
index aac22021439..47c7f6fe9a2 100644
--- a/ansible/README.testbed.md
+++ b/ansible/README.testbed.md
@@ -1,286 +1,9 @@
-# Requirements for the Linux Host
-1. Ubuntu 16.04 x64
-2. Installed docker-engine
-3. Three network cards:
- 1. first is used for the server management
- 2. second is used to connect management interfaces of VMs and docker containers to network.
- 3. third is used to connect VMs and ptf containers to DUTs
-
-Content of /etc/network/interfaces:
-```
-root@STR-AZURE-SERV-02:~# cat /etc/network/interfaces
-# The primary network interface
-auto em1
-iface em1 inet static
- address 10.250.0.245
- netmask 255.255.255.0
- network 10.250.0.0
- broadcast 10.250.0.255
- gateway 10.250.0.1
- dns-nameservers 10.250.0.1 10.250.0.2
- # dns-* options are implemented by the resolvconf package, if installed
- dns-search SOMECOMPANY
-
-auto br1
-iface br1 inet manual
- bridge_ports em2
- bridge_stp on
- bridge_maxwait 0
- bridge_fd 0
-
-auto p4p1
-iface p4p1 inet manual
- mtu 9216
-up ip link set p4p1 up
-```
-
-
-# PTF Testbed topology
-
-```
- Linux Host Fanout Switch DUT
- +----------------------------------------------+ +--------------+ +---------------+
- | PTF Docker | | | | |
- | +----------------------+ | | | | |
- | | eth0 +------vlan101--+ | | Et1 +-----+ Ethernet0 |
- | | eth1 +------vlan102--| | | Et2 +-----+ Ethernet4 |
- | | eth2 +------vlan103--| | | Et3 +-----+ Ethernet8 |
- | | eth3 +------vlan104--| | | Et4 +-----+ Ethernet12 |
- | | eth4 +------vlan105--| | | Et5 +-----+ Ethernet16 |
- | | eth5 +------vlan106--| | | Et6 +-----+ Ethernet20 |
- | | eth6 +------vlan107--| | | Et7 +-----+ Ethernet24 |
- | | eth7 +------vlan108--| | | Et8 +-----+ Ethernet28 |
- | | eth8 +------vlan109--| | | Et9 +-----+ Etherent32 |
- | | eth9 +------vlan110--| | | Et10 +-----+ Ethernet36 |
- | | eth10 +------vlan111--| | | Et11 +-----+ Ethernet40 |
- | | eth11 +------vlan112--| | | Et12 +-----+ Ethernet44 |
- | | eth12 +------vlan113--| | | Et13 +-----+ Ethernet48 |
- | | eth13 +------vlan114--| | | Et14 +-----+ Ethernet52 |
- | | eth14 +------vlan115--| | | Et15 +-----+ Ethernet56 |
- | | eth15 +------vlan116--+---+-- eth0 --+ Et33 Et16 +-----+ Ethernet60 |
- | | eth16 +------vlan117--| | | Et17 +-----+ Ethernet64 |
- | | eth17 +------vlan118--| | | Et18 +-----+ Ethernet68 |
- | | eth18 +------vlan119--| | | Et19 +-----+ Ethernet72 |
- | | eth19 +------vlan120--| | | Et20 +-----+ Ethernet76 |
- | | eth20 +------vlan121--| | | Et21 +-----+ Ethernet80 |
- | | eth21 +------vlan122--| | | Et22 +-----+ Ethernet84 |
- | | eth22 +------vlan123--| | | Et23 +-----+ Ethernet88 |
- | | eth23 +------vlan124--| | | Et24 +-----+ Ethernet92 |
- | | eth24 +------vlan125--| | | Et25 +-----+ Ethernet96 |
- | | eth25 +------vlan126--| | | Et26 +-----+ Ethernet100 |
- | | eth26 +------vlan127--| | | Et27 +-----+ Ethernet104 |
- | | eth27 +------vlan128--| | | Et28 +-----+ Ethernet108 |
- | | eth28 +------vlan129--| | | Et29 +-----+ Ethernet112 |
- | | eth29 +------vlan130--| | | Et30 +-----+ Ethernet116 |
- | | eth30 +------vlan131--| | | Et31 +-----+ Ethernet120 |
- | | eth31 +------vlan132--+ | | Et32 +-----+ Ethernet124 |
- | +----------------------+ | | | | |
- | | | | | |
- +----------------------------------------------+ +--------------+ +---------------+
-```
-Figure 1: PTF container testbed
-
-- *PTF docker*: A docker container that has 32 ports with pre-installed PTF tools. See https://github.com/Azure/sonic-buildimage/tree/master/dockers/docker-ptf
-- *Vlan ports*: 32 vlan ports are created on top of a physical port, e.g., eth0, inside the Linux host. After creation the vlan ports are injected directly to a ptf docker host.
-- *Fanout switch*: A physical switch which enables VLAN trunking.
- * Et33 is a vlan trunking port and is connected to the eth0 port of the linux host.
- * Et1-Et32 are vlan access ports and are connect to DUT.
- * Enable LACP/LLDP passthrough
- * Disable spanning tree protocol
-
-### Deploy testbed with one ptf container
-1. clone sonic-mgmt repo to local directory
-2. Edit 'ansible/group_vars/vm_host'. Put your credentials to reach the server
-3. Check, that you can reach the server by running command 'ansible -i veos -m ping vm_host_1' from ansible directory. The output should contain 'pong'
-4. Edit 'ansible/group_vars/vm_host/main.yml'.
- * 'http_proxy': your http_proxy
- * 'http_proxy': your https_proxy
-5. Edit 'ansible/host_vars/STR-ACS-SERV-01.yml'. It contains settings for STR-ACS-SERV-01. STR-ACS-SERV-02 contains similar settings which are applied to STR-ACS-SERV-02
- * 'mgmt_gw': ip address of gateway for management interfaces of ptf_container
- * 'mgmt_bridge': the bridge which is used to connect the management network
- * 'externel_iface': the interface which is connected to the fanout switch
- * 'ptf_X_enabled': true, if you want to run X ptf container
- * 'ptf_X_mgmt_ip': which ip is used inside of the container for the management network
- * 'ptf_X_vlan_base': vlan number which is used for connection to first port of DUT
-7. Edit 'ansible/vars/docker_registry.yml'. You need put your docker registry server here
-8. Start ptf container with command 'ansible-playbook -i veos start_ptf_containers.yml --vault-password-file=~/.password --limit server_1 -e ptf_1=true'. See start_ptf_containers.yml for more examples
-9. Stop ptf container with command 'ansible-playbook -i veos stop_ptf_containers.yml --vault-password-file=~/.password --limit server_1 -e ptf_1=true'. See stop_ptf_containers.yml for more examples
-
-
-# VM set testbed topology
-
-```
- Linux Host Fanout DUT
- Switch
- +-------------------------------------------------------------+ +----------+ +-------------+
- | PTF Docker VM sets Ovs | | | | |
- | +--------------+ +-------+ | | | | |
- | +---------+ | VM_1 eth0 +------+ +--vlan101--+ | | Et1 +-----+ Ethernet0 |
- | | | +--------------+ | | | | | | | |
- | | eth0 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_2 eth0 +------+ +--vlan102--+ | | Et2 +-----+ Ethernet4 |
- | | | +--------------+ | | | | | | | |
- | | eth1 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_3 eth0 +------+ +--vlan103--+ | | Et3 +-----+ Ethernet8 |
- | | | +--------------+ | | | | | | | |
- | | eth2 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_4 eth0 +------+ +--vlan104--+ | | Et4 +-----+ Ethernet12 |
- | | | +--------------+ | | | | | | | |
- | | eth3 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_5 eth0 +------+ +--vlan105--+ | | Et5 +-----+ Ethernet16 |
- | | | +--------------+ | | | | | | | |
- | | eth4 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_6 eth0 +------+ +--vlan106--+ | | Et6 +-----+ Ethernet20 |
- | | | +--------------+ | | | | | | | |
- | | eth5 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_7 eth0 +------+ +--vlan107--+ | | Et7 +-----+ Ethernet24 |
- | | | +--------------+ | | | | | | | |
- | | eth6 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_8 eth0 +------+ +--vlan108--+ | | Et8 +-----+ Ethernet28 |
- | | | +--------------+ | | | | | | | |
- | | eth7 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_9 eth0 +------+ +--vlan109--+ | | Et9 +-----+ Etherent32 |
- | | | +--------------+ | | | | | | | |
- | | eth8 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_10 eth0 +------+ +--vlan110--+ | | Et10 +-----+ Ethernet36 |
- | | | +--------------+ | | | | | | | |
- | | eth9 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_11 eth0 +------+ +--vlan111--+ | | Et11 +-----+ Ethernet40 |
- | | | +--------------+ | | | | | | | |
- | | eth10 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_12 eth0 +------+ +--vlan112--+ | | Et12 +-----+ Ethernet44 |
- | | | +--------------+ | | | | | | | |
- | | eth11 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_13 eth0 +------+ +--vlan113--+ | | Et13 +-----+ Ethernet48 |
- | | | +--------------+ | | | | | | | |
- | | eth12 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_14 eth0 +------+ +--vlan114--+ | | Et14 +-----+ Ethernet52 |
- | | | +--------------+ | | | | | | | |
- | | eth13 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_15 eth0 +------+ +--vlan115--+ | | Et15 +-----+ Ethernet56 |
- | | | +--------------+ | | | | | | | |
- | | eth14 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_16 eth0 +------+ | | | | Et16 +-----+ Ethernet60 |
- | | | +--------------+ | +--vlan116--+---+-- eth0 --+ Et33 | | |
- | | eth15 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_17 eth0 +------+ +--vlan117--+ | | Et17 +-----+ Ethernet64 |
- | | | +--------------+ | | | | | | | |
- | | eth16 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_18 eth0 +------+ +--vlan118--+ | | Et18 +-----+ Ethernet68 |
- | | | +--------------+ | | | | | | | |
- | | eth17 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_19 eth0 +------+ +--vlan119--+ | | Et19 +-----+ Ethernet72 |
- | | | +--------------+ | | | | | | | |
- | | eth18 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_20 eth0 +------+ +--vlan120--+ | | Et20 +-----+ Ethernet76 |
- | | | +--------------+ | | | | | | | |
- | | eth19 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_21 eth0 +------+ +--vlan121--+ | | Et21 +-----+ Ethernet80 |
- | | | +--------------+ | | | | | | | |
- | | eth20 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_22 eth0 +------+ +--vlan122--+ | | Et22 +-----+ Ethernet84 |
- | | | +--------------+ | | | | | | | |
- | | eth21 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_23 eth0 +------+ +--vlan123--+ | | Et23 +-----+ Ethernet88 |
- | | | +--------------+ | | | | | | | |
- | | eth22 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_24 eth0 +------+ +--vlan124--+ | | Et24 +-----+ Ethernet92 |
- | | | +--------------+ | | | | | | | |
- | | eth23 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_25 eth0 +------+ +--vlan125--+ | | Et25 +-----+ Ethernet96 |
- | | | +--------------+ | | | | | | | |
- | | eth24 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_26 eth0 +------+ +--vlan126--+ | | Et26 +-----+ Ethernet100 |
- | | | +--------------+ | | | | | | | |
- | | eth25 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_27 eth0 +------+ +--vlan127--+ | | Et27 +-----+ Ethernet104 |
- | | | +--------------+ | | | | | | | |
- | | eth26 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_28 eth0 +------+ +--vlan128--+ | | Et28 +-----+ Ethernet108 |
- | | | +--------------+ | | | | | | | |
- | | eth27 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_29 eth0 +------+ +--vlan129--+ | | Et29 +-----+ Ethernet112 |
- | | | +--------------+ | | | | | | | |
- | | eth28 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_30 eth0 +------+ +--vlan130--+ | | Et30 +-----+ Ethernet116 |
- | | | +--------------+ | | | | | | | |
- | | eth29 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_31 eth0 +------+ +--vlan131--+ | | Et31 +-----+ Ethernet120 |
- | | | +--------------+ | | | | | | | |
- | | eth30 +------------------------+ | | | | | | |
- | | | +--------------+ +-------| | | | | | |
- | | | | VM_32 eth0 +------+ +--vlan132--+ | | Et32 +-----+ Ethernet124 |
- | | | +--------------+ + | | | | | |
- | | eth31 +------------------------+ | | | | | |
- | | | +-------| | | | | |
- | |---------+ | | | | |
- +-------------------------------------------------------------+ +----------+ +-------------+
-```
-Figure 2: VM set testbed with injected PTF docker
-
-In this testbed, we have 32 VMs and 1 PTF docker. The VMs use Arista vEOS. Each VM has 10 network interfaces:
- 1. 8 front panel ports. These ports are connected to openvswitch bridges, which are connected to vlan interfaces. The vlan interfaces are connected to the fanout switch (through physical port).
- 2. 1 back panel port. All testbed VMs connected to each other using this port (it isn't shown on the figure above).
- 3. 1 management port. This port is used to connect to the VMs
-
-The ptf docker container connects to the bridges which connect the VMs frontpanel ports and physical vlans. Each bridge has three ports:
- 1. Frontpanel port from a VM
- 2. Physical vlan port
- 3. PTF container port
-
-Packets coming from the physical vlan interface are sent to both the VMs and the PTF docker. Packets from the VM and PTF docker are
-sent to the vlan interface. It allows us to inject packets from the PTF host to DUT and maintain a BGP session between VM and DUT at the same time.
-
-### Deploy testbed with one VM set
-1. clone sonic-mgmt repo to local directory
-2. Edit 'ansible/veos' file. Put ip address of your server after 'ansible_host='
-3. Edit 'ansible/group_vars/eos/eos.yml' file. Put your internal snmp community string after 'snmp_rocommunity:'.
-4. Edit 'ansible/group_vars/vm_host'. Put your credentials to reach the server
-5. Check, that you can reach the server by running command 'ansible -i veos -m ping vm_host_1' from ansible directory. The output should contain 'pong'
-6. Edit 'ansible/group_vars/vm_host/main.yml'.
- * 'root_path': path where VMs virtual disks resides
- * 'vm_images_url': URL where VM images could be downloaded
- * 'cd_image_filename': filename of cd image of veos
- * 'hdd_image_filename': filename of hdd image of veos
- * 'http_proxy': your http_proxy
- * 'http_proxy': your https_proxy
-7. Edit 'ansible/host_vars/STR-ACS-SERV-01.yml'. It contains settings for STR-ACS-SERV-01. STR-ACS-SERV-02 contains similar settings which are applied to STR-ACS-SERV-02
- * 'mgmt_gw': ip address of gateway for management interfaces of VM. See 3.2
- * 'vm_X_enabled': true, if you want to run X vm set
- * 'vm_X_vlan_base': vlan number which is used for connection to first port of DUT.
- * 'vlans': list of vlan offsets for the VM FP ports. For example: if vlans equal to "5,6" it means that the VM frontpanel port 0 will be connected to vlan {{ vm_X_vlan_base + 5 - 1 }} and VM frontpanel port 1 will be connected to vlan {{ vm_X_vlan_base + 6 - 1 }}
-8. Edit 'ansible/minigraph/*.xml' files. You need to adjust following xml nodes to settings of your network:
- * DeviceMiniGraph/DpgDec/DeviceDataPlaneInfo/ManagementIPInterfaces/ManagementIPInterface/Prefix/IPPrefix
- * DeviceMiniGraph/DpgDec/DeviceDataPlaneInfo/ManagementIPInterfaces/ManagementIPInterface/PrefixStr
-9. Start testbed with command 'ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos start_vm_sets.yml --limit server_1 -e vm_set_1=true'
-10. Stop testbed with command 'ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos stop_vm_sets.yml --limit server_1 -e vm_set_1=true'
+# SONiC Testbed
+
+- [Overview](doc/README.testbed.Overview.md)
+- [Setup](doc/README.testbed.Setup.md)
+- [Topology](doc/README.testbed.Topology.md)
+- [Configuration](doc/README.testbed.Config.md)
+- [Command Line](doc/README.testbed.Cli.md)
+- [FAQ](doc/README.testbed.FAQ.md)
+- [Internal](doc/README.testbed.Internal.md)
diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg
index bf23f1abb56..91691208305 100644
--- a/ansible/ansible.cfg
+++ b/ansible/ansible.cfg
@@ -102,7 +102,7 @@ ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid}
# by default (as of 1.4), Ansible may display deprecation warnings for language
# features that should no longer be used and will be removed in future versions.
# to disable these warnings, set the following value to False:
-#deprecation_warnings = True
+deprecation_warnings = False
# (as of 1.8), Ansible can optionally warn when usage of the shell and
# command module appear to be simplified by using a default Ansible module
@@ -119,7 +119,7 @@ action_plugins = plugins/action
connection_plugins = plugins/connection
# lookup_plugins = /usr/share/ansible_plugins/lookup_plugins
# vars_plugins = /usr/share/ansible_plugins/vars_plugins
-# filter_plugins = /usr/share/ansible_plugins/filter_plugins
+filter_plugins = plugins/filter
callback_whitelist = profile_tasks
# by default callbacks are not loaded for /bin/ansible, enable this if you
@@ -155,7 +155,9 @@ callback_whitelist = profile_tasks
# wanting to use, for example, IP information from one group of servers
# without having to talk to them in the same playbook run to get their
# current IP information.
-fact_caching = memory
+fact_caching = jsonfile
+fact_caching_connection = ~/.ansible/cache
+fact_caching_timeout = 600
# retry files
@@ -232,3 +234,4 @@ accelerate_daemon_timeout = 30
# the default behaviour that copies the existing context or uses the user default
# needs to be changed to use the file system dependant context.
#special_context_filesystems=nfs,vboxsf,fuse
+
diff --git a/ansible/basic_check.yml b/ansible/basic_check.yml
new file mode 100644
index 00000000000..0f8f1219ee9
--- /dev/null
+++ b/ansible/basic_check.yml
@@ -0,0 +1,30 @@
+
+- hosts: sonic
+ gather_facts: no
+ tasks:
+
+ - name: Get process information in syncd docker
+ shell: docker exec -i syncd ps aux | grep /usr/bin/syncd
+ register: ps_out
+
+ - debug: var=ps_out.stdout_lines
+
+ - name: Verify that syncd process is running
+ assert: { that: "{{ ps_out.stdout_lines | length }} > 0"}
+
+ - name: Get syslog error information
+ shell: cat /var/log/syslog |tail -n 5000 |grep error
+ become: true
+ register: syslog_out
+ failed_when: false
+
+ - debug: var=syslog_out.stdout_lines
+
+ - name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ connection: local
+ become: no
+ tags: always
+
+ - include: roles/test/tasks/interface.yml
+
diff --git a/ansible/boot_onie.yml b/ansible/boot_onie.yml
new file mode 100644
index 00000000000..585c70549ce
--- /dev/null
+++ b/ansible/boot_onie.yml
@@ -0,0 +1,61 @@
+# Example usage:
+#
+# ansible-playbook boot_onie.yml -i inventory --vault-password-file ~/password.txt --limit devicename
+
+- hosts: all
+ gather_facts: no
+ tasks:
+
+ - name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ connection: local
+ tags: always
+ become: no
+
+ - name: Set next boot device to ONIE
+ become: true
+ shell: grub-editenv /host/grub/grubenv set next_entry=ONIE
+
+ - name: Reboot into ONIE
+ become: true
+ shell: sleep 2 && shutdown -r now "Boot into onie."
+ async: 1
+ poll: 0
+ ignore_errors: true
+
+ - set_fact:
+ real_ansible_host: "{{ ansible_ssh_host }}"
+
+ - name: Wait for switch to come back (to ONIE)
+ local_action:
+ wait_for host={{ real_ansible_host }}
+ port=22
+ state=started
+ delay=60
+ timeout=300
+ become: false
+ changed_when: false
+
+ - name: Wait for switch to reboot again
+ local_action:
+ wait_for host={{ real_ansible_host }}
+ port=22
+ state=stopped
+ delay=5
+ timeout=600
+ become: false
+ changed_when: false
+
+ - name: Wait for switch to come back (to SONiC)
+ local_action:
+ wait_for host={{ real_ansible_host }}
+ port=22
+ state=started
+ delay=30
+ timeout=600
+ search_regex=OpenSSH
+ become: false
+ changed_when: false
+
+ - name: Wait for the SONiC initialization process
+ pause: seconds=60
diff --git a/ansible/config_sonic_basedon_testbed.yml b/ansible/config_sonic_basedon_testbed.yml
new file mode 100644
index 00000000000..94ff94e8b80
--- /dev/null
+++ b/ansible/config_sonic_basedon_testbed.yml
@@ -0,0 +1,98 @@
+# This Playbook run time generate matching configuration file for SONiC switch(Minigraph) based on a specific testbed topology specified in testbed.csv
+# When user call testbed-cli to deploy a testbed topology, use this playbook to generate matching SONiC minigraph file and deploy it into SONiC switch under test.
+# Or when you know your topology name, you may use this playbook alone to generate a minigraph matching your topology name without deploy it.
+#
+# VM Topologies are defined inside of vars/ directory in files vars/topo_{{ topology_name}}.yml
+# Every topology should have a name to distinct one topology from another on the server
+# Every topology contains a ptf container which will be used as placeholder for the injected interfaces from VMs, or direct connections to PTF host
+# VMs inventory file is also required to have all VMs ready for generating the minigraph file
+# VMs inventory is in file 'veos'
+#
+# Template files for generating minigraph.xml are defined in template/topo directory
+#
+# To generate and deploy minigraph for SONiC switch matching the VM topology please use following command
+# ansible-playbook -i lab config_sonic_basedon_testbed.yml -l sonic_dut_name -e vm_base=VM0300 -e topo=t0 [-e deploy=true]
+#
+# Parameters
+# -l str-msn2700-01 - the sonic_dut_name you are going to generate minigraph for
+# -e vm_base=VM0300 - the VM name which is used to as base to calculate VM name for this set
+# -e topo=t0 - the name of topology to generate minigraph file
+# -e deploy=True - if deploy the newly generated minigraph to the targent DUT, default is false if not defined
+#
+# After minigraph.xml is generated, the playbook will replace the original minigraph file under ansible/minigraph/ with the newly generated minigraph file for the SONiC device.
+# The playbook will based on deploy=True or False to deside if load the SONiC device with new minigraph or not.
+# If deploy=true, the playbook will reboot the SONiC switch after change to new minigraph to make it take effect
+#
+####################################################################################################################################################################################
+
+- hosts: sonic
+ gather_facts: yes
+ tasks:
+ - fail: msg="need to provide topology type and vm base like topo=t0 and vm_base=VM100"
+ when: (topo is not defined) or (vm_base is not defined)
+
+ - fail: msg="need hwsku, interface speed, netmask and interface prefix/postfix defined to generate configuration file"
+ when: (hwsku is not defined) or (iface_speed is not defined) or (mgmt_subnet_mask_length is not defined)
+
+ - set_fact:
+ VM_topo: "{% if 'ptf' in topo %}False{% else %}True{% endif %}"
+ remote_dut: "{{ ansible_ssh_host }}"
+ template_name: "{{ 't1' if topo=='ptf32' else topo }}"
+
+ - testbed_vm_info: base_vm="{{ vm_base }}" topo="{{ topo }}"
+ connection: local
+ when: VM_topo
+
+ - name: find interface name mapping
+ port_alias: hwsku="{{ hwsku }}"
+ connection: local
+
+ - debug: var=port_alias
+
+ - name: save original minigraph file (if original file does not exist, then ignore errors)
+ shell: mv minigraph/{{ inventory_hostname }}.xml minigraph/{{ inventory_hostname }}.xml.orig
+ connection: local
+ ignore_errors: true
+
+ - name: create minigraph file in minigraph folder
+ become: true
+ template: src=templates/topo/{{ template_name }}.j2
+ dest=minigraph/{{ inventory_hostname}}.xml
+ connection: local
+
+ - block:
+ - name: saved original minigraph file (if original file may don't exist, then ignore errors)
+ shell: mv /etc/sonic/minigraph.xml /etc/sonic/minigraph.xml.orig
+ become: true
+ ignore_errors: true
+
+ - name: create minigraph file for SONiC device
+ template: src=templates/topo/{{ template_name }}.j2
+ dest=/etc/sonic/minigraph.xml
+ become: true
+
+ - name: disable automatic minigraph update if we are deploying new minigraph into SONiC
+ lineinfile:
+ name: /etc/sonic/updategraph.conf
+ regexp: '^enabled='
+ line: 'enabled=false'
+ become: true
+
+ # reload the device and wait it to come back
+ - name: Reboot is required for minigraph change
+ shell: sleep 2 && shutdown -r now "Ansible Create new configuration Minigraph file, triggered reboot."
+ async: 1
+ poll: 0
+ become: true
+ ignore_errors: true
+
+ - name: waiting for switch to come back
+ local_action:
+ wait_for host={{ remote_dut }}
+ port=22
+ state=started
+ delay=30
+ timeout=300
+ become: false
+ changed_when: false
+ when: deploy is defined and deploy|bool == true
diff --git a/ansible/doc/README.testbed.Cli.md b/ansible/doc/README.testbed.Cli.md
new file mode 100644
index 00000000000..dd0dabba1bc
--- /dev/null
+++ b/ansible/doc/README.testbed.Cli.md
@@ -0,0 +1,50 @@
+# Testbed Command Line
+
+```testbed-cli.sh``` is the command line to setup/teardown the testbed, as well as add/remove/switch topology.
+
+- Maintenance purposes only
+ - ```./testbed-cli.sh start-vms {server_name} ~./password``` # after a server restarted
+ - ```./testbed-cli.sh stop-vms {server_name} ~./password``` # before a server restarted
+- General usage
+ - ```./testbed-cli.sh add-topo {topo_name} ~./password``` # create topo with name {topo_name} from testbed.csv
+ - ```./testbed-cli.sh remove-topo {topo_name} ~./password``` # destroy topo with name {topo_name} from testbed.csv
+ - ```./testbed-cli.sh renumber-topo {topo_name} ~./password``` # renumber topo with name {topo_name} from testbed.csv
+
+## Add/Remove topo
+```
+# uniq-name,testbed-name,topo,ptf_image_name,ptf_ip,server,vm_base,dut,owner
+vms1-1-t1,vms1-1,t1,docker-ptf-sai-mlnx,10.0.10.5/23,server_1,VM0100,str-msn2700-11,t1 tests
+vms1-1-t1-lag,vms1-1,t1-lag,docker-ptf-sai-mlnx,10.0.10.5/23,server_1,VM0100,str-msn2700-11,t1-lag tests
+
+```
+Goal is to use one VM with different topologies
+
+- To add a new testbed “vms1-1-t1”:
+ - ./testbed-cli add-topo vms1-1-t1 ~/.password
+
+- To switch from testbed “vms1-1-t1” to testbed “vms1-1-lag”
+ - ./testbed-cli remove-topo vms1-1-t1 ~/.password
+ - ./testbed-cli add-topo vms1-1-t1-lag ~/.password
+
+Feature: The VMs configuration will be updated while switching from one topo to another
+Feature: Might be used for renumbering too
+Caveat: Have to remember what was the initial topology. Should be fixed in future
+
+# Renumber topo
+```
+# uniq-name,testbed-name,topo,ptf_image_name,ptf_ip,server,vm_base,dut,owner
+vms2-2-b,vms2-2,t1,docker-ptf-sai-brcm,10.0.10.7/23,server_1,VM0100,str-d6000-05,brcm test
+vms2-2-m,vms2-2,t1,docker-ptf-sai-mlnx,10.0.10.7/23,server_1,VM0100,str-msn2700-5,mlnx test
+
+```
+Goal is to use one VM set against different DUTs
+
+- To add a new testbed “vms2-2-b”:
+ - ./testbed-cli add-topo vms2-2-b ~/.password
+
+- To switch from testbed “vms2-2-b” to testbed “vms2-2-m”
+ - ./testbed-cli renumber-topo vms2-2-m ~/.password
+
+Feature: The VMs configuration will NOT be updated while switching from one topo to another (faster).
+
+TODO: check topo field when renumbering between topologies
diff --git a/ansible/doc/README.testbed.Config.md b/ansible/doc/README.testbed.Config.md
new file mode 100644
index 00000000000..db6c8f9e91e
--- /dev/null
+++ b/ansible/doc/README.testbed.Config.md
@@ -0,0 +1,43 @@
+# Testbed Configuration
+
+```testbed.csv``` is the topology configuration file for the testbed.
+
+# ```testbed.csv```
+```
+# conf-name,group-name,topo,ptf_image_name,ptf_mgmt_ip,server,vm_base,dut,comment
+ptf1-m,ptf1,ptf32,docker-ptf-sai-mlnx,10.255.0.188/24,server_1,,str-msn2700-01,Tests ptf
+vms-t1,vms1-1,t1,docker-ptf-sai-mlnx,10.255.0.178/24,server_1,VM0100,str-msn2700-01,Tests vms
+vms-t1-lag,vms1-1,t1-lag,docker-ptf-sai-mlnx,10.255.0.178/24,server_1,VM0100,str-msn2700-01,Tests vms
+
+```
+
+- conf-name - to address row in table
+- group-name – used in interface names, up to 8 characters
+- topo – name of topology
+- ptf_imagename – defines PTF image
+- ptf_mgmt_ip – ip address for mgmt interface of PTF container
+- server – server where the testbed resides
+- vm_base – first VM for the testbed. If empty, no VMs are used
+- dut – target dut name
+- comment – any text here
+
+# ```testbed.csv``` consistency rules
+```
+# uniq-name,testbed-name,topo,ptf_image_name,ptf_ip,server,vm_base,dut,owner
+vms2-2-b,vms2-2,t1,docker-ptf-sai-brcm,10.0.10.7/23,server_1,VM0100,str-d6000-05,brcm test
+vms2-2-m,vms2-2,t1,docker-ptf-sai-mlnx,10.0.10.7/23,server_1,VM0100,str-msn2700-5,mlnx test
+
+```
+Must be strictly checked in code reviews
+ - uniq-name must be unique
+ - All testbed records with the same testbed-name must have the same:
+ - ptf_ip
+ - server
+ - vm_base
+ - testbed-name must be up to 8 characters long
+ - topo name must be valid (topo registered in ```veos``` and topo file presented in vars/topo_*.yml
+ - ptf_imagename must be valid
+ - server name must be valid and presented in veos inventory file
+ - vm_base must not overlap with testbeds from different groups (different test-name)
+
+TODO: check this constraints in testbed-cli.sh
diff --git a/ansible/doc/README.testbed.FAQ.md b/ansible/doc/README.testbed.FAQ.md
new file mode 100644
index 00000000000..a5a9d309af9
--- /dev/null
+++ b/ansible/doc/README.testbed.FAQ.md
@@ -0,0 +1,13 @@
+# FAQ
+
+## How to find IP addresses of VMs and PTF
+ - IP address of testbed PTF container could be found in testbed.csv
+ - To find some VM IP address:
+ - find vm_offset parameter for the VM in your topology file
+ - find vm_base parameter in testbed.csv
+ - Calculate physical VM name as vm_base + vm_offset
+ - Find physical VM entry in veos file
+
+TODO: Create ansible playbook for this
+
+
diff --git a/ansible/doc/README.testbed.Internal.md b/ansible/doc/README.testbed.Internal.md
new file mode 100644
index 00000000000..78521f80879
--- /dev/null
+++ b/ansible/doc/README.testbed.Internal.md
@@ -0,0 +1,129 @@
+# Testbed internals
+
+## Topology definition
+
+ - List of currently defined topologies in veos inventory file
+```
+[servers:vars]
+topologies=[‘t1', ‘t1-lag', 't0', 'ptf32', 'ptf64']
+```
+ - Topologies stored inside of vars/topo_*.yml, where * is a topology name
+ - Configuration templates for the topologies saved in roles/eos/templates/*.yml
+
+## Topology file
+
+ - Topology file is a regular ansible yaml file with variables:
+ - topology – defines physical topology
+ - configuration – defines variables for VMs configuration templates
+ - configuration_properties – defines group variables for VMs configuration templates
+
+ - topology dictionary is required
+ - configuration and configuration_properties are optional and used only for topologies with VMs
+
+## Topology file. topology dictionary
+
+ - Two dictionaries:
+ - host_interface – defines a list of port offsets which would be inserted into the PTF container
+ - VMs – defines a list and a physical configuration of VMs used in topology
+
+```
+topology:
+ host_interfaces:
+ - 0
+ - 1
+ VMs:
+ ARISTA01T1:
+ vlans:
+ - 2
+ - 3
+ vm_offset: 0
+ ARISTA02T1:
+ vlans:
+ - 4
+ vm_offset: 1
+
+```
+ - ARISTA01T1 – hostname for a VM
+ - vlans - list of vlan offsets used in VM
+ - vm_offset – offset of VM with base configured as vm_base in testbed.csv
+
+ - In this example:
+ - Let’s consider: vm_base == VM0100, vlan_base == ‘100’
+ - First VM:
+ - hostname ARISTA01T1
+ - Uses VM with physical name VM0100
+ - Ethernet1 is connected to vlan 102
+ - Ethernet2 is connected to vlan 103
+ - Ethernet9 is connected to backplane network (implicitly configured)
+ - Second VM:
+ - hostname ARISTA02T1
+ - Uses VM with physical name VM0101 (vm_offset: 1 + vm_base: VM0100)
+ - Ethernet1 is connected to vlan 104
+ - Ethernet9 is connected to backplane network (implicitly configured)
+ - PTF container:
+ - 5 ethernet interfaces:
+ - eth0 is directly connected to DUT. vlan 100
+ - eth1 is directly connected to DUT. vlan 101
+ - eth2 is injected interface for Ethernet1 of VM ARISTA01T1
+ - eth3 is injected interface for Ethernet2 of VM ARISTA01T1
+ - eth4 is injected interface for Ethernet1 of VM ARISTA02T1
+
+## Topology file. configuration_properties
+```
+configuration_properties:
+ common:
+ nhipv4: 10.10.246.100
+ nhipv6: FC0A::C9
+ spine:
+ swrole: spine
+ podset_number: 200
+ tor_number: 16
+ tor_subnet_number: 2
+ leaf_asn_start: 62001
+ tor_asn_start: 65501
+ failure_rate: 0
+ tor:
+ swrole: tor
+ tor_subnet_number: 5
+
+```
+ - Configuration properties contains any number of dictionary entries
+ - You could have as many as you want
+ - Lately you can refer to these entries in your configuration dictionary. See entry “properties”
+ - You could use them as {{ props.property_name }} inside of jinja2 template. Example: {% for tor in range(0, props.tor_number) %}
+
+## Topology file. configuration
+```
+configuration:
+ ARISTA01T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.0
+ - FC00::1
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.1/32
+ ipv6: 2064:100::1/128
+ Ethernet1:
+ ipv4: 10.0.0.1/31
+ ipv6: fc00::2/126
+ Ethernet9:
+ ipv4: 10.10.246.1/24
+ ipv6: fc0a::2/64
+
+```
+ - Configurations contains any number of dictionary entries
+ - You could have as many as you want
+ - You have to have entry properties when you want to bring some common property into the configuration
+ - You could use configuration as {{configuration[hostname].property }} inside of jinja2 template.
+
+ Example:
+```
+{% set host = configuration[hostname] %}
+{% for name, iface in host['interfaces'].items() %}
+```
diff --git a/ansible/doc/README.testbed.Overview.md b/ansible/doc/README.testbed.Overview.md
new file mode 100644
index 00000000000..4fcf3aa1381
--- /dev/null
+++ b/ansible/doc/README.testbed.Overview.md
@@ -0,0 +1,56 @@
+# SONiC Testbed Overview
+
+This document gives overview of the SONiC testbed.
+
+## Physical topology
+
+
+
+1. Every DUT port is connected to one of leaf fanout switches
+2. Every leaf fanout switch has unique vlan tag for every DUT port
+3. Root fanout switch connects leaf fanout switches and testbed servers
+4. Connections from root fanout switches are 802.1Q trunks
+5. Any testbed server can access any DUT port by sending a packet with the port vlan tag (root fanout switch should have this vlan number enabled on the server trunk)
+
+## Fanout switch
+*Fanout switch*: A physical switch which enables VLAN trunking.
+ * Hardware SKU: Arista 7260 or similar
+ * Et33 is a vlan trunking port and is connected to the eth0 port of the linux host.
+ * Et1-Et32 are vlan access ports and are connect to DUT.
+ * Enable LACP/LLDP passthrough
+ * Disable spanning tree protocol
+
+## Testbed server
+
+- Server SKU (this is what we are using, not mandatory): Dell 730; 2 CPUs each has 18 cores; 192G memory; hard disk:2X500G
+- NIC: Mellanox MT27700 Family CX4
+
+
+
+### Network connections
+
+- The testbed server has 2 network ports:
+ - Trunk port (Mellanox MT27700 Family CX4) to root fanout switch
+ - Server management port to manage the server, VMs and PTF containers on the server
+
+### VMs
+
+The VMs use Arista vEOS. They are using to setup protocol test such as BGP, LACP, LLDP. They are created using ```testbed-cli.sh start-vms``` command. Each VM uses 2G of RAM and has 10 network interfaces:
+
+- 8 front panel ports. These ports are connected to openvswitch bridges, which are connected to vlan interfaces. The vlan interfaces are connected to the fanout switch (through physical port).
+- 1 back panel port. All VMs in one topology have their 9th port connected to this backplane network.
+- 1 management port. This port is used to connect to the VMs
+
+### PTF
+
+PTF container is used to send and receive data packets to validate the DUT data plane.
+
+#### PTF with direct port
+
+
+DUT front panel port is directly connected to one of PTF container ports. Usually eth0 port of PTF container connects Ethernet0 port of DUT, eth1 port of PTF container connects Ethernet4 port of DUT and so on. This is usually used in PTF topologies to connect DUT ports to PTF container ports.
+
+#### PTF with injected port
+
+
+DUT front panel port is directly connected to one of VMs interfaces. But also we have a tap into this connection. Packets coming from the physical vlan interface are sent to both the VMs and the PTF docker. Packets from the VM and PTF docker are sent to the vlan interface. It allows us to inject packets from the PTF host to DUT and maintain a BGP session between VM and DUT at the same time.
diff --git a/ansible/doc/README.testbed.Setup.md b/ansible/doc/README.testbed.Setup.md
new file mode 100644
index 00000000000..a741a09b9e5
--- /dev/null
+++ b/ansible/doc/README.testbed.Setup.md
@@ -0,0 +1,93 @@
+# Testbed Setup
+
+This document describes the steps to setup the testbed and deploy a topology.
+
+## Prepare testbed server
+
+- Install Ubuntu 16.04 or 17.04 amd64 server.
+- Setup management port configuration using sample ```/etc/network/interfaces```.
+
+```
+root@server-1:~# cat /etc/network/interfaces
+# The management network interface
+auto ma0
+iface ma0 inet manual
+
+# Server, VM and PTF management interface
+auto br1
+iface br1 inet static
+ bridge_ports ma0
+ bridge_stp off
+ bridge_maxwait 0
+ bridge_fd 0
+ address 10.250.0.245
+ netmask 255.255.255.0
+ network 10.250.0.0
+ broadcast 10.250.0.255
+ gateway 10.250.0.1
+ dns-nameservers 10.250.0.1 10.250.0.2
+ # dns-* options are implemented by the resolvconf package, if installed
+```
+
+- Installed python 2.7 (required by ansible).
+- Add Docker’s official GPG key
+```
+ $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
+```
+
+## Build and run ```sonic-mgmt``` docker
+
+ansible playbook in ```sonic-mgmt``` repo requires to setup ansible and various dependencies.
+We have built a ```sonic-mgmt``` docker that installs all dependencies, and you can simply
+build that docker and ansible playbook inside the docker.
+
+- Build ```sonic-mgmt``` docker
+```
+git clone --recursive https://github.com/Azure/sonic-buildimage.git
+make target/docker-sonic-mgmt.gz
+```
+
+- Run ```sonic-mgmt``` docker
+```
+docker load -i target/docker-sonic-mgmt.gz
+docker run -it docker-sonic-mgmt bash
+cd ~/sonic-mgmt
+```
+
+From now on, all steps are running inside the ```sonic-mgmt``` docker.
+
+## Prepare testbed configurations
+
+Prepare various configuration files for your testbed.
+
+- Add/Update your testbed server management IP in veos file. Example:'STR-ACS-SERV-01 ansible_host=10.0.0.5' where 10.0.0.5 your server mgmt ip
+- Add testbed server credentials in ```ansible/group_vars/vm_host/creds.yml```
+- Check that ansible could reach this device by command ```ansible -m ping -i veos vm_host_1```
+- Put files: ```Aboot-veos-serial-8.0.0.iso``` and ```vEOS-lab-4.15.9M.vmdk``` to /home/{your_username from step 3}/veos-vm/images on your testbed server
+- Edit ```ansible/host_vars/STR-ACS-SERV-01.yml```. You need to change ```external_iface```,```mgmt_gw``` and ```mgmt_prefixlen```. These settings define network parameters for VM/ptf management interfaces. Example:
+
+```
+external_iface: p4p1 <--- trunk port of the server (connected to the fanout switch)
+mgmt_gw: 10.250.0.1 <--- ip of gateway for VM mgmt interfaces
+mgmt_prefixlen: 24 <--- prefixlen for management interfaces
+```
+
+- Add ip addresses for your VMs in veos inventory file ```ansible/veos``` inventory file. These IP addresses should be in the management subnet defined in above file.
+- Update VM credentials in ```ansible/group_vars/eos/creds.yml```. Use root:123456 as credentials
+- Add information about your docker registry here: ```vars/docker_registry.yml```
+
+## Setup VMs in the server
+
+
+```
+./testbed-cli.sh start-vms server_1 password.txt
+```
+
+Check that all VMs are up and running: ```ansible -m ping -i veos server_1```
+
+## Deploy topology
+
+- Update testbed.csv with your data. At least update PTF mgmt interface settings
+- To deploy PTF topology run: ```./testbed-cli.sh add-topo ptf1-m ~/.password```
+- To remove PTF topology run: ```./testbed-cli.sh remove-topo ptf1-m ~/.password```
+- To deploy T1 topology run: ```./testbed-cli.sh add-topo vms-t1 ~/.password```
diff --git a/ansible/doc/README.testbed.Topology.md b/ansible/doc/README.testbed.Topology.md
new file mode 100644
index 00000000000..75ab767ff29
--- /dev/null
+++ b/ansible/doc/README.testbed.Topology.md
@@ -0,0 +1,65 @@
+# Topologies
+
+1. Configuration of a testbed topology is defined in one file: ```testbed.csv```
+2. One script to operate all testbeds: ```testbed-cli.sh```
+3. Flexible topologies which allow to use VM_SET and PTF container as one entity
+4. All VM management ip information in one place: ```veos``` inventory file
+5. PTF container is generalized and used in every topology
+6. Automatic provisioning of fanout switch configuration (should be refactored)
+
+## Testbed topology configuration
+
+- One entry in ```testbed.csv``` consist of:
+ - physical topology: How ports of VMs and PTF connected to DUT
+ - configuration templates for VMs
+- Topologies are defined in vars/topo_*.yml files
+- Current topologies are:
+ - t1: 32 VMs + PTF container for injected ports
+ - t1-lag: 24 VMs + PTF container for injected ports. 8 VMs has two ports each in LAG
+ - ptf32: classic PTF container with 32 ports connected directly to DUT ports
+ - ptf64: as ptf32, but with 64 ports
+ - t0: 4 VMs + ptf. PTF container has 4 injected ports + 28 directly connected ports
+
+## Current topologies
+
+### t1
+
+
+
+ - Requires 32 VMs
+ - All DUT ports are connected to VMs
+ - PTF container has injected ports only
+
+### t1-lag
+
+
+
+ - Requires 24 VMs
+ - All DUT ports are connected to VMs
+ - PTF container has injected ports only
+
+### ptf32
+
+
+
+ - Requires 0 VMs
+ - All DUT ports are directly connected to PTF container
+ - PTF container has no injected ports
+
+### ptf64
+
+
+
+ - Requires 0 VMs
+ - All DUT ports are directly connected to PTF container
+ - PTF container has no injected ports
+
+### t0
+
+
+
+ - Requires 4 VMs
+ - 4 DUT ports are connected to VMs
+ - PTF container has 4 injected ports and 28 directly connected ports
+
+
diff --git a/ansible/doc/img/testbed-direct.png b/ansible/doc/img/testbed-direct.png
new file mode 100644
index 00000000000..b1304c3182e
Binary files /dev/null and b/ansible/doc/img/testbed-direct.png differ
diff --git a/ansible/doc/img/testbed-injected.png b/ansible/doc/img/testbed-injected.png
new file mode 100644
index 00000000000..34015ad1a58
Binary files /dev/null and b/ansible/doc/img/testbed-injected.png differ
diff --git a/ansible/doc/img/testbed-ptf32.png b/ansible/doc/img/testbed-ptf32.png
new file mode 100644
index 00000000000..04cec7a8e61
Binary files /dev/null and b/ansible/doc/img/testbed-ptf32.png differ
diff --git a/ansible/doc/img/testbed-ptf64.png b/ansible/doc/img/testbed-ptf64.png
new file mode 100644
index 00000000000..9f2d4330b50
Binary files /dev/null and b/ansible/doc/img/testbed-ptf64.png differ
diff --git a/ansible/doc/img/testbed-server.png b/ansible/doc/img/testbed-server.png
new file mode 100644
index 00000000000..d03020609bd
Binary files /dev/null and b/ansible/doc/img/testbed-server.png differ
diff --git a/ansible/doc/img/testbed-t0.png b/ansible/doc/img/testbed-t0.png
new file mode 100644
index 00000000000..77c7db16def
Binary files /dev/null and b/ansible/doc/img/testbed-t0.png differ
diff --git a/ansible/doc/img/testbed-t1-lag.png b/ansible/doc/img/testbed-t1-lag.png
new file mode 100644
index 00000000000..f60c55d68cc
Binary files /dev/null and b/ansible/doc/img/testbed-t1-lag.png differ
diff --git a/ansible/doc/img/testbed-t1.png b/ansible/doc/img/testbed-t1.png
new file mode 100644
index 00000000000..6153d65b480
Binary files /dev/null and b/ansible/doc/img/testbed-t1.png differ
diff --git a/ansible/doc/img/testbed.png b/ansible/doc/img/testbed.png
new file mode 100644
index 00000000000..650acf8edd6
Binary files /dev/null and b/ansible/doc/img/testbed.png differ
diff --git a/ansible/fanout.yml b/ansible/fanout.yml
new file mode 100644
index 00000000000..9651613bfa5
--- /dev/null
+++ b/ansible/fanout.yml
@@ -0,0 +1,9 @@
+#Example:
+# ansible-playbook fanout.yml -i str --limit str-7260-01 -b --vault-password-file ~/password.txt
+- hosts: [fanout]
+ gather_facts: no
+ roles:
+ - fanout
+
+
+
diff --git a/ansible/fanout_connect.yml b/ansible/fanout_connect.yml
new file mode 100644
index 00000000000..d662e8010fa
--- /dev/null
+++ b/ansible/fanout_connect.yml
@@ -0,0 +1,27 @@
+#Example:
+# ansible-playbook fanout_connect.yml -i veos --limit server_1 --vault-password-file password.txt -e "dut=str-msn2700-01"
+- hosts: servers:&vm_host
+ gather_facts: no
+ tasks:
+ - fail: msg="Please provide VM server name and server port name, see comment line in playbook"
+ when:
+ - dut is not defined
+
+ - set_fact:
+ server: "{{ inventory_hostname|lower }}"
+ server_port: "{{ external_iface }}"
+
+ - debug: msg="Connect {{ server }}:{{ server_port }} to {{ dut }}"
+
+ - name: get the username running the deploy
+ command: whoami
+ connection: local
+ become: no
+ register: calling_username
+ changed_when: false
+
+ - set_fact: userid={{ calling_username.stdout }}
+
+ - include: roles/fanout/tasks/rootfanout_connect.yml
+
+
diff --git a/ansible/files/creategraph.py b/ansible/files/creategraph.py
new file mode 100644
index 00000000000..0ccb473672d
--- /dev/null
+++ b/ansible/files/creategraph.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+import csv, sys, os
+from lxml import etree
+
+DEVICECSV = 'sonic_lab_devices.csv'
+LINKCSV = 'sonic_lab_links.csv'
+LAB_CONNECTION_GRAPH_ROOT_NAME = 'LabConnectionGraph'
+LAB_CONNECTION_GRAPH_DPGL2_NAME = 'DevicesL2Info'
+
+class LabGraph(object):
+
+ """
+ This is used to create "graph" file of lab for all connections and vlan info from csv file
+ We(both engineer and lab technician) maintian and modify the csv file to keep track of the lab
+ infrastucture for Sonic development and testing environment.
+ """
+
+ def __init__(self, dev_csvfile='', link_csvfile=''):
+ #TODO:make generated xml file name as parameters in the future to make it more flexible
+ self.devices = []
+ self.links = []
+ self.devcsv = dev_csvfile
+ self.linkcsv = link_csvfile
+ self.png_xmlfile = 'str_sonic_png.xml'
+ self.dpg_xmlfile = 'str_sonic_dpg.xml'
+ self.one_xmlfile = 'lab_connection_graph.xml'
+ self.pngroot = etree.Element('PhysicalNetworkGraphDeclaration')
+ self.dpgroot = etree.Element('DataPlaneGraph')
+
+
+ def read_devices(self):
+ csv_dev = open(self.devcsv)
+ csv_devices = csv.DictReader(csv_dev)
+ devices_root = etree.SubElement(self.pngroot, 'Devices')
+ for row in csv_devices:
+ attrs = {}
+ self.devices.append(row)
+ for key in row:
+ if key.lower() != 'managementip':
+ attrs[key]=row[key].decode('utf-8')
+ prod = etree.SubElement(devices_root, 'Device', attrs)
+ csv_dev.close()
+
+ def read_links(self):
+ csv_file = open(self.linkcsv)
+ csv_links = csv.DictReader(csv_file)
+ links_root = etree.SubElement(self.pngroot, 'DeviceInterfaceLinks')
+ for link in csv_links:
+ attrs = {}
+ for key in link:
+ if key.lower() != 'vlanid' and key.lower() != 'vlanmode':
+ attrs[key]=link[key].decode('utf-8')
+ prod = etree.SubElement(links_root, 'DeviceInterfaceLink', attrs)
+ self.links.append(link)
+ csv_file.close()
+
+ def generate_dpg(self):
+ for dev in self.devices:
+ hostname = dev.get('Hostname', '')
+ managementip = dev.get('ManagementIp', '')
+ if hostname and 'fanout' in dev['Type'].lower():
+ ###### Build Management interface IP here, if we create each device indivial minigraph file, we may comment this out
+ l3inforoot = etree.SubElement(self.dpgroot, 'DevicesL3Info', {'Hostname': hostname})
+ etree.SubElement(l3inforoot, 'ManagementIPInterface', {'Name': 'ManagementIp', 'Prefix': managementip})
+ ####### Build L2 information Here
+ l2inforoot = etree.SubElement(self.dpgroot, LAB_CONNECTION_GRAPH_DPGL2_NAME, {'Hostname': hostname})
+ vlanattr = {}
+ for link in self.links:
+ if link['StartDevice'] == hostname:
+ vlanattr['portname'] = link['StartPort']
+ if link['EndDevice'] == hostname:
+ vlanattr['portname'] = link['EndPort']
+ if link['StartDevice'] == hostname or link['EndDevice'] == hostname:
+ vlanattr['vlanids'] = link['VlanID']
+ vlanattr['mode'] = link['VlanMode']
+ etree.SubElement(l2inforoot, 'InterfaceVlan', vlanattr)
+
+ def create_xml(self):
+ '''
+
+ if two seperate file of png and dpg needed, uncomment these part
+
+ pngxml = open(self.png_xmlfile, 'w')
+ png = etree.tostring(self.pngroot, pretty_print=True)
+ pngxml.write(png)
+
+ pngxml = open(self.dpg_xmlfile, 'w')
+ dpg = etree.tostring(self.dpgroot, pretty_print=True)
+ pngxml.write(dpg)
+ '''
+
+ onexml = open(self.one_xmlfile, 'w')
+ root=etree.Element(LAB_CONNECTION_GRAPH_ROOT_NAME)
+ root.append(self.pngroot)
+ root.append(self.dpgroot)
+ result = etree.tostring(root, pretty_print=True)
+ onexml.write(result)
+
+def main():
+
+ mygraph = LabGraph(DEVICECSV, LINKCSV)
+
+ mygraph.read_devices()
+ mygraph.read_links()
+ mygraph.generate_dpg()
+ mygraph.create_xml()
+
+
+if __name__ == '__main__':
+ main()
+
diff --git a/ansible/files/lab_connection_graph.xml b/ansible/files/lab_connection_graph.xml
new file mode 100644
index 00000000000..885b21a8fd8
--- /dev/null
+++ b/ansible/files/lab_connection_graph.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ansible/files/sonic_lab_devices.csv b/ansible/files/sonic_lab_devices.csv
new file mode 100644
index 00000000000..b11a58d53d3
--- /dev/null
+++ b/ansible/files/sonic_lab_devices.csv
@@ -0,0 +1,5 @@
+Hostname,ManagementIp,HwSku,Type
+str-msn2700-01,10.251.0.188/23,Mellanox-2700,DevSonic
+str-7260-10,10.251.0.13/23,Arista-7260QX-64,FanoutLeaf
+str-7260-11,10.251.0.234/23,Arista-7260QX-64,FanoutRoot
+str-acs-serv-01,10.251.0.245/23,TestServ,Server
diff --git a/ansible/files/sonic_lab_links.csv b/ansible/files/sonic_lab_links.csv
new file mode 100644
index 00000000000..f82e968740f
--- /dev/null
+++ b/ansible/files/sonic_lab_links.csv
@@ -0,0 +1,35 @@
+StartDevice,StartPort,EndDevice,EndPort,BandWidth,VlanID,VlanMode
+str-msn2700-01,Ethernet0,str-7260-10,Ethernet1,40000,1681,Access
+str-msn2700-01,Ethernet4,str-7260-10,Ethernet2,40000,1682,Access
+str-msn2700-01,Ethernet8,str-7260-10,Ethernet3,40000,1683,Access
+str-msn2700-01,Ethernet12,str-7260-10,Ethernet4,40000,1684,Access
+str-msn2700-01,Ethernet16,str-7260-10,Ethernet5,40000,1685,Access
+str-msn2700-01,Ethernet20,str-7260-10,Ethernet6,40000,1686,Access
+str-msn2700-01,Ethernet24,str-7260-10,Ethernet7,40000,1687,Access
+str-msn2700-01,Ethernet28,str-7260-10,Ethernet8,40000,1688,Access
+str-msn2700-01,Ethernet32,str-7260-10,Ethernet9,40000,1689,Access
+str-msn2700-01,Ethernet36,str-7260-10,Ethernet10,40000,1690,Access
+str-msn2700-01,Ethernet40,str-7260-10,Ethernet11,40000,1691,Access
+str-msn2700-01,Ethernet44,str-7260-10,Ethernet12,40000,1692,Access
+str-msn2700-01,Ethernet48,str-7260-10,Ethernet13,40000,1693,Access
+str-msn2700-01,Ethernet52,str-7260-10,Ethernet14,40000,1694,Access
+str-msn2700-01,Ethernet56,str-7260-10,Ethernet15,40000,1695,Access
+str-msn2700-01,Ethernet60,str-7260-10,Ethernet16,40000,1696,Access
+str-msn2700-01,Ethernet64,str-7260-10,Ethernet17,40000,1697,Access
+str-msn2700-01,Ethernet68,str-7260-10,Ethernet18,40000,1698,Access
+str-msn2700-01,Ethernet72,str-7260-10,Ethernet19,40000,1699,Access
+str-msn2700-01,Ethernet76,str-7260-10,Ethernet20,40000,1700,Access
+str-msn2700-01,Ethernet80,str-7260-10,Ethernet21,40000,1701,Access
+str-msn2700-01,Ethernet84,str-7260-10,Ethernet22,40000,1702,Access
+str-msn2700-01,Ethernet88,str-7260-10,Ethernet23,40000,1703,Access
+str-msn2700-01,Ethernet92,str-7260-10,Ethernet24,40000,1704,Access
+str-msn2700-01,Ethernet96,str-7260-10,Ethernet25,40000,1705,Access
+str-msn2700-01,Ethernet100,str-7260-10,Ethernet26,40000,1706,Access
+str-msn2700-01,Ethernet104,str-7260-10,Ethernet27,40000,1707,Access
+str-msn2700-01,Ethernet108,str-7260-10,Ethernet28,40000,1708,Access
+str-msn2700-01,Ethernet112,str-7260-10,Ethernet29,40000,1709,Access
+str-msn2700-01,Ethernet116,str-7260-10,Ethernet30,40000,1710,Access
+str-msn2700-01,Ethernet120,str-7260-10,Ethernet31,40000,1711,Access
+str-msn2700-01,Ethernet124,str-7260-10,Ethernet32,40000,1712,Access
+str-7260-11,Ethernet19,str-acs-serv-01,p4p1,40000,,Trunk
+str-7260-11,Ethernet30,str-7260-10,Ethernet64,40000,1681-1712,Trunk
diff --git a/ansible/group_vars/all/labinfo.json b/ansible/group_vars/all/labinfo.json
new file mode 100644
index 00000000000..183d9ffd39b
--- /dev/null
+++ b/ansible/group_vars/all/labinfo.json
@@ -0,0 +1,28 @@
+{
+ "hwsku_map": {
+ "Arista-7050-Q4S48": "Arista",
+ "Arista-7508-Q288": "Arista",
+ "Arista-7260QX-64": "Arista",
+ "Arista-VM": "Arista",
+ "Nexus-3064-NX": "Nexus",
+ "Force10-S6100": "Force10",
+ "Force10-S6000": "Force10"
+ },
+ "switch_login": {
+ "Nexus": {
+ "user": "admin",
+ "passwd": ["password"],
+ "enable": null
+ },
+ "Arista": {
+ "user": "admin",
+ "passwd": ["password", "123456"],
+ "enable": ['', null]
+ },
+ "Force10": {
+ "user": "admin",
+ "passwd": ["password"],
+ "enable": ["password"]
+ }
+ }
+}
diff --git a/ansible/group_vars/eos/eos.yml b/ansible/group_vars/eos/eos.yml
index c1220425c6f..220e0a77901 100644
--- a/ansible/group_vars/eos/eos.yml
+++ b/ansible/group_vars/eos/eos.yml
@@ -1,3 +1,4 @@
# snmp variables
-snmp_rocommunity: public
+snmp_rocommunity: strcommunity
+snmp_location: str
diff --git a/ansible/group_vars/lab/lab.yml b/ansible/group_vars/lab/lab.yml
new file mode 100644
index 00000000000..4b33f607cad
--- /dev/null
+++ b/ansible/group_vars/lab/lab.yml
@@ -0,0 +1,35 @@
+---
+#testlab (lab) group variables
+# file: group_vars/lab.yml
+
+# ntp variables
+ntp_servers: ['10.0.0.1', '10.0.0.2']
+
+# syslog variables
+syslog_servers: ['10.0.0.5', '10.0.0.6']
+
+# dns variables
+dns_servers: ['10.0.0.5', '10.0.0.6']
+
+# forced_mgmt_routes
+forced_mgmt_routes: ['10.0.0.100/31', '10.250.0.8', '10.255.0.0/28']
+
+# ErspanDestinationIpv4
+erspan_dest: ['10.0.0.7']
+
+radius_servers: []
+
+tacacs_servers: ['10.0.0.9', '10.0.0.8']
+
+# tacacs grous
+tacacs_group: 'testlab'
+
+# snmp servers
+snmp_servers: ['10.0.0.9']
+
+# dhcp replay servers
+dhcp_servers: ['10.0.0.1']
+#
+# snmp variables
+snmp_rocommunity: public
+snmp_location: testlab
diff --git a/ansible/group_vars/lab/secrets.yml b/ansible/group_vars/lab/secrets.yml
new file mode 100644
index 00000000000..c0d5afdb972
--- /dev/null
+++ b/ansible/group_vars/lab/secrets.yml
@@ -0,0 +1,5 @@
+ansible_ssh_pass: password
+ansible_become_pass: password
+sonicadmin_user: admin
+sonicadmin_password: password
+sonicadmin_initial_password: password
diff --git a/ansible/group_vars/leaf_topo_1/topo.yml b/ansible/group_vars/leaf_topo_1/topo.yml
deleted file mode 100644
index e99f950cc52..00000000000
--- a/ansible/group_vars/leaf_topo_1/topo.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-podset_number : 200
-tor_number : 16
-tor_subnet_number : 2
-leaf_asn_start : 62001
-tor_asn_start : 65501
-failure_rate : 0
-local_tor_subnet_number : 5
diff --git a/ansible/group_vars/sonic/sku-sensors-data.yml b/ansible/group_vars/sonic/sku-sensors-data.yml
new file mode 100644
index 00000000000..2b032660c00
--- /dev/null
+++ b/ansible/group_vars/sonic/sku-sensors-data.yml
@@ -0,0 +1,622 @@
+sensors_checks:
+ Force10-S6000:
+ alarms:
+ fan:
+ - dni_dps460-i2c-1-58/fan1/fan1_alarm
+ - dni_dps460-i2c-1-58/fan1/fan1_fault
+ - dni_dps460-i2c-1-59/fan1/fan1_alarm
+ - dni_dps460-i2c-1-59/fan1/fan1_fault
+ power:
+ - w83627dhg-isa-0a00/VCore 1/in0_alarm
+ - w83627dhg-isa-0a00/VCore 2/in1_alarm
+ - w83627dhg-isa-0a00/AVCC/in2_alarm
+ - w83627dhg-isa-0a00/+3.3V/in3_alarm
+ - w83627dhg-isa-0a00/3VSB/in7_alarm
+ - w83627dhg-isa-0a00/Vbat/in8_alarm
+ - ltc4215-i2c-11-40/in1/in1_min_alarm
+ - ltc4215-i2c-11-40/in1/in1_max_alarm
+ - ltc4215-i2c-11-40/in2/in2_min_alarm
+ - ltc4215-i2c-11-40/curr1/curr1_max_alarm
+ - ltc4215-i2c-11-42/in1/in1_min_alarm
+ - ltc4215-i2c-11-42/in1/in1_max_alarm
+ - ltc4215-i2c-11-42/in2/in2_min_alarm
+ - ltc4215-i2c-11-42/curr1/curr1_max_alarm
+ temp:
+ - coretemp-isa-0000/Core 0/temp2_crit_alarm
+ - coretemp-isa-0000/Core 1/temp3_crit_alarm
+ - jc42-i2c-10-18/temp1/temp1_max_alarm
+ - jc42-i2c-10-18/temp1/temp1_min_alarm
+ - jc42-i2c-10-18/temp1/temp1_crit_alarm
+ - emc1403-i2c-10-4d/temp1/temp1_max_alarm
+ - emc1403-i2c-10-4d/temp1/temp1_min_alarm
+ - emc1403-i2c-10-4d/temp1/temp1_crit_alarm
+ - emc1403-i2c-10-4d/temp2/temp2_max_alarm
+ - emc1403-i2c-10-4d/temp2/temp2_min_alarm
+ - emc1403-i2c-10-4d/temp2/temp2_crit_alarm
+ - emc1403-i2c-10-4d/temp2/temp2_fault
+ - emc1403-i2c-10-4d/temp3/temp3_max_alarm
+ - emc1403-i2c-10-4d/temp3/temp3_min_alarm
+ - emc1403-i2c-10-4d/temp3/temp3_crit_alarm
+ - emc1403-i2c-10-4d/temp3/temp3_fault
+ - dni_dps460-i2c-1-58/temp1/temp1_max_alarm
+ - dni_dps460-i2c-1-58/temp2/temp2_max_alarm
+ - dni_dps460-i2c-1-59/temp1/temp1_max_alarm
+ - dni_dps460-i2c-1-59/temp2/temp2_max_alarm
+ compares:
+ fan: []
+ power: []
+ temp:
+ - - acpitz-virtual-0/temp1/temp1_input
+ - acpitz-virtual-0/temp1/temp1_crit
+ - - acpitz-virtual-0/temp2/temp2_input
+ - acpitz-virtual-0/temp2/temp2_crit
+ - - tmp75-i2c-11-4c/temp1/temp1_input
+ - tmp75-i2c-11-4c/temp1/temp1_max
+ - - tmp75-i2c-11-4d/temp1/temp1_input
+ - tmp75-i2c-11-4d/temp1/temp1_max
+ - - tmp75-i2c-11-4e/temp1/temp1_input
+ - tmp75-i2c-11-4e/temp1/temp1_max
+ non_zero:
+ fan:
+ - max6620-i2c-11-29/fan1/fan1_input
+ - max6620-i2c-11-29/fan2/fan2_input
+ - max6620-i2c-11-29/fan3/fan3_input
+ - max6620-i2c-11-29/fan4/fan4_input
+ - max6620-i2c-11-2a/fan1/fan1_input
+ - max6620-i2c-11-2a/fan2/fan2_input
+ power: []
+ temp: []
+ psu_skips:
+ dni_dps460-i2c-1-58:
+ number: 2
+ side: right
+ skip_list:
+ - dni_dps460-i2c-1-58
+ - ltc4215-i2c-11-40
+ dni_dps460-i2c-1-59:
+ number: 1
+ side: left
+ skip_list:
+ - dni_dps460-i2c-1-59
+ - ltc4215-i2c-11-42
+
+ ACS-MSN2700:
+ alarms:
+ fan:
+ - dps460-i2c-10-59/fan1/fan1_alarm
+ - dps460-i2c-10-58/fan1/fan1_alarm
+ power:
+ - dps460-i2c-10-59/vin/in1_min_alarm
+ - dps460-i2c-10-59/vin/in1_max_alarm
+ - dps460-i2c-10-59/vin/in1_lcrit_alarm
+ - dps460-i2c-10-59/vin/in1_crit_alarm
+ - dps460-i2c-10-59/vout1/in3_min_alarm
+ - dps460-i2c-10-59/vout1/in3_max_alarm
+ - dps460-i2c-10-59/vout1/in3_lcrit_alarm
+ - dps460-i2c-10-59/vout1/in3_crit_alarm
+ - dps460-i2c-10-59/pin/power1_alarm
+ - dps460-i2c-10-59/pout1/power2_cap_alarm
+ - dps460-i2c-10-59/pout1/power2_max_alarm
+ - dps460-i2c-10-59/pout1/power2_crit_alarm
+ - dps460-i2c-10-59/iin/curr1_max_alarm
+ - dps460-i2c-10-59/iin/curr1_crit_alarm
+ - dps460-i2c-10-59/iout1/curr2_max_alarm
+ - dps460-i2c-10-59/iout1/curr2_lcrit_alarm
+ - dps460-i2c-10-59/iout1/curr2_crit_alarm
+ - dps460-i2c-10-58/vin/in1_min_alarm
+ - dps460-i2c-10-58/vin/in1_max_alarm
+ - dps460-i2c-10-58/vin/in1_lcrit_alarm
+ - dps460-i2c-10-58/vin/in1_crit_alarm
+ - dps460-i2c-10-58/vout1/in3_min_alarm
+ - dps460-i2c-10-58/vout1/in3_max_alarm
+ - dps460-i2c-10-58/vout1/in3_lcrit_alarm
+ - dps460-i2c-10-58/vout1/in3_crit_alarm
+ - dps460-i2c-10-58/pin/power1_alarm
+ - dps460-i2c-10-58/pout1/power2_cap_alarm
+ - dps460-i2c-10-58/pout1/power2_max_alarm
+ - dps460-i2c-10-58/pout1/power2_crit_alarm
+ - dps460-i2c-10-58/iin/curr1_max_alarm
+ - dps460-i2c-10-58/iin/curr1_crit_alarm
+ - dps460-i2c-10-58/iout1/curr2_max_alarm
+ - dps460-i2c-10-58/iout1/curr2_lcrit_alarm
+ - dps460-i2c-10-58/iout1/curr2_crit_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_min_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_max_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_lcrit_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_crit_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_min_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_max_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_lcrit_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_crit_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_min_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_max_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_lcrit_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_crit_alarm
+ - ucd9200-i2c-5-27/iout1/curr2_max_alarm
+ - ucd9200-i2c-5-27/iout1/curr2_lcrit_alarm
+ - ucd9200-i2c-5-27/iout1/curr2_crit_alarm
+ - ucd9200-i2c-5-27/iout2/curr3_max_alarm
+ - ucd9200-i2c-5-27/iout2/curr3_lcrit_alarm
+ - ucd9200-i2c-5-27/iout2/curr3_crit_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_min_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_max_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_lcrit_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_crit_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_min_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_max_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_lcrit_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_crit_alarm
+ - ucd9200-i2c-5-41/iout1/curr2_max_alarm
+ - ucd9200-i2c-5-41/iout1/curr2_lcrit_alarm
+ - ucd9200-i2c-5-41/iout1/curr2_crit_alarm
+ temp:
+ - coretemp-isa-0000/Physical id 0/temp1_crit_alarm
+ - coretemp-isa-0000/Core 0/temp2_crit_alarm
+ - coretemp-isa-0000/Core 1/temp3_crit_alarm
+ - dps460-i2c-10-59/temp1/temp1_max_alarm
+ - dps460-i2c-10-59/temp1/temp1_min_alarm
+ - dps460-i2c-10-59/temp1/temp1_crit_alarm
+ - dps460-i2c-10-59/temp1/temp1_lcrit_alarm
+ - dps460-i2c-10-59/temp2/temp2_max_alarm
+ - dps460-i2c-10-59/temp2/temp2_min_alarm
+ - dps460-i2c-10-59/temp2/temp2_crit_alarm
+ - dps460-i2c-10-59/temp2/temp2_lcrit_alarm
+ - dps460-i2c-10-59/temp3/temp3_max_alarm
+ - dps460-i2c-10-59/temp3/temp3_min_alarm
+ - dps460-i2c-10-59/temp3/temp3_crit_alarm
+ - dps460-i2c-10-59/temp3/temp3_lcrit_alarm
+ - dps460-i2c-10-58/temp1/temp1_max_alarm
+ - dps460-i2c-10-58/temp1/temp1_min_alarm
+ - dps460-i2c-10-58/temp1/temp1_crit_alarm
+ - dps460-i2c-10-58/temp1/temp1_lcrit_alarm
+ - dps460-i2c-10-58/temp2/temp2_max_alarm
+ - dps460-i2c-10-58/temp2/temp2_min_alarm
+ - dps460-i2c-10-58/temp2/temp2_crit_alarm
+ - dps460-i2c-10-58/temp2/temp2_lcrit_alarm
+ - dps460-i2c-10-58/temp3/temp3_max_alarm
+ - dps460-i2c-10-58/temp3/temp3_min_alarm
+ - dps460-i2c-10-58/temp3/temp3_crit_alarm
+ - dps460-i2c-10-58/temp3/temp3_lcrit_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp/temp1_max_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp/temp1_crit_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp2/temp2_max_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp2/temp2_crit_alarm
+ - ucd9200-i2c-5-27/temp3/temp3_max_alarm
+ - ucd9200-i2c-5-27/temp3/temp3_crit_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp1/temp1_max_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp1/temp1_crit_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp2/temp2_max_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp2/temp2_crit_alarm
+ compares:
+ fan:
+ - - spectrum-i2c-2-48/fan1/fan1_input
+ - spectrum-i2c-2-48/fan1/fan1_max
+ - - spectrum-i2c-2-48/fan1/fan1_min
+ - spectrum-i2c-2-48/fan1/fan1_input
+ - - spectrum-i2c-2-48/fan2/fan2_input
+ - spectrum-i2c-2-48/fan2/fan2_max
+ - - spectrum-i2c-2-48/fan2/fan2_min
+ - spectrum-i2c-2-48/fan2/fan2_input
+ - - spectrum-i2c-2-48/fan3/fan3_input
+ - spectrum-i2c-2-48/fan3/fan3_max
+ - - spectrum-i2c-2-48/fan3/fan3_min
+ - spectrum-i2c-2-48/fan3/fan3_input
+ - - spectrum-i2c-2-48/fan4/fan4_input
+ - spectrum-i2c-2-48/fan4/fan4_max
+ - - spectrum-i2c-2-48/fan4/fan4_min
+ - spectrum-i2c-2-48/fan4/fan4_input
+ - - spectrum-i2c-2-48/fan5/fan5_input
+ - spectrum-i2c-2-48/fan5/fan5_max
+ - - spectrum-i2c-2-48/fan5/fan5_min
+ - spectrum-i2c-2-48/fan5/fan5_input
+ - - spectrum-i2c-2-48/fan6/fan6_input
+ - spectrum-i2c-2-48/fan6/fan6_max
+ - - spectrum-i2c-2-48/fan6/fan6_min
+ - spectrum-i2c-2-48/fan6/fan6_input
+ - - spectrum-i2c-2-48/fan7/fan7_input
+ - spectrum-i2c-2-48/fan7/fan7_max
+ - - spectrum-i2c-2-48/fan7/fan7_min
+ - spectrum-i2c-2-48/fan7/fan7_input
+ - - spectrum-i2c-2-48/fan8/fan8_input
+ - spectrum-i2c-2-48/fan8/fan8_max
+ - - spectrum-i2c-2-48/fan8/fan8_min
+ - spectrum-i2c-2-48/fan8/fan8_input
+ power:
+ - - mlnxa2dswb-i2c-5-6d/1.8V_sw_spc/in1_input
+ - mlnxa2dswb-i2c-5-6d/1.8V_sw_spc/in1_max
+ - - mlnxa2dswb-i2c-5-6d/1.8V_sw_spc/in1_min
+ - mlnxa2dswb-i2c-5-6d/1.8V_sw_spc/in1_input
+ - - mlnxa2dmnb-i2c-15-6d/ddr3_0.675/in1_input
+ - mlnxa2dmnb-i2c-15-6d/ddr3_0.675/in1_max
+ - - mlnxa2dmnb-i2c-15-6d/ddr3_0.675/in1_min
+ - mlnxa2dmnb-i2c-15-6d/ddr3_0.675/in1_input
+ - - mlnxa2dmnb-i2c-15-6d/cpu_0.9/in2_input
+ - mlnxa2dmnb-i2c-15-6d/cpu_0.9/in2_max
+ - - mlnxa2dmnb-i2c-15-6d/sys/in3_input
+ - mlnxa2dmnb-i2c-15-6d/sys/in3_max
+ - - mlnxa2dmnb-i2c-15-6d/sys/in3_min
+ - mlnxa2dmnb-i2c-15-6d/sys/in3_input
+ - - mlnxa2dmnb-i2c-15-6d/cpu_1.8/in4_input
+ - mlnxa2dmnb-i2c-15-6d/cpu_1.8/in4_max
+ - - mlnxa2dmnb-i2c-15-6d/cpu_1.8/in4_min
+ - mlnxa2dmnb-i2c-15-6d/cpu_1.8/in4_input
+ - - mlnxa2dmnb-i2c-15-6d/cpu_pch_1.05/in5_input
+ - mlnxa2dmnb-i2c-15-6d/cpu_pch_1.05/in5_max
+ - - mlnxa2dmnb-i2c-15-6d/cpu_pch_1.05/in5_min
+ - mlnxa2dmnb-i2c-15-6d/cpu_pch_1.05/in5_input
+ - - mlnxa2dmnb-i2c-15-6d/cpu_1.05/in6_input
+ - mlnxa2dmnb-i2c-15-6d/cpu_1.05/in6_max
+ - - mlnxa2dmnb-i2c-15-6d/cpu_1.05/in6_min
+ - mlnxa2dmnb-i2c-15-6d/cpu_1.05/in6_input
+ - - mlnxa2dmnb-i2c-15-6d/ddr3_1.35/in7_input
+ - mlnxa2dmnb-i2c-15-6d/ddr3_1.35/in7_max
+ - - mlnxa2dmnb-i2c-15-6d/ddr3_1.35/in7_min
+ - mlnxa2dmnb-i2c-15-6d/ddr3_1.35/in7_input
+ - - mlnxa2dmnb-i2c-15-6d/usb_5/in8_input
+ - mlnxa2dmnb-i2c-15-6d/usb_5/in8_max
+ - - mlnxa2dmnb-i2c-15-6d/usb_5/in8_min
+ - mlnxa2dmnb-i2c-15-6d/usb_5/in8_input
+ - - mlnxa2dmnb-i2c-15-6d/lan_1.05/in9_input
+ - mlnxa2dmnb-i2c-15-6d/lan_1.05/in9_max
+ - - mlnxa2dmnb-i2c-15-6d/lan_1.05/in9_min
+ - mlnxa2dmnb-i2c-15-6d/lan_1.05/in9_input
+ temp:
+ - - acpitz-virtual-0/temp1/temp1_input
+ - acpitz-virtual-0/temp1/temp1_crit
+ - - acpitz-virtual-0/temp2/temp2_input
+ - acpitz-virtual-0/temp2/temp2_crit
+ - - spectrum-i2c-2-48/temp1/temp1_input
+ - spectrum-i2c-2-48/temp1/temp1_max
+ - - spectrum-i2c-2-48/temp1/temp1_min
+ - spectrum-i2c-2-48/temp1/temp1_input
+ - - lm75-i2c-7-4a/Ambient Port Temp/temp1_input
+ - lm75-i2c-7-4a/Ambient Port Temp/temp1_max_hyst
+ - - lm75-i2c-17-49/temp1/temp1_input
+ - lm75-i2c-17-49/temp1/temp1_max_hyst
+ non_zero:
+ fan: []
+ power:
+ - ucd9200-i2c-5-27/pout1/power2_input
+ - ucd9200-i2c-5-27/pout2/power3_input
+ - ucd9200-i2c-5-41/pout1/power2_input
+ temp: []
+ psu_skips:
+ dps460-i2c-10-58:
+ number: 2
+ side: right
+ skip_list:
+ - dps460-i2c-10-58
+ dps460-i2c-10-59:
+ number: 1
+ side: left
+ skip_list:
+ - dps460-i2c-10-59
+
+ ACS-MSN2740:
+ alarms:
+ fan:
+ - dps460-i2c-4-59/fan1/fan1_alarm
+ - dps460-i2c-4-58/fan1/fan1_alarm
+ power:
+ - dps460-i2c-4-59/vin/in1_min_alarm
+ - dps460-i2c-4-59/vin/in1_max_alarm
+ - dps460-i2c-4-59/vin/in1_lcrit_alarm
+ - dps460-i2c-4-59/vin/in1_crit_alarm
+ - dps460-i2c-4-59/vout1/in3_min_alarm
+ - dps460-i2c-4-59/vout1/in3_max_alarm
+ - dps460-i2c-4-59/vout1/in3_lcrit_alarm
+ - dps460-i2c-4-59/vout1/in3_crit_alarm
+ - dps460-i2c-4-59/pin/power1_alarm
+ - dps460-i2c-4-59/pout1/power2_cap_alarm
+ - dps460-i2c-4-59/pout1/power2_max_alarm
+ - dps460-i2c-4-59/pout1/power2_crit_alarm
+ - dps460-i2c-4-59/iin/curr1_max_alarm
+ - dps460-i2c-4-59/iin/curr1_crit_alarm
+ - dps460-i2c-4-59/iout1/curr2_max_alarm
+ - dps460-i2c-4-59/iout1/curr2_lcrit_alarm
+ - dps460-i2c-4-59/iout1/curr2_crit_alarm
+ - dps460-i2c-4-58/vin/in1_min_alarm
+ - dps460-i2c-4-58/vin/in1_max_alarm
+ - dps460-i2c-4-58/vin/in1_lcrit_alarm
+ - dps460-i2c-4-58/vin/in1_crit_alarm
+ - dps460-i2c-4-58/vout1/in3_min_alarm
+ - dps460-i2c-4-58/vout1/in3_max_alarm
+ - dps460-i2c-4-58/vout1/in3_lcrit_alarm
+ - dps460-i2c-4-58/vout1/in3_crit_alarm
+ - dps460-i2c-4-58/pin/power1_alarm
+ - dps460-i2c-4-58/pout1/power2_cap_alarm
+ - dps460-i2c-4-58/pout1/power2_max_alarm
+ - dps460-i2c-4-58/pout1/power2_crit_alarm
+ - dps460-i2c-4-58/iin/curr1_max_alarm
+ - dps460-i2c-4-58/iin/curr1_crit_alarm
+ - dps460-i2c-4-58/iout1/curr2_max_alarm
+ - dps460-i2c-4-58/iout1/curr2_lcrit_alarm
+ - dps460-i2c-4-58/iout1/curr2_crit_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_min_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_max_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_lcrit_alarm
+ - ucd9200-i2c-5-27/UCD1 vin/in1_crit_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_min_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_max_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_lcrit_alarm
+ - ucd9200-i2c-5-27/ASIC 3.3 vout/in2_crit_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_min_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_max_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_lcrit_alarm
+ - ucd9200-i2c-5-27/ASIC 1.2 vout/in3_crit_alarm
+ - ucd9200-i2c-5-27/iout1/curr2_max_alarm
+ - ucd9200-i2c-5-27/iout1/curr2_lcrit_alarm
+ - ucd9200-i2c-5-27/iout1/curr2_crit_alarm
+ - ucd9200-i2c-5-27/iout2/curr3_max_alarm
+ - ucd9200-i2c-5-27/iout2/curr3_lcrit_alarm
+ - ucd9200-i2c-5-27/iout2/curr3_crit_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_min_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_max_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_lcrit_alarm
+ - ucd9200-i2c-5-41/UCD2 vin/in1_crit_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_min_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_max_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_lcrit_alarm
+ - ucd9200-i2c-5-41/ASIC Vcore vout/in2_crit_alarm
+ - ucd9200-i2c-5-41/iout1/curr2_max_alarm
+ - ucd9200-i2c-5-41/iout1/curr2_lcrit_alarm
+ - ucd9200-i2c-5-41/iout1/curr2_crit_alarm
+ temp:
+ - coretemp-isa-0000/Core 0/temp2_crit_alarm
+ - coretemp-isa-0000/Core 1/temp3_crit_alarm
+ - coretemp-isa-0000/Core 2/temp4_crit_alarm
+ - coretemp-isa-0000/Core 3/temp5_crit_alarm
+ - dps460-i2c-4-59/temp1/temp1_max_alarm
+ - dps460-i2c-4-59/temp1/temp1_min_alarm
+ - dps460-i2c-4-59/temp1/temp1_crit_alarm
+ - dps460-i2c-4-59/temp1/temp1_lcrit_alarm
+ - dps460-i2c-4-59/temp2/temp2_max_alarm
+ - dps460-i2c-4-59/temp2/temp2_min_alarm
+ - dps460-i2c-4-59/temp2/temp2_crit_alarm
+ - dps460-i2c-4-59/temp2/temp2_lcrit_alarm
+ - dps460-i2c-4-59/temp3/temp3_max_alarm
+ - dps460-i2c-4-59/temp3/temp3_min_alarm
+ - dps460-i2c-4-59/temp3/temp3_crit_alarm
+ - dps460-i2c-4-59/temp3/temp3_lcrit_alarm
+ - dps460-i2c-4-58/temp1/temp1_max_alarm
+ - dps460-i2c-4-58/temp1/temp1_min_alarm
+ - dps460-i2c-4-58/temp1/temp1_crit_alarm
+ - dps460-i2c-4-58/temp1/temp1_lcrit_alarm
+ - dps460-i2c-4-58/temp2/temp2_max_alarm
+ - dps460-i2c-4-58/temp2/temp2_min_alarm
+ - dps460-i2c-4-58/temp2/temp2_crit_alarm
+ - dps460-i2c-4-58/temp2/temp2_lcrit_alarm
+ - dps460-i2c-4-58/temp3/temp3_max_alarm
+ - dps460-i2c-4-58/temp3/temp3_min_alarm
+ - dps460-i2c-4-58/temp3/temp3_crit_alarm
+ - dps460-i2c-4-58/temp3/temp3_lcrit_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp/temp1_max_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp/temp1_crit_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp2/temp2_max_alarm
+ - ucd9200-i2c-5-27/UCD1 Temp2/temp2_crit_alarm
+ - ucd9200-i2c-5-27/temp3/temp3_max_alarm
+ - ucd9200-i2c-5-27/temp3/temp3_crit_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp1/temp1_max_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp1/temp1_crit_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp2/temp2_max_alarm
+ - ucd9200-i2c-5-41/UCD2 Temp2/temp2_crit_alarm
+ compares:
+ fan:
+ - - spectrum-i2c-2-48/fan1/fan1_input
+ - spectrum-i2c-2-48/fan1/fan1_max
+ - - spectrum-i2c-2-48/fan1/fan1_min
+ - spectrum-i2c-2-48/fan1/fan1_input
+ - - spectrum-i2c-2-48/fan2/fan2_input
+ - spectrum-i2c-2-48/fan2/fan2_max
+ - - spectrum-i2c-2-48/fan2/fan2_min
+ - spectrum-i2c-2-48/fan2/fan2_input
+ - - spectrum-i2c-2-48/fan3/fan3_input
+ - spectrum-i2c-2-48/fan3/fan3_max
+ - - spectrum-i2c-2-48/fan3/fan3_min
+ - spectrum-i2c-2-48/fan3/fan3_input
+ - - spectrum-i2c-2-48/fan4/fan4_input
+ - spectrum-i2c-2-48/fan4/fan4_max
+ - - spectrum-i2c-2-48/fan4/fan4_min
+ - spectrum-i2c-2-48/fan4/fan4_input
+ power:
+ - - mlnxa2dswb-i2c-5-64/12v/in1_input
+ - mlnxa2dswb-i2c-5-64/12v/in1_max
+ - - mlnxa2dswb-i2c-5-64/12v/in1_min
+ - mlnxa2dswb-i2c-5-64/12v/in1_input
+ - - mlnxa2dswb-i2c-5-64/12v_aux/in2_input
+ - mlnxa2dswb-i2c-5-64/12v_aux/in2_max
+ - - mlnxa2dswb-i2c-5-64/12v_aux/in2_min
+ - mlnxa2dswb-i2c-5-64/12v_aux/in2_input
+ - - mlnxa2dswb-i2c-5-64/3.3v_aux/in3_input
+ - mlnxa2dswb-i2c-5-64/3.3v_aux/in3_max
+ - - mlnxa2dswb-i2c-5-64/3.3v_aux/in3_min
+ - mlnxa2dswb-i2c-5-64/3.3v_aux/in3_input
+ - - mlnxa2dmnb-i2c-15-6d/soc_core/in1_input
+ - mlnxa2dmnb-i2c-15-6d/soc_core/in1_max
+ - - mlnxa2dmnb-i2c-15-6d/soc_core/in1_min
+ - mlnxa2dmnb-i2c-15-6d/soc_core/in1_input
+ - - mlnxa2dmnb-i2c-15-6d/soc_vnn/in2_input
+ - mlnxa2dmnb-i2c-15-6d/soc_vnn/in2_max
+ - - mlnxa2dmnb-i2c-15-6d/soc_vnn/in2_min
+ - mlnxa2dmnb-i2c-15-6d/soc_vnn/in2_input
+ - - mlnxa2dmnb-i2c-15-6d/cpu_0.675v/in3_input
+ - mlnxa2dmnb-i2c-15-6d/cpu_0.675v/in3_max
+ - - mlnxa2dmnb-i2c-15-6d/cpu_0.675v/in3_min
+ - mlnxa2dmnb-i2c-15-6d/cpu_0.675v/in3_input
+ - - mlnxa2dmnb-i2c-15-6d/1v/in4_input
+ - mlnxa2dmnb-i2c-15-6d/1v/in4_max
+ - - mlnxa2dmnb-i2c-15-6d/1v/in4_min
+ - mlnxa2dmnb-i2c-15-6d/1v/in4_input
+ - - mlnxa2dmnb-i2c-15-6d/vddq/in5_input
+ - mlnxa2dmnb-i2c-15-6d/vddq/in5_max
+ - - mlnxa2dmnb-i2c-15-6d/vddq/in5_min
+ - mlnxa2dmnb-i2c-15-6d/vddq/in5_input
+ - - mlnxa2dmnb-i2c-15-6d/1.8v/in6_input
+ - mlnxa2dmnb-i2c-15-6d/1.8v/in6_max
+ - - mlnxa2dmnb-i2c-15-6d/1.8v/in6_min
+ - mlnxa2dmnb-i2c-15-6d/1.8v/in6_input
+ - - mlnxa2dmnb-i2c-15-6d/sys_3.3v/in7_input
+ - mlnxa2dmnb-i2c-15-6d/sys_3.3v/in7_max
+ - - mlnxa2dmnb-i2c-15-6d/sys_3.3v/in7_min
+ - mlnxa2dmnb-i2c-15-6d/sys_3.3v/in7_input
+ - - mlnxa2dmnb-i2c-15-6d/12v/in8_input
+ - mlnxa2dmnb-i2c-15-6d/12v/in8_max
+ - - mlnxa2dmnb-i2c-15-6d/12v/in8_min
+ - mlnxa2dmnb-i2c-15-6d/12v/in8_input
+ - - mlnxa2dmnb-i2c-15-6d/1.35v/in9_input
+ - mlnxa2dmnb-i2c-15-6d/1.35v/in9_max
+ - - mlnxa2dmnb-i2c-15-6d/1.35v/in9_min
+ - mlnxa2dmnb-i2c-15-6d/1.35v/in9_input
+ - - mlnxa2dmnb-i2c-15-6d/vccsram/in10_input
+ - mlnxa2dmnb-i2c-15-6d/vccsram/in10_max
+ - - mlnxa2dmnb-i2c-15-6d/vccsram/in10_min
+ - mlnxa2dmnb-i2c-15-6d/vccsram/in10_input
+ - - mlnxa2dmnb-i2c-15-6d/1.5v/in11_input
+ - mlnxa2dmnb-i2c-15-6d/1.5v/in11_max
+ - - mlnxa2dmnb-i2c-15-6d/1.5v/in11_min
+ - mlnxa2dmnb-i2c-15-6d/1.5v/in11_input
+ - - mlnxa2dmnb-i2c-15-6d/5v/in12_input
+ - mlnxa2dmnb-i2c-15-6d/5v/in12_max
+ - - mlnxa2dmnb-i2c-15-6d/5v/in12_min
+ - mlnxa2dmnb-i2c-15-6d/5v/in12_input
+ - - mlnxa2dmnb-i2c-15-6d/3.3v_aux/in13_input
+ - mlnxa2dmnb-i2c-15-6d/3.3v_aux/in13_max
+ - - mlnxa2dmnb-i2c-15-6d/3.3v_aux/in13_min
+ - mlnxa2dmnb-i2c-15-6d/3.3v_aux/in13_input
+ temp:
+ - - spectrum-i2c-2-48/temp1/temp1_input
+ - spectrum-i2c-2-48/temp1/temp1_max
+ - - spectrum-i2c-2-48/temp1/temp1_min
+ - spectrum-i2c-2-48/temp1/temp1_input
+ - - tmp102-i2c-7-48/temp1/temp1_input
+ - tmp102-i2c-7-48/temp1/temp1_max_hyst
+ non_zero:
+ fan: []
+ power:
+ - ucd9200-i2c-5-27/pout1/power2_input
+ - ucd9200-i2c-5-27/pout2/power3_input
+ - ucd9200-i2c-5-41/pout1/power2_input
+ temp: []
+ psu_skips:
+ dps460-i2c-4-58:
+ number: 2
+ side: right
+ skip_list:
+ - dps460-i2c-4-58
+ dps460-i2c-4-59:
+ number: 1
+ side: left
+ skip_list:
+ - dps460-i2c-4-59
+
+ Arista-7050-QX32:
+ alarms:
+ fan: []
+ power:
+ - pmbus-i2c-3-4e/vout1/in1_min_alarm
+ - pmbus-i2c-3-4e/vout1/in1_max_alarm
+ - pmbus-i2c-3-4e/vout1/in1_lcrit_alarm
+ - pmbus-i2c-3-4e/vout1/in1_crit_alarm
+ - pmbus-i2c-5-58/vin/in1_min_alarm
+ - pmbus-i2c-5-58/vin/in1_max_alarm
+ - pmbus-i2c-5-58/vin/in1_crit_alarm
+ - pmbus-i2c-5-58/vout1/in3_min_alarm
+ - pmbus-i2c-5-58/vout1/in3_max_alarm
+ - pmbus-i2c-5-58/vout1/in3_lcrit_alarm
+ - pmbus-i2c-5-58/vout1/in3_crit_alarm
+ - pmbus-i2c-5-58/pin/power1_alarm
+ - pmbus-i2c-5-58/pout1/power2_cap_alarm
+ - pmbus-i2c-5-58/pout1/power2_max_alarm
+ - pmbus-i2c-5-58/pout1/power2_crit_alarm
+ - pmbus-i2c-5-58/iin/curr1_max_alarm
+ - pmbus-i2c-5-58/iin/curr1_crit_alarm
+ - pmbus-i2c-5-58/iout1/curr2_max_alarm
+ - pmbus-i2c-5-58/iout1/curr2_lcrit_alarm
+ - pmbus-i2c-5-58/iout1/curr2_crit_alarm
+ - pmbus-i2c-6-58/vin/in1_min_alarm
+ - pmbus-i2c-6-58/vin/in1_max_alarm
+ - pmbus-i2c-6-58/vin/in1_lcrit_alarm
+ - pmbus-i2c-6-58/vin/in1_crit_alarm
+ - pmbus-i2c-6-58/vout1/in3_min_alarm
+ - pmbus-i2c-6-58/vout1/in3_max_alarm
+ - pmbus-i2c-6-58/vout1/in3_lcrit_alarm
+ - pmbus-i2c-6-58/vout1/in3_crit_alarm
+ - pmbus-i2c-6-58/iin/curr1_max_alarm
+ - pmbus-i2c-6-58/iin/curr1_crit_alarm
+ - pmbus-i2c-6-58/iout1/curr2_max_alarm
+ - pmbus-i2c-6-58/iout1/curr2_lcrit_alarm
+ - pmbus-i2c-6-58/iout1/curr2_crit_alarm
+ - pmbus-i2c-7-4e/vout1/in1_min_alarm
+ - pmbus-i2c-7-4e/vout1/in1_max_alarm
+ - pmbus-i2c-7-4e/vout1/in1_lcrit_alarm
+ - pmbus-i2c-7-4e/vout1/in1_crit_alarm
+
+ temp:
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 1/temp1_max_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 1/temp1_min_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 1/temp1_crit_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 1/temp1_lcrit_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 2/temp2_max_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 2/temp2_min_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 2/temp2_crit_alarm
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 2/temp2_lcrit_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 1/temp1_max_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 1/temp1_min_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 1/temp1_crit_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 1/temp1_lcrit_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 2/temp2_max_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 2/temp2_min_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 2/temp2_crit_alarm
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 2/temp2_lcrit_alarm
+
+ compares:
+ fan: []
+ power:
+ - - pmbus-i2c-3-4e/vout1/in1_input
+ - pmbus-i2c-3-4e/vout1/in1_max
+ - - pmbus-i2c-5-58/vin/in1_input
+ - pmbus-i2c-5-58/vin/in1_max
+ - - pmbus-i2c-5-58/vout1/in3_input
+ - pmbus-i2c-5-58/vout1/in3_max
+ - - pmbus-i2c-5-58/pin/power1_input
+ - pmbus-i2c-5-58/pin/power1_max
+ - - pmbus-i2c-5-58/pout1/power2_input
+ - pmbus-i2c-5-58/pout1/power2_max
+ - - pmbus-i2c-5-58/iin/curr1_input
+ - pmbus-i2c-5-58/iin/curr1_max
+ - - pmbus-i2c-5-58/iout1/curr2_input
+ - pmbus-i2c-5-58/iout1/curr2_max
+ - - pmbus-i2c-7-4e/vout1/in1_input
+ - pmbus-i2c-7-4e/vout1/in1_max
+ temp:
+ - - k10temp-pci-00c3/Cpu temp sensor/temp1_input
+ - k10temp-pci-00c3/Cpu temp sensor/temp1_max
+ - - lm73-i2c-3-48/Rear Temp Sensor/temp1_input
+ - lm73-i2c-3-48/Rear Temp Sensor/temp1_max
+ - - lm86-i2c-2-4c/Board Temp Sensor/temp1_input
+ - lm86-i2c-2-4c/Board Temp Sensor/temp1_max
+ - - lm86-i2c-2-4c/Front-panel Temp Sensor/temp2_input
+ - lm86-i2c-2-4c/Front-panel Temp Sensor/temp2_max
+ - - pmbus-i2c-3-4e/Power Controller Sensor 1/temp1_input
+ - pmbus-i2c-3-4e/Power Controller Sensor 1/temp1_max
+ - - pmbus-i2c-3-4e/Power Controller Sensor 2/temp2_input
+ - pmbus-i2c-3-4e/Power Controller Sensor 2/temp2_max
+ - - pmbus-i2c-5-58/Power Supply 1 Sensor 1/temp1_input
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 1/temp1_max
+ - - pmbus-i2c-5-58/Power Supply 1 Sensor 2/temp2_input
+ - pmbus-i2c-5-58/Power Supply 1 Sensor 2/temp2_max
+ - - pmbus-i2c-6-58/Power Supply 2 Sensor 1/temp1_input
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 1/temp1_max
+ - - pmbus-i2c-6-58/Power Supply 2 Sensor 2/temp2_input
+ - pmbus-i2c-6-58/Power Supply 2 Sensor 2/temp2_max
+
+ non_zero:
+ fan:
+ - pmbus-i2c-5-58/fan1/fan1_input
+ - pmbus-i2c-6-58/fan1/fan1_input
+ power:
+ - pmbus-i2c-6-58/vcap/in2_input
+ - pmbus-i2c-5-58/vcap/in2_input
+ temp: []
+
+ psu_skips: {}
diff --git a/ansible/group_vars/sonic/vars b/ansible/group_vars/sonic/vars
index e7282eed497..8154122deb3 100644
--- a/ansible/group_vars/sonic/vars
+++ b/ansible/group_vars/sonic/vars
@@ -1,9 +1,4 @@
ansible_ssh_user: admin
-ansible_ssh_pass: password
-ansible_become_pass: password
-sonicadmin_user: admin
-sonicadmin_password: password
-sonicadmin_initial_password: 123456
sonic_version: "v2"
@@ -22,8 +17,18 @@ sensor_hwskus: [ "ACS-MSN2700", "Force10-S6000" ]
## 1. http://stackoverflow.com/questions/9254178/is-there-yaml-syntax-for-sharing-part-of-a-list-or-map
## 2. https://groups.google.com/forum/#!msg/ansible-project/M-FNUK9Wz98/gH63Ka4hDAAJ
+sswsyncd_docker_volumes_dict:
+ "/etc/ssw/:/etc/ssw/:ro":
+ "/etc/sonic/:/etc/sonic/:ro":
+ "/etc/network/interfaces:/etc/network/interfaces:ro":
+ "/var/run/docker-syncd:/var/run/sswsyncd":
+
+sswsyncd_docker_volumes: "{{ sswsyncd_docker_volumes_dict.keys() }}"
+
syncd_docker_volumes_dict:
"/host/machine.conf:/etc/machine.conf":
+ "/var/run/docker-syncd:/var/run/sswsyncd":
+ "/etc/sonic/:/etc/sonic/:ro":
syncd_docker_volumes: "{{ syncd_docker_volumes_dict.keys() }}"
@@ -35,20 +40,3 @@ orchagent_docker_volumes_dict:
"/host/machine.conf:/host/machine.conf":
orchagent_docker_volumes: "{{ orchagent_docker_volumes_dict.keys() }}"
-
-sonic_apt_repo: "http://packages.microsoft.com/repos/sonic-dev/"
-apt_repo: "http://debian-archive.trafficmanager.net/debian/"
-apt_default_release: "*"
-
-# ntp variables
-ntp_servers: ['10.0.0.1', '10.0.0.2']
-
-# syslog variables
-syslog_servers: ['10.0.0.5', '10.0.0.6']
-
-# dns variables
-dns_servers: ['10.0.0.5', '10.0.0.6']
-
-# snmp variables
-snmp_rocommunity: public
-snmp_location: testlab
diff --git a/ansible/group_vars/sonic_latest/package_versions.yml b/ansible/group_vars/sonic_latest/package_versions.yml
index 89e66e7562e..138a31a1d4d 100644
--- a/ansible/group_vars/sonic_latest/package_versions.yml
+++ b/ansible/group_vars/sonic_latest/package_versions.yml
@@ -1,5 +1,5 @@
platform_modules_s6000: { name: platform-modules-s6000 , version: "*" }
-opennslv2: { name: opennsl-modules-3.16.0-4-amd64 , version: "3.2.1.5-3*" }
+opennslv2: { name: opennsl-modules-3.16.0-4-amd64 , version: "3.2.2.2*" }
version_sx_kernel: "*"
version_mlnxsdk: "*"
version_iproute2_mlnx: "1.mlnx*"
@@ -24,3 +24,4 @@ image_id_fpm: docker-fpm:{{ dockers_tag }}
image_id_snmp_sv2: docker-snmp-sv2:{{ dockers_tag }}
image_id_lldp_sv2: docker-lldp-sv2:{{ dockers_tag }}
image_id_teamd: docker-teamd:{{ dockers_tag }}
+image_id_dhcp_relay: docker-dhcp-relay:{{ dockers_tag }}
diff --git a/ansible/group_vars/vm_host/main.yml b/ansible/group_vars/vm_host/main.yml
index 0776901916d..d9b041c9f6b 100644
--- a/ansible/group_vars/vm_host/main.yml
+++ b/ansible/group_vars/vm_host/main.yml
@@ -1,7 +1,11 @@
root_path: /home/azure/veos-vm
vm_images_url: https://acsbe.blob.core.windows.net/vmimages
-cd_image_filename: Aboot-veos-serial-2.1.0.iso
-hdd_image_filename: vEOS-lab-4.15.2.1F.vmdk
+cd_image_filename: Aboot-veos-serial-8.0.0.iso
+hdd_image_filename: vEOS-lab-4.15.9M.vmdk
+skip_image_downloading: false
+
+vm_console_base: 7000
+memory: 2097152
# proxy
proxy_env:
diff --git a/ansible/host_vars/STR-ACS-SERV-01.yml b/ansible/host_vars/STR-ACS-SERV-01.yml
index 2ea0e284794..9c87d6ee0b6 100644
--- a/ansible/host_vars/STR-ACS-SERV-01.yml
+++ b/ansible/host_vars/STR-ACS-SERV-01.yml
@@ -1,424 +1,5 @@
mgmt_bridge: br1
+mgmt_prefixlen: 23
mgmt_gw: 10.255.0.1
external_iface: p4p1
-
-ptf_1_enabled: true
-ptf_1_mgmt_ip: 10.255.0.188/24
-ptf_1_vlan_base: 393
-
-ptf_2_enabled: false
-ptf_2_mgmt_ip: 10.255.0.50/24
-ptf_2_vlan_base: 101 # ???
-
-ptf_3_enabled: true
-ptf_3_mgmt_ip: 10.255.0.254/24
-ptf_3_vlan_base: 233
-
-ptf_4_enabled: true
-ptf_4_mgmt_ip: 10.255.0.185/24
-ptf_4_vlan_base: 265
-
-ptf_5_enabled: true
-ptf_5_mgmt_ip: 10.255.0.176/24
-ptf_5_vlan_base: 553
-
-ptf_6_enabled: true
-ptf_6_mgmt_ip: 10.255.0.177/24
-ptf_6_vlan_base: 425
-
-vm_1_enabled: true
-vm_1_vlan_base: 489
-vm_1_injected_ip: 10.255.0.178/24
-VMs_1:
- ARISTA01T0:
- num: 0
- filename: 01-ARISTA01T0.xml
- serial_port: 5000
- vlans: "16"
- memory: "{{ tor_memory }}"
- ARISTA01T2:
- num: 1
- filename: 01-ARISTA01T2.xml
- serial_port: 5016
- vlans: "0"
- memory: "{{ spine_memory }}"
- ARISTA02T0:
- num: 2
- filename: 01-ARISTA02T0.xml
- serial_port: 5001
- vlans: "17"
- memory: "{{ tor_memory }}"
- ARISTA02T2:
- num: 3
- filename: 01-ARISTA02T2.xml
- serial_port: 5017
- vlans: "1"
- memory: "{{ spine_memory }}"
- ARISTA03T0:
- num: 4
- filename: 01-ARISTA03T0.xml
- serial_port: 5002
- vlans: "18"
- memory: "{{ tor_memory }}"
- ARISTA03T2:
- num: 5
- filename: 01-ARISTA03T2.xml
- serial_port: 5018
- vlans: "2"
- memory: "{{ spine_memory }}"
- ARISTA04T0:
- num: 6
- filename: 01-ARISTA04T0.xml
- serial_port: 5003
- vlans: "19"
- memory: "{{ tor_memory }}"
- ARISTA04T2:
- num: 7
- filename: 01-ARISTA04T2.xml
- serial_port: 5019
- vlans: "3"
- memory: "{{ spine_memory }}"
- ARISTA05T0:
- num: 8
- filename: 01-ARISTA05T0.xml
- serial_port: 5004
- vlans: "20"
- memory: "{{ tor_memory }}"
- ARISTA05T2:
- num: 9
- filename: 01-ARISTA05T2.xml
- serial_port: 5020
- vlans: "4"
- memory: "{{ spine_memory }}"
- ARISTA06T0:
- num: 10
- filename: 01-ARISTA06T0.xml
- serial_port: 5005
- vlans: "21"
- memory: "{{ tor_memory }}"
- ARISTA06T2:
- num: 11
- filename: 01-ARISTA06T2.xml
- serial_port: 5021
- vlans: "5"
- memory: "{{ spine_memory }}"
- ARISTA07T0:
- num: 12
- filename: 01-ARISTA07T0.xml
- serial_port: 5006
- vlans: "22"
- memory: "{{ tor_memory }}"
- ARISTA07T2:
- num: 13
- filename: 01-ARISTA07T2.xml
- serial_port: 5022
- vlans: "6"
- memory: "{{ spine_memory }}"
- ARISTA08T0:
- num: 14
- filename: 01-ARISTA08T0.xml
- serial_port: 5007
- vlans: "23"
- memory: "{{ tor_memory }}"
- ARISTA08T2:
- num: 15
- filename: 01-ARISTA08T2.xml
- serial_port: 5023
- vlans: "7"
- memory: "{{ spine_memory }}"
- ARISTA09T0:
- num: 16
- filename: 01-ARISTA09T0.xml
- serial_port: 5008
- vlans: "24"
- memory: "{{ tor_memory }}"
- ARISTA09T2:
- num: 17
- filename: 01-ARISTA09T2.xml
- serial_port: 5024
- vlans: "8"
- memory: "{{ spine_memory }}"
- ARISTA10T0:
- num: 18
- filename: 01-ARISTA10T0.xml
- serial_port: 5009
- vlans: "25"
- memory: "{{ tor_memory }}"
- ARISTA10T2:
- num: 19
- filename: 01-ARISTA10T2.xml
- serial_port: 5025
- vlans: "9"
- memory: "{{ spine_memory }}"
- ARISTA11T0:
- num: 20
- filename: 01-ARISTA11T0.xml
- serial_port: 5010
- vlans: "26"
- memory: "{{ tor_memory }}"
- ARISTA11T2:
- num: 21
- filename: 01-ARISTA11T2.xml
- serial_port: 5026
- vlans: "10"
- memory: "{{ spine_memory }}"
- ARISTA12T0:
- num: 22
- filename: 01-ARISTA12T0.xml
- serial_port: 5011
- vlans: "27"
- memory: "{{ tor_memory }}"
- ARISTA12T2:
- num: 23
- filename: 01-ARISTA12T2.xml
- serial_port: 5027
- vlans: "11"
- memory: "{{ spine_memory }}"
- ARISTA13T0:
- num: 24
- filename: 01-ARISTA13T0.xml
- serial_port: 5012
- vlans: "28"
- memory: "{{ tor_memory }}"
- ARISTA13T2:
- num: 25
- filename: 01-ARISTA13T2.xml
- serial_port: 5028
- vlans: "12"
- memory: "{{ spine_memory }}"
- ARISTA14T0:
- num: 26
- filename: 01-ARISTA14T0.xml
- serial_port: 5013
- vlans: "29"
- memory: "{{ tor_memory }}"
- ARISTA14T2:
- num: 27
- filename: 01-ARISTA14T2.xml
- serial_port: 5029
- vlans: "13"
- memory: "{{ spine_memory }}"
- ARISTA15T0:
- num: 28
- filename: 01-ARISTA15T0.xml
- serial_port: 5014
- vlans: "30"
- memory: "{{ tor_memory }}"
- ARISTA15T2:
- num: 29
- filename: 01-ARISTA15T2.xml
- serial_port: 5030
- vlans: "14"
- memory: "{{ spine_memory }}"
- ARISTA16T0:
- num: 30
- filename: 01-ARISTA16T0.xml
- serial_port: 5015
- vlans: "31"
- memory: "{{ tor_memory }}"
- ARISTA16T2:
- num: 31
- filename: 01-ARISTA16T2.xml
- serial_port: 5031
- vlans: "15"
- memory: "{{ spine_memory }}"
-
-
-vm_2_enabled: true
-vm_2_vlan_base: 297
-vm_2_injected_ip: 10.255.0.179/24
-VMs_2:
- ARISTA01T0:
- num: 0
- filename: 03-ARISTA01T0.xml
- serial_port: 5032
- vlans: "16"
- memory: "{{ tor_memory }}"
- ARISTA01T2:
- num: 1
- filename: 03-ARISTA01T2.xml
- serial_port: 5048
- vlans: "0"
- memory: "{{ spine_memory }}"
- ARISTA02T0:
- num: 2
- filename: 03-ARISTA02T0.xml
- serial_port: 5033
- vlans: "17"
- memory: "{{ tor_memory }}"
- ARISTA02T2:
- num: 3
- filename: 03-ARISTA02T2.xml
- serial_port: 5049
- vlans: "1"
- memory: "{{ spine_memory }}"
- ARISTA03T0:
- num: 4
- filename: 03-ARISTA03T0.xml
- serial_port: 5034
- vlans: "18"
- memory: "{{ tor_memory }}"
- ARISTA03T2:
- num: 5
- filename: 03-ARISTA03T2.xml
- serial_port: 5050
- vlans: "2"
- memory: "{{ spine_memory }}"
- ARISTA04T0:
- num: 6
- filename: 03-ARISTA04T0.xml
- serial_port: 5035
- vlans: "19"
- memory: "{{ tor_memory }}"
- ARISTA04T2:
- num: 7
- filename: 03-ARISTA04T2.xml
- serial_port: 5051
- vlans: "3"
- memory: "{{ spine_memory }}"
- ARISTA05T0:
- num: 8
- filename: 03-ARISTA05T0.xml
- serial_port: 5036
- vlans: "20"
- memory: "{{ tor_memory }}"
- ARISTA05T2:
- num: 9
- filename: 03-ARISTA05T2.xml
- serial_port: 5052
- vlans: "4"
- memory: "{{ spine_memory }}"
- ARISTA06T0:
- num: 10
- filename: 03-ARISTA06T0.xml
- serial_port: 5037
- vlans: "21"
- memory: "{{ tor_memory }}"
- ARISTA06T2:
- num: 11
- filename: 03-ARISTA06T2.xml
- serial_port: 5053
- vlans: "5"
- memory: "{{ spine_memory }}"
- ARISTA07T0:
- num: 12
- filename: 03-ARISTA07T0.xml
- serial_port: 5038
- vlans: "22"
- memory: "{{ tor_memory }}"
- ARISTA07T2:
- num: 13
- filename: 03-ARISTA07T2.xml
- serial_port: 5054
- vlans: "6"
- memory: "{{ spine_memory }}"
- ARISTA08T0:
- num: 14
- filename: 03-ARISTA08T0.xml
- serial_port: 5039
- vlans: "23"
- memory: "{{ tor_memory }}"
- ARISTA08T2:
- num: 15
- filename: 03-ARISTA08T2.xml
- serial_port: 5055
- vlans: "7"
- memory: "{{ spine_memory }}"
- ARISTA09T0:
- num: 16
- filename: 03-ARISTA09T0.xml
- serial_port: 5040
- vlans: "24"
- memory: "{{ tor_memory }}"
- ARISTA09T2:
- num: 17
- filename: 03-ARISTA09T2.xml
- serial_port: 5056
- vlans: "8"
- memory: "{{ spine_memory }}"
- ARISTA10T0:
- num: 18
- filename: 03-ARISTA10T0.xml
- serial_port: 5041
- vlans: "25"
- memory: "{{ tor_memory }}"
- ARISTA10T2:
- num: 19
- filename: 03-ARISTA10T2.xml
- serial_port: 5057
- vlans: "9"
- memory: "{{ spine_memory }}"
- ARISTA11T0:
- num: 20
- filename: 03-ARISTA11T0.xml
- serial_port: 5042
- vlans: "26"
- memory: "{{ tor_memory }}"
- ARISTA11T2:
- num: 21
- filename: 03-ARISTA11T2.xml
- serial_port: 5058
- vlans: "10"
- memory: "{{ spine_memory }}"
- ARISTA12T0:
- num: 22
- filename: 03-ARISTA12T0.xml
- serial_port: 5043
- vlans: "27"
- memory: "{{ tor_memory }}"
- ARISTA12T2:
- num: 23
- filename: 03-ARISTA12T2.xml
- serial_port: 5059
- vlans: "11"
- memory: "{{ spine_memory }}"
- ARISTA13T0:
- num: 24
- filename: 03-ARISTA13T0.xml
- serial_port: 5044
- vlans: "28"
- memory: "{{ tor_memory }}"
- ARISTA13T2:
- num: 25
- filename: 03-ARISTA13T2.xml
- serial_port: 5060
- vlans: "12"
- memory: "{{ spine_memory }}"
- ARISTA14T0:
- num: 26
- filename: 03-ARISTA14T0.xml
- serial_port: 5045
- vlans: "29"
- memory: "{{ tor_memory }}"
- ARISTA14T2:
- num: 27
- filename: 03-ARISTA14T2.xml
- serial_port: 5061
- vlans: "13"
- memory: "{{ spine_memory }}"
- ARISTA15T0:
- num: 28
- filename: 03-ARISTA15T0.xml
- serial_port: 5046
- vlans: "30"
- memory: "{{ tor_memory }}"
- ARISTA15T2:
- num: 29
- filename: 03-ARISTA15T2.xml
- serial_port: 5062
- vlans: "14"
- memory: "{{ spine_memory }}"
- ARISTA16T0:
- num: 30
- filename: 03-ARISTA16T0.xml
- serial_port: 5047
- vlans: "31"
- memory: "{{ tor_memory }}"
- ARISTA16T2:
- num: 31
- filename: 03-ARISTA16T2.xml
- serial_port: 5063
- vlans: "15"
- memory: "{{ spine_memory }}"
-
diff --git a/ansible/host_vars/STR-ACS-SERV-02.yml b/ansible/host_vars/STR-ACS-SERV-02.yml
index 1d6aaa8a60f..9c87d6ee0b6 100644
--- a/ansible/host_vars/STR-ACS-SERV-02.yml
+++ b/ansible/host_vars/STR-ACS-SERV-02.yml
@@ -1,423 +1,5 @@
mgmt_bridge: br1
+mgmt_prefixlen: 23
mgmt_gw: 10.255.0.1
external_iface: p4p1
-ptf_1_enabled: true
-ptf_1_mgmt_ip: 10.255.0.189/24
-ptf_1_vlan_base: 809
-
-ptf_2_enabled: false
-ptf_2_mgmt_ip: 10.255.0.51/24
-ptf_2_vlan_base: 0 # ???
-
-ptf_3_enabled: true
-ptf_3_mgmt_ip: 10.255.0.186/24
-ptf_3_vlan_base: 841
-
-ptf_4_enabled: true
-ptf_4_mgmt_ip: 10.255.0.184/24
-ptf_4_vlan_base: 969
-
-ptf_5_enabled: false
-ptf_5_mgmt_ip: 10.255.0.183/24
-ptf_5_vlan_base: 489 # ???
-
-ptf_6_enabled: false
-ptf_6_mgmt_ip: 10.255.0.182/24
-ptf_6_vlan_base: 745 # ???
-
-vm_1_enabled: true
-vm_1_vlan_base: 457
-vm_1_injected_ip: 10.255.0.180/24
-VMs_1:
- ARISTA01T0:
- num: 0
- filename: 02-ARISTA01T0.xml
- serial_port: 5000
- vlans: "16"
- memory: "{{ tor_memory }}"
- ARISTA01T2:
- num: 1
- filename: 02-ARISTA01T2.xml
- serial_port: 5016
- vlans: "0"
- memory: "{{ spine_memory }}"
- ARISTA02T0:
- num: 2
- filename: 02-ARISTA02T0.xml
- serial_port: 5001
- vlans: "17"
- memory: "{{ tor_memory }}"
- ARISTA02T2:
- num: 3
- filename: 02-ARISTA02T2.xml
- serial_port: 5017
- vlans: "1"
- memory: "{{ spine_memory }}"
- ARISTA03T0:
- num: 4
- filename: 02-ARISTA03T0.xml
- serial_port: 5002
- vlans: "18"
- memory: "{{ tor_memory }}"
- ARISTA03T2:
- num: 5
- filename: 02-ARISTA03T2.xml
- serial_port: 5018
- vlans: "2"
- memory: "{{ spine_memory }}"
- ARISTA04T0:
- num: 6
- filename: 02-ARISTA04T0.xml
- serial_port: 5003
- vlans: "19"
- memory: "{{ tor_memory }}"
- ARISTA04T2:
- num: 7
- filename: 02-ARISTA04T2.xml
- serial_port: 5019
- vlans: "3"
- memory: "{{ spine_memory }}"
- ARISTA05T0:
- num: 8
- filename: 02-ARISTA05T0.xml
- serial_port: 5004
- vlans: "20"
- memory: "{{ tor_memory }}"
- ARISTA05T2:
- num: 9
- filename: 02-ARISTA05T2.xml
- serial_port: 5020
- vlans: "4"
- memory: "{{ spine_memory }}"
- ARISTA06T0:
- num: 10
- filename: 02-ARISTA06T0.xml
- serial_port: 5005
- vlans: "21"
- memory: "{{ tor_memory }}"
- ARISTA06T2:
- num: 11
- filename: 02-ARISTA06T2.xml
- serial_port: 5021
- vlans: "5"
- memory: "{{ spine_memory }}"
- ARISTA07T0:
- num: 12
- filename: 02-ARISTA07T0.xml
- serial_port: 5006
- vlans: "22"
- memory: "{{ tor_memory }}"
- ARISTA07T2:
- num: 13
- filename: 02-ARISTA07T2.xml
- serial_port: 5022
- vlans: "6"
- memory: "{{ spine_memory }}"
- ARISTA08T0:
- num: 14
- filename: 02-ARISTA08T0.xml
- serial_port: 5007
- vlans: "23"
- memory: "{{ tor_memory }}"
- ARISTA08T2:
- num: 15
- filename: 02-ARISTA08T2.xml
- serial_port: 5023
- vlans: "7"
- memory: "{{ spine_memory }}"
- ARISTA09T0:
- num: 16
- filename: 02-ARISTA09T0.xml
- serial_port: 5008
- vlans: "24"
- memory: "{{ tor_memory }}"
- ARISTA09T2:
- num: 17
- filename: 02-ARISTA09T2.xml
- serial_port: 5024
- vlans: "8"
- memory: "{{ spine_memory }}"
- ARISTA10T0:
- num: 18
- filename: 02-ARISTA10T0.xml
- serial_port: 5009
- vlans: "25"
- memory: "{{ tor_memory }}"
- ARISTA10T2:
- num: 19
- filename: 02-ARISTA10T2.xml
- serial_port: 5025
- vlans: "9"
- memory: "{{ spine_memory }}"
- ARISTA11T0:
- num: 20
- filename: 02-ARISTA11T0.xml
- serial_port: 5010
- vlans: "26"
- memory: "{{ tor_memory }}"
- ARISTA11T2:
- num: 21
- filename: 02-ARISTA11T2.xml
- serial_port: 5026
- vlans: "10"
- memory: "{{ spine_memory }}"
- ARISTA12T0:
- num: 22
- filename: 02-ARISTA12T0.xml
- serial_port: 5011
- vlans: "27"
- memory: "{{ tor_memory }}"
- ARISTA12T2:
- num: 23
- filename: 02-ARISTA12T2.xml
- serial_port: 5027
- vlans: "11"
- memory: "{{ spine_memory }}"
- ARISTA13T0:
- num: 24
- filename: 02-ARISTA13T0.xml
- serial_port: 5012
- vlans: "28"
- memory: "{{ tor_memory }}"
- ARISTA13T2:
- num: 25
- filename: 02-ARISTA13T2.xml
- serial_port: 5028
- vlans: "12"
- memory: "{{ spine_memory }}"
- ARISTA14T0:
- num: 26
- filename: 02-ARISTA14T0.xml
- serial_port: 5013
- vlans: "29"
- memory: "{{ tor_memory }}"
- ARISTA14T2:
- num: 27
- filename: 02-ARISTA14T2.xml
- serial_port: 5029
- vlans: "13"
- memory: "{{ spine_memory }}"
- ARISTA15T0:
- num: 28
- filename: 02-ARISTA15T0.xml
- serial_port: 5014
- vlans: "30"
- memory: "{{ tor_memory }}"
- ARISTA15T2:
- num: 29
- filename: 02-ARISTA15T2.xml
- serial_port: 5030
- vlans: "14"
- memory: "{{ spine_memory }}"
- ARISTA16T0:
- num: 30
- filename: 02-ARISTA16T0.xml
- serial_port: 5015
- vlans: "31"
- memory: "{{ tor_memory }}"
- ARISTA16T2:
- num: 31
- filename: 02-ARISTA16T2.xml
- serial_port: 5031
- vlans: "15"
- memory: "{{ spine_memory }}"
-
-
-vm_2_enabled: true
-vm_2_vlan_base: 777
-vm_2_injected_ip: 10.255.0.181/24
-VMs_2:
- ARISTA01T0:
- num: 0
- filename: 04-ARISTA01T0.xml
- serial_port: 5032
- vlans: "16"
- memory: "{{ tor_memory }}"
- ARISTA01T2:
- num: 1
- filename: 04-ARISTA01T2.xml
- serial_port: 5048
- vlans: "0"
- memory: "{{ spine_memory }}"
- ARISTA02T0:
- num: 2
- filename: 04-ARISTA02T0.xml
- serial_port: 5033
- vlans: "17"
- memory: "{{ tor_memory }}"
- ARISTA02T2:
- num: 3
- filename: 04-ARISTA02T2.xml
- serial_port: 5049
- vlans: "1"
- memory: "{{ spine_memory }}"
- ARISTA03T0:
- num: 4
- filename: 04-ARISTA03T0.xml
- serial_port: 5034
- vlans: "18"
- memory: "{{ tor_memory }}"
- ARISTA03T2:
- num: 5
- filename: 04-ARISTA03T2.xml
- serial_port: 5050
- vlans: "2"
- memory: "{{ spine_memory }}"
- ARISTA04T0:
- num: 6
- filename: 04-ARISTA04T0.xml
- serial_port: 5035
- vlans: "19"
- memory: "{{ tor_memory }}"
- ARISTA04T2:
- num: 7
- filename: 04-ARISTA04T2.xml
- serial_port: 5051
- vlans: "3"
- memory: "{{ spine_memory }}"
- ARISTA05T0:
- num: 8
- filename: 04-ARISTA05T0.xml
- serial_port: 5036
- vlans: "20"
- memory: "{{ tor_memory }}"
- ARISTA05T2:
- num: 9
- filename: 04-ARISTA05T2.xml
- serial_port: 5052
- vlans: "4"
- memory: "{{ spine_memory }}"
- ARISTA06T0:
- num: 10
- filename: 04-ARISTA06T0.xml
- serial_port: 5037
- vlans: "21"
- memory: "{{ tor_memory }}"
- ARISTA06T2:
- num: 11
- filename: 04-ARISTA06T2.xml
- serial_port: 5053
- vlans: "5"
- memory: "{{ spine_memory }}"
- ARISTA07T0:
- num: 12
- filename: 04-ARISTA07T0.xml
- serial_port: 5038
- vlans: "22"
- memory: "{{ tor_memory }}"
- ARISTA07T2:
- num: 13
- filename: 04-ARISTA07T2.xml
- serial_port: 5054
- vlans: "6"
- memory: "{{ spine_memory }}"
- ARISTA08T0:
- num: 14
- filename: 04-ARISTA08T0.xml
- serial_port: 5039
- vlans: "23"
- memory: "{{ tor_memory }}"
- ARISTA08T2:
- num: 15
- filename: 04-ARISTA08T2.xml
- serial_port: 5055
- vlans: "7"
- memory: "{{ spine_memory }}"
- ARISTA09T0:
- num: 16
- filename: 04-ARISTA09T0.xml
- serial_port: 5040
- vlans: "24"
- memory: "{{ tor_memory }}"
- ARISTA09T2:
- num: 17
- filename: 04-ARISTA09T2.xml
- serial_port: 5056
- vlans: "8"
- memory: "{{ spine_memory }}"
- ARISTA10T0:
- num: 18
- filename: 04-ARISTA10T0.xml
- serial_port: 5041
- vlans: "25"
- memory: "{{ tor_memory }}"
- ARISTA10T2:
- num: 19
- filename: 04-ARISTA10T2.xml
- serial_port: 5057
- vlans: "9"
- memory: "{{ spine_memory }}"
- ARISTA11T0:
- num: 20
- filename: 04-ARISTA11T0.xml
- serial_port: 5042
- vlans: "26"
- memory: "{{ tor_memory }}"
- ARISTA11T2:
- num: 21
- filename: 04-ARISTA11T2.xml
- serial_port: 5058
- vlans: "10"
- memory: "{{ spine_memory }}"
- ARISTA12T0:
- num: 22
- filename: 04-ARISTA12T0.xml
- serial_port: 5043
- vlans: "27"
- memory: "{{ tor_memory }}"
- ARISTA12T2:
- num: 23
- filename: 04-ARISTA12T2.xml
- serial_port: 5059
- vlans: "11"
- memory: "{{ spine_memory }}"
- ARISTA13T0:
- num: 24
- filename: 04-ARISTA13T0.xml
- serial_port: 5044
- vlans: "28"
- memory: "{{ tor_memory }}"
- ARISTA13T2:
- num: 25
- filename: 04-ARISTA13T2.xml
- serial_port: 5060
- vlans: "12"
- memory: "{{ spine_memory }}"
- ARISTA14T0:
- num: 26
- filename: 04-ARISTA14T0.xml
- serial_port: 5045
- vlans: "29"
- memory: "{{ tor_memory }}"
- ARISTA14T2:
- num: 27
- filename: 04-ARISTA14T2.xml
- serial_port: 5061
- vlans: "13"
- memory: "{{ spine_memory }}"
- ARISTA15T0:
- num: 28
- filename: 04-ARISTA15T0.xml
- serial_port: 5046
- vlans: "30"
- memory: "{{ tor_memory }}"
- ARISTA15T2:
- num: 29
- filename: 04-ARISTA15T2.xml
- serial_port: 5062
- vlans: "14"
- memory: "{{ spine_memory }}"
- ARISTA16T0:
- num: 30
- filename: 04-ARISTA16T0.xml
- serial_port: 5047
- vlans: "31"
- memory: "{{ tor_memory }}"
- ARISTA16T2:
- num: 31
- filename: 04-ARISTA16T2.xml
- serial_port: 5063
- vlans: "15"
- memory: "{{ spine_memory }}"
-
diff --git a/ansible/lab b/ansible/lab
new file mode 100644
index 00000000000..056a2168dc7
--- /dev/null
+++ b/ansible/lab
@@ -0,0 +1,22 @@
+[sonic_mlnx_40]
+str-msn2700-01 ansible_host=10.251.0.188
+
+[sonic_mlnx_40:vars]
+hwsku="ACS-MSN2700"
+iface_speed='40000'
+mgmt_subnet_mask_length="24"
+
+[sonic:children]
+sonic_mlnx_40
+
+[ptf]
+ptf_ptf1 ansible_host=10.255.0.188 ansible_ssh_user=root ansible_ssh_pass=root
+ptf_vms1-1 ansible_host=10.255.0.178 ansible_ssh_user=root ansible_ssh_pass=root
+
+[lab:children]
+sonic
+fanout
+
+[fanout]
+str-7260-10 ansible_host=10.251.0.13
+str-7260-11 ansible_host=10.251.0.234
diff --git a/ansible/library/bgp_facts.py b/ansible/library/bgp_facts.py
index 13902dbce0e..f777f5a5cd4 100644
--- a/ansible/library/bgp_facts.py
+++ b/ansible/library/bgp_facts.py
@@ -1,6 +1,5 @@
#!/usr/bin/python
-
DOCUMENTATION = '''
module: bgp_facts
version_added: "2.0"
@@ -63,17 +62,18 @@ def run(self):
"""
Main method of the class
"""
- self.collect_neighbors()
+ self.collect_data('summary')
+ self.parse_summary()
+ self.collect_data('neighbor')
self.parse_neighbors()
self.module.exit_json(ansible_facts=self.facts)
-
- def collect_neighbors(self):
+ def collect_data(self, command_str):
"""
- Collect bgp neighbors by reading output of 'vtysh' command line tool
+ Collect bgp information by reading output of 'vtysh' command line tool
"""
try:
- rc, self.out, err = self.module.run_command('vtysh -c "show ip bgp neighbors"',
+ rc, self.out, err = self.module.run_command('vtysh -c "show ip bgp ' + command_str + '"',
executable='/bin/bash', use_unsafe_shell=True)
except Exception as e:
self.module.fail_json(msg=str(e))
@@ -84,9 +84,14 @@ def collect_neighbors(self):
return
+ def parse_summary(self):
+ regex_asn = re.compile(r'.*local AS number (\d+).*')
+ if regex_asn.match(self.out):
+ self.facts['bgp_localasn'] = regex_asn.match(self.out).group(1)
+
def parse_neighbors(self):
- regex_ip = re.compile(r'^BGP neighbor is (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
+ regex_ip = re.compile(r'^BGP neighbor is \*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[0-9a-fA-F:]+)')
regex_remote_as = re.compile(r'.*remote AS (\d+)')
regex_local_as = re.compile(r'.*local AS (\d+)')
regex_desc = re.compile(r'.*Description: (.*)')
@@ -97,11 +102,12 @@ def parse_neighbors(self):
regex_conn_est = re.compile(r'.*Connections established (\d+)')
regex_conn_dropped = re.compile(r'.*Connections established \d+; dropped (\d+)')
regex_routerid = re.compile(r'.*remote router ID (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
-
+ regex_peer_group = re.compile(r'.*Member of peer-group (.*) for session parameters')
+ regex_subnet = re.compile(r'.*subnet range group: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2})')
neighbors = {}
try:
- split_output = self.out.split("BGP neighbor")
+ split_output = self.out.split("BGP neighbor is")
for n in split_output:
@@ -109,20 +115,23 @@ def parse_neighbors(self):
if 'BGP' in n:
neighbor = {}
message_stats = {}
- n = "BGP neighbor" + n
+ n = "BGP neighbor is" + n
lines = n.splitlines()
+ neighbor['accepted prefixes'] = 0
for line in lines:
- if regex_ip.match(line): neighbor_ip = regex_ip.match(line).group(1)
+ if regex_ip.match(line): neighbor_ip = regex_ip.match(line).group(1).lower()
if regex_remote_as.match(line): neighbor['remote AS'] = int(regex_remote_as.match(line).group(1))
if regex_local_as.match(line): neighbor['local AS'] = int(regex_local_as.match(line).group(1))
if regex_desc.match(line): neighbor['description'] = regex_desc.match(line).group(1)
if regex_state.match(line): neighbor['state'] = regex_state.match(line).group(1).lower()
if regex_mrai.match(line): neighbor['mrai'] = int(regex_mrai.match(line).group(1))
- if regex_accepted.match(line): neighbor['accepted prefixes'] = int(regex_accepted.match(line).group(1))
+ if regex_accepted.match(line): neighbor['accepted prefixes'] += int(regex_accepted.match(line).group(1))
if regex_conn_est.match(line): neighbor['connections established'] = int(regex_conn_est.match(line).group(1))
if regex_conn_dropped.match(line): neighbor['connections dropped'] = int(regex_conn_dropped.match(line).group(1))
if regex_routerid.match(line): neighbor['remote routerid'] = regex_routerid.match(line).group(1)
+ if regex_peer_group.match(line): neighbor['peer group'] = regex_peer_group.match(line).group(1)
+ if regex_subnet.match(line): neighbor['subnet'] = regex_subnet.match(line).group(1)
if regex_stats.match(line):
key, values = line.split(':')
@@ -142,7 +151,6 @@ def parse_neighbors(self):
self.module.fail_json(msg=str(e))
self.facts['bgp_neighbors'] = neighbors
-
return
diff --git a/ansible/library/conn_graph_facts.py b/ansible/library/conn_graph_facts.py
new file mode 100644
index 00000000000..858b8d338ba
--- /dev/null
+++ b/ansible/library/conn_graph_facts.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+
+import lxml.etree as ET
+import yaml
+import os
+import traceback
+import ipaddr as ipaddress
+from operator import itemgetter
+from itertools import groupby
+from collections import defaultdict
+
+DOCUMENTATION='''
+module: conn_graph_facts.py
+version_added: 2.0
+short_description: Retrive lab fanout switches physical and vlan connections
+Description:
+ Retrive lab fanout switches physical and vlan connections
+ add to Ansible facts
+options:
+ host: [fanout switch name|Server name|Sonic Switch Name]
+ requred: True
+
+Ansible_facts:
+ device_info: The device(host) type and hwsku
+ device_conn: each physical connection of the device(host)
+ device_vlan_range: all configured vlan range for the device(host)
+ device_port_vlans: detailed vlanids for each physical port and switchport mode
+ server_links: each server port vlan ids
+
+'''
+
+EXAMPLES='''
+ - name: conn_graph_facts: host = "str-7260-11"
+
+ return:
+ "device_info": {
+ "ManagementIp": "10.251.0.76/24",
+ "HwSku": "Arista-7260QX-64",
+ "Type": "FanoutLeaf"
+ },
+ "device_conn": [
+ {
+ "StartPort": "Ethernet0",
+ "EndPort": "Ethernet33",
+ "StartDevice": "str-s6000-on-1",
+ "VlanID": "233",
+ "BandWidth": "40000",
+ "VlanMode": "Access",
+ "EndDevice": "str-7260-01"
+ },
+ {...}
+ ],
+ "device_vlan_range": {
+ "VlanRange": "201-980,1041-1100"
+ },
+ "device_vlan_port:=: {
+ ...
+ "Ethernet44": {
+ "vlanids": "801-860",
+ "mode": "Trunk"
+ },
+ "Ethernet42": {
+ "vlanids": "861-920",
+ "mode": "Trunk"
+ },......
+ }
+
+
+'''
+
+LAB_CONNECTION_GRAPH_FILE = 'lab_connection_graph.xml'
+LAB_GRAPHFILE_PATH = 'files/'
+
+class Parse_Lab_Graph():
+ """
+ Parse the generated lab physical connection graph and insert Ansible fact of the graph
+ for deploying fanout switches and dynamically configure vlan mapping to hook up EOS VMs
+ and ptf docker for lab testing
+
+ There is a creategraph.py under ansible/files to create the png and dpg like graph file for lab devices from csv file
+ The 2 csv files under ansible/files are csv files to list all devices and device links for Sonic testbed
+ There is a sonic_server_links.yml file to describe the connections between servers port and Sonic devices
+ This module conn_graph_file also parse the server links to have a full root fanout switches template for deployment.
+ """
+
+ def __init__(self, xmlfile):
+ self.root = ET.parse(xmlfile)
+ self.devices = {}
+ self.vlanport = {}
+ self.vlanrange = {}
+ self.links = {}
+ self.server = defaultdict(dict)
+ self.pngtag = 'PhysicalNetworkGraphDeclaration'
+ self.dpgtag = 'DataPlaneGraph'
+
+ def port_vlanlist(self, vlanrange):
+ vlans = []
+ for vlanid in list(map(str.strip,vlanrange.split(','))):
+ if vlanid.isdigit():
+ vlans.append(int(vlanid))
+ continue
+ elif '-' in vlanid:
+ vlanlist = list(map(str.strip,vlanid.split('-')))
+ vlans.extend(range(int(vlanlist[0]), int(vlanlist[1])+1))
+ continue
+ elif vlanid != '':
+ raise Exception, 'vlan range error "%s"'%vlanrange
+ vlans = sorted(set(vlans))
+ return vlans
+
+ def parse_graph(self):
+ """
+ Parse the xml graph file
+ """
+ deviceinfo = {}
+ deviceroot = self.root.find(self.pngtag).find('Devices')
+ devices = deviceroot.findall('Device')
+ if devices is not None:
+ for dev in devices:
+ hostname = dev.attrib['Hostname']
+ if hostname is not None:
+ deviceinfo[hostname] = {}
+ hwsku = dev.attrib['HwSku']
+ devtype = dev.attrib['Type']
+ deviceinfo[hostname]['HwSku'] = hwsku
+ deviceinfo[hostname]['Type'] = devtype
+ self.links[hostname] = {}
+ devicel2info = {}
+ devicel3s = self.root.find(self.dpgtag).findall('DevicesL3Info')
+ devicel2s = self.root.find(self.dpgtag).findall('DevicesL2Info')
+ if devicel2s is not None:
+ for l2info in devicel2s:
+ hostname = l2info.attrib['Hostname']
+ if hostname is not None:
+ devicel2info[hostname] = {}
+ vlans = l2info.findall('InterfaceVlan')
+ for vlan in vlans:
+ portname = vlan.attrib['portname']
+ portmode = vlan.attrib['mode']
+ portvlanid = vlan.attrib['vlanids']
+ portvlanlist = self.port_vlanlist(portvlanid)
+ devicel2info[hostname][portname] = {'mode': portmode, 'vlanids': portvlanid, 'vlanlist': portvlanlist}
+ if devicel3s is not None:
+ for l3info in devicel3s:
+ hostname = l3info.attrib['Hostname']
+ if hostname is not None:
+ management_ip = l3info.find('ManagementIPInterface').attrib['Prefix']
+ deviceinfo[hostname]['ManagementIp'] = management_ip
+ mgmtip = ipaddress.IPNetwork(management_ip)
+ deviceinfo[hostname]['mgmtip'] = str(mgmtip.ip)
+ management_gw = str(mgmtip.network+1)
+ deviceinfo[hostname]['ManagementGw'] = management_gw
+ allinks = self.root.find(self.pngtag).find('DeviceInterfaceLinks').findall('DeviceInterfaceLink')
+ if allinks is not None:
+ for link in allinks:
+ start_dev = link.attrib['StartDevice']
+ end_dev = link.attrib['EndDevice']
+ if start_dev:
+ self.links[start_dev][link.attrib['StartPort']] = {'peerdevice':link.attrib['EndDevice'], 'peerport': link.attrib['EndPort']}
+ if end_dev:
+ self.links[end_dev][link.attrib['EndPort']] = {'peerdevice': link.attrib['StartDevice'], 'peerport': link.attrib['StartPort']}
+ self.devices = deviceinfo
+ self.vlanport = devicel2info
+
+ def convert_list2range(self, l):
+ """
+ common module to convert a list to range for easier vlan configuration generation
+ """
+ ranges = []
+ sl = sorted(set(l))
+ for k,g in groupby(enumerate(sl), lambda (i,x): i-x):
+ group = list(map(itemgetter(1), g))
+ if len(group) == 1:
+ ranges.append(str(group[0]))
+ else:
+ ranges.append(str(group[0])+'-'+str(group[-1]))
+ return ranges
+
+ def get_server_links(self):
+ return self.server
+
+ def get_host_vlan(self, hostname):
+ """
+ Calculate dpg vlan data for each link(port) and return a Switch/Device total Vlan range
+ """
+
+ if hostname in self.devices and self.devices[hostname]['Type'].lower() == 'devsonic':
+ self.vlanport[hostname] = {}
+ for port in self.links[hostname]:
+ peerdevice = self.links[hostname][port]['peerdevice']
+ peerport = self.links[hostname][port]['peerport']
+ peerportmode = self.vlanport[peerdevice][peerport]['mode']
+ peervlanids = self.vlanport[peerdevice][peerport]['vlanids']
+ peervlanlist = self.vlanport[peerdevice][peerport]['vlanlist']
+ self.vlanport[hostname][port] = {'mode': peerportmode, 'vlanids': peervlanids, 'vlanlist': peervlanlist}
+
+ if hostname in self.vlanport:
+ dpgvlans = self.vlanport[hostname]
+ vlans = []
+ for intf in dpgvlans:
+ vlans += dpgvlans[intf]['vlanlist']
+ self.vlanrange = self.convert_list2range(vlans)
+ return {'VlanRange': self.vlanrange, 'VlanList': vlans }
+
+ def get_host_device_info(self, hostname):
+ """
+ return the given hostname device info of hwsku and type
+ """
+ if hostname in self.devices:
+ return self.devices[hostname]
+ else:
+ return self.devices
+
+ def get_host_port_vlans(self, hostname):
+ """
+ return the given hostname device vlan port information
+ """
+ if hostname in self.vlanport:
+ return self.vlanport[hostname]
+ else:
+ return self.vlanport
+
+ def get_host_connections(self, hostname):
+ """
+ return the given hostname device each individual connection
+ """
+ if hostname in self.links:
+ return self.links[hostname]
+ else:
+ return self.links
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ host=dict(required=False),
+ filename=dict(required=False),
+ ),
+ supports_check_mode=True
+ )
+ m_args = module.params
+ hostname = m_args['host']
+ try:
+ lab_graph = Parse_Lab_Graph(LAB_GRAPHFILE_PATH+LAB_CONNECTION_GRAPH_FILE)
+ lab_graph.parse_graph()
+ dev = lab_graph.get_host_device_info(hostname)
+ if dev is None:
+ module.fail_json(msg="cannot find info for "+hostname)
+ results = {}
+ results['device_info'] = lab_graph.get_host_device_info(hostname)
+ results['device_conn'] = lab_graph.get_host_connections(hostname)
+ if lab_graph.get_host_vlan(hostname):
+ results['device_vlan_range'] = lab_graph.get_host_vlan(hostname)['VlanRange']
+ results['device_vlan_list'] = lab_graph.get_host_vlan(hostname)['VlanList']
+ results['device_port_vlans'] = lab_graph.get_host_port_vlans(hostname)
+ module.exit_json(ansible_facts=results)
+ except (IOError, OSError):
+ module.fail_json(msg="Can not find lab graph file "+LAB_CONNECTION_GRAPH_FILE)
+ except Exception as e:
+ module.fail_json(msg=traceback.format_exc())
+
+
+from ansible.module_utils.basic import *
+if __name__== "__main__":
+ main()
+
+
diff --git a/ansible/library/get_ip_in_range.py b/ansible/library/get_ip_in_range.py
new file mode 100644
index 00000000000..8d16c5723cc
--- /dev/null
+++ b/ansible/library/get_ip_in_range.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python
+from netaddr import *
+import sys
+import ipaddress
+
+DOCUMENTATION = '''
+module: get_ip_in_range
+version_added: "1.0"
+short_description: Get certain number of ips within a prefix
+description:
+ - Generate certain number of unique IP withn a subnet
+ - Generated ips will be inserted into the 'generated_ips' key
+options:
+ num:
+ description:
+ - set to the number of ip that needs to be generated.
+ required: true
+ prefix:
+ description:
+ - the required ip range in prefix format.
+ required: true
+ exclude_ips:
+ description:
+ - the ips within the prefix that are excluded.
+ required: false
+'''
+
+EXAMPLES = '''
+- name: Get IP in range
+ get_ip_in_range: num={{num}} prefix={{prefix}}
+'''
+
+
+class IpRangeModule(object):
+ def __init__(self):
+ self.module = AnsibleModule(
+ argument_spec=dict(
+ num=dict(required=True, type='int'),
+ prefix=dict(required=True),
+ exclude_ips=dict(required=False, default=[], type='list'),
+ ),
+ supports_check_mode=True)
+
+ self.out = None
+ self.facts = {}
+
+ return
+
+ def run(self):
+ """
+ Main method of the class
+
+ """
+ m_args = self.module.params
+ exclude_ips = []
+ ip_list = m_args['exclude_ips']
+ for ip in ip_list:
+ exclude_ips.append(IPAddress(ip))
+
+ self.generate_ips(m_args['num'], m_args['prefix'], exclude_ips)
+ self.module.exit_json(ansible_facts=self.facts)
+
+
+ def generate_ips(self, num, prefix, exclude_ips):
+ """
+ Generate ips
+ """
+ prefix = IPNetwork(prefix)
+ exclude_ips.append(prefix.broadcast)
+ exclude_ips.append(prefix.network)
+ available_ips = list(prefix)
+
+ if len(available_ips) - len(exclude_ips)< num:
+ self.module.fail_json(msg="Don't have enough available ips in prefix, num=%d, prefix=%s, exclude_ips=%s." %
+ (num, prefix, exclude_ips))
+ generated_ips = []
+ for available_ip in available_ips:
+ if available_ip not in exclude_ips:
+ generated_ips.append(str(available_ip) + '/' + str(prefix.prefixlen))
+ if len(generated_ips) == num:
+ break
+ self.facts['generated_ips'] = generated_ips
+ return
+
+
+def main():
+ ip_range = IpRangeModule()
+ ip_range.run()
+
+ return
+
+
+from ansible.module_utils.basic import *
+if __name__ == "__main__":
+ main()
diff --git a/ansible/library/lag_facts.py b/ansible/library/lag_facts.py
new file mode 100644
index 00000000000..0a5afb4a413
--- /dev/null
+++ b/ansible/library/lag_facts.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+
+import json
+from ansible.module_utils.basic import *
+
+DOCUMENTATION = '''
+---
+module: lag_facts
+Ansible_version_added: "2.0.0.2"
+Sonic_version: "2.0"
+short_description: Retrieve lag(LACP) information from a device
+description:
+ - Retrieved facts will be inserted to:
+ lag_facts:
+ - 'names': [list all portchannel names]
+ - 'lags': {portchannel: detailed portchannel information }
+'''
+
+EXAMPLES = '''
+# Gather lab facts
+ - name: Gather lag info
+ lag_facts: host=10.255.0.200
+ - name: display lag information
+ debug: var=lag_facts
+'''
+
+class LagModule(object):
+ def __init__(self):
+ self.module = AnsibleModule(
+ argument_spec=dict(
+ host=dict(required=True),
+ ),
+ supports_check_mode=False,
+ )
+ self.lag_names = []
+ self.lags = {}
+ return
+
+ def run(self):
+ '''
+ Main method of the class
+ '''
+ self.get_po_names()
+ for po in self.lag_names:
+ self.lags[po] = {}
+ self.lags[po]['po_stats'] = self.get_po_status(po)
+ self.lags[po]['po_config'] = self.get_po_config(po)
+ self.lags[po]['po_intf_stat'] = self.get_po_intf_stat(po)
+ self.module.exit_json(ansible_facts={'lag_facts': {'names': self.lag_names, 'lags': self.lags}})
+ return
+
+ def get_po_names(self):
+ '''
+ Collect configured lag interface names
+ '''
+ rt, out, err = self.module.run_command("sonic-cfggen -m /etc/sonic/minigraph.xml -v \"minigraph_portchannels.keys() | join(' ')\"")
+ if rt != 0:
+ fail_msg="Command to retrieve portchannel names failed return=%d, out=%s, err=%s" %(rt, out, err)
+ self.module.fail_json(msg=fail_msg)
+ else:
+ self.lag_names = out.split()
+ return
+
+ def get_po_status(self, po_name):
+ '''
+ Collect lag information by command docker teamdctl
+ '''
+ rt, out, err = self.module.run_command("docker exec -i teamd teamdctl "+po_name+" state dump")
+ if rt != 0:
+ fail_msg="failed dump port channel %s status return=%d, out=%s, err=%s" %(po_name, rt, out, err)
+ self.module.fail_json(msg=fail_msg)
+ json_info = json.loads(out)
+ return json_info
+
+ def get_po_config(self, po_name):
+ '''
+ Collect lag information by command docker teamdctl
+ '''
+ rt, out, err = self.module.run_command("docker exec -i teamd teamdctl "+po_name+" config dump")
+ if rt != 0:
+ fail_msg="failed dump port channel %s config return=%d, out=%s, err=%s" %(po_name, rt, out, err)
+ self.module.fail_json(msg=fail_msg)
+ json_info = json.loads(out)
+ return json_info
+
+ def get_po_intf_stat(self, po_name):
+ '''
+ Collect lag information by command docker teamdctl
+ '''
+ rt, out, err = self.module.run_command("ip link show " + po_name)
+ if rt != 0:
+ fail_msg="failed show interface status of %s return=%d, out=%s, err=%s" %(po_name, rt, out, err)
+ self.module.fail_json(msg=fail_msg)
+ if 'NO-CARRIER' in out:
+ return 'Down'
+ else:
+ return 'Up'
+
+def main():
+ lags = LagModule()
+ lags.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible/library/minigraph_facts.py b/ansible/library/minigraph_facts.py
index fc4a1b22966..53dfb1b0458 100644
--- a/ansible/library/minigraph_facts.py
+++ b/ansible/library/minigraph_facts.py
@@ -8,6 +8,8 @@
import copy
import ipaddr as ipaddress
from collections import defaultdict
+from natsort import natsorted
+
from lxml import etree as ET
from lxml.etree import QName
@@ -45,10 +47,12 @@
class minigraph_encoder(json.JSONEncoder):
def default(self, obj):
- if isinstance(obj, (ipaddress.IPv4Network, ipaddress.IPv6Network, ipaddress.IPv4Address, ipaddress.IPv6Address)):
+ if isinstance(obj,
+ (ipaddress.IPv4Network, ipaddress.IPv6Network, ipaddress.IPv4Address, ipaddress.IPv6Address)):
return str(obj)
return json.JSONEncoder.default(self, obj)
-
+
+
def parse_png(png, hname):
neighbors = {}
devices = {}
@@ -69,9 +73,14 @@ def parse_png(png, hname):
startport = link.find(str(QName(ns, "StartPort"))).text
if enddevice == hname:
+ if port_alias_map.has_key(endport):
+ endport = port_alias_map[endport]
neighbors[endport] = {'name': startdevice, 'port': startport}
else:
+ if port_alias_map.has_key(startport):
+ startport = port_alias_map[startport]
neighbors[startport] = {'name': enddevice, 'port': endport}
+
if child.tag == str(QName(ns, "Devices")):
for device in child.findall(str(QName(ns, "Device"))):
lo_addr = None
@@ -111,7 +120,6 @@ def parse_png(png, hname):
elif node.tag == str(QName(ns, "EndDevice")):
mgmt_dev = node.text
-
return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port)
@@ -123,9 +131,12 @@ def parse_dpg(dpg, hname):
ipintfs = child.find(str(QName(ns, "IPInterfaces")))
intfs = []
- vlan_map = {}
for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))):
- intfname = ipintf.find(str(QName(ns, "AttachTo"))).text
+ intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text
+ if port_alias_map.has_key(intfalias):
+ intfname = port_alias_map[intfalias]
+ else:
+ intfname = intfalias
ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text
ipn = ipaddress.IPNetwork(ipprefix)
ipaddr = ipn.ip
@@ -133,52 +144,32 @@ def parse_dpg(dpg, hname):
addr_bits = ipn.max_prefixlen
subnet = ipaddress.IPNetwork(str(ipn.network) + '/' + str(prefix_len))
ipmask = ipn.netmask
-
+
intf = {'addr': ipaddr, 'subnet': subnet}
if isinstance(ipn, ipaddress.IPv4Network):
intf['mask'] = ipmask
else:
intf['mask'] = str(prefix_len)
+ intf.update({'attachto': intfname, 'prefixlen': int(prefix_len)})
- if intfname[0:4] == "Vlan":
- if intfname in vlan_map:
- vlan_map[intfname].append(intf)
-
+ # TODO: remove peer_addr after dependency removed
+ ipaddr_val = int(ipn.ip)
+ peer_addr_val = None
+ if int(prefix_len) == addr_bits - 2:
+ if ipaddr_val & 0x3 == 1:
+ peer_addr_val = ipaddr_val + 1
else:
- vlan_map[intfname] = [intf]
- else:
- intf.update({'name': intfname, 'prefixlen': int(prefix_len)})
-
- if port_alias_map.has_key(intfname):
- intf['alias'] = port_alias_map[intfname]
+ peer_addr_val = ipaddr_val - 1
+ elif int(prefix_len) == addr_bits - 1:
+ if ipaddr_val & 0x1 == 0:
+ peer_addr_val = ipaddr_val + 1
else:
- intf['alias'] = intfname
+ peer_addr_val = ipaddr_val - 1
- # TODO: remove peer_addr after dependency removed
- ipaddr_val = int(ipn.ip)
- peer_addr_val = None
- if int(prefix_len) == addr_bits - 2:
- if ipaddr_val & 0x3 == 1:
- peer_addr_val = ipaddr_val + 1
- else:
- peer_addr_val = ipaddr_val - 1
- elif int(prefix_len) == addr_bits - 1:
- if ipaddr_val & 0x1 == 0:
- peer_addr_val = ipaddr_val + 1
- else:
- peer_addr_val = ipaddr_val - 1
-
- if peer_addr_val is not None:
- intf['peer_addr'] = ipaddress.IPAddress(peer_addr_val)
- intfs.append(intf)
-
- pcintfs = child.find(str(QName(ns, "PortChannelInterfaces")))
- pc_intfs = []
- for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))):
- pcintfname = pcintf.find(str(QName(ns, "Name"))).text
- pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text
- pcmbr_list = pcintfmbr.split(';', 1)
- pc_intfs.append({'name': pcintfname, 'members': pcmbr_list})
+ if peer_addr_val is not None:
+ intf['peer_addr'] = ipaddress.IPAddress(peer_addr_val)
+ intfs.append(intf)
+ ports[intfname] = {'name': intfname, 'alias': intfalias}
lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces")))
lo_intfs = []
@@ -201,30 +192,67 @@ def parse_dpg(dpg, hname):
for mgmtintf in mgmtintfs.findall(str(QName(ns1, "ManagementIPInterface"))):
ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text
mgmtipn = ipaddress.IPNetwork(ipprefix)
+ # Ignore IPv6 management address
+ if mgmtipn.version == 6:
+ continue
ipaddr = mgmtipn.ip
prefix_len = str(mgmtipn.prefixlen)
ipmask = mgmtipn.netmask
gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1)
mgmt_intf = {'addr': ipaddr, 'prefixlen': prefix_len, 'mask': ipmask, 'gwaddr': gwaddr}
+ pcintfs = child.find(str(QName(ns, "PortChannelInterfaces")))
+ pc_intfs = []
+ pcs = {}
+ for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))):
+ pcintfname = pcintf.find(str(QName(ns, "Name"))).text
+ pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text
+ pcmbr_list = pcintfmbr.split(';', 1)
+ for i, member in enumerate(pcmbr_list):
+ pcmbr_list[i] = port_alias_map[member]
+ ports[port_alias_map[member]] = {'name': port_alias_map[member], 'alias': member}
+ pcs[pcintfname] = {'name': pcintfname, 'members': pcmbr_list}
+ ports.pop(pcintfname)
+
vlanintfs = child.find(str(QName(ns, "VlanInterfaces")))
vlan_intfs = []
+ vlans = {}
for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))):
vintfname = vintf.find(str(QName(ns, "Name"))).text
vlanid = vintf.find(str(QName(ns, "VlanID"))).text
vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text
vmbr_list = vintfmbr.split(';')
+ for i, member in enumerate(vmbr_list):
+ vmbr_list[i] = port_alias_map[member]
+ ports[port_alias_map[member]] = {'name': port_alias_map[member], 'alias': member}
vlan_attributes = {'name': vintfname, 'members': vmbr_list, 'vlanid': vlanid}
- for addrtuple in vlan_map.get(vintfname, []):
- vlan_attributes.update(addrtuple)
- vlan_intfs.append(copy.deepcopy(vlan_attributes))
-
- return intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs
- return None, None, None, None, None
+ vlans[vintfname] = vlan_attributes
+ ports.pop(vintfname)
+
+ aclintfs = child.find(str(QName(ns, "AclInterfaces")))
+ acls = {}
+ for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
+ aclname = aclintf.find(str(QName(ns, "InAcl"))).text
+ aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';')
+ acl_intfs = []
+ for member in aclattach:
+ member = member.strip()
+ if pcs.has_key(member):
+ acl_intfs.extend(pcs[member]['members']) # For ACL attaching to port channels, we break them into port channel members
+ elif vlans.has_key(member):
+ print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported"
+ elif port_alias_map.has_key(member):
+ acl_intfs.append(port_alias_map[member])
+ if acl_intfs:
+ acls[aclname] = acl_intfs
+
+ return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls
+ return None, None, None, None, None, None
def parse_cpg(cpg, hname):
bgp_sessions = []
myasn = None
+ bgp_peers_with_range = []
for child in cpg:
tag = child.tag
if tag == str(QName(ns, "PeeringSessions")):
@@ -251,12 +279,51 @@ def parse_cpg(cpg, hname):
hostname = router.find(str(QName(ns1, "Hostname"))).text
if hostname == hname:
myasn = int(asn)
+ peers = router.find(str(QName(ns1, "Peers")))
+ for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))):
+ addr = bgpPeer.find(str(QName(ns, "Address"))).text
+ if bgpPeer.find(str(QName(ns1, "PeersRange"))) is not None:
+ name = bgpPeer.find(str(QName(ns1, "Name"))).text
+ ip_range = bgpPeer.find(str(QName(ns1, "PeersRange"))).text
+ ip_range_group = ip_range.split(';') if ip_range and ip_range != "" else []
+ bgp_peers_with_range.append({
+ 'name': name,
+ 'ip_range': ip_range_group
+ })
+
else:
for bgp_session in bgp_sessions:
if hostname == bgp_session['name']:
bgp_session['asn'] = int(asn)
- return bgp_sessions, myasn
+ return bgp_sessions, myasn, bgp_peers_with_range
+
+
+def parse_meta(meta, hname):
+ syslog_servers = []
+ dhcp_servers = []
+ ntp_servers = []
+ mgmt_routes = []
+ deployment_id = None
+ device_metas = meta.find(str(QName(ns, "Devices")))
+ for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
+ if device.find(str(QName(ns1, "Name"))).text == hname:
+ properties = device.find(str(QName(ns1, "Properties")))
+ for device_property in properties.findall(str(QName(ns1, "DeviceProperty"))):
+ name = device_property.find(str(QName(ns1, "Name"))).text
+ value = device_property.find(str(QName(ns1, "Value"))).text
+ value_group = value.split(';') if value and value != "" else []
+ if name == "DhcpResources":
+ dhcp_servers = value_group
+ elif name == "NtpResources":
+ ntp_servers = value_group
+ elif name == "SyslogResources":
+ syslog_servers = value_group
+ elif name == "ForcedMgmtRoutes":
+ mgmt_routes = value_group
+ elif name == "DeploymentId":
+ deployment_id = value
+ return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, deployment_id
def get_console_info(devices, dev, port):
@@ -274,6 +341,7 @@ def get_console_info(devices, dev, port):
return ret_val
+
def get_mgmt_info(devices, dev, port):
for k, v in devices.items():
if k == dev:
@@ -338,15 +406,27 @@ def parse_xml(filename, hostname):
intfs = None
vlan_intfs = None
pc_intfs = None
+ vlans = None
+ pcs = None
mgmt_intf = None
lo_intf = None
neighbors = None
devices = None
+ hostname = None
+ syslog_servers = []
+ dhcp_servers = []
+ ntp_servers = []
+ mgmt_routes = []
+ bgp_peers_with_range = []
+ deployment_id = None
hwsku_qn = QName(ns, "HwSku")
+ hostname_qn = QName(ns, "Hostname")
for child in root:
if child.tag == str(hwsku_qn):
hwsku = child.text
+ if child.tag == str(hostname_qn):
+ hostname = child.text
# port_alias_map maps ngs port name to sonic port name
if hwsku == "Force10-S6000":
@@ -355,40 +435,70 @@ def parse_xml(filename, hostname):
elif hwsku == "Force10-S6100":
for i in range(0, 4):
for j in range(0, 16):
- port_alias_map["fortyGigE1/%d/%d" % (i+1, j+1)] = "Ethernet%d" % (i * 16 + j + 1)
+ port_alias_map["fortyGigE1/%d/%d" % (i+1, j+1)] = "Ethernet%d" % (i * 16 + j)
elif hwsku == "Arista-7050-QX32":
for i in range(1, 25):
port_alias_map["Ethernet%d/1" % i] = "Ethernet%d" % ((i - 1) * 4)
for i in range(25, 33):
port_alias_map["Ethernet%d" % i] = "Ethernet%d" % ((i - 1) * 4)
+ elif hwsku == "Arista-7050-QX-32S":
+ for i in range(6, 29):
+ port_alias_map["Ethernet%d/1" % i] = "Ethernet%d" % ((i - 1) * 4)
+ for i in range(1,5) + range(29, 37):
+ port_alias_map["Ethernet%d" % i] = "Ethernet%d" % ((i - 1) * 4)
else:
for i in range(0, 128, 4):
port_alias_map["Ethernet%d" % i] = "Ethernet%d" % i
for child in root:
if child.tag == str(QName(ns, "DpgDec")):
- (intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs) = parse_dpg(child, hostname)
+ (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls) = parse_dpg(child, hostname)
elif child.tag == str(QName(ns, "CpgDec")):
- (bgp_sessions, bgp_asn) = parse_cpg(child, hostname)
+ (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname)
elif child.tag == str(QName(ns, "PngDec")):
(neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname)
elif child.tag == str(QName(ns, "UngDec")):
(u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname)
-
- # Replace port with alias in Vlan interfaces members
- if vlan_intfs is not None:
- for vlan in vlan_intfs:
- for i,member in enumerate(vlan['members']):
- vlan['members'][i] = port_alias_map[member]
- # Convert vlan members into a space-delimited string
- vlan['members'] = " ".join(vlan['members'])
-
- # Replace port with alias in port channel interfaces members
- if pc_intfs is not None:
- for pc in pc_intfs:
- for i,member in enumerate(pc['members']):
- pc['members'][i] = port_alias_map[member]
-
+ elif child.tag == str(QName(ns, "MetadataDeclaration")):
+ (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, deployment_id) = parse_meta(child, hostname)
+
+ # Create port index map. Since we currently output a mix of NGS names
+ # and SONiC mapped names, we include both in this map.
+ # SONiC aliases, when sorted in natural sort order, match the phyical port
+ # index order, so we sort by SONiC port alias, and map
+ # back to NGS names after sorting using this inverted map
+ #
+ # TODO: Move all alias-related code out of minigraph_facts.py and into
+ # its own module to be used as another layer after parsing the minigraph.
+ inverted_port_alias_map = {v: k for k, v in port_alias_map.iteritems()}
+
+ # Start by creating a list of all port aliases
+ port_alias_list = []
+ for k, v in port_alias_map.iteritems():
+ port_alias_list.append(v)
+
+ # Sort the list in natural order
+ port_alias_list_sorted = natsorted(port_alias_list)
+
+ # Create map from SONiC alias to physical index and NGS name to physical index
+ port_index_map = {}
+ for idx, val in enumerate(port_alias_list_sorted):
+ port_index_map[val] = idx
+ port_index_map[inverted_port_alias_map[val]] = idx
+
+ # Create maps:
+ # from SONiC phy iface name to NGS phy iface name
+ # from NGS phy iface name to SONiC phy iface name
+ # These maps include mappings from original name to original name too
+ iface_map_sonic_to_ngs = {}
+ iface_map_ngs_to_sonic = {}
+ for val in port_alias_list_sorted:
+ iface_map_sonic_to_ngs[val] = inverted_port_alias_map[val]
+ iface_map_sonic_to_ngs[inverted_port_alias_map[val]] = inverted_port_alias_map[val]
+ iface_map_ngs_to_sonic[inverted_port_alias_map[val]] = val
+ iface_map_ngs_to_sonic[val] = val
+
+ # Generate results
Tree = lambda: defaultdict(Tree)
results = Tree()
@@ -398,25 +508,51 @@ def parse_xml(filename, hostname):
# TODO: alternatively (preferred), implement class containers for multiple-attribute entries, enabling sort by attr
results['minigraph_bgp'] = sorted(bgp_sessions, key=lambda x: x['addr'])
results['minigraph_bgp_asn'] = bgp_asn
+ results['minigraph_bgp_peers_with_range'] = bgp_peers_with_range
# TODO: sort does not work properly on all interfaces of varying lengths. Need to sort by integer group(s).
- results['minigraph_interfaces'] = sorted(intfs, key=lambda x: x['name'])
- results['minigraph_vlan_interfaces'] = vlan_intfs
- results['minigraph_portchannel_interfaces'] = pc_intfs
+
+ phyport_intfs = []
+ vlan_intfs = []
+ pc_intfs = []
+ for intf in intfs:
+ intfname = intf['attachto']
+ if intfname[0:4] == 'Vlan':
+ vlan_intfs.append(intf)
+ elif intfname[0:11] == 'PortChannel':
+ pc_intfs.append(intf)
+ else:
+ phyport_intfs.append(intf)
+
+ results['minigraph_interfaces'] = sorted(phyport_intfs, key=lambda x: x['attachto'])
+ results['minigraph_vlan_interfaces'] = sorted(vlan_intfs, key=lambda x: x['attachto'])
+ results['minigraph_portchannel_interfaces'] = sorted(pc_intfs, key=lambda x: x['attachto'])
+ results['minigraph_ports'] = ports
+ results['minigraph_vlans'] = vlans
+ results['minigraph_portchannels'] = pcs
results['minigraph_mgmt_interface'] = mgmt_intf
results['minigraph_lo_interfaces'] = lo_intfs
+ results['minigraph_acls'] = acls
results['minigraph_neighbors'] = neighbors
results['minigraph_devices'] = devices
results['minigraph_underlay_neighbors'] = u_neighbors
results['minigraph_underlay_devices'] = u_devices
- # note - this may include files under acs/ansible/minigraph, or those under the default cache folder.
- # (see ANSIBLE_USER_MINIGRAPH_PATH at the top of the module)
+ results['minigraph_port_indices'] = port_index_map
+ results['minigraph_map_sonic_to_ngs'] = iface_map_sonic_to_ngs
+ results['minigraph_map_ngs_to_sonic'] = iface_map_ngs_to_sonic
results['minigraph_as_xml'] = mini_graph_path
- results['minigraph_console'] = get_console_info(devices, console_dev, console_port)
- results['minigraph_mgmt'] = get_mgmt_info(devices, mgmt_dev, mgmt_port)
-
+ if devices != None:
+ results['minigraph_console'] = get_console_info(devices, console_dev, console_port)
+ results['minigraph_mgmt'] = get_mgmt_info(devices, mgmt_dev, mgmt_port)
+ results['minigraph_hostname'] = hostname
+ results['inventory_hostname'] = hostname
+ results['syslog_servers'] = syslog_servers
+ results['dhcp_servers'] = dhcp_servers
+ results['ntp_servers'] = ntp_servers
+ results['forced_mgmt_routes'] = mgmt_routes
+ results['deployment_id'] = deployment_id
return results
-
+ports = {}
port_alias_map = {}
def main():
@@ -462,11 +598,7 @@ def print_parse_xml(hostname):
results = parse_xml(filename, hostname)
print(json.dumps(results, indent=3, cls=minigraph_encoder))
-def debug_main():
- print_parse_xml('switch1')
-
from ansible.module_utils.basic import *
if __name__ == "__main__":
main()
- #debug_main()
diff --git a/ansible/library/port_alias.py b/ansible/library/port_alias.py
new file mode 100644
index 00000000000..18d9020a7e0
--- /dev/null
+++ b/ansible/library/port_alias.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+
+import re
+import os
+import traceback
+import subprocess
+from operator import itemgetter
+from itertools import groupby
+from collections import defaultdict
+
+DOCUMENTATION = '''
+module: port_alias.py
+Ansible_version_added: 2.0.0.2
+short_description: Find SONiC device port alias mapping if there is alias mapping
+Description:
+ Minigraph file is using SONiC deivce alias to describe the interface name, it's vendor and and hardware platform dependent
+ This module is used to find the correct port_config.ini for the hwsku and return Ansible ansible_facts.port_alias
+ The definition of this mapping is specified in http://github.com/azure/sonic-buildimage/device
+ You should build docker-sonic-mgmt from sonic-buildimage and run Ansible from sonic-mgmt docker container
+ Input:
+ hwsku
+
+ Return Ansible_facts:
+ port_alias: SONiC interface name or SONiC interface alias if alias is available
+
+'''
+
+EXAMPLES = '''
+ - name: get hardware interface name
+ port_alias: hwsku='ACS-MSN2700'
+'''
+
+### TODO: we could eventually use sonic config package to replace this port_alias module later ###############
+### Here are the expectation of files of device port_config.ini located, in case changed please modify it here
+FILE_PATH = '/usr/share/sonic/device'
+PORTMAP_FILE = 'port_config.ini'
+
+class SonicPortAliasMap():
+ """
+ Retrieve SONiC device interface port alias mapping
+
+ """
+ def __init__(self, hwsku):
+ self.filename = ''
+ self.hwsku = hwsku
+ self.portmap = []
+ return
+
+ def findfile(self):
+ for (rootdir, dirnames, filenames) in os.walk(FILE_PATH):
+ if self.hwsku in rootdir and len(dirnames) == 0 and PORTMAP_FILE in filenames:
+ self.filename = rootdir+'/'+PORTMAP_FILE
+
+ def get_portmap(self):
+ self.findfile()
+ if self.filename == '':
+ raise Exception("Something wrong when trying to find the portmap file, either the hwsku is not available or file location is not correct")
+ with open(self.filename) as f:
+ lines = f.readlines()
+ for line in lines:
+ if 'Ethernet' in line:
+ mapping = line.split()
+ if len(mapping) < 3:
+ self.portmap.append(mapping[0])
+ else:
+ self.portmap.append(mapping[2])
+ return
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ hwsku=dict(required=True, type='str')
+ ),
+ supports_check_mode=False
+ )
+ m_args = module.params
+ try:
+ allmap = SonicPortAliasMap(m_args['hwsku'])
+ allmap.get_portmap()
+ module.exit_json(ansible_facts={'port_alias': allmap.portmap})
+ except (IOError, OSError):
+ module.fail_json(msg=allmap.portmap)
+ except Exception:
+ module.fail_json(msg=allmap.portmap)
+
+from ansible.module_utils.basic import *
+if __name__ == "__main__":
+ main()
diff --git a/ansible/library/syslog_server.py b/ansible/library/syslog_server.py
deleted file mode 100644
index 9f5575b8b55..00000000000
--- a/ansible/library/syslog_server.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/python
-
-DOCUMENTATION = '''
----
-module: syslog_server
-version_added: "1.0"
-author: John Arnold (johnar@microsoft.com)
-short_description: Receive Syslog messages
-description:
- - Start a Syslog listener, receive syslog messages and return them.
-options:
-'''
-
-EXAMPLES = '''
-# Receive Syslog messages
-- name: Receive Syslog Messages
- syslog_server:
-'''
-
-from ansible.module_utils.basic import *
-from collections import defaultdict
-import socket
-import struct
-import re
-import json
-import time
-import SocketServer
-import threading
-
-
-#HOST, PORT = "0.0.0.0", 5514
-
-queuedOutput = []
-
-
-class ThreadedUDPServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer):
- pass
-
-
-class ThreadedUDPRequestHandler(SocketServer.BaseRequestHandler):
-
- def handle(self):
- data = bytes.decode(self.request[0].strip())
- socket = self.request[1]
-
- newLogString = "%s %s %s\n" % ( time.time(), self.client_address[0], data)
-
- global queuedOutput
- queuedOutput.append(newLogString)
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- timeout=dict(required=False, default=30),
- port=dict(required=False, default=5514),
- host=dict(required=False, default="0.0.0.0")
- ),
- supports_check_mode=False)
-
- args = module.params
-
- try:
- server = ThreadedUDPServer((args['host'],int(args['port'])), ThreadedUDPRequestHandler)
- server.allow_reuse_address=True
-
- server_thread = threading.Thread(target=server.serve_forever)
- server_thread.daemon = True
- server_thread.start()
-
- time.sleep(float(args['timeout']))
- server.shutdown()
-
- except Exception, e:
- module.fail_json(msg = str(e))
-
- Tree = lambda: defaultdict(Tree)
- results = Tree()
-
- global queuedOutput
- results['syslog_messages'] = queuedOutput
-
- module.exit_json(ansible_facts=results)
-
-if __name__ == "__main__":
- main()
-
diff --git a/ansible/library/testbed_vm_info.py b/ansible/library/testbed_vm_info.py
new file mode 100644
index 00000000000..c60c7c7069d
--- /dev/null
+++ b/ansible/library/testbed_vm_info.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+import re
+import yaml
+import os
+import traceback
+import subprocess
+import ipaddr as ipaddress
+from operator import itemgetter
+from itertools import groupby
+from collections import defaultdict
+
+DOCUMENTATION = '''
+module: testbed_vm_info.py
+Ansible_version_added: 2.0.0.2
+short_description: Gather all related VMs info
+Description:
+ When deploy testbed topology with VM connected to SONiC, gather neighbor VMs info for generating SONiC minigraph file
+ options:
+ base_vm: base vm name defined in testbed.csv for the deployed topology; required: True
+ topo: topology name defined in testbed.csv for the deployed topology; required: True
+
+Ansible_facts:
+ 'neighbor_eosvm_mgmt': all VM hosts management IPs
+ 'topoall': topology information
+
+'''
+
+EXAMPLES = '''
+ - name: gather vm information
+ testbed_vm_info: base_vm='VM0100' topo='t1'
+'''
+
+### Here are the assumption/expectation of files to gather VM informations, if the file location or name changes, please modify it here
+TOPO_PATH = 'vars/'
+VM_INV_FILE = 'veos'
+
+
+class TestbedVMFacts():
+ """
+ Retrieve testbed VMs management information that for a specified toplogy defined in testbed.csv
+
+ """
+
+ def __init__(self, toponame, vmbase):
+ self.topofile = TOPO_PATH+'topo_'+toponame +'.yml'
+ self.start_index = int(re.findall('VM(\d+)', vmbase)[0])
+ self.vmhosts = {}
+ return
+
+
+ def get_neighbor_eos(self):
+ eos = {}
+ with open(self.topofile) as f:
+ vm_topology = yaml.load(f)
+ self.topoall = vm_topology
+ for vm in vm_topology['topology']['VMs']:
+ vm_index = int(vm_topology['topology']['VMs'][vm]['vm_offset'])+self.start_index
+ eos[vm] = vm_index
+ return eos
+
+
+ def gather_veos_vms(self):
+ vms = {}
+ with open(VM_INV_FILE) as f:
+ lines = f.readlines()
+ for line in lines:
+ if 'VM' in line and 'ansible_host' in line:
+ items = line.split()
+ vms[items[0]] = items[1].split('=')[1]
+ return vms
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ base_vm=dict(required=True, type='str'),
+ topo=dict(required=True, type='str'),
+ ),
+ supports_check_mode=False
+ )
+ m_args = module.params
+ topo_type = m_args['topo']
+ if 'ptf' in topo_type:
+ module.exit_json(ansible_facts={'neighbor_eosvm_mgmt': {}})
+ try:
+ vmsall = TestbedVMFacts(m_args['topo'], m_args['base_vm'])
+ neighbor_eos = vmsall.get_neighbor_eos()
+ vm_inv = vmsall.gather_veos_vms()
+ for eos in neighbor_eos:
+ vmname = 'VM'+format(neighbor_eos[eos], '04d')
+ if vmname in vm_inv:
+ vmsall.vmhosts[eos] = vm_inv[vmname]
+ else:
+ err_msg = "cannot find the vm " + vmname + " in VM inventory file, please make sure you have enough VMs for the topology you are using"
+ module.fail_json(msg=err_msg)
+ module.exit_json(ansible_facts={'neighbor_eosvm_mgmt':vmsall.vmhosts, 'topoall': vmsall.topoall})
+ except (IOError, OSError):
+ module.fail_json(msg="Can not find file "+vmsall.topofile+" or "+VM_INV_FILE)
+ except Exception as e:
+ module.fail_json(msg=traceback.format_exc())
+
+from ansible.module_utils.basic import *
+if __name__ == "__main__":
+ main()
+
diff --git a/ansible/minigraph/01-ARISTA01T0.xml b/ansible/minigraph/01-ARISTA01T0.xml
deleted file mode 100644
index f9948c732f9..00000000000
--- a/ansible/minigraph/01-ARISTA01T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T0
- 10.0.0.33
- str-s6000-on-3
- 10.0.0.32
- 1
- 180
- 60
-
-
- ARISTA01T0
- FC00::42
- str-s6000-on-3
- FC00::41
- 1
- 180
- 60
-
-
-
-
- 64001
- ARISTA01T0
-
-
- 10.0.0.32
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.17/32
-
- 100.1.0.17/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::11/128
-
- 2064:0100::11/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.222/24
-
- 10.255.0.222/24
-
-
-
-
-
- ARISTA01T0
-
-
-
-
-
- Ethernet1
- 10.0.0.33/31
-
-
-
- Ethernet1
- FC00::42/126
-
-
-
- Ethernet9
- 10.10.246.17/24
-
-
-
- Ethernet9
- FC0A::22/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA01T2.xml b/ansible/minigraph/01-ARISTA01T2.xml
deleted file mode 100644
index b75de055192..00000000000
--- a/ansible/minigraph/01-ARISTA01T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T2
- 10.0.0.1
- str-s6000-on-3
- 10.0.0.0
- 1
- 180
- 60
-
-
- ARISTA01T2
- FC00::2
- str-s6000-on-3
- FC00::1
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA01T2
-
-
- 10.0.0.0
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.1/32
-
- 100.1.0.1/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1/128
-
- 2064:0100::1/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.238/24
-
- 10.255.0.238/24
-
-
-
-
-
- ARISTA01T2
-
-
-
-
-
- Ethernet1
- 10.0.0.1/31
-
-
-
- Ethernet1
- FC00::2/126
-
-
-
- Ethernet9
- 10.10.246.1/24
-
-
-
- Ethernet9
- FC0A::2/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA02T0.xml b/ansible/minigraph/01-ARISTA02T0.xml
deleted file mode 100644
index 6740346a232..00000000000
--- a/ansible/minigraph/01-ARISTA02T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T0
- 10.0.0.35
- str-s6000-on-3
- 10.0.0.34
- 1
- 180
- 60
-
-
- ARISTA02T0
- FC00::46
- str-s6000-on-3
- FC00::45
- 1
- 180
- 60
-
-
-
-
- 64002
- ARISTA02T0
-
-
- 10.0.0.34
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.18/32
-
- 100.1.0.18/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::12/128
-
- 2064:0100::12/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.223/24
-
- 10.255.0.223/24
-
-
-
-
-
- ARISTA02T0
-
-
-
-
-
- Ethernet1
- 10.0.0.35/31
-
-
-
- Ethernet1
- FC00::46/126
-
-
-
- Ethernet9
- 10.10.246.18/24
-
-
-
- Ethernet9
- FC0A::25/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA02T2.xml b/ansible/minigraph/01-ARISTA02T2.xml
deleted file mode 100644
index f17240c8403..00000000000
--- a/ansible/minigraph/01-ARISTA02T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T2
- 10.0.0.3
- str-s6000-on-3
- 10.0.0.2
- 1
- 180
- 60
-
-
- ARISTA02T2
- FC00::6
- str-s6000-on-3
- FC00::5
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA02T2
-
-
- 10.0.0.2
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.2/32
-
- 100.1.0.2/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::2/128
-
- 2064:0100::2/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.239/24
-
- 10.255.0.239/24
-
-
-
-
-
- ARISTA02T2
-
-
-
-
-
- Ethernet1
- 10.0.0.3/31
-
-
-
- Ethernet1
- FC00::6/126
-
-
-
- Ethernet9
- 10.10.246.2/24
-
-
-
- Ethernet9
- FC0A::5/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA03T0.xml b/ansible/minigraph/01-ARISTA03T0.xml
deleted file mode 100644
index 13af212f7e6..00000000000
--- a/ansible/minigraph/01-ARISTA03T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T0
- 10.0.0.37
- str-s6000-on-3
- 10.0.0.36
- 1
- 180
- 60
-
-
- ARISTA03T0
- FC00::4A
- str-s6000-on-3
- FC00::49
- 1
- 180
- 60
-
-
-
-
- 64003
- ARISTA03T0
-
-
- 10.0.0.36
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.19/32
-
- 100.1.0.19/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::13/128
-
- 2064:0100::13/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.224/24
-
- 10.255.0.224/24
-
-
-
-
-
- ARISTA03T0
-
-
-
-
-
- Ethernet1
- 10.0.0.37/31
-
-
-
- Ethernet1
- FC00::4A/126
-
-
-
- Ethernet9
- 10.10.246.19/24
-
-
-
- Ethernet9
- FC0A::26/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA03T2.xml b/ansible/minigraph/01-ARISTA03T2.xml
deleted file mode 100644
index 47c48bb358f..00000000000
--- a/ansible/minigraph/01-ARISTA03T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T2
- 10.0.0.5
- str-s6000-on-3
- 10.0.0.4
- 1
- 180
- 60
-
-
- ARISTA03T2
- FC00::A
- str-s6000-on-3
- FC00::9
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA03T2
-
-
- 10.0.0.4
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.3/32
-
- 100.1.0.3/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::3/128
-
- 2064:0100::3/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.240/24
-
- 10.255.0.240/24
-
-
-
-
-
- ARISTA03T2
-
-
-
-
-
- Ethernet1
- 10.0.0.5/31
-
-
-
- Ethernet1
- FC00::A/126
-
-
-
- Ethernet9
- 10.10.246.3/24
-
-
-
- Ethernet9
- FC0A::6/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA04T0.xml b/ansible/minigraph/01-ARISTA04T0.xml
deleted file mode 100644
index 72ef38df383..00000000000
--- a/ansible/minigraph/01-ARISTA04T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T0
- 10.0.0.39
- str-s6000-on-3
- 10.0.0.38
- 1
- 180
- 60
-
-
- ARISTA04T0
- FC00::4E
- str-s6000-on-3
- FC00::4D
- 1
- 180
- 60
-
-
-
-
- 64004
- ARISTA04T0
-
-
- 10.0.0.38
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.20/32
-
- 100.1.0.20/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::14/128
-
- 2064:0100::14/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.225/24
-
- 10.255.0.225/24
-
-
-
-
-
- ARISTA04T0
-
-
-
-
-
- Ethernet1
- 10.0.0.39/31
-
-
-
- Ethernet1
- FC00::4E/126
-
-
-
- Ethernet9
- 10.10.246.20/24
-
-
-
- Ethernet9
- FC0A::29/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA04T2.xml b/ansible/minigraph/01-ARISTA04T2.xml
deleted file mode 100644
index 868edbce67c..00000000000
--- a/ansible/minigraph/01-ARISTA04T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T2
- 10.0.0.7
- str-s6000-on-3
- 10.0.0.6
- 1
- 180
- 60
-
-
- ARISTA04T2
- FC00::E
- str-s6000-on-3
- FC00::D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA04T2
-
-
- 10.0.0.6
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.4/32
-
- 100.1.0.4/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::4/128
-
- 2064:0100::4/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.241/24
-
- 10.255.0.241/24
-
-
-
-
-
- ARISTA04T2
-
-
-
-
-
- Ethernet1
- 10.0.0.7/31
-
-
-
- Ethernet1
- FC00::E/126
-
-
-
- Ethernet9
- 10.10.246.4/24
-
-
-
- Ethernet9
- FC0A::9/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA05T0.xml b/ansible/minigraph/01-ARISTA05T0.xml
deleted file mode 100644
index 97160706e1c..00000000000
--- a/ansible/minigraph/01-ARISTA05T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T0
- 10.0.0.41
- str-s6000-on-3
- 10.0.0.40
- 1
- 180
- 60
-
-
- ARISTA05T0
- FC00::52
- str-s6000-on-3
- FC00::51
- 1
- 180
- 60
-
-
-
-
- 64005
- ARISTA05T0
-
-
- 10.0.0.40
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.21/32
-
- 100.1.0.21/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::15/128
-
- 2064:0100::15/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.226/24
-
- 10.255.0.226/24
-
-
-
-
-
- ARISTA05T0
-
-
-
-
-
- Ethernet1
- 10.0.0.41/31
-
-
-
- Ethernet1
- FC00::52/126
-
-
-
- Ethernet9
- 10.10.246.21/24
-
-
-
- Ethernet9
- FC0A::2A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA05T2.xml b/ansible/minigraph/01-ARISTA05T2.xml
deleted file mode 100644
index f461ebf39c1..00000000000
--- a/ansible/minigraph/01-ARISTA05T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T2
- 10.0.0.9
- str-s6000-on-3
- 10.0.0.8
- 1
- 180
- 60
-
-
- ARISTA05T2
- FC00::12
- str-s6000-on-3
- FC00::11
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA05T2
-
-
- 10.0.0.8
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.5/32
-
- 100.1.0.5/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::5/128
-
- 2064:0100::5/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.242/24
-
- 10.255.0.242/24
-
-
-
-
-
- ARISTA05T2
-
-
-
-
-
- Ethernet1
- 10.0.0.9/31
-
-
-
- Ethernet1
- FC00::12/126
-
-
-
- Ethernet9
- 10.10.246.5/24
-
-
-
- Ethernet9
- FC0A::A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA06T0.xml b/ansible/minigraph/01-ARISTA06T0.xml
deleted file mode 100644
index 70fe6a31633..00000000000
--- a/ansible/minigraph/01-ARISTA06T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T0
- 10.0.0.43
- str-s6000-on-3
- 10.0.0.42
- 1
- 180
- 60
-
-
- ARISTA06T0
- FC00::56
- str-s6000-on-3
- FC00::55
- 1
- 180
- 60
-
-
-
-
- 64006
- ARISTA06T0
-
-
- 10.0.0.42
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.22/32
-
- 100.1.0.22/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::16/128
-
- 2064:0100::16/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.227/24
-
- 10.255.0.227/24
-
-
-
-
-
- ARISTA06T0
-
-
-
-
-
- Ethernet1
- 10.0.0.43/31
-
-
-
- Ethernet1
- FC00::56/126
-
-
-
- Ethernet9
- 10.10.246.22/24
-
-
-
- Ethernet9
- FC0A::2D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA06T2.xml b/ansible/minigraph/01-ARISTA06T2.xml
deleted file mode 100644
index cbbf049d171..00000000000
--- a/ansible/minigraph/01-ARISTA06T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T2
- 10.0.0.11
- str-s6000-on-3
- 10.0.0.10
- 1
- 180
- 60
-
-
- ARISTA06T2
- FC00::16
- str-s6000-on-3
- FC00::15
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA06T2
-
-
- 10.0.0.10
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.6/32
-
- 100.1.0.6/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::6/128
-
- 2064:0100::6/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.243/24
-
- 10.255.0.243/24
-
-
-
-
-
- ARISTA06T2
-
-
-
-
-
- Ethernet1
- 10.0.0.11/31
-
-
-
- Ethernet1
- FC00::16/126
-
-
-
- Ethernet9
- 10.10.246.6/24
-
-
-
- Ethernet9
- FC0A::D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA07T0.xml b/ansible/minigraph/01-ARISTA07T0.xml
deleted file mode 100644
index faef0d0e140..00000000000
--- a/ansible/minigraph/01-ARISTA07T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T0
- 10.0.0.45
- str-s6000-on-3
- 10.0.0.44
- 1
- 180
- 60
-
-
- ARISTA07T0
- FC00::5A
- str-s6000-on-3
- FC00::59
- 1
- 180
- 60
-
-
-
-
- 64007
- ARISTA07T0
-
-
- 10.0.0.44
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.23/32
-
- 100.1.0.23/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::17/128
-
- 2064:0100::17/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.228/24
-
- 10.255.0.228/24
-
-
-
-
-
- ARISTA07T0
-
-
-
-
-
- Ethernet1
- 10.0.0.45/31
-
-
-
- Ethernet1
- FC00::5A/126
-
-
-
- Ethernet9
- 10.10.246.23/24
-
-
-
- Ethernet9
- FC0A::2E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA07T2.xml b/ansible/minigraph/01-ARISTA07T2.xml
deleted file mode 100644
index 18c93018ceb..00000000000
--- a/ansible/minigraph/01-ARISTA07T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T2
- 10.0.0.13
- str-s6000-on-3
- 10.0.0.12
- 1
- 180
- 60
-
-
- ARISTA07T2
- FC00::1A
- str-s6000-on-3
- FC00::19
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA07T2
-
-
- 10.0.0.12
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.7/32
-
- 100.1.0.7/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::7/128
-
- 2064:0100::7/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.244/24
-
- 10.255.0.244/24
-
-
-
-
-
- ARISTA07T2
-
-
-
-
-
- Ethernet1
- 10.0.0.13/31
-
-
-
- Ethernet1
- FC00::1A/126
-
-
-
- Ethernet9
- 10.10.246.7/24
-
-
-
- Ethernet9
- FC0A::E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA08T0.xml b/ansible/minigraph/01-ARISTA08T0.xml
deleted file mode 100644
index 8ea962c7c54..00000000000
--- a/ansible/minigraph/01-ARISTA08T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T0
- 10.0.0.47
- str-s6000-on-3
- 10.0.0.46
- 1
- 180
- 60
-
-
- ARISTA08T0
- FC00::5E
- str-s6000-on-3
- FC00::5D
- 1
- 180
- 60
-
-
-
-
- 64008
- ARISTA08T0
-
-
- 10.0.0.46
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.24/32
-
- 100.1.0.24/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::18/128
-
- 2064:0100::18/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.229/24
-
- 10.255.0.229/24
-
-
-
-
-
- ARISTA08T0
-
-
-
-
-
- Ethernet1
- 10.0.0.47/31
-
-
-
- Ethernet1
- FC00::5E/126
-
-
-
- Ethernet9
- 10.10.246.24/24
-
-
-
- Ethernet9
- FC0A::31/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA08T2.xml b/ansible/minigraph/01-ARISTA08T2.xml
deleted file mode 100644
index 55ff3aa0eaf..00000000000
--- a/ansible/minigraph/01-ARISTA08T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T2
- 10.0.0.15
- str-s6000-on-3
- 10.0.0.14
- 1
- 180
- 60
-
-
- ARISTA08T2
- FC00::1E
- str-s6000-on-3
- FC00::1D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA08T2
-
-
- 10.0.0.14
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.8/32
-
- 100.1.0.8/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::8/128
-
- 2064:0100::8/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.245/24
-
- 10.255.0.245/24
-
-
-
-
-
- ARISTA08T2
-
-
-
-
-
- Ethernet1
- 10.0.0.15/31
-
-
-
- Ethernet1
- FC00::1E/126
-
-
-
- Ethernet9
- 10.10.246.8/24
-
-
-
- Ethernet9
- FC0A::11/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA09T0.xml b/ansible/minigraph/01-ARISTA09T0.xml
deleted file mode 100644
index 3c4114d563f..00000000000
--- a/ansible/minigraph/01-ARISTA09T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T0
- 10.0.0.49
- str-s6000-on-3
- 10.0.0.48
- 1
- 180
- 60
-
-
- ARISTA09T0
- FC00::62
- str-s6000-on-3
- FC00::61
- 1
- 180
- 60
-
-
-
-
- 64009
- ARISTA09T0
-
-
- 10.0.0.48
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.25/32
-
- 100.1.0.25/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::19/128
-
- 2064:0100::19/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.230/24
-
- 10.255.0.230/24
-
-
-
-
-
- ARISTA09T0
-
-
-
-
-
- Ethernet1
- 10.0.0.49/31
-
-
-
- Ethernet1
- FC00::62/126
-
-
-
- Ethernet9
- 10.10.246.25/24
-
-
-
- Ethernet9
- FC0A::32/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA09T2.xml b/ansible/minigraph/01-ARISTA09T2.xml
deleted file mode 100644
index 3e5cc14f895..00000000000
--- a/ansible/minigraph/01-ARISTA09T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T2
- 10.0.0.17
- str-s6000-on-3
- 10.0.0.16
- 1
- 180
- 60
-
-
- ARISTA09T2
- FC00::22
- str-s6000-on-3
- FC00::21
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA09T2
-
-
- 10.0.0.16
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.9/32
-
- 100.1.0.9/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::9/128
-
- 2064:0100::9/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.246/24
-
- 10.255.0.246/24
-
-
-
-
-
- ARISTA09T2
-
-
-
-
-
- Ethernet1
- 10.0.0.17/31
-
-
-
- Ethernet1
- FC00::22/126
-
-
-
- Ethernet9
- 10.10.246.9/24
-
-
-
- Ethernet9
- FC0A::12/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA10T0.xml b/ansible/minigraph/01-ARISTA10T0.xml
deleted file mode 100644
index 7060efce32d..00000000000
--- a/ansible/minigraph/01-ARISTA10T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T0
- 10.0.0.51
- str-s6000-on-3
- 10.0.0.50
- 1
- 180
- 60
-
-
- ARISTA10T0
- FC00::66
- str-s6000-on-3
- FC00::65
- 1
- 180
- 60
-
-
-
-
- 64010
- ARISTA10T0
-
-
- 10.0.0.50
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.26/32
-
- 100.1.0.26/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1A/128
-
- 2064:0100::1A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.231/24
-
- 10.255.0.231/24
-
-
-
-
-
- ARISTA10T0
-
-
-
-
-
- Ethernet1
- 10.0.0.51/31
-
-
-
- Ethernet1
- FC00::66/126
-
-
-
- Ethernet9
- 10.10.246.26/24
-
-
-
- Ethernet9
- FC0A::35/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA10T2.xml b/ansible/minigraph/01-ARISTA10T2.xml
deleted file mode 100644
index f4aa16798df..00000000000
--- a/ansible/minigraph/01-ARISTA10T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T2
- 10.0.0.19
- str-s6000-on-3
- 10.0.0.18
- 1
- 180
- 60
-
-
- ARISTA10T2
- FC00::26
- str-s6000-on-3
- FC00::25
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA10T2
-
-
- 10.0.0.18
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.10/32
-
- 100.1.0.10/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::A/128
-
- 2064:0100::A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.247/24
-
- 10.255.0.247/24
-
-
-
-
-
- ARISTA10T2
-
-
-
-
-
- Ethernet1
- 10.0.0.19/31
-
-
-
- Ethernet1
- FC00::26/126
-
-
-
- Ethernet9
- 10.10.246.10/24
-
-
-
- Ethernet9
- FC0A::15/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA11T0.xml b/ansible/minigraph/01-ARISTA11T0.xml
deleted file mode 100644
index a6f3e9cabda..00000000000
--- a/ansible/minigraph/01-ARISTA11T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T0
- 10.0.0.53
- str-s6000-on-3
- 10.0.0.52
- 1
- 180
- 60
-
-
- ARISTA11T0
- FC00::6A
- str-s6000-on-3
- FC00::69
- 1
- 180
- 60
-
-
-
-
- 64011
- ARISTA11T0
-
-
- 10.0.0.52
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.27/32
-
- 100.1.0.27/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1B/128
-
- 2064:0100::1B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.232/24
-
- 10.255.0.232/24
-
-
-
-
-
- ARISTA11T0
-
-
-
-
-
- Ethernet1
- 10.0.0.53/31
-
-
-
- Ethernet1
- FC00::6A/126
-
-
-
- Ethernet9
- 10.10.246.27/24
-
-
-
- Ethernet9
- FC0A::36/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA11T2.xml b/ansible/minigraph/01-ARISTA11T2.xml
deleted file mode 100644
index 0cf377bb155..00000000000
--- a/ansible/minigraph/01-ARISTA11T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T2
- 10.0.0.21
- str-s6000-on-3
- 10.0.0.20
- 1
- 180
- 60
-
-
- ARISTA11T2
- FC00::2A
- str-s6000-on-3
- FC00::29
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA11T2
-
-
- 10.0.0.20
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.11/32
-
- 100.1.0.11/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::B/128
-
- 2064:0100::B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.248/24
-
- 10.255.0.248/24
-
-
-
-
-
- ARISTA11T2
-
-
-
-
-
- Ethernet1
- 10.0.0.21/31
-
-
-
- Ethernet1
- FC00::2A/126
-
-
-
- Ethernet9
- 10.10.246.11/24
-
-
-
- Ethernet9
- FC0A::16/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA12T0.xml b/ansible/minigraph/01-ARISTA12T0.xml
deleted file mode 100644
index 8081a78c1a9..00000000000
--- a/ansible/minigraph/01-ARISTA12T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T0
- 10.0.0.55
- str-s6000-on-3
- 10.0.0.54
- 1
- 180
- 60
-
-
- ARISTA12T0
- FC00::6E
- str-s6000-on-3
- FC00::6D
- 1
- 180
- 60
-
-
-
-
- 64012
- ARISTA12T0
-
-
- 10.0.0.54
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.28/32
-
- 100.1.0.28/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1C/128
-
- 2064:0100::1C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.233/24
-
- 10.255.0.233/24
-
-
-
-
-
- ARISTA12T0
-
-
-
-
-
- Ethernet1
- 10.0.0.55/31
-
-
-
- Ethernet1
- FC00::6E/126
-
-
-
- Ethernet9
- 10.10.246.28/24
-
-
-
- Ethernet9
- FC0A::39/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA12T2.xml b/ansible/minigraph/01-ARISTA12T2.xml
deleted file mode 100644
index 4ee77ff7605..00000000000
--- a/ansible/minigraph/01-ARISTA12T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T2
- 10.0.0.23
- str-s6000-on-3
- 10.0.0.22
- 1
- 180
- 60
-
-
- ARISTA12T2
- FC00::2E
- str-s6000-on-3
- FC00::2D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA12T2
-
-
- 10.0.0.22
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.12/32
-
- 100.1.0.12/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::C/128
-
- 2064:0100::C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.249/24
-
- 10.255.0.249/24
-
-
-
-
-
- ARISTA12T2
-
-
-
-
-
- Ethernet1
- 10.0.0.23/31
-
-
-
- Ethernet1
- FC00::2E/126
-
-
-
- Ethernet9
- 10.10.246.12/24
-
-
-
- Ethernet9
- FC0A::19/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA13T0.xml b/ansible/minigraph/01-ARISTA13T0.xml
deleted file mode 100644
index 62f164d280a..00000000000
--- a/ansible/minigraph/01-ARISTA13T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T0
- 10.0.0.57
- str-s6000-on-3
- 10.0.0.56
- 1
- 180
- 60
-
-
- ARISTA13T0
- FC00::72
- str-s6000-on-3
- FC00::71
- 1
- 180
- 60
-
-
-
-
- 64013
- ARISTA13T0
-
-
- 10.0.0.56
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.29/32
-
- 100.1.0.29/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1D/128
-
- 2064:0100::1D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.234/24
-
- 10.255.0.234/24
-
-
-
-
-
- ARISTA13T0
-
-
-
-
-
- Ethernet1
- 10.0.0.57/31
-
-
-
- Ethernet1
- FC00::72/126
-
-
-
- Ethernet9
- 10.10.246.29/24
-
-
-
- Ethernet9
- FC0A::3A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA13T2.xml b/ansible/minigraph/01-ARISTA13T2.xml
deleted file mode 100644
index 87f5470afee..00000000000
--- a/ansible/minigraph/01-ARISTA13T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T2
- 10.0.0.25
- str-s6000-on-3
- 10.0.0.24
- 1
- 180
- 60
-
-
- ARISTA13T2
- FC00::32
- str-s6000-on-3
- FC00::31
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA13T2
-
-
- 10.0.0.24
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.13/32
-
- 100.1.0.13/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::D/128
-
- 2064:0100::D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.250/24
-
- 10.255.0.250/24
-
-
-
-
-
- ARISTA13T2
-
-
-
-
-
- Ethernet1
- 10.0.0.25/31
-
-
-
- Ethernet1
- FC00::32/126
-
-
-
- Ethernet9
- 10.10.246.13/24
-
-
-
- Ethernet9
- FC0A::1A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA14T0.xml b/ansible/minigraph/01-ARISTA14T0.xml
deleted file mode 100644
index eff74232578..00000000000
--- a/ansible/minigraph/01-ARISTA14T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T0
- 10.0.0.59
- str-s6000-on-3
- 10.0.0.58
- 1
- 180
- 60
-
-
- ARISTA14T0
- FC00::76
- str-s6000-on-3
- FC00::75
- 1
- 180
- 60
-
-
-
-
- 64014
- ARISTA14T0
-
-
- 10.0.0.58
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.30/32
-
- 100.1.0.30/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1E/128
-
- 2064:0100::1E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.235/24
-
- 10.255.0.235/24
-
-
-
-
-
- ARISTA14T0
-
-
-
-
-
- Ethernet1
- 10.0.0.59/31
-
-
-
- Ethernet1
- FC00::76/126
-
-
-
- Ethernet9
- 10.10.246.30/24
-
-
-
- Ethernet9
- FC0A::3D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA14T2.xml b/ansible/minigraph/01-ARISTA14T2.xml
deleted file mode 100644
index 07bc655f7cf..00000000000
--- a/ansible/minigraph/01-ARISTA14T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T2
- 10.0.0.27
- str-s6000-on-3
- 10.0.0.26
- 1
- 180
- 60
-
-
- ARISTA14T2
- FC00::36
- str-s6000-on-3
- FC00::35
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA14T2
-
-
- 10.0.0.26
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.14/32
-
- 100.1.0.14/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::E/128
-
- 2064:0100::E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.251/24
-
- 10.255.0.251/24
-
-
-
-
-
- ARISTA14T2
-
-
-
-
-
- Ethernet1
- 10.0.0.27/31
-
-
-
- Ethernet1
- FC00::36/126
-
-
-
- Ethernet9
- 10.10.246.14/24
-
-
-
- Ethernet9
- FC0A::1D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA15T0.xml b/ansible/minigraph/01-ARISTA15T0.xml
deleted file mode 100644
index 0d889ab2353..00000000000
--- a/ansible/minigraph/01-ARISTA15T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T0
- 10.0.0.61
- str-s6000-on-3
- 10.0.0.60
- 1
- 180
- 60
-
-
- ARISTA15T0
- FC00::7A
- str-s6000-on-3
- FC00::79
- 1
- 180
- 60
-
-
-
-
- 64015
- ARISTA15T0
-
-
- 10.0.0.60
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.31/32
-
- 100.1.0.31/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1F/128
-
- 2064:0100::1F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.236/24
-
- 10.255.0.236/24
-
-
-
-
-
- ARISTA15T0
-
-
-
-
-
- Ethernet1
- 10.0.0.61/31
-
-
-
- Ethernet1
- FC00::7A/126
-
-
-
- Ethernet9
- 10.10.246.31/24
-
-
-
- Ethernet9
- FC0A::3E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA15T2.xml b/ansible/minigraph/01-ARISTA15T2.xml
deleted file mode 100644
index 5f24170a6fa..00000000000
--- a/ansible/minigraph/01-ARISTA15T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T2
- 10.0.0.29
- str-s6000-on-3
- 10.0.0.28
- 1
- 180
- 60
-
-
- ARISTA15T2
- FC00::3A
- str-s6000-on-3
- FC00::39
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA15T2
-
-
- 10.0.0.28
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.15/32
-
- 100.1.0.15/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::F/128
-
- 2064:0100::F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.252/24
-
- 10.255.0.252/24
-
-
-
-
-
- ARISTA15T2
-
-
-
-
-
- Ethernet1
- 10.0.0.29/31
-
-
-
- Ethernet1
- FC00::3A/126
-
-
-
- Ethernet9
- 10.10.246.15/24
-
-
-
- Ethernet9
- FC0A::1E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA16T0.xml b/ansible/minigraph/01-ARISTA16T0.xml
deleted file mode 100644
index 850d2a13d37..00000000000
--- a/ansible/minigraph/01-ARISTA16T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T0
- 10.0.0.63
- str-s6000-on-3
- 10.0.0.62
- 1
- 180
- 60
-
-
- ARISTA16T0
- FC00::7E
- str-s6000-on-3
- FC00::7D
- 1
- 180
- 60
-
-
-
-
- 64016
- ARISTA16T0
-
-
- 10.0.0.62
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.32/32
-
- 100.1.0.32/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::20/128
-
- 2064:0100::20/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.237/24
-
- 10.255.0.237/24
-
-
-
-
-
- ARISTA16T0
-
-
-
-
-
- Ethernet1
- 10.0.0.63/31
-
-
-
- Ethernet1
- FC00::7E/126
-
-
-
- Ethernet9
- 10.10.246.32/24
-
-
-
- Ethernet9
- FC0A::41/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/01-ARISTA16T2.xml b/ansible/minigraph/01-ARISTA16T2.xml
deleted file mode 100644
index 85f5ea46616..00000000000
--- a/ansible/minigraph/01-ARISTA16T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T2
- 10.0.0.31
- str-s6000-on-3
- 10.0.0.30
- 1
- 180
- 60
-
-
- ARISTA16T2
- FC00::3E
- str-s6000-on-3
- FC00::3D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA16T2
-
-
- 10.0.0.30
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.16/32
-
- 100.1.0.16/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::10/128
-
- 2064:0100::10/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.253/24
-
- 10.255.0.253/24
-
-
-
-
-
- ARISTA16T2
-
-
-
-
-
- Ethernet1
- 10.0.0.31/31
-
-
-
- Ethernet1
- FC00::3E/126
-
-
-
- Ethernet9
- 10.10.246.16/24
-
-
-
- Ethernet9
- FC0A::21/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA01T0.xml b/ansible/minigraph/02-ARISTA01T0.xml
deleted file mode 100644
index d7bacb07e6a..00000000000
--- a/ansible/minigraph/02-ARISTA01T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T0
- 10.0.0.33
- str-s6000-on-3
- 10.0.0.32
- 1
- 180
- 60
-
-
- ARISTA01T0
- FC00::42
- str-s6000-on-3
- FC00::41
- 1
- 180
- 60
-
-
-
-
- 64001
- ARISTA01T0
-
-
- 10.0.0.32
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.17/32
-
- 100.1.0.17/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::11/128
-
- 2064:0100::11/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.190/24
-
- 10.255.0.190/24
-
-
-
-
-
- ARISTA01T0
-
-
-
-
-
- Ethernet1
- 10.0.0.33/31
-
-
-
- Ethernet1
- FC00::42/126
-
-
-
- Ethernet9
- 10.10.246.17/24
-
-
-
- Ethernet9
- FC0A::22/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA01T2.xml b/ansible/minigraph/02-ARISTA01T2.xml
deleted file mode 100644
index 977d15c6055..00000000000
--- a/ansible/minigraph/02-ARISTA01T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T2
- 10.0.0.1
- str-s6000-on-3
- 10.0.0.0
- 1
- 180
- 60
-
-
- ARISTA01T2
- FC00::2
- str-s6000-on-3
- FC00::1
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA01T2
-
-
- 10.0.0.0
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.1/32
-
- 100.1.0.1/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1/128
-
- 2064:0100::1/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.206/24
-
- 10.255.0.206/24
-
-
-
-
-
- ARISTA01T2
-
-
-
-
-
- Ethernet1
- 10.0.0.1/31
-
-
-
- Ethernet1
- FC00::2/126
-
-
-
- Ethernet9
- 10.10.246.1/24
-
-
-
- Ethernet9
- FC0A::2/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA02T0.xml b/ansible/minigraph/02-ARISTA02T0.xml
deleted file mode 100644
index 4d82b243eb0..00000000000
--- a/ansible/minigraph/02-ARISTA02T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T0
- 10.0.0.35
- str-s6000-on-3
- 10.0.0.34
- 1
- 180
- 60
-
-
- ARISTA02T0
- FC00::46
- str-s6000-on-3
- FC00::45
- 1
- 180
- 60
-
-
-
-
- 64002
- ARISTA02T0
-
-
- 10.0.0.34
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.18/32
-
- 100.1.0.18/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::12/128
-
- 2064:0100::12/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.191/24
-
- 10.255.0.191/24
-
-
-
-
-
- ARISTA02T0
-
-
-
-
-
- Ethernet1
- 10.0.0.35/31
-
-
-
- Ethernet1
- FC00::46/126
-
-
-
- Ethernet9
- 10.10.246.18/24
-
-
-
- Ethernet9
- FC0A::25/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA02T2.xml b/ansible/minigraph/02-ARISTA02T2.xml
deleted file mode 100644
index 1e162a3f28a..00000000000
--- a/ansible/minigraph/02-ARISTA02T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T2
- 10.0.0.3
- str-s6000-on-3
- 10.0.0.2
- 1
- 180
- 60
-
-
- ARISTA02T2
- FC00::6
- str-s6000-on-3
- FC00::5
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA02T2
-
-
- 10.0.0.2
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.2/32
-
- 100.1.0.2/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::2/128
-
- 2064:0100::2/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.207/24
-
- 10.255.0.207/24
-
-
-
-
-
- ARISTA02T2
-
-
-
-
-
- Ethernet1
- 10.0.0.3/31
-
-
-
- Ethernet1
- FC00::6/126
-
-
-
- Ethernet9
- 10.10.246.2/24
-
-
-
- Ethernet9
- FC0A::5/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA03T0.xml b/ansible/minigraph/02-ARISTA03T0.xml
deleted file mode 100644
index 64f95e76c36..00000000000
--- a/ansible/minigraph/02-ARISTA03T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T0
- 10.0.0.37
- str-s6000-on-3
- 10.0.0.36
- 1
- 180
- 60
-
-
- ARISTA03T0
- FC00::4A
- str-s6000-on-3
- FC00::49
- 1
- 180
- 60
-
-
-
-
- 64003
- ARISTA03T0
-
-
- 10.0.0.36
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.19/32
-
- 100.1.0.19/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::13/128
-
- 2064:0100::13/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.192/24
-
- 10.255.0.192/24
-
-
-
-
-
- ARISTA03T0
-
-
-
-
-
- Ethernet1
- 10.0.0.37/31
-
-
-
- Ethernet1
- FC00::4A/126
-
-
-
- Ethernet9
- 10.10.246.19/24
-
-
-
- Ethernet9
- FC0A::26/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA03T2.xml b/ansible/minigraph/02-ARISTA03T2.xml
deleted file mode 100644
index ec38fbbade6..00000000000
--- a/ansible/minigraph/02-ARISTA03T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T2
- 10.0.0.5
- str-s6000-on-3
- 10.0.0.4
- 1
- 180
- 60
-
-
- ARISTA03T2
- FC00::A
- str-s6000-on-3
- FC00::9
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA03T2
-
-
- 10.0.0.4
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.3/32
-
- 100.1.0.3/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::3/128
-
- 2064:0100::3/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.208/24
-
- 10.255.0.208/24
-
-
-
-
-
- ARISTA03T2
-
-
-
-
-
- Ethernet1
- 10.0.0.5/31
-
-
-
- Ethernet1
- FC00::A/126
-
-
-
- Ethernet9
- 10.10.246.3/24
-
-
-
- Ethernet9
- FC0A::6/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA04T0.xml b/ansible/minigraph/02-ARISTA04T0.xml
deleted file mode 100644
index 86739596090..00000000000
--- a/ansible/minigraph/02-ARISTA04T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T0
- 10.0.0.39
- str-s6000-on-3
- 10.0.0.38
- 1
- 180
- 60
-
-
- ARISTA04T0
- FC00::4E
- str-s6000-on-3
- FC00::4D
- 1
- 180
- 60
-
-
-
-
- 64004
- ARISTA04T0
-
-
- 10.0.0.38
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.20/32
-
- 100.1.0.20/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::14/128
-
- 2064:0100::14/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.193/24
-
- 10.255.0.193/24
-
-
-
-
-
- ARISTA04T0
-
-
-
-
-
- Ethernet1
- 10.0.0.39/31
-
-
-
- Ethernet1
- FC00::4E/126
-
-
-
- Ethernet9
- 10.10.246.20/24
-
-
-
- Ethernet9
- FC0A::29/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA04T2.xml b/ansible/minigraph/02-ARISTA04T2.xml
deleted file mode 100644
index 14f41c0cbcd..00000000000
--- a/ansible/minigraph/02-ARISTA04T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T2
- 10.0.0.7
- str-s6000-on-3
- 10.0.0.6
- 1
- 180
- 60
-
-
- ARISTA04T2
- FC00::E
- str-s6000-on-3
- FC00::D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA04T2
-
-
- 10.0.0.6
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.4/32
-
- 100.1.0.4/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::4/128
-
- 2064:0100::4/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.209/24
-
- 10.255.0.209/24
-
-
-
-
-
- ARISTA04T2
-
-
-
-
-
- Ethernet1
- 10.0.0.7/31
-
-
-
- Ethernet1
- FC00::E/126
-
-
-
- Ethernet9
- 10.10.246.4/24
-
-
-
- Ethernet9
- FC0A::9/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA05T0.xml b/ansible/minigraph/02-ARISTA05T0.xml
deleted file mode 100644
index 395bc73725a..00000000000
--- a/ansible/minigraph/02-ARISTA05T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T0
- 10.0.0.41
- str-s6000-on-3
- 10.0.0.40
- 1
- 180
- 60
-
-
- ARISTA05T0
- FC00::52
- str-s6000-on-3
- FC00::51
- 1
- 180
- 60
-
-
-
-
- 64005
- ARISTA05T0
-
-
- 10.0.0.40
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.21/32
-
- 100.1.0.21/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::15/128
-
- 2064:0100::15/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.194/24
-
- 10.255.0.194/24
-
-
-
-
-
- ARISTA05T0
-
-
-
-
-
- Ethernet1
- 10.0.0.41/31
-
-
-
- Ethernet1
- FC00::52/126
-
-
-
- Ethernet9
- 10.10.246.21/24
-
-
-
- Ethernet9
- FC0A::2A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA05T2.xml b/ansible/minigraph/02-ARISTA05T2.xml
deleted file mode 100644
index 4e895b6ea48..00000000000
--- a/ansible/minigraph/02-ARISTA05T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T2
- 10.0.0.9
- str-s6000-on-3
- 10.0.0.8
- 1
- 180
- 60
-
-
- ARISTA05T2
- FC00::12
- str-s6000-on-3
- FC00::11
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA05T2
-
-
- 10.0.0.8
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.5/32
-
- 100.1.0.5/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::5/128
-
- 2064:0100::5/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.210/24
-
- 10.255.0.210/24
-
-
-
-
-
- ARISTA05T2
-
-
-
-
-
- Ethernet1
- 10.0.0.9/31
-
-
-
- Ethernet1
- FC00::12/126
-
-
-
- Ethernet9
- 10.10.246.5/24
-
-
-
- Ethernet9
- FC0A::A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA06T0.xml b/ansible/minigraph/02-ARISTA06T0.xml
deleted file mode 100644
index 606b5b32eb5..00000000000
--- a/ansible/minigraph/02-ARISTA06T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T0
- 10.0.0.43
- str-s6000-on-3
- 10.0.0.42
- 1
- 180
- 60
-
-
- ARISTA06T0
- FC00::56
- str-s6000-on-3
- FC00::55
- 1
- 180
- 60
-
-
-
-
- 64006
- ARISTA06T0
-
-
- 10.0.0.42
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.22/32
-
- 100.1.0.22/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::16/128
-
- 2064:0100::16/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.195/24
-
- 10.255.0.195/24
-
-
-
-
-
- ARISTA06T0
-
-
-
-
-
- Ethernet1
- 10.0.0.43/31
-
-
-
- Ethernet1
- FC00::56/126
-
-
-
- Ethernet9
- 10.10.246.22/24
-
-
-
- Ethernet9
- FC0A::2D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA06T2.xml b/ansible/minigraph/02-ARISTA06T2.xml
deleted file mode 100644
index 8d783aa0da5..00000000000
--- a/ansible/minigraph/02-ARISTA06T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T2
- 10.0.0.11
- str-s6000-on-3
- 10.0.0.10
- 1
- 180
- 60
-
-
- ARISTA06T2
- FC00::16
- str-s6000-on-3
- FC00::15
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA06T2
-
-
- 10.0.0.10
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.6/32
-
- 100.1.0.6/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::6/128
-
- 2064:0100::6/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.211/24
-
- 10.255.0.211/24
-
-
-
-
-
- ARISTA06T2
-
-
-
-
-
- Ethernet1
- 10.0.0.11/31
-
-
-
- Ethernet1
- FC00::16/126
-
-
-
- Ethernet9
- 10.10.246.6/24
-
-
-
- Ethernet9
- FC0A::D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA07T0.xml b/ansible/minigraph/02-ARISTA07T0.xml
deleted file mode 100644
index b23946a9f33..00000000000
--- a/ansible/minigraph/02-ARISTA07T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T0
- 10.0.0.45
- str-s6000-on-3
- 10.0.0.44
- 1
- 180
- 60
-
-
- ARISTA07T0
- FC00::5A
- str-s6000-on-3
- FC00::59
- 1
- 180
- 60
-
-
-
-
- 64007
- ARISTA07T0
-
-
- 10.0.0.44
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.23/32
-
- 100.1.0.23/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::17/128
-
- 2064:0100::17/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.196/24
-
- 10.255.0.196/24
-
-
-
-
-
- ARISTA07T0
-
-
-
-
-
- Ethernet1
- 10.0.0.45/31
-
-
-
- Ethernet1
- FC00::5A/126
-
-
-
- Ethernet9
- 10.10.246.23/24
-
-
-
- Ethernet9
- FC0A::2E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA07T2.xml b/ansible/minigraph/02-ARISTA07T2.xml
deleted file mode 100644
index 2e59749b100..00000000000
--- a/ansible/minigraph/02-ARISTA07T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T2
- 10.0.0.13
- str-s6000-on-3
- 10.0.0.12
- 1
- 180
- 60
-
-
- ARISTA07T2
- FC00::1A
- str-s6000-on-3
- FC00::19
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA07T2
-
-
- 10.0.0.12
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.7/32
-
- 100.1.0.7/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::7/128
-
- 2064:0100::7/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.212/24
-
- 10.255.0.212/24
-
-
-
-
-
- ARISTA07T2
-
-
-
-
-
- Ethernet1
- 10.0.0.13/31
-
-
-
- Ethernet1
- FC00::1A/126
-
-
-
- Ethernet9
- 10.10.246.7/24
-
-
-
- Ethernet9
- FC0A::E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA08T0.xml b/ansible/minigraph/02-ARISTA08T0.xml
deleted file mode 100644
index 9cb67b472d2..00000000000
--- a/ansible/minigraph/02-ARISTA08T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T0
- 10.0.0.47
- str-s6000-on-3
- 10.0.0.46
- 1
- 180
- 60
-
-
- ARISTA08T0
- FC00::5E
- str-s6000-on-3
- FC00::5D
- 1
- 180
- 60
-
-
-
-
- 64008
- ARISTA08T0
-
-
- 10.0.0.46
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.24/32
-
- 100.1.0.24/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::18/128
-
- 2064:0100::18/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.197/24
-
- 10.255.0.197/24
-
-
-
-
-
- ARISTA08T0
-
-
-
-
-
- Ethernet1
- 10.0.0.47/31
-
-
-
- Ethernet1
- FC00::5E/126
-
-
-
- Ethernet9
- 10.10.246.24/24
-
-
-
- Ethernet9
- FC0A::31/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA08T2.xml b/ansible/minigraph/02-ARISTA08T2.xml
deleted file mode 100644
index 8b96af4352f..00000000000
--- a/ansible/minigraph/02-ARISTA08T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T2
- 10.0.0.15
- str-s6000-on-3
- 10.0.0.14
- 1
- 180
- 60
-
-
- ARISTA08T2
- FC00::1E
- str-s6000-on-3
- FC00::1D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA08T2
-
-
- 10.0.0.14
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.8/32
-
- 100.1.0.8/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::8/128
-
- 2064:0100::8/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.213/24
-
- 10.255.0.213/24
-
-
-
-
-
- ARISTA08T2
-
-
-
-
-
- Ethernet1
- 10.0.0.15/31
-
-
-
- Ethernet1
- FC00::1E/126
-
-
-
- Ethernet9
- 10.10.246.8/24
-
-
-
- Ethernet9
- FC0A::11/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA09T0.xml b/ansible/minigraph/02-ARISTA09T0.xml
deleted file mode 100644
index e242c4ef398..00000000000
--- a/ansible/minigraph/02-ARISTA09T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T0
- 10.0.0.49
- str-s6000-on-3
- 10.0.0.48
- 1
- 180
- 60
-
-
- ARISTA09T0
- FC00::62
- str-s6000-on-3
- FC00::61
- 1
- 180
- 60
-
-
-
-
- 64009
- ARISTA09T0
-
-
- 10.0.0.48
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.25/32
-
- 100.1.0.25/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::19/128
-
- 2064:0100::19/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.198/24
-
- 10.255.0.198/24
-
-
-
-
-
- ARISTA09T0
-
-
-
-
-
- Ethernet1
- 10.0.0.49/31
-
-
-
- Ethernet1
- FC00::62/126
-
-
-
- Ethernet9
- 10.10.246.25/24
-
-
-
- Ethernet9
- FC0A::32/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA09T2.xml b/ansible/minigraph/02-ARISTA09T2.xml
deleted file mode 100644
index 636b3362596..00000000000
--- a/ansible/minigraph/02-ARISTA09T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T2
- 10.0.0.17
- str-s6000-on-3
- 10.0.0.16
- 1
- 180
- 60
-
-
- ARISTA09T2
- FC00::22
- str-s6000-on-3
- FC00::21
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA09T2
-
-
- 10.0.0.16
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.9/32
-
- 100.1.0.9/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::9/128
-
- 2064:0100::9/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.214/24
-
- 10.255.0.214/24
-
-
-
-
-
- ARISTA09T2
-
-
-
-
-
- Ethernet1
- 10.0.0.17/31
-
-
-
- Ethernet1
- FC00::22/126
-
-
-
- Ethernet9
- 10.10.246.9/24
-
-
-
- Ethernet9
- FC0A::12/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA10T0.xml b/ansible/minigraph/02-ARISTA10T0.xml
deleted file mode 100644
index acf1b4db792..00000000000
--- a/ansible/minigraph/02-ARISTA10T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T0
- 10.0.0.51
- str-s6000-on-3
- 10.0.0.50
- 1
- 180
- 60
-
-
- ARISTA10T0
- FC00::66
- str-s6000-on-3
- FC00::65
- 1
- 180
- 60
-
-
-
-
- 64010
- ARISTA10T0
-
-
- 10.0.0.50
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.26/32
-
- 100.1.0.26/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1A/128
-
- 2064:0100::1A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.199/24
-
- 10.255.0.199/24
-
-
-
-
-
- ARISTA10T0
-
-
-
-
-
- Ethernet1
- 10.0.0.51/31
-
-
-
- Ethernet1
- FC00::66/126
-
-
-
- Ethernet9
- 10.10.246.26/24
-
-
-
- Ethernet9
- FC0A::35/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA10T2.xml b/ansible/minigraph/02-ARISTA10T2.xml
deleted file mode 100644
index 5aceccded7c..00000000000
--- a/ansible/minigraph/02-ARISTA10T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T2
- 10.0.0.19
- str-s6000-on-3
- 10.0.0.18
- 1
- 180
- 60
-
-
- ARISTA10T2
- FC00::26
- str-s6000-on-3
- FC00::25
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA10T2
-
-
- 10.0.0.18
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.10/32
-
- 100.1.0.10/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::A/128
-
- 2064:0100::A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.215/24
-
- 10.255.0.215/24
-
-
-
-
-
- ARISTA10T2
-
-
-
-
-
- Ethernet1
- 10.0.0.19/31
-
-
-
- Ethernet1
- FC00::26/126
-
-
-
- Ethernet9
- 10.10.246.10/24
-
-
-
- Ethernet9
- FC0A::15/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA11T0.xml b/ansible/minigraph/02-ARISTA11T0.xml
deleted file mode 100644
index b778b20c565..00000000000
--- a/ansible/minigraph/02-ARISTA11T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T0
- 10.0.0.53
- str-s6000-on-3
- 10.0.0.52
- 1
- 180
- 60
-
-
- ARISTA11T0
- FC00::6A
- str-s6000-on-3
- FC00::69
- 1
- 180
- 60
-
-
-
-
- 64011
- ARISTA11T0
-
-
- 10.0.0.52
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.27/32
-
- 100.1.0.27/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1B/128
-
- 2064:0100::1B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.200/24
-
- 10.255.0.200/24
-
-
-
-
-
- ARISTA11T0
-
-
-
-
-
- Ethernet1
- 10.0.0.53/31
-
-
-
- Ethernet1
- FC00::6A/126
-
-
-
- Ethernet9
- 10.10.246.27/24
-
-
-
- Ethernet9
- FC0A::36/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA11T2.xml b/ansible/minigraph/02-ARISTA11T2.xml
deleted file mode 100644
index d6dbf76e6c3..00000000000
--- a/ansible/minigraph/02-ARISTA11T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T2
- 10.0.0.21
- str-s6000-on-3
- 10.0.0.20
- 1
- 180
- 60
-
-
- ARISTA11T2
- FC00::2A
- str-s6000-on-3
- FC00::29
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA11T2
-
-
- 10.0.0.20
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.11/32
-
- 100.1.0.11/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::B/128
-
- 2064:0100::B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.216/24
-
- 10.255.0.216/24
-
-
-
-
-
- ARISTA11T2
-
-
-
-
-
- Ethernet1
- 10.0.0.21/31
-
-
-
- Ethernet1
- FC00::2A/126
-
-
-
- Ethernet9
- 10.10.246.11/24
-
-
-
- Ethernet9
- FC0A::16/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA12T0.xml b/ansible/minigraph/02-ARISTA12T0.xml
deleted file mode 100644
index 2a8b7511d1e..00000000000
--- a/ansible/minigraph/02-ARISTA12T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T0
- 10.0.0.55
- str-s6000-on-3
- 10.0.0.54
- 1
- 180
- 60
-
-
- ARISTA12T0
- FC00::6E
- str-s6000-on-3
- FC00::6D
- 1
- 180
- 60
-
-
-
-
- 64012
- ARISTA12T0
-
-
- 10.0.0.54
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.28/32
-
- 100.1.0.28/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1C/128
-
- 2064:0100::1C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.201/24
-
- 10.255.0.201/24
-
-
-
-
-
- ARISTA12T0
-
-
-
-
-
- Ethernet1
- 10.0.0.55/31
-
-
-
- Ethernet1
- FC00::6E/126
-
-
-
- Ethernet9
- 10.10.246.28/24
-
-
-
- Ethernet9
- FC0A::39/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA12T2.xml b/ansible/minigraph/02-ARISTA12T2.xml
deleted file mode 100644
index fcda3f7d6ed..00000000000
--- a/ansible/minigraph/02-ARISTA12T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T2
- 10.0.0.23
- str-s6000-on-3
- 10.0.0.22
- 1
- 180
- 60
-
-
- ARISTA12T2
- FC00::2E
- str-s6000-on-3
- FC00::2D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA12T2
-
-
- 10.0.0.22
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.12/32
-
- 100.1.0.12/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::C/128
-
- 2064:0100::C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.217/24
-
- 10.255.0.217/24
-
-
-
-
-
- ARISTA12T2
-
-
-
-
-
- Ethernet1
- 10.0.0.23/31
-
-
-
- Ethernet1
- FC00::2E/126
-
-
-
- Ethernet9
- 10.10.246.12/24
-
-
-
- Ethernet9
- FC0A::19/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA13T0.xml b/ansible/minigraph/02-ARISTA13T0.xml
deleted file mode 100644
index fd95122f799..00000000000
--- a/ansible/minigraph/02-ARISTA13T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T0
- 10.0.0.57
- str-s6000-on-3
- 10.0.0.56
- 1
- 180
- 60
-
-
- ARISTA13T0
- FC00::72
- str-s6000-on-3
- FC00::71
- 1
- 180
- 60
-
-
-
-
- 64013
- ARISTA13T0
-
-
- 10.0.0.56
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.29/32
-
- 100.1.0.29/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1D/128
-
- 2064:0100::1D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.202/24
-
- 10.255.0.202/24
-
-
-
-
-
- ARISTA13T0
-
-
-
-
-
- Ethernet1
- 10.0.0.57/31
-
-
-
- Ethernet1
- FC00::72/126
-
-
-
- Ethernet9
- 10.10.246.29/24
-
-
-
- Ethernet9
- FC0A::3A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA13T2.xml b/ansible/minigraph/02-ARISTA13T2.xml
deleted file mode 100644
index 83c43fd87a6..00000000000
--- a/ansible/minigraph/02-ARISTA13T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T2
- 10.0.0.25
- str-s6000-on-3
- 10.0.0.24
- 1
- 180
- 60
-
-
- ARISTA13T2
- FC00::32
- str-s6000-on-3
- FC00::31
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA13T2
-
-
- 10.0.0.24
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.13/32
-
- 100.1.0.13/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::D/128
-
- 2064:0100::D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.218/24
-
- 10.255.0.218/24
-
-
-
-
-
- ARISTA13T2
-
-
-
-
-
- Ethernet1
- 10.0.0.25/31
-
-
-
- Ethernet1
- FC00::32/126
-
-
-
- Ethernet9
- 10.10.246.13/24
-
-
-
- Ethernet9
- FC0A::1A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA14T0.xml b/ansible/minigraph/02-ARISTA14T0.xml
deleted file mode 100644
index 369bc7b03b3..00000000000
--- a/ansible/minigraph/02-ARISTA14T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T0
- 10.0.0.59
- str-s6000-on-3
- 10.0.0.58
- 1
- 180
- 60
-
-
- ARISTA14T0
- FC00::76
- str-s6000-on-3
- FC00::75
- 1
- 180
- 60
-
-
-
-
- 64014
- ARISTA14T0
-
-
- 10.0.0.58
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.30/32
-
- 100.1.0.30/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1E/128
-
- 2064:0100::1E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.203/24
-
- 10.255.0.203/24
-
-
-
-
-
- ARISTA14T0
-
-
-
-
-
- Ethernet1
- 10.0.0.59/31
-
-
-
- Ethernet1
- FC00::76/126
-
-
-
- Ethernet9
- 10.10.246.30/24
-
-
-
- Ethernet9
- FC0A::3D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA14T2.xml b/ansible/minigraph/02-ARISTA14T2.xml
deleted file mode 100644
index aba405fe07c..00000000000
--- a/ansible/minigraph/02-ARISTA14T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T2
- 10.0.0.27
- str-s6000-on-3
- 10.0.0.26
- 1
- 180
- 60
-
-
- ARISTA14T2
- FC00::36
- str-s6000-on-3
- FC00::35
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA14T2
-
-
- 10.0.0.26
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.14/32
-
- 100.1.0.14/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::E/128
-
- 2064:0100::E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.219/24
-
- 10.255.0.219/24
-
-
-
-
-
- ARISTA14T2
-
-
-
-
-
- Ethernet1
- 10.0.0.27/31
-
-
-
- Ethernet1
- FC00::36/126
-
-
-
- Ethernet9
- 10.10.246.14/24
-
-
-
- Ethernet9
- FC0A::1D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA15T0.xml b/ansible/minigraph/02-ARISTA15T0.xml
deleted file mode 100644
index e4e114f5b73..00000000000
--- a/ansible/minigraph/02-ARISTA15T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T0
- 10.0.0.61
- str-s6000-on-3
- 10.0.0.60
- 1
- 180
- 60
-
-
- ARISTA15T0
- FC00::7A
- str-s6000-on-3
- FC00::79
- 1
- 180
- 60
-
-
-
-
- 64015
- ARISTA15T0
-
-
- 10.0.0.60
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.31/32
-
- 100.1.0.31/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1F/128
-
- 2064:0100::1F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.204/24
-
- 10.255.0.204/24
-
-
-
-
-
- ARISTA15T0
-
-
-
-
-
- Ethernet1
- 10.0.0.61/31
-
-
-
- Ethernet1
- FC00::7A/126
-
-
-
- Ethernet9
- 10.10.246.31/24
-
-
-
- Ethernet9
- FC0A::3E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA15T2.xml b/ansible/minigraph/02-ARISTA15T2.xml
deleted file mode 100644
index 1d5e4202a94..00000000000
--- a/ansible/minigraph/02-ARISTA15T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T2
- 10.0.0.29
- str-s6000-on-3
- 10.0.0.28
- 1
- 180
- 60
-
-
- ARISTA15T2
- FC00::3A
- str-s6000-on-3
- FC00::39
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA15T2
-
-
- 10.0.0.28
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.15/32
-
- 100.1.0.15/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::F/128
-
- 2064:0100::F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.220/24
-
- 10.255.0.220/24
-
-
-
-
-
- ARISTA15T2
-
-
-
-
-
- Ethernet1
- 10.0.0.29/31
-
-
-
- Ethernet1
- FC00::3A/126
-
-
-
- Ethernet9
- 10.10.246.15/24
-
-
-
- Ethernet9
- FC0A::1E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA16T0.xml b/ansible/minigraph/02-ARISTA16T0.xml
deleted file mode 100644
index 76a41e3010e..00000000000
--- a/ansible/minigraph/02-ARISTA16T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T0
- 10.0.0.63
- str-s6000-on-3
- 10.0.0.62
- 1
- 180
- 60
-
-
- ARISTA16T0
- FC00::7E
- str-s6000-on-3
- FC00::7D
- 1
- 180
- 60
-
-
-
-
- 64016
- ARISTA16T0
-
-
- 10.0.0.62
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.32/32
-
- 100.1.0.32/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::20/128
-
- 2064:0100::20/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.205/24
-
- 10.255.0.205/24
-
-
-
-
-
- ARISTA16T0
-
-
-
-
-
- Ethernet1
- 10.0.0.63/31
-
-
-
- Ethernet1
- FC00::7E/126
-
-
-
- Ethernet9
- 10.10.246.32/24
-
-
-
- Ethernet9
- FC0A::41/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/02-ARISTA16T2.xml b/ansible/minigraph/02-ARISTA16T2.xml
deleted file mode 100644
index d9e5926360e..00000000000
--- a/ansible/minigraph/02-ARISTA16T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T2
- 10.0.0.31
- str-s6000-on-3
- 10.0.0.30
- 1
- 180
- 60
-
-
- ARISTA16T2
- FC00::3E
- str-s6000-on-3
- FC00::3D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA16T2
-
-
- 10.0.0.30
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.16/32
-
- 100.1.0.16/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::10/128
-
- 2064:0100::10/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.221/24
-
- 10.255.0.221/24
-
-
-
-
-
- ARISTA16T2
-
-
-
-
-
- Ethernet1
- 10.0.0.31/31
-
-
-
- Ethernet1
- FC00::3E/126
-
-
-
- Ethernet9
- 10.10.246.16/24
-
-
-
- Ethernet9
- FC0A::21/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA01T0.xml b/ansible/minigraph/03-ARISTA01T0.xml
deleted file mode 100644
index f5493c49dc5..00000000000
--- a/ansible/minigraph/03-ARISTA01T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T0
- 10.0.0.33
- str-s6000-on-3
- 10.0.0.32
- 1
- 180
- 60
-
-
- ARISTA01T0
- FC00::42
- str-s6000-on-3
- FC00::41
- 1
- 180
- 60
-
-
-
-
- 64001
- ARISTA01T0
-
-
- 10.0.0.32
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.17/32
-
- 100.1.0.17/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::11/128
-
- 2064:0100::11/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.52/24
-
- 10.255.0.52/24
-
-
-
-
-
- ARISTA01T0
-
-
-
-
-
- Ethernet1
- 10.0.0.33/31
-
-
-
- Ethernet1
- FC00::42/126
-
-
-
- Ethernet9
- 10.10.246.17/24
-
-
-
- Ethernet9
- FC0A::22/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA01T2.xml b/ansible/minigraph/03-ARISTA01T2.xml
deleted file mode 100644
index ddffbb2e6cd..00000000000
--- a/ansible/minigraph/03-ARISTA01T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T2
- 10.0.0.1
- str-s6000-on-3
- 10.0.0.0
- 1
- 180
- 60
-
-
- ARISTA01T2
- FC00::2
- str-s6000-on-3
- FC00::1
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA01T2
-
-
- 10.0.0.0
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.1/32
-
- 100.1.0.1/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1/128
-
- 2064:0100::1/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.68/24
-
- 10.255.0.68/24
-
-
-
-
-
- ARISTA01T2
-
-
-
-
-
- Ethernet1
- 10.0.0.1/31
-
-
-
- Ethernet1
- FC00::2/126
-
-
-
- Ethernet9
- 10.10.246.1/24
-
-
-
- Ethernet9
- FC0A::2/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA02T0.xml b/ansible/minigraph/03-ARISTA02T0.xml
deleted file mode 100644
index eb6979898ab..00000000000
--- a/ansible/minigraph/03-ARISTA02T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T0
- 10.0.0.35
- str-s6000-on-3
- 10.0.0.34
- 1
- 180
- 60
-
-
- ARISTA02T0
- FC00::46
- str-s6000-on-3
- FC00::45
- 1
- 180
- 60
-
-
-
-
- 64002
- ARISTA02T0
-
-
- 10.0.0.34
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.18/32
-
- 100.1.0.18/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::12/128
-
- 2064:0100::12/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.53/24
-
- 10.255.0.53/24
-
-
-
-
-
- ARISTA02T0
-
-
-
-
-
- Ethernet1
- 10.0.0.35/31
-
-
-
- Ethernet1
- FC00::46/126
-
-
-
- Ethernet9
- 10.10.246.18/24
-
-
-
- Ethernet9
- FC0A::25/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA02T2.xml b/ansible/minigraph/03-ARISTA02T2.xml
deleted file mode 100644
index 72bbc42ead4..00000000000
--- a/ansible/minigraph/03-ARISTA02T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T2
- 10.0.0.3
- str-s6000-on-3
- 10.0.0.2
- 1
- 180
- 60
-
-
- ARISTA02T2
- FC00::6
- str-s6000-on-3
- FC00::5
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA02T2
-
-
- 10.0.0.2
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.2/32
-
- 100.1.0.2/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::2/128
-
- 2064:0100::2/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.69/24
-
- 10.255.0.69/24
-
-
-
-
-
- ARISTA02T2
-
-
-
-
-
- Ethernet1
- 10.0.0.3/31
-
-
-
- Ethernet1
- FC00::6/126
-
-
-
- Ethernet9
- 10.10.246.2/24
-
-
-
- Ethernet9
- FC0A::5/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA03T0.xml b/ansible/minigraph/03-ARISTA03T0.xml
deleted file mode 100644
index 93402843551..00000000000
--- a/ansible/minigraph/03-ARISTA03T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T0
- 10.0.0.37
- str-s6000-on-3
- 10.0.0.36
- 1
- 180
- 60
-
-
- ARISTA03T0
- FC00::4A
- str-s6000-on-3
- FC00::49
- 1
- 180
- 60
-
-
-
-
- 64003
- ARISTA03T0
-
-
- 10.0.0.36
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.19/32
-
- 100.1.0.19/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::13/128
-
- 2064:0100::13/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.54/24
-
- 10.255.0.54/24
-
-
-
-
-
- ARISTA03T0
-
-
-
-
-
- Ethernet1
- 10.0.0.37/31
-
-
-
- Ethernet1
- FC00::4A/126
-
-
-
- Ethernet9
- 10.10.246.19/24
-
-
-
- Ethernet9
- FC0A::26/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA03T2.xml b/ansible/minigraph/03-ARISTA03T2.xml
deleted file mode 100644
index 22260d3da56..00000000000
--- a/ansible/minigraph/03-ARISTA03T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T2
- 10.0.0.5
- str-s6000-on-3
- 10.0.0.4
- 1
- 180
- 60
-
-
- ARISTA03T2
- FC00::A
- str-s6000-on-3
- FC00::9
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA03T2
-
-
- 10.0.0.4
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.3/32
-
- 100.1.0.3/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::3/128
-
- 2064:0100::3/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.70/24
-
- 10.255.0.70/24
-
-
-
-
-
- ARISTA03T2
-
-
-
-
-
- Ethernet1
- 10.0.0.5/31
-
-
-
- Ethernet1
- FC00::A/126
-
-
-
- Ethernet9
- 10.10.246.3/24
-
-
-
- Ethernet9
- FC0A::6/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA04T0.xml b/ansible/minigraph/03-ARISTA04T0.xml
deleted file mode 100644
index fcda70e47a1..00000000000
--- a/ansible/minigraph/03-ARISTA04T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T0
- 10.0.0.39
- str-s6000-on-3
- 10.0.0.38
- 1
- 180
- 60
-
-
- ARISTA04T0
- FC00::4E
- str-s6000-on-3
- FC00::4D
- 1
- 180
- 60
-
-
-
-
- 64004
- ARISTA04T0
-
-
- 10.0.0.38
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.20/32
-
- 100.1.0.20/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::14/128
-
- 2064:0100::14/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.55/24
-
- 10.255.0.55/24
-
-
-
-
-
- ARISTA04T0
-
-
-
-
-
- Ethernet1
- 10.0.0.39/31
-
-
-
- Ethernet1
- FC00::4E/126
-
-
-
- Ethernet9
- 10.10.246.20/24
-
-
-
- Ethernet9
- FC0A::29/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA04T2.xml b/ansible/minigraph/03-ARISTA04T2.xml
deleted file mode 100644
index a01d0160e79..00000000000
--- a/ansible/minigraph/03-ARISTA04T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T2
- 10.0.0.7
- str-s6000-on-3
- 10.0.0.6
- 1
- 180
- 60
-
-
- ARISTA04T2
- FC00::E
- str-s6000-on-3
- FC00::D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA04T2
-
-
- 10.0.0.6
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.4/32
-
- 100.1.0.4/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::4/128
-
- 2064:0100::4/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.71/24
-
- 10.255.0.71/24
-
-
-
-
-
- ARISTA04T2
-
-
-
-
-
- Ethernet1
- 10.0.0.7/31
-
-
-
- Ethernet1
- FC00::E/126
-
-
-
- Ethernet9
- 10.10.246.4/24
-
-
-
- Ethernet9
- FC0A::9/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA05T0.xml b/ansible/minigraph/03-ARISTA05T0.xml
deleted file mode 100644
index 8ea44b0b088..00000000000
--- a/ansible/minigraph/03-ARISTA05T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T0
- 10.0.0.41
- str-s6000-on-3
- 10.0.0.40
- 1
- 180
- 60
-
-
- ARISTA05T0
- FC00::52
- str-s6000-on-3
- FC00::51
- 1
- 180
- 60
-
-
-
-
- 64005
- ARISTA05T0
-
-
- 10.0.0.40
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.21/32
-
- 100.1.0.21/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::15/128
-
- 2064:0100::15/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.56/24
-
- 10.255.0.56/24
-
-
-
-
-
- ARISTA05T0
-
-
-
-
-
- Ethernet1
- 10.0.0.41/31
-
-
-
- Ethernet1
- FC00::52/126
-
-
-
- Ethernet9
- 10.10.246.21/24
-
-
-
- Ethernet9
- FC0A::2A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA05T2.xml b/ansible/minigraph/03-ARISTA05T2.xml
deleted file mode 100644
index 6c77bfb19fd..00000000000
--- a/ansible/minigraph/03-ARISTA05T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T2
- 10.0.0.9
- str-s6000-on-3
- 10.0.0.8
- 1
- 180
- 60
-
-
- ARISTA05T2
- FC00::12
- str-s6000-on-3
- FC00::11
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA05T2
-
-
- 10.0.0.8
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.5/32
-
- 100.1.0.5/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::5/128
-
- 2064:0100::5/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.72/24
-
- 10.255.0.72/24
-
-
-
-
-
- ARISTA05T2
-
-
-
-
-
- Ethernet1
- 10.0.0.9/31
-
-
-
- Ethernet1
- FC00::12/126
-
-
-
- Ethernet9
- 10.10.246.5/24
-
-
-
- Ethernet9
- FC0A::A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA06T0.xml b/ansible/minigraph/03-ARISTA06T0.xml
deleted file mode 100644
index afc4ac29c70..00000000000
--- a/ansible/minigraph/03-ARISTA06T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T0
- 10.0.0.43
- str-s6000-on-3
- 10.0.0.42
- 1
- 180
- 60
-
-
- ARISTA06T0
- FC00::56
- str-s6000-on-3
- FC00::55
- 1
- 180
- 60
-
-
-
-
- 64006
- ARISTA06T0
-
-
- 10.0.0.42
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.22/32
-
- 100.1.0.22/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::16/128
-
- 2064:0100::16/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.57/24
-
- 10.255.0.57/24
-
-
-
-
-
- ARISTA06T0
-
-
-
-
-
- Ethernet1
- 10.0.0.43/31
-
-
-
- Ethernet1
- FC00::56/126
-
-
-
- Ethernet9
- 10.10.246.22/24
-
-
-
- Ethernet9
- FC0A::2D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA06T2.xml b/ansible/minigraph/03-ARISTA06T2.xml
deleted file mode 100644
index dd7dca258c3..00000000000
--- a/ansible/minigraph/03-ARISTA06T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T2
- 10.0.0.11
- str-s6000-on-3
- 10.0.0.10
- 1
- 180
- 60
-
-
- ARISTA06T2
- FC00::16
- str-s6000-on-3
- FC00::15
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA06T2
-
-
- 10.0.0.10
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.6/32
-
- 100.1.0.6/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::6/128
-
- 2064:0100::6/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.73/24
-
- 10.255.0.73/24
-
-
-
-
-
- ARISTA06T2
-
-
-
-
-
- Ethernet1
- 10.0.0.11/31
-
-
-
- Ethernet1
- FC00::16/126
-
-
-
- Ethernet9
- 10.10.246.6/24
-
-
-
- Ethernet9
- FC0A::D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA07T0.xml b/ansible/minigraph/03-ARISTA07T0.xml
deleted file mode 100644
index f75ad3884f5..00000000000
--- a/ansible/minigraph/03-ARISTA07T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T0
- 10.0.0.45
- str-s6000-on-3
- 10.0.0.44
- 1
- 180
- 60
-
-
- ARISTA07T0
- FC00::5A
- str-s6000-on-3
- FC00::59
- 1
- 180
- 60
-
-
-
-
- 64007
- ARISTA07T0
-
-
- 10.0.0.44
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.23/32
-
- 100.1.0.23/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::17/128
-
- 2064:0100::17/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.58/24
-
- 10.255.0.58/24
-
-
-
-
-
- ARISTA07T0
-
-
-
-
-
- Ethernet1
- 10.0.0.45/31
-
-
-
- Ethernet1
- FC00::5A/126
-
-
-
- Ethernet9
- 10.10.246.23/24
-
-
-
- Ethernet9
- FC0A::2E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA07T2.xml b/ansible/minigraph/03-ARISTA07T2.xml
deleted file mode 100644
index d8438a16563..00000000000
--- a/ansible/minigraph/03-ARISTA07T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T2
- 10.0.0.13
- str-s6000-on-3
- 10.0.0.12
- 1
- 180
- 60
-
-
- ARISTA07T2
- FC00::1A
- str-s6000-on-3
- FC00::19
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA07T2
-
-
- 10.0.0.12
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.7/32
-
- 100.1.0.7/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::7/128
-
- 2064:0100::7/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.74/24
-
- 10.255.0.74/24
-
-
-
-
-
- ARISTA07T2
-
-
-
-
-
- Ethernet1
- 10.0.0.13/31
-
-
-
- Ethernet1
- FC00::1A/126
-
-
-
- Ethernet9
- 10.10.246.7/24
-
-
-
- Ethernet9
- FC0A::E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA08T0.xml b/ansible/minigraph/03-ARISTA08T0.xml
deleted file mode 100644
index 6e32505567a..00000000000
--- a/ansible/minigraph/03-ARISTA08T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T0
- 10.0.0.47
- str-s6000-on-3
- 10.0.0.46
- 1
- 180
- 60
-
-
- ARISTA08T0
- FC00::5E
- str-s6000-on-3
- FC00::5D
- 1
- 180
- 60
-
-
-
-
- 64008
- ARISTA08T0
-
-
- 10.0.0.46
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.24/32
-
- 100.1.0.24/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::18/128
-
- 2064:0100::18/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.59/24
-
- 10.255.0.59/24
-
-
-
-
-
- ARISTA08T0
-
-
-
-
-
- Ethernet1
- 10.0.0.47/31
-
-
-
- Ethernet1
- FC00::5E/126
-
-
-
- Ethernet9
- 10.10.246.24/24
-
-
-
- Ethernet9
- FC0A::31/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA08T2.xml b/ansible/minigraph/03-ARISTA08T2.xml
deleted file mode 100644
index 88dcdc6d0f0..00000000000
--- a/ansible/minigraph/03-ARISTA08T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T2
- 10.0.0.15
- str-s6000-on-3
- 10.0.0.14
- 1
- 180
- 60
-
-
- ARISTA08T2
- FC00::1E
- str-s6000-on-3
- FC00::1D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA08T2
-
-
- 10.0.0.14
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.8/32
-
- 100.1.0.8/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::8/128
-
- 2064:0100::8/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.75/24
-
- 10.255.0.75/24
-
-
-
-
-
- ARISTA08T2
-
-
-
-
-
- Ethernet1
- 10.0.0.15/31
-
-
-
- Ethernet1
- FC00::1E/126
-
-
-
- Ethernet9
- 10.10.246.8/24
-
-
-
- Ethernet9
- FC0A::11/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA09T0.xml b/ansible/minigraph/03-ARISTA09T0.xml
deleted file mode 100644
index fd459a5d956..00000000000
--- a/ansible/minigraph/03-ARISTA09T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T0
- 10.0.0.49
- str-s6000-on-3
- 10.0.0.48
- 1
- 180
- 60
-
-
- ARISTA09T0
- FC00::62
- str-s6000-on-3
- FC00::61
- 1
- 180
- 60
-
-
-
-
- 64009
- ARISTA09T0
-
-
- 10.0.0.48
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.25/32
-
- 100.1.0.25/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::19/128
-
- 2064:0100::19/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.60/24
-
- 10.255.0.60/24
-
-
-
-
-
- ARISTA09T0
-
-
-
-
-
- Ethernet1
- 10.0.0.49/31
-
-
-
- Ethernet1
- FC00::62/126
-
-
-
- Ethernet9
- 10.10.246.25/24
-
-
-
- Ethernet9
- FC0A::32/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA09T2.xml b/ansible/minigraph/03-ARISTA09T2.xml
deleted file mode 100644
index b56373eadd1..00000000000
--- a/ansible/minigraph/03-ARISTA09T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T2
- 10.0.0.17
- str-s6000-on-3
- 10.0.0.16
- 1
- 180
- 60
-
-
- ARISTA09T2
- FC00::22
- str-s6000-on-3
- FC00::21
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA09T2
-
-
- 10.0.0.16
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.9/32
-
- 100.1.0.9/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::9/128
-
- 2064:0100::9/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.76/24
-
- 10.255.0.76/24
-
-
-
-
-
- ARISTA09T2
-
-
-
-
-
- Ethernet1
- 10.0.0.17/31
-
-
-
- Ethernet1
- FC00::22/126
-
-
-
- Ethernet9
- 10.10.246.9/24
-
-
-
- Ethernet9
- FC0A::12/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA10T0.xml b/ansible/minigraph/03-ARISTA10T0.xml
deleted file mode 100644
index f7279f3defe..00000000000
--- a/ansible/minigraph/03-ARISTA10T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T0
- 10.0.0.51
- str-s6000-on-3
- 10.0.0.50
- 1
- 180
- 60
-
-
- ARISTA10T0
- FC00::66
- str-s6000-on-3
- FC00::65
- 1
- 180
- 60
-
-
-
-
- 64010
- ARISTA10T0
-
-
- 10.0.0.50
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.26/32
-
- 100.1.0.26/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1A/128
-
- 2064:0100::1A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.61/24
-
- 10.255.0.61/24
-
-
-
-
-
- ARISTA10T0
-
-
-
-
-
- Ethernet1
- 10.0.0.51/31
-
-
-
- Ethernet1
- FC00::66/126
-
-
-
- Ethernet9
- 10.10.246.26/24
-
-
-
- Ethernet9
- FC0A::35/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA10T2.xml b/ansible/minigraph/03-ARISTA10T2.xml
deleted file mode 100644
index e8af16bb7a6..00000000000
--- a/ansible/minigraph/03-ARISTA10T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T2
- 10.0.0.19
- str-s6000-on-3
- 10.0.0.18
- 1
- 180
- 60
-
-
- ARISTA10T2
- FC00::26
- str-s6000-on-3
- FC00::25
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA10T2
-
-
- 10.0.0.18
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.10/32
-
- 100.1.0.10/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::A/128
-
- 2064:0100::A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.77/24
-
- 10.255.0.77/24
-
-
-
-
-
- ARISTA10T2
-
-
-
-
-
- Ethernet1
- 10.0.0.19/31
-
-
-
- Ethernet1
- FC00::26/126
-
-
-
- Ethernet9
- 10.10.246.10/24
-
-
-
- Ethernet9
- FC0A::15/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA11T0.xml b/ansible/minigraph/03-ARISTA11T0.xml
deleted file mode 100644
index ce04c338a39..00000000000
--- a/ansible/minigraph/03-ARISTA11T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T0
- 10.0.0.53
- str-s6000-on-3
- 10.0.0.52
- 1
- 180
- 60
-
-
- ARISTA11T0
- FC00::6A
- str-s6000-on-3
- FC00::69
- 1
- 180
- 60
-
-
-
-
- 64011
- ARISTA11T0
-
-
- 10.0.0.52
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.27/32
-
- 100.1.0.27/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1B/128
-
- 2064:0100::1B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.62/24
-
- 10.255.0.62/24
-
-
-
-
-
- ARISTA11T0
-
-
-
-
-
- Ethernet1
- 10.0.0.53/31
-
-
-
- Ethernet1
- FC00::6A/126
-
-
-
- Ethernet9
- 10.10.246.27/24
-
-
-
- Ethernet9
- FC0A::36/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA11T2.xml b/ansible/minigraph/03-ARISTA11T2.xml
deleted file mode 100644
index 307a314490f..00000000000
--- a/ansible/minigraph/03-ARISTA11T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T2
- 10.0.0.21
- str-s6000-on-3
- 10.0.0.20
- 1
- 180
- 60
-
-
- ARISTA11T2
- FC00::2A
- str-s6000-on-3
- FC00::29
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA11T2
-
-
- 10.0.0.20
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.11/32
-
- 100.1.0.11/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::B/128
-
- 2064:0100::B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.78/24
-
- 10.255.0.78/24
-
-
-
-
-
- ARISTA11T2
-
-
-
-
-
- Ethernet1
- 10.0.0.21/31
-
-
-
- Ethernet1
- FC00::2A/126
-
-
-
- Ethernet9
- 10.10.246.11/24
-
-
-
- Ethernet9
- FC0A::16/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA12T0.xml b/ansible/minigraph/03-ARISTA12T0.xml
deleted file mode 100644
index 7de47f9f1a6..00000000000
--- a/ansible/minigraph/03-ARISTA12T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T0
- 10.0.0.55
- str-s6000-on-3
- 10.0.0.54
- 1
- 180
- 60
-
-
- ARISTA12T0
- FC00::6E
- str-s6000-on-3
- FC00::6D
- 1
- 180
- 60
-
-
-
-
- 64012
- ARISTA12T0
-
-
- 10.0.0.54
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.28/32
-
- 100.1.0.28/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1C/128
-
- 2064:0100::1C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.63/24
-
- 10.255.0.63/24
-
-
-
-
-
- ARISTA12T0
-
-
-
-
-
- Ethernet1
- 10.0.0.55/31
-
-
-
- Ethernet1
- FC00::6E/126
-
-
-
- Ethernet9
- 10.10.246.28/24
-
-
-
- Ethernet9
- FC0A::39/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA12T2.xml b/ansible/minigraph/03-ARISTA12T2.xml
deleted file mode 100644
index 27ce7cb7f42..00000000000
--- a/ansible/minigraph/03-ARISTA12T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T2
- 10.0.0.23
- str-s6000-on-3
- 10.0.0.22
- 1
- 180
- 60
-
-
- ARISTA12T2
- FC00::2E
- str-s6000-on-3
- FC00::2D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA12T2
-
-
- 10.0.0.22
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.12/32
-
- 100.1.0.12/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::C/128
-
- 2064:0100::C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.79/24
-
- 10.255.0.79/24
-
-
-
-
-
- ARISTA12T2
-
-
-
-
-
- Ethernet1
- 10.0.0.23/31
-
-
-
- Ethernet1
- FC00::2E/126
-
-
-
- Ethernet9
- 10.10.246.12/24
-
-
-
- Ethernet9
- FC0A::19/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA13T0.xml b/ansible/minigraph/03-ARISTA13T0.xml
deleted file mode 100644
index 941ff0f0f5d..00000000000
--- a/ansible/minigraph/03-ARISTA13T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T0
- 10.0.0.57
- str-s6000-on-3
- 10.0.0.56
- 1
- 180
- 60
-
-
- ARISTA13T0
- FC00::72
- str-s6000-on-3
- FC00::71
- 1
- 180
- 60
-
-
-
-
- 64013
- ARISTA13T0
-
-
- 10.0.0.56
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.29/32
-
- 100.1.0.29/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1D/128
-
- 2064:0100::1D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.64/24
-
- 10.255.0.64/24
-
-
-
-
-
- ARISTA13T0
-
-
-
-
-
- Ethernet1
- 10.0.0.57/31
-
-
-
- Ethernet1
- FC00::72/126
-
-
-
- Ethernet9
- 10.10.246.29/24
-
-
-
- Ethernet9
- FC0A::3A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA13T2.xml b/ansible/minigraph/03-ARISTA13T2.xml
deleted file mode 100644
index c5ce257dfd4..00000000000
--- a/ansible/minigraph/03-ARISTA13T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T2
- 10.0.0.25
- str-s6000-on-3
- 10.0.0.24
- 1
- 180
- 60
-
-
- ARISTA13T2
- FC00::32
- str-s6000-on-3
- FC00::31
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA13T2
-
-
- 10.0.0.24
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.13/32
-
- 100.1.0.13/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::D/128
-
- 2064:0100::D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.80/24
-
- 10.255.0.80/24
-
-
-
-
-
- ARISTA13T2
-
-
-
-
-
- Ethernet1
- 10.0.0.25/31
-
-
-
- Ethernet1
- FC00::32/126
-
-
-
- Ethernet9
- 10.10.246.13/24
-
-
-
- Ethernet9
- FC0A::1A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA14T0.xml b/ansible/minigraph/03-ARISTA14T0.xml
deleted file mode 100644
index 9e2b2e54824..00000000000
--- a/ansible/minigraph/03-ARISTA14T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T0
- 10.0.0.59
- str-s6000-on-3
- 10.0.0.58
- 1
- 180
- 60
-
-
- ARISTA14T0
- FC00::76
- str-s6000-on-3
- FC00::75
- 1
- 180
- 60
-
-
-
-
- 64014
- ARISTA14T0
-
-
- 10.0.0.58
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.30/32
-
- 100.1.0.30/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1E/128
-
- 2064:0100::1E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.65/24
-
- 10.255.0.65/24
-
-
-
-
-
- ARISTA14T0
-
-
-
-
-
- Ethernet1
- 10.0.0.59/31
-
-
-
- Ethernet1
- FC00::76/126
-
-
-
- Ethernet9
- 10.10.246.30/24
-
-
-
- Ethernet9
- FC0A::3D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA14T2.xml b/ansible/minigraph/03-ARISTA14T2.xml
deleted file mode 100644
index 5a0a2aad7a9..00000000000
--- a/ansible/minigraph/03-ARISTA14T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T2
- 10.0.0.27
- str-s6000-on-3
- 10.0.0.26
- 1
- 180
- 60
-
-
- ARISTA14T2
- FC00::36
- str-s6000-on-3
- FC00::35
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA14T2
-
-
- 10.0.0.26
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.14/32
-
- 100.1.0.14/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::E/128
-
- 2064:0100::E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.81/24
-
- 10.255.0.81/24
-
-
-
-
-
- ARISTA14T2
-
-
-
-
-
- Ethernet1
- 10.0.0.27/31
-
-
-
- Ethernet1
- FC00::36/126
-
-
-
- Ethernet9
- 10.10.246.14/24
-
-
-
- Ethernet9
- FC0A::1D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA15T0.xml b/ansible/minigraph/03-ARISTA15T0.xml
deleted file mode 100644
index 79ed77748e0..00000000000
--- a/ansible/minigraph/03-ARISTA15T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T0
- 10.0.0.61
- str-s6000-on-3
- 10.0.0.60
- 1
- 180
- 60
-
-
- ARISTA15T0
- FC00::7A
- str-s6000-on-3
- FC00::79
- 1
- 180
- 60
-
-
-
-
- 64015
- ARISTA15T0
-
-
- 10.0.0.60
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.31/32
-
- 100.1.0.31/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1F/128
-
- 2064:0100::1F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.66/24
-
- 10.255.0.66/24
-
-
-
-
-
- ARISTA15T0
-
-
-
-
-
- Ethernet1
- 10.0.0.61/31
-
-
-
- Ethernet1
- FC00::7A/126
-
-
-
- Ethernet9
- 10.10.246.31/24
-
-
-
- Ethernet9
- FC0A::3E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA15T2.xml b/ansible/minigraph/03-ARISTA15T2.xml
deleted file mode 100644
index 8de07f588cb..00000000000
--- a/ansible/minigraph/03-ARISTA15T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T2
- 10.0.0.29
- str-s6000-on-3
- 10.0.0.28
- 1
- 180
- 60
-
-
- ARISTA15T2
- FC00::3A
- str-s6000-on-3
- FC00::39
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA15T2
-
-
- 10.0.0.28
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.15/32
-
- 100.1.0.15/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::F/128
-
- 2064:0100::F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.82/24
-
- 10.255.0.82/24
-
-
-
-
-
- ARISTA15T2
-
-
-
-
-
- Ethernet1
- 10.0.0.29/31
-
-
-
- Ethernet1
- FC00::3A/126
-
-
-
- Ethernet9
- 10.10.246.15/24
-
-
-
- Ethernet9
- FC0A::1E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA16T0.xml b/ansible/minigraph/03-ARISTA16T0.xml
deleted file mode 100644
index bf052ba420f..00000000000
--- a/ansible/minigraph/03-ARISTA16T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T0
- 10.0.0.63
- str-s6000-on-3
- 10.0.0.62
- 1
- 180
- 60
-
-
- ARISTA16T0
- FC00::7E
- str-s6000-on-3
- FC00::7D
- 1
- 180
- 60
-
-
-
-
- 64016
- ARISTA16T0
-
-
- 10.0.0.62
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.32/32
-
- 100.1.0.32/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::20/128
-
- 2064:0100::20/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.67/24
-
- 10.255.0.67/24
-
-
-
-
-
- ARISTA16T0
-
-
-
-
-
- Ethernet1
- 10.0.0.63/31
-
-
-
- Ethernet1
- FC00::7E/126
-
-
-
- Ethernet9
- 10.10.246.32/24
-
-
-
- Ethernet9
- FC0A::41/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/03-ARISTA16T2.xml b/ansible/minigraph/03-ARISTA16T2.xml
deleted file mode 100644
index fcef68d165f..00000000000
--- a/ansible/minigraph/03-ARISTA16T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T2
- 10.0.0.31
- str-s6000-on-3
- 10.0.0.30
- 1
- 180
- 60
-
-
- ARISTA16T2
- FC00::3E
- str-s6000-on-3
- FC00::3D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA16T2
-
-
- 10.0.0.30
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.16/32
-
- 100.1.0.16/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::10/128
-
- 2064:0100::10/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.83/24
-
- 10.255.0.83/24
-
-
-
-
-
- ARISTA16T2
-
-
-
-
-
- Ethernet1
- 10.0.0.31/31
-
-
-
- Ethernet1
- FC00::3E/126
-
-
-
- Ethernet9
- 10.10.246.16/24
-
-
-
- Ethernet9
- FC0A::21/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA01T0.xml b/ansible/minigraph/04-ARISTA01T0.xml
deleted file mode 100644
index 4fd8b982ce1..00000000000
--- a/ansible/minigraph/04-ARISTA01T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T0
- 10.0.0.33
- str-s6000-on-3
- 10.0.0.32
- 1
- 180
- 60
-
-
- ARISTA01T0
- FC00::42
- str-s6000-on-3
- FC00::41
- 1
- 180
- 60
-
-
-
-
- 64001
- ARISTA01T0
-
-
- 10.0.0.32
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.17/32
-
- 100.1.0.17/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::11/128
-
- 2064:0100::11/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.84/24
-
- 10.255.0.84/24
-
-
-
-
-
- ARISTA01T0
-
-
-
-
-
- Ethernet1
- 10.0.0.33/31
-
-
-
- Ethernet1
- FC00::42/126
-
-
-
- Ethernet9
- 10.10.246.17/24
-
-
-
- Ethernet9
- FC0A::22/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA01T2.xml b/ansible/minigraph/04-ARISTA01T2.xml
deleted file mode 100644
index 1df23b2a056..00000000000
--- a/ansible/minigraph/04-ARISTA01T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA01T2
- 10.0.0.1
- str-s6000-on-3
- 10.0.0.0
- 1
- 180
- 60
-
-
- ARISTA01T2
- FC00::2
- str-s6000-on-3
- FC00::1
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA01T2
-
-
- 10.0.0.0
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.1/32
-
- 100.1.0.1/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1/128
-
- 2064:0100::1/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.108/24
-
- 10.255.0.108/24
-
-
-
-
-
- ARISTA01T2
-
-
-
-
-
- Ethernet1
- 10.0.0.1/31
-
-
-
- Ethernet1
- FC00::2/126
-
-
-
- Ethernet9
- 10.10.246.1/24
-
-
-
- Ethernet9
- FC0A::2/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA01T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA02T0.xml b/ansible/minigraph/04-ARISTA02T0.xml
deleted file mode 100644
index 3ea06cd3364..00000000000
--- a/ansible/minigraph/04-ARISTA02T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T0
- 10.0.0.35
- str-s6000-on-3
- 10.0.0.34
- 1
- 180
- 60
-
-
- ARISTA02T0
- FC00::46
- str-s6000-on-3
- FC00::45
- 1
- 180
- 60
-
-
-
-
- 64002
- ARISTA02T0
-
-
- 10.0.0.34
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.18/32
-
- 100.1.0.18/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::12/128
-
- 2064:0100::12/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.85/24
-
- 10.255.0.85/24
-
-
-
-
-
- ARISTA02T0
-
-
-
-
-
- Ethernet1
- 10.0.0.35/31
-
-
-
- Ethernet1
- FC00::46/126
-
-
-
- Ethernet9
- 10.10.246.18/24
-
-
-
- Ethernet9
- FC0A::25/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA02T2.xml b/ansible/minigraph/04-ARISTA02T2.xml
deleted file mode 100644
index e35dc8370fb..00000000000
--- a/ansible/minigraph/04-ARISTA02T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA02T2
- 10.0.0.3
- str-s6000-on-3
- 10.0.0.2
- 1
- 180
- 60
-
-
- ARISTA02T2
- FC00::6
- str-s6000-on-3
- FC00::5
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA02T2
-
-
- 10.0.0.2
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.2/32
-
- 100.1.0.2/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::2/128
-
- 2064:0100::2/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.109/24
-
- 10.255.0.109/24
-
-
-
-
-
- ARISTA02T2
-
-
-
-
-
- Ethernet1
- 10.0.0.3/31
-
-
-
- Ethernet1
- FC00::6/126
-
-
-
- Ethernet9
- 10.10.246.2/24
-
-
-
- Ethernet9
- FC0A::5/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA02T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA03T0.xml b/ansible/minigraph/04-ARISTA03T0.xml
deleted file mode 100644
index 37645be094d..00000000000
--- a/ansible/minigraph/04-ARISTA03T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T0
- 10.0.0.37
- str-s6000-on-3
- 10.0.0.36
- 1
- 180
- 60
-
-
- ARISTA03T0
- FC00::4A
- str-s6000-on-3
- FC00::49
- 1
- 180
- 60
-
-
-
-
- 64003
- ARISTA03T0
-
-
- 10.0.0.36
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.19/32
-
- 100.1.0.19/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::13/128
-
- 2064:0100::13/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.86/24
-
- 10.255.0.86/24
-
-
-
-
-
- ARISTA03T0
-
-
-
-
-
- Ethernet1
- 10.0.0.37/31
-
-
-
- Ethernet1
- FC00::4A/126
-
-
-
- Ethernet9
- 10.10.246.19/24
-
-
-
- Ethernet9
- FC0A::26/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA03T2.xml b/ansible/minigraph/04-ARISTA03T2.xml
deleted file mode 100644
index 7be756d25af..00000000000
--- a/ansible/minigraph/04-ARISTA03T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA03T2
- 10.0.0.5
- str-s6000-on-3
- 10.0.0.4
- 1
- 180
- 60
-
-
- ARISTA03T2
- FC00::A
- str-s6000-on-3
- FC00::9
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA03T2
-
-
- 10.0.0.4
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.3/32
-
- 100.1.0.3/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::3/128
-
- 2064:0100::3/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.114/24
-
- 10.255.0.114/24
-
-
-
-
-
- ARISTA03T2
-
-
-
-
-
- Ethernet1
- 10.0.0.5/31
-
-
-
- Ethernet1
- FC00::A/126
-
-
-
- Ethernet9
- 10.10.246.3/24
-
-
-
- Ethernet9
- FC0A::6/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA03T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA04T0.xml b/ansible/minigraph/04-ARISTA04T0.xml
deleted file mode 100644
index 01006bdda84..00000000000
--- a/ansible/minigraph/04-ARISTA04T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T0
- 10.0.0.39
- str-s6000-on-3
- 10.0.0.38
- 1
- 180
- 60
-
-
- ARISTA04T0
- FC00::4E
- str-s6000-on-3
- FC00::4D
- 1
- 180
- 60
-
-
-
-
- 64004
- ARISTA04T0
-
-
- 10.0.0.38
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.20/32
-
- 100.1.0.20/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::14/128
-
- 2064:0100::14/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.87/24
-
- 10.255.0.87/24
-
-
-
-
-
- ARISTA04T0
-
-
-
-
-
- Ethernet1
- 10.0.0.39/31
-
-
-
- Ethernet1
- FC00::4E/126
-
-
-
- Ethernet9
- 10.10.246.20/24
-
-
-
- Ethernet9
- FC0A::29/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA04T2.xml b/ansible/minigraph/04-ARISTA04T2.xml
deleted file mode 100644
index 26f3b18fc3c..00000000000
--- a/ansible/minigraph/04-ARISTA04T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA04T2
- 10.0.0.7
- str-s6000-on-3
- 10.0.0.6
- 1
- 180
- 60
-
-
- ARISTA04T2
- FC00::E
- str-s6000-on-3
- FC00::D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA04T2
-
-
- 10.0.0.6
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.4/32
-
- 100.1.0.4/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::4/128
-
- 2064:0100::4/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.115/24
-
- 10.255.0.115/24
-
-
-
-
-
- ARISTA04T2
-
-
-
-
-
- Ethernet1
- 10.0.0.7/31
-
-
-
- Ethernet1
- FC00::E/126
-
-
-
- Ethernet9
- 10.10.246.4/24
-
-
-
- Ethernet9
- FC0A::9/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA04T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA05T0.xml b/ansible/minigraph/04-ARISTA05T0.xml
deleted file mode 100644
index 2486302dbe0..00000000000
--- a/ansible/minigraph/04-ARISTA05T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T0
- 10.0.0.41
- str-s6000-on-3
- 10.0.0.40
- 1
- 180
- 60
-
-
- ARISTA05T0
- FC00::52
- str-s6000-on-3
- FC00::51
- 1
- 180
- 60
-
-
-
-
- 64005
- ARISTA05T0
-
-
- 10.0.0.40
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.21/32
-
- 100.1.0.21/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::15/128
-
- 2064:0100::15/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.88/24
-
- 10.255.0.88/24
-
-
-
-
-
- ARISTA05T0
-
-
-
-
-
- Ethernet1
- 10.0.0.41/31
-
-
-
- Ethernet1
- FC00::52/126
-
-
-
- Ethernet9
- 10.10.246.21/24
-
-
-
- Ethernet9
- FC0A::2A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA05T2.xml b/ansible/minigraph/04-ARISTA05T2.xml
deleted file mode 100644
index 4b68d0448d9..00000000000
--- a/ansible/minigraph/04-ARISTA05T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA05T2
- 10.0.0.9
- str-s6000-on-3
- 10.0.0.8
- 1
- 180
- 60
-
-
- ARISTA05T2
- FC00::12
- str-s6000-on-3
- FC00::11
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA05T2
-
-
- 10.0.0.8
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.5/32
-
- 100.1.0.5/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::5/128
-
- 2064:0100::5/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.116/24
-
- 10.255.0.116/24
-
-
-
-
-
- ARISTA05T2
-
-
-
-
-
- Ethernet1
- 10.0.0.9/31
-
-
-
- Ethernet1
- FC00::12/126
-
-
-
- Ethernet9
- 10.10.246.5/24
-
-
-
- Ethernet9
- FC0A::A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA05T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA06T0.xml b/ansible/minigraph/04-ARISTA06T0.xml
deleted file mode 100644
index 86d2451fbb3..00000000000
--- a/ansible/minigraph/04-ARISTA06T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T0
- 10.0.0.43
- str-s6000-on-3
- 10.0.0.42
- 1
- 180
- 60
-
-
- ARISTA06T0
- FC00::56
- str-s6000-on-3
- FC00::55
- 1
- 180
- 60
-
-
-
-
- 64006
- ARISTA06T0
-
-
- 10.0.0.42
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.22/32
-
- 100.1.0.22/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::16/128
-
- 2064:0100::16/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.89/24
-
- 10.255.0.89/24
-
-
-
-
-
- ARISTA06T0
-
-
-
-
-
- Ethernet1
- 10.0.0.43/31
-
-
-
- Ethernet1
- FC00::56/126
-
-
-
- Ethernet9
- 10.10.246.22/24
-
-
-
- Ethernet9
- FC0A::2D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA06T2.xml b/ansible/minigraph/04-ARISTA06T2.xml
deleted file mode 100644
index 112e2561219..00000000000
--- a/ansible/minigraph/04-ARISTA06T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA06T2
- 10.0.0.11
- str-s6000-on-3
- 10.0.0.10
- 1
- 180
- 60
-
-
- ARISTA06T2
- FC00::16
- str-s6000-on-3
- FC00::15
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA06T2
-
-
- 10.0.0.10
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.6/32
-
- 100.1.0.6/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::6/128
-
- 2064:0100::6/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.117/24
-
- 10.255.0.117/24
-
-
-
-
-
- ARISTA06T2
-
-
-
-
-
- Ethernet1
- 10.0.0.11/31
-
-
-
- Ethernet1
- FC00::16/126
-
-
-
- Ethernet9
- 10.10.246.6/24
-
-
-
- Ethernet9
- FC0A::D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA06T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA07T0.xml b/ansible/minigraph/04-ARISTA07T0.xml
deleted file mode 100644
index 8a023560ebc..00000000000
--- a/ansible/minigraph/04-ARISTA07T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T0
- 10.0.0.45
- str-s6000-on-3
- 10.0.0.44
- 1
- 180
- 60
-
-
- ARISTA07T0
- FC00::5A
- str-s6000-on-3
- FC00::59
- 1
- 180
- 60
-
-
-
-
- 64007
- ARISTA07T0
-
-
- 10.0.0.44
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.23/32
-
- 100.1.0.23/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::17/128
-
- 2064:0100::17/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.90/24
-
- 10.255.0.90/24
-
-
-
-
-
- ARISTA07T0
-
-
-
-
-
- Ethernet1
- 10.0.0.45/31
-
-
-
- Ethernet1
- FC00::5A/126
-
-
-
- Ethernet9
- 10.10.246.23/24
-
-
-
- Ethernet9
- FC0A::2E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA07T2.xml b/ansible/minigraph/04-ARISTA07T2.xml
deleted file mode 100644
index f6349b7f018..00000000000
--- a/ansible/minigraph/04-ARISTA07T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA07T2
- 10.0.0.13
- str-s6000-on-3
- 10.0.0.12
- 1
- 180
- 60
-
-
- ARISTA07T2
- FC00::1A
- str-s6000-on-3
- FC00::19
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA07T2
-
-
- 10.0.0.12
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.7/32
-
- 100.1.0.7/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::7/128
-
- 2064:0100::7/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.118/24
-
- 10.255.0.118/24
-
-
-
-
-
- ARISTA07T2
-
-
-
-
-
- Ethernet1
- 10.0.0.13/31
-
-
-
- Ethernet1
- FC00::1A/126
-
-
-
- Ethernet9
- 10.10.246.7/24
-
-
-
- Ethernet9
- FC0A::E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA07T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA08T0.xml b/ansible/minigraph/04-ARISTA08T0.xml
deleted file mode 100644
index ecac4881664..00000000000
--- a/ansible/minigraph/04-ARISTA08T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T0
- 10.0.0.47
- str-s6000-on-3
- 10.0.0.46
- 1
- 180
- 60
-
-
- ARISTA08T0
- FC00::5E
- str-s6000-on-3
- FC00::5D
- 1
- 180
- 60
-
-
-
-
- 64008
- ARISTA08T0
-
-
- 10.0.0.46
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.24/32
-
- 100.1.0.24/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::18/128
-
- 2064:0100::18/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.92/24
-
- 10.255.0.92/24
-
-
-
-
-
- ARISTA08T0
-
-
-
-
-
- Ethernet1
- 10.0.0.47/31
-
-
-
- Ethernet1
- FC00::5E/126
-
-
-
- Ethernet9
- 10.10.246.24/24
-
-
-
- Ethernet9
- FC0A::31/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA08T2.xml b/ansible/minigraph/04-ARISTA08T2.xml
deleted file mode 100644
index afc56dadbfb..00000000000
--- a/ansible/minigraph/04-ARISTA08T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA08T2
- 10.0.0.15
- str-s6000-on-3
- 10.0.0.14
- 1
- 180
- 60
-
-
- ARISTA08T2
- FC00::1E
- str-s6000-on-3
- FC00::1D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA08T2
-
-
- 10.0.0.14
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.8/32
-
- 100.1.0.8/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::8/128
-
- 2064:0100::8/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.119/24
-
- 10.255.0.119/24
-
-
-
-
-
- ARISTA08T2
-
-
-
-
-
- Ethernet1
- 10.0.0.15/31
-
-
-
- Ethernet1
- FC00::1E/126
-
-
-
- Ethernet9
- 10.10.246.8/24
-
-
-
- Ethernet9
- FC0A::11/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA08T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA09T0.xml b/ansible/minigraph/04-ARISTA09T0.xml
deleted file mode 100644
index 5a92f18d454..00000000000
--- a/ansible/minigraph/04-ARISTA09T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T0
- 10.0.0.49
- str-s6000-on-3
- 10.0.0.48
- 1
- 180
- 60
-
-
- ARISTA09T0
- FC00::62
- str-s6000-on-3
- FC00::61
- 1
- 180
- 60
-
-
-
-
- 64009
- ARISTA09T0
-
-
- 10.0.0.48
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.25/32
-
- 100.1.0.25/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::19/128
-
- 2064:0100::19/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.93/24
-
- 10.255.0.93/24
-
-
-
-
-
- ARISTA09T0
-
-
-
-
-
- Ethernet1
- 10.0.0.49/31
-
-
-
- Ethernet1
- FC00::62/126
-
-
-
- Ethernet9
- 10.10.246.25/24
-
-
-
- Ethernet9
- FC0A::32/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA09T2.xml b/ansible/minigraph/04-ARISTA09T2.xml
deleted file mode 100644
index 687c9a9982d..00000000000
--- a/ansible/minigraph/04-ARISTA09T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA09T2
- 10.0.0.17
- str-s6000-on-3
- 10.0.0.16
- 1
- 180
- 60
-
-
- ARISTA09T2
- FC00::22
- str-s6000-on-3
- FC00::21
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA09T2
-
-
- 10.0.0.16
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.9/32
-
- 100.1.0.9/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::9/128
-
- 2064:0100::9/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.120/24
-
- 10.255.0.120/24
-
-
-
-
-
- ARISTA09T2
-
-
-
-
-
- Ethernet1
- 10.0.0.17/31
-
-
-
- Ethernet1
- FC00::22/126
-
-
-
- Ethernet9
- 10.10.246.9/24
-
-
-
- Ethernet9
- FC0A::12/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA09T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA10T0.xml b/ansible/minigraph/04-ARISTA10T0.xml
deleted file mode 100644
index 6a62ee16e9f..00000000000
--- a/ansible/minigraph/04-ARISTA10T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T0
- 10.0.0.51
- str-s6000-on-3
- 10.0.0.50
- 1
- 180
- 60
-
-
- ARISTA10T0
- FC00::66
- str-s6000-on-3
- FC00::65
- 1
- 180
- 60
-
-
-
-
- 64010
- ARISTA10T0
-
-
- 10.0.0.50
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.26/32
-
- 100.1.0.26/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1A/128
-
- 2064:0100::1A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.94/24
-
- 10.255.0.94/24
-
-
-
-
-
- ARISTA10T0
-
-
-
-
-
- Ethernet1
- 10.0.0.51/31
-
-
-
- Ethernet1
- FC00::66/126
-
-
-
- Ethernet9
- 10.10.246.26/24
-
-
-
- Ethernet9
- FC0A::35/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA10T2.xml b/ansible/minigraph/04-ARISTA10T2.xml
deleted file mode 100644
index 5a1028ee4fd..00000000000
--- a/ansible/minigraph/04-ARISTA10T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA10T2
- 10.0.0.19
- str-s6000-on-3
- 10.0.0.18
- 1
- 180
- 60
-
-
- ARISTA10T2
- FC00::26
- str-s6000-on-3
- FC00::25
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA10T2
-
-
- 10.0.0.18
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.10/32
-
- 100.1.0.10/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::A/128
-
- 2064:0100::A/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.121/24
-
- 10.255.0.121/24
-
-
-
-
-
- ARISTA10T2
-
-
-
-
-
- Ethernet1
- 10.0.0.19/31
-
-
-
- Ethernet1
- FC00::26/126
-
-
-
- Ethernet9
- 10.10.246.10/24
-
-
-
- Ethernet9
- FC0A::15/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA10T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA11T0.xml b/ansible/minigraph/04-ARISTA11T0.xml
deleted file mode 100644
index 1541a67a09e..00000000000
--- a/ansible/minigraph/04-ARISTA11T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T0
- 10.0.0.53
- str-s6000-on-3
- 10.0.0.52
- 1
- 180
- 60
-
-
- ARISTA11T0
- FC00::6A
- str-s6000-on-3
- FC00::69
- 1
- 180
- 60
-
-
-
-
- 64011
- ARISTA11T0
-
-
- 10.0.0.52
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.27/32
-
- 100.1.0.27/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1B/128
-
- 2064:0100::1B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.95/24
-
- 10.255.0.95/24
-
-
-
-
-
- ARISTA11T0
-
-
-
-
-
- Ethernet1
- 10.0.0.53/31
-
-
-
- Ethernet1
- FC00::6A/126
-
-
-
- Ethernet9
- 10.10.246.27/24
-
-
-
- Ethernet9
- FC0A::36/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA11T2.xml b/ansible/minigraph/04-ARISTA11T2.xml
deleted file mode 100644
index ea4920276b8..00000000000
--- a/ansible/minigraph/04-ARISTA11T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA11T2
- 10.0.0.21
- str-s6000-on-3
- 10.0.0.20
- 1
- 180
- 60
-
-
- ARISTA11T2
- FC00::2A
- str-s6000-on-3
- FC00::29
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA11T2
-
-
- 10.0.0.20
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.11/32
-
- 100.1.0.11/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::B/128
-
- 2064:0100::B/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.122/24
-
- 10.255.0.122/24
-
-
-
-
-
- ARISTA11T2
-
-
-
-
-
- Ethernet1
- 10.0.0.21/31
-
-
-
- Ethernet1
- FC00::2A/126
-
-
-
- Ethernet9
- 10.10.246.11/24
-
-
-
- Ethernet9
- FC0A::16/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA11T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA12T0.xml b/ansible/minigraph/04-ARISTA12T0.xml
deleted file mode 100644
index 9060e2ba957..00000000000
--- a/ansible/minigraph/04-ARISTA12T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T0
- 10.0.0.55
- str-s6000-on-3
- 10.0.0.54
- 1
- 180
- 60
-
-
- ARISTA12T0
- FC00::6E
- str-s6000-on-3
- FC00::6D
- 1
- 180
- 60
-
-
-
-
- 64012
- ARISTA12T0
-
-
- 10.0.0.54
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.28/32
-
- 100.1.0.28/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1C/128
-
- 2064:0100::1C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.96/24
-
- 10.255.0.96/24
-
-
-
-
-
- ARISTA12T0
-
-
-
-
-
- Ethernet1
- 10.0.0.55/31
-
-
-
- Ethernet1
- FC00::6E/126
-
-
-
- Ethernet9
- 10.10.246.28/24
-
-
-
- Ethernet9
- FC0A::39/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA12T2.xml b/ansible/minigraph/04-ARISTA12T2.xml
deleted file mode 100644
index fb7e07c4822..00000000000
--- a/ansible/minigraph/04-ARISTA12T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA12T2
- 10.0.0.23
- str-s6000-on-3
- 10.0.0.22
- 1
- 180
- 60
-
-
- ARISTA12T2
- FC00::2E
- str-s6000-on-3
- FC00::2D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA12T2
-
-
- 10.0.0.22
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.12/32
-
- 100.1.0.12/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::C/128
-
- 2064:0100::C/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.123/24
-
- 10.255.0.123/24
-
-
-
-
-
- ARISTA12T2
-
-
-
-
-
- Ethernet1
- 10.0.0.23/31
-
-
-
- Ethernet1
- FC00::2E/126
-
-
-
- Ethernet9
- 10.10.246.12/24
-
-
-
- Ethernet9
- FC0A::19/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA12T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA13T0.xml b/ansible/minigraph/04-ARISTA13T0.xml
deleted file mode 100644
index 925454fef90..00000000000
--- a/ansible/minigraph/04-ARISTA13T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T0
- 10.0.0.57
- str-s6000-on-3
- 10.0.0.56
- 1
- 180
- 60
-
-
- ARISTA13T0
- FC00::72
- str-s6000-on-3
- FC00::71
- 1
- 180
- 60
-
-
-
-
- 64013
- ARISTA13T0
-
-
- 10.0.0.56
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.29/32
-
- 100.1.0.29/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1D/128
-
- 2064:0100::1D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.97/24
-
- 10.255.0.97/24
-
-
-
-
-
- ARISTA13T0
-
-
-
-
-
- Ethernet1
- 10.0.0.57/31
-
-
-
- Ethernet1
- FC00::72/126
-
-
-
- Ethernet9
- 10.10.246.29/24
-
-
-
- Ethernet9
- FC0A::3A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA13T2.xml b/ansible/minigraph/04-ARISTA13T2.xml
deleted file mode 100644
index 93b7f9413b0..00000000000
--- a/ansible/minigraph/04-ARISTA13T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA13T2
- 10.0.0.25
- str-s6000-on-3
- 10.0.0.24
- 1
- 180
- 60
-
-
- ARISTA13T2
- FC00::32
- str-s6000-on-3
- FC00::31
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA13T2
-
-
- 10.0.0.24
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.13/32
-
- 100.1.0.13/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::D/128
-
- 2064:0100::D/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.124/24
-
- 10.255.0.124/24
-
-
-
-
-
- ARISTA13T2
-
-
-
-
-
- Ethernet1
- 10.0.0.25/31
-
-
-
- Ethernet1
- FC00::32/126
-
-
-
- Ethernet9
- 10.10.246.13/24
-
-
-
- Ethernet9
- FC0A::1A/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA13T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA14T0.xml b/ansible/minigraph/04-ARISTA14T0.xml
deleted file mode 100644
index 8d7e96b8b11..00000000000
--- a/ansible/minigraph/04-ARISTA14T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T0
- 10.0.0.59
- str-s6000-on-3
- 10.0.0.58
- 1
- 180
- 60
-
-
- ARISTA14T0
- FC00::76
- str-s6000-on-3
- FC00::75
- 1
- 180
- 60
-
-
-
-
- 64014
- ARISTA14T0
-
-
- 10.0.0.58
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.30/32
-
- 100.1.0.30/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1E/128
-
- 2064:0100::1E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.98/24
-
- 10.255.0.98/24
-
-
-
-
-
- ARISTA14T0
-
-
-
-
-
- Ethernet1
- 10.0.0.59/31
-
-
-
- Ethernet1
- FC00::76/126
-
-
-
- Ethernet9
- 10.10.246.30/24
-
-
-
- Ethernet9
- FC0A::3D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA14T2.xml b/ansible/minigraph/04-ARISTA14T2.xml
deleted file mode 100644
index b6b8991818c..00000000000
--- a/ansible/minigraph/04-ARISTA14T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA14T2
- 10.0.0.27
- str-s6000-on-3
- 10.0.0.26
- 1
- 180
- 60
-
-
- ARISTA14T2
- FC00::36
- str-s6000-on-3
- FC00::35
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA14T2
-
-
- 10.0.0.26
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.14/32
-
- 100.1.0.14/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::E/128
-
- 2064:0100::E/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.125/24
-
- 10.255.0.125/24
-
-
-
-
-
- ARISTA14T2
-
-
-
-
-
- Ethernet1
- 10.0.0.27/31
-
-
-
- Ethernet1
- FC00::36/126
-
-
-
- Ethernet9
- 10.10.246.14/24
-
-
-
- Ethernet9
- FC0A::1D/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA14T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA15T0.xml b/ansible/minigraph/04-ARISTA15T0.xml
deleted file mode 100644
index 435f3904015..00000000000
--- a/ansible/minigraph/04-ARISTA15T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T0
- 10.0.0.61
- str-s6000-on-3
- 10.0.0.60
- 1
- 180
- 60
-
-
- ARISTA15T0
- FC00::7A
- str-s6000-on-3
- FC00::79
- 1
- 180
- 60
-
-
-
-
- 64015
- ARISTA15T0
-
-
- 10.0.0.60
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.31/32
-
- 100.1.0.31/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::1F/128
-
- 2064:0100::1F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.99/24
-
- 10.255.0.99/24
-
-
-
-
-
- ARISTA15T0
-
-
-
-
-
- Ethernet1
- 10.0.0.61/31
-
-
-
- Ethernet1
- FC00::7A/126
-
-
-
- Ethernet9
- 10.10.246.31/24
-
-
-
- Ethernet9
- FC0A::3E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA15T2.xml b/ansible/minigraph/04-ARISTA15T2.xml
deleted file mode 100644
index 4422c30b31a..00000000000
--- a/ansible/minigraph/04-ARISTA15T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA15T2
- 10.0.0.29
- str-s6000-on-3
- 10.0.0.28
- 1
- 180
- 60
-
-
- ARISTA15T2
- FC00::3A
- str-s6000-on-3
- FC00::39
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA15T2
-
-
- 10.0.0.28
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.15/32
-
- 100.1.0.15/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::F/128
-
- 2064:0100::F/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.146/24
-
- 10.255.0.146/24
-
-
-
-
-
- ARISTA15T2
-
-
-
-
-
- Ethernet1
- 10.0.0.29/31
-
-
-
- Ethernet1
- FC00::3A/126
-
-
-
- Ethernet9
- 10.10.246.15/24
-
-
-
- Ethernet9
- FC0A::1E/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA15T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA16T0.xml b/ansible/minigraph/04-ARISTA16T0.xml
deleted file mode 100644
index 7d6e58d6e03..00000000000
--- a/ansible/minigraph/04-ARISTA16T0.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T0
- 10.0.0.63
- str-s6000-on-3
- 10.0.0.62
- 1
- 180
- 60
-
-
- ARISTA16T0
- FC00::7E
- str-s6000-on-3
- FC00::7D
- 1
- 180
- 60
-
-
-
-
- 64016
- ARISTA16T0
-
-
- 10.0.0.62
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.32/32
-
- 100.1.0.32/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::20/128
-
- 2064:0100::20/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.107/24
-
- 10.255.0.107/24
-
-
-
-
-
- ARISTA16T0
-
-
-
-
-
- Ethernet1
- 10.0.0.63/31
-
-
-
- Ethernet1
- FC00::7E/126
-
-
-
- Ethernet9
- 10.10.246.32/24
-
-
-
- Ethernet9
- FC0A::41/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T0
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/04-ARISTA16T2.xml b/ansible/minigraph/04-ARISTA16T2.xml
deleted file mode 100644
index 5ce8b5b43bc..00000000000
--- a/ansible/minigraph/04-ARISTA16T2.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- ARISTA16T2
- 10.0.0.31
- str-s6000-on-3
- 10.0.0.30
- 1
- 180
- 60
-
-
- ARISTA16T2
- FC00::3E
- str-s6000-on-3
- FC00::3D
- 1
- 180
- 60
-
-
-
-
- 65200
- ARISTA16T2
-
-
- 10.0.0.30
-
-
-
-
-
-
-
- 65100
- str-s6000-on-3
-
-
-
-
-
-
-
-
-
- HostIP
- Loopback0
-
- 100.1.0.16/32
-
- 100.1.0.16/32
-
-
- HostIP1
- Loopback0
-
- 2064:0100::10/128
-
- 2064:0100::10/128
-
-
-
-
- HostIP
- eth0
-
- 10.255.0.147/24
-
- 10.255.0.147/24
-
-
-
-
-
- ARISTA16T2
-
-
-
-
-
- Ethernet1
- 10.0.0.31/31
-
-
-
- Ethernet1
- FC00::3E/126
-
-
-
- Ethernet9
- 10.10.246.16/24
-
-
-
- Ethernet9
- FC0A::21/64
-
-
-
-
-
-
-
-
-
-
-
-
- ARISTA16T2
- Arista-VEOS
-
-
diff --git a/ansible/minigraph/OCPSCH0104001MS.xml b/ansible/minigraph/OCPSCH0104001MS.xml
index 769a7302d2d..50f749f9fff 100644
--- a/ansible/minigraph/OCPSCH0104001MS.xml
+++ b/ansible/minigraph/OCPSCH0104001MS.xml
@@ -352,6 +352,12 @@
Ethernet0
+
+
+ OCPSCH0104001MS
+ AS7512
+
+
diff --git a/ansible/minigraph/OCPSCH0104002MS.xml b/ansible/minigraph/OCPSCH0104002MS.xml
index 766d45dc908..37fff59f8f7 100644
--- a/ansible/minigraph/OCPSCH0104002MS.xml
+++ b/ansible/minigraph/OCPSCH0104002MS.xml
@@ -270,13 +270,13 @@
IPInterface
Ethernet24
- 10.10.2.22/30
+ 10.10.2.26/30
IPInterface
Ethernet28
- 10.10.2.22/30
+ 10.10.2.30/30
@@ -360,6 +360,12 @@
Ethernet4
+
+
+ OCPSCH0104002MS
+ ACS-MSN2700
+
+
diff --git a/ansible/minigraph/OCPSCH01040AALF.xml b/ansible/minigraph/OCPSCH01040AALF.xml
index 2506ad7944a..86d8ca1a6e6 100644
--- a/ansible/minigraph/OCPSCH01040AALF.xml
+++ b/ansible/minigraph/OCPSCH01040AALF.xml
@@ -117,6 +117,12 @@
Ethernet4
+
+
+ OCPSCH01040AALF
+ ACS-S6000
+
+
diff --git a/ansible/minigraph/OCPSCH01040BBLF.xml b/ansible/minigraph/OCPSCH01040BBLF.xml
index 465d39744d9..59be72e31bf 100644
--- a/ansible/minigraph/OCPSCH01040BBLF.xml
+++ b/ansible/minigraph/OCPSCH01040BBLF.xml
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet0
+ OCPSCH01040BBLF
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet0
+ OCPSCH01040BBLF
+ Ethernet4
+
+
+
+
+ OCPSCH01040BBLF
+ ACS-MSN2700
+
+
+
OCPSCH01040BBLF
ACS-MSN2700
diff --git a/ansible/minigraph/OCPSCH01040CCLF.xml b/ansible/minigraph/OCPSCH01040CCLF.xml
index 654b90ee2e9..ce5cb71f25f 100644
--- a/ansible/minigraph/OCPSCH01040CCLF.xml
+++ b/ansible/minigraph/OCPSCH01040CCLF.xml
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet0
+ OCPSCH01040CCLF
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet0
+ OCPSCH01040CCLF
+ Ethernet4
+
+
+
+
+ OCPSCH01040CCLF
+ ACS-CAVM
+
+
+
OCPSCH01040CCLF
ACS-CAVM
diff --git a/ansible/minigraph/OCPSCH01040DDLF.xml b/ansible/minigraph/OCPSCH01040DDLF.xml
index 1121fd97156..47efabf7d81 100644
--- a/ansible/minigraph/OCPSCH01040DDLF.xml
+++ b/ansible/minigraph/OCPSCH01040DDLF.xml
@@ -88,7 +88,7 @@
- Ethernet4
+ Ethernet1
10.10.2.13/30
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH01040DDLF
+ Ethernet0
+ OCPSCH0104012MS
+ Ethernet12
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPCH01040DDLF
+ Ethernet1
+ OCPSCH0104002MS
+ Ethernet12
+
+
+
+
+ OCPSCH01040DDLF
+ Force10-Z9100
+
+
+
OCPSCH01040DDLF
- ACS-BF
+ Force10-Z9100
diff --git a/ansible/minigraph/OCPSCH01040EELF.xml b/ansible/minigraph/OCPSCH01040EELF.xml
index cbf6e4c1dbf..59c60fccdc5 100644
--- a/ansible/minigraph/OCPSCH01040EELF.xml
+++ b/ansible/minigraph/OCPSCH01040EELF.xml
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet0
+ OCPSCH01040EELF
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet0
+ OCPSCH01040EELF
+ Ethernet4
+
+
+
+
+ OCPSCH01040EELF
+ ACS-BF
+
+
+
OCPSCH01040EELF
ACS-BF
diff --git a/ansible/minigraph/OCPSCH01040FFLF.xml b/ansible/minigraph/OCPSCH01040FFLF.xml
index 1be36e538e9..e7b9afa01b0 100644
--- a/ansible/minigraph/OCPSCH01040FFLF.xml
+++ b/ansible/minigraph/OCPSCH01040FFLF.xml
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet0
+ OCPSCH01040FFLF
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet0
+ OCPSCH01040FFLF
+ Ethernet4
+
+
+
+
+ OCPSCH01040FFLF
+ ACS-A7050-QX32
+
+
+
OCPSCH01040FFLF
ACS-A7050-QX32
diff --git a/ansible/minigraph/OCPSCH01040GGLF.xml b/ansible/minigraph/OCPSCH01040GGLF.xml
index ad56373bdac..978577e5443 100644
--- a/ansible/minigraph/OCPSCH01040GGLF.xml
+++ b/ansible/minigraph/OCPSCH01040GGLF.xml
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet0
+ OCPSCH01040GGLF
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet0
+ OCPSCH01040GGLF
+ Ethernet4
+
+
+
+
+ OCPSCH01040GGLF
+ ACS-BF
+
+
+
OCPSCH01040GGLF
ACS-BF
diff --git a/ansible/minigraph/OCPSCH01040HHLF.xml b/ansible/minigraph/OCPSCH01040HHLF.xml
index f643cb3955e..ba223330b9e 100644
--- a/ansible/minigraph/OCPSCH01040HHLF.xml
+++ b/ansible/minigraph/OCPSCH01040HHLF.xml
@@ -98,6 +98,32 @@
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet0
+ OCPSCH01040HHLF
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet0
+ OCPSCH01040HHLF
+ Ethernet4
+
+
+
+
+ OCPSCH01040HHLF
+ ACS-BF
+
+
+
OCPSCH01040HHLF
ACS-BF
diff --git a/ansible/minigraph/switch-t0.xml b/ansible/minigraph/switch-t0.xml
new file mode 100644
index 00000000000..413aedf7e23
--- /dev/null
+++ b/ansible/minigraph/switch-t0.xml
@@ -0,0 +1,315 @@
+
+
+
+
+
+ false
+ switch-t0
+ 10.0.0.56
+ ARISTA01T1
+ 10.0.0.57
+ 1
+ 180
+ 60
+
+
+ switch-t0
+ FC00::71
+ ARISTA01T1
+ FC00::72
+ 1
+ 180
+ 60
+
+
+ false
+ switch-t0
+ 10.0.0.58
+ ARISTA02T1
+ 10.0.0.59
+ 1
+ 180
+ 60
+
+
+ switch-t0
+ FC00::75
+ ARISTA02T1
+ FC00::76
+ 1
+ 180
+ 60
+
+
+ false
+ switch-t0
+ 10.0.0.60
+ ARISTA03T1
+ 10.0.0.61
+ 1
+ 180
+ 60
+
+
+ switch-t0
+ FC00::79
+ ARISTA03T1
+ FC00::7A
+ 1
+ 180
+ 60
+
+
+ false
+ switch-t0
+ 10.0.0.62
+ ARISTA04T1
+ 10.0.0.63
+ 1
+ 180
+ 60
+
+
+ switch-t0
+ FC00::7D
+ ARISTA04T1
+ FC00::7E
+ 1
+ 180
+ 60
+
+
+
+
+ 65100
+ switch-t0
+
+
+ 10.0.0.57
+
+
+
+
+
+ 10.0.0.59
+
+
+
+
+
+ 10.0.0.61
+
+
+
+
+
+ 10.0.0.63
+
+
+
+
+
+
+
+
+ 64600
+ ARISTA01T1
+
+
+
+ 64600
+ ARISTA02T1
+
+
+
+ 64600
+ ARISTA03T1
+
+
+
+ 64600
+ ARISTA04T1
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::32/128
+
+ FC00:1::32/128
+
+
+
+
+ HostIP
+ eth0
+
+ 10.0.0.100/24
+
+ 10.0.0.100/24
+
+
+
+
+
+
+ switch-t0
+
+
+ PortChannel01
+ fortyGigE0/112
+
+
+
+ PortChannel02
+ fortyGigE0/116
+
+
+
+ PortChannel03
+ fortyGigE0/120
+
+
+
+ PortChannel04
+ fortyGigE0/124
+
+
+
+
+
+ Vlan1000
+ fortyGigE0/4;fortyGigE0/8;fortyGigE0/12;fortyGigE0/16;fortyGigE0/20;fortyGigE0/24;fortyGigE0/28;fortyGigE0/32;fortyGigE0/36;fortyGigE0/40;fortyGigE0/44;fortyGigE0/48;fortyGigE0/52;fortyGigE0/56;fortyGigE0/60;fortyGigE0/64;fortyGigE0/68;fortyGigE0/72;fortyGigE0/76;fortyGigE0/80;fortyGigE0/84;fortyGigE0/88;fortyGigE0/92;fortyGigE0/96
+ False
+ 0.0.0.0/0
+
+ 1000
+ 1000
+ 192.168.0.0/27
+
+
+
+
+
+ PortChannel01
+ 10.0.0.56/31
+
+
+
+ PortChannel01
+ FC00::71/126
+
+
+
+ PortChannel02
+ 10.0.0.58/31
+
+
+
+ PortChannel02
+ FC00::75/126
+
+
+
+ PortChannel03
+ 10.0.0.60/31
+
+
+
+ PortChannel03
+ FC00::79/126
+
+
+
+ PortChannel04
+ 10.0.0.62/31
+
+
+
+ PortChannel04
+ FC00::7D/126
+
+
+
+ Vlan1000
+ 192.168.0.1/27
+
+
+
+
+
+
+
+
+
+
+
+ DeviceInterfaceLink
+ ARISTA01T1
+ Ethernet1/1
+ switch-t0
+ fortyGigE0/112
+
+
+ DeviceInterfaceLink
+ ARISTA02T1
+ Ethernet1/1
+ switch-t0
+ fortyGigE0/116
+
+
+ DeviceInterfaceLink
+ ARISTA03T1
+ Ethernet1/1
+ switch-t0
+ fortyGigE0/120
+
+
+ DeviceInterfaceLink
+ ARISTA04T1
+ Ethernet1/1
+ switch-t0
+ fortyGigE0/124
+
+
+
+
+ switch-t0
+ Force10-S6000
+
+
+ ARISTA01T1
+ Arista
+
+
+ ARISTA02T1
+ Arista
+
+
+ ARISTA03T1
+ Arista
+
+
+ ARISTA04T1
+ Arista
+
+
+
+ switch-t0
+ Force10-S6000
+
diff --git a/ansible/minigraph/switch1.xml b/ansible/minigraph/switch1.xml
index f585f142730..4771c9a0427 100644
--- a/ansible/minigraph/switch1.xml
+++ b/ansible/minigraph/switch1.xml
@@ -1045,6 +1045,12 @@
Ethernet1
+
+
+ switch1
+ Force10-S6000
+
+
switch1
Force10-S6000
diff --git a/ansible/minigraph/switch2.xml b/ansible/minigraph/switch2.xml
index 61d383cc10e..1e42e638f63 100644
--- a/ansible/minigraph/switch2.xml
+++ b/ansible/minigraph/switch2.xml
@@ -1045,6 +1045,12 @@
Ethernet1
+
+
+ switch2
+ ACS-MSN2700
+
+
switch2
ACS-MSN2700
diff --git a/ansible/minigraph/switch3.xml b/ansible/minigraph/switch3.xml
index e1025643513..acd1416fdfb 100644
--- a/ansible/minigraph/switch3.xml
+++ b/ansible/minigraph/switch3.xml
@@ -910,6 +910,12 @@
Ethernet1
+
+
+ switch3
+ Force10-S6000
+
+
switch3
Force10-S6000
diff --git a/ansible/minigraph/switch5.xml b/ansible/minigraph/switch5.xml
index 14ac242f9fe..e3754462b89 100644
--- a/ansible/minigraph/switch5.xml
+++ b/ansible/minigraph/switch5.xml
@@ -1262,6 +1262,12 @@
Ethernet1
+
+
+ switch5
+ ACS-MSN2700
+
+
switch5
ACS-MSN2700
diff --git a/ansible/minigraph/t0-64-32.xml b/ansible/minigraph/t0-64-32.xml
new file mode 100644
index 00000000000..8bc775cfb12
--- /dev/null
+++ b/ansible/minigraph/t0-64-32.xml
@@ -0,0 +1,585 @@
+
+
+
+
+
+ ARISTA01T1
+ 10.0.0.1
+ t0-64-32
+ 10.0.0.0
+ 1
+ 180
+ 60
+
+
+ ARISTA02T1
+ 10.0.0.5
+ t0-64-32
+ 10.0.0.4
+ 1
+ 180
+ 60
+
+
+ ARISTA03T1
+ 10.0.0.9
+ t0-64-32
+ 10.0.0.8
+ 1
+ 180
+ 60
+
+
+ ARISTA04T1
+ 10.0.0.13
+ t0-64-32
+ 10.0.0.12
+ 1
+ 180
+ 60
+
+
+ ARISTA01T1
+ FC00::2
+ t0-64-32
+ FC00::1
+ 1
+ 180
+ 60
+
+
+ ARISTA02T1
+ FC00::A
+ t0-64-32
+ FC00::9
+ 1
+ 180
+ 60
+
+
+ ARISTA03T1
+ FC00::12
+ t0-64-32
+ FC00::11
+ 1
+ 180
+ 60
+
+
+ ARISTA04T1
+ FC00::1A
+ t0-64-32
+ FC00::19
+ 1
+ 180
+ 60
+
+
+
+
+ 64601
+ t0-64-32
+
+
+ BGPPeer
+ 10.0.0.1
+
+
+
+
+
+ BGPPeer
+ 10.0.0.5
+
+
+
+
+
+ BGPPeer
+ 10.0.0.9
+
+
+
+
+
+ BGPPeer
+ 10.0.0.13
+
+
+
+
+
+ BGPPeer
+ FC00::2
+
+
+
+
+
+ BGPPeer
+ FC00::A
+
+
+
+
+
+ BGPPeer
+ FC00::12
+
+
+
+
+
+ BGPPeer
+ FC00::1A
+
+
+
+
+
+
+
+
+ 64802
+ ARISTA01T1
+
+
+
+ 64802
+ ARISTA02T1
+
+
+
+ 64802
+ ARISTA03T1
+
+
+
+ 64802
+ ARISTA04T1
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.33/32
+
+ 10.1.0.33/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::33/128
+
+ FC00:1::33/128
+
+
+
+
+ HostIP
+ eth0
+
+ 10.250.0.113/23
+
+ 10.250.0.113/23
+
+
+
+
+
+ t0-64-32
+
+
+ PortChannelInterface
+ PortChannel1
+ fortyGigE0/0;fortyGigE0/4
+
+
+
+ PortChannelInterface
+ PortChannel4
+ fortyGigE0/16;fortyGigE0/20
+
+
+
+ PortChannelInterface
+ PortChannel16
+ fortyGigE0/64;fortyGigE0/68
+
+
+
+ PortChannelInterface
+ PortChannel20
+ fortyGigE0/80;fortyGigE0/84
+
+
+
+
+
+ VlanInterface
+ Vlan2
+ fortyGigE0/24;fortyGigE0/28;fortyGigE0/32;fortyGigE0/40;fortyGigE0/44;fortyGigE0/48;fortyGigE0/52;fortyGigE0/56;fortyGigE0/60;fortyGigE0/88;fortyGigE0/92;fortyGigE0/96;fortyGigE0/100;fortyGigE0/104;fortyGigE0/108;fortyGigE0/112;fortyGigE0/116;fortyGigE0/120;fortyGigE0/124
+ False
+ 0.0.0.0/0
+
+ 2
+ 2
+ 172.0.0.0/26
+
+
+
+
+ IPInterface
+
+ PortChannel1
+ 10.0.0.0/31
+
+
+ IPInterface
+
+ PortChannel4
+ 10.0.0.4/31
+
+
+ IPInterface
+
+ PortChannel16
+ 10.0.0.8/31
+
+
+ IPInterface
+
+ PortChannel20
+ 10.0.0.12/31
+
+
+ IPInterface
+
+ PortChannel1
+ FC00::1/126
+
+
+ IPInterface
+
+ PortChannel4
+ FC00::9/126
+
+
+ IPInterface
+
+ PortChannel16
+ FC00::11/126
+
+
+ IPInterface
+
+ PortChannel20
+ FC00::19/126
+
+
+ IPInterface
+
+ Vlan2
+ 172.0.0.1/26
+
+
+
+
+
+
+
+
+
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA01T1
+ Ethernet1
+ true
+ t0-64-32
+ fortyGigE0/0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA01T1
+ Ethernet2
+ true
+ t0-64-32
+ fortyGigE0/4
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA02T1
+ Ethernet1
+ true
+ t0-64-32
+ fortyGigE0/16
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA02T1
+ Ethernet2
+ true
+ t0-64-32
+ fortyGigE0/20
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA03T1
+ Ethernet1
+ true
+ t0-64-32
+ fortyGigE0/64
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA03T1
+ Ethernet2
+ true
+ t0-64-32
+ fortyGigE0/68
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA04T1
+ Ethernet1
+ true
+ t0-64-32
+ fortyGigE0/80
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA04T1
+ Ethernet2
+ true
+ t0-64-32
+ fortyGigE0/84
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/24
+ true
+ server-01
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/28
+ true
+ server-02
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/32
+ true
+ server-03
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/40
+ true
+ server-05
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/44
+ true
+ server-06
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/48
+ true
+ server-07
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/52
+ true
+ server-08
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/56
+ true
+ server-09
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/60
+ true
+ server-10
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/88
+ true
+ server-19
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/92
+ true
+ server-20
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/96
+ true
+ server-21
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/100
+ true
+ server-22
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/104
+ true
+ server-23
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/108
+ true
+ server-24
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/112
+ true
+ server-25
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/116
+ true
+ server-26
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/120
+ true
+ server-27
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64-32
+ fortyGigE0/124
+ true
+ server-28
+ 0
+
+
+
+
+ t0-64-32
+ Force10-S6000
+
+ 10.250.0.113
+
+
+
+
+ t0-64-32
+ Force10-S6000
+
diff --git a/ansible/minigraph/t0-64.xml b/ansible/minigraph/t0-64.xml
new file mode 100644
index 00000000000..8b5f9fa7f10
--- /dev/null
+++ b/ansible/minigraph/t0-64.xml
@@ -0,0 +1,755 @@
+
+
+
+
+
+ ARISTA01T1
+ 10.0.0.1
+ t0-64
+ 10.0.0.0
+ 1
+ 180
+ 60
+
+
+ ARISTA02T1
+ 10.0.0.5
+ t0-64
+ 10.0.0.4
+ 1
+ 180
+ 60
+
+
+ ARISTA03T1
+ 10.0.0.9
+ t0-64
+ 10.0.0.8
+ 1
+ 180
+ 60
+
+
+ ARISTA04T1
+ 10.0.0.13
+ t0-64
+ 10.0.0.12
+ 1
+ 180
+ 60
+
+
+ ARISTA01T1
+ FC00::2
+ t0-64
+ FC00::1
+ 1
+ 180
+ 60
+
+
+ ARISTA02T1
+ FC00::A
+ t0-64
+ FC00::9
+ 1
+ 180
+ 60
+
+
+ ARISTA03T1
+ FC00::12
+ t0-64
+ FC00::11
+ 1
+ 180
+ 60
+
+
+ ARISTA04T1
+ FC00::1A
+ t0-64
+ FC00::19
+ 1
+ 180
+ 60
+
+
+
+
+ 64601
+ t0-64
+
+
+ BGPPeer
+ 10.0.0.1
+
+
+
+
+
+ BGPPeer
+ 10.0.0.5
+
+
+
+
+
+ BGPPeer
+ 10.0.0.9
+
+
+
+
+
+ BGPPeer
+ 10.0.0.13
+
+
+
+
+
+ BGPPeer
+ FC00::2
+
+
+
+
+
+ BGPPeer
+ FC00::A
+
+
+
+
+
+ BGPPeer
+ FC00::12
+
+
+
+
+
+ BGPPeer
+ FC00::1A
+
+
+
+
+
+
+
+
+ 64802
+ ARISTA01T1
+
+
+
+ 64802
+ ARISTA02T1
+
+
+
+ 64802
+ ARISTA03T1
+
+
+
+ 64802
+ ARISTA04T1
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::32/128
+
+ FC00:1::32/128
+
+
+
+
+ HostIP
+ eth0
+
+ 10.251.0.243/23
+
+ 10.251.0.243/23
+
+
+
+
+
+ t0-64
+
+
+ PortChannelInterface
+ PortChannel1
+ fortyGigE1/1/1;fortyGigE1/1/2
+
+
+
+ PortChannelInterface
+ PortChannel4
+ fortyGigE1/1/5;fortyGigE1/1/6
+
+
+
+ PortChannelInterface
+ PortChannel16
+ fortyGigE1/2/1;fortyGigE1/2/2
+
+
+
+ PortChannelInterface
+ PortChannel20
+ fortyGigE1/2/5;fortyGigE1/2/6
+
+
+
+
+
+ VlanInterface
+ Vlan2
+ fortyGigE1/1/7;fortyGigE1/1/8;fortyGigE1/1/9;fortyGigE1/1/10;fortyGigE1/1/11;fortyGigE1/1/12;fortyGigE1/1/13;fortyGigE1/1/14;fortyGigE1/1/15;fortyGigE1/1/16;fortyGigE1/3/1;fortyGigE1/3/5;fortyGigE1/3/6;fortyGigE1/3/7;fortyGigE1/3/8;fortyGigE1/3/9;fortyGigE1/3/10;fortyGigE1/3/11;fortyGigE1/2/7;fortyGigE1/2/8;fortyGigE1/2/9;fortyGigE1/2/10;fortyGigE1/2/11;fortyGigE1/2/12;fortyGigE1/2/13;fortyGigE1/2/14;fortyGigE1/2/15;fortyGigE1/2/16;fortyGigE1/4/1;fortyGigE1/4/5;fortyGigE1/4/6;fortyGigE1/4/7;fortyGigE1/4/8;fortyGigE1/4/9;fortyGigE1/4/10;fortyGigE1/4/11
+ False
+ 0.0.0.0/0
+
+ 2
+ 2
+ 172.0.0.0/26
+
+
+
+
+ IPInterface
+
+ PortChannel1
+ 10.0.0.0/31
+
+
+ IPInterface
+
+ PortChannel4
+ 10.0.0.4/31
+
+
+ IPInterface
+
+ PortChannel16
+ 10.0.0.8/31
+
+
+ IPInterface
+
+ PortChannel20
+ 10.0.0.12/31
+
+
+ IPInterface
+
+ PortChannel1
+ FC00::1/126
+
+
+ IPInterface
+
+ PortChannel4
+ FC00::9/126
+
+
+ IPInterface
+
+ PortChannel16
+ FC00::11/126
+
+
+ IPInterface
+
+ PortChannel20
+ FC00::19/126
+
+
+ IPInterface
+
+ Vlan2
+ 172.0.0.1/26
+
+
+
+
+
+
+
+
+
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA01T1
+ Ethernet1
+ true
+ t0-64
+ fortyGigE1/1/1
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA01T1
+ Ethernet2
+ true
+ t0-64
+ fortyGigE1/1/2
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA02T1
+ Ethernet1
+ true
+ t0-64
+ fortyGigE1/1/5
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA02T1
+ Ethernet2
+ true
+ t0-64
+ fortyGigE1/1/6
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA03T1
+ Ethernet1
+ true
+ t0-64
+ fortyGigE1/2/1
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA03T1
+ Ethernet2
+ true
+ t0-64
+ fortyGigE1/2/2
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA04T1
+ Ethernet1
+ true
+ t0-64
+ fortyGigE1/2/5
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ ARISTA04T1
+ Ethernet2
+ true
+ t0-64
+ fortyGigE1/2/6
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/7
+ true
+ server-01
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/8
+ true
+ server-02
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/9
+ true
+ server-03
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/10
+ true
+ server-04
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/11
+ true
+ server-05
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/12
+ true
+ server-06
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/13
+ true
+ server-07
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/14
+ true
+ server-08
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/15
+ true
+ server-09
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/1/16
+ true
+ server-10
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/1
+ true
+ server-11
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/5
+ true
+ server-12
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/6
+ true
+ server-13
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/7
+ true
+ server-14
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/8
+ true
+ server-15
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/9
+ true
+ server-16
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/10
+ true
+ server-17
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/3/11
+ true
+ server-18
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/7
+ true
+ server-19
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/8
+ true
+ server-20
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/9
+ true
+ server-21
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/10
+ true
+ server-22
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/11
+ true
+ server-23
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/12
+ true
+ server-24
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/13
+ true
+ server-25
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/14
+ true
+ server-26
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/15
+ true
+ server-27
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/2/16
+ true
+ server-28
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/1
+ true
+ server-29
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/5
+ true
+ server-30
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/6
+ true
+ server-31
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/7
+ true
+ server-32
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/8
+ true
+ server-33
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/9
+ true
+ server-34
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/10
+ true
+ server-35
+ 0
+
+
+ DeviceInterfaceLink
+ true
+ 40000
+ t0-64
+ fortyGigE1/4/11
+ true
+ server-36
+ 0
+
+
+
+
+ t0-64
+ Force10-S6100
+
+ 10.251.0.243
+
+
+
+
+ t0-64
+ Force10-S6100
+
diff --git a/ansible/action_plugins/switch.py b/ansible/plugins/action/apswitch.py
similarity index 99%
rename from ansible/action_plugins/switch.py
rename to ansible/plugins/action/apswitch.py
index b957a15e2c4..28c9229e40e 100644
--- a/ansible/action_plugins/switch.py
+++ b/ansible/plugins/action/apswitch.py
@@ -56,3 +56,4 @@ def run(self, tmp=None, task_vars=None):
timeout=_timeout)
return result
+
diff --git a/ansible/connection_plugins/switch.py b/ansible/plugins/connection/switch.py
similarity index 91%
rename from ansible/connection_plugins/switch.py
rename to ansible/plugins/connection/switch.py
index a06f302edd4..47e25db26ac 100644
--- a/ansible/connection_plugins/switch.py
+++ b/ansible/plugins/connection/switch.py
@@ -93,17 +93,28 @@ def _spawn_connect(self):
if attempt == len(self.login['user']):
raise AnsibleError("none of the passwords in the book works")
- self.hname = client.before.split()[-1]
- self.hname = self.hname.replace("(", "[(]")
- self.hname = self.hname.replace(")", "[)]")
+ self.before_backup = client.before.split()
# determine the sku
- client.sendline('show version | no-more')
+ client.sendline('show version')
client.expect(['#', '>'])
if 'Arista' in client.before:
self.sku = 'eos'
elif 'Cisco' in client.before:
self.sku = 'nxos'
+ if 'MLNX-OS' in client.before:
+ self.sku = 'mlnx_os'
+
+ if self.sku == 'mlnx_os':
+ self.hname = ' '.join(self.before_backup[-3:])
+ self.hname = self.hname.replace("(", "[(]")
+ self.hname = self.hname.replace(")", "[)]")
+ self.hname = self.hname.replace("]", "\]")
+ self.hname = self.hname.replace("[", "\[")
+ else:
+ self.hname = self.before_backup[-1]
+ self.hname = self.hname.replace("(", "[(]")
+ self.hname = self.hname.replace(")", "[)]")
if i == 0 and self.enable:
attempt = 0
@@ -182,7 +193,7 @@ def exec_command(self, *args, **kwargs):
# "%s(\([a-z\-]+\))?#": privileged prompt including configure mode
# Prompt includes Login, Password, and yes/no for "start shell" case in Dell FTOS (launch bash shell)
if not self.bash:
- prompts = ["%s>" % self.hname, "%s(\([a-zA-Z0-9\/\-]+\))?#" % self.hname, '[Ll]ogin:', '[Pp]assword:', '\[(confirm )?yes\/no\]:', '\(y\/n\)\??\s?\[n\]']
+ prompts = ["%s>" % self.hname, "%s.+" % self.hname, "%s(\([a-zA-Z0-9\/\-]+\))?#" % self.hname, '[Ll]ogin:', '[Pp]assword:', '\[(confirm )?yes\/no\]:', '\(y\/n\)\??\s?\[n\]']
else:
if self.sku == 'nxos':
# bash-3.2$ for nexus 6.5
diff --git a/ansible/plugins/filter/filters.py b/ansible/plugins/filter/filters.py
new file mode 100644
index 00000000000..4bf39421c20
--- /dev/null
+++ b/ansible/plugins/filter/filters.py
@@ -0,0 +1,149 @@
+from ansible import errors
+from math import log
+
+class FilterModule(object):
+ def filters(self):
+ return {
+ 'extract_by_prefix': extract_by_prefix,
+ 'filter_by_prefix': filter_by_prefix,
+ 'filter_vm_targets': filter_vm_targets,
+ 'extract_hostname': extract_hostname,
+ }
+
+def extract_by_prefix(values, prefix):
+ """
+ This function takes a list as 'values' parameter and extract a first value from the list which contains prefix.
+ The prefix is defined in parameter 'prefix'
+ """
+ if values is None:
+ raise errors.AnsibleFilterError('Values is not provided')
+
+ if prefix is None:
+ raise errors.AnsibleFilterError('Prefix is not provided')
+
+ if not isinstance(values, list):
+ raise errors.AnsibleFilterError('Wrong type for values')
+
+ if not isinstance(prefix, str):
+ raise errors.AnsibleFilterError('Wrong type for the prefix')
+
+ if len(values) == 0:
+ raise errors.AnsibleFilterError('Empty list. Nothing to extract')
+
+ for v in values:
+ if v.startswith(prefix):
+ return v
+
+ raise errors.AnsibleFilterError('Value not found')
+
+def filter_by_prefix(values, prefix):
+ """
+ This function takes a list as 'values' parameter and filters out all list values which contain prefix.
+ The prefix is defined in parameter 'prefix'
+ """
+ if values is None:
+ raise errors.AnsibleFilterError('Values is not provided')
+
+ if prefix is None:
+ raise errors.AnsibleFilterError('Prefix is not provided')
+
+ if not isinstance(values, list):
+ raise errors.AnsibleFilterError('Wrong type for values')
+
+ if not isinstance(prefix, str):
+ raise errors.AnsibleFilterError('Wrong type for the prefix')
+
+ return filter(lambda x: x.startswith(prefix), values)
+
+
+def filter_vm_targets(values, topology, vm_base):
+ """
+ This function takes a list of host VMs as parameter 'values' and then extract a list of host VMs
+ which starts with 'vm_base' and contains all VMs which mentioned in 'vm_offset' keys inside of 'topology' structure
+ """
+ if values is None:
+ raise errors.AnsibleFilterError('Values is not provided')
+
+ if topology is None:
+ raise errors.AnsibleFilterError('topology is not provided')
+
+ if vm_base is None:
+ raise errors.AnsibleFilterError('vm_base is not provided')
+
+ if not isinstance(values, list):
+ raise errors.AnsibleFilterError('Wrong type for values')
+
+ if not isinstance(topology, dict):
+ raise errors.AnsibleFilterError('Wrong type for the topology')
+
+ if not isinstance(vm_base, str) and not isinstance(vm_base, unicode):
+ raise errors.AnsibleFilterError('Wrong type for the vm_base')
+
+ if vm_base not in values:
+ raise errors.AnsibleFilterError('Current vm_base: %s is not found in vm_list' % vm_base)
+
+ result = []
+ base = values.index(vm_base)
+ for hostname, attr in topology.iteritems():
+ result.append(values[base + attr['vm_offset']])
+
+ return result
+
+def extract_hostname(values, topology, vm_base, inventory_hostname):
+ """
+ This function takes a list of host VMs as parameter 'values' and then return 'inventory_hostname'
+ corresponding EOS hostname based on 'topology' structure, 'vm_base' parameters
+ """
+ if values is None:
+ raise errors.AnsibleFilterError('Values is not provided')
+
+ if topology is None:
+ raise errors.AnsibleFilterError('topology is not provided')
+
+ if vm_base is None:
+ raise errors.AnsibleFilterError('vm_base is not provided')
+
+ if inventory_hostname is None:
+ raise errors.AnsibleFilterError('inventory_hostname is not provided')
+
+ if not isinstance(values, list):
+ raise errors.AnsibleFilterError('Wrong type for values')
+
+ if not isinstance(topology, dict):
+ raise errors.AnsibleFilterError('Wrong type for the topology')
+
+ if not isinstance(vm_base, str) and not isinstance(vm_base, unicode):
+ raise errors.AnsibleFilterError('Wrong type for the vm_base')
+
+ if not isinstance(inventory_hostname, str) and not isinstance(inventory_hostname, unicode):
+ raise errors.AnsibleFilterError('Wrong type for the inventor_hostname')
+
+ if vm_base not in values:
+ raise errors.AnsibleFilterError('Current vm_base: %s is not found in vm_list' % vm_base)
+
+ hash = {}
+ base = values.index(vm_base)
+ for hostname, attr in topology.iteritems():
+ if inventory_hostname == values[base + attr['vm_offset']]:
+ return hostname
+
+ return "hostname not found" # This string should not be used as valid hostname
+
+def log(value, base):
+ """
+ This function returns the logarithm of 'value' to the given base 'base'
+ """
+ if value is None:
+ raise errors.AnsibleFilterError('value is not provided')
+
+ if base is None:
+ raise errors.AnsibleFilterError('base is not provided')
+
+ if not isinstance(value, int):
+ raise errors.AnsibleFilterError('Wrong type for value')
+
+ if not isinstance(base, int):
+ raise errors.AnsibleFilterError('Wrong type for base')
+
+ return math.log(value, base)
+
diff --git a/ansible/renumber_vm_set.yml b/ansible/renumber_vm_set.yml
deleted file mode 100644
index d366def14b3..00000000000
--- a/ansible/renumber_vm_set.yml
+++ /dev/null
@@ -1,19 +0,0 @@
----
-# This Playbook renumber a vm set. See details about vm sets in start_vm_sets.yml
-#
-# To renumber second vm set to new vlan range on the second server
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos renumber_vm_set.yml --vault-password-file=~/.password --limit server_2 -e vm_set_2=true -e vm_2_vlan_base=233
-
-- hosts: servers:&vm_host
- gather_facts: yes
- become: true
- vars:
- vm_set_1: false
- vm_set_2: false
- vars_files:
- - vars/azure_storage.yml
- pre_tasks:
- roles:
- - { role: vm_set, action: 'renumber', id: 1, VMs: "{{ VMs_1 }}", vlan_base: "{{ vm_1_vlan_base }}", when: vm_set_1 and vm_1_enabled }
- - { role: vm_set, action: 'renumber', id: 2, VMs: "{{ VMs_2 }}", vlan_base: "{{ vm_2_vlan_base }}", when: vm_set_2 and vm_2_enabled }
-
diff --git a/ansible/roles/eos/handlers/main.yml b/ansible/roles/eos/handlers/main.yml
index 94214ba21fd..ddd945ccf1b 100644
--- a/ansible/roles/eos/handlers/main.yml
+++ b/ansible/roles/eos/handlers/main.yml
@@ -1,6 +1,3 @@
----
-# Handlers for acs
-
- name: Restart the box
command: /sbin/shutdown -r now "Ansible updates triggered"
diff --git a/ansible/roles/eos/tasks/main.yml b/ansible/roles/eos/tasks/main.yml
index dc47d80357f..9ff055ed587 100644
--- a/ansible/roles/eos/tasks/main.yml
+++ b/ansible/roles/eos/tasks/main.yml
@@ -1,24 +1,16 @@
-# Gather minigraph facts
-- name: Gathering minigraph facts about the device
- minigraph_facts: host={{ hostname }} filename={{ filename }}
- connection: local
- tags: always
-
- name: copy boot-config
copy: src=boot-config
dest=/mnt/flash/boot-config
-- name: build spine startup config
- template: src=spine.j2
- dest=/mnt/flash/startup-config
- when: swrole == "spine"
- notify:
- - Restart the box
+- name: Expand {{ hostname }} properties into props
+ set_fact: props="{{ configuration_properties[item] | combine(props | default({})) }}"
+ with_items: properties_list
+ when: hostname in configuration and configuration_properties[item] is defined
-- name: build tor startup config
- template: src=tor.j2
+- name: build a startup config
+ template: src="{{ topo }}-{{ props.swrole }}.j2"
dest=/mnt/flash/startup-config
- when: swrole == "tor"
+ when: configuration is defined
notify:
- Restart the box
diff --git a/ansible/roles/eos/templates/spine.j2 b/ansible/roles/eos/templates/spine.j2
deleted file mode 100644
index e2003648d8e..00000000000
--- a/ansible/roles/eos/templates/spine.j2
+++ /dev/null
@@ -1,115 +0,0 @@
-hostname {{ hostname }}
-!
-spanning-tree mode mstp
-!
-aaa root secret 0 123456
-!
-username admin privilege 15 role network-admin secret 0 123456
-!
-clock timezone UTC
-!
-lldp run
-lldp management-address Management1
-!
-snmp-server community {{ snmp_rocommunity }} ro
-!
-ip routing
-ipv6 unicast-routing
-!
-ip route 0.0.0.0/0 {{ minigraph_mgmt_interface["gwaddr"] }}
-
-route-map DEFAULT_ROUTES permit
-!
-{% for podset in range(0, podset_number) %}
-{% for tor in range(0, tor_number) %}
-{% for subnet in range(0, tor_subnet_number) %}
-ip route 192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {{ nhipv4 }}
-ipv6 route 20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {{ nhipv6 }}
-{% endfor %}
-{% endfor %}
-{% endfor %}
-!
-{% for podset in range(0, podset_number) %}
-{% for tor in range(0, tor_number) %}
-ip prefix-list test_ipv4_{{ podset}}_{{ tor }} seq 10 permit 192.168.{{ podset }}.{{ tor * 16 }}/28 ge 28
-ipv6 prefix-list test_ipv6_{{ podset}}_{{ tor }}
- seq 10 permit 20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16) }}::/60 ge 60
-exit
-{% endfor %}
-{% endfor %}
-!
-interface Management 1
- description TO LAB MGMT SWITCH
- ip address {{ minigraph_mgmt_interface["addr"] }} {{ minigraph_mgmt_interface["mask"] }}
- no shutdown
-!
-{% for lo in minigraph_lo_interfaces %}
-interface {{ lo['name'] }}
- description LOOPBACK
-{% if lo['addr'] | ipv4 %}
- ip address {{ lo['addr'] }}/{{ lo['prefixlen'] }}
-{% elif lo['addr'] | ipv6 %}
- ipv6 enable
- ipv6 address {{ lo['addr'] }}/{{ lo['prefixlen'] }}
- ipv6 nd ra suppress
-{% endif %}
- no shutdown
-{% endfor %}
-!
-{% for iface in minigraph_interfaces %}
-interface {{ iface['name'] }}
- no switchport
-{% if iface['addr'] | ipv4 %}
- ip address {{ iface['addr'] }} {{ iface['mask'] }}
-{% elif iface['addr'] | ipv6 %}
- ipv6 enable
- ipv6 address {{ iface['addr'] }}/{{ iface['mask'] }}
- ipv6 nd ra suppress
-{% endif %}
- no shutdown
-!
-{% endfor %}
-!
-{% for podset in range(0, podset_number) %}
-{% if range(0, 1000)|random() >= failure_rate %}
-{% for tor in range(0, tor_number) %}
-{% set leafasn = leaf_asn_start + podset %}
-{% set torasn = tor_asn_start + tor %}
-route-map PREPENDAS permit {{ 2 * (podset * tor_number + tor + 1) }}
- match ip address prefix-list test_ipv4_{{ podset }}_{{ tor }}
- set as-path prepend {{ leafasn }} {{ torasn }}
-!
-route-map PREPENDAS permit {{ 2 * (podset * tor_number + tor + 1) + 1 }}
- match ipv6 address prefix-list test_ipv6_{{ podset }}_{{ tor }}
- set as-path prepend {{ leafasn }} {{ torasn }}
-!
-{% endfor %}
-{% endif %}
-{% endfor %}
-!
-router bgp {{ minigraph_bgp_asn }}
- router-id {{ minigraph_lo_interfaces[0]['addr'] }}
- !
-{% for neighbor in minigraph_bgp %}
- neighbor {{ neighbor["addr"] }} remote-as {{ neighbor["asn"] }}
- neighbor {{ neighbor["addr"] }} description {{ neighbor["asn"]}}
- neighbor {{ neighbor["addr"] }} default-originate route-map DEFAULT_ROUTES
-{% if neighbor["addr"] | ipv6 %}
- address-family ipv6
- neighbor {{ neighbor["addr"] }} activate
- exit
-{% endif %}
-{% endfor %}
- !
-{% for lo in minigraph_lo_interfaces %}
- network {{ lo['addr'] }}/{{ lo['prefixlen'] }}
-{% endfor %}
- redistribute static route-map PREPENDAS
-!
-management api http-commands
- no protocol https
- protocol http
- no shutdown
-!
-end
-
diff --git a/ansible/roles/eos/templates/t0-64-32-leaf.j2 b/ansible/roles/eos/templates/t0-64-32-leaf.j2
new file mode 100644
index 00000000000..f7a21f4d8b6
--- /dev/null
+++ b/ansible/roles/eos/templates/t0-64-32-leaf.j2
@@ -0,0 +1,157 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+route-map DEFAULT_ROUTES permit
+!
+{# #}
+{# NOTE: Using large enough values (e.g., podset_number = 200, #}
+{# max_tor_subnet_number = 16, tor_subnet_size = 64), will cause #}
+{# us to overflow the 192.168.0.0/16 private address space here. #}
+{# This should be fine for internal use, but may pose an issue if used otherwise #}
+{# #}
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (subnet * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - ((props.tor_subnet_size | log(2))) | int) %}
+ip route 192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} {{ props.nhipv4 }}
+ipv6 route 20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/64 {{ props.nhipv6 }}
+{% endfor %}
+{% endfor %}
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - (((props.max_tor_subnet_number * props.tor_subnet_size) | log(2)) | int) ) %}
+{% set prefixlen_v6 = (64 - (((props.max_tor_subnet_number * props.tor_subnet_size) | log(2)) | int) ) %}
+ip prefix-list test_ipv4_{{ podset}}_{{ tor }} seq 10 permit 192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} ge {{ prefixlen_v4 }}
+ipv6 prefix-list test_ipv6_{{ podset}}_{{ tor }}
+ seq 10 permit 20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/{{ prefixlen_v6 }} ge {{ prefixlen_v6 }}
+exit
+{% endfor %}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if name.startswith('Port-Channel') %}
+ port-channel min-links 2
+{% endif %}
+{% if iface['lacp'] is defined %}
+ channel-group {{ iface['lacp'] }} mode active
+ lacp rate normal
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% if range(0, 1000)|random() >= props.failure_rate %}
+{% for tor in range(0, props.tor_number) %}
+{% set leafasn = props.leaf_asn_start + podset %}
+{% set torasn = props.tor_asn_start + tor %}
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) }}
+ match ip address prefix-list test_ipv4_{{ podset }}_{{ tor }}
+{% if podset == 0 %}
+ set as-path prepend {{ torasn }}
+{% else %}
+ set as-path prepend {{ props.spine_asn }} {{ leafasn }} {{ torasn }}
+{% endif %}
+!
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
+ match ipv6 address prefix-list test_ipv6_{{ podset }}_{{ tor }}
+{% if podset == 0 %}
+ set as-path prepend {{ torasn }}
+{% else %}
+ set as-path prepend {{ props.spine_asn }} {{ leafasn }} {{ torasn }}
+{% endif %}
+!
+{% endfor %}
+{% endif %}
+{% endfor %}
+!
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+ neighbor {{ remote_ip }} default-originate route-map DEFAULT_ROUTES
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+ redistribute static route-map PREPENDAS
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
diff --git a/ansible/roles/eos/templates/t0-64-leaf.j2 b/ansible/roles/eos/templates/t0-64-leaf.j2
new file mode 100644
index 00000000000..f7a21f4d8b6
--- /dev/null
+++ b/ansible/roles/eos/templates/t0-64-leaf.j2
@@ -0,0 +1,157 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+route-map DEFAULT_ROUTES permit
+!
+{# #}
+{# NOTE: Using large enough values (e.g., podset_number = 200, #}
+{# max_tor_subnet_number = 16, tor_subnet_size = 64), will cause #}
+{# us to overflow the 192.168.0.0/16 private address space here. #}
+{# This should be fine for internal use, but may pose an issue if used otherwise #}
+{# #}
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (subnet * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - ((props.tor_subnet_size | log(2))) | int) %}
+ip route 192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} {{ props.nhipv4 }}
+ipv6 route 20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/64 {{ props.nhipv6 }}
+{% endfor %}
+{% endfor %}
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - (((props.max_tor_subnet_number * props.tor_subnet_size) | log(2)) | int) ) %}
+{% set prefixlen_v6 = (64 - (((props.max_tor_subnet_number * props.tor_subnet_size) | log(2)) | int) ) %}
+ip prefix-list test_ipv4_{{ podset}}_{{ tor }} seq 10 permit 192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} ge {{ prefixlen_v4 }}
+ipv6 prefix-list test_ipv6_{{ podset}}_{{ tor }}
+ seq 10 permit 20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/{{ prefixlen_v6 }} ge {{ prefixlen_v6 }}
+exit
+{% endfor %}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if name.startswith('Port-Channel') %}
+ port-channel min-links 2
+{% endif %}
+{% if iface['lacp'] is defined %}
+ channel-group {{ iface['lacp'] }} mode active
+ lacp rate normal
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% if range(0, 1000)|random() >= props.failure_rate %}
+{% for tor in range(0, props.tor_number) %}
+{% set leafasn = props.leaf_asn_start + podset %}
+{% set torasn = props.tor_asn_start + tor %}
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) }}
+ match ip address prefix-list test_ipv4_{{ podset }}_{{ tor }}
+{% if podset == 0 %}
+ set as-path prepend {{ torasn }}
+{% else %}
+ set as-path prepend {{ props.spine_asn }} {{ leafasn }} {{ torasn }}
+{% endif %}
+!
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
+ match ipv6 address prefix-list test_ipv6_{{ podset }}_{{ tor }}
+{% if podset == 0 %}
+ set as-path prepend {{ torasn }}
+{% else %}
+ set as-path prepend {{ props.spine_asn }} {{ leafasn }} {{ torasn }}
+{% endif %}
+!
+{% endfor %}
+{% endif %}
+{% endfor %}
+!
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+ neighbor {{ remote_ip }} default-originate route-map DEFAULT_ROUTES
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+ redistribute static route-map PREPENDAS
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
diff --git a/ansible/roles/eos/templates/t0-leaf.j2 b/ansible/roles/eos/templates/t0-leaf.j2
new file mode 100644
index 00000000000..21d318d47b7
--- /dev/null
+++ b/ansible/roles/eos/templates/t0-leaf.j2
@@ -0,0 +1,157 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+route-map DEFAULT_ROUTES permit
+!
+{# #}
+{# NOTE: Using large enough values (e.g., podset_number = 200, #}
+{# max_tor_subnet_number = 16, tor_subnet_size = 64), will cause #}
+{# us to overflow the 192.168.0.0/16 private address space here. #}
+{# This should be fine for internal use, but may pose an issue if used otherwise #}
+{# #}
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (subnet * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - ((props.tor_subnet_size | log(2))) | int) %}
+ip route 192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} {{ props.nhipv4 }}
+ipv6 route 20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/64 {{ props.nhipv6 }}
+{% endfor %}
+{% endfor %}
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - (((props.max_tor_subnet_number * props.tor_subnet_size) | log(2)) | int) ) %}
+{% set prefixlen_v6 = (64 - (((props.max_tor_subnet_number * props.tor_subnet_size) | log(2)) | int) ) %}
+ip prefix-list test_ipv4_{{ podset}}_{{ tor }} seq 10 permit 192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} ge {{ prefixlen_v4 }}
+ipv6 prefix-list test_ipv6_{{ podset}}_{{ tor }}
+ seq 10 permit 20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/{{ prefixlen_v6 }} ge {{ prefixlen_v6 }}
+exit
+{% endfor %}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if name.startswith('Port-Channel') %}
+ port-channel min-links 1
+{% endif %}
+{% if iface['lacp'] is defined %}
+ channel-group {{ iface['lacp'] }} mode active
+ lacp rate normal
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% if range(0, 1000)|random() >= props.failure_rate %}
+{% for tor in range(0, props.tor_number) %}
+{% set leafasn = props.leaf_asn_start + podset %}
+{% set torasn = props.tor_asn_start + tor %}
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) }}
+ match ip address prefix-list test_ipv4_{{ podset }}_{{ tor }}
+{% if podset == 0 %}
+ set as-path prepend {{ torasn }}
+{% else %}
+ set as-path prepend {{ props.spine_asn }} {{ leafasn }} {{ torasn }}
+{% endif %}
+!
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
+ match ipv6 address prefix-list test_ipv6_{{ podset }}_{{ tor }}
+{% if podset == 0 %}
+ set as-path prepend {{ torasn }}
+{% else %}
+ set as-path prepend {{ props.spine_asn }} {{ leafasn }} {{ torasn }}
+{% endif %}
+!
+{% endfor %}
+{% endif %}
+{% endfor %}
+!
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+ neighbor {{ remote_ip }} default-originate route-map DEFAULT_ROUTES
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+ redistribute static route-map PREPENDAS
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
diff --git a/ansible/roles/eos/templates/t1-lag-spine.j2 b/ansible/roles/eos/templates/t1-lag-spine.j2
new file mode 100644
index 00000000000..6c47ef6c331
--- /dev/null
+++ b/ansible/roles/eos/templates/t1-lag-spine.j2
@@ -0,0 +1,129 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+route-map DEFAULT_ROUTES permit
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+ip route 192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {{ props.nhipv4 }}
+ipv6 route 20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {{ props.nhipv6 }}
+{% endfor %}
+{% endfor %}
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+ip prefix-list test_ipv4_{{ podset}}_{{ tor }} seq 10 permit 192.168.{{ podset }}.{{ tor * 16 }}/28 ge 28
+ipv6 prefix-list test_ipv6_{{ podset}}_{{ tor }}
+ seq 10 permit 20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16) }}::/60 ge 60
+exit
+{% endfor %}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if name.startswith('Port-Channel') %}
+ port-channel min-links 2
+{% endif %}
+{% if iface['lacp'] is defined %}
+ channel-group {{ iface['lacp'] }} mode active
+ lacp rate normal
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+{% for podset in range(0, props.podset_number) %}
+{% if range(0, 1000)|random() >= props.failure_rate %}
+{% for tor in range(0, props.tor_number) %}
+{% set leafasn = props.leaf_asn_start + podset %}
+{% set torasn = props.tor_asn_start + tor %}
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) }}
+ match ip address prefix-list test_ipv4_{{ podset }}_{{ tor }}
+ set as-path prepend {{ leafasn }} {{ torasn }}
+!
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
+ match ipv6 address prefix-list test_ipv6_{{ podset }}_{{ tor }}
+ set as-path prepend {{ leafasn }} {{ torasn }}
+!
+{% endfor %}
+{% endif %}
+{% endfor %}
+!
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+ neighbor {{ remote_ip }} default-originate route-map DEFAULT_ROUTES
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+ redistribute static route-map PREPENDAS
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
+
diff --git a/ansible/roles/eos/templates/t1-lag-tor.j2 b/ansible/roles/eos/templates/t1-lag-tor.j2
new file mode 100644
index 00000000000..a5ebd5b7454
--- /dev/null
+++ b/ansible/roles/eos/templates/t1-lag-tor.j2
@@ -0,0 +1,93 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+{% set tornum = host['tornum'] %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+{% for subnet in range(0, props.tor_subnet_number) %}
+ip route 172.16.{{ tornum }}.{{ subnet }}/32 {{ props.nhipv4 }}
+ipv6 route 20AC:10{{ '%02X' % tornum }}:0:{{ '%02X' % subnet }}::/64 {{ props.nhipv6 }}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+ network 172.16.{{ tornum }}.{{ subnet }}/32
+ network 20AC:10{{ '%02X' % tornum }}:0:{{ '%02X' % subnet }}::/64
+{% endfor %}
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
+
diff --git a/ansible/roles/eos/templates/t1-spine.j2 b/ansible/roles/eos/templates/t1-spine.j2
new file mode 100644
index 00000000000..5dcb10c3dda
--- /dev/null
+++ b/ansible/roles/eos/templates/t1-spine.j2
@@ -0,0 +1,122 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+route-map DEFAULT_ROUTES permit
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+ip route 192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {{ props.nhipv4 }}
+ipv6 route 20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {{ props.nhipv6 }}
+{% endfor %}
+{% endfor %}
+{% endfor %}
+!
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+ip prefix-list test_ipv4_{{ podset}}_{{ tor }} seq 10 permit 192.168.{{ podset }}.{{ tor * 16 }}/28 ge 28
+ipv6 prefix-list test_ipv6_{{ podset}}_{{ tor }}
+ seq 10 permit 20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16) }}::/60 ge 60
+exit
+{% endfor %}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+{% for podset in range(0, props.podset_number) %}
+{% if range(0, 1000)|random() >= props.failure_rate %}
+{% for tor in range(0, props.tor_number) %}
+{% set leafasn = props.leaf_asn_start + podset %}
+{% set torasn = props.tor_asn_start + tor %}
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) }}
+ match ip address prefix-list test_ipv4_{{ podset }}_{{ tor }}
+ set as-path prepend {{ leafasn }} {{ torasn }}
+!
+route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
+ match ipv6 address prefix-list test_ipv6_{{ podset }}_{{ tor }}
+ set as-path prepend {{ leafasn }} {{ torasn }}
+!
+{% endfor %}
+{% endif %}
+{% endfor %}
+!
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+ neighbor {{ remote_ip }} default-originate route-map DEFAULT_ROUTES
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+ redistribute static route-map PREPENDAS
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
+
diff --git a/ansible/roles/eos/templates/t1-tor.j2 b/ansible/roles/eos/templates/t1-tor.j2
new file mode 100644
index 00000000000..a5ebd5b7454
--- /dev/null
+++ b/ansible/roles/eos/templates/t1-tor.j2
@@ -0,0 +1,93 @@
+{% set host = configuration[hostname] %}
+{% set mgmt_ip = ansible_host %}
+{% set tornum = host['tornum'] %}
+hostname {{ hostname }}
+!
+vrf definition MGMT
+ rd 1:1
+!
+spanning-tree mode mstp
+!
+aaa root secret 0 123456
+!
+username admin privilege 15 role network-admin secret 0 123456
+!
+clock timezone UTC
+!
+lldp run
+lldp management-address Management1
+lldp management-address vrf MGMT
+!
+snmp-server community {{ snmp_rocommunity }} ro
+snmp-server vrf MGMT
+!
+ip routing
+ip routing vrf MGMT
+ipv6 unicast-routing
+!
+ip route vrf MGMT 0.0.0.0/0 {{ mgmt_gw }}
+!
+{% for subnet in range(0, props.tor_subnet_number) %}
+ip route 172.16.{{ tornum }}.{{ subnet }}/32 {{ props.nhipv4 }}
+ipv6 route 20AC:10{{ '%02X' % tornum }}:0:{{ '%02X' % subnet }}::/64 {{ props.nhipv6 }}
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ vrf forwarding MGMT
+ ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
+ no shutdown
+!
+{% for name, iface in host['interfaces'].items() %}
+interface {{ name }}
+{% if name.startswith('Loopback') %}
+ description LOOPBACK
+{% else %}
+ no switchport
+{% endif %}
+{% if iface['ipv4'] is defined %}
+ ip address {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ ipv6 enable
+ ipv6 address {{ iface['ipv6'] }}
+ ipv6 nd ra suppress
+{% endif %}
+ no shutdown
+!
+{% endfor %}
+router bgp {{ host['bgp']['asn'] }}
+ router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
+ !
+{% for asn, remote_ips in host['bgp']['peers'].items() %}
+{% for remote_ip in remote_ips %}
+ neighbor {{ remote_ip }} remote-as {{ asn }}
+ neighbor {{ remote_ip }} description {{ asn }}
+{% if remote_ip | ipv6 %}
+ address-family ipv6
+ neighbor {{ remote_ip }} activate
+ exit
+{% endif %}
+{% endfor %}
+{% endfor %}
+ !
+{% for name, iface in host['interfaces'].items() if name.startswith('Loopback') %}
+{% if iface['ipv4'] is defined %}
+ network {{ iface['ipv4'] }}
+{% endif %}
+{% if iface['ipv6'] is defined %}
+ network {{ iface['ipv6'] }}
+{% endif %}
+{% endfor %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+ network 172.16.{{ tornum }}.{{ subnet }}/32
+ network 20AC:10{{ '%02X' % tornum }}:0:{{ '%02X' % subnet }}::/64
+{% endfor %}
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+end
+
diff --git a/ansible/roles/eos/templates/tor.j2 b/ansible/roles/eos/templates/tor.j2
deleted file mode 100644
index 0fb3fe2bf5e..00000000000
--- a/ansible/roles/eos/templates/tor.j2
+++ /dev/null
@@ -1,86 +0,0 @@
-hostname {{ hostname }}
-!
-spanning-tree mode mstp
-!
-aaa root secret 0 123456
-!
-username admin privilege 15 role network-admin secret 0 123456
-!
-clock timezone UTC
-!
-lldp run
-lldp management-address Management1
-!
-snmp-server community {{ snmp_rocommunity }} ro
-!
-ip routing
-ipv6 unicast-routing
-!
-ip route 0.0.0.0/0 {{ minigraph_mgmt_interface["gwaddr"] }}
-!
-{% for subnet in range(0, local_tor_subnet_number) %}
-ip route 172.16.{{ tornum }}.{{ subnet }}/32 {{ nhipv4 }}
-ipv6 route 20AC:10{{ '%02X' % tornum }}:0:{{ '%02X' % subnet }}::/64 {{ nhipv6 }}
-{% endfor %}
-!
-interface Management 1
- description TO LAB MGMT SWITCH
- ip address {{ minigraph_mgmt_interface["addr"] }} {{ minigraph_mgmt_interface["mask"] }}
- no shutdown
-!
-{% for lo in minigraph_lo_interfaces %}
-interface {{ lo['name'] }}
- description LOOPBACK
-{% if lo['addr'] | ipv4 %}
- ip address {{ lo['addr'] }}/{{ lo['prefixlen'] }}
-{% elif lo['addr'] | ipv6 %}
- ipv6 enable
- ipv6 address {{ lo['addr'] }}/{{ lo['prefixlen'] }}
- ipv6 nd ra suppress
-{% endif %}
- no shutdown
-{% endfor %}
-!
-{% for iface in minigraph_interfaces %}
-interface {{ iface['name'] }}
- no switchport
-{% if iface['addr'] | ipv4 %}
- ip address {{ iface['addr'] }} {{ iface['mask'] }}
-{% elif iface['addr'] | ipv6 %}
- ipv6 enable
- ipv6 address {{ iface['addr'] }}/{{ iface['mask'] }}
- ipv6 nd ra suppress
-{% endif %}
- no shutdown
-!
-{% endfor %}
-!
-router bgp {{ minigraph_bgp_asn }}
- router-id {{ minigraph_lo_interfaces[0]['addr'] }}
- !
-{% for neighbor in minigraph_bgp %}
- neighbor {{ neighbor["addr"] }} remote-as {{ neighbor["asn"] }}
- neighbor {{ neighbor["addr"] }} description {{ neighbor["asn"]}}
-{% if neighbor["addr"] | ipv6 %}
- address-family ipv6
- neighbor {{ neighbor["addr"] }} activate
- exit
-{% endif %}
-{% endfor %}
- !
-{% for lo in minigraph_lo_interfaces %}
- network {{ lo['addr'] }}/{{ lo['prefixlen'] }}
-{% endfor %}
-
-{% for subnet in range(0, local_tor_subnet_number) %}
- network 172.16.{{ tornum }}.{{ subnet }}/32
- network 20AC:10{{ '%02X' % tornum }}:0:{{ '%02X' % subnet }}::/64
-{% endfor %}
-!
-management api http-commands
- no protocol https
- protocol http
- no shutdown
-!
-end
-
diff --git a/ansible/roles/fanout/handlers/main.yml b/ansible/roles/fanout/handlers/main.yml
new file mode 100644
index 00000000000..84ce362197e
--- /dev/null
+++ b/ansible/roles/fanout/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+
+- name: Restart the box
+ command: /sbin/shutdown -r now "Ansible updates triggered"
+
diff --git a/ansible/roles/fanout/tasks/main.yml b/ansible/roles/fanout/tasks/main.yml
new file mode 100644
index 00000000000..b7e976291b9
--- /dev/null
+++ b/ansible/roles/fanout/tasks/main.yml
@@ -0,0 +1,43 @@
+# Gather minigraph facts
+- name: Gathering lab graph facts about the device
+ conn_graph_facts: host={{ inventory_hostname }}
+ connection: local
+ tags: always
+
+- block:
+ - name: prepare {{ sonicadmin_user }} password
+ set_fact: ansible_ssh_user={{ sonicadmin_user }} ansible_ssh_pass={{ sonicadmin_password }}
+
+ - name: setup fanout bash account
+ template: src=rc.eos.j2
+ dest=/mnt/flash/rc.eos
+
+ - name: build fanout startup config
+ template: src=arista_7260_deploy.j2
+ dest=/mnt/flash/startup-config
+ notify:
+ - Restart the box
+ when: device_info.HwSku == "Arista-7260QX-64"
+
+- block:
+ - name: prepare admin password
+ set_fact: ansible_ssh_user=admin ansible_ssh_pass={{ lab_admin_pass }}
+
+ - name: build fanout startup config
+ action: apswitch template=force10_s6100_deploy.j2
+ connection: switch
+ args:
+ login: "{{ switch_login['Force10'] }}"
+ when: device_info.HwSku == "Force10-S6100"
+
+- block:
+ - name: prepare admin password
+ set_fact: ansible_ssh_user=admin ansible_ssh_pass={{ lab_admin_pass }}
+
+ - name: build fanout startup config
+ action: apswitch template=nexus_3164_deploy.j2
+ connection: switch
+ args:
+ login: "{{ switch_login['Nexus'] }}"
+ when: device_info.HwSku == "Nexus-3164"
+
diff --git a/ansible/roles/fanout/tasks/rootfanout_connect.yml b/ansible/roles/fanout/tasks/rootfanout_connect.yml
new file mode 100644
index 00000000000..ce8f15a1692
--- /dev/null
+++ b/ansible/roles/fanout/tasks/rootfanout_connect.yml
@@ -0,0 +1,34 @@
+# This playbook is trying to change root fanout switch one port to the DUT vlan range based on which server which port and DUT name
+# This playbook is called from fanout_connect.yml
+# Gather graph facts
+- name: Gathering connection facts about the DUT device
+ conn_graph_facts: host={{ dut }}
+ connection: local
+ tags: always
+ register: dutinfo
+
+- name: Gathering connection facts about the lab
+ conn_graph_facts:
+ connection: local
+ tags: always
+ register: lab
+
+- set_fact:
+ dut_vlans: "{{ dutinfo.ansible_facts.device_vlan_range }}"
+ lab_devices: "{{ lab.ansible_facts.device_info }}"
+
+- name: Find the root fanout switch
+ set_fact:
+ ansible_host: "{{ lab_devices[item]['mgmtip'] }}"
+ root_dev: "{{ item }}"
+ with_items: "{{ lab_devices }}"
+ when: lab_devices[item]['Type'] == 'FanoutRoot'
+
+- set_fact:
+ root_conn: "{{ lab.ansible_facts['device_conn'][root_dev] }}"
+
+- name: Change root fanout port vlan
+ action: apswitch template=roles/fanout/templates/arista_7260_connect.j2
+ connection: switch
+ args:
+ login: "{{ switch_login['Arista'] }}"
diff --git a/ansible/roles/fanout/templates/arista_7260_connect.j2 b/ansible/roles/fanout/templates/arista_7260_connect.j2
new file mode 100644
index 00000000000..c9ed8c9dc27
--- /dev/null
+++ b/ansible/roles/fanout/templates/arista_7260_connect.j2
@@ -0,0 +1,22 @@
+!
+config
+{% for i in range(1,65) %}
+{% set intf = 'Ethernet' + i|string %}
+{% if intf in root_conn %}
+{% set peer_dev = root_conn[intf]['peerdevice'] %}
+{% set peer_port = root_conn[intf]['peerport'] %}
+{% if 'Fanout' not in lab_devices[peer_dev]['Type'] %}
+ interface {{ intf }}
+ switchport mode trunk
+ switchport trunk allowed vlan remove {{ dut_vlans | list | join(',') }}
+ no shutdown
+{% if peer_dev == server and peer_port == server_port %}
+ switchport trunk allowed vlan add {{ dut_vlans | list | join(',') }}
+{% endif %}
+{% endif %}
+{% endif %}
+{% endfor %}
+!
+copy running-config startup-config
+end
+
diff --git a/ansible/roles/fanout/templates/arista_7260_deploy.j2 b/ansible/roles/fanout/templates/arista_7260_deploy.j2
new file mode 100644
index 00000000000..6783d8eb4b8
--- /dev/null
+++ b/ansible/roles/fanout/templates/arista_7260_deploy.j2
@@ -0,0 +1,101 @@
+!
+! boot system flash:/EOS-4.15.1FX-7260QX.swi
+!
+!
+no errdisable detect cause link-flap
+!
+no schedule tech-support
+!
+transceiver qsfp default-mode 4x10G
+!
+no lldp run
+!
+hostname {{ inventory_hostname }}
+!
+ntp source vrf management Management1
+{% for ntp_server in ntp_servers %}
+ntp server vrf management {{ ntp_server }}
+{% endfor %}
+!
+spanning-tree mode none
+no spanning-tree vlan {{ device_vlan_range | list | join(',') }}
+!
+service unsupported-transceiver microsoft 361ac33e
+!
+aaa authorization exec default local
+!
+no aaa root
+!
+username admin privilege 15 role network-admin secret 0 {{ lab_admin_pass }}
+username eapi privilege 15 secret 0 {{ lab_admin_pass }}
+!
+vlan {{ device_vlan_range | list | join(',') }}
+!
+vrf definition management
+ rd 1:1
+!
+{% for i in range(1,65) %}
+{% set intf = 'Ethernet' + i|string %}
+interface {{ intf }}
+{% if intf in device_port_vlans and device_port_vlans[intf]['mode'] != "Trunk" %}
+ description {{ device_conn[intf]['peerdevice'] }}-{{ device_conn[intf]['peerport'] }}
+ switchport access vlan {{ device_port_vlans[intf]['vlanids'] }}
+ switchport mode dot1q-tunnel
+ spanning-tree portfast
+ speed forced 40gfull
+ no shutdown
+{% elif intf in device_port_vlans and device_port_vlans[intf]['mode'] == 'Trunk' %}
+ description {{ device_conn[intf]['peerdevice'] }}-{{ device_conn[intf]['peerport'] }}
+ switchport mode trunk
+ switchport trunk allowed vlan {{ device_port_vlans[intf]['vlanids'] }}
+ no shutdown
+{% else %}
+ shutdown
+{% endif %}
+!
+{% endfor %}
+!
+interface Management 1
+ description TO LAB MGMT SWITCH
+ ip address {{ device_info["ManagementIp"] }}
+ no shutdown
+!
+# LACP packets pass through
+mac address-table reserved forward 0180.c200.0002
+# LLDP packets pass through
+mac address-table reserved forward 0180.c200.000e
+!
+ip route 0.0.0.0/0 {{ device_info["ManagementGw"] }}
+ip route vrf management 0.0.0.0/0 {{ device_info["ManagementGw"] }}
+!
+ip routing
+no ip routing vrf management
+!
+banner login
+NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
+
+Unauthorized access and/or use prohibited. All access and/or use subject to monitoring.
+
+NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
+EOF
+!
+management api http-commands
+ vrf management
+ no shutdown
+!
+management api http-commands
+ no protocol https
+ protocol http
+ no shutdown
+!
+management console
+ idle-timeout 60
+!
+management ssh
+ idle-timeout 60
+ authentication mode password
+!
+!
+end
+
+
diff --git a/ansible/roles/fanout/templates/force10_s6100.j2 b/ansible/roles/fanout/templates/force10_s6100.j2
new file mode 100644
index 00000000000..fca4a92d6d8
--- /dev/null
+++ b/ansible/roles/fanout/templates/force10_s6100.j2
@@ -0,0 +1,78 @@
+conf t
+!
+vlan-stack protocol-type 8100
+!
+hostname {{ inventory_hostname }}
+!
+!
+redundancy auto-synchronize full
+!
+!
+username admin password 0 {{ lab_admin_pass }} privilege 15
+!
+allow unsupported-transceiver
+!
+stack-unit 1 provision S6100-ON
+!
+mac-address-table aging-time 10
+!
+{% for i in range(1,3) %}
+{% for j in range(1,17) %}
+interface fortyGigE 1/{{ i }}/{{ j }}
+ no ip address
+ switchport
+ vlan-stack access
+ no shutdown
+{% endfor %}
+{% endfor %}
+!
+{% for j in range(13,16) %}
+interface fortyGigE 1/4/{{ j }}
+ no ip address
+ switchport
+ vlan-stack trunk
+ no shutdown
+{% endfor %}
+!
+interface ManagementEthernet 1/1
+ ip address {{ minigraph_mgmt_interface["addr"] }} {{ minigraph_mgmt_interface["mask"] }}
+ no shutdown
+!
+interface Vlan 1
+!
+{% for i in range(1,3) %}
+{% for j in range(1,17) %}
+interface Vlan {{ 100 + (i - 1) * 16 + j }}
+ no ip address
+ vlan-stack compatible
+ member fortyGigE 1/{{ i }}/{{ j }}
+ member fortyGigE 1/4/13,1/4/14,1/4/15
+ shutdown
+{% endfor %}
+{% endfor %}
+!
+management route 0.0.0.0/0 10.250.0.1
+!
+ip ssh server enable
+!
+no protocol lldp
+!
+line console 0
+line vty 0
+line vty 1
+line vty 2
+line vty 3
+line vty 4
+line vty 5
+line vty 6
+line vty 7
+line vty 8
+line vty 9
+!
+reload-type
+ boot-type normal-reload
+ config-scr-download enable
+!
+end
+write mem
+
diff --git a/ansible/roles/fanout/templates/force10_s6100_deploy.j2 b/ansible/roles/fanout/templates/force10_s6100_deploy.j2
new file mode 100644
index 00000000000..1324c8b1995
--- /dev/null
+++ b/ansible/roles/fanout/templates/force10_s6100_deploy.j2
@@ -0,0 +1,79 @@
+conf t
+!
+vlan-stack protocol-type 8100
+!
+hostname {{ inventory_hostname }}
+!
+!
+redundancy auto-synchronize full
+!
+!
+username admin password 0 {{ lab_admin_pass }} privilege 15
+!
+allow unsupported-transceiver
+!
+stack-unit 1 provision S6100-ON
+!
+mac-address-table aging-time 10
+!
+{% for i in range(1,5) %}
+{% for j in range(1,17) %}
+{% set intf = 'fortyGigE 1/' + i|string + '/' + j|string %}
+interface {{ intf }}
+ no ip address
+ switchport
+{% if intf in device_port_vlans and device_port_vlans[intf]['mode'] != 'Trunk' %}
+ description {{ device_conn[intf]['peerdevice'] }}-{{ device_conn[intf]['peerport'] }}
+ vlan-stack access
+ no shutdown
+ interface Vlan {{ device_port_vlans[intf]['vlanids'] }}
+ vlan-stack compatible
+ member {{ intf }}
+{% elif intf in device_port_vlans and device_port_vlans[intf]['mode'] == 'Trunk' %}
+ description {{ device_conn[intf]['peerdevice'] }}-{{ device_conn[intf]['peerport'] }}
+ vlan-stack trunk
+ no shutdown
+{% for vlanid in device_port_vlans[intf]['vlanlist'] %}
+ interface Vlan {{ vlanid }}
+ vlan-stack compatible
+ member {{ intf }}
+ no shutdown
+{% endfor %}
+{% else %}
+ shutdown
+{% endif %}
+!
+{% endfor %}
+{% endfor %}
+!
+interface ManagementEthernet 1/1
+ ip address {{ device_info["ManagementIp"] }}
+ no shutdown
+!
+interface Vlan 1
+!
+management route 0.0.0.0/0 {{ device_info["ManagementGw"] }}
+!
+ip ssh server enable
+!
+no protocol lldp
+!
+line console 0
+line vty 0
+line vty 1
+line vty 2
+line vty 3
+line vty 4
+line vty 5
+line vty 6
+line vty 7
+line vty 8
+line vty 9
+!
+reload-type
+ boot-type normal-reload
+ config-scr-download enable
+!
+end
+write mem
+
diff --git a/ansible/roles/fanout/templates/lag_fn_ports.j2 b/ansible/roles/fanout/templates/lag_fn_ports.j2
new file mode 100644
index 00000000000..93a6a724339
--- /dev/null
+++ b/ansible/roles/fanout/templates/lag_fn_ports.j2
@@ -0,0 +1,5 @@
+enable
+configure terminal
+interface {{ config_iface }}
+{{ state }}
+exit
diff --git a/ansible/roles/fanout/templates/nexus_3164_deploy.j2 b/ansible/roles/fanout/templates/nexus_3164_deploy.j2
new file mode 100644
index 00000000000..453ab0d033a
--- /dev/null
+++ b/ansible/roles/fanout/templates/nexus_3164_deploy.j2
@@ -0,0 +1,38 @@
+config
+no vlan 101-4094
+{% for vlanid in device_vlan_list %}
+ vlan {{ vlanid }}
+ no spanning-tree vlan {{ vlanid }}
+{% endfor %}
+{% for i in range(1,65) %}
+{% set intf = 'Ethernet1/' + i|string %}
+ default interface {{ intf }}
+{% endfor %}
+{% for i in range(1,65) %}
+{% set intf = 'Ethernet1/' + i|string %}
+ interface {{ intf }}
+{% if intf in device_port_vlans and device_port_vlans[intf]['mode'] != "Trunk" %}
+ description {{ device_conn[intf]['peerdevice'] }}-{{ device_conn[intf]['peerport'] }}
+ switchport
+ speed 40000
+ no negotiate auto
+ switchport access vlan {{ device_port_vlans[intf]['vlanids'] }}
+ no shutdown
+{% elif intf in device_port_vlans and device_port_vlans[intf]['mode'] == 'Trunk' %}
+ description {{ device_conn[intf]['peerdevice'] }}-{{ device_conn[intf]['peerport'] }}
+ switchport
+ speed 40000
+ no negotiate auto
+ switchport mode trunk
+ switchport trunk allowed vlan {{ device_port_vlans[intf]['vlanids'] }}
+ no shutdown
+{% else %}
+ shutdown
+{% endif %}
+!
+{% endfor %}
+copy running-config startup-config
+!
+end
+
+
diff --git a/ansible/roles/fanout/templates/rc.eos.j2 b/ansible/roles/fanout/templates/rc.eos.j2
new file mode 100644
index 00000000000..81d5626d500
--- /dev/null
+++ b/ansible/roles/fanout/templates/rc.eos.j2
@@ -0,0 +1,5 @@
+#!/bin/sh
+useradd -d /persist/local/{{ sonicadmin_user }} -G eosadmin {{ sonicadmin_user }}
+echo {{ sonicadmin_password }} | sudo passwd --stdin {{ sonicadmin_user }}
+
+
diff --git a/ansible/roles/ptf_host/library/ptf_network.py b/ansible/roles/ptf_host/library/ptf_network.py
deleted file mode 100644
index 2799a34ad22..00000000000
--- a/ansible/roles/ptf_host/library/ptf_network.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/usr/bin/python
-
-import subprocess
-from docker import Client
-from ansible.module_utils.basic import *
-
-DOCUMENTATION = '''
----
-module: ptf_network.py
-version_added: "0.2"
-author: Pavel Shirshov (pavelsh@microsoft.com)
-short_description: Generate virtual network for a ptf container
-description:
- - This module generates 32 (by default) fp internal network interfaces with names 'eth0'..'eth31', and internal management interface with a name 'mgmt'.
- - The internal fp network interfaces are linux vlan interfaces encapsulated inside of a container.
- - The management interface is connected to host mgmt bridge using veth pair.
-
-Parameters:
- - ptf_name: name of a ptf container
- - ctr_num: a number of ptf container
- - iface: external interface, parent for vlans
- - num_of_ports: number of FP ports, 32 by default
- - vlan_base: the first vlan for the network
- - fp_mtu: MTU for FP ports
- - mgmt_ip_addr: ip address for mgmt port (with network length)
- - mgmt_ip_gw: default gateway for mgmt address
- - mgmt_bridge: a name of the management bridge (host network)
-
-'''
-
-EXAMPLES = '''
-- name: Create internal network for the docker container
- ptf_network:
- id: 3
- ptf_name: ptf_{{ id }}
- ctr_num: "{{ id }}"
- iface: "{{ ptf_external_iface }}"
- vlan_base: 101
- mgmt_ip_addr: "10.255.0.198"
- mgmt_ip_gw: "10.255.0.1"
- mgmt_bridge: "br1"
-
-'''
-
-
-DEFAULT_MTU = 0
-DEFAULT_N_PORTS = 32
-
-
-class PTFNetwork(object):
-
- def __init__(self, ptf_name, ctr_num, iface, fp_mtu=DEFAULT_MTU):
- self.ptf_name = ptf_name
- self.ctr_num = ctr_num
- self.iface = iface
- self.fp_mtu = fp_mtu
-
- self.pid = PTFNetwork.get_pid(ptf_name)
-
- return
-
- @staticmethod
- def get_pid(ptf_name):
- cli = Client(base_url='unix://var/run/docker.sock')
- result = cli.inspect_container(ptf_name)
-
- return result['State']['Pid']
-
- @staticmethod
- def cmd(cmdline):
- cmd = cmdline.split(' ')
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = process.communicate()
- ret_code = process.returncode
-
- if ret_code != 0:
- raise Exception("ret_code=%d, error message=%s. cmd=%s" % (ret_code, stderr, cmdline))
-
- return stdout
-
- @staticmethod
- def brctl(cmdline):
- out = PTFNetwork.cmd(cmdline)
-
- br_to_ifs = {}
- if_to_br = {}
-
- rows = out.split('\n')[1:]
- cur_br = None
- for row in rows:
- if len(row) == 0:
- continue
- terms = row.split()
- if not row[0].isspace():
- cur_br = terms[0]
- br_to_ifs[cur_br] = []
- if len(terms) > 3:
- br_to_ifs[cur_br].append(terms[3])
- if_to_br[terms[3]] = cur_br
- else:
- br_to_ifs[cur_br].append(terms[0])
- if_to_br[terms[0]] = cur_br
-
- return br_to_ifs, if_to_br
-
- @staticmethod
- def ifconfig(cmdline):
- out = PTFNetwork.cmd(cmdline)
-
- ifaces = set()
-
- rows = out.split('\n')
- for row in rows:
- if len(row) == 0:
- continue
- terms = row.split()
- if not row[0].isspace():
- ifaces.add(terms[0])
-
- return ifaces
-
- def update(self):
- self.host_br_to_ifs, self.host_if_to_br = PTFNetwork.brctl('brctl show')
- self.host_ifaces = PTFNetwork.ifconfig('ifconfig -a')
- self.ctr_ifaces = PTFNetwork.ifconfig('nsenter -t %s -n ifconfig -a' % self.pid)
-
- return
-
- def add_br_if_to_docker(self, bridge, ext_if, int_if):
- self.update()
-
- if ext_if not in self.host_ifaces:
- cmd1 = "ip link add %s type veth peer name %s" % (ext_if, int_if)
- PTFNetwork.cmd(cmd1)
-
- if ext_if not in self.host_if_to_br:
- cmd2 = "brctl addif %s %s" % (bridge, ext_if)
- PTFNetwork.cmd(cmd2)
-
- cmd3 = "ip link set %s up" % ext_if
- PTFNetwork.cmd(cmd3)
-
- self.update()
-
- if int_if in self.host_ifaces and int_if not in self.ctr_ifaces:
- cmd4 = "ip link set netns %s dev %s" % (self.pid, int_if)
- PTFNetwork.cmd(cmd4)
-
- self.update()
-
- cmd5 = "nsenter -t %s -n ip link set %s up" % (self.pid, int_if)
- PTFNetwork.cmd(cmd5)
-
- return
-
- def add_ip_to_int_if(self, int_if, mgmt_ip_addr, mgmt_gw):
- self.update()
- if int_if in self.ctr_ifaces:
- cmd_1 = "nsenter -t %s -n ip addr flush dev %s" % (self.pid, int_if)
- PTFNetwork.cmd(cmd_1)
- cmd_2 = "nsenter -t %s -n ip addr add %s dev %s" % (self.pid, mgmt_ip_addr, int_if)
- PTFNetwork.cmd(cmd_2)
- cmd_3 = "nsenter -t %s -n ip route add default via %s dev %s" % (self.pid, mgmt_gw, int_if )
- PTFNetwork.cmd(cmd_3)
-
- return
-
- def change_phy_if_mtu(self, iface_name):
- if self.fp_mtu == DEFAULT_MTU:
- return
-
- self.update()
-
- if iface_name in self.ctr_ifaces:
- cmd = "nsenter -t %s -n ip link set dev %s mtu %d" % (self.pid, iface_name, self.fp_mtu)
- PTFNetwork.cmd(cmd)
- else:
- raise Exception("Internal interface: %s doesn't exist" % iface_name)
-
- return
-
- def add_phy_if_to_docker(self, iface_name, vlan):
- int_if = "%s.%d" % (self.iface, vlan)
-
- if int_if not in self.host_ifaces and iface_name not in self.ctr_ifaces and int_if not in self.ctr_ifaces:
- cmd1 = "vconfig add %s %s" % (self.iface, vlan)
- PTFNetwork.cmd(cmd1)
-
- self.update()
-
- if int_if in self.host_ifaces and int_if not in self.ctr_ifaces and iface_name not in self.ctr_ifaces:
- cmd2 = "ip link set netns %s dev %s" % (self.pid, int_if)
- PTFNetwork.cmd(cmd2)
-
- self.update()
-
- if int_if in self.ctr_ifaces and iface_name not in self.ctr_ifaces:
- cmd3 = "nsenter -t %s -n ip link set dev %s name %s" % (self.pid, int_if, iface_name)
- PTFNetwork.cmd(cmd3)
-
- cmd4 = "nsenter -t %s -n ip link set %s up" % (self.pid, iface_name)
- PTFNetwork.cmd(cmd4)
-
- return
-
- def add_fp_ports(self, num_of_ports, vlan_base):
- if self.iface in self.host_ifaces:
- cmd = "ip link set %s up" % self.iface
- PTFNetwork.cmd(cmd)
-
- if self.fp_mtu != DEFAULT_MTU:
- cmd = "ip link set dev %s mtu %d" % (self.iface, self.fp_mtu)
- PTFNetwork.cmd(cmd)
- else:
- raise Exception("External interface: %s doesn't exist" % self.iface)
-
- for i in xrange(num_of_ports):
- vlan = vlan_base + i
- iface_name = "eth%d" % i
- self.add_phy_if_to_docker(iface_name, vlan)
- self.change_phy_if_mtu(iface_name)
-
- return
-
- def add_mgmt_port(self, mgmt_bridge, mgmt_ip, mgmt_gw):
- self.add_br_if_to_docker(mgmt_bridge, "ptf-mgmt-%d" % self.ctr_num, "mgmt")
- self.add_ip_to_int_if("mgmt", mgmt_ip, mgmt_gw)
-
- return
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- ptf_name=dict(required=True, type='str'),
- ctr_num=dict(required=True, type='int'),
- iface=dict(required=True, type='str'),
- num_of_ports=dict(required=False, type='int', default=DEFAULT_N_PORTS),
- vlan_base=dict(required=True, type='int'),
- fp_mtu=dict(required=False, type='int', default=DEFAULT_MTU),
- mgmt_ip_addr=dict(required=True, type='str'),
- mgmt_ip_gw=dict(required=True, type='str'),
- mgmt_bridge=dict(required=True, type='str')),
- supports_check_mode=False)
-
- ptf_name = module.params['ptf_name']
- ctr_num = module.params['ctr_num']
- iface = module.params['iface']
- num_of_ports = module.params['num_of_ports']
- vlan_base = module.params['vlan_base']
- fp_mtu = module.params['fp_mtu']
- mgmt_ip_addr = module.params['mgmt_ip_addr']
- mgmt_ip_gw = module.params['mgmt_ip_gw']
- mgmt_bridge = module.params['mgmt_bridge']
-
- try:
- net = PTFNetwork(ptf_name, ctr_num, iface, fp_mtu)
- net.add_mgmt_port(mgmt_bridge, mgmt_ip_addr, mgmt_ip_gw)
- net.add_fp_ports(num_of_ports, vlan_base)
-
- except Exception as error:
- module.fail_json(msg=str(error))
-
- module.exit_json(changed=True)
-
-if __name__ == "__main__":
- main()
-
diff --git a/ansible/roles/ptf_host/tasks/main.yml b/ansible/roles/ptf_host/tasks/main.yml
deleted file mode 100644
index c8499014638..00000000000
--- a/ansible/roles/ptf_host/tasks/main.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-# This role create/destroy one entity of ptf container.
-# Input parameters for the role:
-# - action: 'start' or 'stop' for creating or removeing ptf container respectively
-# - id: sequence number for ptf container on the host.
-# - external_iface: interface which will be used as parent for vlan interface creation
-# - vlan_base: first vlan id for the container
-# - mgmt_ip: ip address with netmask for the management interface of the container
-# - mgmt_gw: gateway for the container
-# - mgmt_bridge: linux bridge which is used for management interface connections
-# - proxy_env: for docker daemon proxy settings. should be dictionary with 'http_proxy', 'https_proxy' values
-# - docker_registry_host: ip address of a docker registry host
-# - docker_registry_username: username for the docker registry host
-# - docker_registry_password: password for the docker registry host
-
-- name: Install necessary packages. ptf {{ id }}
- apt: pkg={{ item }} update_cache=yes cache_valid_time=3600
- with_items:
- - net-tools
- - bridge-utils
- - util-linux
- - iproute2
- - vlan
- - python-pip
-
-- name: Install python packages. ptf {{ id }}
- pip: name=docker-py state=present version=1.7.2
- environment: "{{ proxy_env | default({}) }}"
-
-- name: Remove ptf docker container. ptf {{ id }}
- docker:
- name: ptf_{{ id }}
- image: "{{ docker_registry_host }}/{{ docker_image }}"
- state: absent
- when: action == 'stop'
-
-- name: Create docker container. ptf {{ id }}
- docker:
- registry: "{{ docker_registry_host }}"
- username: "{{ docker_registry_username }}"
- password: "{{ docker_registry_password }}"
- name: ptf_{{ id }}
- image: "{{ docker_registry_host }}/{{ docker_image }}"
- pull: always
- state: reloaded
- net: none
- detach: True
- cap_add: NET_ADMIN
- when: action == 'start'
-
-- name: Create internal network for the docker container. ptf {{ id }}
- ptf_network:
- ptf_name: ptf_{{ id }}
- ctr_num: "{{ id }}"
- iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
- fp_mtu: "{{ fp_mtu_size }}"
- mgmt_ip_addr: "{{ mgmt_ip }}"
- mgmt_ip_gw: "{{ mgmt_gw }}"
- mgmt_bridge: "{{ mgmt_bridge }}"
- when: action == 'start'
-
diff --git a/ansible/roles/ptf_host/vars/main.yml b/ansible/roles/ptf_host/vars/main.yml
deleted file mode 100644
index 5d38dcdfa96..00000000000
--- a/ansible/roles/ptf_host/vars/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-fp_mtu_size: 9216
-docker_image: docker-ptf
-
diff --git a/ansible/roles/sonic-common/tasks/dhcp_relay.yml b/ansible/roles/sonic-common/tasks/dhcp_relay.yml
new file mode 100644
index 00000000000..05917db58ff
--- /dev/null
+++ b/ansible/roles/sonic-common/tasks/dhcp_relay.yml
@@ -0,0 +1,10 @@
+- name: Ensure DHCP Relay container started
+ include: sonicdocker.yml
+ vars:
+ docker_container: dhcp_relay
+ docker_image: "{{ image_id_dhcp_relay }}"
+ docker_privileged: yes
+ docker_state: reloaded
+ docker_volumes:
+ - /etc/sonic/:/etc/sonic/:ro
+
diff --git a/ansible/roles/sonic-common/tasks/lldp.yml b/ansible/roles/sonic-common/tasks/lldp.yml
index d06667fda2c..d1df01ba973 100644
--- a/ansible/roles/sonic-common/tasks/lldp.yml
+++ b/ansible/roles/sonic-common/tasks/lldp.yml
@@ -18,6 +18,8 @@
docker_image: "{{ image_id_lldp }}"
docker_privileged: yes
docker_state: reloaded
+ docker_volumes_from:
+ - database
docker_volumes:
- /etc/sonic/:/etc/sonic/:ro
diff --git a/ansible/roles/sonic-common/tasks/main.yml b/ansible/roles/sonic-common/tasks/main.yml
index a6649610af9..1ea562d3c52 100644
--- a/ansible/roles/sonic-common/tasks/main.yml
+++ b/ansible/roles/sonic-common/tasks/main.yml
@@ -1,3 +1,4 @@
+# Gather minigraph facts
- name: Gathering minigraph facts about the device
minigraph_facts: host={{ inventory_hostname }}
become: no
@@ -8,7 +9,7 @@
sonic_asic_type: broadcom
when: sonic_hwsku in broadcom_hwskus
tags: always
-
+
- name: Set sonic_asic_type fact
set_fact:
sonic_asic_type: mellanox
@@ -38,7 +39,7 @@
dest=/etc/sonic/minigraph.xml
mode=0644
tags: always
-
+
# Syslog
- name: Install Syslog daemon
become: true
@@ -103,6 +104,7 @@
# Assign hostname
- name: Assign hostname
+ become: true
hostname: name={{ inventory_hostname }}
tags: system
@@ -138,6 +140,7 @@
register: if_copy
tags: network,unsafe
+# Do the same change in /etc/network/interfaces here
- name: Add MGMT Default Route to table default
become: true
command: ip route add default via {{ minigraph_mgmt_interface["gwaddr"] }} dev eth0 table default
@@ -153,6 +156,7 @@
changed_when: False
- name: Add mgmt ip rule if it does not exist
+ become: true
shell: /bin/ip rule add from {{ minigraph_mgmt_interface['addr'] }}/32 table default
tags: network,unsafe
when: ip_rules.stdout.find("from {{ minigraph_mgmt_interface['addr'] }} lookup default") == -1
@@ -169,7 +173,7 @@
## Redis database
- include: database.yml
- tags:
+ tags:
- swss
- database
- unsafe
@@ -217,6 +221,11 @@
- include: lldp.yml
tags: lldp
+# DHCP Relay
+- include: dhcp_relay.yml
+ tags: dhcp_relay
+ when: minigraph_devices[inventory_hostname]['type'] == "ToRRouter"
+
- command: /bin/true
notify: Clean up apt
diff --git a/ansible/roles/sonic-common/tasks/sensors_check.yml b/ansible/roles/sonic-common/tasks/sensors_check.yml
new file mode 100644
index 00000000000..6cfc6af7043
--- /dev/null
+++ b/ansible/roles/sonic-common/tasks/sensors_check.yml
@@ -0,0 +1,24 @@
+- name: Get platform monitor docker name
+ shell: docker ps -a --format '{{'{{'}}.Image{{'}} {{'}}.Names{{'}}'}}' | grep 'platform' | awk '{print $2}'
+ register: pmon_ps
+
+- set_fact:
+ ansible_python_interpreter: "docker exec -i {{ pmon_ps.stdout }} python"
+
+- name: Gather sensors
+ sensors_facts: checks={{ sensors_checks[minigraph_hwsku] }}
+ vars:
+ ansible_shell_type: docker
+
+- set_fact:
+ ansible_python_interpreter: "/usr/bin/python"
+
+- name: Output of sensors information
+ debug: var=vars['sensors']
+
+- name: Assert no alarm
+ assert: { that: "{{ vars['sensors']['alarm'] }} == False" }
+
+- name: Show warnings
+ debug: var=vars['sensors']['warnings']
+ when: vars['sensors']['warning']
diff --git a/ansible/roles/sonic-common/tasks/snmp.yml b/ansible/roles/sonic-common/tasks/snmp.yml
index 4a99c969e79..1cad998cf19 100644
--- a/ansible/roles/sonic-common/tasks/snmp.yml
+++ b/ansible/roles/sonic-common/tasks/snmp.yml
@@ -18,6 +18,8 @@
docker_image: "{{ image_id_snmp }}"
docker_privileged: yes
docker_state: reloaded
+ docker_volumes_from:
+ - database
docker_volumes:
- /etc/sonic/:/etc/sonic/:ro
- /etc/ssw/:/etc/ssw/:ro
diff --git a/ansible/roles/sonic-common/templates/dhcp_relay.yml.j2 b/ansible/roles/sonic-common/templates/dhcp_relay.yml.j2
new file mode 100644
index 00000000000..e5348b9c749
--- /dev/null
+++ b/ansible/roles/sonic-common/templates/dhcp_relay.yml.j2
@@ -0,0 +1 @@
+dhcp_servers: "{{ dhcp_servers | join(' ') }}"
diff --git a/ansible/roles/sonic-common/templates/etc/systemd/system/dhcp_relay.j2 b/ansible/roles/sonic-common/templates/etc/systemd/system/dhcp_relay.j2
new file mode 100644
index 00000000000..71f4b4c1d51
--- /dev/null
+++ b/ansible/roles/sonic-common/templates/etc/systemd/system/dhcp_relay.j2
@@ -0,0 +1,12 @@
+[Unit]
+Description=DHCP relay container
+Requires=docker.service
+After=docker.service
+
+[Service]
+User={{ sonicadmin_user }}
+ExecStart=/usr/bin/docker start -a dhcp_relay
+ExecStop=/usr/bin/docker stop dhcp_relay
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/sonicv2/tasks/sonic-cavm.yml b/ansible/roles/sonicv2/tasks/sonic-cavm.yml
index 59fb4535d80..4f7f8e599b4 100644
--- a/ansible/roles/sonicv2/tasks/sonic-cavm.yml
+++ b/ansible/roles/sonicv2/tasks/sonic-cavm.yml
@@ -18,7 +18,7 @@
# Install docker containers
- name: Start syncd docker container
- include: ../../sonic-common/tasks/sonicdocker.yml
+ include: sonicdocker.yml
vars:
docker_container: syncd
docker_image: "{{ image_id_syncd_cavm }}"
diff --git a/ansible/roles/sonicv2/templates/etc/systemd/system/syncd.j2 b/ansible/roles/sonicv2/templates/etc/systemd/system/syncd.j2
index 27f8d8d876b..dee037e90d2 100644
--- a/ansible/roles/sonicv2/templates/etc/systemd/system/syncd.j2
+++ b/ansible/roles/sonicv2/templates/etc/systemd/system/syncd.j2
@@ -1,6 +1,6 @@
[Unit]
Description=syncd container
-Requires=database.service swss.service
+Requires=database.service
After=database.service swss.service
[Service]
diff --git a/ansible/roles/test/files/acstests/IP_decap_test.py b/ansible/roles/test/files/acstests/IP_decap_test.py
new file mode 100644
index 00000000000..fff1e27bbde
--- /dev/null
+++ b/ansible/roles/test/files/acstests/IP_decap_test.py
@@ -0,0 +1,189 @@
+'''
+Owner: Dor Marcus
+Created on: 12/09/2017
+Description: This file contains the Decapasulation test for SONIC, to test Decapsulation of IPv4 with double and triple encapsulated packets
+
+ Design is available in https://github.com/Azure/SONiC/wiki/IPv4-Decapsulation-test
+
+Precondition: Before the test start, all routes need to be defined as in the route_info.txt file, in addition to the decap rule that need to be set as the dspc_mode
+topology: The test need to run on non-lag systems with at least 31 active ports
+
+Usage: Examples of how to start the test
+ ptf --test-dir /root/dor/ ip_decap_test_red --platform remote -t "verbose=True;route_info='/tmp/route_info.txt';lo_ip='10.1.0.32';router_mac='00:02:03:04:05:00';dscp_mode='pipe'" --log-dir /tmp/logs --verbose
+Parameters: route_info - The route_info file location
+ lo_ip - The loop_back IP that is configured in the decap rule
+ router_mac - The mac of the router_mac
+ dscp_mode - The rule for the dscp parameter in the decap packet that is configured in the JSON file ('pipe' for inner and 'uniform' for outer)
+
+'''
+
+#---------------------------------------------------------------------
+# Global imports
+#---------------------------------------------------------------------
+import random
+import time
+import logging
+import ptf.packet as scapy
+import socket
+import ptf.dataplane as dataplane
+
+from ptf.testutils import *
+from ptf.mask import Mask
+import ipaddress
+
+import os
+import unittest
+
+import ptf
+from ptf.base_tests import BaseTest
+from ptf import config
+import ptf.dataplane as dataplane
+import ptf.testutils as testutils
+
+import pprint
+from router_utils import *
+
+
+#---------------------------------------------------------------------
+# Global variables
+#---------------------------------------------------------------------
+PREFIX_AND_PORT_SPLITTER=" "
+PORT_LIST_SPLITTER=","
+PORT_COUNT = 31
+
+class DecapPacketTest(BaseTest, RouterUtility):
+ def __init__(self):
+ BaseTest.__init__(self)
+ self.test_params = testutils.test_params_get()
+ #-----------------------------------------------------------------
+ def setUp(self):
+ '''
+ @summary: Setup for the test
+ '''
+ self.dataplane = ptf.dataplane_instance
+ self.router_mac = self.test_params['router_mac']
+ #-----------------------------------------------------------------
+
+ def send_and_verify(self, dst_ip, expected_ports, src_port, triple_encap = False):
+ '''
+ @summary: This function builds encap packet, send and verify their arrival, When a packet will not arrived as expected an exeption will be throwen
+ @dst_ip: the destination ip for the inner IP header
+ @expected_ports: list of ports that a packet can arrived from
+ @src_port: the physical port that the packet will be sent from
+ @triple_encap: Bool if to send triple encapsulated packet
+ '''
+ #setting parameters
+ src_mac = self.dataplane.get_mac(0, 0)
+ dst_mac = '00:11:22:33:44:55'
+ inner_src_ip = '2.2.2.2'
+ router_mac = self.test_params['router_mac']
+ dscp_in = random.randint(0, 32)
+ tos_in = dscp_in << 2
+ dscp_out = random.randint(0, 32)
+ tos_out = dscp_out << 2
+ if ("pipe" == self.test_params['dscp_mode']):
+ exp_tos = tos_in
+ elif("uniform" == self.test_params['dscp_mode']):
+ exp_tos = tos_out
+ else:
+ print("ERROR: no dscp is configured")
+ exit()
+
+ #building the packets and the expected packets
+ if (not triple_encap):
+ #for the double encap packet we will use IP header with TCP header without mac
+ inner_pkt = simple_ip_only_packet(ip_dst=dst_ip, ip_src=inner_src_ip, ip_ttl=64)
+ #after the decap process the retuning packet will be normal tcp packet, The TTL is taked from the inner layer and redused by one
+ exp_pkt = simple_tcp_packet(pktlen=114,
+ eth_dst=dst_mac,
+ eth_src=router_mac,
+ ip_dst=dst_ip,
+ ip_src=inner_src_ip,
+ ip_tos=exp_tos,
+ ip_ttl=63)
+ else:
+ #Building triple encap packet with SCAPY, because there is no PTF function for it, I use the defualt values for the TCP header
+ tcp_hdr = scapy.TCP(sport=1234, dport=80, flags="S", chksum=0)
+ inner_pkt2 = scapy.IP(src='4.4.4.4', dst='3.3.3.3', tos=0, ttl=64, id=1, ihl=None) / tcp_hdr
+ inner_pkt = scapy.IP(src=inner_src_ip, dst=dst_ip, tos=tos_in, ttl=64, id=1, ihl=None,proto =4) / inner_pkt2
+ inner_pkt = inner_pkt/("".join([chr(x) for x in xrange(100 - len(inner_pkt))]))
+ #The expected packet is also built by scapy, and the TTL is taked from the inner layer and redused by one
+ exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac)/inner_pkt
+ exp_pkt['IP'].tos = exp_tos #this parameter is taken by the decap rule configuration
+ exp_pkt['IP'].ttl = 63
+
+ pkt = simple_ipv4ip_packet(
+ eth_dst=router_mac,
+ eth_src=src_mac,
+ ip_src='1.1.1.1',
+ ip_dst=self.test_params['lo_ip'],
+ ip_tos=tos_out,
+ ip_ttl=random.randint(2, 63),
+ inner_frame=inner_pkt)
+
+ #send and verify the return packets
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src")
+ send_packet(self, src_port, pkt)
+ (match_index, rcv_pkt) = verify_packet_any_port(self, masked_exp_pkt, expected_ports)
+ #-----------------------------------------------------------------
+
+ def runTest(self):
+ test_result = True
+ random.seed(1)
+ self.load_route_info(self.test_params["route_info"])
+ default_route_ports =[]
+ unicast_ip = 'none'
+ unicast_dst_port = []
+ print self.route_info.iteritems()
+ #running on the routes_info file and extractin ECMP route and unicast route
+ for prefix, port_index_list in self.route_info.iteritems():
+ dest_ip_addr = prefix.split("/")[0]
+
+ if (self.is_ipv6_address(dest_ip_addr)):
+ continue
+
+ if (len(port_index_list) > 1):
+ for port_index in port_index_list:
+ if (len(port_index)> 0):
+ default_route_ports.append(int(port_index))
+ default_route_dst_ip = dest_ip_addr
+ elif (len(port_index_list) == 1):
+ unicast_ip = dest_ip_addr
+ unicast_dst_port = [int(port_index_list[0])]
+ #when found unicast and ECMP routes stop
+ if ((unicast_ip != 'none') and (len(default_route_ports) != 0)):
+ break
+
+ #Sending double and triple encapsulated packets from all ports with unicast and ECMP IP routes
+ for src_port in range(PORT_COUNT):
+
+ try:
+ self.send_and_verify(default_route_dst_ip, default_route_ports, src_port)
+ except:
+ print("ERROR: failed to send encap packet with default route from port: " + str(src_port))
+ test_result = False
+
+ try:
+ self.send_and_verify(default_route_dst_ip, default_route_ports, src_port, True)
+ except:
+ print("ERROR: failed to send triple encap packet with default route from port: " + str(src_port))
+ test_result = False
+
+ try:
+ self.send_and_verify(unicast_ip, unicast_dst_port, src_port)
+ except:
+ print("ERROR: failed to send encap packet with unicast route from port: " + str(src_port))
+ test_result = False
+
+ try:
+ self.send_and_verify(unicast_ip, unicast_dst_port, src_port, True)
+ except:
+ print("ERROR: faield to send triple encap packet with unicast route from port: " + str(src_port))
+ test_result = False
+
+ assert(test_result)
+#---------------------------------------------------------------------
+
+
diff --git a/ansible/roles/test/files/acstests/acl_port_range_traffic_test.py b/ansible/roles/test/files/acstests/acl_port_range_traffic_test.py
index 9eb5df7f940..737c6479ff2 100644
--- a/ansible/roles/test/files/acstests/acl_port_range_traffic_test.py
+++ b/ansible/roles/test/files/acstests/acl_port_range_traffic_test.py
@@ -10,7 +10,7 @@
class SendTCP(acs_base_test.ACSDataplaneTest):
def runTest(self):
pkt = scapy2.Ether(src="e4:1d:2d:a5:f3:ac", dst="00:02:03:04:05:00")
- pkt /= scapy2.IP(src="20.0.0.2", dst="20.0.0.1")
+ pkt /= scapy2.IP(src="10.0.0.1", dst="10.0.0.0")
# get L4 port number
port_number = testutils.test_params_get("port_number")
diff --git a/ansible/roles/test/files/acstests/acltb_test.py b/ansible/roles/test/files/acstests/acltb_test.py
new file mode 100644
index 00000000000..eeb73a9f1d9
--- /dev/null
+++ b/ansible/roles/test/files/acstests/acltb_test.py
@@ -0,0 +1,266 @@
+'''
+Description: This file contains the ACL test for SONiC testbed
+
+ Implemented according to the https://github.com/Azure/SONiC/wiki/ACL-test-plan
+
+Usage: Examples of how to use:
+ ptf --test-dir acstests acltb_test.AclTest --platform remote -t 'router_mac="00:02:03:04:05:00";verbose=True;route_info="/tmp/route_info.txt"'
+'''
+
+#---------------------------------------------------------------------
+# Global imports
+#---------------------------------------------------------------------
+import random
+import time
+import logging
+import ptf.packet as scapy
+import socket
+import ptf.dataplane as dataplane
+
+from ptf.testutils import *
+from ptf.mask import Mask
+import ipaddress
+
+import os
+import logging
+import unittest
+
+import ptf
+from ptf.base_tests import BaseTest
+from ptf import config
+import ptf.dataplane as dataplane
+import ptf.testutils as testutils
+
+import pprint
+
+class AclTest(BaseTest):
+ '''
+ @summary: ACL tests on testbed topo: t1
+ '''
+
+ #---------------------------------------------------------------------
+ # Class variables
+ #---------------------------------------------------------------------
+ PORT_COUNT = 31 # temporary exclude the last port
+
+ def __init__(self):
+ '''
+ @summary: constructor
+ '''
+ BaseTest.__init__(self)
+ self.test_params = testutils.test_params_get()
+ #---------------------------------------------------------------------
+
+ def setUp(self):
+ '''
+ @summary: Setup for the test
+ '''
+
+ self.dataplane = ptf.dataplane_instance
+ self.router_mac = self.test_params['router_mac']
+
+ #---------------------------------------------------------------------
+
+ '''
+ For diagnostic purposes only
+ '''
+ def print_route_info(self):
+ pprint.pprint(self.route_info)
+ return
+ #---------------------------------------------------------------------
+
+ def verify_packet_any_port(self, pkt, ports=[], device_number=0):
+ """
+ @summary: Check that the packet is received on _any_ of the specified ports belonging to
+ the given device (default device_number is 0).
+
+ The function returns when either the expected packet is received or timeout (1 second).
+
+ Also verifies that the packet is or received on any other ports for this
+ device, and that no other packets are received on the device (unless --relax
+ is in effect).
+ @param pkt : packet to verify
+ @param ports : list of ports
+
+ @return: index of the port on which the packet is received and the packet.
+ """
+ received = False
+ match_index = 0
+ (rcv_device, rcv_port, rcv_pkt, pkt_time) = dp_poll(self, device_number=device_number, exp_pkt=pkt, timeout=1)
+
+ if rcv_port in ports:
+ match_index = ports.index(rcv_port)
+ received = True
+
+ return (match_index, rcv_pkt, received)
+ #---------------------------------------------------------------------
+
+ def runSendReceiveTest(self, pkt2send, src_port , pkt2recv, destination_ports):
+ """
+ @summary Send packet and verify it is received/not received on the expected ports
+ """
+
+ masked2recv = Mask(pkt2recv)
+ masked2recv.set_do_not_care_scapy(scapy.Ether, "dst")
+ masked2recv.set_do_not_care_scapy(scapy.Ether, "src")
+
+ send_packet(self, src_port, pkt2send)
+ (index, rcv_pkt, received) = self.verify_packet_any_port(masked2recv, destination_ports)
+
+ self.tests_total += 1
+
+ return received
+
+ #---------------------------------------------------------------------
+ def runAclTests(self, dst_ip, dst_ip_blocked, src_port, dst_ports):
+ """
+ @summary: Crete and send packet to verify each ACL rule
+ @return: Number of tests passed
+ """
+
+ tests_passed = 0
+ self.tests_total = 0
+
+ print "\nPort to sent packets to: %d" % src_port
+ print "Destination IP: %s" % dst_ip_blocked
+ print "Ports to expect packet from: ",
+ pprint.pprint(dst_ports)
+ print "Dst IP expected to be blocked: ", dst_ip_blocked
+
+ pkt0 = simple_tcp_packet(
+ eth_dst = self.router_mac,
+ eth_src = self.dataplane.get_mac(0, 0),
+ ip_src = "10.0.0.1",
+ ip_dst = dst_ip,
+ tcp_sport = 0x1234,
+ tcp_dport = 0x50,
+ ip_ttl = 64
+ )
+ #exp_pkt = pkt.deepcopy()
+ exp_pkt0 = simple_tcp_packet(
+ eth_dst = self.dataplane.get_mac(0, 0),
+ eth_src = self.router_mac,
+ ip_src = "10.0.0.1",
+ ip_dst = dst_ip,
+ tcp_sport = 0x1234,
+ tcp_dport = 0x50,
+ ip_ttl = 63
+ )
+
+ print ""
+ # Test #1 - Verify source IP match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['IP'].src = "10.0.0.2"
+ exp_pkt['IP'].src = "10.0.0.2"
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #1 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #2 - Verify destination IP match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['IP'].dst = dst_ip_blocked
+ exp_pkt['IP'].dst = dst_ip_blocked
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #2 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #3 - Verify L4 source port match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['TCP'].sport = 0x1235
+ exp_pkt['TCP'].sport = 0x1235
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #3 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #4 - Verify L4 destination port match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['TCP'].dport = 0x1235
+ exp_pkt['TCP'].dport = 0x1235
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #4 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #5 - Verify ether type match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['Ethernet'].type = 0x1234
+ exp_pkt['Ethernet'].type = 0x1234
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #5 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #6 - Verify ip protocol match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['IP'].proto = 0x7E
+ exp_pkt['IP'].proto = 0x7E
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #6 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #7 - Verify TCP flags match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['TCP'].flags = 0x12
+ exp_pkt['TCP'].flags = 0x12
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #7 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #9 - Verify source port range match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['TCP'].sport = 0x123A
+ exp_pkt['TCP'].sport = 0x123A
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #9 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #10 - Verify destination port range match
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['TCP'].dport = 0x123A
+ exp_pkt['TCP'].dport = 0x123A
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (0 if res else 1)
+ print "Test #10 %s" % ("FAILED" if res else "PASSED")
+
+ # Test #11 - Verify rules priority
+ pkt = pkt0.copy()
+ exp_pkt = exp_pkt0.copy()
+ pkt['IP'].src = "10.0.0.3"
+ exp_pkt['IP'].src = "10.0.0.3"
+ res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports)
+ tests_passed += (1 if res else 0)
+ print "Test #11 %s" % ("PASSED" if res else "FAILED")
+
+ return tests_passed, self.tests_total
+
+ #---------------------------------------------------------------------
+
+ def runTest(self):
+ """
+ @summary: Crete and send packet to verify each ACL rule
+ """
+
+ test_result = False
+
+ self.switch_info = open(self.test_params["switch_info"], 'r').readlines()
+ self.tor_ports = map(int, self.switch_info[0].rstrip(",\n").split(","))
+ self.spine_ports = map(int, self.switch_info[1].rstrip(",\n").split(","))
+ self.dest_ip_addr_spine = self.switch_info[2].strip()
+ self.dest_ip_addr_spine_blocked = self.switch_info[3].strip()
+ self.dest_ip_addr_tor = self.switch_info[4].strip()
+ self.dest_ip_addr_tor_blocked = self.switch_info[5].strip()
+
+ # Verify ACLs on tor port
+ (tests_passed, tests_total) = self.runAclTests(self.dest_ip_addr_spine, self.dest_ip_addr_spine_blocked, self.tor_ports[0], self.spine_ports)
+ assert(tests_passed == tests_total)
+
+ # Verify ACLs on spine port
+ (tests_passed, tests_total) = self.runAclTests(self.dest_ip_addr_tor, self.dest_ip_addr_tor_blocked, self.spine_ports[0], self.tor_ports)
+ assert(tests_passed == tests_total)
diff --git a/ansible/roles/test/files/acstests/everflow_tb_test.py b/ansible/roles/test/files/acstests/everflow_tb_test.py
new file mode 100644
index 00000000000..35e731c1b69
--- /dev/null
+++ b/ansible/roles/test/files/acstests/everflow_tb_test.py
@@ -0,0 +1,268 @@
+'''
+Description: This file contains the Everflow test for SONiC testbed
+
+ Implemented according to the https://github.com/Azure/SONiC/wiki/Everflow-test-plan
+
+Usage: Examples of how to use:
+ ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'router_mac="00:02:03:04:05:00";src_port="20";dst_ports="21,22";session_src_ip="1.1.1.1";session_dst_ip="2.2.2.2";session_ttl="64";session_dscp="0";verbose=True'
+'''
+
+
+import ptf
+import ptf.packet as scapy
+import ptf.dataplane as dataplane
+import ptf.testutils as testutils
+from ptf.base_tests import BaseTest
+from ptf.mask import Mask
+
+def reportResults(test_name):
+ '''
+ @summary Report test result
+ '''
+ def testDecorator(func):
+ def wrapper(*args, **kwargs):
+ res = func(*args, **kwargs)
+ print 'Test "%s" %s' % (test_name, "PASSED" if res else "FAILED")
+ return res
+ return wrapper
+ return testDecorator
+
+
+class EverflowTest(BaseTest):
+ '''
+ @summary: Everflow tests on testbed topo: t1 or t1-lag
+ '''
+
+ GRE_PROTOCOL_NUMBER = 47
+ PORT_COUNT = 31 # temporary exclude the last port
+
+
+ def __init__(self):
+ '''
+ @summary: constructor
+ '''
+ BaseTest.__init__(self)
+ self.test_params = testutils.test_params_get()
+
+
+ def gre_type_filter(self, pkt_str):
+ '''
+ @summaty: Filter GRE packets
+ '''
+ try:
+ pkt = scapy.Ether(pkt_str)
+
+ if scapy.IP not in pkt:
+ return False
+
+ return pkt[scapy.IP].proto == self.GRE_PROTOCOL_NUMBER
+ except:
+ return False
+
+
+ def setUp(self):
+ '''
+ @summary: Setup for the test
+ '''
+
+ self.dataplane = ptf.dataplane_instance
+ self.hwsku = self.test_params['hwsku']
+ self.router_mac = self.test_params['router_mac']
+ self.session_src_ip = self.test_params['session_src_ip']
+ self.session_dst_ip = self.test_params['session_dst_ip']
+ self.session_ttl = int(self.test_params['session_ttl'])
+ self.session_dscp = int(self.test_params['session_dscp'])
+ self.src_port = int(float(self.test_params['src_port']))
+ self.dst_ports = [int(float(p)) for p in self.test_params['dst_ports'].split(",") if p]
+ self.expected_dst_mac = self.test_params.get('expected_dst_mac', None)
+
+ testutils.add_filter(self.gre_type_filter)
+
+ self.tests_total = 0
+ self.base_pkt = testutils.simple_tcp_packet(
+ eth_dst = self.router_mac,
+ eth_src = self.dataplane.get_mac(0, 0),
+ ip_src = "20.0.0.1",
+ ip_dst = "30.0.0.1",
+ tcp_sport = 0x1234,
+ tcp_dport = 0x50,
+ ip_ttl = 64
+ )
+
+
+ def receivePacketOnPorts(self, ports=[], device_number=0):
+ '''
+ @summary Receive packet on any of specified ports
+ '''
+ received = False
+ match_index = 0
+ (rcv_device, rcv_port, rcv_pkt, pkt_time) = testutils.dp_poll(self, device_number=device_number, timeout=1)
+
+ if rcv_port in ports:
+ match_index = ports.index(rcv_port)
+ received = True
+
+ return (match_index, rcv_pkt, received)
+
+
+ def runSendReceiveTest(self, pkt2send, src_port, destination_ports):
+ """
+ @summary Send packet and verify it is received/not received on the expected ports
+ """
+
+ testutils.send_packet(self, src_port, pkt2send)
+ (index, rcv_pkt, received) = self.receivePacketOnPorts(destination_ports)
+
+ self.tests_total += 1
+
+ if not received:
+ return False
+
+ scapy_pkt = scapy.Ether(rcv_pkt)
+
+ if scapy.IP not in scapy_pkt:
+ return False
+
+ if self.expected_dst_mac and scapy_pkt.dst != self.expected_dst_mac:
+ return False
+
+ if scapy_pkt[scapy.IP].src != self.session_src_ip:
+ return False
+
+ if scapy_pkt[scapy.IP].dst != self.session_dst_ip:
+ return False
+
+ if scapy_pkt[scapy.IP].ttl != self.session_ttl:
+ return False
+
+ # TODO: Fanout modifies DSCP. TOS value is olways 0.
+ #if (scapy_pkt[scapy.IP].tos >> 2) != self.session_dscp:
+ # return False
+
+ payload = str(scapy_pkt[scapy.GRE].payload)
+
+ if self.hwsku in ["ACS-MSN2700", "ACS-MSN2100", "ACS-MSN2410", "ACS-MSN2740"]:
+ payload = str(scapy_pkt[scapy.GRE].payload)[22:]
+
+ inner_pkt = scapy.Ether(payload)
+
+ masked_inner_pkt = Mask(inner_pkt)
+ if scapy.IP in inner_pkt:
+ masked_inner_pkt.set_do_not_care_scapy(scapy.IP, "chksum")
+
+ if scapy.TCP in inner_pkt:
+ masked_inner_pkt.set_do_not_care_scapy(scapy.TCP, "chksum")
+
+ return dataplane.match_exp_pkt(masked_inner_pkt, pkt2send)
+
+
+ @reportResults("Verify SRC IP match")
+ def verifySrcIp(self):
+ pkt = self.base_pkt.copy()
+ pkt['IP'].src = "20.0.0.10"
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify DST IP match")
+ def verifyDstIp(self):
+ pkt = self.base_pkt.copy()
+ pkt['IP'].dst = "30.0.0.10"
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify L4 SRC port match")
+ def verifyL4SrcPort(self):
+ pkt = self.base_pkt.copy()
+ pkt['TCP'].sport = 0x1235
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify L4 DST port match")
+ def verifyL4DstPort(self):
+ pkt = self.base_pkt.copy()
+ pkt['TCP'].dport = 0x1235
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify IP protocol match")
+ def verifyIpProtocol(self):
+ pkt = self.base_pkt.copy()
+ pkt['IP'].proto = 0x7E
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify TCP flags match")
+ def verifyTcpFlags(self):
+ pkt = self.base_pkt.copy()
+ pkt['TCP'].flags = 0x12
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify L4 SRC port range match")
+ def verifyL4SrcPortRange(self):
+ pkt = self.base_pkt.copy()
+ pkt['TCP'].sport = 4675
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify L4 DST port range match")
+ def verifyL4DstPortRange(self):
+ pkt = self.base_pkt.copy()
+ pkt['TCP'].dport = 4675
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ @reportResults("Verify IP DSCP match")
+ def verifyIpDscp(self):
+ pkt = self.base_pkt.copy()
+ pkt['IP'].tos = 51 << 2
+ return self.runSendReceiveTest(pkt, self.src_port, self.dst_ports)
+
+
+ def runEverflowTests(self):
+ """
+ @summary: Crete and send packet to verify each ACL rule
+ @return: Number of tests passed
+ """
+
+ tests_passed = 0
+ self.tests_total = 0
+
+ if self.verifySrcIp():
+ tests_passed += 1
+
+ if self.verifyDstIp():
+ tests_passed += 1
+
+ if self.verifyL4SrcPort():
+ tests_passed += 1
+
+ if self.verifyL4DstPort():
+ tests_passed += 1
+
+ if self.verifyIpProtocol():
+ tests_passed += 1
+
+ if self.verifyTcpFlags():
+ tests_passed += 1
+
+ if self.verifyL4SrcPortRange():
+ tests_passed += 1
+
+ if self.verifyL4DstPortRange():
+ tests_passed += 1
+
+ if self.verifyIpDscp():
+ tests_passed += 1
+
+ return tests_passed, self.tests_total
+
+
+ def runTest(self):
+ """
+ @summary: Run Everflow tests
+ """
+ (tests_passed, tests_total) = self.runEverflowTests()
+ print "Passed %d test of %d" % (tests_passed, tests_total)
+
+ assert(tests_passed == tests_total)
diff --git a/ansible/roles/test/files/acstests/fib_test.py b/ansible/roles/test/files/acstests/fib_test.py
deleted file mode 100644
index dd0a39f5e54..00000000000
--- a/ansible/roles/test/files/acstests/fib_test.py
+++ /dev/null
@@ -1,333 +0,0 @@
-'''
-Owner: Hrachya Mughnetsyan
-
-Created on: 11/14/2016
-
-Description: This file contains the FIB test for SONIC
-
- Design is available in https://github.com/Azure/SONiC/wiki/FIB-Scale-Test-Plan
-
-Usage: Examples of how to use log analyzer
- ptf --test-dir fib fib_test.FibTest --platform remote -t 'router_mac="00:02:03:04:05:00";verbose=True;route_info="fib/route_info.txt"'
-'''
-
-#---------------------------------------------------------------------
-# Global imports
-#---------------------------------------------------------------------
-import random
-import time
-import logging
-import ptf.packet as scapy
-import socket
-import ptf.dataplane as dataplane
-
-from ptf.testutils import *
-from ptf.mask import Mask
-import ipaddress
-
-import os
-import logging
-import unittest
-
-import ptf
-from ptf.base_tests import BaseTest
-from ptf import config
-import ptf.dataplane as dataplane
-import ptf.testutils as testutils
-
-import pprint
-
-class FibTest(BaseTest):
- '''
- @summary: Overview of functionality
- Test routes advertised by BGP peers of SONIC are working properly.
- The setup of peers is described in 'VM set' section in
- https://github.com/Azure/sonic-mgmt/blob/master/ansible/README.testbed.md
-
- Routes advertized by the peers have ECMP groups. The purpose of the test is to make sure
- that packets are forwarded through one of the ports specified in route's ECMP group.
-
-
- This class receives a text file describing the bgp routes added to the switch.
-
- File contains informaiton about each bgp route which was added to the switch.
-
- #-----------------------------------------------------------------------
- Format of the route_info file
- #-----------------------------------------------------------------------
- Example:
- 192.168.0.65/32 02,00,01,13,14,08,04,09,03,07,06,12,11,10,15,05,
- 20C0:A800:0:41::/64 02,00,01,13,14,08,04,09,03,07,06,12,11,10,15,05,
-
- Meaning:
- Each entry describes IP prefix, and indexes of ports-members of ecmp group for the route.
- The packet should be received from one of those ports.
- #-----------------------------------------------------------------------
-
- The file is loaded on startup and is used to
- - construct packet with correct destination IP
- - validate that packet arrived from switch from a port which
- is member of ECMP group for given route.
-
- For each route test
- - builds a packet with destination IP matching to the IP in the route
- - sends packet to the switch
- - verifies that packet came back from the switch on one of
- the ports specified in the ECMP group of the route.
-
- '''
-
- #---------------------------------------------------------------------
- # Class variables
- #---------------------------------------------------------------------
- PREFIX_AND_PORT_SPLITTER=" "
- PORT_LIST_SPLITTER=","
- PORT_COUNT = 32
-
- '''
- Information about routes to test.
- '''
- route_info={}
-
-
- def __init__(self):
- '''
- @summary: constructor
- '''
- BaseTest.__init__(self)
- self.test_params = testutils.test_params_get()
- #---------------------------------------------------------------------
-
- def setUp(self):
- '''
- @summary: Setup for the test
- '''
- self.dataplane = ptf.dataplane_instance
- self.router_mac = self.test_params['router_mac']
- #---------------------------------------------------------------------
-
- def load_route_info(self, route_info_path):
- '''
- @summary: Load route_info file into self.route_info. For details see section 'Format of the route_info file' in the summary of the class.
- @param route_info_path : Path to the file
- '''
- with open(route_info_path, 'r') as route_info_file:
- for line in route_info_file:
- line = line.strip()
- if (0==len(line)):
- continue
- prefix_ports_pair = line.split(self.PREFIX_AND_PORT_SPLITTER)
- port_list = prefix_ports_pair[1].split(self.PORT_LIST_SPLITTER)
- self.route_info[prefix_ports_pair[0]]=port_list
- return
- #---------------------------------------------------------------------
-
- '''
- For diagnostic purposes only
- '''
- def print_route_info(self):
- pprint.pprint(self.route_info)
- return
- #---------------------------------------------------------------------
-
- def verify_packet_any_port(self, pkt, ports=[], device_number=0):
- """
- @summary: Check that the packet is received on _any_ of the specified ports belonging to
- the given device (default device_number is 0).
-
- The function returns when either the expected packet is received or timeout (1 second).
-
- Also verifies that the packet is or received on any other ports for this
- device, and that no other packets are received on the device (unless --relax
- is in effect).
- @param pkt : packet to verify
- @param ports : list of ports
-
- @return: index of the port on which the packet is received and the packet.
- """
- received = False
- match_index = 0
- (rcv_device, rcv_port, rcv_pkt, pkt_time) = dp_poll(
- self,
- device_number=device_number,
- exp_pkt=pkt,
- timeout=1
- )
-
- if rcv_port in ports:
- match_index = ports.index(rcv_port)
- received = True
-
- return (match_index, rcv_pkt, received)
- #---------------------------------------------------------------------
-
- def is_ipv4_address(self, ipaddr):
- '''
- @summary: Check address is valid IPv4 address.
- @param ipaddr IP address to check
- @return Boolean
- '''
- is_valid_ipv4 = True
- try :
- # building ipaddress fails for some of addresses unless unicode(ipaddr) is specified for both ipv4/ipv6
- # Example - 192.168.156.129, it is valid IPV4 address, send_packet works with it.
- ip = ipaddress.IPv4Address(unicode(ipaddr))
- except Exception, e :
- is_valid_ipv4 = False
-
- return is_valid_ipv4
- #---------------------------------------------------------------------
-
- def is_ipv6_address(self, ipaddr):
- '''
- @summary: Check address is valid IPv6 address.
- @param ipaddr IP address to check
- @return Boolean
- '''
- is_valid_ipv6 = True
- try :
- ip = ipaddress.IPv6Address(unicode(ipaddr))
- except Exception, e:
- is_valid_ipv6 = False
-
- return is_valid_ipv6
- #---------------------------------------------------------------------
-
- def check_ipv4_route(self, source_port_index, dest_ip_addr, destination_port_list):
- '''
- @summary: Check IPv4 route works.
- @param source_port_index: index of port to use for sending packet to switch
- @param dest_ip_addr: destination IP to build packet with.
- @param destination_port_list: list of ports on which to expect packet to come back from the switch
- @return Boolean
- '''
- sport = 0x1234
- dport = 0x50
- ip_src = "10.0.0.1"
- ip_dst = dest_ip_addr
-
- src_mac = self.dataplane.get_mac(0, 0)
-
- pkt = simple_tcp_packet(
- eth_dst=self.router_mac,
- eth_src=src_mac,
- ip_src=ip_src,
- ip_dst=ip_dst,
- tcp_sport=sport,
- tcp_dport=dport,
- ip_ttl=64)
- exp_pkt = simple_tcp_packet(
- eth_dst=self.dataplane.get_mac(0, 0),
- eth_src=self.router_mac,
- ip_src=ip_src,
- ip_dst=ip_dst,
- tcp_sport=sport,
- tcp_dport=dport,
- ip_ttl=63)
- masked_exp_pkt = Mask(exp_pkt)
- masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"dst")
- masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"src")
-
- result = False
- send_packet(self, source_port_index, pkt)
-
- (match_index,rcv_pkt, received) = self.verify_packet_any_port(masked_exp_pkt,destination_port_list)
- if received:
- result = True
- else:
- print 'FAIL for ip:%s' % dest_ip_addr ,
- pprint.pprint(destination_port_list)
- return result
- #---------------------------------------------------------------------
-
- def check_ipv6_route(self, source_port_index, dest_ip_addr, destination_port_list):
- '''
- @summary: Check IPv6 route works.
- @param source_port_index: index of port to use for sending packet to switch
- @param dest_ip_addr: destination IP to build packet with.
- @param destination_port_list: list of ports on which to expect packet to come back from the switch
- @return Boolean
- '''
- sport = 0x2233
- dport = 0x60
- ip_src = '2000::1'
- ip_dst = dest_ip_addr
-
- src_mac = self.dataplane.get_mac(0, 0)
-
- pkt = simple_tcpv6_packet(
- eth_dst=self.router_mac,
- eth_src=src_mac,
- ipv6_dst=ip_dst,
- ipv6_src=ip_src,
- tcp_sport=sport,
- tcp_dport=dport,
- ipv6_hlim=64)
- exp_pkt = simple_tcpv6_packet(
- eth_dst=self.dataplane.get_mac(0, 0),
- eth_src=src_mac,
- ipv6_dst=ip_dst,
- ipv6_src=ip_src,
- tcp_sport=sport,
- tcp_dport=dport,
- ipv6_hlim=63)
- masked_exp_pkt = Mask(exp_pkt)
- masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"dst")
- masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"src")
-
- result = False
- send_packet(self, source_port_index, pkt)
-
- (match_index,rcv_pkt, received) = self.verify_packet_any_port(masked_exp_pkt,destination_port_list)
-
- if received:
- result = True
- else:
- print 'src_port:%d' % source_port_index,
- print 'FAIL for ip:%s' % dest_ip_addr ,
- pprint.pprint(destination_port_list)
- return result
- #---------------------------------------------------------------------
-
- def runTest(self):
- """
- @summary: Send packet for each route and validate it arrives
- on one of expected ECMP ports
- """
- self.load_route_info(self.test_params["route_info"])
- pass_count = 0
- test_result = True
- result = True
- ip4_route_cnt = 0
- ip6_route_cnt = 0
-
- for prefix, port_index_list in self.route_info.iteritems() :
- dest_ip_addr = prefix.split("/")[0]
- destination_port_list = []
- for port_index in port_index_list :
- if len(port_index) > 0 :
- destination_port_list.append(int(port_index))
-
- for src_port in xrange(0, self.PORT_COUNT):
-
- if src_port in destination_port_list: continue
-
- if self.is_ipv4_address(dest_ip_addr):
- ip4_route_cnt += 1
- result = self.check_ipv4_route(src_port, dest_ip_addr, destination_port_list)
- elif self.is_ipv6_address(dest_ip_addr):
- ip6_route_cnt += 1
- result = self.check_ipv6_route(src_port, dest_ip_addr, destination_port_list)
- else:
- print 'Invalid ip address:%s' % dest_ip_addr
- assert(False)
-
- test_result = test_result and result
- if(result):
- pass_count = pass_count + 1
-
- print 'pass_count:%d' % pass_count
- print 'ip4_route_cnt:%d' % ip4_route_cnt
- print 'ip6_route_cnt:%d' % ip6_route_cnt
- assert(test_result)
- #---------------------------------------------------------------------
diff --git a/ansible/roles/test/files/acstests/lag_test.py b/ansible/roles/test/files/acstests/lag_test.py
index 00c7e8cd26e..957c6f8684e 100644
--- a/ansible/roles/test/files/acstests/lag_test.py
+++ b/ansible/roles/test/files/acstests/lag_test.py
@@ -1,18 +1,7 @@
-'''
-Owner: Hrachya Mughnetsyan
+#-----------------------------------
+# A set of traffic-tests for checking LAGs functionality.
+#-----------------------------------
-Created on: 01/09/2017
-
-Description: This file contains the LAG test for SONIC
- Design is available in https://github.com/Azure/SONiC/wiki/LAG-test-plan
-
-Usage: Examples of how to use log analyzer
- time ptf --test-dir /root/sonic-mgmt/ansible/roles/test/files/acstests lag_test.LagAllRoutes --platform remote -t "verbose=True;router_mac='00:02:03:04:05:00';lag_info='/tmp/lag.txt'"
-'''
-
-#---------------------------------------------------------------------
-# Global imports
-#---------------------------------------------------------------------
import random
import time
import logging
@@ -35,449 +24,106 @@
import ptf.testutils as testutils
from router_utils import *
import pprint
+from scapy.all import rdpcap
-class LagAllRoutes(BaseTest,RouterUtility):
- '''
- @summary: Overview of functionality
- Test routes advertised by BGP peers of SONIC are working properly.
- The setup of peers is described in 'VM set' section in
- https://github.com/Azure/sonic-mgmt/blob/master/ansible/README.testbed.md
-
- Routes advertized by the peers have ECMP groups. The purpose of the test is to make sure
- that packets are forwarded through one of the ports specified in route's ECMP group.
-
-
- This class receives a text file describing the bgp routes added to the switch.
-
- File contains informaiton about each bgp route which was added to the switch.
-
- #-----------------------------------------------------------------------
- Format of the lag_info file
- #-----------------------------------------------------------------------
- Example:
- 192.168.0.0/32 [0,1];[2,3];[4,5];[6,7];[8,9];[10,11];[12,13];[14,15]
- 20C0:A800:0:00::/64 [0,1];[2,3];[4,5];[6,7];[8,9];[10,11];[12,13];[14,15]
-
- 172.16.7.4/32 [22]
- 20AC:1007:0:04::/64 [22]
-
- Meaning:
- Each entry describes IP prefix, and indexes of ports-members of ecmp group for the route.
- The packet should be received from one of those ports.
- #-----------------------------------------------------------------------
-
- The file is loaded on startup and is used to
- - construct packet with correct destination IP
- - validate that packet arrived from switch from a port which
- is member of ECMP group for given route.
-
- For each route test
- - builds a packet with destination IP matching to the IP in the route
- - sends packet to the switch
- - verifies that packet came back from the switch on one of
- the ports specified in the ECMP group of the route.
-
+class LagMembersTrafficTest(BaseTest,RouterUtility):
'''
+ @ summary: run traffic from to . All packets should arrive to .
- #---------------------------------------------------------------------
- # Class variables
- #---------------------------------------------------------------------
- VERBOSE_OUT = True
-
- '''
- Number of copies of the packet to send.
- Currently set to 1. We may decide to increase this in next stages of the test.
+ @ param: dst_addr - destination address of the traffic (usually LAG interface IP)
+ @ param: src_iface - interface, where traffic is sent from
+ @ param: check_pkts_iface - where packets should arrive (because usually one of LAG members is being DOWN in test purposes).
+ @ param: num_of_pkts - amount of traffic to send
+ @ param: dut_mac - DUT MAC address
'''
- IPV4_SEND_PACKET_COPY_CNT = 1
- IPV6_SEND_PACKET_COPY_CNT = 1
-
- '''
- Information about LAG to test.
- '''
- lag_info={}
-
-
def __init__(self):
- '''
- @summary: constructor
- '''
BaseTest.__init__(self)
self.test_params = testutils.test_params_get()
- #---------------------------------------------------------------------
def setUp(self):
'''
@summary: Setup for the test
'''
self.dataplane = ptf.dataplane_instance
- self.router_mac = self.test_params['router_mac']
- #---------------------------------------------------------------------
-
- def print_verbose(self, msg):
- if(not self.VERBOSE_OUT):
- return
- print msg
- #---------------------------------------------------------------------
-
- def load_lag_info(self, lag_info_path):
- '''
- @summary: Load lag_info file into self.lag_info. For details see section 'Format of the lag_info file' in the summary of the class.
- @param lag_info_path : Path to the file
- '''
- with open(lag_info_path, 'r') as lag_info_file:
- for line in lag_info_file:
- line = line.strip()
- if (0==len(line)):
- continue
- prefix_ports_pair = line.split(PREFIX_AND_PORT_SPLITTER)
- port_group_list = prefix_ports_pair[1].split(PORT_GROUP_SPLITTER)
- self.lag_info[prefix_ports_pair[0]]=[]
- for port_group in port_group_list:
- lag_members = port_group[1:-1].split(PORT_LIST_SPLITTER)
- self.lag_info[prefix_ports_pair[0]].append(lag_members)
- return
- #---------------------------------------------------------------------
-
+ def runTest(self):
+ self.dst_addr = self.test_params['dst_addr']
+ self.src_iface = int(self.test_params['src_iface'])
+ self.check_pkts_iface = int(self.test_params['check_pkts_iface'])
+ self.num_of_pkts = int(self.test_params['num_of_pkts'])
+ self.dut_mac = self.test_params['dut_mac']
+
+ slash_index = self.dst_addr.find("/")
+ if slash_index != -1:
+ self.dst_addr = self.dst_addr[:slash_index]
+
+ # Generate packet (use DUT MAC address as next-hop-mac).
+ pkt = simple_icmp_packet(eth_dst=self.dut_mac,
+ ip_dst=self.dst_addr)
+
+ # Generate expected packet (ignore MAC addresses).
+ exp_pkt = simple_icmp_packet(ip_ttl=63,
+ ip_dst=self.dst_addr)
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src")
+
+ # Send packets and verify it on dst port.
+ i = 0
+ while i < int(self.num_of_pkts):
+ send_packet(self, self.src_iface, pkt)
+ verify_packet(self, masked_exp_pkt, self.check_pkts_iface)
+ i += 1
+
+class LacpTimingTest(BaseTest,RouterUtility):
'''
- For diagnostic purposes only
+ @ summary: Verify LACP packets arrive with proper packet timing.
+
+ @ param: exp_iface - where to expect LACP packets.
+ @ param: timeout - time to expect the LACP packet.
+ @ param: packet_timing - time between two packets.
+ @ param: ether_type - Ethernet type of expected packet.
'''
- def print_lag_info(self):
- pprint.pprint(self.lag_info)
- return
- #---------------------------------------------------------------------
-
- def get_spine_ecmp_group(self):
- '''
- @summary: return ecmp group for spine routes
- '''
- for prefix, port_group_list in self.lag_info.iteritems() :
- if len(port_group_list) <= 1 :
- continue
- return port_group_list
-
- return None
- #---------------------------------------------------------------------
-
- def get_lag_total_cnt(self, lag_port_group, port_cnt_map):
- '''
- @summary: Return total number of packets received by given lag.
- @param: lag_port_group - index of lag
- @param: port_cnt_map - map
- '''
- # total packet count for current LAG
- lag_total_cnt = 0
- for port_ind in lag_port_group:
- if int(port_ind) in port_cnt_map:
- lag_total_cnt += port_cnt_map[int(port_ind)]
- return lag_total_cnt
- #---------------------------------------------------------------------
-
- def check_packet_count_ratio(self, actaul_counts, expected_counts, expected_ratio):
- '''
- @summary: Check actual packets are in +/- expected ratio of expected packet count
- '''
- ratio = abs(actaul_counts - expected_counts) / expected_counts
- self.print_verbose('ratio:%f' % ratio)
-
- if (ratio > expected_ratio):
- return False
- return True
- #---------------------------------------------------------------------
-
- def check_lag_member_counts(self, port_cnt_map, ecmp_group_list, expected_ratio = 0.25, inactive_lag_info = None):
- '''
- @summary: Check traffic distributed between lag memeber ports inside each lag.
- @param port_cnt_map: map with collected port counters during runtime
- @ecmp_group_list: list of lags, each containing list of member ports.
- @expected_ratio: Amount of packets received on a lag member shuold be in
- 'expected_ratio' with expected amount of packets on a lag member.
- The expected amount of packets == total packets on lag / number of members.
- @return Boolean
- '''
- self.print_verbose('\ncheck_lag_member_counts --------------\n')
- self.print_verbose('expected_ratio:%f'%expected_ratio)
- if self.VERBOSE_OUT:
- pprint.pprint(port_cnt_map)
-
- if (expected_ratio < 0) or (expected_ratio > 1):
- print 'ERROR: expected_ratio:%d must be in [0,1] value range' % expected_ratio
- return False
-
- result = True
- # process each LAG
- for group_idx, port_group in enumerate(ecmp_group_list) :
-
- self.print_verbose('\ncheck lag[%d] members ----------------' % group_idx)
-
- # total packet count for current LAG
- lag_total_cnt = self.get_lag_total_cnt(port_group, port_cnt_map)
-
- if inactive_lag_info is not None:
- if group_idx == inactive_lag_info[0]:
- self.print_verbose('lag[%d] member marked as inactive' % group_idx)
- if lag_total_cnt != 0:
- self.print_verbose('ERROR: lag[%d] member:%d is marked as inactive, but total lag count is not 0, count:%d' % (group_idx, inactive_lag_info[0], lag_total_cnt))
- result = result and (lag_total_cnt == 0)
- continue
-
- if lag_total_cnt == 0:
- self.print_verbose('lag received 0 packets')
- continue
-
- # expected count on each lag member
- expected_cnt_per_member = float(lag_total_cnt) / len(port_group)
-
- self.print_verbose('lag_total_cnt:%d' % lag_total_cnt)
- self.print_verbose('expected_cnt_per_member:%f' % expected_cnt_per_member)
-
- curr_port_member_actual_count = 0
- for arr_ind, port_ind in enumerate(port_group):
- curr_port_member_actual_count = 0
- if int(port_ind) in port_cnt_map:
- curr_port_member_actual_count = port_cnt_map[int(port_ind)]
- self.print_verbose('lag[%d].port[%d](port:%d) cnt:%d' % (group_idx, arr_ind, int(port_ind), curr_port_member_actual_count))
+ def __init__(self):
+ BaseTest.__init__(self)
+ self.test_params = testutils.test_params_get()
- self.print_verbose('curr_port_member_actual_count:%d' % curr_port_member_actual_count)
-
- lag_member_result = self.check_packet_count_ratio(curr_port_member_actual_count, expected_cnt_per_member, expected_ratio)
- if not lag_member_result:
- print 'ERROR: counters for lag group:%d not correct' % group_idx
- result = result and lag_member_result
-
- return result
-
- #---------------------------------------------------------------------
- def check_lag_counts(self, port_cnt_map, ecmp_group_list, expected_ratio = 0.25, inactive_lag_info = None):
+ def setUp(self):
'''
- @summary: Check traffic distributed between lags
- @param port_cnt_map: map with collected port counters during runtime
- @param inactive_lag_info: tuple
- @return Boolean
+ @summary: Setup for the test
'''
- self.print_verbose('\ncheck_lag_counts ------------\n')
- self.print_verbose('expected_ratio%f'%expected_ratio)
- if self.VERBOSE_OUT:
- pprint.pprint(port_cnt_map)
-
- if (expected_ratio < 0) or (expected_ratio > 1):
- print 'ERROR: expected_ratio:%d must be in [0,1] value range' % expected_ratio
- return False
-
- result = True
-
- lag_counter = {}
- lag_total_cnt = 0
- # get counters for each LAG, and total across all LAGs.
- for group_idx, port_group in enumerate(ecmp_group_list) :
- # total packet count for current LAG
- lag_cnt = self.get_lag_total_cnt(port_group, port_cnt_map)
- self.print_verbose('lag[%d] counter:%d' % (group_idx, lag_cnt))
-
- if (inactive_lag_info is not None) and (group_idx == inactive_lag_info[0]):
- self.print_verbose('lag[%d] member:%d marked as inactive.'%(group_idx,inactive_lag_info[1]))
- if lag_cnt != 0:
- self.print_verbose('ERROR: counter of inactive lag[%d] is not 0. counter:%d' % (group_idx, lag_cnt))
- result = False
- else:
- lag_counter[group_idx] = lag_cnt
- lag_total_cnt += lag_cnt
-
- self.print_verbose('lag_total_cnt:%d' % lag_total_cnt)
- if self.VERBOSE_OUT:
- print 'lag counters:',
- pprint.pprint(lag_counter)
-
- if lag_total_cnt == 0:
- self.print_verbose('No traffic passed through any of lags')
- return False
-
- # expected count on each lag member
- expected_cnt_per_lag = float(lag_total_cnt) / len(lag_counter)
- self.print_verbose('expected_cnt_per_lag:%f' % expected_cnt_per_lag)
-
- # check counter on each LAG
- for lag_ind, actual_lag_cnt in lag_counter.iteritems():
- self.print_verbose('\ncheck lag[%d] ----------------' % lag_ind)
- self.print_verbose('actual_lag_cnt:%d' % actual_lag_cnt)
- lag_result = self.check_packet_count_ratio(actual_lag_cnt, expected_cnt_per_lag, expected_ratio)
- if not lag_result:
- print 'ERROR: counters for lag:%d not correct' % lag_ind
- result = result and lag_result
+ self.dataplane = ptf.dataplane_instance
- return result
- #---------------------------------------------------------------------
-
- def update_port_counter(self, port_counter, rcv_port_ind, count):
- '''
- @summary: update(increment) packet counter for given phisical port
- @param port_counter: map holding counters for each port
- @param rcv_port_ind: port for which to update the counter
- @param count: amount by which to update the counter
- '''
- if rcv_port_ind in port_counter:
- port_counter[rcv_port_ind] += count
- else:
- port_counter[rcv_port_ind] = count
+ def runTest(self):
- #---------------------------------------------------------------------
- def generate_ipv4_list(self, outer_range = 254, inner_range = 16):
- '''
- @summary: Generate list of ipv4 addresses to be used for packet generation
- @param outer_range: range of values for -.-.X.- component of IP address
- @param inner_range: range of values for -.-.-.X component of IP address
- '''
- # Generate SRC IP list for packets.
- src_ipv4_list = []
- IP_LAST_WORD_RANGE = outer_range#max 254
- IP_2ND_LAST_WORD_RANGE = inner_range#max 16
- for i in xrange(IP_LAST_WORD_RANGE):
- for j in xrange(IP_2ND_LAST_WORD_RANGE):
- src_ipv4_addr = '10.0.' + str(j) + '.' + str(i+1)
- src_ipv4_list.append(src_ipv4_addr)
- return src_ipv4_list
+ # Get test parameters
+ self.exp_iface = self.test_params['exp_iface']
+ self.timeout = self.test_params['timeout']
+ self.packet_timing = self.test_params['packet_timing']
+ self.ether_type = self.test_params['ether_type']
- #---------------------------------------------------------------------
- def generate_ipv6_list(self, outer_range = 5, inner_range = 10):
- '''
- @summary: Generate list of ipv6 addresses to be used for packet generation
- @param outer_range: range of values for ---X::- component of IP address
- @param inner_range: range of values for ----::X component of IP address
- '''
- # Generate SRC IP list for packets.
- src_ipv6_list = []
- for i in xrange(outer_range):
- for j in xrange(inner_range):
- src_ipv6_addr = '200' + str(i) + '::' + str(j)
- src_ipv6_list.append(src_ipv6_addr)
- return src_ipv6_list
- #---------------------------------------------------------------------
-
- def get_inactive_lag_info(self):
- '''
- @summary: parse test_params for information about inactive lag.
- lag_index specifies index of the lag which is inactive.
- member_index specifies index of the lag member port which is inactive.
- '''
- inactive_lag_info = None
- lag_index = None
- member_index = None
- if 'lag_index' in self.test_params:
- lag_index = self.test_params["lag_index"]
-
- if 'member_index' in self.test_params:
- member_index = self.test_params["member_index"]
-
- if (lag_index is None) and (member_index is None):
- inactive_lag_info = None
- elif (lag_index is not None) and (member_index is not None):
- inactive_lag_info = (lag_index, member_index)
- else:
- print 'Invalid input parameters for inactive lag state'
- assert(False)
-
- return inactive_lag_info
-
- #---------------------------------------------------------------------
-
- def runTest(self):
- """
- @summary: Send packet for each route and validate it arrives
- on one of expected ECMP ports
- """
+ # Generate a packet.
+ exp_pkt = simple_eth_packet(eth_type=self.ether_type)
+ exp_pkt = exp_pkt/("0" * 64)
- self.load_lag_info(self.test_params["lag_info"])
- inactive_lag_info = self.get_inactive_lag_info()
- pprint.pprint(inactive_lag_info)
- passed_prefic_count = 0
- test_result = True
- result = True
- total_ipv4_packet_cnt = 0
- total_ipv6_packet_cnt = 0
- port_counter = {}
- src_ipv4_list = []
- src_ipv6_list = []
-
-
- for prefix, port_group_list in self.lag_info.iteritems() :
- dest_ip_addr = prefix.split("/")[0]
- destination_port_list = []
-
- # Generate list of destination ports to receive packet from for current route
- for port_group in port_group_list :
- for port_index in port_group:
- destination_port_list.append(int(port_index))
-
- # send packet through each port which is NOT in the list of destination ports,
- # otherwise there will be a loop-back and switch will drop packets
- # Pick random port to send through
- src_port = random.randint(0, PORT_COUNT-1)
- while src_port in destination_port_list:
- src_port = random.randint(0, PORT_COUNT-1)
-
-
- # Generate ipv4 and ipv6 packets to be sent.
- # Format: map
- ipv4_packets = {}
- ipv6_packets = {}
-
- if self.is_ipv4_address(dest_ip_addr):
- if 'skip_ipv4' in self.test_params:
- continue
- #Generate list of src_ip addresses. Currently we generate only 1 src_ip, but
- #in next stages of test we'll generate N amount(tbd).
- src_ipv4_list = self.generate_ipv4_list(1,1)
-
- for ipv4_src in src_ipv4_list :
- sport = random.randint(0,0xffff)
- dport = random.randint(0,0xffff)
- src_mac = self.create_random_mac()
- ipv4_packets[ipv4_src] = self.create_ipv4_packets(ipv4_src, sport, dport, dest_ip_addr, destination_port_list, src_mac)
+ # Ignore fields with value unknown
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"dst")
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"src")
+ masked_exp_pkt.set_do_not_care(14 * 8, 110 * 8)
- for src_ip in ipv4_packets:
- total_ipv4_packet_cnt += self.IPV4_SEND_PACKET_COPY_CNT
- ret_val, rcv_port_ind = self.check_route(ipv4_packets[src_ip][0], ipv4_packets[src_ip][1], src_port, dest_ip_addr, destination_port_list, self.IPV4_SEND_PACKET_COPY_CNT)
- result = result and ret_val
- self.update_port_counter(port_counter, destination_port_list[rcv_port_ind], self.IPV4_SEND_PACKET_COPY_CNT)
+ # Verify two LACP packets.
+ (rcv_device, rcv_port, rcv_pkt, first_pkt_time) = self.dataplane.poll(port_number=self.exp_iface, timeout=self.timeout, exp_pkt=masked_exp_pkt)
+ (rcv_device, rcv_port, rcv_pkt, last_pkt_time) = self.dataplane.poll(port_number=self.exp_iface, timeout=self.timeout, exp_pkt=masked_exp_pkt)
- elif self.is_ipv6_address(dest_ip_addr):
- if 'skip_ipv6' in self.test_params:
- continue
- #Generate list of src_ip addresses. Currently we generate only 1 src_ip, but
- #in next stages of test we'll generate N amount(tbd).
- src_ipv6_list = self.generate_ipv6_list(1,1)
-
- for ipv6_src in src_ipv6_list :
- sport = random.randint(0,0xffff)
- dport = random.randint(0,0xffff)
- src_mac = self.create_random_mac()
- ipv6_packets[ipv6_src] = self.create_ipv6_packets(ipv6_src, sport, dport, dest_ip_addr, destination_port_list, src_mac)
-
- for src_ip in ipv6_packets:
- total_ipv6_packet_cnt += self.IPV6_SEND_PACKET_COPY_CNT
- ret_val, rcv_port_ind = self.check_route(ipv6_packets[src_ip][0], ipv6_packets[src_ip][1], src_port, dest_ip_addr, destination_port_list, self.IPV6_SEND_PACKET_COPY_CNT)
- result = result and ret_val
- self.update_port_counter(port_counter, destination_port_list[rcv_port_ind], self.IPV6_SEND_PACKET_COPY_CNT)
- else:
- print 'Invalid ip address:%s\n' % dest_ip_addr
- assert(False)
+ # Check the packet received.
+ self.assertTrue(rcv_pkt != None, "Failed to receive LACP packet\n")
- test_result = test_result and result
- if(result):
- passed_prefic_count = passed_prefic_count + 1
-
-
- spine_ecmp_group = self.get_spine_ecmp_group()
- lag_member_counter_check = self.check_lag_member_counts(port_counter, spine_ecmp_group, 0.25, inactive_lag_info)
- lag_counter_check = self.check_lag_counts(port_counter, spine_ecmp_group, 0.25, inactive_lag_info)
-
- print 'passed routes count:%d' % passed_prefic_count
- print 'total_ipv4_packet_cnt:%d' % total_ipv4_packet_cnt
- print 'total_ipv6_packet_cnt:%d' % total_ipv6_packet_cnt
+ # Get current packet timing
+ first_pkt_time = round(float(first_pkt_time), 2)
+ last_pkt_time = round(float(last_pkt_time), 2)
+ current_pkt_timing = last_pkt_time - first_pkt_time
- assert(lag_member_counter_check)
- assert(lag_counter_check)
-
- assert(test_result)
- #---------------------------------------------------------------------
+ # Check that packet timing matches the expected value.
+ self.assertTrue(abs(current_pkt_timing - float(self.packet_timing)) < 0.01, "Bad packet timing: %.2f seconds while expected timing is %d seconds" % (current_pkt_timing, self.packet_timing))
diff --git a/ansible/roles/test/files/acstests/router_utils.py b/ansible/roles/test/files/acstests/router_utils.py
index 9011a35732c..222a598db32 100644
--- a/ansible/roles/test/files/acstests/router_utils.py
+++ b/ansible/roles/test/files/acstests/router_utils.py
@@ -19,6 +19,30 @@
PORT_COUNT = 32
class RouterUtility():
+ route_info = {}
+ def load_route_info(self, route_info_path):
+ '''
+ @summary: Load route_info file into self.route_info. For details see section 'Format of the route_info file' in the summary of the class.
+ @param route_info_path : Path to the file
+ '''
+ with open(route_info_path, 'r') as route_info_file:
+ for line in route_info_file:
+ line = line.strip()
+ if (0==len(line)):
+ continue
+ prefix_ports_pair = line.split(PREFIX_AND_PORT_SPLITTER)
+ port_list = prefix_ports_pair[1].split(PORT_LIST_SPLITTER)
+ self.route_info[prefix_ports_pair[0]]=port_list
+ return
+ #---------------------------------------------------------------------
+
+ def print_route_info(self):
+ '''
+ For diagnostic purposes only
+ '''
+ pprint.pprint(self.route_info)
+ return
+ #---------------------------------------------------------------------
def is_ipv4_address(self, ipaddr):
'''
@summary: Check address is valid IPv4 address.
@@ -178,4 +202,4 @@ def check_route(self, pkt, masked_exp_pkt, source_port_index, dest_ip_addr, dest
return received, match_index
#---------------------------------------------------------------------
-
\ No newline at end of file
+
diff --git a/ansible/roles/test/files/helpers/announce_routes.py b/ansible/roles/test/files/helpers/announce_routes.py
new file mode 100644
index 00000000000..e13849ac5b3
--- /dev/null
+++ b/ansible/roles/test/files/helpers/announce_routes.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import cPickle
+import os
+import time
+import sys
+
+with open(sys.argv[1]) as f:
+ routes = f.readlines()
+
+routes=[x.strip() for x in routes]
+ports = set()
+
+for route in routes:
+ [command, port] = route.split(";")
+ port = port.strip()
+ ports.add(port)
+ os.system('curl -s --form "command=%s" http://localhost:%s/' % (command, port))
+
+for n in range(0, 20):
+ time.sleep(10)
+ for port in ports:
+ os.system('curl -s --form "command=flush route" http://localhost:%s/' % port)
+
diff --git a/ansible/roles/test/files/helpers/arp_responder.py b/ansible/roles/test/files/helpers/arp_responder.py
new file mode 100644
index 00000000000..89dce78f417
--- /dev/null
+++ b/ansible/roles/test/files/helpers/arp_responder.py
@@ -0,0 +1,154 @@
+import binascii
+import socket
+import struct
+import select
+import json
+import argparse
+import os.path
+from fcntl import ioctl
+from pprint import pprint
+
+
+def hexdump(data):
+ print " ".join("%02x" % ord(d) for d in data)
+
+def get_if(iff, cmd):
+ s = socket.socket()
+ ifreq = ioctl(s, cmd, struct.pack("16s16x",iff))
+ s.close()
+
+ return ifreq
+
+def get_mac(iff):
+ SIOCGIFHWADDR = 0x8927 # Get hardware address
+ return get_if(iff, SIOCGIFHWADDR)[18:24]
+
+
+class Interface(object):
+ ETH_P_ALL = 0x03
+ RCV_TIMEOUT = 1000
+ RCV_SIZE = 4096
+
+ def __init__(self, iface):
+ self.iface = iface
+ self.socket = None
+ self.mac_address = get_mac(iface)
+
+ def __del__(self):
+ if self.socket:
+ self.socket.close()
+
+ def bind(self):
+ self.socket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(self.ETH_P_ALL))
+ self.socket.bind((self.iface, 0))
+ self.socket.settimeout(self.RCV_TIMEOUT)
+
+ def handler(self):
+ return self.socket.fileno()
+
+ def recv(self):
+ return self.socket.recv(self.RCV_SIZE)
+
+ def send(self, data):
+ self.socket.send(data)
+
+ def mac(self):
+ return self.mac_address
+
+ def name(self):
+ return self.iface
+
+
+class Poller(object):
+ def __init__(self, interfaces, responder):
+ self.responder = responder
+ self.mapping = {}
+ for interface in interfaces:
+ self.mapping[interface.handler()] = interface
+
+ def poll(self):
+ handlers = self.mapping.keys()
+ while True:
+ (rdlist, _, _) = select.select(handlers, [], [])
+ for handler in rdlist:
+ self.responder.action(self.mapping[handler])
+
+
+class ARPResponder(object):
+ ARP_PKT_LEN = 60
+ def __init__(self, ip_sets):
+ self.arp_chunk = binascii.unhexlify('08060001080006040002') # defines a part of the packet for ARP Reply
+ self.arp_pad = binascii.unhexlify('00' * 18)
+
+ self.ip_sets = ip_sets
+
+ return
+
+ def action(self, interface):
+ data = interface.recv()
+ if len(data) != self.ARP_PKT_LEN:
+ return
+
+ remote_mac, remote_ip, request_ip = self.extract_arp_info(data)
+
+ request_ip_str = socket.inet_ntoa(request_ip)
+ if request_ip_str not in self.ip_sets[interface.name()]:
+ return
+
+ arp_reply = self.generate_arp_reply(self.ip_sets[interface.name()][request_ip_str], remote_mac, request_ip, remote_ip)
+ interface.send(arp_reply)
+
+ return
+
+ def extract_arp_info(self, data):
+ return data[6:12], data[28:32], data[38:42] # remote_mac, remote_ip, request_ip
+
+ def generate_arp_reply(self, local_mac, remote_mac, local_ip, remote_ip):
+ return remote_mac + local_mac + self.arp_chunk + local_mac + local_ip + remote_mac + remote_ip + self.arp_pad
+
+def parse_args():
+ parser = argparse.ArgumentParser(description='ARP autoresponder')
+ parser.add_argument('--conf', '-c', type=str, dest='conf', default='/tmp/from_t1.json', help='path to json file with configuration')
+ parser.add_argument('--extended', '-e', action='store_true', dest='extended', default=False, help='enable extended mode')
+ args = parser.parse_args()
+
+ return args
+
+def main():
+ args = parse_args()
+
+ if not os.path.exists(args.conf):
+ print "Can't find file %s" % args.conf
+ return
+
+ with open(args.conf) as fp:
+ data = json.load(fp)
+
+ # generate ip_sets. every ip address will have it's own uniq mac address
+ ip_sets = {}
+ counter = 0
+ for iface, ip_dict in data.items():
+ ip_sets[str(iface)] = {}
+ if args.extended:
+ for ip, mac in ip_dict.items():
+ ip_sets[str(iface)][str(ip)] = binascii.unhexlify(str(mac))
+ counter += 1
+ else:
+ for ip in ip_dict:
+ ip_sets[str(iface)][str(ip)] = get_mac(iface)
+
+ ifaces = []
+ for iface_name in ip_sets.keys():
+ iface = Interface(iface_name)
+ iface.bind()
+ ifaces.append(iface)
+
+ resp = ARPResponder(ip_sets)
+
+ p = Poller(ifaces, resp)
+ p.poll()
+
+ return
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible/roles/test/files/helpers/change_mac.sh b/ansible/roles/test/files/helpers/change_mac.sh
new file mode 100644
index 00000000000..bc72109f753
--- /dev/null
+++ b/ansible/roles/test/files/helpers/change_mac.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+for i in $(ifconfig | grep eth | cut -f 1 -d ' ')
+do
+ prefix=$(ifconfig $i | grep HWaddr | cut -c39-53)
+ suffix=$( printf "%02d" ${i##eth})
+ mac=$prefix$suffix
+ echo $i $mac
+ ifconfig $i hw ether $mac
+done
diff --git a/ansible/roles/test/files/helpers/dump.py b/ansible/roles/test/files/helpers/dump.py
new file mode 100644
index 00000000000..4bca81fe6a7
--- /dev/null
+++ b/ansible/roles/test/files/helpers/dump.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+from sys import stdin
+import json
+import os
+import sys
+
+while True:
+ try:
+ line = stdin.readline()
+ obj = json.loads(line)
+ f = open("/root/exabgp/" + obj["neighbor"]["ip"], "a")
+ print >> f, line,
+ f.close()
+ except:
+ continue
diff --git a/ansible/roles/test/files/helpers/http_api.py b/ansible/roles/test/files/helpers/http_api.py
new file mode 100644
index 00000000000..fd719b28c86
--- /dev/null
+++ b/ansible/roles/test/files/helpers/http_api.py
@@ -0,0 +1,16 @@
+from flask import Flask, request
+import sys
+
+app = Flask(__name__)
+
+# Setup a command route to listen for prefix advertisements
+@app.route('/', methods=['POST'])
+def run_command():
+ command = request.form['command']
+ sys.stdout.write('%s\n' % command)
+ sys.stdout.flush()
+ return 'OK\n'
+
+if __name__ == '__main__':
+ app.run(port=sys.argv[1])
+
diff --git a/ansible/roles/test/files/helpers/invert_iface_behind_lag_member.yml b/ansible/roles/test/files/helpers/invert_iface_behind_lag_member.yml
new file mode 100644
index 00000000000..747268884b2
--- /dev/null
+++ b/ansible/roles/test/files/helpers/invert_iface_behind_lag_member.yml
@@ -0,0 +1,15 @@
+#------------------------------
+# This playbook inverts iface_behind_lag_member_index variable (from 0 to 1, and vice versa).
+#------------------------------
+
+- set_fact:
+ inverted: 0
+
+- set_fact:
+ iface_behind_lag_member_index: 1
+ inverted: 1
+ when: iface_behind_lag_member_index == 0
+
+- set_fact:
+ iface_behind_lag_member_index: 0
+ when: (iface_behind_lag_member_index == 1) and (inverted == 0)
diff --git a/ansible/roles/test/files/mem_check.sh b/ansible/roles/test/files/mem_check.sh
new file mode 100755
index 00000000000..eeb2250bdeb
--- /dev/null
+++ b/ansible/roles/test/files/mem_check.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+#
+# mem_check.sh
+#
+# Check for memory leaks in Redis client output buffers
+# Returns 0 if under threshold, 1 if over threshold
+#
+
+REDIS_CLIENT_LIST_OUTPUT_FILE=/tmp/redis_client_list
+
+OMEM_THRESHOLD_BYTES=1048576 # 1MB
+
+TOTAL_OMEM_BYTES=0
+
+# Save 'redis-cli client list' output to temp file
+/usr/bin/redis-cli client list > $REDIS_CLIENT_LIST_OUTPUT_FILE
+
+# Extract 'omem' value from each line (client)
+while read LINE; do
+ OMEM_BYTES=$(echo $LINE | sed 's/.*omem=\([0-9][0-9]*\) .*/\1/')
+ TOTAL_OMEM_BYTES=$((TOTAL_OMEM_BYTES += OMEM_BYTES))
+done < $REDIS_CLIENT_LIST_OUTPUT_FILE
+
+# Clean up
+rm $REDIS_CLIENT_LIST_OUTPUT_FILE
+
+if [ $TOTAL_OMEM_BYTES -gt $OMEM_THRESHOLD_BYTES ]; then
+ exit 1
+fi
+
+exit 0
+
diff --git a/ansible/roles/test/files/ptftests/IP_decap_test.py b/ansible/roles/test/files/ptftests/IP_decap_test.py
new file mode 100644
index 00000000000..274526e88ff
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/IP_decap_test.py
@@ -0,0 +1,167 @@
+'''
+Description: This file contains the Decapasulation test for SONIC, to test Decapsulation of IPv4 with double and triple encapsulated packets
+
+ Design is available in https://github.com/Azure/SONiC/wiki/IPv4-Decapsulation-test
+
+Precondition: Before the test start, all routes need to be defined as in the fib_info.txt file, in addition to the decap rule that need to be set as the dspc_mode
+topology: SUpports t1, t1-lag and t0 topology
+
+Usage: Examples of how to start the test
+ ptf --test-dir /root/dor/ ip_decap_test_red --platform remote -t "verbose=True;fib_info='/root/fib_info.txt';lo_ip='10.1.0.32';router_mac='00:02:03:04:05:00';dscp_mode='pipe'; testbed_type='t1'" --log-dir /tmp/logs --verbose
+Parameters: fib_info - The fib_info file location
+ lo_ip - The loop_back IP that is configured in the decap rule
+ router_mac - The mac of the router_mac
+ testbed_type - The type of testbed topology
+ dscp_mode - The rule for the dscp parameter in the decap packet that is configured in the JSON file ('pipe' for inner and 'uniform' for outer)
+
+'''
+
+#---------------------------------------------------------------------
+# Global imports
+#---------------------------------------------------------------------
+import random
+import time
+import logging
+import ptf.packet as scapy
+import socket
+import ptf.dataplane as dataplane
+
+from ptf.testutils import *
+from ptf.mask import Mask
+import ipaddress
+
+import os
+import unittest
+
+import ptf
+from ptf.base_tests import BaseTest
+from ptf import config
+import ptf.dataplane as dataplane
+import ptf.testutils as testutils
+
+import pprint
+
+import fib
+
+class DecapPacketTest(BaseTest):
+ def __init__(self):
+ '''
+ @summary: constructor
+ '''
+ BaseTest.__init__(self)
+ self.test_params = testutils.test_params_get()
+ #-----------------------------------------------------------------
+ def setUp(self):
+ '''
+ @summary: Setup for the test
+ '''
+ self.dataplane = ptf.dataplane_instance
+ self.router_mac = self.test_params['router_mac']
+ self.fib = fib.Fib(self.test_params['fib_info'])
+ if self.test_params['testbed_type'] == 't1' or self.test_params['testbed_type'] == 't1-lag':
+ self.src_ports = range(0, 32)
+ if self.test_params['testbed_type'] == 't0':
+ self.src_ports = range(1, 25) + range(28, 32)
+ #-----------------------------------------------------------------
+
+ def send_and_verify(self, dst_ip, expected_ports, src_port, triple_encap = False):
+ '''
+ @summary: This function builds encap packet, send and verify their arrival.
+ @dst_ip: the destination ip for the inner IP header
+ @expected_ports: list of ports that a packet can arrived from
+ @src_port: the physical port that the packet will be sent from
+ @triple_encap: True to send triple encapsulated packet
+ '''
+ #setting parameters
+ src_mac = self.dataplane.get_mac(0, 0)
+ dst_mac = '00:11:22:33:44:55'
+ inner_src_ip = '2.2.2.2'
+ router_mac = self.test_params['router_mac']
+ dscp_in = random.randint(0, 32)
+ tos_in = dscp_in << 2
+ dscp_out = random.randint(0, 32)
+ tos_out = dscp_out << 2
+ if ("pipe" == self.test_params['dscp_mode']):
+ exp_tos = tos_in
+ elif("uniform" == self.test_params['dscp_mode']):
+ exp_tos = tos_out
+ else:
+ print("ERROR: no dscp is configured")
+ exit()
+
+ default_packet_len = 100
+ default_packet_add_header_len = 114
+
+ #building the packets and the expected packets
+ if (not triple_encap):
+ #for the double encap packet we will use IP header with TCP header without mac
+ inner_pkt = simple_ip_only_packet(ip_dst=dst_ip, ip_src=inner_src_ip, ip_ttl=64, ip_tos=tos_in)
+ #after the decap process the retuning packet will be normal tcp packet, The TTL is taked from the inner layer and redused by one
+ exp_pkt = simple_tcp_packet(pktlen=default_packet_add_header_len,
+ eth_dst=dst_mac,
+ eth_src=router_mac,
+ ip_dst=dst_ip,
+ ip_src=inner_src_ip,
+ ip_tos=exp_tos,
+ ip_ttl=63)
+ else:
+ #Building triple encap packet with SCAPY, because there is no PTF function for it, I use the defualt values for the TCP header
+ tcp_hdr = scapy.TCP(sport=1234, dport=80, flags="S", chksum=0)
+ inner_pkt2 = scapy.IP(src='4.4.4.4', dst='3.3.3.3', tos=0, ttl=64, id=1, ihl=None) / tcp_hdr
+ inner_pkt = scapy.IP(src=inner_src_ip, dst=dst_ip, tos=tos_in, ttl=64, id=1, ihl=None,proto=4) / inner_pkt2
+ inner_pkt = inner_pkt/("".join([chr(x) for x in xrange(default_packet_len - len(inner_pkt))]))
+ #The expected packet is also built by scapy, and the TTL is taked from the inner layer and redused by one
+ exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac)/inner_pkt
+ exp_pkt['IP'].tos = exp_tos #this parameter is taken by the decap rule configuration
+ exp_pkt['IP'].ttl = 63
+
+ pkt = simple_ipv4ip_packet(
+ eth_dst=router_mac,
+ eth_src=src_mac,
+ ip_src='1.1.1.1',
+ ip_dst=self.test_params['lo_ip'],
+ ip_tos=tos_out,
+ ip_ttl=random.randint(2, 63),
+ inner_frame=inner_pkt)
+
+ #send and verify the return packets
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src")
+ send_packet(self, src_port, pkt)
+ logging.info(".....Sending packet from port" + str(src_port) + " to " + dst_ip + ", Triple_encap: " + str(triple_encap))
+ (matched, received) = verify_packet_any_port(self, masked_exp_pkt, expected_ports)
+ assert received
+ return (matched, received)
+ #-----------------------------------------------------------------
+
+ def runTest(self):
+ """
+ @summary: Send double and triple encapsulated packets for each range of IPv4 and
+ expect the packet to be received from one of the expected ports
+ """
+ # IPv4 Test
+ for ip_range in self.fib.ipv4_ranges():
+ # Get the expected list of ports that would receive the packets
+ exp_port_list = self.fib[ip_range.get_first_ip()].get_next_hop_list()
+ # Choose random one source port from all ports excluding the expected ones
+ src_port = random.choice([port for port in self.src_ports if port not in exp_port_list])
+
+ if not len(exp_port_list):
+ continue
+
+ logging.info("Check IP range:" + str(ip_range) + " on " + str(exp_port_list) + "...")
+ # Send a packet with the first IP in the range
+ self.send_and_verify(ip_range.get_first_ip(), exp_port_list, src_port)
+ self.send_and_verify(ip_range.get_first_ip(), exp_port_list, src_port, True)
+ # Send a packet with the last IP in the range
+ if ip_range.length() > 1:
+ self.send_and_verify(ip_range.get_last_ip(), exp_port_list, src_port)
+ self.send_and_verify(ip_range.get_last_ip(), exp_port_list, src_port, True)
+ # Send a packet with a random IP in the range
+ if ip_range.length() > 2:
+ self.send_and_verify(ip_range.get_random_ip(), exp_port_list, src_port)
+ self.send_and_verify(ip_range.get_random_ip(), exp_port_list, src_port, True)
+#---------------------------------------------------------------------
+
+
diff --git a/ansible/roles/test/files/ptftests/copp_tests.py b/ansible/roles/test/files/ptftests/copp_tests.py
new file mode 100644
index 00000000000..fe18decb772
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/copp_tests.py
@@ -0,0 +1,421 @@
+# ptf --test-dir saitests copp_tests --qlen=100000 --platform nn -t "verbose=True;pkt_tx_count=100000" --device-socket 0-3@tcp://127.0.0.1:10900 --device-socket 1-3@tcp://10.3.147.47:10900
+#
+# copp_test.${name_test}
+#
+# ARPTest
+# DHCPTest
+# LLDPTest
+# BGPTest
+# LACPTest
+# SNMPTest
+# SSHTest
+# IP2METest
+# DefaultTest
+
+import ptf
+from ptf.base_tests import BaseTest
+from ptf import config
+import ptf.testutils as testutils
+from ptf.testutils import *
+from ptf.dataplane import match_exp_pkt
+import os
+import signal
+import datetime
+import subprocess
+import threading
+
+
+class ControlPlaneBaseTest(BaseTest):
+ MAX_PORTS = 32
+ PPS_LIMIT = 600
+ PPS_LIMIT_MIN = PPS_LIMIT * 0.9
+ PPS_LIMIT_MAX = PPS_LIMIT * 1.1
+ NO_POLICER_LIMIT = PPS_LIMIT * 1.4
+ PKT_TX_COUNT = 100000
+ TASK_TIMEOUT = 300 # Wait up to 5 minutes for tasks to complete
+
+ def __init__(self):
+ BaseTest.__init__(self)
+ self.log_fp = open('/tmp/copp.log', 'a')
+ test_params = testutils.test_params_get()
+ self.verbose = 'verbose' in test_params and test_params['verbose']
+
+ self.pkt_tx_count = test_params.get('pkt_tx_count', self.PKT_TX_COUNT)
+ if self.pkt_tx_count == 0:
+ self.pkt_tx_count = self.PKT_TX_COUNT
+ self.pkt_rx_limit = self.pkt_tx_count * 0.90
+
+ self.timeout_thr = None
+
+ self.myip = {}
+ self.peerip = {}
+ for i in xrange(self.MAX_PORTS):
+ self.myip[i] = "10.0.0.%d" % (i*2+1)
+ self.peerip[i] = "10.0.0.%d" % (i*2)
+
+ return
+
+ def log(self, message, debug=False):
+ current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ if (debug and self.verbose) or (not debug):
+ print "%s : %s" % (current_time, message)
+ self.log_fp.write("%s : %s\n" % (current_time, message))
+
+ def setUp(self):
+ self.dataplane = ptf.dataplane_instance
+
+ self.my_mac = {}
+ self.peer_mac = {}
+ for port_id, port in self.dataplane.ports.iteritems():
+ if port_id[0] == 0:
+ self.my_mac[port_id[1]] = port.mac()
+ elif port_id[0] == 1:
+ self.peer_mac[port_id[1]] = port.mac()
+ else:
+ assert True
+
+ self.dataplane.flush()
+ if config["log_dir"] != None:
+ filename = os.path.join(config["log_dir"], str(self)) + ".pcap"
+ self.dataplane.start_pcap(filename)
+
+ def tearDown(self):
+ if config["log_dir"] != None:
+ self.dataplane.stop_pcap()
+ self.log_fp.close()
+
+ def timeout(self, seconds, message):
+ def timeout_exception(self, message):
+ self.log('Timeout is reached: %s' % message)
+ self.tearDown()
+ os.kill(os.getpid(), signal.SIGINT)
+
+ if self.timeout_thr is None:
+ self.timeout_thr = threading.Timer(seconds, timeout_exception, args=(self, message))
+ self.timeout_thr.start()
+ else:
+ raise Exception("Timeout already set")
+
+ def cancel_timeout(self):
+ if self.timeout_thr is not None:
+ self.timeout_thr.cancel()
+ self.timeout_thr = None
+
+ def copp_test(self, packet, count, send_intf, recv_intf):
+ b_c_0 = self.dataplane.get_counters(*send_intf)
+ b_c_1 = self.dataplane.get_counters(*recv_intf)
+ b_n_0 = self.dataplane.get_nn_counters(*send_intf)
+ b_n_1 = self.dataplane.get_nn_counters(*recv_intf)
+
+ start_time=datetime.datetime.now()
+
+ for i in xrange(count):
+ testutils.send_packet(self, send_intf, packet)
+
+ end_time=datetime.datetime.now()
+
+ total_rcv_pkt_cnt = testutils.count_matched_packets(self, packet, recv_intf[1], recv_intf[0])
+
+ e_c_0 = self.dataplane.get_counters(*send_intf)
+ e_c_1 = self.dataplane.get_counters(*recv_intf)
+ e_n_0 = self.dataplane.get_nn_counters(*send_intf)
+ e_n_1 = self.dataplane.get_nn_counters(*recv_intf)
+ self.log("", True)
+ self.log("Counters before the test:", True)
+ self.log("If counter (0, n): %s" % str(b_c_0), True)
+ self.log("NN counter (0, n): %s" % str(b_n_0), True)
+ self.log("If counter (1, n): %s" % str(b_c_1), True)
+ self.log("NN counter (1, n): %s" % str(b_n_1), True)
+ self.log("", True)
+ self.log("Counters after the test:", True)
+ self.log("If counter (0, n): %s" % str(e_c_0), True)
+ self.log("NN counter (0, n): %s" % str(e_n_0), True)
+ self.log("If counter (1, n): %s" % str(e_c_1), True)
+ self.log("NN counter (1, n): %s" % str(e_n_1), True)
+ self.log("")
+ self.log("Sent through NN to local ptf_nn_agent: %d" % int(e_c_0[1] - b_c_0[1]))
+ self.log("Sent through If to remote ptf_nn_agent: %d" % int(e_n_0[1] - b_n_0[1]))
+ self.log("Recv from If on remote ptf_nn_agent: %d" % int(e_c_1[0] - b_c_1[0]))
+ self.log("Recv from NN on from remote ptf_nn_agent: %d" % int(e_n_1[0] - b_n_1[0]))
+
+ time_delta = end_time - start_time
+ time_delta_ms = (time_delta.microseconds + time_delta.seconds * 10**6) / 10**3
+ tx_pps = int(count/(float(time_delta_ms)/1000))
+ rx_pps = int(total_rcv_pkt_cnt/(float(time_delta_ms)/1000))
+
+ return total_rcv_pkt_cnt, time_delta, time_delta_ms, tx_pps, rx_pps
+
+ def contruct_packet(self, port_number):
+ raise NotImplemented
+
+ def check_constraints(self, total_rcv_pkt_cnt, time_delta_ms, rx_pps):
+ raise NotImplemented
+
+ def one_port_test(self, port_number):
+ packet = self.contruct_packet(port_number)
+ total_rcv_pkt_cnt, time_delta, time_delta_ms, tx_pps, rx_pps = self.copp_test(str(packet), self.pkt_tx_count, (0, port_number), (1, port_number))
+ self.printStats(self.pkt_tx_count, total_rcv_pkt_cnt, time_delta, tx_pps, rx_pps)
+ self.check_constraints(total_rcv_pkt_cnt, time_delta_ms, rx_pps)
+
+ return
+
+ def run_suite(self):
+ self.timeout(self.TASK_TIMEOUT, "The test case hasn't been completed in %d seconds" % self.TASK_TIMEOUT) # FIXME: better make it decorator
+ self.one_port_test(3)
+ self.cancel_timeout()
+
+ def printStats(self, pkt_send_count, total_rcv_pkt_cnt, time_delta, tx_pps, rx_pps):
+ self.log("")
+ self.log('test stats')
+ self.log('Packet sent = %10d' % pkt_send_count)
+ self.log('Packet rcvd = %10d' % total_rcv_pkt_cnt)
+ self.log('Test time = %s' % str(time_delta))
+ self.log('TX PPS = %d' % tx_pps)
+ self.log('RX PPS = %d' % rx_pps)
+
+ return
+
+class NoPolicyTest(ControlPlaneBaseTest):
+ def __init__(self):
+ ControlPlaneBaseTest.__init__(self)
+
+ def check_constraints(self, total_rcv_pkt_cnt, time_delta_ms, rx_pps):
+ self.log("")
+ self.log("Checking constraints (NoPolicy):")
+ self.log("rx_pps (%d) > NO_POLICER_LIMIT (%d): %s" % (int(rx_pps), int(self.NO_POLICER_LIMIT), str(rx_pps > self.NO_POLICER_LIMIT)))
+ self.log("total_rcv_pkt_cnt (%d) > pkt_rx_limit (%d): %s" % \
+ (int(total_rcv_pkt_cnt), int(self.pkt_rx_limit), str(total_rcv_pkt_cnt > self.pkt_rx_limit)))
+
+ assert(rx_pps > self.NO_POLICER_LIMIT)
+ assert(total_rcv_pkt_cnt > self.pkt_rx_limit)
+
+class PolicyTest(ControlPlaneBaseTest):
+ def __init__(self):
+ ControlPlaneBaseTest.__init__(self)
+
+ def check_constraints(self, total_rcv_pkt_cnt, time_delta_ms, rx_pps):
+ self.log("")
+ self.log("Checking constraints (PolicyApplied):")
+ self.log("PPS_LIMIT_MIN (%d) <= rx_pps (%d) <= PPS_LIMIT_MAX (%d): %s" % \
+ (int(self.PPS_LIMIT_MIN), int(rx_pps), int(self.PPS_LIMIT_MAX), str(self.PPS_LIMIT_MIN <= rx_pps <= self.PPS_LIMIT_MAX)))
+
+ assert(self.PPS_LIMIT_MIN <= rx_pps <= self.PPS_LIMIT_MAX)
+
+
+# SONIC config contains policer CIR=600 for ARP
+class ARPTest(PolicyTest):
+ def __init__(self):
+ PolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("ARPTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ src_mac = self.my_mac[port_number]
+ src_ip = self.myip[port_number]
+ dst_ip = self.peerip[port_number]
+
+ packet = simple_arp_packet(
+ eth_dst='ff:ff:ff:ff:ff:ff',
+ eth_src=src_mac,
+ arp_op=1,
+ ip_snd=src_ip,
+ ip_tgt=dst_ip,
+ hw_snd=src_mac,
+ hw_tgt='ff:ff:ff:ff:ff:ff')
+
+ return packet
+
+# SONIC configuration has no policer limiting for DHCP
+class DHCPTest(NoPolicyTest):
+ def __init__(self):
+ NoPolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("DHCPTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ src_mac = self.my_mac[port_number]
+ packet = simple_udp_packet(pktlen=100,
+ eth_dst='ff:ff:ff:ff:ff:ff',
+ eth_src=src_mac,
+ dl_vlan_enable=False,
+ vlan_vid=0,
+ vlan_pcp=0,
+ dl_vlan_cfi=0,
+ ip_src='0.0.0.0',
+ ip_dst='255.255.255.255',
+ ip_tos=0,
+ ip_ttl=64,
+ udp_sport=68,
+ udp_dport=67,
+ ip_ihl=None,
+ ip_options=False,
+ with_udp_chksum=True
+ )
+
+ return packet
+
+
+# SONIC configuration has no policer limiting for LLDP
+class LLDPTest(NoPolicyTest):
+ def __init__(self):
+ NoPolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("LLDPTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ src_mac = self.my_mac[port_number]
+ packet = simple_eth_packet(
+ eth_dst='01:80:c2:00:00:0e',
+ eth_src=src_mac,
+ eth_type=0x88cc
+ )
+
+ return packet
+
+# SONIC configuration has no policer limiting for BGP
+class BGPTest(NoPolicyTest):
+ def __init__(self):
+ NoPolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("BGPTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ dst_mac = self.peer_mac[port_number]
+ dst_ip = self.peerip[port_number]
+ packet = simple_tcp_packet(
+ eth_dst=dst_mac,
+ ip_dst=dst_ip,
+ ip_ttl=1,
+ tcp_dport=179
+ )
+ return packet
+
+# SONIC configuration has no policer limiting for LACP
+class LACPTest(NoPolicyTest):
+ def __init__(self):
+ NoPolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("LACPTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ packet = simple_eth_packet(
+ pktlen=14,
+ eth_dst='01:80:c2:00:00:02',
+ eth_type=0x8809
+ ) / (chr(0x01)*50)
+
+ return packet
+
+# SNMP packets are trapped as IP2ME packets.
+# IP2ME configuration in SONIC contains policer CIR=600
+class SNMPTest(PolicyTest): #FIXME: trapped as ip2me. mellanox should add support for SNMP trap
+ def __init__(self):
+ PolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("SNMPTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ src_mac = self.my_mac[port_number]
+ dst_mac = self.peer_mac[port_number]
+ dst_ip = self.peerip[port_number]
+ packet = simple_udp_packet(
+ eth_dst=dst_mac,
+ ip_dst=dst_ip,
+ eth_src=src_mac,
+ udp_dport=161
+ )
+ return packet
+
+# SONIC configuration has no policer limiting for SSH
+class SSHTest(PolicyTest): # FIXME: ssh is policed now
+ def __init__(self):
+ PolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("SSHTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ dst_mac = self.peer_mac[port_number]
+ src_ip = self.myip[port_number]
+ dst_ip = self.peerip[port_number]
+
+ packet = simple_tcp_packet(
+ eth_dst=dst_mac,
+ ip_dst=dst_ip,
+ ip_src=src_ip,
+ tcp_flags='F',
+ tcp_sport=22,
+ tcp_dport=22)
+
+ return packet
+
+# IP2ME configuration in SONIC contains policer CIR=600
+class IP2METest(PolicyTest):
+ def __init__(self):
+ PolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("IP2METest")
+ self.run_suite()
+
+ def one_port_test(self, port_number):
+ for port in self.dataplane.ports.iterkeys():
+ if port[0] == 0:
+ continue
+ packet = self.contruct_packet(port[1])
+ total_rcv_pkt_cnt, time_delta, time_delta_ms, tx_pps, rx_pps = self.copp_test(str(packet), self.pkt_tx_count, (0, port_number), (1, port_number))
+ self.printStats(self.pkt_tx_count, total_rcv_pkt_cnt, time_delta, tx_pps, rx_pps)
+ self.check_constraints(total_rcv_pkt_cnt, time_delta_ms, rx_pps)
+
+ return
+
+ def contruct_packet(self, port_number):
+ src_mac = self.my_mac[port_number]
+ dst_mac = self.peer_mac[port_number]
+ dst_ip = self.peerip[port_number]
+
+ packet = simple_tcp_packet(
+ eth_src=src_mac,
+ eth_dst=dst_mac,
+ ip_dst=dst_ip
+ )
+
+ return packet
+
+
+class DefaultTest(PolicyTest):
+ def __init__(self):
+ PolicyTest.__init__(self)
+
+ def runTest(self):
+ self.log("DefaultTest")
+ self.run_suite()
+
+ def contruct_packet(self, port_number):
+ dst_mac = self.peer_mac[port_number]
+ src_ip = self.myip[port_number]
+ dst_port_number = (port_number + 1) % self.MAX_PORTS
+ dst_ip = self.peerip[dst_port_number]
+
+ packet = simple_tcp_packet(
+ eth_dst=dst_mac,
+ ip_dst=dst_ip,
+ ip_src=src_ip,
+ tcp_sport=10000,
+ tcp_dport=10000,
+ ip_ttl=1)
+
+ return packet
diff --git a/ansible/roles/test/files/ptftests/dhcp_relay_test.py b/ansible/roles/test/files/ptftests/dhcp_relay_test.py
new file mode 100644
index 00000000000..6ae050df941
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/dhcp_relay_test.py
@@ -0,0 +1,434 @@
+import ast
+import struct
+import ipaddress
+
+# Packet Test Framework imports
+import ptf
+import ptf.packet as scapy
+import ptf.testutils as testutils
+from ptf import config
+from ptf.base_tests import BaseTest
+from ptf.mask import Mask
+
+
+# Helper function to increment an IP address
+# ip_addr should be passed as a dot-decimal string
+# Return value is also a dot-decimal string
+def incrementIpAddress(ip_addr, by=1):
+ new_addr = ipaddress.ip_address(unicode(ip_addr))
+ new_addr = new_addr + by
+ return str(new_addr)
+
+
+
+class DataplaneBaseTest(BaseTest):
+ def __init__(self):
+ BaseTest.__init__(self)
+
+ def setUp(self):
+ self.dataplane = ptf.dataplane_instance
+ self.dataplane.flush()
+ if config["log_dir"] is not None:
+ filename = os.path.join(config["log_dir"], str(self)) + ".pcap"
+ self.dataplane.start_pcap(filename)
+
+ def tearDown(self):
+ if config["log_dir"] is not None:
+ self.dataplane.stop_pcap()
+
+"""
+ This test simulates a new host booting up on the VLAN network of a ToR and
+ requesting an IP address via DHCP. Setup is as follows:
+ - DHCP client is simulated by listening/sending on an interface connected to VLAN of ToR.
+ - DHCP server is simulated by listening/sending on injected PTF interfaces which link
+ ToR to leaves. This way we can listen for traffic sent from DHCP relay out to would-be DHCP servers
+
+ This test performs the following functionality:
+ 1.) Simulated client broadcasts a DHCPDISCOVER message
+ 2.) Verify DHCP relay running on ToR receives the DHCPDISCOVER message
+ and relays it to all of its known DHCP servers, appending the proper Option 82 information
+ 3.) Simulate DHCPOFFER message broadcast from a DHCP server to the ToR
+ 4.) Verify DHCP relay receives the DHCPOFFER message and forwards it to our
+ simulated client.
+ 5.) Simulated client broadcasts a DHCPREQUEST message
+ 6.) Verify DHCP relay running on ToR receives the DHCPREQUEST message
+ and relays it to all of its known DHCP servers, appending the proper Option 82 information
+ 7.) Simulate DHCPACK message sent from a DHCP server to the ToR
+ 8.) Verify DHCP relay receives the DHCPACK message and forwards it to our
+ simulated client.
+
+ To run: place the following in a shell script (this will test against str-s6000-acs-12 (ec:f4:bb:fe:88:0a)):
+ ptf --test-dir ptftests dhcp_relay_test.DHCPTest --platform remote -t "hostname=\"str-s6000-acs-12\"; client_port_index=\"1\"; client_iface_alias=\"fortyGigE0/4\"; leaf_port_indices=\"[29, 31, 28, 30]\"; num_dhcp_servers=\"48\"; server_ip=\"192.0.0.1\"; relay_iface_ip=\"192.168.0.1\"; relay_iface_mac=\"ec:f4:bb:fe:88:0a\"; relay_iface_netmask=\"255.255.255.224\"" --disable-vxlan --disable-geneve --disable-erspan --disable-mpls --disable-nvgre
+
+ The above command is configured to test with the following configuration:
+ - VLAN IP of DuT is 192.168.0.1, MAC address is ec:f4:bb:fe:88:0a (this is configured to test against str-s6000-acs-12)
+ - Simulated client will live on PTF interface eth4 (interface number 4)
+ - Assumes leaf switches are connected to injected PTF interfaces 28, 29, 30, 31
+ - Test will simulate replies from server with IP '192.0.0.1'
+ - Simulated server will offer simulated client IP '192.168.0.2' with a subnet of '255.255.255.0' (this should be in the VLAN of DuT)
+
+
+ DHCP Relay currently installed with SONiC is isc-dhcp-relay
+
+ TODO???:
+ 1) DHCP Renew Test
+ 2) DHCP NACK Test
+ 3) Test with multiple DHCP Servers
+
+"""
+
+class DHCPTest(DataplaneBaseTest):
+
+ BROADCAST_MAC = 'ff:ff:ff:ff:ff:ff'
+ BROADCAST_IP = '255.255.255.255'
+ DEFAULT_ROUTE_IP = '0.0.0.0'
+ DHCP_CLIENT_PORT = 68
+ DHCP_SERVER_PORT = 67
+ DHCP_LEASE_TIME_OFFSET = 292
+ DHCP_LEASE_TIME_LEN = 6
+ LEASE_TIME = 86400
+ DHCP_PKT_BOOTP_MIN_LEN = 300
+
+ def __init__(self):
+ DataplaneBaseTest.__init__(self)
+
+
+ def setUp(self):
+ DataplaneBaseTest.setUp(self)
+
+ self.test_params = testutils.test_params_get()
+
+ self.hostname = self.test_params['hostname']
+
+ # These are the interfaces we are injected into that link to out leaf switches
+ self.server_port_indices = ast.literal_eval(self.test_params['leaf_port_indices'])
+ self.num_dhcp_servers = int(self.test_params['num_dhcp_servers'])
+
+ self.assertTrue(self.num_dhcp_servers > 0,
+ "Error: This test requires at least one DHCP server to be specified!")
+
+ # We will simulate a responding DHCP server on the first interface in the provided set
+ self.server_ip = self.test_params['server_ip']
+ self.server_iface_mac = self.dataplane.get_mac(0, self.server_port_indices[0])
+
+ self.relay_iface_ip = self.test_params['relay_iface_ip']
+ self.relay_iface_mac = self.test_params['relay_iface_mac']
+
+ self.client_iface_alias = self.test_params['client_iface_alias']
+ self.client_port_index = int(self.test_params['client_port_index'])
+ self.client_mac = self.dataplane.get_mac(0, self.client_port_index)
+
+ # option82 is a byte string created by the relay agent. It contains the circuit_id and remote_id fields.
+ # circuit_id is stored as suboption 1 of option 82.
+ # It consists of the following:
+ # Byte 0: Suboption number, always set to 1
+ # Byte 1: Length of suboption data in bytes
+ # Bytes 2+: Suboption data
+ # Our circuit_id string is of the form "hostname:portname"
+ circuit_id_string = self.hostname + ":" + self.client_iface_alias
+ self.option82 = struct.pack('BB', 1, len(circuit_id_string))
+ self.option82 += circuit_id_string
+
+ # remote_id is stored as suboption 2 of option 82.
+ # It consists of the following:
+ # Byte 0: Suboption number, always set to 2
+ # Byte 1: Length of suboption data in bytes
+ # Bytes 2+: Suboption data
+ # Our remote_id string simply consists of the MAC address of the port that received the request
+ remote_id_string = self.relay_iface_mac
+ self.option82 += struct.pack('BB', 2, len(remote_id_string))
+ self.option82 += remote_id_string
+
+ # We'll assign our client the IP address 1 greater than our relay interface (i.e., gateway) IP
+ self.client_ip = incrementIpAddress(self.relay_iface_ip, 1)
+ self.client_subnet = self.test_params['relay_iface_netmask']
+
+
+ def tearDown(self):
+ DataplaneBaseTest.tearDown(self)
+
+
+ """
+ Packet generation functions/wrappers
+
+ """
+
+ def create_dhcp_discover_packet(self):
+ return testutils.dhcp_discover_packet(eth_client=self.client_mac)
+
+ def create_dhcp_discover_relayed_packet(self):
+ my_chaddr = ''.join([chr(int(octet, 16)) for octet in self.client_mac.split(':')])
+
+ # Relay modifies the DHCPDISCOVER message in the following ways:
+ # 1.) Increments the hops count in the DHCP header
+ # 2.) Updates the gateway IP address in hte BOOTP header (if it is 0.0.0.0)
+ # 3.) Replaces the source IP with the IP of the interface which the relay
+ # received the broadcast DHCPDISCOVER message on
+ # 4.) Replaces the destination IP with the IP address of the DHCP server
+ # each message is being forwarded to
+ # Here, the actual destination MAC should be the MAC of the leaf the relay
+ # forwards through and the destination IP should be the IP of the DHCP server
+ # the relay is forwarding to. We don't need to confirm these, so we'll
+ # just mask them off later
+ #
+ # TODO: In IP layer, DHCP relay also replaces source IP with IP of interface on
+ # which it received the broadcast DHCPDISCOVER from client. This appears to
+ # be loopback. We could pull from minigraph and check here.
+ ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800)
+ ip = scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64)
+ udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308)
+ bootp = scapy.BOOTP(op=1,
+ htype=1,
+ hlen=6,
+ hops=1,
+ xid=0,
+ secs=0,
+ flags=0,
+ ciaddr=self.DEFAULT_ROUTE_IP,
+ yiaddr=self.DEFAULT_ROUTE_IP,
+ siaddr=self.DEFAULT_ROUTE_IP,
+ giaddr=self.relay_iface_ip,
+ chaddr=my_chaddr)
+ bootp /= scapy.DHCP(options=[('message-type', 'discover'),
+ ('relay_agent_Information', self.option82),
+ ('end')])
+
+ # If our bootp layer is too small, pad it
+ pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp)
+ if pad_bytes > 0:
+ bootp /= scapy.PADDING('\x00' * pad_bytes)
+
+ pkt = ether / ip / udp / bootp
+ return pkt
+
+ def create_dhcp_offer_packet(self):
+ return testutils.dhcp_offer_packet(eth_server=self.server_iface_mac,
+ eth_dst=self.relay_iface_mac,
+ eth_client=self.client_mac,
+ ip_server=self.server_ip,
+ ip_dst=self.relay_iface_ip,
+ ip_offered=self.client_ip,
+ port_dst=self.DHCP_SERVER_PORT,
+ ip_gateway=self.relay_iface_ip,
+ netmask_client=self.client_subnet,
+ dhcp_lease=self.LEASE_TIME,
+ padding_bytes=0)
+
+ def create_dhcp_request_packet(self):
+ return testutils.dhcp_request_packet(eth_client=self.client_mac,
+ ip_server=self.server_ip,
+ ip_requested=self.client_ip)
+
+ def create_dhcp_request_relayed_packet(self):
+ my_chaddr = ''.join([chr(int(octet, 16)) for octet in self.client_mac.split(':')])
+
+ # Here, the actual destination MAC should be the MAC of the leaf the relay
+ # forwards through and the destination IP should be the IP of the DHCP server
+ # the relay is forwarding to. We don't need to confirm these, so we'll
+ # just mask them off later
+ #
+ # TODO: In IP layer, DHCP relay also replaces source IP with IP of interface on
+ # which it received the broadcast DHCPREQUEST from client. This appears to
+ # be loopback. We could pull from minigraph and check here.
+ ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800)
+ ip = scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=336, ttl=64)
+ udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=316)
+ bootp = scapy.BOOTP(op=1,
+ htype=1,
+ hlen=6,
+ hops=1,
+ xid=0,
+ secs=0,
+ flags=0,
+ ciaddr=self.DEFAULT_ROUTE_IP,
+ yiaddr=self.DEFAULT_ROUTE_IP,
+ siaddr=self.DEFAULT_ROUTE_IP,
+ giaddr=self.relay_iface_ip,
+ chaddr=my_chaddr)
+ bootp /= scapy.DHCP(options=[('message-type', 'request'),
+ ('requested_addr', self.client_ip),
+ ('server_id', self.server_ip),
+ ('relay_agent_Information', self.option82),
+ ('end')])
+
+ # If our bootp layer is too small, pad it
+ pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp)
+ if pad_bytes > 0:
+ bootp /= scapy.PADDING('\x00' * pad_bytes)
+
+ pkt = ether / ip / udp / bootp
+ return pkt
+
+ def create_dhcp_ack_packet(self):
+ return testutils.dhcp_ack_packet(eth_server=self.server_iface_mac,
+ eth_dst=self.relay_iface_mac,
+ eth_client=self.client_mac,
+ ip_server=self.server_ip,
+ ip_dst=self.relay_iface_ip,
+ ip_offered=self.client_ip,
+ port_dst=self.DHCP_SERVER_PORT,
+ ip_gateway=self.relay_iface_ip,
+ netmask_client=self.client_subnet,
+ dhcp_lease=self.LEASE_TIME,
+ padding_bytes=0)
+
+
+ """
+ Send/receive functions
+
+ """
+
+ # Simulate client coming on VLAN and broadcasting a DHCPDISCOVER message
+ def client_send_discover(self):
+ # Form and send DHCPDISCOVER packet
+ dhcp_discover = self.create_dhcp_discover_packet()
+ testutils.send_packet(self, self.client_port_index, dhcp_discover)
+
+ # Verify that the DHCP relay actually received and relayed the DHCPDISCOVER message to all of
+ # its known DHCP servers. We also verify that the relay inserted Option 82 information in the
+ # packet.
+ def verify_relayed_discover(self):
+ # Create a packet resembling a relayed DCHPDISCOVER packet
+ dhcp_discover_relayed = self.create_dhcp_discover_relayed_packet()
+
+ # Mask off fields we don't care about matching
+ masked_discover = Mask(dhcp_discover_relayed)
+ masked_discover.set_do_not_care_scapy(scapy.Ether, "dst")
+
+ masked_discover.set_do_not_care_scapy(scapy.IP, "version")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "ihl")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "tos")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "len")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "id")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "flags")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "frag")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "ttl")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "proto")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "chksum")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "src")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "dst")
+ masked_discover.set_do_not_care_scapy(scapy.IP, "options")
+
+ masked_discover.set_do_not_care_scapy(scapy.UDP, "chksum")
+ masked_discover.set_do_not_care_scapy(scapy.UDP, "len")
+
+ masked_discover.set_do_not_care_scapy(scapy.BOOTP, "sname")
+ masked_discover.set_do_not_care_scapy(scapy.BOOTP, "file")
+
+ masked_discover.set_do_not_care_scapy(scapy.PADDING, "load")
+
+ # Count the number of these packets received on the ports connected to our leaves
+ discover_count = testutils.count_matched_packets_all_ports(self, masked_discover, self.server_port_indices)
+ self.assertTrue(discover_count == self.num_dhcp_servers,
+ "Failed: Discover count of %d != %d (num_dhcp_servers)" % (discover_count, self.num_dhcp_servers))
+
+ # Simulate a DHCP server sending a DHCPOFFER message to client.
+ # We do this by injecting a DHCPOFFER message on the link connected to one
+ # of our leaf switches.
+ def server_send_offer(self):
+ dhcp_offer = self.create_dhcp_offer_packet()
+ testutils.send_packet(self, self.server_port_indices[0], dhcp_offer)
+
+ # Verify that the DHCPOFFER would be received by our simulated client
+ def verify_offer_received(self):
+ dhcp_offer = self.create_dhcp_offer_packet()
+
+ masked_offer = Mask(dhcp_offer)
+ masked_offer.set_do_not_care_scapy(scapy.Ether, "src")
+ masked_offer.set_do_not_care_scapy(scapy.Ether, "dst")
+
+ masked_offer.set_do_not_care_scapy(scapy.IP, "chksum")
+ masked_offer.set_do_not_care_scapy(scapy.IP, "src")
+ masked_offer.set_do_not_care_scapy(scapy.IP, "dst")
+
+ masked_offer.set_do_not_care_scapy(scapy.UDP, "chksum")
+ masked_offer.set_do_not_care_scapy(scapy.UDP, "dport")
+
+ # Mask out lease time since it can change depending on when the server receives the request
+ # Lease time in ack can be slightly different than in offer, since lease time varies slightly
+ # We also want to ignore the checksums since they will vary a bit depending on the timestamp
+ # Offset is byte 292, 6 byte field, set_do_not_care() expects values in bits
+ masked_offer.set_do_not_care((self.DHCP_LEASE_TIME_OFFSET * 8), (self.DHCP_LEASE_TIME_LEN * 8))
+
+ # NOTE: verify_packet() will fail for us via an assert, so no need to check a return value here
+ testutils.verify_packet(self, masked_offer, self.client_port_index)
+
+ # Simulate our client sending a DHCPREQUEST message
+ def client_send_request(self):
+ dhcp_request = self.create_dhcp_request_packet()
+ testutils.send_packet(self, self.client_port_index, dhcp_request)
+
+ # Verify that the DHCP relay actually received and relayed the DHCPREQUEST message to all of
+ # its known DHCP servers. We also verify that the relay inserted Option 82 information in the
+ # packet.
+ def verify_relayed_request(self):
+ # Create a packet resembling a relayed DCHPREQUEST packet
+ dhcp_request_relayed = self.create_dhcp_request_relayed_packet()
+
+ # Mask off fields we don't care about matching
+ masked_request = Mask(dhcp_request_relayed)
+ masked_request.set_do_not_care_scapy(scapy.Ether, "dst")
+
+ masked_request.set_do_not_care_scapy(scapy.IP, "version")
+ masked_request.set_do_not_care_scapy(scapy.IP, "ihl")
+ masked_request.set_do_not_care_scapy(scapy.IP, "tos")
+ masked_request.set_do_not_care_scapy(scapy.IP, "len")
+ masked_request.set_do_not_care_scapy(scapy.IP, "id")
+ masked_request.set_do_not_care_scapy(scapy.IP, "flags")
+ masked_request.set_do_not_care_scapy(scapy.IP, "frag")
+ masked_request.set_do_not_care_scapy(scapy.IP, "ttl")
+ masked_request.set_do_not_care_scapy(scapy.IP, "proto")
+ masked_request.set_do_not_care_scapy(scapy.IP, "chksum")
+ masked_request.set_do_not_care_scapy(scapy.IP, "src")
+ masked_request.set_do_not_care_scapy(scapy.IP, "dst")
+ masked_request.set_do_not_care_scapy(scapy.IP, "options")
+
+ masked_request.set_do_not_care_scapy(scapy.UDP, "chksum")
+ masked_request.set_do_not_care_scapy(scapy.UDP, "len")
+
+ masked_request.set_do_not_care_scapy(scapy.BOOTP, "sname")
+ masked_request.set_do_not_care_scapy(scapy.BOOTP, "file")
+
+ # Count the number of these packets received on the ports connected to our leaves
+ request_count = testutils.count_matched_packets_all_ports(self, masked_request, self.server_port_indices)
+ self.assertTrue(request_count == self.num_dhcp_servers,
+ "Failed: Request count of %d != %d (num_dhcp_servers)" % (request_count, self.num_dhcp_servers))
+
+ # Simulate a DHCP server sending a DHCPOFFER message to client from one of our leaves
+ def server_send_ack(self):
+ dhcp_ack = self.create_dhcp_ack_packet()
+ testutils.send_packet(self, self.server_port_indices[0], dhcp_ack)
+
+ # Verify that the DHCPACK would be received by our simulated client
+ def verify_ack_received(self):
+ dhcp_ack = self.create_dhcp_ack_packet()
+
+ # Mask out lease time, ip checksum, udp checksum (explanation above)
+ masked_ack = Mask(dhcp_ack)
+
+ masked_ack.set_do_not_care_scapy(scapy.Ether, "src")
+ masked_ack.set_do_not_care_scapy(scapy.Ether, "dst")
+
+ masked_ack.set_do_not_care_scapy(scapy.IP, "chksum")
+ masked_ack.set_do_not_care_scapy(scapy.IP, "src")
+ masked_ack.set_do_not_care_scapy(scapy.IP, "dst")
+
+ masked_ack.set_do_not_care_scapy(scapy.UDP, "chksum")
+ masked_ack.set_do_not_care_scapy(scapy.UDP, "dport")
+
+ # Also mask out lease time (see comment in verify_offer_received() above)
+ masked_ack.set_do_not_care((self.DHCP_LEASE_TIME_OFFSET * 8), (self.DHCP_LEASE_TIME_LEN * 8))
+
+ # NOTE: verify_packet() will fail for us via an assert, so no need to check a return value here
+ testutils.verify_packet(self, masked_ack, self.client_port_index)
+
+ def runTest(self):
+ self.client_send_discover()
+ self.verify_relayed_discover()
+ self.server_send_offer()
+ self.verify_offer_received()
+ self.client_send_request()
+ self.verify_relayed_request()
+ self.server_send_ack()
+ self.verify_ack_received()
+
diff --git a/ansible/roles/test/files/ptftests/ecmp_test.py b/ansible/roles/test/files/ptftests/ecmp_test.py
new file mode 100644
index 00000000000..fac78b7fbad
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/ecmp_test.py
@@ -0,0 +1,159 @@
+"""
+SONiC Dataplane ECMP tests
+"""
+import random
+import time
+import logging
+import ptf.packet as scapy
+import socket
+import datetime
+import ptf.dataplane as dataplane
+import ptf.testutils as testutils
+import ptf
+from ptf import config
+from ptf.testutils import *
+from ptf.mask import Mask
+from ptf.base_tests import BaseTest
+
+# For SONiC
+# testing ECMP uniformn distribution over 16 RIFs from 16 differnt ports
+# ---- Test require 32 connected ports and SONiC up and running ----
+# ---- MUST RUN WITH "--relax" option on the ptf running line ----
+# Preliminary steps
+# 1. Configure IPs of all of the connected ports
+# (SONiC will configure neighbors)
+# 2. configure all routes (run add_routes.sh on SONiC)
+
+# Test structure
+# Sending Packets sequance
+# 1. Main loop running on 16 sources ports
+# 2. IP_LAST_WORD_RANGE loop running from 0-254
+# 3. IP_2ND_LAST_WORD_RANGE loop running 0-15
+# 4. Inside loop, to increase the number of packets, with differnt ports
+# 5. Sending and reciving packets, and counting destanation ports
+# - Final counters checking for uniform distribution
+
+# Final steps
+# For cleaning configuration run remove_routes.sh from SONiC
+
+
+# Constants
+IP_LAST_WORD_RANGE = 254
+IP_2ND_LAST_WORD_RANGE = 16
+NUMBER_OF_SRC_PORTS = 16
+NUMBER_OF_DST_PORTS = 16
+
+
+class ECMPtest(BaseTest):
+ def __init__(self):
+ BaseTest.__init__(self)
+ self.test_params = testutils.test_params_get()
+ self.verbose = self.test_params['verbose']
+ self.log_fp = open('/tmp/ecmp.log', 'a')
+
+ def log(self, message, debug=False):
+ current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ if (debug and self.verbose) or (not debug):
+ print "%s : %s" % (current_time, message)
+ self.log_fp.write("%s : %s\n" % (current_time, message))
+
+ def runTest(self):
+ self.pkt_counter = [0]*NUMBER_OF_DST_PORTS
+ self.send_packets()
+ self.check_distribution()
+
+ def send_packets(self):
+ random.seed(time.time())
+ sport = 0x1234
+ dport = 0x50
+ router_mac = self.test_params['router_mac']
+ destanation_ports = range(NUMBER_OF_SRC_PORTS,NUMBER_OF_DST_PORTS+NUMBER_OF_SRC_PORTS)
+ self.log("the router mac is %s" % router_mac)
+ self.log("the rif macs are:")
+ for i in range(16):
+ self.log(" %s" % self.dataplane.get_mac(0, i+16))
+
+ #send packets
+ for port in xrange(NUMBER_OF_SRC_PORTS):
+ for i in xrange(IP_LAST_WORD_RANGE):
+ for j in xrange(IP_2ND_LAST_WORD_RANGE):
+ ip_src = '10.0.0.' + str(port * 2 + 32)
+ src_mac = self.dataplane.get_mac(0, 0)
+ ip_dst = '172.16.' + str(j) + '.' + str(i + 1)
+
+ pkt = simple_tcp_packet(
+ eth_dst=router_mac,
+ eth_src=src_mac,
+ ip_src=ip_src,
+ ip_dst=ip_dst,
+ ip_id=i*j*port,
+ tcp_sport=sport,
+ tcp_dport=dport,
+ ip_ttl=64)
+ exp_pkt = simple_tcp_packet(
+ eth_dst=self.dataplane.get_mac(0, 16),
+ eth_src=router_mac,
+ ip_src=ip_src,
+ ip_dst=ip_dst,
+ ip_id=i*j*port,
+ tcp_sport=sport,
+ tcp_dport=dport,
+ ip_ttl=63)
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"dst")
+
+ sleep_time = 1
+ repeat = 5 # Repeat the send action until we receive a packet
+ while True:
+ send_packet(self, port, pkt)
+ self.log("Sent packet src=%s dst=%s port=%s" % (ip_src, ip_dst, port), True)
+ port_index = self.verify_packet_any_port(masked_exp_pkt, destanation_ports)
+ if port_index is None:
+ self.log("Expected packet isn't received. Repeating", True)
+ time.sleep(sleep_time)
+ sleep_time *= 2
+ repeat -= 1
+ if repeat == 0:
+ self.fail("Can't receive packet: src=%s dst=%s port=%s" % (ip_src, ip_dst, port))
+ else:
+ break
+ self.log("Received expected packet from port %d" % destanation_ports[port_index], True)
+
+ self.pkt_counter[port_index] += 1
+ sport = random.randint(0,0xffff)
+ dport = random.randint(0,0xffff)
+ return
+
+ def check_distribution(self):
+ #final uniform distribution check
+
+ self.log("")
+ for i, counter in enumerate(self.pkt_counter):
+ self.log("Port %02d counter: %d" % (i, counter))
+
+ for stat_port in xrange(NUMBER_OF_DST_PORTS):
+ self.assertTrue((self.pkt_counter[stat_port] >= ((IP_LAST_WORD_RANGE * IP_2ND_LAST_WORD_RANGE) * 0.9)),
+ "Not all paths are equally balanced, %s" % self.pkt_counter[stat_port])
+ self.assertTrue((self.pkt_counter[stat_port] <= ((IP_LAST_WORD_RANGE * IP_2ND_LAST_WORD_RANGE) * 1.1)),
+ "Not all paths are equally balanced, %s" % self.pkt_counter[stat_port])
+
+ return
+
+ def setUp(self):
+ BaseTest.setUp(self)
+ self.dataplane = ptf.dataplane_instance
+ self.dataplane.flush()
+
+ def tearDown(self):
+ if config["log_dir"] != None:
+ self.dataplane.stop_pcap()
+ self.log_fp.close()
+ BaseTest.tearDown(self)
+
+ def verify_packet_any_port(self, pkt, ports=[], device_number=0):
+ (rcv_device, rcv_port, rcv_pkt, pkt_time) = dp_poll(self, device_number=device_number, exp_pkt=pkt, timeout=1)
+
+ if rcv_port in ports:
+ return ports.index(rcv_port)
+ else:
+ return None
diff --git a/ansible/roles/test/files/ptftests/fast-reboot.py b/ansible/roles/test/files/ptftests/fast-reboot.py
new file mode 100644
index 00000000000..309a9485f3c
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/fast-reboot.py
@@ -0,0 +1,840 @@
+#
+#ptf --test-dir ptftests fast-reboot --qlen=1000 --platform remote -t 'verbose=True;dut_username="admin";dut_hostname="10.0.0.243";fast_reboot_limit=30;portchannel_ports_file="/tmp/portchannel_interfaces.json";vlan_ports_file="/tmp/vlan_interfaces.json";ports_file="/tmp/ports.json";dut_mac="4c:76:25:f5:48:80";default_ip_range="192.168.0.0/16";vlan_ip_range="172.0.0.0/22";arista_vms="[\"10.0.0.200\",\"10.0.0.201\",\"10.0.0.202\",\"10.0.0.203\"]"' --platform-dir ptftests --disable-vxlan --disable-geneve --disable-erspan --disable-mpls --disable-nvgre
+#
+#
+# This test checks that DUT is able to make FastReboot procedure
+#
+# This test supposes that fast-reboot initiates by running /usr/bin/fast-reboot command.
+#
+# The test uses "pings". The "pings" are packets which are sent through dataplane in two directions
+# 1. From one of vlan interfaces to T1 device. The source ip, source interface, and destination IP are chosen randomly from valid choices. Number of packet is 100.
+# 2. From all of portchannel ports to all of vlan ports. The source ip, source interface, and destination IP are chosed sequentially from valid choices.
+# Currently we have 500 distrinct destination vlan addresses. Our target to have 1000 of them.
+#
+# The test sequence is following:
+# 1. Check that DUT is stable. That means that "pings" work in both directions: from T1 to servers and from servers to T1.
+# 2. If DUT is stable the test starts continiously pinging DUT in both directions.
+# 3. The test runs '/usr/bin/fast-reboot' on DUT remotely. The ssh key supposed to be uploaded by ansible before the test
+# 4. As soon as it sees that ping starts failuring in one of directions the test registers a start of dataplace disruption
+# 5. As soon as the test sees that pings start working for DUT in both directions it registers a stop of dataplane disruption
+# 6. If the length of the disruption is less than 30 seconds (if not redefined by parameter) - the test passes
+# 7. If there're any drops, when control plane is down - the test fails
+# 8. When test start fast-reboot procedure it connects to all VM (which emulates T1) and starts fetching status of BGP and LACP
+# LACP is supposed to be down for one time only, if not - the test fails
+# if default value of BGP graceful restart timeout is less than 120 seconds the test fails
+# if BGP graceful restart is not enabled on DUT the test fails
+# If BGP graceful restart timeout value is almost exceeded (less than 15 seconds) the test fails
+# if BGP routes disappeares more then once, the test failed
+#
+# The test expects you're running the test with link state propagation helper.
+# That helper propagate a link state from fanout switch port to corresponding VM port
+#
+
+import ptf
+from ptf.base_tests import BaseTest
+from ptf import config
+import ptf.testutils as testutils
+from ptf.testutils import *
+from ptf.dataplane import match_exp_pkt
+import datetime
+import time
+import subprocess
+from ptf.mask import Mask
+import socket
+import ptf.packet as scapy
+import threading
+import os
+import signal
+import random
+import struct
+import socket
+from pprint import pprint
+from fcntl import ioctl
+import sys
+import json
+import re
+from collections import defaultdict
+import json
+import paramiko
+import Queue
+import pickle
+from operator import itemgetter
+
+
+class Arista(object):
+ DEBUG = False
+ def __init__(self, ip, queue, test_params, login='admin', password='123456'):
+ self.ip = ip
+ self.queue = queue
+ self.login = login
+ self.password = password
+ self.conn = None
+ self.hostname = None
+ self.v4_routes = [test_params['vlan_ip_range'], test_params['lo_prefix']]
+ self.v6_routes = [test_params['lo_v6_prefix']]
+ self.fails = set()
+ self.min_bgp_gr_timeout = int(test_params['min_bgp_gr_timeout'])
+
+ def __del__(self):
+ self.disconnect()
+
+ def connect(self):
+ self.conn = paramiko.SSHClient()
+ self.conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ self.conn.connect(self.ip, username=self.login, password=self.password, allow_agent=False, look_for_keys=False)
+ self.shell = self.conn.invoke_shell()
+
+ first_prompt = self.do_cmd(None, prompt = '>')
+ self.hostname = self.extract_hostname(first_prompt)
+
+ self.do_cmd('enable')
+ self.do_cmd('terminal length 0')
+
+ return self.shell
+
+ def extract_hostname(self, first_prompt):
+ lines = first_prompt.split('\n')
+ prompt = lines[-1]
+ return prompt.strip().replace('>', '#')
+
+ def do_cmd(self, cmd, prompt = None):
+ if prompt == None:
+ prompt = self.hostname
+
+ if cmd is not None:
+ self.shell.send(cmd + '\n')
+
+ input_buffer = ''
+ while prompt not in input_buffer:
+ input_buffer += self.shell.recv(16384)
+
+ return input_buffer
+
+ def disconnect(self):
+ if self.conn is not None:
+ self.conn.close()
+ self.conn = None
+
+ return
+
+ def run(self):
+ data = {}
+ debug_data = {}
+ run_once = False
+ log_first_line = None
+ quit_enabled = False
+ routing_works = True
+ self.connect()
+ while not (quit_enabled and v4_routing_ok and v6_routing_ok):
+ cmd = self.queue.get()
+ if cmd == 'quit':
+ quit_enabled = True
+ continue
+ cur_time = time.time()
+ info = {}
+ debug_info = {}
+ lacp_output = self.do_cmd('show lacp neighbor')
+ info['lacp'] = self.parse_lacp(lacp_output)
+ bgp_neig_output = self.do_cmd('show ip bgp neighbors')
+ info['bgp_neig'] = self.parse_bgp_neighbor(bgp_neig_output)
+
+ bgp_route_v4_output = self.do_cmd('show ip route bgp | json')
+ v4_routing_ok = self.parse_bgp_route(bgp_route_v4_output, self.v4_routes)
+ info['bgp_route_v4'] = v4_routing_ok
+
+ bgp_route_v6_output = self.do_cmd("show ipv6 route bgp | json")
+ v6_routing_ok = self.parse_bgp_route(bgp_route_v6_output, self.v6_routes)
+ info["bgp_route_v6"] = v6_routing_ok
+
+ if not run_once:
+ self.ipv4_gr_enabled, self.ipv6_gr_enabled, self.gr_timeout = self.parse_bgp_neighbor_once(bgp_neig_output)
+ log_first_line = "session_begins_%f" % cur_time
+ self.do_cmd("send log message %s" % log_first_line)
+ run_once = True
+
+ data[cur_time] = info
+ if self.DEBUG:
+ debug_data[cur_time] = {
+ 'show lacp neighbor' : lacp_output,
+ 'show ip bgp neighbors' : bgp_neig_output,
+ 'show ip route bgp' : bgp_route_v4_output,
+ 'show ipv6 route bgp' : bgp_route_v4_output,
+ }
+
+ attempts = 15
+ for _ in range(attempts):
+ log_output = self.do_cmd("show log | begin %s" % log_first_line)
+ log_lines = log_output.split("\r\n")[1:-1]
+ log_data = self.parse_logs(log_lines)
+ if len(log_data) != 0:
+ break
+ time.sleep(1) # wait until logs are populated
+
+ self.disconnect()
+
+ # save data for troubleshooting
+ with open("/tmp/%s.data.pickle" % self.ip, "w") as fp:
+ pickle.dump(data, fp)
+
+ # save debug data for troubleshooting
+ if self.DEBUG:
+ with open("/tmp/%s.raw.pickle" % self.ip, "w") as fp:
+ pickle.dump(debug_data, fp)
+ with open("/tmp/%s.logging" % self.ip, "w") as fp:
+ fp.write("\n".join(log_lines))
+
+ self.check_gr_peer_status(data)
+ cli_data = {}
+ cli_data['lacp'] = self.check_series_status(data, "lacp", "LACP session")
+ cli_data['bgp_v4'] = self.check_series_status(data, "bgp_route_v4", "BGP v4 routes")
+ cli_data['bgp_v6'] = self.check_series_status(data, "bgp_route_v6", "BGP v6 routes")
+
+ return self.fails, cli_data, log_data
+
+ def extract_from_logs(self, regexp, data):
+ raw_data = []
+ result = defaultdict(list)
+ initial_time = -1
+ re_compiled = re.compile(regexp)
+ for line in data:
+ m = re_compiled.match(line)
+ if not m:
+ continue
+ raw_data.append((datetime.datetime.strptime(m.group(1), "%b %d %X"), m.group(2), m.group(3)))
+
+ if len(raw_data) > 0:
+ initial_time = raw_data[0][0]
+ for when, what, status in raw_data:
+ offset = (when - initial_time if when > initial_time else initial_time - when).seconds
+ result[what].append((offset, status))
+
+ return result, initial_time
+
+ def parse_logs(self, data):
+ result = {}
+ bgp_r = r'^(\S+ \d+ \S+) \S+ Rib: %BGP-5-ADJCHANGE: peer (\S+) .+ (\S+)$'
+ result_bgp, initial_time_bgp = self.extract_from_logs(bgp_r, data)
+ if_r = r'^(\S+ \d+ \S+) \S+ Ebra: %LINEPROTO-5-UPDOWN: Line protocol on Interface (\S+), changed state to (\S+)$'
+ result_if, initial_time_if = self.extract_from_logs(if_r, data)
+
+ if initial_time_bgp == -1 or initial_time_if == -1:
+ return result
+
+ for events in result_bgp.values():
+ if events[-1][1] != 'Established':
+ return result
+
+ # first state is Idle, last state is Established
+ for events in result_bgp.values():
+ assert(events[0][1] == 'Idle')
+ assert(events[-1][1] == 'Established')
+ # first state is down, last state is up
+ for events in result_if.values():
+ assert(events[0][1] == 'down')
+ assert(events[-1][1] == 'up')
+
+ po_name = [ifname for ifname in result_if.keys() if 'Port-Channel' in ifname][0]
+ neigh_ipv4 = [neig_ip for neig_ip in result_bgp.keys() if '.' in neig_ip][0]
+
+ result['PortChannel was down (seconds)'] = result_if[po_name][-1][0] - result_if[po_name][0][0]
+ for if_name in sorted(result_if.keys()):
+ result['Interface %s was down (times)' % if_name] = map(itemgetter(1), result_if[if_name]).count("down")
+
+ for neig_ip in result_bgp.keys():
+ key = "BGP IPv6 was down (seconds)" if ':' in neig_ip else "BGP IPv4 was down (seconds)"
+ result[key] = result_bgp[neig_ip][-1][0] - result_bgp[neig_ip][0][0]
+
+ for neig_ip in result_bgp.keys():
+ key = "BGP IPv6 was down (times)" if ':' in neig_ip else "BGP IPv4 was down (times)"
+ result[key] = map(itemgetter(1), result_bgp[neig_ip]).count("Idle")
+
+ bgp_po_offset = (initial_time_if - initial_time_bgp if initial_time_if > initial_time_bgp else initial_time_bgp - initial_time_if).seconds
+ result['PortChannel went down after bgp session was down (seconds)'] = bgp_po_offset + result_if[po_name][0][0]
+
+ for neig_ip in result_bgp.keys():
+ key = "BGP IPv6 was gotten up after Po was up (seconds)" if ':' in neig_ip else "BGP IPv4 was gotten up after Po was up (seconds)"
+ result[key] = result_bgp[neig_ip][-1][0] - bgp_po_offset - result_if[po_name][-1][0]
+
+ return result
+
+ def parse_lacp(self, output):
+ return output.find('Bundled') != -1
+
+ def parse_bgp_neighbor_once(self, output):
+ is_gr_ipv4_enabled = False
+ is_gr_ipv6_enabled = False
+ restart_time = None
+ for line in output.split('\n'):
+ if ' Restart-time is' in line:
+ restart_time = int(line.replace(' Restart-time is ', ''))
+ continue
+
+ if 'is enabled, Forwarding State is' in line:
+ if 'IPv6' in line:
+ is_gr_ipv6_enabled = True
+ elif 'IPv4' in line:
+ is_gr_ipv4_enabled = True
+
+ return is_gr_ipv4_enabled, is_gr_ipv6_enabled, restart_time
+
+ def parse_bgp_neighbor(self, output):
+ gr_active = None
+ gr_timer = None
+ for line in output.split('\n'):
+ if 'Restart timer is' in line:
+ gr_active = 'is active' in line
+ gr_timer = str(line[-9:-1])
+
+ return gr_active, gr_timer
+
+ def parse_bgp_route(self, output, expects):
+ prefixes = set()
+ data = "\n".join(output.split("\r\n")[1:-1])
+ obj = json.loads(data)
+
+ if "vrfs" in obj and "default" in obj["vrfs"]:
+ obj = obj["vrfs"]["default"]
+ for prefix, attrs in obj["routes"].items():
+ if "routeAction" not in attrs or attrs["routeAction"] != "forward":
+ continue
+ if all("Port-Channel" in via["interface"] for via in attrs["vias"]):
+ prefixes.add(prefix)
+
+ return set(expects) == prefixes
+
+ def check_gr_peer_status(self, output):
+ # [0] True 'ipv4_gr_enabled', [1] doesn't matter 'ipv6_enabled', [2] should be >= 120
+ if not self.ipv4_gr_enabled:
+ self.fails.add("bgp ipv4 graceful restart is not enabled")
+ if not self.ipv6_gr_enabled:
+ pass # ToDo:
+ if self.gr_timeout < 120: # bgp graceful restart timeout less then 120 seconds
+ self.fails.add("bgp graceful restart timeout is less then 120 seconds")
+
+ for when, other in sorted(output.items(), key = lambda x : x[0]):
+ gr_active, timer = other['bgp_neig']
+ # wnen it's False, it's ok, wnen it's True, check that inactivity timer not less then self.min_bgp_gr_timeout seconds
+ if gr_active and datetime.datetime.strptime(timer, '%H:%M:%S') < datetime.datetime(1900, 1, 1, second = self.min_bgp_gr_timeout):
+ self.fails.add("graceful restart timer is almost finished. Less then %d seconds left" % self.min_bgp_gr_timeout)
+
+ def check_series_status(self, output, entity, what):
+ # find how long anything was down
+ # Input parameter is a dictionary when:status
+ # constraints:
+ # entity must be down just once
+ # entity must be up when the test starts
+ # entity must be up when the test stops
+
+ sorted_keys = sorted(output.keys())
+ if not output[sorted_keys[0]][entity]:
+ self.fails.add("%s must be up when the test starts" % what)
+ return 0, 0
+ if not output[sorted_keys[-1]][entity]:
+ self.fails.add("%s must be up when the test stops" % what)
+ return 0, 0
+
+ start = sorted_keys[0]
+ cur_state = True
+ res = defaultdict(list)
+ for when in sorted_keys[1:]:
+ if cur_state != output[when][entity]:
+ res[cur_state].append(when - start)
+ start = when
+ cur_state = output[when][entity]
+ res[cur_state].append(when - start)
+
+ is_down_count = len(res[False])
+
+ if is_down_count > 1:
+ self.fails.add("%s must be down just for once" % what)
+
+ return is_down_count, sum(res[False]) # summary_downtime
+
+class FastReloadTest(BaseTest):
+ TIMEOUT = 0.5
+ def __init__(self):
+ BaseTest.__init__(self)
+ self.fails = {}
+ self.cli_info = {}
+ self.logs_info = {}
+ self.log_fp = open('/tmp/fast-reboot.log', 'w')
+ self.test_params = testutils.test_params_get()
+ self.check_param('verbose', False, required = False)
+ self.check_param('dut_username', '', required = True)
+ self.check_param('dut_hostname', '', required = True)
+ self.check_param('fast_reboot_limit', 30, required = False)
+ self.check_param('graceful_limit', 120, required = False)
+ self.check_param('portchannel_ports_file', '', required = True)
+ self.check_param('vlan_ports_file', '', required = True)
+ self.check_param('ports_file', '', required = True)
+ self.check_param('dut_mac', '', required = True)
+ self.check_param('default_ip_range', '', required = True)
+ self.check_param('vlan_ip_range', '', required = True)
+ self.check_param('lo_prefix', '10.1.0.32/32', required = False)
+ self.check_param('lo_v6_prefix', 'fc00:1::32/128', required = False)
+ self.check_param('arista_vms', [], required = True)
+ self.check_param('min_bgp_gr_timeout', 15, required = False)
+
+ # Default settings
+ self.nr_pc_pkts = 100
+ self.nr_tests = 3
+ self.reboot_delay = 10
+ self.task_timeout = 300 # Wait up to 5 minutes for tasks to complete
+ self.max_nr_vl_pkts = 500 # FIXME: should be 1000. But bcm asic is not stable
+ self.timeout_thr = None
+
+ return
+
+ def read_json(self, name):
+ with open(self.test_params[name]) as fp:
+ content = json.load(fp)
+
+ return content
+
+ def read_port_indices(self):
+ self.port_indices = self.read_json('ports_file')
+
+ return
+
+ def read_portchannel_ports(self):
+ content = self.read_json('portchannel_ports_file')
+ pc_ifaces = []
+ for pc in content.values():
+ pc_ifaces.extend([self.port_indices[member] for member in pc['members']])
+
+ return pc_ifaces
+
+ def read_vlan_ports(self):
+ content = self.read_json('vlan_ports_file')
+ if len(content) > 1:
+ raise "Too many vlans"
+ return [self.port_indices[ifname] for ifname in content.values()[0]['members']]
+
+ def check_param(self, param, default, required = False):
+ if param not in self.test_params:
+ if required:
+ raise Exception("Test parameter '%s' is required" % param)
+ self.test_params[param] = default
+
+ def random_ip(self, ip):
+ net_addr, mask = ip.split('/')
+ n_hosts = 2**(32 - int(mask))
+ random_host = random.randint(2, n_hosts - 2)
+ return self.host_ip(ip, random_host)
+
+ def host_ip(self, net_ip, host_number):
+ src_addr, mask = net_ip.split('/')
+ n_hosts = 2**(32 - int(mask))
+ if host_number > (n_hosts - 2):
+ raise Exception("host number %d is greater than number of hosts %d in the network %s" % (host_number, n_hosts - 2, net_ip))
+ src_addr_n = struct.unpack(">I", socket.inet_aton(src_addr))[0]
+ net_addr_n = src_addr_n & (2**32 - n_hosts)
+ host_addr_n = net_addr_n + host_number
+ host_ip = socket.inet_ntoa(struct.pack(">I", host_addr_n))
+
+ return host_ip
+
+ def random_port(self, ports):
+ return random.choice(ports)
+
+ def log(self, message, verbose=False):
+ current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ if verbose and self.test_params['verbose'] or not verbose:
+ print "%s : %s" % (current_time, message)
+ self.log_fp.write("%s : %s\n" % (current_time, message))
+
+ def timeout(self, seconds, message):
+ def timeout_exception(self, message):
+ self.log('Timeout is reached: %s' % message)
+ self.tearDown()
+ os.kill(os.getpid(), signal.SIGINT)
+
+ if self.timeout_thr is None:
+ self.timeout_thr = threading.Timer(seconds, timeout_exception, args=(self, message))
+ self.timeout_thr.start()
+ else:
+ raise Exception("Timeout already set")
+
+ def cancel_timeout(self):
+ if self.timeout_thr is not None:
+ self.timeout_thr.cancel()
+ self.timeout_thr = None
+
+ def setUp(self):
+ self.read_port_indices()
+ self.portchannel_ports = self.read_portchannel_ports()
+ vlan_ip_range = self.test_params['vlan_ip_range']
+ self.vlan_ports = self.read_vlan_ports()
+
+ self.limit = datetime.timedelta(seconds=self.test_params['fast_reboot_limit'])
+ self.dut_ssh = self.test_params['dut_username'] + '@' + self.test_params['dut_hostname']
+ self.dut_mac = self.test_params['dut_mac']
+ #
+ self.nr_vl_pkts = self.generate_from_t1()
+
+ self.log("Test params:")
+ self.log("DUT ssh: %s" % self.dut_ssh)
+ self.log("DUT fast-reboot limit: %s" % self.limit)
+ self.log("DUT mac address: %s" % self.dut_mac)
+
+ self.log("From server src addr: %s" % self.from_server_src_addr)
+ self.log("From server src port: %s" % self.from_server_src_port)
+ self.log("From server dst addr: %s" % self.from_server_dst_addr)
+ self.log("From server dst ports: %s" % self.from_server_dst_ports)
+ self.log("From upper layer number of packets: %d" % self.nr_vl_pkts)
+
+ self.dataplane = ptf.dataplane_instance
+ for p in self.dataplane.ports.values():
+ port = p.get_packet_source()
+ port.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1000000)
+
+ self.dataplane.flush()
+ if config["log_dir"] != None:
+ filename = os.path.join(config["log_dir"], str(self)) + ".pcap"
+ self.dataplane.start_pcap(filename)
+
+ self.log("Enabling arp_responder")
+ self.cmd(["supervisorctl", "start", "arp_responder"])
+
+ return
+
+ def tearDown(self):
+ self.log("Disabling arp_responder")
+ self.cmd(["supervisorctl", "stop", "arp_responder"])
+ if config["log_dir"] != None:
+ self.dataplane.stop_pcap()
+ self.log_fp.close()
+
+ def get_if(self, iff, cmd):
+ s = socket.socket()
+ ifreq = ioctl(s, cmd, struct.pack("16s16x",iff))
+ s.close()
+
+ return ifreq
+
+ def get_mac(self, iff):
+ SIOCGIFHWADDR = 0x8927 # Get hardware address
+ return ':'.join(['%02x' % ord(char) for char in self.get_if(iff, SIOCGIFHWADDR)[18:24]])
+
+ def generate_from_t1(self):
+ self.from_t1 = []
+
+ vlan_ip_range = self.test_params['vlan_ip_range']
+
+ _, mask = vlan_ip_range.split('/')
+ n_hosts = min(2**(32 - int(mask)) - 3, self.max_nr_vl_pkts)
+
+ dump = defaultdict(dict)
+ counter = 0
+ for i in xrange(2, n_hosts + 2):
+ from_t1_src_addr = self.random_ip(self.test_params['default_ip_range'])
+ from_t1_src_port = self.random_port(self.portchannel_ports)
+ from_t1_dst_addr = self.host_ip(vlan_ip_range, i)
+ from_t1_dst_port = self.vlan_ports[i % len(self.vlan_ports)]
+ from_t1_if_name = "eth%d" % from_t1_dst_port
+ from_t1_if_addr = "%s/%s" % (from_t1_dst_addr, vlan_ip_range.split('/')[1])
+ vlan_mac_hex = '72060001%04x' % counter
+ lag_mac_hex = '5c010203%04x' % counter
+ mac_addr = ':'.join(lag_mac_hex[i:i+2] for i in range(0, len(lag_mac_hex), 2))
+ packet = simple_tcp_packet(
+ eth_src=mac_addr,
+ eth_dst=self.dut_mac,
+ ip_src=from_t1_src_addr,
+ ip_dst=from_t1_dst_addr,
+ ip_ttl=255,
+ tcp_dport=5000
+ )
+ self.from_t1.append((from_t1_src_port, str(packet)))
+ dump[from_t1_if_name][from_t1_dst_addr] = vlan_mac_hex
+ counter += 1
+
+ exp_packet = simple_tcp_packet(
+ ip_src="0.0.0.0",
+ ip_dst="0.0.0.0",
+ tcp_dport=5000,
+ )
+
+ self.from_t1_exp_packet = Mask(exp_packet)
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.Ether, "src")
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.Ether, "dst")
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.IP, "src")
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.IP, "dst")
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.IP, "chksum")
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.TCP, "chksum")
+ self.from_t1_exp_packet.set_do_not_care_scapy(scapy.IP, "ttl")
+
+ # save data for arp_replay process
+ with open("/tmp/from_t1.json", "w") as fp:
+ json.dump(dump, fp)
+
+ random_vlan_iface = random.choice(dump.keys())
+ self.from_server_src_port = int(random_vlan_iface.replace('eth',''))
+ self.from_server_src_addr = random.choice(dump[random_vlan_iface].keys())
+ self.from_server_dst_addr = self.random_ip(self.test_params['default_ip_range'])
+ self.from_server_dst_ports = self.portchannel_ports
+
+ return n_hosts
+
+ def runTest(self):
+ self.reboot_start = None
+ no_routing_start = None
+ no_routing_stop = None
+
+ arista_vms = self.test_params['arista_vms'][1:-1].split(",")
+ ssh_targets = [vm[1:-1] for vm in arista_vms]
+
+ self.ssh_jobs = []
+ for addr in ssh_targets:
+ q = Queue.Queue()
+ thr = threading.Thread(target=self.peer_state_check, kwargs={'ip': addr, 'queue': q})
+ thr.setDaemon(True)
+ self.ssh_jobs.append((thr, q))
+ thr.start()
+
+ thr = threading.Thread(target=self.background)
+ thr.setDaemon(True)
+ self.log("Check that device is alive and pinging")
+ self.assertTrue(self.check_alive(), 'DUT is not stable')
+
+ self.log("Schedule to reboot the remote switch in %s sec" % self.reboot_delay)
+ thr.start()
+
+ self.log("Wait until ASIC stops")
+ self.timeout(self.task_timeout, "DUT hasn't stopped in %d seconds" % self.task_timeout)
+ no_routing_start, upper_replies = self.check_forwarding_stop()
+ self.cancel_timeout()
+
+ self.log("ASIC was stopped, Waiting until it's up. Stop time: %s" % str(no_routing_start))
+ self.timeout(self.task_timeout, "DUT hasn't started to work for %d seconds" % self.task_timeout)
+ no_routing_stop, _ = self.check_forwarding_resume()
+ self.cancel_timeout()
+
+ # wait until all bgp session are established
+ self.log("Wait until bgp routing is up on all devices")
+ for _, q in self.ssh_jobs:
+ q.put('quit')
+
+ self.timeout(self.task_timeout, "SSH threads haven't finished for %d seconds" % self.task_timeout)
+ while any(thr.is_alive() for thr, _ in self.ssh_jobs):
+ for _, q in self.ssh_jobs:
+ q.put('go')
+ time.sleep(self.TIMEOUT)
+
+ for thr, _ in self.ssh_jobs:
+ thr.join()
+ self.cancel_timeout()
+
+ self.log("ASIC works again. Start time: %s" % str(no_routing_stop))
+ self.log("")
+
+ no_cp_replies = self.extract_no_cpu_replies(upper_replies)
+
+ self.fails['dut'] = set()
+ if no_routing_stop - no_routing_start > self.limit:
+ self.fails['dut'].add("Downtime must be less then %s seconds. It was %s" \
+ % (self.test_params['fast_reboot_limit'], str(no_routing_stop - no_routing_start)))
+ if no_routing_stop - self.reboot_start > datetime.timedelta(seconds=self.test_params['graceful_limit']):
+ self.fails['dut'].add("Fast-reboot cycle must be less than graceful limit %s seconds" % self.test_params['graceful_limit'])
+ if no_cp_replies < 0.95 * self.nr_vl_pkts:
+ self.fails['dut'].add("Dataplane didn't route to all servers, when control-plane was down: %d vs %d" % (no_cp_replies, self.nr_vl_pkts))
+
+ # Generating report
+ self.log("="*50)
+ self.log("Report:")
+ self.log("="*50)
+
+ self.log("LACP/BGP were down for (extracted from cli):")
+ self.log("-"*50)
+ for ip in sorted(self.cli_info.keys()):
+ self.log(" %s - lacp: %7.3f (%d) bgp v4: %7.3f (%d) bgp v6: %7.3f (%d)" \
+ % (ip, self.cli_info[ip]['lacp'][1], self.cli_info[ip]['lacp'][0], \
+ self.cli_info[ip]['bgp_v4'][1], self.cli_info[ip]['bgp_v4'][0],\
+ self.cli_info[ip]['bgp_v6'][1], self.cli_info[ip]['bgp_v6'][0]))
+
+ self.log("-"*50)
+ self.log("Extracted from VM logs:")
+ self.log("-"*50)
+ for ip in sorted(self.logs_info.keys()):
+ self.log("Extracted log info from %s" % ip)
+ for msg in sorted(self.logs_info[ip].keys()):
+ self.log(" %s : %d" % (msg, self.logs_info[ip][msg]))
+ self.log("-"*50)
+
+ self.log("Summary:")
+ self.log("-"*50)
+ self.log("Downtime was %s" % str(no_routing_stop - no_routing_start))
+ self.log("Reboot time was %s" % str(no_routing_stop - self.reboot_start))
+
+
+ self.log("How many packets were received back when control plane was down: %d Expected: %d" % (no_cp_replies, self.nr_vl_pkts))
+
+ is_good = all(len(fails) == 0 for fails in self.fails.values())
+
+ if not is_good:
+ self.log("-"*50)
+ self.log("Fails:")
+ self.log("-"*50)
+
+ errors = "\n\nSomething went wrong. Please check output below:\n\n"
+ for name, fails in self.fails.items():
+ for fail in fails:
+ self.log("FAILED:%s:%s" % (name, fail))
+ errors += "FAILED:%s:%s\n" % (name, fail)
+
+ self.log("="*50)
+
+ self.assertTrue(is_good, errors)
+
+ def extract_no_cpu_replies(self, arr):
+ """
+ This function tries to extract number of replies from dataplane, when control plane is non working
+ """
+ # remove all tail zero values
+ non_zero = filter(lambda x : x > 0, arr)
+
+ # check that last value is different from previos
+ if len(non_zero) > 1 and non_zero[-1] < non_zero[-2]:
+ return non_zero[-2]
+ else:
+ return non_zero[-1]
+
+ def background(self):
+ time.sleep(self.reboot_delay)
+
+ self.log("Rebooting remote side")
+ self.reboot_start = datetime.datetime.now()
+ stdout, stderr, return_code = self.cmd(["ssh", "-oStrictHostKeyChecking=no", self.dut_ssh, "sudo fast-reboot"])
+ if stdout != []:
+ self.log("stdout from fast-reboot: %s" % str(stdout))
+ if stderr != []:
+ self.log("stderr from fast-reboot: %s" % str(stderr))
+ self.log("return code from fast-reboot: %s" % str(return_code))
+
+ return
+
+ def cmd(self, cmds):
+ process = subprocess.Popen(cmds,
+ shell=False,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ return_code = process.returncode
+
+ return stdout, stderr, return_code
+
+ def peer_state_check(self, ip, queue):
+ ssh = Arista(ip, queue, self.test_params)
+ self.fails[ip], self.cli_info[ip], self.logs_info[ip] = ssh.run()
+
+ def check_forwarding_stop(self):
+ return self.iteration(True)
+
+ def check_forwarding_resume(self):
+ return self.iteration(False)
+
+ def iteration(self, is_stop):
+ recorded_time = None
+ counter = self.nr_tests
+ nr_from_upper_array = []
+ while True:
+ success, nr_from_upper = self.ping_iteration()
+ nr_from_upper_array.append(nr_from_upper)
+ for _, q in self.ssh_jobs:
+ q.put('go')
+ if success and is_stop or not success and not is_stop:
+ self.log("Base state", True)
+ recorded_time = None
+ else:
+ self.log("Changed state", True)
+ if recorded_time is None:
+ recorded_time = datetime.datetime.now()
+ if counter == 0:
+ break
+ else:
+ counter -= 1
+
+ return recorded_time, nr_from_upper_array
+
+ def ping_iteration(self):
+ replies_from_servers = self.pingFromServers()
+ if replies_from_servers > 0:
+ replies_from_upper = self.pingFromUpperTier()
+ else:
+ replies_from_upper = 0
+ return replies_from_servers > 0 and replies_from_upper > 0, replies_from_upper
+
+ def check_alive(self):
+ # This function checks that DUT routes packets in both directions.
+ #
+ # Sometimes first attempt failes because ARP response to DUT is not so fast.
+ # But after this the functions expects to see steady "replies".
+ # If the function sees that there is some issue with dataplane after we see successful replies
+ # it consider that DUT is not healthy too
+ #
+ # Sometimes I see that DUT returns more replies then requests.
+ # I think this is because of not populated FDB table
+ # The function waits while it's done
+
+ was_alive = False
+ for counter in range(self.nr_tests * 2):
+ success, _ = self.ping_alive()
+ if success:
+ was_alive = True
+ else:
+ if was_alive:
+ return False # Stopped working after it working for sometime?
+
+ # wait, until FDB entries are populated
+ while self.ping_alive()[1]:
+ pass
+
+ return True
+
+ def ping_alive(self):
+ nr_from_s = self.pingFromServers()
+ nr_from_l = self.pingFromUpperTier()
+
+ is_alive = nr_from_s > self.nr_pc_pkts * 0.7 and nr_from_l > self.nr_vl_pkts * 0.7
+ is_asic_weird = nr_from_s > self.nr_pc_pkts or nr_from_l > self.nr_vl_pkts
+ # we receive more, then received. not populated FDB table
+
+ return is_alive, is_asic_weird
+
+ def pingFromServers(self):
+ packet = simple_tcp_packet(
+ eth_dst=self.dut_mac,
+ ip_src=self.from_server_src_addr,
+ ip_dst=self.from_server_dst_addr,
+ tcp_dport=5000
+ )
+ exp_packet = simple_tcp_packet(
+ ip_src=self.from_server_src_addr,
+ ip_dst=self.from_server_dst_addr,
+ ip_ttl=63,
+ tcp_dport=5000,
+ )
+
+ exp_packet = Mask(exp_packet)
+ exp_packet.set_do_not_care_scapy(scapy.Ether,"src")
+ exp_packet.set_do_not_care_scapy(scapy.Ether,"dst")
+
+ raw_packet = str(packet)
+
+ for i in xrange(self.nr_pc_pkts):
+ testutils.send_packet(self, self.from_server_src_port, raw_packet)
+
+ total_rcv_pkt_cnt = testutils.count_matched_packets_all_ports(self, exp_packet, self.from_server_dst_ports, timeout=self.TIMEOUT)
+
+ self.log("Send %5d Received %5d servers->t1" % (self.nr_pc_pkts, total_rcv_pkt_cnt), True)
+
+ return total_rcv_pkt_cnt
+
+ def pingFromUpperTier(self):
+ for entry in self.from_t1:
+ testutils.send_packet(self, *entry)
+
+ total_rcv_pkt_cnt = testutils.count_matched_packets_all_ports(self, self.from_t1_exp_packet, self.vlan_ports, timeout=self.TIMEOUT)
+
+ self.log("Send %5d Received %5d t1->servers" % (self.nr_vl_pkts, total_rcv_pkt_cnt), True)
+
+ return total_rcv_pkt_cnt
diff --git a/ansible/roles/test/files/ptftests/fdb.py b/ansible/roles/test/files/ptftests/fdb.py
new file mode 100644
index 00000000000..bc2c8be5c10
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/fdb.py
@@ -0,0 +1,22 @@
+from ipaddress import ip_address, ip_network
+
+class Fdb():
+ def __init__(self, file_path):
+
+ self._arp_dict = {}
+ self._vlan_dict = {}
+
+ with open(file_path, 'r') as f:
+ for line in f.readlines():
+ entry = line.split(' ', 1)
+ prefix = ip_network(unicode(entry[0]))
+ self._vlan_dict[prefix] = [int(i) for i in entry[1].split()]
+
+ def insert(self, mac, member):
+ self._arp_dict[member] = mac
+
+ def get_vlan_table(self):
+ return self._vlan_dict
+
+ def get_arp_table(self):
+ return self._arp_dict
diff --git a/ansible/roles/test/files/ptftests/fdb_test.py b/ansible/roles/test/files/ptftests/fdb_test.py
new file mode 100644
index 00000000000..394ded3461c
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/fdb_test.py
@@ -0,0 +1,92 @@
+import fdb
+import json
+import logging
+import subprocess
+
+from collections import defaultdict
+from ipaddress import ip_address, ip_network
+
+import ptf
+import ptf.packet as scapy
+import ptf.dataplane as dataplane
+
+from ptf import config
+from ptf.base_tests import BaseTest
+from ptf.testutils import *
+
+class FdbTest(BaseTest):
+ def __init__(self):
+ BaseTest.__init__(self)
+ self.test_params = test_params_get()
+ #--------------------------------------------------------------------------
+
+ def log(self, message):
+ logging.info(message)
+ #--------------------------------------------------------------------------
+
+ def shell(self, cmds):
+ sp = subprocess.Popen(cmds, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = sp.communicate()
+ rc = sp.returncode
+
+ return stdout, stderr, rc
+ #--------------------------------------------------------------------------
+
+ def setUp(self):
+ self.dataplane = ptf.dataplane_instance
+ self.fdb = fdb.Fdb(self.test_params['fdb_info'])
+ self.vlan_ip = ip_address(unicode(self.test_params['vlan_ip']))
+
+ self.setUpFdb()
+ self.setUpArpResponder()
+
+ self.log("Start arp_responder")
+ self.shell(["supervisorctl", "start", "arp_responder"])
+ #--------------------------------------------------------------------------
+
+ def tearDown(self):
+ self.log("Stop arp_responder")
+ self.shell(["supervisorctl", "stop", "arp_responder"])
+ #--------------------------------------------------------------------------
+
+ def setUpFdb(self):
+ vlan_table = self.fdb.get_vlan_table()
+ for vlan in vlan_table:
+ for member in vlan_table[vlan]:
+ mac = self.dataplane.get_mac(0, member)
+ self.fdb.insert(mac, member)
+ #--------------------------------------------------------------------------
+
+ def setUpArpResponder(self):
+ vlan_table = self.fdb.get_vlan_table()
+ arp_table = self.fdb.get_arp_table()
+ d = defaultdict(list)
+ for vlan in vlan_table:
+ network = ip_network(vlan)
+ length = int(network[-1]) - int(network[0])
+ index = 1
+ for member in vlan_table[vlan]:
+ iface = "eth%d" % member
+ index = index + 1 if network[index + 1] != self.vlan_ip else index + 2
+ d[iface].append(str(network[index]))
+ with open('/tmp/from_t1.json', 'w') as file:
+ json.dump(d, file)
+ #--------------------------------------------------------------------------
+
+ def check_route(self, src_mac, dst_mac, src_port, dst_port):
+ pkt = simple_eth_packet(eth_dst=dst_mac,
+ eth_src=src_mac,
+ eth_type=0x1234)
+ self.log("Send packet " + str(src_mac) + "->" + str(dst_mac) + " from " + str(src_port) + " to " + str(dst_port) + "...")
+ send(self, src_port, pkt)
+ verify_packet(self, pkt, dst_port)
+ #--------------------------------------------------------------------------
+
+ def runTest(self):
+ vlan_table = self.fdb.get_vlan_table()
+ arp_table = self.fdb.get_arp_table()
+ for vlan in vlan_table:
+ for src in vlan_table[vlan]:
+ for dst in [i for i in vlan_table[vlan] if i != src]:
+ self.check_route(arp_table[src], arp_table[dst], src, dst)
+ #--------------------------------------------------------------------------
diff --git a/ansible/roles/test/files/ptftests/fib.py b/ansible/roles/test/files/ptftests/fib.py
new file mode 100644
index 00000000000..d4dc005f9e5
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/fib.py
@@ -0,0 +1,76 @@
+import re
+from ipaddress import ip_address, ip_network
+from lpm import LpmDict
+
+# These subnets are excluded from FIB test
+# reference: RFC 5735 Special Use IPv4 Addresses
+# RFC 5156 Special Use IPv6 Addresses
+
+EXCLUDE_IPV4_PREFIXES = [
+ '0.0.0.0/8', # "This" Network RFC 1122, Section 3.2.1.3
+ '10.0.0.0/8', # Private-Use Networks RFC 1918
+ '127.0.0.0/8', # Loopback RFC 1122, Section 3.2.1.3
+ '169.254.0.0/16', # Link Local RFC RFC 3927
+ '224.0.0.0/4', # Multicast RFC 3171
+ '255.255.255.255/32' # Limited Broadcast RFC 919, Section 7
+ # RFC 922, Section 7
+]
+
+EXCLUDE_IPV6_PREFIXES = [
+ '::/0', # Currently no IPv6 default route
+ '::/128', # Unspecified RFC 4291
+ '::1/128', # Loopback RFC 4291
+ 'ff00::/8' # Multicast RFC 4291
+ ]
+
+class Fib():
+ class NextHop():
+ def __init__(self, next_hop = ''):
+ self._next_hop = []
+ matches = re.findall('\[([\s\d]+)\]', next_hop)
+ for match in matches:
+ self._next_hop.append([int(s) for s in match.split()])
+
+ def __str__(self):
+ return str(self._next_hop)
+
+ def get_next_hop(self):
+ return self._next_hop
+
+ def get_next_hop_list(self):
+ port_list = [p for intf in self._next_hop for p in intf]
+ return port_list
+
+ # Initialize FIB with FIB file
+ def __init__(self, file_path):
+ self._ipv4_lpm_dict = LpmDict()
+ for ip in EXCLUDE_IPV4_PREFIXES:
+ self._ipv4_lpm_dict[ip] = self.NextHop()
+
+ self._ipv6_lpm_dict = LpmDict(ipv4=False)
+ for ip in EXCLUDE_IPV6_PREFIXES:
+ self._ipv6_lpm_dict[ip] = self.NextHop()
+
+ with open(file_path, 'r') as f:
+ for line in f.readlines():
+ if line[0] == '#': continue
+ entry = line.split(' ', 1)
+ prefix = ip_network(unicode(entry[0]))
+ next_hop = self.NextHop(entry[1])
+ if prefix.version is 4:
+ self._ipv4_lpm_dict[str(prefix)] = next_hop
+ elif prefix.version is 6:
+ self._ipv6_lpm_dict[str(prefix)] = next_hop
+
+ def __getitem__(self, ip):
+ ip = ip_address(unicode(ip))
+ if ip.version is 4:
+ return self._ipv4_lpm_dict[str(ip)]
+ elif ip.version is 6:
+ return self._ipv6_lpm_dict[str(ip)]
+
+ def ipv4_ranges(self):
+ return self._ipv4_lpm_dict.ranges()
+
+ def ipv6_ranges(self):
+ return self._ipv6_lpm_dict.ranges()
diff --git a/ansible/roles/test/files/ptftests/fib_test.py b/ansible/roles/test/files/ptftests/fib_test.py
new file mode 100644
index 00000000000..b5caa107ad1
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/fib_test.py
@@ -0,0 +1,278 @@
+'''
+Description: This file contains the FIB test for SONIC
+
+ Design is available in https://github.com/Azure/SONiC/wiki/FIB-Scale-Test-Plan
+
+Usage: Examples of how to use log analyzer
+ ptf --test-dir fib fib_test.FibTest --platform remote -t 'router_mac="00:02:03:04:05:00";route_info="fib/route_info.txt";testbed_type=t1'
+'''
+
+#---------------------------------------------------------------------
+# Global imports
+#---------------------------------------------------------------------
+import ipaddress
+import logging
+import random
+import socket
+import sys
+
+import ptf
+import ptf.packet as scapy
+import ptf.dataplane as dataplane
+
+from ptf import config
+from ptf.base_tests import BaseTest
+from ptf.mask import Mask
+from ptf.testutils import *
+
+import fib
+
+class FibTest(BaseTest):
+ '''
+ @summary: Overview of functionality
+ Test routes advertised by BGP peers of SONIC are working properly.
+ The setup of peers is described in 'VM set' section in
+ https://github.com/Azure/sonic-mgmt/blob/master/ansible/README.testbed.md
+
+ Routes advertized by the peers have ECMP groups. The purpose of the test is to make sure
+ that packets are forwarded through one of the ports specified in route's ECMP group.
+
+ This class receives a text file describing the bgp routes added to the switch.
+ File contains informaiton about each bgp route which was added to the switch.
+
+ #-----------------------------------------------------------------------
+
+ The file is loaded on startup and is used to
+ - construct packet with correct destination IP
+ - validate that packet arrived from switch from a port which
+ is member of ECMP group for given route.
+
+ For each route test
+ - builds a packet with destination IP matching to the IP in the route
+ - sends packet to the switch
+ - verifies that packet came back from the switch on one of
+ the ports specified in the ECMP group of the route.
+
+ '''
+
+ #---------------------------------------------------------------------
+ # Class variables
+ #---------------------------------------------------------------------
+ DEFAULT_BALANCING_RANGE = 0.25
+ BALANCING_TEST_TIMES = 10000
+ DEFAULT_BALANCING_TEST_RATIO = 0.0001
+
+ def __init__(self):
+ '''
+ @summary: constructor
+ '''
+ BaseTest.__init__(self)
+ self.test_params = test_params_get()
+
+ #---------------------------------------------------------------------
+
+ def setUp(self):
+ '''
+ @summary: Setup for the test
+ Two test parameters are used:
+ - fib_info: the FIB information generated according to the testbed
+ - router_mac: the MAC address of the DUT used to create the eth_dst
+ of the packet
+ - testbed_type: the type of the testbed used to determine the source
+ port
+ TODO: Have a separate line in fib_info/file to indicate all UP ports
+ '''
+ self.dataplane = ptf.dataplane_instance
+ self.fib = fib.Fib(self.test_params['fib_info'])
+ self.router_mac = self.test_params['router_mac']
+
+ self.test_ipv4 = self.test_params.get('ipv4', True)
+ self.test_ipv6 = self.test_params.get('ipv6', True)
+
+ self.balancing_range = self.test_params.get('balancing_range', self.DEFAULT_BALANCING_RANGE)
+ self.balancing_test_ratio = self.test_params.get('balancing_test_ratio', self.DEFAULT_BALANCING_TEST_RATIO)
+
+ if self.test_params['testbed_type'] == 't1' or self.test_params['testbed_type'] == 't1-lag':
+ self.src_ports = range(0, 32)
+ if self.test_params['testbed_type'] == 't0':
+ self.src_ports = range(1, 25) + range(28, 32)
+ #---------------------------------------------------------------------
+
+ def check_ip_range(self, ipv4=True):
+ if ipv4:
+ ip_ranges = self.fib.ipv4_ranges()
+ else:
+ ip_ranges = self.fib.ipv6_ranges()
+
+ for ip_range in ip_ranges:
+
+ # Get the expected list of ports that would receive the packets
+ exp_port_list = self.fib[ip_range.get_first_ip()].get_next_hop_list()
+ # Choose random one source port from all ports excluding the expected ones
+ src_port = random.choice([port for port in self.src_ports if port not in exp_port_list])
+
+ if not exp_port_list:
+ continue
+
+ logging.info("Check IP range:" + str(ip_range) + " on " + str(exp_port_list) + "...")
+
+ # Send a packet with the first IP in the range
+ self.check_ip_route(src_port, ip_range.get_first_ip(), exp_port_list, ipv4)
+ # Send a packet with the last IP in the range
+ if ip_range.length() > 1:
+ self.check_ip_route(src_port, ip_range.get_last_ip(), exp_port_list, ipv4)
+ # Send a packet with a random IP in the range
+ if ip_range.length() > 2:
+ self.check_ip_route(src_port, ip_range.get_random_ip(), exp_port_list, ipv4)
+
+ # Test traffic balancing across ECMP/LAG members
+ if len(exp_port_list) > 1 and random.random() < self.balancing_test_ratio:
+ logging.info("Check IP range balancing...")
+ dst_ip = ip_range.get_random_ip()
+ hit_count_map = {}
+ for i in range(0, self.BALANCING_TEST_TIMES):
+ (matched_index, received) = self.check_ip_route(src_port, dst_ip, exp_port_list, ipv4)
+ hit_count_map[matched_index] = hit_count_map.get(matched_index, 0) + 1
+ self.check_balancing(self.fib[dst_ip].get_next_hop(), hit_count_map)
+
+ def check_ip_route(self, src_port, dst_ip_addr, dst_port_list, ipv4=True):
+ if ipv4:
+ (matched_index, received) = self.check_ipv4_route(src_port, dst_ip_addr, dst_port_list)
+ else:
+ (matched_index, received) = self.check_ipv6_route(src_port, dst_ip_addr, dst_port_list)
+
+ assert received
+
+ matched_port = dst_port_list[matched_index]
+ logging.info("Received packet at " + str(matched_port))
+
+ return (matched_port, received)
+
+ def check_ipv4_route(self, src_port, dst_ip_addr, dst_port_list):
+ '''
+ @summary: Check IPv4 route works.
+ @param src_port: index of port to use for sending packet to switch
+ @param dest_ip_addr: destination IP to build packet with.
+ @param dst_port_list: list of ports on which to expect packet to come back from the switch
+ '''
+ sport = random.randint(0, 65535)
+ dport = random.randint(0, 65535)
+ ip_src = "10.0.0.1"
+ ip_dst = dst_ip_addr
+ src_mac = self.dataplane.get_mac(0, 0)
+
+ pkt = simple_tcp_packet(
+ eth_dst=self.router_mac,
+ eth_src=src_mac,
+ ip_src=ip_src,
+ ip_dst=ip_dst,
+ tcp_sport=sport,
+ tcp_dport=dport,
+ ip_ttl=64)
+ exp_pkt = simple_tcp_packet(
+ eth_src=self.router_mac,
+ ip_src=ip_src,
+ ip_dst=ip_dst,
+ tcp_sport=sport,
+ tcp_dport=dport,
+ ip_ttl=63)
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
+
+ send_packet(self, src_port, pkt)
+ logging.info("Sending packet from port " + str(src_port) + " to " + ip_dst)
+
+ return verify_packet_any_port(self, masked_exp_pkt, dst_port_list)
+ #---------------------------------------------------------------------
+
+ def check_ipv6_route(self, src_port, dst_ip_addr, dst_port_list):
+ '''
+ @summary: Check IPv6 route works.
+ @param source_port_index: index of port to use for sending packet to switch
+ @param dest_ip_addr: destination IP to build packet with.
+ @param dst_port_list: list of ports on which to expect packet to come back from the switch
+ @return Boolean
+ '''
+ sport = random.randint(0, 65535)
+ dport = random.randint(0, 65535)
+ ip_src = '2000::1'
+ ip_dst = dst_ip_addr
+ src_mac = self.dataplane.get_mac(0, 0)
+
+ pkt = simple_tcpv6_packet(
+ eth_dst=self.router_mac,
+ eth_src=src_mac,
+ ipv6_dst=ip_dst,
+ ipv6_src=ip_src,
+ tcp_sport=sport,
+ tcp_dport=dport,
+ ipv6_hlim=64)
+ exp_pkt = simple_tcpv6_packet(
+ eth_src=self.router_mac,
+ ipv6_dst=ip_dst,
+ ipv6_src=ip_src,
+ tcp_sport=sport,
+ tcp_dport=dport,
+ ipv6_hlim=63)
+ masked_exp_pkt = Mask(exp_pkt)
+ masked_exp_pkt.set_do_not_care_scapy(scapy.Ether,"dst")
+
+ send_packet(self, src_port, pkt)
+ logging.info("Sending packet from port " + str(src_port) + " to " + ip_dst)
+
+ return verify_packet_any_port(self, masked_exp_pkt, dst_port_list)
+ #---------------------------------------------------------------------
+ def check_within_expected_range(self, actual, expected):
+ '''
+ @summary: Check if the actual number is within the accepted range of the expected number
+ @param actual : acutal number of recieved packets
+ @param expected : expected number of recieved packets
+ @return (percentage, bool)
+ '''
+ percentage = (actual - expected) / float(expected)
+ return (percentage, abs(percentage) <= self.balancing_range)
+
+ #---------------------------------------------------------------------
+ def check_balancing(self, dest_port_list, port_hit_cnt):
+ '''
+ @summary: Check if the traffic is balanced across the ECMP groups and the LAG members
+ @param dest_port_list : a list of ECMP entries and in each ECMP entry a list of ports
+ @param port_hit_cnt : a dict that records the number of packets each port received
+ @return bool
+ '''
+
+ logging.info("%-10s \t %-10s \t %10s \t %10s \t %10s" % ("type", "port(s)", "exp_cnt", "act_cnt", "diff(%)"))
+ result = True
+
+ total_hit_cnt = sum(port_hit_cnt.values())
+ for ecmp_entry in dest_port_list:
+ total_entry_hit_cnt = 0
+ for member in ecmp_entry:
+ total_entry_hit_cnt += port_hit_cnt.get(member, 0)
+ (p, r) = self.check_within_expected_range(total_entry_hit_cnt, float(total_hit_cnt)/len(dest_port_list))
+ logging.info("%-10s \t %-10s \t %10d \t %10d \t %10s"
+ % ("ECMP", str(ecmp_entry), total_hit_cnt/len(dest_port_list), total_entry_hit_cnt, str(round(p, 4)*100) + '%'))
+ result &= r
+ if len(ecmp_entry) == 1 or total_entry_hit_cnt == 0:
+ continue
+ for member in ecmp_entry:
+ (p, r) = self.check_within_expected_range(port_hit_cnt.get(member, 0), float(total_entry_hit_cnt)/len(ecmp_entry))
+ logging.info("%-10s \t %-10s \t %10d \t %10d \t %10s"
+ % ("LAG", str(member), total_entry_hit_cnt/len(ecmp_entry), port_hit_cnt.get(member, 0), str(round(p, 4)*100) + '%'))
+ result &= r
+
+ assert result
+
+ #---------------------------------------------------------------------
+
+ def runTest(self):
+ """
+ @summary: Send packet for each range of both IPv4 and IPv6 spaces and
+ expect the packet to be received from one of the expected ports
+ """
+ # IPv4 Test
+ if (self.test_ipv4):
+ self.check_ip_range()
+ # IPv6 Test
+ if (self.test_ipv6):
+ self.check_ip_range(ipv4=False)
diff --git a/ansible/roles/test/files/ptftests/lpm.py b/ansible/roles/test/files/ptftests/lpm.py
new file mode 100644
index 00000000000..f30fdcef4e9
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/lpm.py
@@ -0,0 +1,105 @@
+import random
+
+from ipaddress import ip_address, ip_network
+from SubnetTree import SubnetTree
+
+'''
+LpmDict is a class used in FIB test for LPM and IP segmentation.
+
+This class contains a class variable SubnetTree() _subnet_tree to solve the
+LPM search functionality, which is achieved using Patricia tree. In order to
+have IP segmentation functionality: segment the whole IP space into different
+segments from start to end according to the prefixes (networks) it reads.
+
+Initially, the whole IP space contains only one range. After inserting
+prefixes, the IP space is segmented into multiple ranges. The ranges()
+function returns all ranges in the LpmDict with a list of IpIntervals. The
+sub-class IpInterval then could be used to get the first/last/random IP within
+this range. It could also check the length of the range and if an IP is within
+this range.
+
+To achieve the LPM functionality, use the LpmDict as a dictionary and use
+[] operator to get the corresponding value using the key (IP).
+
+Please check the test_lpm.py file to see the details of how this class works.
+'''
+class LpmDict():
+ class IpInterval:
+ def __init__(self, s):
+ self._start = s
+ self._end = s
+
+ def __init__(self, s, e):
+ assert s <= e
+ self._start = s
+ self._end = e
+
+ # __len__ has hard limit on returning long int
+ def length(self):
+ return int(self._end) - int(self._start)
+
+ def contains(self, ip):
+ return ip >= self._start and ip <= self._end
+
+ def get_first_ip(self):
+ return str(self._start)
+
+ def get_last_ip(self):
+ return str(self._end)
+
+ def get_random_ip(self):
+ diff = self.length()
+ return str(self._start + random.randint(0, diff))
+
+ def __str__(self):
+ return str(self._start) + ' - ' + str(self._end)
+
+ def __init__(self, ipv4=True):
+ self._ipv4 = ipv4
+ self._prefix_set = set()
+ self._subnet_tree = SubnetTree()
+ # 0.0.0.0 is a non-routable meta-address that needs to be skipped
+ self._boundaries = { ip_address(u'0.0.0.0') : 1} if ipv4 else { ip_address(u'::') : 1}
+
+ def __setitem__(self, key, value):
+ prefix = ip_network(unicode(key))
+ # add the current key to self._prefix_set only when it is not the default route and it is not a duplicate key
+ if prefix.prefixlen and key not in self._prefix_set:
+ boundary = prefix[0]
+ self._boundaries[boundary] = self._boundaries.get(boundary, 0) + 1
+ if prefix[-1] != ip_address(u'255.255.255.255') and prefix[-1] != ip_address(u'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'):
+ next_boundary = prefix[-1] + 1
+ self._boundaries[next_boundary] = self._boundaries.get(next_boundary, 0) + 1
+ self._prefix_set.add(key)
+ self._subnet_tree.__setitem__(key, value)
+
+ def __getitem__(self, key):
+ return self._subnet_tree[key]
+
+ def __delitem__(self, key):
+ if '/0' not in key:
+ prefix = ip_network(unicode(key))
+ boundary = prefix[0]
+ next_boundary = prefix[-1] + 1
+ self._boundaries[boundary] = self._boundaries.get(boundary) - 1
+ if not self._boundaries[boundary]:
+ del self._boundaries[boundary]
+ self._boundaries[next_boundary] = self._boundaries.get(next_boundary) - 1
+ if not self._boundaries[next_boundary]:
+ del self._boundaries[next_boundary]
+ self._prefix_set.remove(key)
+ self._subnet_tree.__delitem__(key)
+
+ def ranges(self):
+ sorted_boundaries = sorted(self._boundaries.keys())
+ ranges = []
+ for index, boundary in enumerate(sorted_boundaries):
+ if index != len(sorted_boundaries) - 1:
+ interval = self.IpInterval(sorted_boundaries[index], sorted_boundaries[index + 1] - 1)
+ else:
+ if self._ipv4:
+ interval = self.IpInterval(sorted_boundaries[index], ip_address(u'255.255.255.255'))
+ else:
+ interval = self.IpInterval(sorted_boundaries[index], ip_address(u'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'))
+ ranges.append(interval)
+ return ranges
diff --git a/ansible/roles/test/files/ptftests/remote.py b/ansible/roles/test/files/ptftests/remote.py
new file mode 100644
index 00000000000..9c36653116d
--- /dev/null
+++ b/ansible/roles/test/files/ptftests/remote.py
@@ -0,0 +1,38 @@
+"""
+Remote platform
+
+This platform uses physical ethernet interfaces.
+"""
+
+def get_ifaces():
+ with open('/proc/net/dev') as fp:
+ all = fp.read()
+
+ ifaces = []
+ for line in all.split('\n'):
+ # Skip a header
+ if ':' not in line:
+ continue
+
+ iface = line.split(':')[0].strip()
+
+ # Skip not FP interfaces
+ if 'eth' not in iface:
+ continue
+
+ ifaces.append(iface)
+
+ # Sort before return
+ return sorted(ifaces, key=lambda x: int(x.replace('eth', '')))
+
+
+def platform_config_update(config):
+ """
+ Update configuration for the remote platform
+
+ @param config The configuration dictionary to use/update
+ """
+
+ remote_port_map = {(0, i) : v for i, v in enumerate(get_ifaces())}
+ config["port_map"] = remote_port_map.copy()
+ config["caps_table_idx"] = 0
diff --git a/ansible/roles/test/files/tools/loganalyzer/loganalyzer.py b/ansible/roles/test/files/tools/loganalyzer/loganalyzer.py
index 679bfe2f814..1177c491684 100644
--- a/ansible/roles/test/files/tools/loganalyzer/loganalyzer.py
+++ b/ansible/roles/test/files/tools/loganalyzer/loganalyzer.py
@@ -329,7 +329,7 @@ def analyze_file(self, log_file_path, match_messages_regex, ignore_messages_rege
found_expected_message = True
expecting_lines.append(rev_line)
- if self.line_matches(rev_line, match_messages_regex, ignore_messages_regex):
+ elif self.line_matches(rev_line, match_messages_regex, ignore_messages_regex):
matching_lines.append(rev_line)
if (not found_start_marker):
diff --git a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
index 8cda128620d..5f78ef2c265 100644
--- a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
+++ b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
@@ -4,11 +4,32 @@
- debug: msg="starting loganalyzer analysis phase"
-- set_fact: cmd="python {{ run_dir }}/loganalyzer.py --action analyze --run_id {{ testname_unique }} --out_dir {{ test_out_dir }} -m {{ match_file }} -i {{ ignore_file }} -e {{ test_expect_file }} -v"
+- name: Init variables
+ set_fact:
+ match_file_option: "-m {{ match_file }}"
+ ignore_file_option: "-i {{ ignore_file }}"
+ expect_file_option: "-e {{ expect_file }}"
+
+- name: Add test specific match file
+ set_fact:
+ match_file_option: "{{ match_file_option }},{{ test_match_file }} "
+ when: test_match_file is defined
+
+- name: Add test specific ignore file
+ set_fact:
+ ignore_file_option: "{{ ignore_file_option }},{{ test_ignore_file }}"
+ when: test_ignore_file is defined
+
+- name: Use test specific expect file
+ set_fact:
+ expect_file_option: "-e {{ test_expect_file }}"
+ when: test_expect_file is defined
+
+- set_fact: cmd="python {{ run_dir }}/loganalyzer.py --action analyze --run_id {{ testname_unique }} --out_dir {{ test_out_dir }} {{ match_file_option }} {{ ignore_file_option }} {{ expect_file_option }} -v"
- debug: msg={{cmd}}
-- name: Initialize loganalyzer {{ testname }}
+- name: Invoke loganalyzer analyse {{ testname }}
become: True
shell: "{{ cmd }}"
args:
diff --git a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_common_expect.txt b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_common_expect.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_end.yml b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_end.yml
index f5f570ac29e..d79322b1375 100644
--- a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_end.yml
+++ b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_end.yml
@@ -3,24 +3,45 @@
#------------------------------------------------
- set_fact:
- result_file: result.loganalysis.{{testname_unique}}.log
- summary_file: summary.loganalysis.{{testname_unique}}.log
-- debug : msg="summary_file {{summary_file}}"
+ result_file: result.loganalysis.{{ testname_unique }}.log
+ summary_file: summary.loganalysis.{{ testname_unique }}.log
+ test_fetch_dir: test/{{ inventory_hostname }}
+
+# Output content of result files to ansible console
+- shell: cat {{ test_out_dir }}/*
+ register: out
+- debug: var=out.stdout_lines
+
+- name: Check if loganalyzer found any error
+ shell: grep "TOTAL MATCHES" "{{ test_out_dir }}/{{ summary_file }}" | sed -n "s/TOTAL MATCHES:[[:space:]]*//p"
+ register: errors_found
+
+- set_fact:
+ fail_in_logs: errors_found.stdout != "0"
+
+- name: Generate system dump
+ command: generate_dump
+ register: generate_dump
+ when: fail_in_logs
+
- name : Fetch result files from switch to ansible machine
- fetch: src={{ test_out_dir }}/{{item}} dest=/tmp
+ fetch:
+ src: "{{ item }}"
+ dest: "{{ test_fetch_dir }}/{{ item | basename }}"
+ flat: yes
with_items:
- - "{{result_file}}"
- - "{{summary_file}}"
-
-- name : Create destination directory on PTF host for loganalyzer results
- file: path="{{ test_out_dir }}" state=directory
- delegate_to: "{{ ptf_host }}"
+ - "{{ test_out_dir }}/{{result_file}}"
+ - "{{ test_out_dir }}/{{summary_file}}"
+ - "{{ generate_dump.stdout | default(omit) }}"
+ when: fail_in_logs
-- name: Copy loganalyzer result files from ansible machine to PTF host
- copy: src="/tmp/{{inventory_hostname}}/{{test_out_dir}}/{{item}}" dest="{{ test_out_dir }}/{{item}}"
+- debug: msg="File {{ item }} saved to {{ test_fetch_dir }}"
with_items:
- - "{{ result_file }}"
- - "{{ summary_file }}"
- delegate_to: "{{ ptf_host }}"
+ - "{{result_file}}"
+ - "{{summary_file}}"
+ - "{{ generate_dump.stdout | default(omit) }}"
+ when: fail_in_logs
-- debug: msg="Location of log files on PTF host - {{ test_out_dir }}"
\ No newline at end of file
+- name: Fail due to errors in logs
+ fail:
+ when: fail_in_logs
diff --git a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_init.yml b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_init.yml
index 586c2807b88..8ab6011e27e 100644
--- a/ansible/roles/test/files/tools/loganalyzer/loganalyzer_init.yml
+++ b/ansible/roles/test/files/tools/loganalyzer/loganalyzer_init.yml
@@ -5,16 +5,44 @@
- set_fact:
loganalyzer_location: "{{ 'roles/test/files/tools/loganalyzer' }}"
+- set_fact:
+ match_file: loganalyzer_common_match.txt
+ when: match_file is not defined
+
+- set_fact:
+ ignore_file: loganalyzer_common_ignore.txt
+ when: ignore_file is not defined
+
+- set_fact:
+ expect_file: "loganalyzer_common_expect.txt"
+ when: expect_file is not defined
+
+- set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date }}.{{ ansible_date_time.time }}"
+ when: testname_unique is not defined
+
+- set_fact:
+ test_out_dir: "{{ out_dir }}/{{ testname_unique }}"
+ when: test_out_dir is not defined
+
- name: Copy loganalyzer common match and ignore files to switch
copy: src="{{ loganalyzer_location }}/{{ item }}" dest="{{ run_dir }}/{{ item }}"
with_items:
- "{{ match_file }}"
- "{{ ignore_file }}"
+ - "{{ expect_file }}"
+
+- name: Copy test specific file match-files to switch
+ copy: src="{{ tests_location }}/{{ testname }}/{{ test_match_file }}" dest="{{ run_dir }}/{{ test_match_file }}"
+ when: test_match_file is defined
+
+- name: Copy test specific ignore-files to switch
+ copy: src="{{ tests_location }}/{{ testname }}/{{ test_ignore_file }}" dest="{{ run_dir }}/{{ test_ignore_file }}"
+ when: test_ignore_file is defined
- name: Copy test specific expect-files to switch
- copy: src="{{ tests_location }}/{{ testname }}/{{ item }}" dest="{{ run_dir }}/{{ item }}"
- with_items:
- - "{{ test_expect_file }}"
+ copy: src="{{ tests_location }}/{{ testname }}/{{ test_expect_file }}" dest="{{ run_dir }}/{{ test_expect_file }}"
+ when: test_expect_file is defined
- name: Copy loganalyzer.py to run directory
copy: src="{{ loganalyzer_location }}/loganalyzer.py" dest="{{ run_dir }}"
@@ -27,6 +55,8 @@
- name: create output directory for current test run
file: path="{{ test_out_dir }}" state=directory
+- name: Force log rotation to have most of log file available
+ command: logrotate -f /etc/logrotate.conf
- debug: msg="starting loganalyzer_init.py"
- debug: msg="python {{ run_dir }}/loganalyzer.py --action init --run_id {{ testname_unique }}"
diff --git a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/acl_counter_traffic_test.yml b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/acl_counter_traffic_test.yml
index b28aea62300..8f5cda3521a 100644
--- a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/acl_counter_traffic_test.yml
+++ b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/acl_counter_traffic_test.yml
@@ -26,10 +26,6 @@
#----------------------------------------
# L3 TRAFFIC TESTING.
#----------------------------------------
- - name: Set host interface IP address.
- shell: ifconfig {{ ptf_host_if }} 20.0.0.2
- delegate_to: "{{ ptf_host }}"
-
- name: Create an ACL L3 table.
shell: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_table_type_l3 }}
@@ -94,6 +90,7 @@
table_name_check: "{{ table_name }}"
rule_name_check: "{{ rule_name }}"
expect_data: false
+ expected_counter_value: 0
include: "{{ acl_check_db }}"
#--------------------
@@ -107,10 +104,10 @@
shell: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_table_type_mirror }}
- name: Add neighbor.
- shell: ip neigh add {{ switch_if1_ip }} lladdr 0e:9c:37:42:43:67 dev Ethernet0
+ shell: ip neigh replace {{ neighbor2_ip }} lladdr 0e:9c:37:42:43:67 dev Ethernet0
- name: Add route.
- shell: ip route add {{ dst_mirror_subnet }} via {{ switch_if1_ip }}
+ shell: ip route add {{ dst_mirror_subnet }} via {{ neighbor2_ip }}
- name: Create a rule within mirror table.
shell: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_rule_mirror }}
@@ -152,6 +149,7 @@
table_name_check: "{{ mirror_table_name }}"
rule_name_check: "{{ mirror_rule_name }}"
expect_data: false
+ expected_counter_value: 0
include: "{{ acl_check_db }}"
# CLEANUP.
@@ -159,6 +157,14 @@
include: "{{ run_config_cleanup }}"
- always:
+ - name: Delete neighbor.
+ shell: ip neigh del {{ neighbor2_ip }} dev Ethernet0
+ ignore_errors: yes
+
+ - name: Delete route.
+ shell: ip route del {{ dst_mirror_subnet }}
+ ignore_errors: yes
+
- name: Remove all the temporary files created by the test.
file: path="{{ run_dir }}/{{ item }}" state=absent
with_items:
diff --git a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_mirror_session.json b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_mirror_session.json
index 17809a5cbf7..edd911b5d7b 100644
--- a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_mirror_session.json
+++ b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_mirror_session.json
@@ -1,7 +1,7 @@
[
{
"MIRROR_SESSION_TABLE:session1": {
- "src_ip": "20.0.0.2",
+ "src_ip": "10.0.0.1",
"dst_ip": "2.2.2.4",
"gre_type": "0x6558",
"dscp": "50",
diff --git a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule.json b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule.json
index 501254cef38..53616c89299 100644
--- a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule.json
+++ b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table:acl_config_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "20.0.0.1/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.0/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule_mirror.json b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule_mirror.json
index 3941897a0d9..9cb5ad2e308 100644
--- a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule_mirror.json
+++ b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_rule_mirror.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table_mirror:acl_config_rule_mirror": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "20.0.0.1/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.0/24",
"MIRROR_ACTION" : "session1"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_l3.json b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_l3.json
index 50c5bf97fc4..04f81369513 100644
--- a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_l3.json
+++ b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_l3.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_mirror.json b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_mirror.json
index 34913d823d0..2c75d2250e3 100644
--- a/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_mirror.json
+++ b/ansible/roles/test/tasks/acl/acl_counter_traffic_test/config_table_type_mirror.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table_mirror": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "MIRROR",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_input_test/acl_config_invalid.json b/ansible/roles/test/tasks/acl/acl_input_test/acl_config_invalid.json
index 0f2e2462ad6..b62daf9481b 100644
--- a/ansible/roles/test/tasks/acl/acl_input_test/acl_config_invalid.json
+++ b/ansible/roles/test/tasks/acl/acl_input_test/acl_config_invalid.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:555555739a2cc107": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
@@ -10,8 +10,8 @@
{
"ACL_RULE_TABLE:555555739a2cc107:3f8a10ff": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_input_test/acl_config_valid.json b/ansible/roles/test/tasks/acl/acl_input_test/acl_config_valid.json
index 6a228f9da45..e74231ca2df 100644
--- a/ansible/roles/test/tasks/acl/acl_input_test/acl_config_valid.json
+++ b/ansible/roles/test/tasks/acl/acl_input_test/acl_config_valid.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:555555739a2cc107": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
@@ -10,8 +10,8 @@
{
"ACL_RULE_TABLE:555555739a2cc107:3f8a10ff": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/acl_orchagent_logic_test.yml b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/acl_orchagent_logic_test.yml
index f82343f6708..98ae5cf0e58 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/acl_orchagent_logic_test.yml
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/acl_orchagent_logic_test.yml
@@ -79,25 +79,6 @@
- name: Run config cleanup after.
include: "{{ run_config_cleanup }}"
-#-----------------------------------------
-# test duplicate table creation
-#-----------------------------------------
- - name: Create L3 table.
- vars:
- config_file: "{{ config_table_type_l3 }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: false
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - name: Create duplicate L3 table.
- vars:
- config_file: "{{ config_table_type_l3 }}"
- test_expect_file: "{{ config_table_type_expect }}"
- errors_expected: true
- run_cleanup: true
- include: "{{ run_config_test }}"
-
#------------------------------------------
# RULES TESTING
#------------------------------------------
@@ -479,13 +460,6 @@
run_cleanup: false
include: "{{ run_config_test }}"
- - name: Rule test - empty rule with no expectes.
- vars:
- config_file: "{{ config_rule_empty_invalid }}"
- test_expect_file: "{{ config_rule_empty_expect }}"
- errors_expected: true
- run_cleanup: false
- include: "{{ run_config_test }}"
- name: Rule test - create rule in non-existing table.
vars:
@@ -495,35 +469,6 @@
run_cleanup: true
include: "{{ run_config_test }}"
-#----------------------------------------------
-# test duplicate rule creation
-#----------------------------------------------
- - name: Create L3 table.
- vars:
- config_file: "{{ config_table_type_l3 }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: false
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - name: Rule test - valid rule.
- vars:
- config_file: "{{ config_rule }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: false
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- # Duplicate rule!
- - name: Rule test - duplicate rule creation.
- vars:
- config_file: "{{ config_rule }}"
- test_expect_file: "{{ config_duplicate_rule_expect }}"
- errors_expected: true
- run_cleanup: true
- include: "{{ run_config_test }}"
-
-
#----------------------------------------------------------------------------------
#----------------------------------------------------------------------------------
# Delete-test uploads different valid and invalid configs with OP: "DEL" and checks for the errors.
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_non_existing.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_non_existing.json
index 51726172541..04546bcbaf9 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_non_existing.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_non_existing.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table:non_existing_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "DEL"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_valid.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_valid.json
index 92a35b2d133..730b2b04847 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_valid.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_rule_valid.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table:acl_test_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "DEL"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_diff_fields.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_diff_fields.json
index c9d38a66d61..b075fead6b2 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_diff_fields.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_diff_fields.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"ports" : "Ethernet4"
},
"OP": "DEL"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_valid.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_valid.json
index 4fd99c3cf76..fcfcdb4ce03 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_valid.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_valid.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_with_rules.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_with_rules.json
index 4fd99c3cf76..fcfcdb4ce03 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_with_rules.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_del_table_with_rules.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_dscp_in_l3_table.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_dscp_in_l3_table.json
index e93302b550f..9982681dbcf 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_dscp_in_l3_table.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_dscp_in_l3_table.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table:acl_test_dscp_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD",
"dscp" : "0xFF"
},
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_ether_type_expect_file b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_ether_type_expect_file
index 820e6566073..42a9c938c8e 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_ether_type_expect_file
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_ether_type_expect_file
@@ -1 +1 @@
-r, ".*Failed to create.*rule. Rule configuration is invalid"
+r, ".*Failed to create ACL rule. Rule configuration is invalid"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule.json
index a153d8c57bd..c0e2cd2d5df 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table:acl_test_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule_in_non_existing_table.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule_in_non_existing_table.json
index f3e70d5f55c..f954d5a5504 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule_in_non_existing_table.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_rule_in_non_existing_table.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:NON_EXISTING_TABLE:acl_test_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "FORWARD"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_table_type_l3.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_table_type_l3.json
index 50c5bf97fc4..04f81369513 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_table_type_l3.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_table_type_l3.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_1.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_1.json
index 1fc8c396df9..8d38055cca6 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_1.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_1.json
@@ -3,7 +3,7 @@
"ACL_RULE_TABLE:acl_test_table:acl_test_rule_valid_1": {
"priority" : "55",
"PACKET_ACTION" : "FORWARD",
- "TCP_FLAGS" : "FA"
+ "TCP_FLAGS" : "0x1/0xFF"
},
"OP": "SET"
}
diff --git a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_2.json b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_2.json
index 92c8685318b..090f64d17ee 100644
--- a/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_2.json
+++ b/ansible/roles/test/tasks/acl/acl_orchagent_logic_test/config_tcp_flags_valid_2.json
@@ -3,7 +3,7 @@
"ACL_RULE_TABLE:acl_test_table:acl_test_rule_valid_2": {
"priority" : "55",
"PACKET_ACTION" : "FORWARD",
- "TCP_FLAGS" : "0xFA"
+ "TCP_FLAGS" : "0xFA/0xFF"
},
"OP": "SET"
}
diff --git a/ansible/roles/test/tasks/acl/acl_port_bind_test/config_bind_duplicate_port_expect_file b/ansible/roles/test/tasks/acl/acl_port_bind_test/config_bind_duplicate_port_expect_file
index 7e2f78a4918..b285572d8a3 100644
--- a/ansible/roles/test/tasks/acl/acl_port_bind_test/config_bind_duplicate_port_expect_file
+++ b/ansible/roles/test/tasks/acl/acl_port_bind_test/config_bind_duplicate_port_expect_file
@@ -1 +1 @@
-r, ".*Failed to process port list. Duplicate port entry."
+r, ".*Failed to process port list. Duplicate port entry"
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/acl_port_range_test.yml b/ansible/roles/test/tasks/acl/acl_port_range_test/acl_port_range_test.yml
index bf08062dd99..6c3abcab5c9 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/acl_port_range_test.yml
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/acl_port_range_test.yml
@@ -70,40 +70,6 @@
run_cleanup: false
include: "{{ run_config_test }}"
- - name: Run config cleanup after.
- include: "{{ run_config_cleanup }}"
-
- # Mirror table and rule testing.
- - name: Create a mirror session.
- shell: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_mirror_session }}
-
- - name: Create a mirror table.
- shell: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_table_type_mirror }}
-
- - name: Add neighbor.
- shell: ip neigh add {{ switch_if_ip }} lladdr 0e:9c:37:42:43:67 dev {{ switch_if }}
-
- - name: Add route.
- shell: ip route add {{ dst_mirror_subnet }} via {{ switch_if_ip }}
-
- - name: Rule test - valid port range on mirror table.
- vars:
- config_file: "{{ config_l4_port_range_on_mirror_table }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: false
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - block:
- - name: See that Redis DB has got an appropriate field.
- shell: docker exec -i database redis-cli -n 1 KEYS \* | grep SAI_OBJECT_TYPE_ACL_RANGE
- register: grep
- failed_when: grep.rc != 0
-
- always:
- - fail: msg="Redis DB has NOT got an appropriate field for rule (config file used - {{ config_l4_port_range_on_mirror_table }})"
- when: grep.rc != 0
-
- name: Run config cleanup after.
include: "{{ run_config_cleanup }}"
@@ -142,51 +108,9 @@
config_file: "{{ config_l4_port_range_invalid_4 }}"
test_expect_file: "{{ config_l4_port_range_expect }}"
errors_expected: true
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - name: Rule test - two ranges in rule, both matching source port.
- vars:
- config_file: "{{ config_l4_port_range_invalid_5 }}"
- test_expect_file: "{{ config_l4_port_range_expect }}"
- errors_expected: true
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - name: Rule test - two ranges in rule, both matching destination port.
- vars:
- config_file: "{{ config_l4_port_range_invalid_6 }}"
- test_expect_file: "{{ config_l4_port_range_expect }}"
- errors_expected: true
- run_cleanup: false
+ run_cleanup: true
include: "{{ run_config_test }}"
- - name: Rule test - three valid ranges in one rule (error case).
- vars:
- config_file: "{{ config_l4_port_range_invalid_7 }}"
- test_expect_file: "{{ config_l4_port_range_expect }}"
- errors_expected: true
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - name: Rule test - 17 valid rules (syncd might crash).
- vars:
- config_file: "{{ config_l4_port_range_invalid_8 }}"
- test_expect_file: "{{ config_l4_port_range_expect }}"
- errors_expected: false
- run_cleanup: false
- include: "{{ run_config_test }}"
-
- - block:
- - name: See that Redis-DB has NOT got an appropriate field.
- shell: docker exec -i database redis-cli -n 1 KEYS \* | grep SAI_OBJECT_TYPE_ACL_RANGE
- register: grep
- failed_when: grep.rc == 0
-
- always:
- - fail: msg="Redis-DB has got data about invalid rule"
- when: grep.rc == 0
-
#--------------------------------
# Test the configuration deleting.
#--------------------------------
@@ -249,10 +173,6 @@
loganalyzer_run_analyze: false
include: "{{ run_loganalyzer }}"
- - name: Set host interface IP address.
- shell: ifconfig {{ ptf_host_if }} {{ ptf_host_if_ip }}/24
- delegate_to: "{{ ptf_host }}"
-
- name: Create target directory
file: path={{ host_testdir }} state=directory
delegate_to: "{{ ptf_host }}"
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_limited_port_range.json b/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_limited_port_range.json
index 09ddd679dcd..4d0fc6d4304 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_limited_port_range.json
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_limited_port_range.json
@@ -1,6 +1,6 @@
[
{
- "ACL_RULE_TABLE:acl_test_table:acl_rule_limited_port_range": {
+ "ACL_RULE_TABLE:acl_test_table:acl_rule_limited_range": {
"priority" : "55",
"PACKET_ACTION" : "FORWARD",
"L4_SRC_PORT_RANGE" : "1028-4096"
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_port_range_on_mirror_table.json b/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_port_range_on_mirror_table.json
index 41aed469ac4..0780c1f863f 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_port_range_on_mirror_table.json
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/config_l4_port_range_on_mirror_table.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table_mirror:acl_test_rule": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "20.0.0.1/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.0/24",
"MIRROR_ACTION" : "test_session",
"L4_SRC_PORT_RANGE" : "0-1028"
},
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/config_mirror_session.json b/ansible/roles/test/tasks/acl/acl_port_range_test/config_mirror_session.json
index 403af08b05e..c34fa450b20 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/config_mirror_session.json
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/config_mirror_session.json
@@ -1,7 +1,7 @@
[
{
"MIRROR_SESSION_TABLE:test_session": {
- "src_ip": "20.0.0.2",
+ "src_ip": "10.0.0.1",
"dst_ip": "2.2.2.4",
"gre_type": "0x6558",
"dscp": "50",
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/config_rule_mirror.json b/ansible/roles/test/tasks/acl/acl_port_range_test/config_rule_mirror.json
index 3941897a0d9..9cb5ad2e308 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/config_rule_mirror.json
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/config_rule_mirror.json
@@ -2,8 +2,8 @@
{
"ACL_RULE_TABLE:acl_test_table_mirror:acl_config_rule_mirror": {
"priority" : "55",
- "SRC_IP" : "20.0.0.2/24",
- "DST_IP" : "20.0.0.1/24",
+ "SRC_IP" : "10.0.0.1/24",
+ "DST_IP" : "10.0.0.0/24",
"MIRROR_ACTION" : "session1"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_l3.json b/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_l3.json
index 50c5bf97fc4..04f81369513 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_l3.json
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_l3.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "L3",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_mirror.json b/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_mirror.json
index 34913d823d0..2c75d2250e3 100644
--- a/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_mirror.json
+++ b/ansible/roles/test/tasks/acl/acl_port_range_test/config_table_type_mirror.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:acl_test_table_mirror": {
- "policy_desc" : "Permit_some_traffic_from_20.0.0.2",
+ "policy_desc" : "Permit_some_traffic_from_10.0.0.1",
"type" : "MIRROR",
"ports" : "Ethernet0"
},
diff --git a/ansible/roles/test/tasks/acl/acl_traffic_test/acl_traffic_test.yml b/ansible/roles/test/tasks/acl/acl_traffic_test/acl_traffic_test.yml
index d38bd01c634..2be2dfd3050 100644
--- a/ansible/roles/test/tasks/acl/acl_traffic_test/acl_traffic_test.yml
+++ b/ansible/roles/test/tasks/acl/acl_traffic_test/acl_traffic_test.yml
@@ -77,30 +77,6 @@
run_cleanup: true
include: "{{ run_ping_test }}"
- - name: ACL drop traffic by destination l4 port test
- vars:
- config_file: "{{ config_traffic_drop_l4_dst_port }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: true
- run_cleanup: true
- include: "{{ run_ptf_test }}"
-
- - name: ACL drop traffic by source l4 port test
- vars:
- config_file: "{{ config_traffic_drop_l4_src_port }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: true
- run_cleanup: true
- include: "{{ run_ptf_test }}"
-
- - name: ACL drop traffic by tcp flags test
- vars:
- config_file: "{{ config_traffic_drop_tcp_flags }}"
- test_expect_file: "{{ config_empty_expect }}"
- errors_expected: true
- run_cleanup: true
- include: "{{ run_ptf_test }}"
-
always:
- name: Remove all the temporary created by the test.
file: path="{{ run_dir }}/{{ item }}" state=absent
diff --git a/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_dst_ip.json b/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_dst_ip.json
index 41b358f958c..7d09fd252e2 100644
--- a/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_dst_ip.json
+++ b/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_dst_ip.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:Drop_IP": {
- "policy_desc" : "Drop_IP_Traffic_to_21.0.0.1",
+ "policy_desc" : "Drop_IP_Traffic_to_10.0.0.2",
"type" : "L3",
"ports" : "Ethernet0"
},
@@ -10,7 +10,7 @@
{
"ACL_RULE_TABLE:Drop_IP:TheDrop": {
"priority" : "55",
- "DST_IP" : "21.0.0.1/24",
+ "DST_IP" : "10.0.0.2/24",
"PACKET_ACTION" : "DROP"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_src_ip.json b/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_src_ip.json
index 73e82b8a5da..70d9f1e950d 100644
--- a/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_src_ip.json
+++ b/ansible/roles/test/tasks/acl/acl_traffic_test/config_traffic_drop_src_ip.json
@@ -1,7 +1,7 @@
[
{
"ACL_TABLE:Drop_IP": {
- "policy_desc" : "Drop_IP_Traffic_from_21.0.0.2",
+ "policy_desc" : "Drop_IP_Traffic_from_10.0.0.3",
"type" : "L3",
"ports" : "Ethernet0"
},
@@ -10,7 +10,7 @@
{
"ACL_RULE_TABLE:Drop_IP:TheDrop": {
"priority" : "55",
- "SRC_IP" : "21.0.0.2/24",
+ "SRC_IP" : "10.0.0.3/24",
"PACKET_ACTION" : "DROP"
},
"OP": "SET"
diff --git a/ansible/roles/test/tasks/acl/acl_traffic_test/run_ping_test.yml b/ansible/roles/test/tasks/acl/acl_traffic_test/run_ping_test.yml
index 0fd6be9df4a..0eabbfed108 100644
--- a/ansible/roles/test/tasks/acl/acl_traffic_test/run_ping_test.yml
+++ b/ansible/roles/test/tasks/acl/acl_traffic_test/run_ping_test.yml
@@ -2,7 +2,10 @@
# Execute ping and check the log.
#-----------------------------------------
-- include_vars: "{{ vars_files_location }}/run_ping_test_vars.yml"
+- include_vars: "vars/run_ping_test_vars.yml"
+
+- name: Start log analyser
+ include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
- block:
- name: Execute ping from host to switch to validate link
@@ -11,9 +14,6 @@
failed_when: pingrc.rc != 0
delegate_to: "{{ ptf_host }}"
- - name: Start log analyser
- include: "{{ loganalyzer_init }}"
-
- name: Set ACL rules.
command: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_file }}
@@ -35,7 +35,7 @@
- name: Check the number of error messages (positive tests only).
fail: msg="{{ errors_found.stdout }} errors found while running {{ testname }} / {{ config_file }}. Please see {{ test_out_dir }}/{{ result_file }}"
- when: errors_found.stdout != "0"
+ when: errors_found.rc != 0
- name: Do configuration cleanup.
include: "{{ run_config_cleanup }}"
diff --git a/ansible/roles/test/tasks/acl/acl_traffic_test/run_ptf_test.yml b/ansible/roles/test/tasks/acl/acl_traffic_test/run_ptf_test.yml
index 06e13474e6a..059652ddaec 100644
--- a/ansible/roles/test/tasks/acl/acl_traffic_test/run_ptf_test.yml
+++ b/ansible/roles/test/tasks/acl/acl_traffic_test/run_ptf_test.yml
@@ -2,7 +2,7 @@
# Send some TCP packets.
#-----------------------------------------
-- include_vars: "{{ vars_files_location }}/run_ptf_test_vars.yml"
+- include_vars: "vars/run_ptf_test_vars.yml"
- block:
- name: Execute ping from host to switch to validate link
diff --git a/ansible/roles/test/tasks/acl/acltb_expect_messages.txt b/ansible/roles/test/tasks/acl/acltb_expect_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/acl/acltb_ignore_messages.txt b/ansible/roles/test/tasks/acl/acltb_ignore_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/acl/acltb_match_messages.txt b/ansible/roles/test/tasks/acl/acltb_match_messages.txt
new file mode 100644
index 00000000000..b6898ebbf4c
--- /dev/null
+++ b/ansible/roles/test/tasks/acl/acltb_match_messages.txt
@@ -0,0 +1 @@
+s, "removeNeighbor: Neighbor is still referenced"
diff --git a/ansible/roles/test/tasks/acltb.yml b/ansible/roles/test/tasks/acltb.yml
new file mode 100644
index 00000000000..bd10a48bb89
--- /dev/null
+++ b/ansible/roles/test/tasks/acltb.yml
@@ -0,0 +1,20 @@
+#-----------------------------------------
+# Apply ACL configuration
+#-----------------------------------------
+- name: Acl test setup on testbed
+ include: acltb_configure.yml
+ tags: acltb_configure
+
+#-----------------------------------------
+# Run ACL test
+#-----------------------------------------
+- name: Acl test run on testbed
+ include: acltb_test.yml
+ tags: acltb_test
+
+#-----------------------------------------
+# Clean up ACL configuration
+#-----------------------------------------
+- name: Clean up ACL test configuration on the testbed
+ include: acltb_cleanup.yml
+ tags: acltb_cleanup
diff --git a/ansible/roles/test/tasks/acltb_cleanup.yml b/ansible/roles/test/tasks/acltb_cleanup.yml
new file mode 100644
index 00000000000..290229e4c70
--- /dev/null
+++ b/ansible/roles/test/tasks/acltb_cleanup.yml
@@ -0,0 +1,68 @@
+# Set facts for ACL configuration
+- set_fact:
+ acltb_configs:
+ - "{{ 'acltb_test_rules.json' }}"
+ - "{{ 'acltb_test_table.json' }}"
+
+# Set facts for the loganalizer
+- set_fact:
+ testname: acl
+ run_dir: /tmp
+ out_dir: /tmp/ansible-loganalyzer-results
+ test_match_file: acltb_match_messages.txt
+ test_ignore_file: acltb_ignore_messages.txt
+ test_expect_file: acltb_expect_messages.txt
+ match_file: loganalyzer_common_match.txt
+ ignore_file: loganalyzer_common_ignore.txt
+ tests_location: "{{ 'roles/test/tasks' }}"
+
+# Separate set_fact is required to be able to use 'testname' fact.
+- set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
+
+# Separate set_fact is required to be able to use 'testname_unique' fact.
+- set_fact:
+ test_out_dir: "{{ out_dir }}/{{testname_unique}}"
+ match_file_list: "{{ run_dir }}/{{test_match_file}},{{ run_dir }}/{{match_file}}"
+ ignore_file_list: "{{ run_dir }}/{{test_ignore_file}},{{ run_dir }}/{{ignore_file}}"
+ result_file: result.loganalysis.{{testname_unique}}.log
+ summary_file: summary.loganalysis.{{testname_unique}}.log
+
+# Gather minigraph facts
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ become: no
+ connection: local
+
+- name: Read port reverse alias mapping
+ set_fact:
+ alias_reverse_map: "{{ minigraph_map_ngs_to_sonic }}"
+
+# Generate json files with ACL configuration for tests
+- template: src=acltb_test_table.j2 dest=/tmp/acltb_test_table.json
+ connection: local
+
+- template: src=acltb_test_rules.j2 dest=/tmp/acltb_test_rules.json
+ connection: local
+
+# Copy ACL config to the swss container via the switch
+- name: Copy ACL config file to the DUT
+ copy: src="/tmp/{{ item }}" dest="/tmp/{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
+
+- name: Copy ACL config file to the swss container
+ command: docker cp "/tmp/{{ item }}" swss:/etc/swss/config.d/"{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
+
+- name: Create ACL configuration to delete rules/tables
+ command: docker exec -t swss bash -c "sed -i 's/SET/DEL/g' /etc/swss/config.d/{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
+
+- block:
+ - name: Apply ACL delete configuration
+ command: docker exec -t swss bash -c "swssconfig /etc/swss/config.d/{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
diff --git a/ansible/roles/test/tasks/acltb_configure.yml b/ansible/roles/test/tasks/acltb_configure.yml
new file mode 100644
index 00000000000..44915a0e789
--- /dev/null
+++ b/ansible/roles/test/tasks/acltb_configure.yml
@@ -0,0 +1,64 @@
+# Set facts for ACL configuration
+- set_fact:
+ acltb_configs:
+ - "{{ 'acltb_test_table.json' }}"
+ - "{{ 'acltb_test_rules.json' }}"
+
+# Set facts for the loganalizer
+- set_fact:
+ testname: acl
+ run_dir: /tmp
+ out_dir: /tmp/ansible-loganalyzer-results
+ test_match_file: acltb_match_messages.txt
+ test_ignore_file: acltb_ignore_messages.txt
+ test_expect_file: acltb_expect_messages.txt
+ match_file: loganalyzer_common_match.txt
+ ignore_file: loganalyzer_common_ignore.txt
+ tests_location: "{{ 'roles/test/tasks' }}"
+
+# Separate set_fact is required to be able to use 'testname' fact.
+- set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
+
+# Separate set_fact is required to be able to use 'testname_unique' fact.
+- set_fact:
+ test_out_dir: "{{ out_dir }}/{{testname_unique}}"
+ match_file_list: "{{ run_dir }}/{{test_match_file}},{{ run_dir }}/{{match_file}}"
+ ignore_file_list: "{{ run_dir }}/{{test_ignore_file}},{{ run_dir }}/{{ignore_file}}"
+ result_file: result.loganalysis.{{testname_unique}}.log
+ summary_file: summary.loganalysis.{{testname_unique}}.log
+
+# Gather minigraph facts
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ become: no
+ connection: local
+
+- name: Read port reverse alias mapping
+ set_fact:
+ alias_reverse_map: "{{ minigraph_map_ngs_to_sonic }}"
+ podset_number: 200
+
+# Generate json files with ACL configuration for tests
+- template: src=acltb_test_table.j2 dest=/tmp/acltb_test_table.json
+ connection: local
+
+- template: src=acltb_test_rules.j2 dest=/tmp/acltb_test_rules.json
+ connection: local
+
+# Copy ACL config to the swss container via the switch
+- name: Copy ACL config file to the DUT
+ copy: src="/tmp/{{ item }}" dest="/tmp/{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
+
+- name: Copy ACL config file to the swss container
+ command: docker cp "/tmp/{{ item }}" swss:/etc/swss/config.d/"{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
+
+- block:
+ - name: Apply ACL configuration
+ command: docker exec -t swss bash -c "swssconfig /etc/swss/config.d/{{ item }}"
+ with_items:
+ - "{{ acltb_configs }}"
diff --git a/ansible/roles/test/tasks/acltb_ranges_test.yml b/ansible/roles/test/tasks/acltb_ranges_test.yml
new file mode 100644
index 00000000000..42165b3700c
--- /dev/null
+++ b/ansible/roles/test/tasks/acltb_ranges_test.yml
@@ -0,0 +1,106 @@
+# Usage example:
+# ansible-playbook test_sonic.yml -i inventory --limit arc-switch1028 --tags acltb_ranges_test -b -e ranges_number=3 -e ptf_host=ptf-fib
+#
+# Variable "ranges_number" defines how many ACL range objects the test will attempt to create
+#
+
+# Input arguments check
+- fail: msg="ranges_number is not defined."
+ when: ranges_number is not defined
+
+# Set facts for ACL configuration
+- set_fact:
+ acltb_configs:
+ - "{{ 'acl_ranges_table' }}"
+ - "{{ 'acl_ranges_rules' }}"
+
+# Set facts for the loganalizer
+- set_fact:
+ testname: acl
+ run_dir: /tmp
+ out_dir: /tmp/ansible-loganalyzer-results
+ test_match_file: acltb_match_messages.txt
+ test_ignore_file: acltb_ignore_messages.txt
+ test_expect_file: acltb_expect_messages.txt
+ match_file: loganalyzer_common_match.txt
+ ignore_file: loganalyzer_common_ignore.txt
+
+# Separate set_fact is required to be able to use 'testname' fact.
+- set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
+
+# Separate set_fact is required to be able to use 'testname_unique' fact.
+- set_fact:
+ test_out_dir: "{{ out_dir }}/{{testname_unique}}"
+ match_file_list: "{{ run_dir }}/{{test_match_file}},{{ run_dir }}/{{match_file}}"
+ ignore_file_list: "{{ run_dir }}/{{test_ignore_file}},{{ run_dir }}/{{ignore_file}}"
+ result_file: result.loganalysis.{{testname_unique}}.log
+ summary_file: summary.loganalysis.{{testname_unique}}.log
+
+# Gather minigraph facts
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ become: no
+ connection: local
+
+- name: Read port reverse alias mapping
+ set_fact:
+ alias_reverse_map: "{{ lookup('file', 'roles/sonicv2/files/ssw/{{ sonic_hwsku }}/alias_reverse_map.json') | from_json }}"
+
+- include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
+ vars:
+ tests_location: "{{ 'roles/test/tasks' }}"
+
+# Outer block to execute laganalizer in always block
+- block:
+ # Perform the test: generate and apply acl jsons
+ - block:
+ - name: Copy JSON configs into docker filesystem
+ template: src={{ item }}.j2 dest=/tmp/{{ item }}.json
+ with_items:
+ - "{{ acltb_configs }}"
+
+ - name: Load JSON configs
+ shell: swssconfig /tmp/{{ item }}.json
+ with_items:
+ - "{{ acltb_configs }}"
+
+ - name: Change JSON configs to delete (table)
+ shell: sed 's/SET/DEL/g' /tmp/{{ item }}.json >/tmp/del_{{ item }}.json
+ with_items:
+ - "{{ acltb_configs }}"
+
+ - name: Pause 5 sec to let rules to settle down
+ pause:
+ seconds: 5
+
+ - name: Load JSON configs in reversed order
+ shell: swssconfig /tmp/del_{{ item }}.json
+ with_items:
+ - "{{ acltb_configs[::-1] }}"
+
+ vars:
+ ansible_shell_type: docker
+ ansible_python_interpreter: docker exec -i swss python
+
+ always:
+ - include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
+ vars:
+ tests_location: "{{ 'roles/test/tasks' }}"
+
+ # Output content of result files to ansible console
+ - shell: cat {{ test_out_dir }}/*
+ register: out
+ - debug: var=out.stdout_lines
+
+ - name: Get the total number of error messages.
+ shell: grep "TOTAL MATCHES" "{{ test_out_dir }}/{{ summary_file }}" | sed -n "s/TOTAL MATCHES:[[:space:]]*//p"
+ register: errors_found
+
+ - name: Check the number of error messages (positive tests only).
+ fail: msg="{{ errors_found.stdout }} errors found while running {{ testname }} test. Please see {{ test_out_dir }}/{{ result_file }}"
+ when: errors_found.stdout != "0"
+
+ - include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml
+ vars:
+ tests_location: "{{ 'roles/test/tasks' }}"
diff --git a/ansible/roles/test/tasks/acltb_test.yml b/ansible/roles/test/tasks/acltb_test.yml
new file mode 100644
index 00000000000..30a6f74864e
--- /dev/null
+++ b/ansible/roles/test/tasks/acltb_test.yml
@@ -0,0 +1,76 @@
+#-----------------------------------------
+# Run ACL test and Perform log analysis.
+#-----------------------------------------
+
+# Pre-check testbed_type value
+- fail: msg="testbed_type is not defined."
+ when: testbed_type is not defined
+
+- fail: msg="testbed_type {{testbed_type}} is invalid."
+ when: testbed_type not in ['t1-lag', 't1']
+
+- include_vars: "vars/topo_{{testbed_type}}.yml"
+
+# Gather minigraph facts
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ become: no
+ connection: local
+
+- name: Read port reverse alias mapping
+ set_fact:
+ alias_reverse_map: "{{ minigraph_map_ngs_to_sonic }}"
+
+- name: Expand properties into props
+ set_fact: props="{{configuration_properties['spine']}}"
+ when: testbed_type in ['t1', 't1-lag']
+
+# Generate file with switch information
+- template: src=acltb.j2 dest=/tmp/acltb_switch_info.txt
+ connection: local
+
+- name: Copy switch info file to the PTF host
+ copy: src=/tmp/acltb_switch_info.txt dest=/tmp/acltb_switch_info.txt
+ delegate_to: "{{ ptf_host }}"
+
+- set_fact:
+ testname: acl
+ run_dir: /tmp
+ out_dir: /tmp/ansible-loganalyzer-results
+ test_match_file: acltb_match_messages.txt
+ test_ignore_file: acltb_ignore_messages.txt
+ test_expect_file: acltb_expect_messages.txt
+ match_file: loganalyzer_common_match.txt
+ ignore_file: loganalyzer_common_ignore.txt
+ tests_location: "{{ 'roles/test/tasks' }}"
+
+# Separate set_fact is required to be able to use 'testname' fact.
+- set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
+
+# Separate set_fact is required to be able to use 'testname_unique' fact.
+- set_fact:
+ test_out_dir: "{{ out_dir }}/{{testname_unique}}"
+ match_file_list: "{{ run_dir }}/{{test_match_file}},{{ run_dir }}/{{match_file}}"
+ ignore_file_list: "{{ run_dir }}/{{test_ignore_file}},{{ run_dir }}/{{ignore_file}}"
+ result_file: result.loganalysis.{{testname_unique}}.log
+ summary_file: summary.loganalysis.{{testname_unique}}.log
+
+- name: Copy the ACL test to PTF container
+ become: true
+ copy: src=roles/test/files/acstests/acltb_test.py dest=/root/test/
+ delegate_to: "{{ ptf_host }}"
+
+# Run the ACL PTF test
+- block:
+ - name: Run the test
+ include: ptf_runner.yml
+ vars:
+ ptf_test_name: ACL Test
+ ptf_test_dir: test
+ ptf_test_path: acltb_test.AclTest
+ ptf_platform: remote
+ ptf_test_params:
+ - verbose=True
+ - router_mac=\"{{ ansible_Ethernet0['macaddress'] }}\"
+ - switch_info=\"/tmp/acltb_switch_info.txt\"
diff --git a/ansible/roles/test/tasks/arpall.yml b/ansible/roles/test/tasks/arpall.yml
index 3bcd65fb0d4..e891ae9aaf8 100644
--- a/ansible/roles/test/tasks/arpall.yml
+++ b/ansible/roles/test/tasks/arpall.yml
@@ -55,7 +55,7 @@
assert:
that:
- "'{{ item.key }}|string' != '10.10.1.4'"
- with_dict: arptable2.arptable.v4
+ with_dict: "{{ arptable2.arptable.v4 }}"
## check DUT won't reply ARP and install ARP entry when src address is not in interface subnet range
- name: Clear DUT arp cache
@@ -76,7 +76,7 @@
assert:
that:
- "'{{ item.key }}|string' != '10.10.1.22'"
- with_dict: arptable3.arptable.v4
+ with_dict: "{{ arptable3.arptable.v4 }}"
## Test Gratuitous ARP behavior, no Gratuitous ARP installed when arp was not resolved before
- name: Clear DUT arp cache
@@ -97,7 +97,7 @@
assert:
that:
- "'{{ item.key }}|string' != '10.10.1.7'"
- with_dict: arptable5.arptable.v4
+ with_dict: "{{ arptable5.arptable.v4 }}"
# Test Gratuitous ARP update case, when received garp, no arp reply, update arp table if it was solved before
- name: Send correct arp packets (10.10.1.3 to 10.10.1.2 with src_mac=00:06:07:08:09:0a)
@@ -136,8 +136,8 @@
# Recover DUT interface IP Address before entering this test case
- name: Recover DUT IP address based on minigraph
- command: /sbin/ifconfig {{item.name}} {{ item.addr }} netmask {{ item.mask }}
+ command: /sbin/ifconfig {{item.attachto}} {{ item.addr }} netmask {{ item.mask }}
become: yes
- with_items: minigraph_interfaces
- when: item.name == 'Ethernet4' or item.name == 'Ethernet8'
+ with_items: "{{ minigraph_interfaces }}"
+ when: (item.attachto == 'Ethernet4' or item.attachto == 'Ethernet8') and item.addr|ipv4
diff --git a/ansible/roles/test/tasks/base_sanity.yml b/ansible/roles/test/tasks/base_sanity.yml
new file mode 100644
index 00000000000..1e0f26436f1
--- /dev/null
+++ b/ansible/roles/test/tasks/base_sanity.yml
@@ -0,0 +1,18 @@
+ - name: Get process information in syncd docker
+ shell: docker exec -i syncd ps aux | grep /usr/bin/syncd
+ register: ps_out
+
+ - debug: var=ps_out.stdout_lines
+
+ - name: Verify that syncd process is running
+ assert: { that: "{{ ps_out.stdout_lines | length }} > 0"}
+
+ - name: Get syslog error information
+ shell: cat /var/log/syslog |tail -n 5000 |grep -i error
+ become: true
+ register: syslog_out
+ failed_when: false
+
+ - debug: var=syslog_out.stdout_lines
+
+
diff --git a/ansible/roles/test/tasks/bgp_fact.yml b/ansible/roles/test/tasks/bgp_fact.yml
index 05d69a055c5..d4fd9e79783 100644
--- a/ansible/roles/test/tasks/bgp_fact.yml
+++ b/ansible/roles/test/tasks/bgp_fact.yml
@@ -18,17 +18,17 @@
- name: Verify bgp sessions are established
assert: { that: "'{{ bgp_neighbors[item]['state'] }}' == 'established'" }
- with_items: bgp_neighbors.keys()
+ with_items: "{{ bgp_neighbors.keys() }}"
- name: Verify locat ASNs in bgp sessions
assert: { that: "'{{ bgp_neighbors[item]['local AS'] }}' == '{{ minigraph_bgp_asn }}'" }
- with_items: bgp_neighbors.keys()
+ with_items: "{{ bgp_neighbors.keys() }}"
- name: Compare the bgp neighbors name with minigraph bgp neigbhors name
- assert: { that: "'{{ item['name'] }}' == '{{ bgp_neighbors[item['addr']]['description'] }}'" }
- with_items: minigraph_bgp
+ assert: { that: "'{{ item['name'] }}' == '{{ bgp_neighbors[item['addr'].lower()]['description'] }}'" }
+ with_items: "{{ minigraph_bgp }}"
- name: Compare the bgp neighbors ASN with minigraph
- assert: { that: "'{{ item['asn'] }}' == '{{ bgp_neighbors[item['addr']]['remote AS'] }}'" }
- with_items: minigraph_bgp
+ assert: { that: "'{{ item['asn'] }}' == '{{ bgp_neighbors[item['addr'].lower()]['remote AS'] }}'" }
+ with_items: "{{ minigraph_bgp }}"
diff --git a/ansible/roles/test/tasks/bgp_flap.yml b/ansible/roles/test/tasks/bgp_flap.yml
index 192886cb298..e9987917e52 100644
--- a/ansible/roles/test/tasks/bgp_flap.yml
+++ b/ansible/roles/test/tasks/bgp_flap.yml
@@ -1,4 +1,3 @@
-# Shuotian Cheng
#
# This test is part of sswsyncd functionality tests.
#
@@ -7,18 +6,17 @@
# nexthopgroup table is updated according to the certain BGP session flappings.
- set_fact:
acs_devices: "{{ minigraph_devices }}"
- bgp_neighbors: "{{ minigraph_bgp }}"
- debug: var=sonic_asic_type
- set_fact: asic="{{ sonic_asic_type }}"
- include: bgp_nei_up.yml
- with_items: bgp_neighbors
+ with_items: "{{ minigraph_bgp }}"
when: "'T2' in item['name']"
- include: bgp_entry_flap.yml
- with_items: bgp_neighbors
+ with_items: "{{ minigraph_bgp }}"
- name: recover minigraph facts about the device(above steps loaded neighbors configuration)
minigraph_facts: host="{{ inventory_hostname }}"
diff --git a/ansible/roles/test/tasks/bgp_speaker.yml b/ansible/roles/test/tasks/bgp_speaker.yml
new file mode 100644
index 00000000000..b5cfa5a0ad2
--- /dev/null
+++ b/ansible/roles/test/tasks/bgp_speaker.yml
@@ -0,0 +1,184 @@
+#========================================
+# Run BGP Speaker test
+#========================================
+
+- fail: msg="Information about tested missing"
+ when: (testbed_type is not defined or ptf_host is not defined)
+
+- fail: msg="Invalid testbed_type value '{{testbed_type}}'"
+ when: testbed_type not in ['t0']
+
+- include_vars: "vars/deployment_id_asn_map.yml"
+
+- name: Gather minigraph facts about the device
+ minigraph_facts: host={{inventory_hostname}}
+ become: no
+ connection: local
+
+- name: print deployment id
+ debug: msg="{{deployment_id}}"
+
+- name: set bgp speaker asn number
+ set_fact:
+ bgp_speaker_asn={{deployment_id_asn_map[deployment_id]}}
+
+- name: print bgp speaker asn number
+ debug: msg="{{bgp_speaker_asn}}"
+
+- name: Generate three ips in VLAN range
+ get_ip_in_range: num=3 prefix="{{minigraph_vlan_interfaces[0]['addr']}}/{{minigraph_vlan_interfaces[0]['prefixlen']}}" exclude_ips="{{minigraph_vlan_interfaces[0]['addr']}}"
+ become: no
+ connection: local
+ failed_when: False
+
+- name: Store the value of VLAN IPs
+ set_fact:
+ vlan_ips={{generated_ips}}
+
+- debug: msg="{{generated_ips}}"
+
+- name: Generate two ips in bgp speaker peer range
+ get_ip_in_range: num=2 prefix={{minigraph_bgp_peers_with_range[0]['ip_range'][0]}}
+ become: no
+ connection: local
+
+- name: Set the value of ips in bgp speaker peer range
+ set_fact: speaker_ips={{generated_ips}}
+
+- debug: msg="{{generated_ips}}"
+
+# vlan_ips[0], speaker_ips[0], speaker_ips[1] are IPs for three bgp speakers
+# vlan_ips[1], vlan_ips[2] are IPs for mux under DUT.
+- name: Create directory /exabgp to store exabgp related files.
+ file: path=/root/exabgp state=directory
+ connection: local
+
+- name: set exabgp folder name
+ set_fact:
+ exabgp_dir="/root/exabgp"
+
+- name: Create directory /exabgp to store exabgp related files.
+ file: path={{exabgp_dir}} state=directory
+ delegate_to: "{{ptf_host}}"
+
+- name: Copy helper files to ptf container
+ copy: src=roles/test/files/helpers dest=/root
+ delegate_to: "{{ptf_host}}"
+
+- name: set exabgp folder name
+ set_fact:
+ helper_dir="/root/helpers"
+
+- name: Generate configurations for exabgp instances
+ template: src=roles/test/templates/exabgp/config.j2 dest={{exabgp_dir}}/{{item.file_name}}
+ with_items:
+ - {file_name: "config_1.ini", local_ip: '{{speaker_ips[0]}}', port_num: '5000'}
+ - {file_name: "config_2.ini", local_ip: '{{speaker_ips[1]}}', port_num: '6000'}
+ - {file_name: "config_3.ini", local_ip: '{{vlan_ips[0]}}', port_num: '7000'}
+ delegate_to: "{{ptf_host}}"
+
+- set_fact: addr_family='ipv4'
+ when: addr_family is not defined
+
+- name: Activate IPv6 address family
+ shell: vtysh -c "conf t" -c "router bgp {{ minigraph_bgp_asn }}" -c "address-family ipv6" -c "neighbor BGPSLBPassive activate"
+ when: addr_family == 'ipv6'
+
+- name: Set the prefix to be announced
+ set_fact:
+ announce_prefix: "{% if addr_family=='ipv4' %}10.10.10.0/26{% else %}2010::/126{% endif %}"
+
+- name: Generate routes to be announced
+ template: src=roles/test/templates/exabgp/routes.j2 dest={{exabgp_dir}}/routes
+ with_items:
+ - {speaker_ip: '{{vlan_ips[0]}}',
+ mux_ip_1: "{% if addr_family=='ipv4' %}{{vlan_ips[1]}}{% else %}{{minigraph_portchannel_interfaces[1]['peer_addr']}}{% endif %}",
+ mux_ip_2: "{% if addr_family=='ipv4' %}{{vlan_ips[2]}}{% else %}{{minigraph_portchannel_interfaces[3]['peer_addr']}}{% endif %}",
+ port_num_1: '5000',
+ port_num_2: '6000',
+ port_num_3: '7000'}
+ delegate_to: "{{ptf_host}}"
+
+- name: Generate start file for exabgp instances
+ template: src=roles/test/templates/exabgp/start.j2 dest={{exabgp_dir}}/{{item.file_name}} mode=u+rwx
+ with_items:
+ - {file_name: 'start.sh', config_file_1: 'config_1.ini', config_file_2: 'config_2.ini', config_file_3: 'config_3.ini', phy_ip: '{{vlan_ips[0]}}', logical_ip_1: '{{speaker_ips[0]}}', logical_ip_2: '{{speaker_ips[1]}}'}
+ delegate_to: "{{ptf_host}}"
+
+- name: Start exabgp instances
+ shell: sh {{exabgp_dir}}/start.sh
+ delegate_to: "{{ptf_host}}"
+
+- pause:
+ seconds: 5
+ prompt: "make sure dynamic bgp neighbors appear"
+
+- name: Announce the routes
+ shell: python {{helper_dir}}/announce_routes.py {{exabgp_dir}}/routes >/dev/null 2>&1 &
+ delegate_to: "{{ptf_host}}"
+
+- pause:
+ seconds: 30
+ prompt: "make sure routes announced to dynamic bgp neighbors"
+
+- name: Gather bgp facts from bgp container
+ bgp_facts:
+
+- debug: msg="{{bgp_neighbors}}"
+
+- name: Verify bgp sessions are established
+ assert: {that: "'{{ bgp_neighbors[item]['state'] }}' == 'established'"}
+ with_items: "{{ bgp_neighbors.keys() }}"
+
+- name: Verify accepted prefixes of the dynamic neighbors are correct
+ assert: {that: "'{{ bgp_neighbors[item]['accepted prefixes'] }}' == '1'"}
+ with_items: "['{{speaker_ips[0].split('/')[0]}}', '{{speaker_ips[1].split('/')[0]}}', '{{vlan_ips[0].split('/')[0]}}'] "
+
+# Send packets to verify that accepted prefixes are correctly applied in HW.
+# PTF FIB test is used to send the packets.
+
+- name: Generate route-port map information
+ template: src=roles/test/templates/bgp_speaker_route.j2
+ dest=/tmp/bgp_speaker_route.txt
+ connection: local
+
+- name: Copy the bgp_speaker_route to ptf container
+ copy: src=/tmp/bgp_speaker_route.txt dest=/root
+ delegate_to: "{{ptf_host}}"
+
+- name: Copy the test to ptf container
+ copy: src=roles/test/files/ptftests dest=/root
+ delegate_to: "{{ ptf_host }}"
+
+- set_fact: ipv4=true
+ when: addr_family == 'ipv4'
+
+- set_fact: ipv6=true
+ when: addr_family == 'ipv6'
+
+- name: "Start PTF runner"
+ include: ptf_runner.yml
+ vars:
+ ptf_test_name: FIB test
+ ptf_test_dir: ptftests
+ ptf_test_path: fib_test.FibTest
+ ptf_platform: remote
+ ptf_test_params:
+ - testbed_type='{{testbed_type}}'
+ - router_mac='{{ansible_Ethernet0['macaddress']}}'
+ - fib_info='/root/bgp_speaker_route.txt'
+ - ipv4={{ ipv4|default(false) }}
+ - ipv6={{ ipv6|default(false) }}
+ ptf_extra_options: "--relax --debug info --log-file /tmp/bgp_speaker_test.FibTest.log"
+
+- name: Deactivate IPv6 address family
+ shell: vtysh -c "conf t" -c "router bgp {{ minigraph_bgp_asn }}" -c "address-family ipv6" -c "no neighbor BGPSLBPassive activate"
+ when: addr_family == 'ipv6'
+
+- name: Kill exabgp instances
+ shell: pkill exabgp
+ delegate_to: "{{ptf_host}}"
+
+- name: Remove Assigned IPs
+ shell: ip addr flush dev eth{{ '%d' % (minigraph_vlans[minigraph_vlan_interfaces[0]['attachto']]['members'][0] | replace("Ethernet", "") | int / 4)}}
+ delegate_to: "{{ptf_host}}"
diff --git a/ansible/roles/test/tasks/copp.yml b/ansible/roles/test/tasks/copp.yml
index 83af3b8fdd1..94643bad034 100644
--- a/ansible/roles/test/tasks/copp.yml
+++ b/ansible/roles/test/tasks/copp.yml
@@ -25,14 +25,20 @@
delegate_to: "{{ ptf_host }}"
- name: copy the test to ptf container
- copy: src=roles/test/files/saitests dest=/root
+ copy: src=roles/test/files/ptftests dest=/root
delegate_to: "{{ ptf_host }}"
- - include: copp_ptf.yml
+ - include: ptf_runner.yml
vars:
- test_name: COPP test - {{ item }}
- test_path: copp_tests.{{ item }}
- test_params: ""
+ ptf_test_name: COPP test - {{ item }}
+ ptf_test_dir: ptftests
+ ptf_test_path: copp_tests.{{ item }}
+ ptf_platform: nn
+ ptf_qlen: 100000
+ ptf_test_params:
+ - verbose=False
+ - pkt_tx_count={{ pkt_tx_count|default(0) }}
+ ptf_extra_options: --device-socket 0-3@tcp://127.0.0.1:10900 --device-socket 1-3@tcp://{{ ansible_eth0['ipv4']['address'] }}:10900
with_items:
- ARPTest
- DHCPTest
diff --git a/ansible/roles/test/tasks/decap.yml b/ansible/roles/test/tasks/decap.yml
new file mode 100644
index 00000000000..bbda78ef0c0
--- /dev/null
+++ b/ansible/roles/test/tasks/decap.yml
@@ -0,0 +1,79 @@
+#-----------------------------------------
+# Run Decap test
+#-----------------------------------------
+
+- fail: msg="information about testbed missing."
+ when: (testbed_type is not defined) or
+ (dscp_mode is not defined)
+
+- fail: msg="Invalid testbed_type value '{{testbed_type}}'"
+ when: testbed_type not in [ 't1', 't0', 't1-lag']
+
+- fail: msg="Invalid testbed_type value '{{dscp_mode}}'"
+ when: dscp_mode not in [ 'pipe','uniform']
+
+- include_vars: "vars/topo_{{testbed_type}}.yml"
+
+- name: Expand properties into props
+ set_fact: props="{{configuration_properties['spine']}}"
+ when: testbed_type in ['t1', 't1-lag']
+
+- name: Expand properties into props
+ set_fact: props="{{configuration_properties['common']}}"
+ when: testbed_type in ['t0']
+
+- name: Expand properties into props
+ set_fact: props_tor="{{configuration_properties['tor']}}"
+ when: testbed_type in ['t1', 't1-lag']
+
+# Gather minigraph facts
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ become: no
+ connection: local
+
+# Obtain loopback ip of the device
+- name: Obtain loopback ip of the device
+ set_fact: lo_ip="{{ minigraph_lo_interfaces[0]['addr'] }}"
+
+- name: print loopback ip
+ debug: msg="{{ lo_ip }}"
+
+# Generate file with BGP routes information
+- template: src=roles/test/templates/fib.j2 dest=/tmp/fib_info.txt
+ connection: local
+
+# Copy the fib_info to ptf container
+- template: src=/tmp/fib_info.txt dest=/root
+ connection: local
+ delegate_to: "{{ ptf_host }}"
+
+- set_fact:
+ testname: decap
+
+# Separate set_fact is required to be able to use 'testname' fact.
+- set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
+
+- debug: msg="generated run id:{{testname_unique}}"
+
+- debug : msg="INVOKE DECAP TEST"
+
+- name: copy the test to ptf container
+ copy: src=roles/test/files/ptftests dest=/root
+ delegate_to: "{{ ptf_host }}"
+
+- name: "Running test {{ testname }}"
+ include: ptf_runner.yml
+ vars:
+ ptf_test_name: '{{ testname_unique }}'
+ ptf_test_dir: ptftests
+ ptf_test_path: IP_decap_test.DecapPacketTest
+ ptf_platform: remote
+ ptf_test_params:
+ - testbed_type='{{ testbed_type }}'
+ - fib_info='/root/fib_info.txt'
+ - router_mac='{{ansible_Ethernet0['macaddress']}}'
+ - dscp_mode='{{ dscp_mode }}'
+ - lo_ip='{{ lo_ip }}'
+ ptf_extra_options: "--relax --debug info --log-file /tmp/{{ testname_unique }}.log "
diff --git a/ansible/roles/test/tasks/deinit_config_test.yml b/ansible/roles/test/tasks/deinit_config_test.yml
new file mode 100644
index 00000000000..df8ced567fc
--- /dev/null
+++ b/ansible/roles/test/tasks/deinit_config_test.yml
@@ -0,0 +1,9 @@
+- name: Remove all the temporary files created by the test.
+ file: path="{{ run_dir }}/{{ item }}" state=absent
+ with_items:
+ - "{{ config_files }}"
+
+- name: Remove all JSON configs from docker container filesystem.
+ command: docker exec swss rm {{ docker_testdir }}/{{ item }}
+ with_items:
+ - "{{ config_files }}"
diff --git a/ansible/roles/test/tasks/dhcp_relay.yml b/ansible/roles/test/tasks/dhcp_relay.yml
new file mode 100644
index 00000000000..01efb517acf
--- /dev/null
+++ b/ansible/roles/test/tasks/dhcp_relay.yml
@@ -0,0 +1,48 @@
+# We choose client port index to be index of first port on Vlan
+- name: Obtain client interface alias
+ set_fact:
+ client_iface_alias: "{{ minigraph_map_sonic_to_ngs[minigraph_vlans[minigraph_vlans.keys()[0]]['members'][0]] }}"
+
+- name: Obtain client port index
+ set_fact:
+ client_port_index: "{{ minigraph_port_indices[client_iface_alias] }}"
+
+- name: Obtain leaf port indices
+ set_fact:
+ leaf_port_indices: []
+
+- set_fact:
+ leaf_port_indices: "{{ leaf_port_indices }} + [ {{ minigraph_port_indices[item.key] }} ]"
+ with_dict: "{{ minigraph_neighbors }}"
+ when: minigraph_devices[item.value.name] is defined and minigraph_devices[item.value.name]['type'] == "LeafRouter"
+
+- name: Obtain MAC address of {{ minigraph_vlan_interfaces[0]['attachto'] }} interface
+ become: true
+ shell: "cat /sys/class/net/{{ minigraph_vlan_interfaces[0]['attachto'] }}/address"
+ register: result
+
+- set_fact:
+ relay_iface_mac: "{{ result.stdout | from_yaml }}"
+
+- name: Copy tests to the PTF container
+ copy: src=roles/test/files/ptftests dest=/root
+ delegate_to: "{{ ptf_host }}"
+
+# Run the DHCP relay PTF test
+- include: ptf_runner.yml
+ vars:
+ ptf_test_name: DHCP Relay Test
+ ptf_test_dir: ptftests
+ ptf_test_path: dhcp_relay_test.DHCPTest
+ ptf_platform: remote
+ ptf_test_params:
+ - hostname=\"{{ inventory_hostname }}\"
+ - client_port_index=\"{{ client_port_index }}\"
+ - client_iface_alias=\"{{ client_iface_alias }}\"
+ - leaf_port_indices=\"{{ leaf_port_indices }}\"
+ - num_dhcp_servers=\"{{ dhcp_servers | length }}\"
+ - server_ip=\"{{ dhcp_servers[0] }}\"
+ - relay_iface_ip=\"{{ minigraph_vlan_interfaces[0]['addr'] }}\"
+ - relay_iface_mac=\"{{ relay_iface_mac }}\"
+ - relay_iface_netmask=\"{{ minigraph_vlan_interfaces[0]['mask'] }}\"
+
diff --git a/ansible/roles/test/tasks/ecmp.yml b/ansible/roles/test/tasks/ecmp.yml
index 930adc26b92..9af35579c11 100644
--- a/ansible/roles/test/tasks/ecmp.yml
+++ b/ansible/roles/test/tasks/ecmp.yml
@@ -1,27 +1,4 @@
- block:
- - name: Ensure LLDP Daemon stopped
- become: yes
- supervisorctl: state=stopped name={{ item }}
- vars:
- ansible_shell_type: docker
- ansible_python_interpreter: docker exec -i lldp python
- with_items:
- - lldp-syncd
- - lldpd
-
- - name: Disable bgpd
- become: yes
- lineinfile: dest=/etc/quagga/daemons
- regexp=^bgpd=.*$
- line='bgpd=no'
- notify:
- - Restart Quagga Daemon
- vars:
- ansible_shell_type: docker
- ansible_python_interpreter: docker exec -i bgp python
-
- - meta: flush_handlers
-
- fail: msg="Please set ptf_host variable"
when: ptf_host is not defined
@@ -60,7 +37,7 @@
debug: var=out.stdout_lines
- name: copy the test to ptf container
- copy: src=roles/test/files/saitests dest=/root
+ copy: src=roles/test/files/ptftests dest=/root
delegate_to: "{{ ptf_host }}"
- name: Install routes on the switch
@@ -92,12 +69,18 @@
- name: Output of the arp table on target host {{ ansible_host }}
debug: var=out.stdout_lines
- - include: qos_sai_ptf.yml
+ - include: ptf_runner.yml
vars:
- test_name: ECMP test
- test_path: ecmp_test.ECMPtest
- test_params: ""
- extra_options: "--relax --log-dir /tmp/"
+ ptf_test_name: ECMP test
+ ptf_test_dir: ptftests
+ ptf_test_path: ecmp_test.ECMPtest
+ ptf_platform: remote
+ ptf_test_params:
+ - verbose=True
+ - server='{{ ansible_host }}'
+ - port_map_file='/root/{{ ptf_portmap | basename }}'
+ - router_mac='{{ ansible_Ethernet0['macaddress'] }}'
+ ptf_extra_options: "--relax --log-dir /tmp/"
always:
- name: Remove routes from the switch
@@ -106,26 +89,3 @@
- name: Remove existing ip from ptf host
script: roles/test/files/helpers/remove_ip.sh
delegate_to: "{{ ptf_host }}"
-
- - name: Restore LLDP Daemon
- become: yes
- supervisorctl: state=started name={{ item }}
- vars:
- ansible_shell_type: docker
- ansible_python_interpreter: docker exec -i lldp python
- with_items:
- - lldpd
- - lldp-syncd
-
- - name: Enable bgpd
- become: yes
- lineinfile: dest=/etc/quagga/daemons
- regexp=^bgpd=.*$
- line='bgpd=yes'
- notify:
- - Restart Quagga Daemon
- vars:
- ansible_shell_type: docker
- ansible_python_interpreter: docker exec -i bgp python
-
- - meta: flush_handlers
diff --git a/ansible/roles/test/tasks/everflow.yml b/ansible/roles/test/tasks/everflow.yml
new file mode 100644
index 00000000000..14d6faa0d57
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow.yml
@@ -0,0 +1,29 @@
+#-----------------------------------------
+# Run all the everflow tests.
+#-----------------------------------------
+
+- set_fact:
+ run_dir: /home/admin/everflow_tests
+ out_dir: /home/admin/everflow_tests/results
+ docker_testdir: /tmp
+ tests_location: roles/test/tasks/everflow
+
+- name: Create run_dir
+ file: path="{{ run_dir }}" state=directory
+
+ #****************************************#
+ # Start tests #
+ #****************************************#
+
+- block:
+ - name: Test Everflow configuration validation.
+ include: "roles/test/tasks/everflow/config_test/config_test.yml"
+
+ - name: Test Everflow session activation/deactivation logic.
+ include: "roles/test/tasks/everflow/logic_test/logic_test.yml"
+
+ always:
+ - name: General cleanup.
+ file: path="{{ item }}" state=absent
+ with_items:
+ - "{{ run_dir }}/loganalyzer.py"
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_delete.json b/ansible/roles/test/tasks/everflow/config_test/config_delete.json
new file mode 100644
index 00000000000..7bfc46df0db
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_delete.json
@@ -0,0 +1,7 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ },
+ "OP": "DEL"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_1.json
new file mode 100644
index 00000000000..debb45b1232
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "5x0",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_2.json b/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_2.json
new file mode 100644
index 00000000000..6a9979feeab
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_2.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "-1",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_3.json b/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_3.json
new file mode 100644
index 00000000000..7df5df56326
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_dscp_invalid_3.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "100",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_dst_ip_invalid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_dst_ip_invalid_1.json
new file mode 100644
index 00000000000..05edc56e26f
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_dst_ip_invalid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2222.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_1.json
new file mode 100644
index 00000000000..d01f8c401c3
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x65z58",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_2.json b/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_2.json
new file mode 100644
index 00000000000..1efcf2282aa
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_2.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "-1",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_3.json b/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_3.json
new file mode 100644
index 00000000000..521fdce89fd
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_gre_type_invalid_3.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0xffffff",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_1.json
new file mode 100644
index 00000000000..4c29795cb6c
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5o4"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_2.json b/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_2.json
new file mode 100644
index 00000000000..60f3d66455d
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_2.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "-1"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_3.json b/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_3.json
new file mode 100644
index 00000000000..15762b018ca
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_queue_invalid_3.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "1000"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_src_ip_invalid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_src_ip_invalid_1.json
new file mode 100644
index 00000000000..20f236be18f
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_src_ip_invalid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "11111.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_test.yml b/ansible/roles/test/tasks/everflow/config_test/config_test.yml
new file mode 100644
index 00000000000..1c04930ae2f
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_test.yml
@@ -0,0 +1,173 @@
+- name: Define variables for test
+ set_fact:
+ testname: config_test
+ config_files:
+ - config_src_ip_invalid_1.json
+ - config_dst_ip_invalid_1.json
+ - config_gre_type_invalid_1.json
+ - config_gre_type_invalid_2.json
+ - config_gre_type_invalid_3.json
+ - config_dscp_invalid_1.json
+ - config_dscp_invalid_2.json
+ - config_dscp_invalid_3.json
+ - config_ttl_invalid_1.json
+ - config_ttl_invalid_2.json
+ - config_ttl_invalid_3.json
+ - config_queue_invalid_1.json
+ - config_queue_invalid_2.json
+ - config_queue_invalid_3.json
+ - config_valid_1.json
+ - config_valid_2.json
+ - config_delete.json
+
+- name: Initialize config test
+ include: roles/test/tasks/init_config_test.yml
+
+- block:
+ - name: Config tests - invalid SRC IP address.
+ vars:
+ config_file: config_src_ip_invalid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid DST IP address.
+ vars:
+ config_file: config_dst_ip_invalid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid GRE type (non integer value).
+ vars:
+ config_file: config_gre_type_invalid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid GRE type (value < that min bound).
+ vars:
+ config_file: config_gre_type_invalid_2.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid GRE type (value > that min bound).
+ vars:
+ config_file: config_gre_type_invalid_3.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid DSCP (non integer value).
+ vars:
+ config_file: config_dscp_invalid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid DSCP (value < that min bound).
+ vars:
+ config_file: config_dscp_invalid_2.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid DSCP (value > that min bound).
+ vars:
+ config_file: config_dscp_invalid_3.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid TTL (non integer value).
+ vars:
+ config_file: config_ttl_invalid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid TTL (value < that min bound).
+ vars:
+ config_file: config_ttl_invalid_2.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid TTL (value > that min bound).
+ vars:
+ config_file: config_ttl_invalid_3.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid queue (non integer value).
+ vars:
+ config_file: config_queue_invalid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid queue (value < that min bound).
+ vars:
+ config_file: config_queue_invalid_2.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - invalid queue (value > that max bound).
+ vars:
+ config_file: config_queue_invalid_3.json
+ test_expect_file: config_test_expect_file
+ errors_expected: true
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - valid config (all integers are in 10 base).
+ vars:
+ config_file: config_valid_1.json
+ test_expect_file: config_test_expect_file
+ errors_expected: false
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - valid config (all integers are in hex).
+ vars:
+ config_file: config_valid_2.json
+ test_expect_file: config_test_expect_file
+ errors_expected: false
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - delete configuration part 1 (apply config).
+ vars:
+ config_file: config_valid_2.json
+ test_expect_file: config_test_expect_file
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Config tests - delete configuration part 2 (delete config).
+ vars:
+ config_file: config_delete.json
+ test_expect_file: config_test_expect_file
+ errors_expected: false
+ run_cleanup: true
+ include: roles/test/tasks/run_config_test.yml
+
+ always:
+ - name: Remove all the temporary files created by the test.
+ include: roles/test/tasks/deinit_config_test.yml
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_test_expect_file b/ansible/roles/test/tasks/everflow/config_test/config_test_expect_file
new file mode 100644
index 00000000000..fbfc84ffb21
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_test_expect_file
@@ -0,0 +1 @@
+r, ".*Failed to parse session .* attribute .*"
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_test_update_expect_file b/ansible/roles/test/tasks/everflow/config_test/config_test_update_expect_file
new file mode 100644
index 00000000000..747d32a4200
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_test_update_expect_file
@@ -0,0 +1 @@
+r, ".*Failed to create session. Session .* already exists"
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_1.json
new file mode 100644
index 00000000000..b0099e4dcff
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "-1is",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_2.json b/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_2.json
new file mode 100644
index 00000000000..874f71c8c9d
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_2.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "-1",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_3.json b/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_3.json
new file mode 100644
index 00000000000..b2206adf9ba
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_ttl_invalid_3.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "100000",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_valid_1.json b/ansible/roles/test/tasks/everflow/config_test/config_valid_1.json
new file mode 100644
index 00000000000..72efa94db06
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_valid_1.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "25944",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/config_test/config_valid_2.json b/ansible/roles/test/tasks/everflow/config_test/config_valid_2.json
new file mode 100644
index 00000000000..d67b744da55
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/config_test/config_valid_2.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "0x32",
+ "ttl": "0xa",
+ "queue": "0x5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/create_session_expect_file b/ansible/roles/test/tasks/everflow/create_session_expect_file
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/create_session_expect_file
@@ -0,0 +1 @@
+
diff --git a/ansible/roles/test/tasks/everflow/logic_test/config_valid.json b/ansible/roles/test/tasks/everflow/logic_test/config_valid.json
new file mode 100644
index 00000000000..72efa94db06
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/logic_test/config_valid.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:session1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "25944",
+ "dscp": "50",
+ "ttl": "10",
+ "queue": "5"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow/logic_test/create_session_expect_file b/ansible/roles/test/tasks/everflow/logic_test/create_session_expect_file
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/everflow/logic_test/logic_test.yml b/ansible/roles/test/tasks/everflow/logic_test/logic_test.yml
new file mode 100644
index 00000000000..db6c54ae436
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow/logic_test/logic_test.yml
@@ -0,0 +1,123 @@
+- name: Define variables for test
+ set_fact:
+ testname: logic_test
+ sw_if: Ethernet8
+ session_name: session1
+ session_ip_prefix_1: 2.2.2.0/24
+ session_ip_prefix_2: 2.2.2.0/30
+ config_files:
+ - config_valid.json
+
+- fail: msg="Please set sw_if variable (interface that switch is connected to host)"
+ when: sw_if is not defined
+
+- name: Initialize config test.
+ include: roles/test/tasks/init_config_test.yml
+
+- name: Get IP address of one switch interface
+ shell: ifconfig {{ sw_if }} | grep "inet addr:" | awk '{print $2}' | sed "s/addr://"
+ register: sw_if_ip
+
+- name: Print {{ sw_if }} IP address
+ debug: msg="{{ sw_if_ip }}"
+
+- name: Generate neighbor IP and MAC addresses.
+ set_fact:
+ neigh_ip: "{{ sw_if_ip.stdout.split(\".\")[:3]|join(\".\") + \".\" + (sw_if_ip.stdout.split(\".\")[3]|int + 1)|string }}"
+ neigh_mac_1: "00:11:22:33:44:55"
+ neigh_mac_2: "00:11:22:33:44:66"
+
+- name: Print neighbor IP address
+ debug: msg="{{neigh_ip}}"
+
+- block:
+ - name: Create session entry.
+ vars:
+ config_file: config_valid.json
+ test_expect_file: create_session_expect_file
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Create route with prefix that matches session DST IP and unresolved next hop.
+ command: ip route add {{ session_ip_prefix_1 }} via {{ neigh_ip }}
+
+ - name: Resolve session route.
+ command: ip neigh replace {{ neigh_ip }} lladdr {{ neigh_mac_1 }} nud permanent dev {{ sw_if }}
+
+ - name: Wait for route initialization.
+ pause:
+ seconds: 10
+
+ - name: Verify session state is active.
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" status
+ register: session_status
+ failed_when: session_status.stdout != "active"
+
+ - name: Create route with longer prefix and resolved next hop.
+ command: ip route add {{ session_ip_prefix_2 }} via {{ neigh_ip }}
+
+ - name: Wait for route initialization.
+ pause:
+ seconds: 10
+
+ - name: Verify session state is active
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" status
+ register: session_status
+ failed_when: session_status.stdout != "active"
+
+ - name: Remove route with longer prefix.
+ command: ip route del {{ session_ip_prefix_2 }}
+
+ - name: Wait for route initialization.
+ pause:
+ seconds: 10
+
+ - name: Verify session state is active
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" status
+ register: session_status
+ failed_when: session_status.stdout != "active"
+
+ - name: Change neighbor MAC address.
+ command: ip neigh replace {{ neigh_ip }} lladdr {{ neigh_mac_2 }} nud permanent dev {{ sw_if }}
+
+ - name: Wait for next hop initialization.
+ pause:
+ seconds: 10
+
+ - name: Verify session state is active
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" status
+ register: session_status
+ failed_when: session_status.stdout != "active"
+
+ - name: Remove session route
+ command: ip route del {{ session_ip_prefix_1 }}
+
+ - name: Wait for route initialization.
+ pause:
+ seconds: 10
+
+ - name: Verify session state is inactive.
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" status
+ register: session_status
+ failed_when: session_status.stdout != "inactive"
+
+ always:
+ - name: Remove session route.
+ command: ip route del {{ session_ip_prefix_1 }}
+ ignore_errors: yes
+
+ - name: Remove session route.
+ command: ip route del {{ session_ip_prefix_2 }}
+ ignore_errors: yes
+
+ - name: Remove neighbor
+ command: ip neigh del {{ neigh_ip }} dev {{ sw_if }}
+ ignore_errors: yes
+
+ - name: Clear session configuration
+ include: roles/test/tasks/run_config_cleanup.yml
+
+ - name: Remove all the temporary files created by the test.
+ include: roles/test/tasks/deinit_config_test.yml
+
diff --git a/ansible/roles/test/tasks/everflow_testbed.yml b/ansible/roles/test/tasks/everflow_testbed.yml
new file mode 100644
index 00000000000..d8299d0ef9e
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed.yml
@@ -0,0 +1,19 @@
+- name: Apply Everflow configuration.
+ include: "roles/test/tasks/everflow_testbed/apply_config.yml"
+ tags: everflow_tb_configure
+
+- name: Run Everflow tests.
+ include: "roles/test/tasks/everflow_testbed/run_test.yml"
+ vars:
+ dst_port_type: "tor"
+ tags: everflow_tb_test
+
+- name: Run Everflow tests.
+ include: "roles/test/tasks/everflow_testbed/run_test.yml"
+ vars:
+ dst_port_type: "spine"
+ tags: everflow_tb_test
+
+- name: Clear Everflow configuration.
+ include: "roles/test/tasks/everflow_testbed/del_config.yml"
+ tags: everflow_tb_cleanup
diff --git a/ansible/roles/test/tasks/everflow_testbed/apply_config.yml b/ansible/roles/test/tasks/everflow_testbed/apply_config.yml
new file mode 100644
index 00000000000..f3dded68930
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/apply_config.yml
@@ -0,0 +1,50 @@
+- set_fact:
+ run_dir: /home/admin/everflow_tests
+ out_dir: /home/admin/everflow_tests/results
+ docker_testdir: /tmp
+ tests_location: roles/test/tasks/everflow_testbed
+ testname: apply_config
+ config_files:
+ - session.json
+ - acl_table.json
+ - acl_rule_persistent.json
+
+- name: Generate json files with ACL configuration for tests
+ template: src={{ tests_location }}/{{ testname }}/acl_table.j2 dest={{ tests_location }}/{{ testname }}/acl_table.json
+ connection: local
+
+- name: Initialize config test
+ include: roles/test/tasks/init_config_test.yml
+
+- block:
+ - name: Apply Everflow session configuration.
+ vars:
+ config_file: session.json
+ test_expect_file: expect_messages.txt
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Apply Everflow ACL table configuration.
+ vars:
+ config_file: acl_table.json
+ test_expect_file: expect_messages.txt
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Apply Everflow ACL rule configuration.
+ vars:
+ config_file: acl_rule_persistent.json
+ test_expect_file: expect_messages.txt
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ always:
+ - name: Remove all the temporary files created by the test.
+ include: roles/test/tasks/deinit_config_test.yml
+
+ - name: Remove temporary files.
+ file: path={{ tests_location }}/{{ testname }}/acl_table.json state=absent
+
diff --git a/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_rule_persistent.json b/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_rule_persistent.json
new file mode 100644
index 00000000000..7dcfc5ad481
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_rule_persistent.json
@@ -0,0 +1,82 @@
+[
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_1": {
+ "priority" : "50",
+ "src_ip" : "20.0.0.10",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_2": {
+ "priority" : "50",
+ "dst_ip" : "30.0.0.10",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_3": {
+ "priority" : "50",
+ "l4_src_port" : "0x1235",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_4": {
+ "priority" : "50",
+ "l4_dst_port" : "0x1235",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_5": {
+ "priority" : "50",
+ "ether_type" : "0x1234",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_6": {
+ "priority" : "50",
+ "ip_protocol" : "0x7E",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_7": {
+ "priority" : "50",
+ "tcp_flags" : "0x12/0x12",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_8": {
+ "priority" : "50",
+ "l4_src_port_range" : "4672-4681",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_9": {
+ "priority" : "50",
+ "l4_dst_port_range" : "4672-4681",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_10": {
+ "priority" : "50",
+ "dscp" : "51",
+ "mirror_action" : "test_session_1"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_table.j2 b/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_table.j2
new file mode 100644
index 00000000000..75a863cfc9b
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_table.j2
@@ -0,0 +1,10 @@
+[
+ {
+ "ACL_TABLE:acl_table_mirror": {
+ "policy_desc" : "Everflow_ACL_table",
+ "type" : "MIRROR",
+ "ports" : "{% for ifname, v in minigraph_neighbors.iteritems() %}{{"%s" % ifname}},{% endfor %}"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_table.json b/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_table.json
new file mode 100644
index 00000000000..0728edc6f97
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/apply_config/acl_table.json
@@ -0,0 +1,10 @@
+[
+ {
+ "ACL_TABLE:acl_table_mirror": {
+ "policy_desc" : "Everflow_ACL_table",
+ "type" : "MIRROR",
+ "ports" : "Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet28,Ethernet88,Ethernet24,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet64,Ethernet60,Ethernet20,Ethernet68,"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/apply_config/expect_messages.txt b/ansible/roles/test/tasks/everflow_testbed/apply_config/expect_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/everflow_testbed/apply_config/session.json b/ansible/roles/test/tasks/everflow_testbed/apply_config/session.json
new file mode 100644
index 00000000000..0bf7c998620
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/apply_config/session.json
@@ -0,0 +1,13 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:test_session_1": {
+ "src_ip": "1.1.1.1",
+ "dst_ip": "2.2.2.2",
+ "gre_type": "0x6558",
+ "dscp": "50",
+ "ttl": "64",
+ "queue": "0"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/del_config.yml b/ansible/roles/test/tasks/everflow_testbed/del_config.yml
new file mode 100644
index 00000000000..72d7d7042a2
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/del_config.yml
@@ -0,0 +1,42 @@
+- set_fact:
+ run_dir: /home/admin/everflow_tests
+ out_dir: /home/admin/everflow_tests/results
+ docker_testdir: /tmp
+ tests_location: roles/test/tasks/everflow_testbed
+ testname: del_config
+ config_files:
+ - session.json
+ - acl_table.json
+ - acl_rule_persistent.json
+
+- name: Initialize config test
+ include: roles/test/tasks/init_config_test.yml
+
+- block:
+ - name: Delete Everflow session configuration.
+ vars:
+ config_file: acl_rule_persistent.json
+ test_expect_file: expect_messages.txt
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Delete Everflow ACL table configuration.
+ vars:
+ config_file: acl_table.json
+ test_expect_file: expect_messages.txt
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ - name: Delete Everflow ACL rule configuration.
+ vars:
+ config_file: session.json
+ test_expect_file: expect_messages.txt
+ errors_expected: false
+ run_cleanup: false
+ include: roles/test/tasks/run_config_test.yml
+
+ always:
+ - name: Remove all the temporary files created by the test.
+ include: roles/test/tasks/deinit_config_test.yml
\ No newline at end of file
diff --git a/ansible/roles/test/tasks/everflow_testbed/del_config/acl_rule_persistent.json b/ansible/roles/test/tasks/everflow_testbed/del_config/acl_rule_persistent.json
new file mode 100644
index 00000000000..686d1969dc9
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/del_config/acl_rule_persistent.json
@@ -0,0 +1,52 @@
+[
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_1": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_2": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_3": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_4": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_5": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_6": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_7": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_8": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_9": {
+ },
+ "OP": "DEL"
+ },
+ {
+ "ACL_RULE_TABLE:acl_table_mirror:rule_10": {
+ },
+ "OP": "DEL"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/del_config/acl_table.json b/ansible/roles/test/tasks/everflow_testbed/del_config/acl_table.json
new file mode 100644
index 00000000000..64620d673db
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/del_config/acl_table.json
@@ -0,0 +1,7 @@
+[
+ {
+ "ACL_TABLE:acl_table_mirror": {
+ },
+ "OP": "DEL"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/del_config/expect_messages.txt b/ansible/roles/test/tasks/everflow_testbed/del_config/expect_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/everflow_testbed/del_config/session.json b/ansible/roles/test/tasks/everflow_testbed/del_config/session.json
new file mode 100644
index 00000000000..396ac97f413
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/del_config/session.json
@@ -0,0 +1,7 @@
+[
+ {
+ "MIRROR_SESSION_TABLE:test_session_1": {
+ },
+ "OP": "DEL"
+ }
+]
diff --git a/ansible/roles/test/tasks/everflow_testbed/expect_messages.txt b/ansible/roles/test/tasks/everflow_testbed/expect_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/everflow_testbed/get_neighbor_info.yml b/ansible/roles/test/tasks/everflow_testbed/get_neighbor_info.yml
new file mode 100644
index 00000000000..8c77854f7f4
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/get_neighbor_info.yml
@@ -0,0 +1,55 @@
+- name: Get DST port 1 info.
+ set_fact:
+ neighbor_info_1: "{{ item }}"
+ with_items: "{{ minigraph_bgp }}"
+ when: item['name'] == minigraph_neighbors[dst_port_1]['name'] and item['addr']|ipv4
+
+- name: Get neighbor 1 MAC address.
+ shell: ip neigh show {{ neighbor_info_1['addr'] }} | awk -F' ' '{print $5}'
+ register: neighbor_mac_info_1
+
+- name: Initialize neighbor_mac_1 variable.
+ set_fact:
+ neighbor_mac_1: "{{ neighbor_mac_info_1.stdout }}"
+
+- name: neighbor 1 info.
+ debug: msg="{{neighbor_info_1}}"
+
+- name: Get DST port 2 info.
+ set_fact:
+ neighbor_info_2: "{{ item }}"
+ with_items: "{{ minigraph_bgp }}"
+ when: item['name'] == minigraph_neighbors[dst_port_2]['name'] and item['addr']|ipv4
+
+- name: Get neighbor 2 MAC address.
+ shell: ip neigh show {{ neighbor_info_2['addr'] }} | awk -F' ' '{print $5}'
+ register: neighbor_mac_info_2
+
+- name: Initialize neighbor_mac_2 variable.
+ set_fact:
+ neighbor_mac_2: "{{ neighbor_mac_info_2.stdout }}"
+
+- name: neighbor 2 info.
+ debug: msg="{{neighbor_info_2}}"
+
+- name: Get DST port 3 info.
+ set_fact:
+ neighbor_info_3: "{{ item }}"
+ with_items: "{{ minigraph_bgp }}"
+ when: item['name'] == minigraph_neighbors[dst_port_3]['name'] and item['addr']|ipv4
+
+- name: Get neighbor 3 MAC address.
+ shell: ip neigh show {{ neighbor_info_3['addr'] }} | awk -F' ' '{print $5}'
+ register: neighbor_mac_info_3
+
+- name: Initialize neighbor_mac_3 variable.
+ set_fact:
+ neighbor_mac_3: "{{ neighbor_mac_info_3.stdout }}"
+
+- name: neighbor 3 info.
+ debug: msg="{{neighbor_info_3}}"
+
+- name: Define unresolved_nexthop variable
+ set_fact:
+ unresolved_nexthop: "20.20.20.100"
+ unresolved_nexthop_prefix: "20.20.20.0/24"
diff --git a/ansible/roles/test/tasks/everflow_testbed/get_port_info.yml b/ansible/roles/test/tasks/everflow_testbed/get_port_info.yml
new file mode 100644
index 00000000000..bfd739ed6be
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/get_port_info.yml
@@ -0,0 +1,160 @@
+- fail: msg="Destination port type is not defined"
+ when: dst_port_type not in ['tor', 'spine']
+
+- name: Init variables.
+ set_fact:
+ tor_ports: []
+ spine_ports: []
+ dst_port_1_is_lag_member: ""
+ dst_port_1_ptf_id: ""
+ dst_port_2: ""
+ dst_port_2_is_lag_member: ""
+ dst_port_2_ptf_id: ""
+ dst_port_3: ""
+ dst_port_3_is_lag_member: ""
+ dst_port_3_ptf_id: ""
+
+- name: Get tor ports
+ set_fact:
+ tor_ports: "{{ tor_ports + [item.key] }}"
+ with_dict: "{{ minigraph_neighbors }}"
+ when: "'T0' in item.value.name"
+
+- name: Sort tor ports by name.
+ set_fact:
+ tor_port: "{{ tor_ports|sort }}"
+
+- name: Print tor ports
+ debug: msg="{{ tor_ports }}"
+
+- name: Get spine ports
+ set_fact:
+ spine_ports: "{{ spine_ports + [item.key] }}"
+ with_dict: "{{ minigraph_neighbors }}"
+ when: "'T2' in item.value.name"
+
+- name: Sort tor ports by name.
+ set_fact:
+ tor_port: "{{ spine_ports|sort }}"
+
+- name: Print spine ports
+ debug: msg="{{ spine_ports }}"
+
+- name: Define SRC port variables.
+ set_fact:
+ src_port: "{{ spine_ports[0] }}"
+ when: "dst_port_type == 'tor'"
+
+- name: Define SRC port variables.
+ set_fact:
+ src_port: "{{ tor_ports[0] }}"
+ when: "dst_port_type == 'spine'"
+
+- name: Define SRC PTF port IDs
+ set_fact:
+ src_port_ptf_id: "{{ src_port|replace(\"Ethernet\", \"\")|int / 4 }}"
+
+- name: Define port variables.
+ set_fact:
+ dst_port_1: "{{ tor_ports[1] }}"
+ when: "dst_port_type == 'tor'"
+
+- name: Define port variables.
+ set_fact:
+ dst_port_1: "{{ spine_ports[1] }}"
+ when: "dst_port_type == 'spine'"
+
+- name: Check if DST port in LAG member
+ set_fact:
+ dst_port_1_is_lag_member: "{{ item.members }}"
+ with_items: "{{ minigraph_portchannels.values() }}"
+ when: "dst_port_1 in item.members"
+
+- name: Define PTF port IDs for dst_port_1
+ set_fact:
+ dst_port_1_ptf_id: "{{ dst_port_1|replace(\"Ethernet\", \"\")|int / 4 }}"
+ when: "not dst_port_1_is_lag_member"
+
+- name: Define PTF port IDs for dst_port_1
+ set_fact:
+ dst_port_1_ptf_id: "{{ item|replace(\"Ethernet\", \"\")|int / 4 }},{{ dst_port_1_ptf_id }}"
+ with_items: "{{ dst_port_1_is_lag_member }}"
+ when: "dst_port_1_is_lag_member"
+
+- name: Define port variables.
+ set_fact:
+ dst_port_2: "{{ item }}"
+ with_items: "{{ tor_ports }}"
+ when: "(dst_port_type == 'tor') and (not dst_port_2) and (item != dst_port_1) and (item not in dst_port_1_is_lag_member)"
+
+- name: Define port variables.
+ set_fact:
+ dst_port_2: "{{ item }}"
+ with_items: "{{ spine_ports }}"
+ when: "(dst_port_type == 'spine') and (not dst_port_2) and (item != dst_port_1) and (item not in dst_port_1_is_lag_member)"
+
+- name: Check if DST port in LAG member
+ set_fact:
+ dst_port_2_is_lag_member: "{{ item.members }}"
+ with_items: "{{ minigraph_portchannels.values() }}"
+ when: "dst_port_2 in item.members"
+
+- name: Print port channels
+ debug:
+ var: dst_port_2_is_lag_member
+
+- name: Define PTF port IDs for dst_port_2
+ set_fact:
+ dst_port_2_ptf_id: "{{ dst_port_2|replace(\"Ethernet\", \"\")|int / 4 }}"
+ when: "not dst_port_2_is_lag_member"
+
+- name: Define PTF port IDs for dst_port_2
+ set_fact:
+ dst_port_2_ptf_id: "{{ item|replace(\"Ethernet\", \"\")|int / 4 }},{{ dst_port_2_ptf_id }}"
+ with_items: "{{ dst_port_2_is_lag_member }}"
+ when: "dst_port_2_is_lag_member"
+
+- name: Define port variables.
+ set_fact:
+ dst_port_3: "{{ item }}"
+ with_items: "{{ tor_ports }}"
+ when: "(dst_port_type == 'tor') and (not dst_port_3) and (item != dst_port_1) and (item != dst_port_2) and (item not in dst_port_1_is_lag_member) and (item not in dst_port_2_is_lag_member)"
+
+- name: Define port variables.
+ set_fact:
+ dst_port_3: "{{ item }}"
+ with_items: "{{ spine_ports }}"
+ when: "(dst_port_type == 'spine') and (not dst_port_3) and (item != dst_port_1) and (item != dst_port_2) and (item not in dst_port_1_is_lag_member) and (item not in dst_port_2_is_lag_member)"
+
+- name: Check if DST port in LAG member
+ set_fact:
+ dst_port_3_is_lag_member: "{{ item.members }}"
+ with_items: "{{ minigraph_portchannels.values() }}"
+ when: "dst_port_3 in item.members"
+
+- name: Print port channels
+ debug:
+ var: dst_port_3_is_lag_member
+
+- name: Define PTF port IDs for dst_port_3
+ set_fact:
+ dst_port_3_ptf_id: "{{ dst_port_3|replace(\"Ethernet\", \"\")|int / 4 }}"
+ when: "not dst_port_3_is_lag_member"
+
+- name: Define PTF port IDs for dst_port_3
+ set_fact:
+ dst_port_3_ptf_id: "{{ item|replace(\"Ethernet\", \"\")|int / 4 }},{{ dst_port_3_ptf_id }}"
+ with_items: "{{ dst_port_3_is_lag_member }}"
+ when: "dst_port_3_is_lag_member"
+
+- name: Print PTF port ID.
+ debug: msg="{{ src_port }} = {{ src_port_ptf_id }}"
+
+- name: Print PTF port ID
+ debug: msg="{{ dst_port_1 }} = {{ dst_port_1_ptf_id }}"
+
+- name: Print PTF port ID
+ debug: msg="{{ dst_port_2 }} = {{ dst_port_2_ptf_id }}"
+
+- name: Print PTF port ID
+ debug: msg="{{ dst_port_3 }} = {{ dst_port_3_ptf_id }}"
diff --git a/ansible/roles/test/tasks/everflow_testbed/get_session_info.yml b/ansible/roles/test/tasks/everflow_testbed/get_session_info.yml
new file mode 100644
index 00000000000..64bd59023e7
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/get_session_info.yml
@@ -0,0 +1,46 @@
+- name: Initialize session_name variable.
+ set_fact:
+ session_name: "test_session_1"
+
+- debug: msg="session name {{ session_name }}"
+
+- name: Get session SRC IP address.
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" src_ip
+ register: session_src_ip_info
+
+- name: Initialize session_src_ip variable.
+ set_fact:
+ session_src_ip: "{{ session_src_ip_info.stdout }}"
+
+- name: Get session DST IP address.
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" dst_ip
+ register: session_dst_ip_info
+
+- name: Initialize session_dst_ip variable.
+ set_fact:
+ session_dst_ip: "{{ session_dst_ip_info.stdout }}"
+
+- name: Get session TTL.
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" ttl
+ register: session_ttl_info
+
+- name: Initialize session_ttl variable.
+ set_fact:
+ session_ttl: "{{ session_ttl_info.stdout }}"
+
+- name: Get session DSCP.
+ shell: docker exec -i swss redis-cli HGET MIRROR_SESSION_TABLE:"{{ session_name }}" dscp
+ register: session_dscp_info
+
+- name: Initialize session_dscp variable.
+ set_fact:
+ session_dscp: "{{ session_dscp_info.stdout }}"
+
+- set_fact:
+ addr_1: "{{ session_dst_ip }}/24"
+ addr_2: "{{ session_dst_ip }}/30"
+
+- name: Initialize session prefixes.
+ set_fact:
+ session_prefix_1: "{{ addr_1|ipaddr('network') }}/{{ addr_1|ipaddr('prefix') }}"
+ session_prefix_2: "{{ addr_2|ipaddr('network') }}/{{ addr_2|ipaddr('prefix') }}"
diff --git a/ansible/roles/test/tasks/everflow_testbed/ignore_messages.txt b/ansible/roles/test/tasks/everflow_testbed/ignore_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/everflow_testbed/match_messages.txt b/ansible/roles/test/tasks/everflow_testbed/match_messages.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/ansible/roles/test/tasks/everflow_testbed/run_test.yml b/ansible/roles/test/tasks/everflow_testbed/run_test.yml
new file mode 100644
index 00000000000..a096ac42102
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/run_test.yml
@@ -0,0 +1,94 @@
+#-----------------------------------------
+# Run Everflow test and Perform log analysis.
+#-----------------------------------------
+
+- fail: msg="testbed_type is not defined."
+ when: testbed_type is not defined
+
+- fail: msg="testbed_type {{testbed_type}} is invalid."
+ when: testbed_type not in ['t1-lag', 't1']
+
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ become: no
+ connection: local
+
+- name: Print neighbors in minigraph
+ debug: msg="{{ minigraph_neighbors }}"
+
+- set_fact:
+ testname: everflow_testbed
+ run_dir: /tmp
+ out_dir: /tmp/ansible-loganalyzer-results
+ test_match_file: match_messages.txt
+ test_ignore_file: ignore_messages.txt
+ test_expect_file: expect_messages.txt
+ match_file: loganalyzer_common_match.txt
+ ignore_file: loganalyzer_common_ignore.txt
+ tests_location: "{{ 'roles/test/tasks' }}"
+
+- name: Get port info.
+ include: roles/test/tasks/everflow_testbed/get_port_info.yml
+
+- name: Get session info.
+ include: roles/test/tasks/everflow_testbed/get_session_info.yml
+
+- name: Get neighbor info.
+ include: roles/test/tasks/everflow_testbed/get_neighbor_info.yml
+
+- name: Define test unique name
+ set_fact:
+ testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
+
+- set_fact:
+ test_out_dir: "{{ out_dir }}/{{testname_unique}}"
+ match_file_list: "{{ run_dir }}/{{test_match_file}},{{ run_dir }}/{{match_file}}"
+ ignore_file_list: "{{ run_dir }}/{{test_ignore_file}},{{ run_dir }}/{{ignore_file}}"
+
+- include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
+
+- block:
+ - name: Copy the test to ptf container.
+ copy: src=roles/test/files/acstests dest=/root
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Add route to unresolved next hop.
+ shell: ip route add {{ unresolved_nexthop_prefix }} dev {{ dst_port_2 }}
+
+ - name: Run testcase 1 - Resolved route
+ include: roles/test/tasks/everflow_testbed/testcase_1.yml
+
+ - name: Run testcase 2 - Longer prefix route with resolved next hop.
+ include: roles/test/tasks/everflow_testbed/testcase_2.yml
+
+ - name: Run testcase 3 - Remove longer prefix route.
+ include: roles/test/tasks/everflow_testbed/testcase_3.yml
+
+ - name: Run testcase 4 - Change neighbor MAC address.
+ include: roles/test/tasks/everflow_testbed/testcase_4.yml
+ when: testbed_type == "t1"
+
+ - name: Run testcase 5 - Resolved ECMP route.
+ include: roles/test/tasks/everflow_testbed/testcase_5.yml
+
+ - name: Run testcase 6 - ECMP route change (add next hop).
+ include: roles/test/tasks/everflow_testbed/testcase_6.yml
+
+ - name: Run testcase 7 - ECMP route change (remove next hop used by session).
+ include: roles/test/tasks/everflow_testbed/testcase_7.yml
+
+ - name: Run testcase 8 - ECMP route change (remove next hop not used by session).
+ include: roles/test/tasks/everflow_testbed/testcase_8.yml
+
+ always:
+ - name: Remove route to unresolved next hop.
+ shell: ip route del {{ unresolved_nexthop_prefix }}
+
+ - include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
+
+ # Output content of result files to ansible console
+ - shell: cat {{ test_out_dir }}/*
+ register: out
+ - debug: var=out.stdout_lines
+
+ - include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_1.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_1.yml
new file mode 100644
index 00000000000..ae54ee2285e
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_1.yml
@@ -0,0 +1,17 @@
+# Test case 1 - Resolved route.
+# Verify that session with resolved route has active state.
+
+- name: Create route with next hop {{ dst_port_1 }}.
+ shell: ip route add {{ session_prefix_1 }} via {{ neighbor_info_1['addr'] }}
+
+- block:
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ always:
+ - name: Remove route
+ shell: ip route del {{ session_prefix_1 }}
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_2.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_2.yml
new file mode 100644
index 00000000000..e4c6089a779
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_2.yml
@@ -0,0 +1,42 @@
+# Test case 2 - Longer prefix route with resolved next hop.
+# Verify that session destination port and MAC address are changed after best match route insertion.
+
+- block:
+ - name: Create route with next hop on {{ dst_port_1 }}.
+ shell: ip route add {{ session_prefix_1 }} via {{ neighbor_info_1['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Create route with best match and unresolved next hop.
+ shell: ip route add {{ session_prefix_2 }} via {{ unresolved_nexthop }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Create route with best match prefix and resolved next hop on destination port {{ dst_port_2 }}.
+ shell: ip route change {{ session_prefix_2 }} via {{ neighbor_info_2['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ always:
+ - name: Remove route.
+ shell: ip route del {{ session_prefix_1 }}
+ ignore_errors: yes
+
+ - name: Remove best match route.
+ shell: ip route del {{ session_prefix_2 }}
+ ignore_errors: yes
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_3.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_3.yml
new file mode 100644
index 00000000000..b6dc10fdf2b
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_3.yml
@@ -0,0 +1,43 @@
+# Test case 3 - Remove longer prefix route.
+# Verify that session destination port and MAC address are changed after best match route removal.
+
+- block:
+ - name: Create route with next hop on {{ dst_port_1 }}.
+ shell: ip route add {{ session_prefix_1 }} via {{ neighbor_info_1['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Create route with best match prefix and resolved next hop {{ dst_port_2 }}.
+ shell: ip route add {{ session_prefix_2 }} via {{ neighbor_info_2['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_2}}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Remove best match route.
+ shell: ip route del {{ session_prefix_2 }}
+ ignore_errors: yes
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ always:
+ - name: Remove route.
+ shell: ip route del {{ session_prefix_1 }}
+ ignore_errors: yes
+
+ - name: Remove best match route.
+ shell: ip route del {{ session_prefix_2 }}
+ ignore_errors: yes
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_4.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_4.yml
new file mode 100644
index 00000000000..3c622c81bf6
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_4.yml
@@ -0,0 +1,35 @@
+# Test case 4 - Change neighbor MAC address.
+# Verify that session destination MAC address is changed after neighbor MAC address update.
+
+- block:
+ - name: Create route with next hop on {{ dst_port_1 }}.
+ shell: ip route add {{ session_prefix_1 }} via {{ neighbor_info_1['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";expected_dst_mac="{{ neighbor_mac_1 }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Change neighbor MAC address.
+ shell: ip neigh replace {{ neighbor_info_1['addr'] }} lladdr "00:11:22:33:44:55" nud permanent dev {{ dst_port_1 }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on destination port {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";expected_dst_mac="00:11:22:33:44:55";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ always:
+ - name: Remove neighbor MAC.
+ shell: ip neigh del {{ neighbor_info_1['addr'] }} dev {{ dst_port_1 }}
+
+ - name: Recover neighbor MAC address.
+ shell: ping {{ neighbor_info_1['addr'] }} -c3
+
+ - name: Remove route.
+ shell: ip route del {{ session_prefix_1 }}
+ ignore_errors: yes
+
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_5.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_5.yml
new file mode 100644
index 00000000000..e041284df13
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_5.yml
@@ -0,0 +1,16 @@
+# Test case 5 - Resolved ECMP route.
+
+- name: Create ECMP route with next hops on {{ dst_port_1 }} and {{ dst_port_2 }}.
+ shell: ip route add {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }}
+
+- block:
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }} or {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}, {{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ always:
+ - name: Remove route
+ shell: ip route del {{ session_prefix_1 }}
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_6.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_6.yml
new file mode 100644
index 00000000000..2b0b11d89c0
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_6.yml
@@ -0,0 +1,35 @@
+# Test case 6 - ECMP route change (add next hop).
+# Verify that insertion of additional next hop to ECMP group doesn't affects session DST MAC and port.
+
+- block:
+ - name: Create ECMP route with next hops on {{ dst_port_1 }} and {{ dst_port_2 }}.
+ shell: ip route add {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }} or {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}, {{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Add next hop on {{ dst_port_3 }} to ECMP route.
+ shell: ip route change {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }} via {{ neighbor_info_3['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }} or {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}, {{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Send traffic and verify that packets are not received on {{ dst_port_3 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_3_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+ failed_when: out.rc == 0
+
+ always:
+ - name: Remove route
+ shell: ip route del {{ session_prefix_1 }}
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_7.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_7.yml
new file mode 100644
index 00000000000..a0d545937fb
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_7.yml
@@ -0,0 +1,53 @@
+# Test case 7 - ECMP route change (remove next hop used by session).
+# Verify that removal of next hop that is not used by session doesn't cause DST port and MAC change.
+
+- block:
+ - name: Create route with next hop on {{ dst_port_1 }}.
+ shell: ip route add {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Add next hops on {{ dst_port_2 }} and {{ dst_port_3 }} to route.
+ shell: ip route change {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }} via {{ neighbor_info_3['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Send traffic and verify that packets are not received on {{ dst_port_2 }} and {{ dst_port_3 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_2_ptf_id }},{{ dst_port_3_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+ failed_when: out.rc == 0
+
+ - name: Delete next hop from ECMP route.
+ shell: ip route change {{ session_prefix_1 }} nexthop via {{ neighbor_info_2['addr'] }} via {{ neighbor_info_3['addr'] }}
+
+ - name: Send traffic and verify that packets are not received {{ dst_port_1 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+ failed_when: out.rc == 0
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_2 }} or {{ dst_port_3 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_2_ptf_id }},{{ dst_port_3_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ always:
+ - name: Remove route
+ shell: ip route del {{ session_prefix_1 }}
diff --git a/ansible/roles/test/tasks/everflow_testbed/testcase_8.yml b/ansible/roles/test/tasks/everflow_testbed/testcase_8.yml
new file mode 100644
index 00000000000..c5227326442
--- /dev/null
+++ b/ansible/roles/test/tasks/everflow_testbed/testcase_8.yml
@@ -0,0 +1,53 @@
+# Test case 8 - ECMP route change (remove next hop not used by session).
+# Verify that after removal of next hop that was used by session from ECMP route session state is active.
+
+- block:
+ - name: Create ECMP route with next hops on {{ dst_port_1 }} and {{ dst_port_2 }}.
+ shell: ip route add {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }} or {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}, {{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Add next hop to ECMP route.
+ shell: ip route change {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }} via {{ neighbor_info_3['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }} or {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}, {{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Send traffic and verify that packets are not received on {{ dst_port_3 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_3_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+ failed_when: out.rc == 0
+
+ - name: Delete next hop from ECMP route.
+ shell: ip route change {{ session_prefix_1 }} nexthop via {{ neighbor_info_1['addr'] }} via {{ neighbor_info_2['addr'] }}
+
+ - name: Send traffic and verify that packets with correct Everflow header are received on {{ dst_port_1 }} or {{ dst_port_2 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_1_ptf_id }}, {{ dst_port_2_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+
+ - name: Send traffic and verify that packets are not received on {{ dst_port_3 }}.
+ shell: ptf --test-dir acstests everflow_tb_test.EverflowTest --platform remote -t 'hwsku="{{ sonic_hwsku }}";router_mac="{{ ansible_Ethernet0['macaddress'] }}";src_port="{{ src_port_ptf_id }}";dst_ports="{{ dst_port_3_ptf_id }}";session_src_ip="{{ session_src_ip }}";session_dst_ip="{{ session_dst_ip }}";session_ttl="{{ session_ttl }}";session_dscp="{{ session_dscp }}";verbose=True'
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ register: out
+ failed_when: out.rc == 0
+
+ always:
+ - name: Remove route
+ shell: ip route del {{ session_prefix_1 }}
diff --git a/ansible/roles/test/tasks/fast-reboot.yml b/ansible/roles/test/tasks/fast-reboot.yml
new file mode 100644
index 00000000000..2756dd56021
--- /dev/null
+++ b/ansible/roles/test/tasks/fast-reboot.yml
@@ -0,0 +1,121 @@
+# example:
+# ansible-playbook sonic-test.yml -i str --limit device_1 --become --vault-password-file ~/password --tags fast_reboot -e "ptf_host=10.0.0.21" -e "vm_hosts=['10.0.0.200','10.0.0.201','10.0.0.202','10.0.0.203']"
+
+- block:
+ - fail: msg="Please set ptf_host variable"
+ when: ptf_host is not defined
+
+ - fail: msg="Please set vm_hosts variable with a list of VMs"
+ when: vm_hosts is not defined
+
+ - name: Remove existing ip from ptf host
+ script: roles/test/files/helpers/remove_ip.sh
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Make all mac addresses in ptf unique - should be done in vm_set
+ script: roles/test/files/helpers/change_mac.sh
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Copy tests to the PTF container
+ copy: src=roles/test/files/ptftests dest=/root
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Copy arp responder to the PTF container
+ copy: src=roles/test/files/helpers/arp_responder.py dest=/opt
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Copy arp responder supervisor configuration to the PTF container
+ template: src=arp_responder.conf.j2 dest=/etc/supervisor/conf.d/arp_responder.conf
+ vars:
+ - arp_responder_args: '-e'
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Reread supervisor configuration
+ shell: /usr/bin/supervisorctl reread
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Update supervisor configuration
+ shell: /usr/bin/supervisorctl update
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Remove old keys
+ file:
+ path: "{{ item }}"
+ state: absent
+ with_items:
+ - /root/.ssh/id_rsa
+ - /root/.ssh/id_rsa.pub
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Check that file /root/.ssh/known_hosts exists
+ stat: path=/etc/shorewall/rules
+ delegate_to: "{{ ptf_host }}"
+ register: known_hosts
+
+ - name: Remove old entry about DUT
+ shell: ssh-keygen -f /root/.ssh/known_hosts -R {{ ansible_host }}
+ delegate_to: "{{ ptf_host }}"
+ when: known_hosts.stat.exists
+
+ - name: Generate public key for ptf host
+ shell: ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N ""
+ args:
+ creates: /root/.ssh/id_rsa
+ delegate_to: "{{ ptf_host }}"
+
+ - name: read authorized key from ptf host
+ fetch:
+ src: '/root/.ssh/id_rsa.pub'
+ dest: /tmp/
+ flat: yes
+ delegate_to: "{{ ptf_host }}"
+
+ - name: set authorized key took from file
+ authorized_key:
+ user: "{{ ansible_ssh_user }}"
+ state: present
+ key: "{{ lookup('file', '/tmp/id_rsa.pub') }}"
+
+ - name: Copy portchannels to ptf host
+ copy:
+ content: "{{ minigraph_portchannels | to_nice_json }}"
+ dest: /tmp/portchannel_interfaces.json
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Copy vlan_interfaces to ptf host
+ copy:
+ content: "{{ minigraph_vlans | to_nice_json }}"
+ dest: /tmp/vlan_interfaces.json
+ delegate_to: "{{ ptf_host }}"
+
+ - name: Copy minigraph_ports to ptf host
+ copy:
+ content: "{{ minigraph_port_indices | to_nice_json }}"
+ dest: /tmp/ports.json
+ delegate_to: "{{ ptf_host }}"
+
+ - include: ptf_runner.yml
+ vars:
+ ptf_test_name: Fast-reboot test
+ ptf_test_dir: ptftests
+ ptf_test_path: fast-reboot.FastReloadTest
+ ptf_platform: remote
+ ptf_qlen: 1000
+ ptf_extra_options: --platform-dir ptftests
+ ptf_test_params:
+ - verbose=False
+ - dut_username=\"{{ ansible_ssh_user }}\"
+ - dut_hostname=\"{{ ansible_host }}\"
+ - fast_reboot_limit=30
+ - portchannel_ports_file=\"/tmp/portchannel_interfaces.json\"
+ - vlan_ports_file=\"/tmp/vlan_interfaces.json\"
+ - ports_file=\"/tmp/ports.json\"
+ - dut_mac='{{ ansible_Ethernet0['macaddress'] }}'
+ - default_ip_range='192.168.0.0/16'
+ - vlan_ip_range=\"{{ minigraph_vlan_interfaces[0]['subnet'] }}\"
+ - arista_vms=\"{{ vm_hosts }}\"
+
+ always:
+ - name: Remove existing ip from ptf host
+ script: roles/test/files/helpers/remove_ip.sh
+ delegate_to: "{{ ptf_host }}"
diff --git a/ansible/roles/test/tasks/fdb.yml b/ansible/roles/test/tasks/fdb.yml
new file mode 100644
index 00000000000..b6fec757057
--- /dev/null
+++ b/ansible/roles/test/tasks/fdb.yml
@@ -0,0 +1,68 @@
+- fail: msg="testbed_type is not defined"
+ when: testbed_type is not defined
+
+- fail: msg="testbed_type {{test_type}} is invalid"
+ when: testbed_type not in ['t0']
+
+- include_vars: "vars/topo_{{testbed_type}}.yml"
+
+- name: Expand properties into props
+ set_fact: props="{{configuration_properties['common']}}"
+ when: testbed_type in ['t0']
+
+- name: Gather minigraph facts about the device
+ minigraph_facts: host={{inventory_hostname}}
+ connection: local
+
+- name: Remove existing IPs from PTF host
+ script: roles/test/files/helpers/remove_ip.sh
+ delegate_to: "{{ptf_host}}"
+
+- name: Set unique MACs to PTF interfaces
+ script: roles/test/files/helpers/change_mac.sh
+ delegate_to: "{{ptf_host}}"
+
+- name: Copy tests to PTF
+ copy: src=roles/test/files/ptftests dest=/root
+ delegate_to: "{{ptf_host}}"
+
+- name: Copy ARP responder to PTF
+ copy: src=roles/test/files/helpers/arp_responder.py dest=/opt
+ delegate_to: "{{ptf_host}}"
+
+- name: Copy arp responder supervisor configuration to the PTF container
+ template: src=arp_responder.conf.j2 dest=/etc/supervisor/conf.d/arp_responder.conf
+ vars:
+ - arp_responder_args: ''
+ delegate_to: "{{ ptf_host }}"
+
+- name: Copy ARP responder supervisor configuration to PTF
+ copy: src=roles/test/files/supervisor/arp_responder.conf dest=/etc/supervisor/conf.d
+ delegate_to: "{{ptf_host}}"
+
+- name: Reread supervisor configuration
+ shell: /usr/bin/supervisorctl reread
+ delegate_to: "{{ptf_host}}"
+
+- name: Update supervisor configuration
+ shell: /usr/bin/supervisorctl update
+ delegate_to: "{{ ptf_host }}"
+
+- name: Copy FDB information file to PTF
+ template: src=roles/test/templates/fdb.j2 dest=/root/fdb_info.txt
+ delegate_to: "{{ ptf_host }}"
+
+- name: "Start PTF runner"
+ include: ptf_runner.yml
+ vars:
+ ptf_test_name: FDB test
+ ptf_test_dir: ptftests
+ ptf_test_path: fdb_test.FdbTest
+ ptf_platform: remote
+ ptf_test_params:
+ - testbed_type='{{testbed_type}}'
+ - router_mac='{{ansible_Ethernet0['macaddress']}}'
+ - fdb_info='/root/fdb_info.txt'
+ - vlan_ip='{{minigraph_vlan_interfaces[0]['addr']}}'
+ ptf_extra_options: "--relax --debug info --log-file /tmp/fdb_test.FdbTest.{{ansible_date_time.iso8601}}.log "
+
diff --git a/ansible/roles/test/tasks/fib.yml b/ansible/roles/test/tasks/fib.yml
index 4aba8bf8402..9a162304641 100644
--- a/ansible/roles/test/tasks/fib.yml
+++ b/ansible/roles/test/tasks/fib.yml
@@ -2,86 +2,64 @@
# Run FIB test and Perform log analysis.
#-----------------------------------------
-- fail: msg="information about testbed missing."
+# Pre-check testbed_type value
+- fail: msg="testbed_type is not defined."
when: testbed_type is not defined
-- fail: msg="Invalid testbed_type value '{{testbed_type}}'"
- when: testbed_type not in ['lag', 'fib']
+- fail: msg="testbed_type {{testbed_type}} is invalid."
+ when: testbed_type not in ['t1-lag', 't1', 't0']
-# Gather minigraph facts
-- name: Gathering minigraph facts about the device
- minigraph_facts: host={{ inventory_hostname }}
- become: no
- connection: local
+- include_vars: "vars/topo_{{testbed_type}}.yml"
-- name: Print neighbors in minigraph
- debug: msg="{{ minigraph_neighbors }}"
+- name: Expand properties into props
+ set_fact: props="{{configuration_properties['spine']}}"
+ when: testbed_type in ['t1', 't1-lag']
-- name: Read port reverse alias mapping
- set_fact:
- alias_reverse_map: "{{ lookup('file', 'roles/sonicv2/files/ssw/{{ sonic_hwsku }}/alias_reverse_map.json') | from_json }}"
+- name: Expand properties into props
+ set_fact: props="{{configuration_properties['common']}}"
+ when: testbed_type in ['t0']
-- name: Print alias reverse mapping
- debug: msg="{{ alias_reverse_map }}"
+- name: Expand ToR properties into props
+ set_fact: props_tor="{{configuration_properties['tor']}}"
+ when: testbed_type in ['t1', 't1-lag']
-# Generate file with BGP routes information
-- template: src=fib.j2 dest=/tmp/fib.txt
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
connection: local
-- name: Copy route into file to the PTF host
- copy: src="/tmp/fib.txt" dest="/tmp/route_info.txt"
- delegate_to: "{{ ptf_host }}"
-
-- set_fact:
- testname: fib
- run_dir: /tmp
- out_dir: /tmp/ansible-loganalyzer-results
- test_match_file: fib_match_messages.txt
- test_ignore_file: fib_ignore_messages.txt
- test_expect_file: fib_expect_messages.txt
- match_file: loganalyzer_common_match.txt
- ignore_file: loganalyzer_common_ignore.txt
- tests_location: "{{ 'roles/test/tasks' }}"
-
-# Separate set_fact is required to be able to use 'testname' fact.
-- set_fact:
- testname_unique: "{{ testname }}.{{ ansible_date_time.date}}.{{ ansible_date_time.hour}}-{{ ansible_date_time.minute}}-{{ ansible_date_time.second}}"
-
-# Separate set_fact is required to be able to use 'testname_unique' fact.
-- set_fact:
- test_out_dir: "{{ out_dir }}/{{testname_unique}}"
- match_file_list: "{{ run_dir }}/{{test_match_file}},{{ run_dir }}/{{match_file}}"
- ignore_file_list: "{{ run_dir }}/{{test_ignore_file}},{{ run_dir }}/{{ignore_file}}"
-
-- debug: msg="output directory for current test run {{ test_out_dir }}"
-- debug: msg="generated run id:{{testname_unique}}"
-
-- include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
-
-- debug : msg="INVOKE FIB TEST"
-
-- block:
+# Generate route file
+- name: Generate route-port map information
+ template: src=roles/test/templates/fib.j2
+ dest=/tmp/fib_info.txt
+ connection: local
- - name: copy the test to ptf container
- copy: src=roles/test/files/acstests dest=/root
- delegate_to: "{{ ptf_host }}"
+- name: copy the fib_info to ptf container
+ copy: src=/tmp/fib_info.txt dest=/root
+ delegate_to: "{{ptf_host}}"
- - name: "Running test {{ testname }}"
- shell: ptf --test-dir acstests fib_test.FibTest --platform remote -t "verbose=True;router_mac='{{ ansible_Ethernet0['macaddress'] }}';route_info='/tmp/route_info.txt'"
- args:
- chdir: /root
- delegate_to: "{{ ptf_host }}"
- register: out
-
- - debug: var=out.stdout_lines
- when: out.rc != 0
+- debug : msg="Start FIB Test"
- always:
- - include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
+- name: copy the test to ptf container
+ copy: src=roles/test/files/ptftests dest=/root
+ delegate_to: "{{ ptf_host }}"
- # Output content of result files to ansible console
- - shell: cat {{ test_out_dir }}/*
- register: out
- - debug: var=out.stdout_lines
-
- - include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml
\ No newline at end of file
+- set_fact: ipv4=true
+ when: ipv4 is not defined
+
+- set_fact: ipv6=true
+ when: ipv6 is not defined
+
+- name: "Start PTF runner"
+ include: ptf_runner.yml
+ vars:
+ ptf_test_name: FIB test
+ ptf_test_dir: ptftests
+ ptf_test_path: fib_test.FibTest
+ ptf_platform: remote
+ ptf_test_params:
+ - testbed_type='{{testbed_type}}'
+ - router_mac='{{ansible_Ethernet0['macaddress']}}'
+ - fib_info='/root/fib_info.txt'
+ - ipv4={{ipv4}}
+ - ipv6={{ipv6}}
+ ptf_extra_options: "--relax --debug info --log-file /tmp/fib_test.FibTest.ipv4.{{ipv4}}.ipv6.{{ipv6}}.{{ansible_date_time.iso8601}}.log "
diff --git a/ansible/roles/test/tasks/init_config_test.yml b/ansible/roles/test/tasks/init_config_test.yml
new file mode 100644
index 00000000000..c0c12db9bb7
--- /dev/null
+++ b/ansible/roles/test/tasks/init_config_test.yml
@@ -0,0 +1,12 @@
+- name: Create run_dir
+ file: path="{{ run_dir }}" state=directory
+
+- name: Copy JSON configs onto switch.
+ copy: src={{ tests_location }}/{{ testname }}/{{ item }} dest={{ run_dir }}/{{ item }}
+ with_items:
+ - "{{ config_files }}"
+
+- name: Copy JSON configs from switch into docker filesystem.
+ command: docker cp {{ run_dir }}/{{ item }} swss:{{ docker_testdir }}/{{ item }}
+ with_items:
+ - "{{ config_files }}"
diff --git a/ansible/roles/test/tasks/interface.yml b/ansible/roles/test/tasks/interface.yml
index c6b56e6a05d..85c557e6934 100644
--- a/ansible/roles/test/tasks/interface.yml
+++ b/ansible/roles/test/tasks/interface.yml
@@ -3,5 +3,12 @@
- name: Verify interfaces are up correctly
assert: { that: "'{{ ansible_interface_facts[item]['active'] }}' == 'True'" }
- with_items: minigraph_interfaces | map(attribute='alias') | list
+ with_items: "{{ minigraph_ports }}"
+- name: Verify port channel interfaces are up correctly
+ assert: { that: "'{{ ansible_interface_facts[item]['active'] }}' == 'True'" }
+ with_items: "{{ minigraph_portchannels.keys() }}"
+
+- name: Verify VLAN interfaces are up correctly
+ assert: { that: "'{{ ansible_interface_facts[item]['active'] }}' == 'True'" }
+ with_items: "{{ minigraph_vlans.keys() }}"
diff --git a/ansible/roles/test/tasks/lag.yml b/ansible/roles/test/tasks/lag.yml
index 64073697300..986dd53569f 100644
--- a/ansible/roles/test/tasks/lag.yml
+++ b/ansible/roles/test/tasks/lag.yml
@@ -74,9 +74,4 @@
always:
- include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
- # Output content of result files to ansible console
- - shell: cat {{ test_out_dir }}/*
- register: out
- - debug: var=out.stdout_lines
-
- - include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml
\ No newline at end of file
+ - include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml
diff --git a/ansible/roles/test/tasks/lag_2.yml b/ansible/roles/test/tasks/lag_2.yml
new file mode 100644
index 00000000000..b3817fd17f4
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_2.yml
@@ -0,0 +1,65 @@
+### this is the Lag_2 lag test that tests each Lag interface minimum link and rate of sending LACP DU packets
+### this test could be consider as an additional/alternative lag test from existing lagall.yml.
+### Due to some labs are using two layer fanout switches, and one DUT might connects to multiple fanoutleaf switches
+### so for minimum link test of lag member flaps, it requires to use lab connection facts to determine the fanout neighbor ports,
+### Also, most of the traffic load balancing tests of LAG interface are covered in new FIB tests. so we are ignoring traffic test
+### for lag member flaps for now, will consider add traffic back if required
+
+- fail: msg="Please define ptf_host"
+ when: ptf_host is not defined
+
+- fail: msg="Please define testbed_type"
+ when: testbed_type is not defined
+
+
+- fail: msg="this test only support t1-lag and t0 testbed_type"
+ when: testbed_type not in ['t1-lag', 't0']
+
+- name: gathering lag facts from device
+ lag_facts: host={{ inventory_hostname }}
+
+- fail: msg="No lag configuration found in {{ inventory_hostname }}"
+ when: lag_facts.names == []
+
+- name: Gathering peer VM information from lldp
+ lldp:
+ vars:
+ ansible_shell_type: docker
+ ansible_python_interpreter: docker exec -i lldp python
+
+- name: gathering minigraph of the device configuration
+ minigraph_facts: host={{ inventory_hostname }}
+ connection: local
+
+- name: Gathering lab graph facts about the device
+ conn_graph_facts: host={{ inventory_hostname }}
+ connection: local
+
+- set_fact:
+ fanout_neighbors: "{{device_conn}}"
+
+- set_fact:
+ vm_neighbors: "{{ minigraph_neighbors }}"
+
+- name: Copy PTF test into PTF-docker for test LACP DU.
+ copy: src=roles/test/files/acstests/{{ item }} dest=/tmp/{{ item }}
+ with_items:
+ - lag_test.py
+ - acs_base_test.py
+ - router_utils.py
+ delegate_to: "{{ ptf_host }}"
+
+- name: Include testbed topology configuration (to get LAG IP and PTF docker interfaces, that are behind LAG VMs).
+ include_vars: vars/topo_t1-lag.yml
+ when: testbed_type == 't1-lag'
+
+- name: Include testbed topology configuration (to get LAG IP and PTF docker interfaces, that are behind LAG VMs).
+ include_vars: vars/topo_t0.yml
+ when: testbed_type == 't0'
+
+- set_fact:
+ dut_mac: "{{ ansible_Ethernet0['macaddress'] }}"
+
+- name: test each lag interface minimum links and rate
+ include: single_lag_test.yml
+ with_items: lag_facts.names
diff --git a/ansible/roles/test/tasks/lag_dut_lacp_test.yml b/ansible/roles/test/tasks/lag_dut_lacp_test.yml
new file mode 100644
index 00000000000..7447276e16d
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_dut_lacp_test.yml
@@ -0,0 +1,19 @@
+#---------------------------------------------------------
+# The following actions are to be done on DUT:
+# 1) Check LACP rate on DUT.
+# 2) Verify if it's slow and raise an error in another case.
+#---------------------------------------------------------
+
+- name: Read teamd state for {{ lag_iface }} on DUT.
+ shell: docker exec -i teamd teamdctl {{ lag_iface }} state
+ register: teamd_state
+
+- name: Verify LACP rate.
+ shell: echo {{ teamd_state.stdout_lines }} | grep "fast rate" | sed -n "s/.*fast rate. //p" | sed -n "s/]//p"
+ register: lacp_rate
+
+- debug:
+ msg="Fast-rate value is set to \'{{ lacp_rate.stdout }}\'"
+
+- fail: msg="Wrong LACP rate set for {{ lag_iface }} LAG interface; 'fast rate' is set to \'{{ lacp_rate.stdout }}\'"
+ when: lacp_rate.stdout != 'no'
diff --git a/ansible/roles/test/tasks/lag_fanout_ports_test.yml b/ansible/roles/test/tasks/lag_fanout_ports_test.yml
new file mode 100644
index 00000000000..da8a5b4c18f
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_fanout_ports_test.yml
@@ -0,0 +1,60 @@
+#---------------------------------------------------------
+# --- Part of lagall.yml test ---
+#---------------------------------------------------------
+# Shutdown LAG ports on Fanout one by one and verify traffic runs correctly.
+# ("LAG ports" stands for ports on Fanout, that are connected to DUT LAg members)
+#
+# Actions to be performed by the test:
+# 1) Get list of LAG Fanout interfaces (fanout ports that are connected to DUT LAGs).
+# 2) Shut one of those ifaces.
+# 3) Verify all the traffic goes through another LAG member on VM and no packets lost.
+#---------------------------------------------------------
+
+- include_vars: vars/lag_fanout_ports_test_vars.yml
+
+# Get fanout credentials ("passwd" and "enable" fields should be formed as a list).
+- set_fact:
+ fanout_creds:
+ user: "{{ fanout_user }}"
+ passwd:
+ - "{{ fanout_pass }}"
+ enable:
+ - "{{ fanout_pass }}"
+
+- block:
+ - name: Put down {{ portmap_dut_fn[dut_lag_member] }} on Fanout.
+ include: run_cisco_script.yml
+ vars:
+ template: roles/fanout/templates/lag_fn_ports.j2
+ host: "{{ fanout_mgmt_ip }}"
+ log_in: "{{ fanout_creds }}"
+ config_iface: "{{ portmap_dut_fn[dut_lag_member] }}"
+ state: 'shutdown'
+
+ - debug:
+ msg: "Wait for configuration to be applied..."
+
+ - pause:
+ seconds: 60
+
+ - include: lag_run_ptf.yml
+ vars:
+ lag_ptf_test_name: LagMembersTrafficTest
+ params: "dst_addr='{{ lag_ip }}';src_iface={{ not_behind_lag_iface }};check_pkts_iface={{ ifaces_behind_lag_member[iface_behind_lag_member_index] }};num_of_pkts={{ num_of_pkts }};dut_mac='{{ dut_mac }}'"
+ change_dir: /tmp
+
+ always:
+ - name: Put up {{ portmap_dut_fn[dut_lag_member] }} on Fanout.
+ include: run_cisco_script.yml
+ vars:
+ template: roles/fanout/templates/lag_fn_ports.j2
+ host: "{{ fanout_mgmt_ip }}"
+ log_in: "{{ fanout_creds }}"
+ config_iface: "{{ portmap_dut_fn[dut_lag_member] }}"
+ state: 'no shutdown'
+
+ - debug:
+ msg: "Wait for configuration to be applied..."
+
+ - pause:
+ seconds: 100
diff --git a/ansible/roles/test/tasks/lag_lacp_timing_test.yml b/ansible/roles/test/tasks/lag_lacp_timing_test.yml
new file mode 100644
index 00000000000..4b8f47d933a
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_lacp_timing_test.yml
@@ -0,0 +1,32 @@
+#--------------------------------------------------
+# --- lag_2.yml test---
+#-------------------------------------------------
+# Using PTF test framework, check the LACP packets timing
+# for each VM that has LAG configured.
+#
+# @ params: iface_behind_lag_member_0 - PTF docker iface, that receives all the packets that VM LAG member does.
+# @ params: iface_behind_lag_member_1 - PTF docker iface, that receives all the packets that VM LAG member does.
+# @ params: vm_name - VM hostname that will be printed before running test.
+#
+# Originally in lagall.yml, and lag_2.yml should cover it
+#--------------------------------------------------------
+
+- set_fact:
+ lacp_ether_type: '0x8809'
+ packet_timing: "{{ lacp_timer }}"
+ packet_timeout: 35
+
+- name: Check LACP timing on eth{{ iface_behind_lag_member_0 }} (interface behind {{ vm_name }}).
+ include: lag_run_ptf.yml
+ vars:
+ lag_ptf_test_name: LacpTimingTest
+ params: "exp_iface={{ iface_behind_lag_member_0 }}; timeout={{ packet_timeout }}; packet_timing={{ packet_timing }}; ether_type={{ lacp_ether_type }}"
+ change_dir: /tmp
+
+- name: Check LACP timing on eth{{ iface_behind_lag_member_1 }} (interface behind {{ vm_name }}).
+ include: lag_run_ptf.yml
+ vars:
+ lag_ptf_test_name: LacpTimingTest
+ params: "exp_iface={{ iface_behind_lag_member_1 }}; timeout={{ packet_timeout }}; packet_timing={{ packet_timing }}; ether_type={{ lacp_ether_type }}"
+ change_dir: /tmp
+ when: iface_behind_lab_member_1 is defined
diff --git a/ansible/roles/test/tasks/lag_minlink.yml b/ansible/roles/test/tasks/lag_minlink.yml
new file mode 100644
index 00000000000..f2c9028a0bd
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_minlink.yml
@@ -0,0 +1,57 @@
+### This playbook is part of lag_2.yml test
+### It is to test LACP LAG functionality behave correctly when link flaps.
+### In this playbook the neighbor of the selected flap_intf interface is shutdown and playbook validate Portchannel interface status and member
+### selection status are correct based on port channel min link configuration. Then bring up the remote interface to make sure
+### Port channel interface is up after peer port is back
+
+- block:
+ - name: Shut down neighbor interface {{ neighbor_interface }} on {{ peer_device }}
+ action: apswitch template=neighbor_interface_shut_single.j2
+ args:
+ host: "{{peer_host}}"
+ login: "{{switch_login[hwsku_map[peer_hwsku]]}}"
+ connection: switch
+
+ - pause:
+ seconds: "{{ wait_down_time }}"
+
+ - lag_facts: host={{ inventory_hostname }}
+
+ - name: Verify all other lag member interfaces are marked selected
+ assert: { that: "'{{ lag_facts.lags[po]['po_stats']['ports'][item]['runner']['selected'] }}' == 'True'" }
+ with_items: "{{ po_interfaces.keys() }}"
+ when: item != "{{ flap_intf }}"
+
+ - name: Verify {{ flap_intf}} lag member interfaces are marked as deselected for the shutdown port
+ assert: { that: "'{{ lag_facts.lags[po]['po_stats']['ports'][item]['runner']['selected'] }}' == 'False'" }
+ with_items: "{{ po_interfaces.keys() }}"
+ when: item == "{{ flap_intf }}"
+
+ - name: verify port-channel {{ po }} interface are marked down correctly if portchannel should down
+ assert: { that: "'{{ lag_facts.lags[po]['po_intf_stat'] }}' == 'Down' "}
+ when: po_flap == True
+
+ - name: verify port-channel {{ po }} interface are marked Up correctly if portchannel should keepup
+ assert: { that: "'{{ lag_facts.lags[po]['po_intf_stat'] }}' == 'Up' "}
+ when: po_flap != True
+
+ ### always bring back port in case test error and left testbed in unknow stage
+ always:
+ - name: Bring up neighbor interface {{ neighbor_interface }} on {{ peer_host }}
+ action: apswitch template=neighbor_interface_no_shut_single.j2
+ args:
+ host: "{{peer_host}}"
+ login: "{{switch_login[hwsku_map[peer_hwsku]]}}"
+ connection: switch
+
+ - pause:
+ seconds: 20
+
+ - lag_facts: host={{ inventory_hostname }}
+
+ - name: Verify all interfaces in port_channel are marked up
+ assert: { that: "'{{ lag_facts.lags[po]['po_stats']['ports'][item]['link']['up'] }}' == 'True'" }
+ with_items: "{{ po_interfaces.keys() }}"
+
+ - name: verify port-channel {{ po }} interface are marked up correctly
+ assert: { that: "'{{ lag_facts.lags[po]['po_intf_stat'] }}' == 'Up' "}
diff --git a/ansible/roles/test/tasks/lag_run_ptf.yml b/ansible/roles/test/tasks/lag_run_ptf.yml
new file mode 100644
index 00000000000..4dbdd87250c
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_run_ptf.yml
@@ -0,0 +1,14 @@
+#-----------------------
+# Send traffic from PTF docker and verify all the packets arrived.
+#
+# Parameters:
+# @ param: lag_ptf_test_name - name of PTf test located in lag_test.py.
+# @ param: params - parameters for the PTF test (specific for each test).
+# @ param: change_dir - directory inside of PTF docker, that contains lag_test.py.
+#-----------------------
+
+- name: Run lag_test.{{ lag_ptf_test_name }} on PTF docker.
+ shell: ptf --test-dir . --platform remote lag_test.{{ lag_ptf_test_name }} -t "{{ params }}"
+ args:
+ chdir: "{{ change_dir }}"
+ delegate_to: "{{ ptf_host }}"
diff --git a/ansible/roles/test/tasks/lag_vm_lacp_test.yml b/ansible/roles/test/tasks/lag_vm_lacp_test.yml
new file mode 100644
index 00000000000..4afb60c66fe
--- /dev/null
+++ b/ansible/roles/test/tasks/lag_vm_lacp_test.yml
@@ -0,0 +1,56 @@
+#---------------------------------------------------------
+# --- Part of lagall.yml test ---
+#---------------------------------------------------------
+# This test verifies that the LACP rate is the same on DUT and VMs.
+#
+# The following actions are to be done for each VM:
+# 1) Perform show running-config on VM.
+# 2) Parse the result by bash commands and read LACP rate.
+# 3) Verify if it's slow and raise an error in another case.
+#
+# @ params: login_creds - credentials for Arista VM
+# @ params: lag_member_0 - First LAG member on VM
+# @ params: lag_member_1 - Second LAG member on VM
+# @ params: vm_ip - Taken from lag_link_flap_vars.yml
+# @ params: vm_name
+#---------------------------------------------------------
+
+- debug:
+ msg: "VM under test is {{ vm_name }}"
+
+- set_fact:
+ expected_rate: 'normal'
+
+ # --- TEST FIRST LAG MEMBER ---
+- name: Read first LAG member configuration to learn LACP rate.
+ include: run_cisco_script.yml
+ vars:
+ template: roles/vm_set/templates/lag_lacp.j2
+ host: "{{ vm_ip }}"
+ log_in: "{{ login_creds }}"
+ show_iface: "{{ lag_member_0 }}"
+
+- name: Get LACP rate.
+ shell: echo {{ cisco_script_res }} | grep lacp | sed -n "s/.*rate //p"
+ register: lacp_rate
+
+# "normal" is default value for LACP rate on Arista VM so it may not be shown
+- fail: msg="Wrong LACP rate for {{ lag_member_0 }} on {{ vm_name }}. The rate is \'{{ lacp_rate.stdout }}\', while the expected value is \'{{ expected_rate }}\'."
+ when: lacp_rate.stdout != "{{ expected_rate }}" and lacp_rate.stdout != ""
+
+ # --- TEST SECOND LAG MEMBER ---
+- name: Read second LAG member configuration to learn LACP rate.
+ include: run_cisco_script.yml
+ vars:
+ template: roles/vm_set/templates/lag_lacp.j2
+ host: "{{ vm_ip }}"
+ log_in: "{{ login_creds }}"
+ show_iface: "{{ lag_member_1 }}"
+
+- name: Get LACP rate.
+ shell: echo {{ cisco_script_res }} | grep lacp | sed -n "s/.*rate //p"
+ register: lacp_rate
+
+# "normal" is default value for LACP rate on Arista VM so it may not be shown
+- fail: msg="Wrong LACP rate for {{ lag_member_1 }} on {{ vm_name }}. The rate is \'{{ lacp_rate.stdout }}\', while the expected value is \'{{ expected_rate }}\'."
+ when: lacp_rate.stdout != "{{ expected_rate }}" and lacp_rate.stdout != ""
diff --git a/ansible/roles/test/tasks/lagall.yml b/ansible/roles/test/tasks/lagall.yml
new file mode 100644
index 00000000000..ab08a6722f3
--- /dev/null
+++ b/ansible/roles/test/tasks/lagall.yml
@@ -0,0 +1,137 @@
+#-----------------------------------
+# File: lagall.yml
+# Author: Anton Patenko
+#-----------------------------------
+# This file runs all the LAG tests.
+#
+# In order to have info about devices to run tests it performs the list of actions:
+# 1) Reads DUT minigraph facts.
+# 2) Creates a list "dut_lag_members" of DUT LAG members, using minigraph facts.
+# 3) Reads LLDP information.
+# 4) Creates a dictionary "lag_vms" of VMs that have LAG configured, using LLDP data and DUT LAG members:
+# "VM name": [ "VM mgmt IP"]
+# 5) Gathers VM LAG interface IP and some other data about interfaces (see vars-sections in "Start tests" block).
+# 6) Runs the tests.
+#
+# Warning! This test is supposed to be ran on T1-LAG topology.
+#
+# Run command:
+# cd ansible;
+# ansible-playbook test_sonic.yml -i inventory --limit --tags lag -e "fanout_switch= ; ptf_host= ; dut_mac=" -vvvvv
+#-----------------------------------
+
+- fail: msg="Please define fanout_switch"
+ when: fanout_switch is not defined
+
+- fail: msg="Please define ptf_host"
+ when: ptf_host is not defined
+
+- fail: msg="Please define dut_mac"
+ when: dut_mac is not defined
+
+- name: Read DUT minigraph facts.
+ minigraph_facts: host={{ inventory_hostname }}
+ connection: local
+ become: no
+
+- set_fact:
+ dut_lag_members: []
+
+# item.1 - reference to list's element value
+# minigraph_portchannel_interfaces - taken from minigraph_facts
+- name: Create a list of LAG members.
+ set_fact:
+ dut_lag_members: "{{ dut_lag_members }} + [ '{{ item.1['members'][0] }}' ] + [ '{{ item.1['members'][1] }}' ]"
+ with_indexed_items: "{{ minigraph_portchannel_interfaces }}"
+
+- name: Gather information from LLDP.
+ lldp:
+ vars:
+ ansible_shell_type: docker
+ ansible_python_interpreter: docker exec -i lldp python
+
+- debug:
+ msg: "{{ dut_lag_members }}"
+
+- debug:
+ msg: "{{ lldp }}"
+
+# Create dictionary { "VM hostname" : "VM mgmt-ip" } to store info about LAG VMs;
+# "combine" filter is used for appending to the dictionary.
+- name: Get VMs that have LAG configured.
+ set_fact:
+ lag_vms: "{{ lag_vms|default({}) | combine( {lldp[item.1]['chassis']['name']: [ lldp[item.1]['chassis']['mgmt-ip'] ]} ) }}"
+ with_indexed_items: "{{ dut_lag_members }}"
+
+# Append VM LAG members to the previous dictionary.
+- name: Get LAG members for each VM.
+ set_fact:
+ lag_vms: "{{ lag_vms | combine( { lldp[item.1]['chassis']['name']: lag_vms[lldp[item.1]['chassis']['name']] | union([ lldp[item.1]['port']['ifname'] ]) }) }}"
+ with_indexed_items: "{{ dut_lag_members }}"
+
+- debug:
+ msg: "VMs that have LAG configured - {{ lag_vms.keys() }}"
+
+- name: Get credentials for Arista VMs.
+ include_vars: group_vars/str/strinfo.json
+
+- name: Add VMs information to in-memory inventory.
+ add_host: name={{ lag_vms[item][0] }} ansible_ssh_user={{ switch_login['Arista']['user'] }} ansible_ssh_pass={{ switch_login['Arista']['passwd'][0] }}
+ with_items: lag_vms.keys()
+
+#-----------------------------------
+# Start tests
+#-----------------------------------
+
+- name: Copy PTF test into PTF-docker.
+ copy: src=roles/test/files/acstests/{{ item }} dest=/tmp/{{ item }}
+ with_items:
+ - lag_test.py
+ - acs_base_test.py
+ - router_utils.py
+ delegate_to: "{{ ptf_host }}"
+
+- name: Include testbed topology configuration (to get LAG IP and PTF docker ifaces, that are behind LAG VMs).
+ include_vars: vars/topo_t1-lag.yml
+
+- name: --TEST-- LACP verification on all VMs.
+ include: lag_vm_lacp_test.yml
+ vars:
+ login_creds: "{{ switch_login['Arista'] }}"
+ lag_member_0: "{{ lag_vms[item][1] }}"
+ lag_member_1: "{{ lag_vms[item][2] }}"
+ vm_ip: "{{ lag_vms[item][0] }}"
+ vm_name: "{{ item }}"
+ with_items: lag_vms.keys()
+
+# Get a list of LAGs on DUT.
+- set_fact:
+ dut_lags: []
+
+- name: Get a list of LAGs on DUT.
+ set_fact:
+ dut_lags: "{{ dut_lags }} + [ '{{ item.1['name'] }}' ]"
+ with_indexed_items: "{{ minigraph_portchannel_interfaces }}"
+
+- name: --TEST-- LACP verification on DUT LAGs.
+ include: lag_dut_lacp_test.yml
+ vars:
+ lag_iface: "{{ dut_lags[1] }}"
+ when: dut_lags is defined
+
+- set_fact:
+ iface_behind_lag_member_index: 0
+
+- name: --TEST-- Fanout ports test.
+ include: lag_fanout_ports_test.yml
+ vars:
+ fanout_mgmt_ip: "{{ hostvars[fanout_switch]['ansible_host'] }}"
+ fanout_user: "{{ hostvars[fanout_switch]['ansible_ssh_user'] }}"
+ fanout_pass: "{{ hostvars[fanout_switch]['ansible_ssh_pass'] }}"
+ dut_mac_addr: "{{ dut_mac }}"
+ lag_ip: "{{ configuration[lldp[dut_lag_members[1]]['chassis']['name']]['interfaces']['Port-Channel1']['ipv4'] }}"
+ ifaces_behind_lag_member: "{{ topology['VMs'][lldp[dut_lag_members[1] ]['chassis']['name']]['vlans'] }}"
+ not_behind_lag_iface: 29
+ dut_lag_member: "{{ dut_lag_members[1] }}"
+ num_of_pkts: 100
+ when: dut_lag_members is defined
diff --git a/ansible/roles/test/tasks/link_flap.yml b/ansible/roles/test/tasks/link_flap.yml
index 808e1ca3e6b..69ad611761b 100644
--- a/ansible/roles/test/tasks/link_flap.yml
+++ b/ansible/roles/test/tasks/link_flap.yml
@@ -1,15 +1,14 @@
-# Shuotian Cheng
-#
-# This test is part of sswsyncd functionality tests.
-#
-# In this test, I try to iteratively shutdown and bring up physical interface
-# from the DUT spine neighbor side by controlling the underlay fan-out switch.
-# Then, I check the neighbor table to ensure certian entries are updated
-# according to the certain link flappings.
+# This is link flap test. In this test, all DUT's neighbor interfaces are
+# flapped. During each flap, the DUT's interface is verified to see if it
+# is updated to the correct up/down state.
-- name: Gathering minigraph facts about the device
- minigraph_facts: host={{ inventory_hostname }}
+- name: Gathering lab graph facts about the device
+ conn_graph_facts: host={{ inventory_hostname }}
connection: local
+ tags: always
-- include: link_entry_flap.yml
- with_items: "{{ minigraph_interfaces }}"
+- set_fact:
+ neighbors: "{{device_conn}}"
+
+- include: link_flap/link_flap_helper.yml
+ with_items: "{{ device_conn.keys() }}"
diff --git a/ansible/roles/test/tasks/link_flap/link_flap_helper.yml b/ansible/roles/test/tasks/link_flap/link_flap_helper.yml
new file mode 100644
index 00000000000..b59f54be013
--- /dev/null
+++ b/ansible/roles/test/tasks/link_flap/link_flap_helper.yml
@@ -0,0 +1,62 @@
+# This is the link_flap.yml helper playbook. link_flap.yml passes the interface
+# to this playbook and in this playbook the neighbor of this interface is
+# flapped.
+
+- block:
+ - set_fact:
+ interface: "{{item}}"
+
+ - debug: msg={{interface}}
+
+ - set_fact:
+ peer_device: "{{neighbors[interface]['peerdevice']}}"
+ neighbor_interface: "{{neighbors[interface]['peerport']}}"
+
+ - conn_graph_facts: host={{ peer_device }}
+ connection: local
+
+ - set_fact:
+ peer_host: "{{device_info['mgmtip']}}"
+ peer_hwsku: "{{device_info['HwSku']}}"
+
+ - set_fact:
+ intfs_to_exclude: "{{interface}}"
+
+ - name: Shut down neighbor interface {{neighbor_interface}} on {{peer_host}}
+ action: apswitch template=neighbor_interface_shut_single.j2
+ args:
+ host: "{{peer_host}}"
+ login: "{{switch_login[hwsku_map[peer_hwsku]]}}"
+ connection: switch
+
+ - pause:
+ seconds: 20
+
+ - interface_facts:
+
+ - name: Verify interfaces are up correctly
+ assert: { that: "'{{ ansible_interface_facts[item]['active'] }}' == 'True'" }
+ with_items: "{{ minigraph_ports }}"
+ when: item != "{{ intfs_to_exclude }}"
+
+ - name: Verify {{intfs_to_exclude}} is down correctly
+ assert: { that: "'{{ ansible_interface_facts[item]['active'] }}' == 'False'" }
+ with_items: "{{ minigraph_ports }}"
+ when: item == "{{ intfs_to_exclude }}"
+
+ always:
+ - name: Bring up neighbor interface {{neighbor_interface}} on {{peer_host}}
+ action: apswitch template=neighbor_interface_no_shut_single.j2
+ args:
+ host: "{{peer_host}}"
+ login: "{{switch_login[hwsku_map[peer_hwsku]]}}"
+ connection: switch
+
+ - pause:
+ seconds: 20
+
+ - interface_facts:
+
+ - name: Verify all interfaces are up
+ assert: { that: "'{{ ansible_interface_facts[item]['active'] }}' == 'True'" }
+ with_items: "{{ minigraph_ports }}"
diff --git a/ansible/roles/test/tasks/lldp.yml b/ansible/roles/test/tasks/lldp.yml
index 65078c9f926..2fa65c56a67 100644
--- a/ansible/roles/test/tasks/lldp.yml
+++ b/ansible/roles/test/tasks/lldp.yml
@@ -19,21 +19,18 @@
- name: Verify LLDP information is available on most interfaces
assert: { that: "{{ lldp|length }} > {{ minigraph_neighbors|length * 0.8 }}"}
-- name: Read port alias mapping
- set_fact:
- alias_map: "{{ lookup('file', 'roles/sonicv2/files/ssw/{{ sonic_hwsku }}/alias_map.json') | from_json }}"
-
- name: Compare the lldp neighbors name with minigraph neigbhors name (exclude the management port)
- assert: { that: "'{{ lldp[item]['chassis']['name'] }}' == '{{ minigraph_neighbors[alias_map[item]]['name'] }}'" }
- with_items: lldp.keys()
+ assert: { that: "'{{ lldp[item]['chassis']['name'] }}' == '{{ minigraph_neighbors[item]['name'] }}'" }
+ with_items: "{{ lldp.keys() }}"
when: item != "eth0"
- name: Compare the lldp neighbors interface with minigraph neigbhor interface (exclude the management port)
- assert: { that: "'{{ lldp[item]['port']['ifname'] }}' == '{{ minigraph_neighbors[alias_map[item]]['port'] }}'" }
- with_items: lldp.keys()
+ assert: { that: "'{{ lldp[item]['port']['ifname'] }}' == '{{ minigraph_neighbors[item]['port'] }}'" }
+ with_items: "{{ lldp.keys() }}"
when: item != "eth0"
- name: Iterate throguh each lldp neighbor and verify the information received by neighbor are also correct
- add_host: name={{ lldp[item]['chassis']['mgmt-ip'] }} groups=lldp_neighbors neighbor_interface={{lldp[item]['port']['ifname']}} dut_interface={{item}} hname={{lldp[item]['chassis']['mgmt-ip'] }} snmp_rocommunity={{ snmp_rocommunity }}
- with_items: lldp.keys()
+ add_host: name={{ lldp[item]['chassis']['mgmt-ip'] }} groups=lldp_neighbors,eos neighbor_interface={{lldp[item]['port']['ifname']}} dut_interface={{item}} hname={{lldp[item]['chassis']['mgmt-ip'] }}
+ with_items: "{{ lldp.keys() }}"
when: item != "eth0"
+
diff --git a/ansible/roles/test/tasks/lldp_neighbor.yml b/ansible/roles/test/tasks/lldp_neighbor.yml
index 87bf48e887d..ca82165ac34 100644
--- a/ansible/roles/test/tasks/lldp_neighbor.yml
+++ b/ansible/roles/test/tasks/lldp_neighbor.yml
@@ -1,10 +1,11 @@
-- name: Gather LLDP information from all neighbors by performing a SNMP walk
+- name: Gather LLDP information from all neighbors by performing a SNMP walk
lldp_facts: host={{ hname }} version=v2c community={{ snmp_rocommunity }}
connection: local
- name: Print LLDP facts from neighbors
debug: msg="{{ ansible_lldp_facts }}"
+# FIXME: use more strict assertions
- name: verify the dut system name field is not empty
assert: {that: "'{{ ansible_lldp_facts[neighbor_interface]['neighbor_sys_name'] }}' != ''"}
@@ -18,5 +19,5 @@
assert: {that: "'{{ ansible_lldp_facts[neighbor_interface]['neighbor_port_id'] }}' != ''"}
- name: verify the dut port description field is published correctly
- assert: {that: "'{{ ansible_lldp_facts[neighbor_interface]['neighbor_port_desc'] }}' == dut_interface"}
+ assert: {that: "'{{ ansible_lldp_facts[neighbor_interface]['neighbor_port_desc'] }}' != ''"}
diff --git a/ansible/roles/test/tasks/mem_check.yml b/ansible/roles/test/tasks/mem_check.yml
new file mode 100644
index 00000000000..cee41f02369
--- /dev/null
+++ b/ansible/roles/test/tasks/mem_check.yml
@@ -0,0 +1,19 @@
+- name: Copy mem_check.sh to the DuT
+ become: true
+ copy:
+ src: roles/test/files/mem_check.sh
+ dest: /tmp/mem_check.sh
+ mode: 0755
+
+- name: Run mem_check.sh
+ become: true
+ shell: /tmp/mem_check.sh
+ register: results
+ failed_when: results.rc != 0
+
+- name: Delete mem_check.sh from the DuT
+ become: true
+ file:
+ state: absent
+ path: /tmp/mem_check.sh
+
diff --git a/ansible/roles/test/tasks/ntp.yml b/ansible/roles/test/tasks/ntp.yml
index 841bfb5e914..c65b4cba007 100644
--- a/ansible/roles/test/tasks/ntp.yml
+++ b/ansible/roles/test/tasks/ntp.yml
@@ -1,9 +1,25 @@
+- name: Stop NTP service
+ become: true
+ service:
+ name: ntp
+ state: stopped
+
+- name: Force local clock to sync with an NTP clock
+ become: true
+ command: ntpd -gq
+
+- name: Start NTP service
+ become: true
+ service:
+ name: ntp
+ state: started
+
- name: Check if NTP is synced
become: true
shell: ntpstat
register: ntpstat_result
until: ntpstat_result.rc == 0
- retries: 5
- delay: 2
+ retries: 8
+ delay: 10
- debug: msg="NTP Status {{ ntpstat_result.stdout }}"
diff --git a/ansible/roles/test/tasks/ptf_runner.yml b/ansible/roles/test/tasks/ptf_runner.yml
new file mode 100644
index 00000000000..a06d1fce831
--- /dev/null
+++ b/ansible/roles/test/tasks/ptf_runner.yml
@@ -0,0 +1,54 @@
+# Common runner for ptf tests
+#
+# Parameters:
+# ptf_host - ip address of ptf host. This ip address should be presented in str inventory file with credentials
+# ptf_test_name - name of the test
+# ptf_test_dir - directory where test was copied to
+# ptf_test_path - ptf path to the test
+# ptf_platform - ptf platform
+# ptf_test_params - a list with the test parameters
+# ptf_qlen - qlen parameter for ptf
+# ptf_extra_options - extra options for ptf
+#
+# Example:
+# - include: ptf_runner.yml
+# vars:
+# ptf_test_name: COPP test - {{ item }}
+# ptf_test_dir: ptftests
+# ptf_test_path: copp_tests.{{ item }}
+# ptf_platform: nn
+# ptf_qlen: 100000
+# ptf_extra_options: --device-socket 0-3@tcp://127.0.0.1:10900 --device-socket 1-3@tcp://{{ ansible_eth0['ipv4']['address'] }}:10900
+# ptf_test_params:
+# - verbose=False
+# - dut_username=\"{{ ansible_ssh_user }}\"
+# - dut_hostname=\"{{ ansible_host }}\"
+# - fast_reboot_limit=30
+# with_items:
+# - ARPTest
+# - DHCPTest
+# - LLDPTest
+# - BGPTest
+# - LACPTest
+# - SNMPTest
+# - SSHTest
+# - IP2METest
+#
+
+- fail: msg="Please set ptf_host variable"
+ when: ptf_host is not defined
+
+- name: "PTF Test - {{ ptf_test_name }}"
+ debug: msg="ptf --test-dir {{ ptf_test_dir }} {{ ptf_test_path }} {% if ptf_qlen is defined %} --qlen={{ ptf_qlen }} {% endif %} --platform {{ ptf_platform }} {% if ptf_test_params is defined %} -t \"{{ ptf_test_params | default([]) | join(';') }}\" {% endif %} {{ ptf_extra_options | default(\"\")}} --disable-vxlan --disable-geneve --disable-erspan --disable-mpls --disable-nvgre 2>&1"
+
+- shell: ptf --test-dir {{ ptf_test_dir }} {{ ptf_test_path }} {% if ptf_qlen is defined %} --qlen={{ ptf_qlen }} {% endif %} --platform {{ ptf_platform }} {% if ptf_test_params is defined %} -t "{{ ptf_test_params | default([]) | join(';') }}" {% endif %} {{ ptf_extra_options | default("")}} --disable-vxlan --disable-geneve --disable-erspan --disable-mpls --disable-nvgre 2>&1
+ args:
+ chdir: /root
+ delegate_to: "{{ ptf_host }}"
+ failed_when: False
+ register: out
+
+- debug: var=out.stdout_lines
+
+- fail: msg="Failed test '{{ ptf_test_name }}'"
+ when: out.rc != 0
diff --git a/ansible/roles/test/tasks/reboot.yml b/ansible/roles/test/tasks/reboot.yml
new file mode 100644
index 00000000000..8134f92134f
--- /dev/null
+++ b/ansible/roles/test/tasks/reboot.yml
@@ -0,0 +1,35 @@
+- name: reboot
+ become: true
+ shell: sleep 2 && shutdown -r now "Reboot test."
+ async: 1
+ poll: 0
+ ignore_errors: true
+
+- name: pause for 1 minute before check
+ pause: minutes=1
+
+- name: Wait for switch to come back
+ local_action:
+ wait_for host={{ ansible_host }}
+ port=22
+ state=started
+ delay=10
+ timeout=180
+ search_regex="OpenSSH_[\w\.]+ Debian"
+ become: false
+ changed_when: false
+
+- name: wait again, processes and interfaces are not availabe right away
+ pause: seconds=120
+
+- name: sanity check to pass
+ include: base_sanity.yml
+
+- name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ connection: local
+ become: no
+ when: minigraph_interfaces is not defined
+
+- include: interface.yml
+
diff --git a/ansible/roles/test/tasks/acl/run_analyze_and_check.yml b/ansible/roles/test/tasks/run_analyze_and_check.yml
similarity index 100%
rename from ansible/roles/test/tasks/acl/run_analyze_and_check.yml
rename to ansible/roles/test/tasks/run_analyze_and_check.yml
diff --git a/ansible/roles/test/tasks/run_cisco_script.yml b/ansible/roles/test/tasks/run_cisco_script.yml
new file mode 100644
index 00000000000..69f12ad45a0
--- /dev/null
+++ b/ansible/roles/test/tasks/run_cisco_script.yml
@@ -0,0 +1,75 @@
+#---------------------------------
+# This script runs script for Cisco cli on remote host:
+# 1) Reads terminal length value.
+# 2) Sets terminal length to 0.
+# 2) Runs script.
+# 3) Sets terminal value to default.
+#
+# @ params: template - j2-file that contains cli commands
+# @ params: host - remote host, where to run the script
+# @ params: log_in - credentials to host
+#---------------------------------
+
+- set_fact:
+ inform_msg: "Current host is {{ host }}"
+
+- debug:
+ msg: "{{ inform_msg }}"
+
+- name: Get terminal characteristics.
+ action: apswitch template=roles/vm_set/templates/get_terminal_length.j2
+ connection: switch
+ args:
+ host: "{{ host }}"
+ enable: no
+ login: "{{ log_in }}"
+ timeout: 300
+ register: cisco_script_res
+
+- debug:
+ msg: "{{ inform_msg }}"
+
+- name: Get terminal length default.
+ shell: echo {{ cisco_script_res }} | grep --ignore-case length | sed -n "s/.*Length. \|.*length. \+//p" | sed -n "s/ rows.*//p"
+ register: terminal_length
+
+- debug:
+ msg: "{{ inform_msg }}"
+
+- name: Disable terminal paging.
+ action: apswitch template=roles/vm_set/templates/set_terminal_length.j2
+ connection: switch
+ args:
+ host: "{{ host }}"
+ enable: no
+ login: "{{ log_in }}"
+ timeout: 300
+ vars:
+ terminal_length_value: '0'
+
+- debug:
+ msg: "{{ inform_msg }}"
+
+- name: Run cisco-script.
+ action: apswitch template={{ template }}
+ connection: switch
+ args:
+ host: "{{ host }}"
+ enable: no
+ login: "{{ log_in }}"
+ timeout: 300
+ register: cisco_script_res
+
+- debug:
+ msg: "{{ inform_msg }}"
+
+- name: Set terminal length back to default.
+ action: apswitch template=roles/vm_set/templates/set_terminal_length.j2
+ connection: switch
+ args:
+ host: "{{ host }}"
+ enable: no
+ login: "{{ log_in }}"
+ timeout: 300
+ vars:
+ terminal_length_value: "{{ terminal_length.stdout }}"
diff --git a/ansible/roles/test/tasks/acl/run_config_cleanup.yml b/ansible/roles/test/tasks/run_config_cleanup.yml
similarity index 82%
rename from ansible/roles/test/tasks/acl/run_config_cleanup.yml
rename to ansible/roles/test/tasks/run_config_cleanup.yml
index b9df508dd51..216c654f7e3 100644
--- a/ansible/roles/test/tasks/acl/run_config_cleanup.yml
+++ b/ansible/roles/test/tasks/run_config_cleanup.yml
@@ -1,7 +1,8 @@
- name: Do configuration cleanup.
- shell: systemctl restart {{ orchagent }}
+ shell: systemctl restart swss
register: clean_up
+ become: true
- fail: msg="swssconfig - failed to cleanup the ACL configuration"
when: clean_up.rc != 0
diff --git a/ansible/roles/test/tasks/acl/run_config_test.yml b/ansible/roles/test/tasks/run_config_test.yml
similarity index 85%
rename from ansible/roles/test/tasks/acl/run_config_test.yml
rename to ansible/roles/test/tasks/run_config_test.yml
index 3cb338b81d4..ccde696bad4 100644
--- a/ansible/roles/test/tasks/acl/run_config_test.yml
+++ b/ansible/roles/test/tasks/run_config_test.yml
@@ -5,17 +5,17 @@
# 3) Run cleanup if needed.
#-----------------------------------------
-- include_vars: "{{ vars_files_location }}/run_config_test_vars.yml"
+- include_vars: "vars/run_config_test_vars.yml"
- block:
- name: Initialize loganalizer. Put start marker to log file.
- include: "{{ loganalyzer_init }}"
+ include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
- name: Load JSON config {{ config_file }}
- command: docker exec -i {{ orchagent }} swssconfig {{ docker_testdir }}/{{ config_file }}
+ command: docker exec -i swss swssconfig {{ docker_testdir }}/{{ config_file }}
- name: Use loganalyzer to check for the error messages {{ testname }} / {{ config_file }}.
- include: "{{ loganalyzer_analyze }}"
+ include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
- name: Get the total number of expected messages.
shell: grep "TOTAL EXPECTED" "{{ test_out_dir }}/{{ summary_file }}" | sed -n "s/TOTAL EXPECTED MATCHES:[[:space:]]*//p"
@@ -42,5 +42,5 @@
when: (errors_expected == true and expects_found.stdout == "0") or (errors_expected == false and errors_found.stdout != "0")
- name: Do configuration cleanup after {{ testname }} / {{ config_file }}
- include: "{{ run_config_cleanup }}"
+ include: roles/test/tasks/run_config_cleanup.yml
when: run_cleanup == true
diff --git a/ansible/roles/test/tasks/acl/run_loganalyzer.yml b/ansible/roles/test/tasks/run_loganalyzer.yml
similarity index 86%
rename from ansible/roles/test/tasks/acl/run_loganalyzer.yml
rename to ansible/roles/test/tasks/run_loganalyzer.yml
index 43d0af79486..73f36c582dc 100644
--- a/ansible/roles/test/tasks/acl/run_loganalyzer.yml
+++ b/ansible/roles/test/tasks/run_loganalyzer.yml
@@ -3,7 +3,7 @@
# or analyze-phase of loganalyzer.
#-----------------------------------------
-- include_vars: "{{ vars_files_location }}/run_loganalyzer_vars.yml"
+- include_vars: "vars/run_loganalyzer_vars.yml"
- name: Initialize loganalizer. Put start marker to log file.
include: "{{ loganalyzer_init }}"
diff --git a/ansible/roles/test/tasks/single_lag_test.yml b/ansible/roles/test/tasks/single_lag_test.yml
new file mode 100644
index 00000000000..348c130f932
--- /dev/null
+++ b/ansible/roles/test/tasks/single_lag_test.yml
@@ -0,0 +1,101 @@
+### Part of lag test palybook lag_2.yml (--tag lag_2)
+### This playbook test one single port channel minimum link feature of one member interface shutdown
+### and portchannel member interfaces sending ACP DU rate
+
+# Gather information of port channel ports, minimum links and total interface member numbers
+- set_fact:
+ po: "{{ item }}"
+ po_interfaces: "{{ lag_facts.lags[item]['po_config']['ports'] }}"
+ po_intf_num: "{{ lag_facts.lags[item]['po_config']['ports']|length }}"
+ po_min_links: "{{lag_facts.lags[item]['po_config']['runner']['min_ports']}}"
+
+# pick flap interface name and calculate when it flaps, should portchannel interface flap or not
+# Current it is using a static capacity < 75%, Portchannel will flap which match Sonic configuration
+# if need to be random, then will make it a var
+- set_fact:
+ po_flap: "{{ (po_intf_num|float - 1)/(po_min_links|float)*100 < 75 }}"
+ flap_intf: "{{ lag_facts.lags[item]['po_config']['ports'].keys()[0] }}"
+
+### figure out fanout switches info for the flapping lag member and run minlink test
+- set_fact:
+ peer_device: "{{ fanout_neighbors[flap_intf]['peerdevice'] }}"
+ neighbor_interface: "{{ fanout_neighbors[flap_intf]['peerport'] }}"
+
+- conn_graph_facts: host={{ peer_device }}
+ connection: local
+
+- set_fact:
+ peer_host: "{{ device_info['mgmtip'] }}"
+ peer_hwsku: "{{ device_info['HwSku'] }}"
+
+- name: test fanout interface (physical) flap and lacp keep correct po status follow minimum links requirement
+ include: lag_minlink.yml
+ vars:
+ wait_down_time: 20
+
+### Now figure out remote VM and interface info for the falpping lag member and run minlink test
+- set_fact:
+ peer_device: "{{vm_neighbors[flap_intf]['name']}}"
+ neighbor_interface: "{{vm_neighbors[flap_intf]['port']}}"
+ peer_hwsku: 'Arista-VM'
+
+##############################################################################################
+##### TODO: use minigraph/and VM configuration to figure out neighbor host access info #####
+##### try not using lldp dynamic info to find neighbor access
+##############################################################################################
+- set_fact:
+ peer_host: "{{ lldp[flap_intf]['chassis']['mgmt-ip'] }}"
+
+- name: test vm interface flap (no physical port down, more like remote port lock) that lag interface can change to correct po status follow minimum links requirement
+ include: lag_minlink.yml
+ vars:
+ wait_down_time: 120
+
+### Now prepare for the remote VM interfaces that using PTF docker to check teh LACP DU packet rate is correct
+- set_fact:
+ iface_behind_lag_member_0: "{{ topology['VMs'][peer_device]['vlans'][0] }}"
+
+- set_fact:
+ iface_behind_lag_member_1: "{{ topology['VMs'][peer_device]['vlans'][1] }}"
+ when: testbed_type == 't1-lag'
+
+- set_fact:
+ neighbor_lag_intfs: []
+
+- set_fact:
+ neighbor_lag_intfs: "{{ neighbor_lag_intfs }} + [ '{{ vm_neighbors[item]['port'] }}' ]"
+ with_items: "{{ po_interfaces }}"
+
+# make sure portchannel peer rate is set to fast
+- name: make sure all lag members on VM are set to fast
+ action: apswitch template=neighbor_lag_rate_fast.j2
+ args:
+ host: "{{peer_host}}"
+ login: "{{switch_login[hwsku_map[peer_hwsku]]}}"
+ connection: switch
+
+- pause:
+ seconds: 5
+
+- name: test lacp packet sending rate is 1 seconds
+ include: lag_lacp_timing_test.yml
+ vars:
+ vm_name: "{{ peer_device }}"
+ lacp_timer: 1
+
+# make sure portchannel peer rate is set to slow
+- name: make sure all lag members on VM are set to slow
+ action: apswitch template=neighbor_lag_rate_slow.j2
+ args:
+ host: "{{peer_host}}"
+ login: "{{switch_login[hwsku_map[peer_hwsku]]}}"
+ connection: switch
+
+- pause:
+ seconds: 5
+
+- name: test lacp packet sending rate is 30 seconds
+ include: lag_lacp_timing_test.yml
+ vars:
+ vm_name: "{{ peer_device }}"
+ lacp_timer: 30
diff --git a/ansible/roles/test/tasks/snmp/interfaces.yml b/ansible/roles/test/tasks/snmp/interfaces.yml
index 93f0a9e518e..a77901fd7a7 100644
--- a/ansible/roles/test/tasks/snmp/interfaces.yml
+++ b/ansible/roles/test/tasks/snmp/interfaces.yml
@@ -5,27 +5,29 @@
- set_fact:
snmp_intf: []
-
-- set_fact:
mg_intf: []
- name: Create snmp interfaces list
set_fact:
- snmp_intf: "{{snmp_intf + [item.value.name] }}"
- with_dict: snmp_interfaces
+ snmp_intf: "{{ snmp_intf + [item.value.name] }}"
+ with_dict: "{{ snmp_interfaces }}"
when: "{{item.value.name is defined}}"
- name: Create minigraph interfaces list
set_fact:
- mg_intf: "{{mg_intf + [item.name] }}"
- with_items: minigraph_interfaces
- when: "{{item.name is defined}}"
+ mg_intf: "{{ mg_intf + [item.value.alias] }}"
+ with_dict: "{{ minigraph_ports }}"
+- name: Add port channel interfaces into minigraph interfaces list
+ set_fact:
+ mg_intf: "{{ mg_intf + [item.key] }}"
+ with_dict: "{{ minigraph_portchannels }}"
+
+- debug: var=minigraph_map_sonic_to_ngs
- debug: var=snmp_intf
- debug: var=mg_intf
- name: Check for missing interfaces in SNMP
- fail: msg="Minigraph interface {{item}} not in SNMP interfaces"
- when: "{{item not in snmp_intf}}"
- with_items: mg_intf
-
+ fail: msg="Minigraph interface {{ minigraph_map_sonic_to_ngs[item] if item in minigraph_map_sonic_to_ngs else item }} not in SNMP interfaces"
+ when: "{{ (item in minigraph_map_sonic_to_ngs and minigraph_map_sonic_to_ngs[item] not in snmp_intf) or (item not in minigraph_map_sonic_to_ngs and item not in snmp_intf) }}"
+ with_items: "{{ mg_intf }}"
diff --git a/ansible/roles/test/tasks/sonic.yml b/ansible/roles/test/tasks/sonic.yml
index 5dc71725ab7..f0b670738a4 100644
--- a/ansible/roles/test/tasks/sonic.yml
+++ b/ansible/roles/test/tasks/sonic.yml
@@ -4,10 +4,39 @@
become: no
tags: always
+### When calling the following tests, you need to provide a command line parameter
+### specifying which PTF docker image host to test against. For example,
+### -e "ptf_host=10.0.0.200"
+- fail: msg="Please set ptf_host variable"
+ when: ptf_host is not defined
+ tags: arp,dhcp_relay
+
+# Set sonic_hwsku
+- name: Set sonic_hwsku fact
+ set_fact:
+ sonic_hwsku: "{{minigraph_hwsku}}"
+ tags: always
+
+- name: Set sonic_asic_type fact
+ set_fact:
+ sonic_asic_type: broadcom
+ when: sonic_hwsku in broadcom_hwskus
+ tags: always
+
+- name: Set sonic_asic_type fact
+ set_fact:
+ sonic_asic_type: mellanox
+ when: sonic_hwsku in mellanox_hwskus
+ tags: always
+
- name: Verify interfaces are up
include: interface.yml
tags: always
+- name: BGP facts test
+ include: bgp_fact.yml
+ tags: bgp_fact
+
- name: Neighbor mac change test
include: neighbour-mac.yml
tags: neighbour
@@ -20,26 +49,28 @@
include: ntp.yml
tags: ntp
-- name: Test Syslog Basic
- include: syslog.yml
- tags: syslog
-
- name: Test SNMP Basic
include: snmp.yml
tags: snmp
-- name: Test SNMP CPU
- include: snmp/cpu.yml
- tags: snmp_cpu
+- name: Test DHCP Relay
+ include: dhcp_relay.yml
+ tags: dhcp_relay
+ when: minigraph_devices[inventory_hostname]['type'] == "ToRRouter"
+
+- name: Test ECMP route distribution
+ include: ecmp.yml
+ tags: ecmp
+
+- name: Test Control-Plain policing COPP
+ include: copp.yml
+ tags: copp
+
+- name: Fast-reboot test
+ include: fast-reboot.yml
+ when: minigraph_portchannel_interfaces | length > 0 and minigraph_vlan_interfaces | length > 0
+ tags: fast_reboot
-- name: Test SNMP Interfaces
- include: snmp/interfaces.yml
- tags: snmp_interfaces
-
-- name: BGP facts test
- include: bgp_fact.yml
- tags: bgp_fact
-
### when callng BGP flaps test, please add command line of which VMs host to test against
### -e "vmhost_num='01'"
- fail: msg="Please set vmhost_num variable"
@@ -50,24 +81,77 @@
include: bgp_flap.yml
tags: sync
-- name: Test Interface Flap from Neighbor
- include: interface_up_down.yml
- tags: link
+- name: Test Syslog Basic
+ include: syslog.yml
+ tags: syslog
-### when calling this ARP test, please add command line of which PTF docker image host to test against
-### -e "ptf_host=10.0.0.200"
-- fail: msg="Please set ptf_host variable"
- when: ptf_host is not defined
- tags: arp
+- name: Test SNMP CPU
+ include: snmp/cpu.yml
+ tags: snmp_cpu
+ when: minigraph_hwsku == "Force10-S6000" or minigraph_hwsku == "ACS-S6000"
+
+- name: Test SNMP Interfaces
+ include: snmp/interfaces.yml
+ tags: snmp_interfaces
+
+- name: Test Interface Flap from Neighbor
+ include: link_flap.yml
+ tags: link_flap
- name: Test kernel ARP behavior
include: arpall.yml
tags: arp
+- name: Test sensors
+ include: sensors_check.yml
+ tags: sensors
+
+- name: Test reboot
+ include: reboot.yml
+ tags: reboot
+
+### When calling this FIB test, please add command line of what testbed_type and which PTF docker to test against
+### -e "testbed_type=t1-lag ptf_host=10.0.0.200"
- name: Fib test
include: fib.yml
tags: fib
-- name: Test ACL
- include: acl.yml
+### When calling this FDB test, please add command line of what testbed_type and which PTF docker to test agains
+### -e "testbed_type=t0 ptf_host=10.64.246.22"
+- name: FDB test
+ include: fdb.yml
+ tags: fdb
+
+### When calling this decap test, please add command line of what testbed_type, dscp_mode, and which PTF docker to test against
+#### -e "testbed_type=t1-lag dscp_mode=pipe ptf_host=10.0.0.200"
+- name: Decap test
+ include: decap.yml
+ tags: decap
+
+- name: BGP Speaker test
+ include: bgp_speaker.yml
+ tags: bgp_speaker
+
+- name: Test Everflow
+ include: everflow.yml
+ tags: everflow
+
+- name: Test Everflow on testbed
+ include: everflow_testbed.yml
+ tags: everflow_testbed
+
+- name: Test LAG
+ include: lagall.yml
+ tags: lag
+
+- name: Test LAG using lag graph file
+ include: lag_2.yml
+ tags: lag_2
+
+- name: Memory check
+ include: mem_check.yml
+ tags: mem_check
+
+- name: ACL test
+ include: acltb.yml
tags: acl
diff --git a/ansible/roles/test/tasks/syslog.yml b/ansible/roles/test/tasks/syslog.yml
index 13fc97a6209..d83bbe06280 100644
--- a/ansible/roles/test/tasks/syslog.yml
+++ b/ansible/roles/test/tasks/syslog.yml
@@ -31,80 +31,89 @@
local_srcip: "{{ local_facts.ansible_facts.ansible_eth0.ipv4.address }}"
original_syslog_servers: "{{ syslog_servers }}"
syslog_port: "{{ 65535 | random(start=65000) }}"
+ test_message: "Basic Test Message"
- debug: var=local_srcip
-# TODO: (johnar) rsyslog template needs to be changed to allow variable port. Static the config for now...
-# Reconfigure syslog on the DUT to point at this remote host
-# set_fact:
-# syslog_servers:
-# - "{{ local_srcip }}"
-
-#- name: Reconfigure Rsyslog for Testing
-# become: true
-# template: src=../../acs/templates/rsyslog.conf.j2
-# dest=/etc/rsyslog.conf
-
- name: Add Rsyslog destination for testing
become: true
- shell: 'echo "*.* @{{ local_srcip }}:{{ syslog_port }}" >> /etc/rsyslog.conf'
+ lineinfile:
+ line: "*.* @{{ local_srcip }}:{{ syslog_port }}"
+ dest: /etc/rsyslog.conf
+ state: present
- name: Restart Syslog Daemon
become: true
service: name=rsyslog state=restarted
-# Start Syslog Server
+# Start local ryslog Server
-- name: Start Syslog Server on ansible localhost
- syslog_server: timeout=10 port="{{ syslog_port }}" host="{{ local_srcip }}"
- async: 60
- poll: 0
- register: syslog_sleeper
+- name: Load imudp module in local syslog
connection: local
- become: no
+ become: true
+ lineinfile:
+ line: "module(load=\"imudp\")"
+ dest: /etc/rsyslog.conf
+ state: present
-- name: Wait a little bit for service to start
- wait_for: timeout=2
+- name: Remove imudp ports
+ connection: local
+ become: true
+ lineinfile:
+ regexp: "input\\(type=\"imudp\" port=\"\\d+\"\\)"
+ dest: /etc/rsyslog.conf
+ state: absent
-# SSH to device and generate a syslog
-- name: Send test syslog
- become: yes
- command: logger --priority INFO Basic Test Message
+- name: Add imudp port {{ syslog_port }}
+ connection: local
+ become: true
+ lineinfile:
+ line: "input(type=\"imudp\" port=\"{{ syslog_port }}\")"
+ dest: /etc/rsyslog.conf
+ state: present
-#- debug: var=syslog_sleeper
+- name: Stop Syslog Daemon
+ connection: local
+ become: true
+ shell: killall rsyslogd
+ ignore_errors: true
-# Retreive syslogs
-- name: Retreive syslog messages
- async_status: jid="{{ syslog_sleeper.ansible_job_id }}"
- register: job_result
- until: job_result.finished
- retries: 30
- delay: 1
+- name: Remove local /var/log/syslog
+ become: true
connection: local
+ file:
+ path: /var/log/syslog
+ state: absent
-- debug: msg="{{ syslog_messages }}"
+- name: Start Syslog Daemon
+ connection: local
+ become: true
+ service: name=rsyslog state=started
-# Reconfigure Rsyslog to to original state
+- name: Wait a little bit for service to start
+ wait_for: timeout=2
-- set_fact:
- syslog_servers: "{{ original_syslog_servers }}"
+# SSH to device and generate a syslog
+- name: Send test syslog
+ become: yes
+ command: logger --priority INFO {{ test_message }}
-- name: Reconfigure Rsyslog to original state
- template: src=roles/sonic-common/templates/rsyslog.conf.j2
- dest=/etc/rsyslog.conf
+- name: Restore original /etc/rsyslog.conf
become: true
+ lineinfile:
+ regexp: "\\*\\.\\* @{{ local_srcip }}:{{ syslog_port }}"
+ dest: /etc/rsyslog.conf
+ state: absent
- name: Restart Syslog Daemon
become: true
service: name=rsyslog state=restarted
-
# Check Messages
- name: Check syslog messages for the test message
- set_fact:
- found1: "true"
- when: "{{ item | search('Basic Test Message') }}"
- with_items: "{{ syslog_messages }}"
+ connection: local
+ become: true
+ shell: grep {{ inventory_hostname }} /var/log/syslog | grep "{{ test_message }}" | grep -v ansible
+ register: grep_result
-- fail: msg='Unable to find test syslog "Basic Test Message"'
- when: found1 is not defined
+- debug: var=grep_result
diff --git a/ansible/roles/test/templates/acl_ranges_rules.j2 b/ansible/roles/test/templates/acl_ranges_rules.j2
new file mode 100644
index 00000000000..3d86efb3665
--- /dev/null
+++ b/ansible/roles/test/templates/acl_ranges_rules.j2
@@ -0,0 +1,14 @@
+[
+{% for tor in range(ranges_number | int) %}
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Range_Test_Table:Rule{{ loop.index }}_port_range_test": {
+ "priority" : "50",
+ "l4_dst_port_range" : "{{ 1024 + loop.index * 16 }}-{{ 1024 + loop.index * 16 + 10 }}",
+ "packet_action" : "forward"
+ },
+ "OP": "SET"
+ }{% if not loop.last %},
+{% endif %}
+{% endfor %}
+
+]
diff --git a/ansible/roles/test/templates/acl_ranges_table.j2 b/ansible/roles/test/templates/acl_ranges_table.j2
new file mode 100644
index 00000000000..9dcf66cc624
--- /dev/null
+++ b/ansible/roles/test/templates/acl_ranges_table.j2
@@ -0,0 +1,10 @@
+[
+ {
+ "ACL_TABLE:ACL_Testbed_Range_Test_Table": {
+ "policy_desc" : "This_table_contains_rules_needed_for_the_testbed_ranges_test",
+ "type" : "L3",
+ "ports" : "{% for ifname, v in minigraph_neighbors.iteritems() %}{{"%s" % alias_reverse_map[ifname]}},{% endfor %}"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/templates/acltb.j2 b/ansible/roles/test/templates/acltb.j2
new file mode 100644
index 00000000000..8a4b65660bc
--- /dev/null
+++ b/ansible/roles/test/templates/acltb.j2
@@ -0,0 +1,10 @@
+{# tor ports #}
+{% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T0" in v.name %}{{ '%d' % minigraph_port_indices[ifname] }},{% endif %}{% endfor %}
+
+{# spine ports #}
+{% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T2" in v.name %}{{ '%d' % minigraph_port_indices[ifname] }},{% endif %}{% endfor %}
+
+192.168.0.0
+192.168.0.16
+172.16.1.0
+172.16.2.0
diff --git a/ansible/roles/test/templates/acltb_test_rules.j2 b/ansible/roles/test/templates/acltb_test_rules.j2
new file mode 100644
index 00000000000..cb842e3adba
--- /dev/null
+++ b/ansible/roles/test/templates/acltb_test_rules.j2
@@ -0,0 +1,109 @@
+{% set break = 0 %}
+{% set acltb_dst_ip_block = "" %}
+{% set acltb_dst_ip_priority = "" %}
+{% for podset in range(0, podset_number) if break == 0 %}
+{% for tor in range(0, 15) if break == 0 %}
+{% if loop.index == 2 %}
+[
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule01_SRC_IP_test": {
+ "priority" : "50",
+ "src_ip" : "10.0.0.2",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule02_DST_IP_test": {
+ "priority" : "50",
+ "dst_ip" : "192.168.{{ podset }}.{{ tor * 16 }}",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule03_SRC_port_test": {
+ "priority" : "50",
+ "l4_src_port" : "0x1235",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule04_DST_port_test": {
+ "priority" : "50",
+ "l4_dst_port" : "0x1235",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule05_Ethertype_test": {
+ "priority" : "50",
+ "ether_type" : "0x1234",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule06_IP_protocol_test": {
+ "priority" : "50",
+ "ip_protocol" : "0x7E",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule07_tcp_flags_test": {
+ "priority" : "50",
+ "tcp_flags" : "0x12/0x12",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule08_IP_type_test": {
+ "priority" : "50",
+ "ip_type" : "IPv6ANY",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule091_SRC_port_range_test": {
+ "priority" : "50",
+ "l4_src_port_range" : "4656-4671",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:Rule0A1_DST_port_range_test": {
+ "priority" : "50",
+ "l4_dst_port_range" : "4640-4687",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:RuleB1_Priority_test_drop": {
+ "priority" : "50",
+ "src_ip" : "10.0.0.3",
+ "packet_action" : "drop"
+ },
+ "OP": "SET"
+ },
+ {
+ "ACL_RULE_TABLE:ACL_Testbed_Test_Table:RuleB2_Priority_test_permit": {
+ "priority" : "51",
+ "src_ip" : "10.0.0.3",
+ "packet_action" : "forward"
+ },
+ "OP": "SET"
+ }
+]
+{% set break = 1 %}
+{% endif %}
+{% endfor %}
+{% set break = 1 %}
+{% endfor %}
diff --git a/ansible/roles/test/templates/acltb_test_table.j2 b/ansible/roles/test/templates/acltb_test_table.j2
new file mode 100644
index 00000000000..ad171fccbc8
--- /dev/null
+++ b/ansible/roles/test/templates/acltb_test_table.j2
@@ -0,0 +1,10 @@
+[
+ {
+ "ACL_TABLE:ACL_Testbed_Test_Table": {
+ "policy_desc" : "This_table_contains_rules_needed_for_the_testbed_regression_tests",
+ "type" : "L3",
+ "ports" : "{% for ifname, v in minigraph_neighbors.iteritems() %}{{"%s" % alias_reverse_map[ifname]}},{% endfor %}"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/templates/arp_responder.conf.j2 b/ansible/roles/test/templates/arp_responder.conf.j2
new file mode 100644
index 00000000000..7d6dcb3062d
--- /dev/null
+++ b/ansible/roles/test/templates/arp_responder.conf.j2
@@ -0,0 +1,10 @@
+[program:arp_responder]
+command=/usr/bin/python /opt/arp_responder.py {{ arp_responder_args }}
+process_name=arp_responder
+stdout_logfile=/tmp/arp_responder.out.log
+stderr_logfile=/tmp/arp_responder.err.log
+redirect_stderr=false
+autostart=false
+autorestart=true
+startsecs=1
+numprocs=1
diff --git a/ansible/roles/test/templates/bgp_neighbor_noshut.j2 b/ansible/roles/test/templates/bgp_neighbor_noshut.j2
index fef0f8c4b29..fe8a98b7852 100644
--- a/ansible/roles/test/templates/bgp_neighbor_noshut.j2
+++ b/ansible/roles/test/templates/bgp_neighbor_noshut.j2
@@ -1,7 +1,7 @@
configure
router bgp {{ asn }}
{% if "Arista" in hwsku %}
-no neighbor {{ peer_addr }} shutdown
+default neighbor {{ peer_addr }} shutdown
{% else %}
neighbor {{ peer_addr }}
no shutdown
diff --git a/ansible/roles/test/templates/bgp_speaker_route.j2 b/ansible/roles/test/templates/bgp_speaker_route.j2
new file mode 100644
index 00000000000..95ec43273a2
--- /dev/null
+++ b/ansible/roles/test/templates/bgp_speaker_route.j2
@@ -0,0 +1,8 @@
+{% if addr_family == 'ipv6' %}
+{{announce_prefix}} {% for portchannel, v in minigraph_portchannels.iteritems() %}[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
+
+{% elif addr_family == 'ipv4' %}
+0.0.0.0/0 {% for portchannel, v in minigraph_portchannels.iteritems() %}[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
+
+{{announce_prefix}} {% for vlan, v in minigraph_vlans.iteritems() %}{% for member in v.members %}[{{ '%d' % minigraph_port_indices[member]}}]{% if not loop.last %} {% endif %}{% endfor %}{% if not loop.last %} {% endif %}{% endfor %}
+{% endif %}
diff --git a/ansible/roles/test/templates/decap_conf.j2 b/ansible/roles/test/templates/decap_conf.j2
new file mode 100644
index 00000000000..91ce121fc18
--- /dev/null
+++ b/ansible/roles/test/templates/decap_conf.j2
@@ -0,0 +1,13 @@
+[
+ {
+ "TUNNEL_DECAP_TABLE:NETBOUNCER" : {
+ "tunnel_type":"IPINIP",
+ "dst_ip":"{{lo_ip}}",
+ "src_ip":"1.1.1.1",
+ "dscp_mode":"{{dscp_mode}}",
+ "ecn_mode":"standard",
+ "ttl_mode":"pipe"
+ },
+ "OP": "SET"
+ }
+]
diff --git a/ansible/roles/test/templates/exabgp/config.j2 b/ansible/roles/test/templates/exabgp/config.j2
new file mode 100644
index 00000000000..61abd440e48
--- /dev/null
+++ b/ansible/roles/test/templates/exabgp/config.j2
@@ -0,0 +1,26 @@
+{%set local_ip = item.local_ip.split('/') %}
+group exabgp {
+ process dump {
+ encoder json;
+ receive {
+ parsed;
+ update;
+ }
+ run /usr/bin/python {{helper_dir}}/dump.py;
+ }
+ process http-api {
+ run /usr/bin/python {{helper_dir}}/http_api.py {{item.port_num}};
+ }
+
+ neighbor {{minigraph_lo_interfaces[0]['addr']}} {
+ router-id {{local_ip[0]}};
+ local-address {{local_ip[0]}};
+ peer-as {{minigraph_bgp_asn}};
+ local-as {{bgp_speaker_asn}};
+ auto-flush false;
+ group-updates true;
+ }
+
+}
+
+
diff --git a/ansible/roles/test/templates/exabgp/routes.j2 b/ansible/roles/test/templates/exabgp/routes.j2
new file mode 100644
index 00000000000..55b8aa1d409
--- /dev/null
+++ b/ansible/roles/test/templates/exabgp/routes.j2
@@ -0,0 +1,6 @@
+{%set mux_ip_1 = item.mux_ip_1.split('/') %}
+{%set mux_ip_2 = item.mux_ip_2.split('/') %}
+{%set speaker_ip = item.speaker_ip.split('/') %}
+neighbor {{minigraph_lo_interfaces[0]['addr']}} announce route {{announce_prefix}} next-hop {{mux_ip_1[0]}};{{item.port_num_1}}
+neighbor {{minigraph_lo_interfaces[0]['addr']}} announce route {{announce_prefix}} next-hop {{mux_ip_2[0]}};{{item.port_num_2}}
+neighbor {{minigraph_lo_interfaces[0]['addr']}} announce route {{minigraph_bgp_peers_with_range[0]['ip_range'][0]}} next-hop {{speaker_ip[0]}};{{item.port_num_3}}
diff --git a/ansible/roles/test/templates/exabgp/start.j2 b/ansible/roles/test/templates/exabgp/start.j2
new file mode 100755
index 00000000000..b3637bbb7cd
--- /dev/null
+++ b/ansible/roles/test/templates/exabgp/start.j2
@@ -0,0 +1,8 @@
+ifconfig eth{{ '%d' % (minigraph_vlans[minigraph_vlan_interfaces[0]['attachto']]['members'][0] | replace("Ethernet", "") | int / 4)}} {{item.phy_ip}}
+ifconfig eth{{ '%d' % (minigraph_vlans[minigraph_vlan_interfaces[0]['attachto']]['members'][0] | replace("Ethernet", "") | int / 4)}}:0 {{item.logical_ip_1}}
+ifconfig eth{{ '%d' % (minigraph_vlans[minigraph_vlan_interfaces[0]['attachto']]['members'][0] | replace("Ethernet", "") | int / 4)}}:1 {{item.logical_ip_2}}
+ip route flush {{minigraph_lo_interfaces[0]['addr']}}/{{minigraph_lo_interfaces[0]['prefixlen']}}
+ip route add {{minigraph_lo_interfaces[0]['addr']}}/{{minigraph_lo_interfaces[0]['prefixlen']}} via {{ minigraph_vlan_interfaces[0]['addr']}}
+env exabgp.daemon.user=root exabgp {{exabgp_dir}}/{{item.config_file_1}} >/dev/null 2>&1 &
+env exabgp.daemon.user=root exabgp {{exabgp_dir}}/{{item.config_file_2}} >/dev/null 2>&1 &
+env exabgp.daemon.user=root exabgp {{exabgp_dir}}/{{item.config_file_3}} >/dev/null 2>&1 &
diff --git a/ansible/roles/test/templates/fdb.j2 b/ansible/roles/test/templates/fdb.j2
new file mode 100644
index 00000000000..6c0b7c79615
--- /dev/null
+++ b/ansible/roles/test/templates/fdb.j2
@@ -0,0 +1,3 @@
+{% for vlan in minigraph_vlan_interfaces %}
+{{ vlan['subnet'] }} {% for ifname in minigraph_vlans[vlan['attachto']]['members'] %} {{ minigraph_port_indices[ifname] }} {% endfor %}
+{% endfor %}
diff --git a/ansible/roles/test/templates/fib.j2 b/ansible/roles/test/templates/fib.j2
index 7940079a4b4..ec9acc35c64 100644
--- a/ansible/roles/test/templates/fib.j2
+++ b/ansible/roles/test/templates/fib.j2
@@ -1,32 +1,56 @@
-{# routes to spines #}
-{% for podset in range(0, podset_number) %}
-{% for tor in range(0, tor_number) %}
-{% for subnet in range(0, tor_subnet_number) %}
-{% if testbed_type == 'fib' %}
-192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T2" in v.name %}{{ '%d' % (alias_reverse_map[ifname]|replace("Ethernet","")|int / 4)}},{% endif %}{% endfor %}
+{# defualt route#}
+{% if testbed_type == 't1' %}
+0.0.0.0/0 {% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T2" in v.name %}{{ '[%d]' % minigraph_port_indices[ifname]}}{% if not loop.last %} {% endif %}{% endif %}{% endfor %}
+{% elif testbed_type == 't0' or testbed_type == 't1-lag' %}
+0.0.0.0/0 {% for portchannel, v in minigraph_portchannels.iteritems() %}
+[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
+{% endif %}
+
+{#routes to uplink#}
+{% for podset in range(0, props.podset_number) %}
+{% for tor in range(0, props.tor_number) %}
+{% for subnet in range(0, props.tor_subnet_number) %}
+{% if testbed_type == 't1' %}
+192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T2" in v.name %}{{ '[%d]' % minigraph_port_indices[ifname]}}{% if not loop.last %} {% endif %}{% endif %}{% endfor %}
+
+20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T2" in v.name %}{{ '[%d]' % minigraph_port_indices[ifname]}}{% if not loop.last %} {% endif %}{% endif %}{% endfor %}
-20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {% for ifname, v in minigraph_neighbors.iteritems() %}{% if "T2" in v.name %}{{ '%d' % (alias_reverse_map[ifname]|replace("Ethernet","")|int / 4)}},{% endif %}{% endfor %}
+{% elif testbed_type == 't1-lag' %}
+192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {% for portchannel, v in minigraph_portchannels.iteritems() %}
+[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
-{% elif testbed_type == 'lag' %}
+20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {% for portchannel, v in minigraph_portchannels.iteritems() %}
+[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
-192.168.{{ podset }}.{{ tor * 16 + subnet }}/32 {% for pc_interface in minigraph_portchannel_interfaces %}
-{% for member in pc_interface['members']%}{{ '%d' % (member|replace("Ethernet","")|int / 4)}},{% endfor %}{% endfor %}
+{% elif testbed_type == 't0' %}
+{% set suffix = ( (podset * props.tor_number * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (tor * props.max_tor_subnet_number * props.tor_subnet_size) +
+ (subnet * props.tor_subnet_size) ) %}
+{% set octet2 = (168 + ((suffix // (256 ** 2))) % 256) %}
+{% set octet3 = ((suffix // 256) % 256) %}
+{% set octet4 = (suffix % 256) %}
+{% set prefixlen_v4 = (32 - ((props.tor_subnet_size | log(2))) | int) %}
+{# Skip 192.168.0.0 as it is in Vlan1000 subnet #}
+{% if octet2 != 168 and octet3 != 0 and octet4 != 0 %}
+192.{{ octet2 }}.{{ octet3 }}.{{ octet4 }}/{{ prefixlen_v4 }} {% for portchannel, v in minigraph_portchannels.iteritems() %}[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
-20C0:A8{{ '%02X' % podset }}:0:{{ '%02X' % (tor * 16 + subnet)}}::/64 {% for pc_interface in minigraph_portchannel_interfaces %}
-{% for member in pc_interface['members']%}{{ '%d' % (member|replace("Ethernet","")|int / 4)}},{% endfor %}{% endfor %}
+20C0:{{ '%02X%02X' % (octet2, octet3) }}:0:{{ '%02X' % octet4 }}::/64 {% for portchannel, v in minigraph_portchannels.iteritems() %}[{% for member in v.members %}{{ '%d' % minigraph_port_indices[member]}}{% if not loop.last %} {% endif %}{% endfor %}]{% if not loop.last %} {% endif %}{% endfor %}
+{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
-
-
-{# routes to tor #}
+{# routes to downlink #}
+{% if testbed_type == 't1' or testbed_type == 't1-lag' %}
{% for ifname, v in minigraph_neighbors.iteritems() %}
{% if "T0" in v.name %}
-{% for subnet in range(0, local_tor_subnet_number) %}
-172.16.{{ v.name|replace("ARISTA", "")|replace("T0", "")|int }}.{{ subnet }}/32 {{ '%d' % (alias_reverse_map[ifname]|replace("Ethernet","")|int / 4)}}
-20AC:10{{ '%02X' % v.name|replace("ARISTA", "")|replace("T0", "")|int }}:0:{{ '%02X' % subnet }}::/64 {{ '%d' % (alias_reverse_map[ifname]|replace("Ethernet","")|int / 4)}}
+{% for subnet in range(0, props_tor.tor_subnet_number) %}
+172.16.{{ v.name|replace("ARISTA", "")|replace("T0", "")|int }}.{{ subnet }}/32 {{ '[%d]' % minigraph_port_indices[ifname]}}{% if not loop.last %} {% endif %}
+
+20AC:10{{ '%02X' % v.name|replace("ARISTA", "")|replace("T0", "")|int }}:0:{{ '%02X' % subnet }}::/64 {{ '[%d] ' % minigraph_port_indices[ifname]}}{% if not loop.last %} {% endif %}
+
+{% endfor %}
+{% endif %}
{% endfor %}
{% endif %}
-{% endfor %}
\ No newline at end of file
diff --git a/ansible/roles/test/templates/neighbor_interface_no_shut_single.j2 b/ansible/roles/test/templates/neighbor_interface_no_shut_single.j2
index 1ce6063c59a..f704f975cb8 100644
--- a/ansible/roles/test/templates/neighbor_interface_no_shut_single.j2
+++ b/ansible/roles/test/templates/neighbor_interface_no_shut_single.j2
@@ -1,5 +1,5 @@
configure
- interface {{ minigraph_neighbors[item].port }}
+ interface {{ neighbor_interface }}
no shutdown
exit
exit
diff --git a/ansible/roles/test/templates/neighbor_interface_shut_single.j2 b/ansible/roles/test/templates/neighbor_interface_shut_single.j2
new file mode 100644
index 00000000000..3c8a2e8e38e
--- /dev/null
+++ b/ansible/roles/test/templates/neighbor_interface_shut_single.j2
@@ -0,0 +1,6 @@
+configure
+ interface {{ neighbor_interface }}
+ shutdown
+ exit
+exit
+exit
diff --git a/ansible/roles/test/templates/neighbor_lag_rate_fast.j2 b/ansible/roles/test/templates/neighbor_lag_rate_fast.j2
new file mode 100644
index 00000000000..56143207b58
--- /dev/null
+++ b/ansible/roles/test/templates/neighbor_lag_rate_fast.j2
@@ -0,0 +1,9 @@
+enable
+configure
+{% for intf in neighbor_lag_intfs %}
+ interface {{ intf }}
+ lacp rate fast
+ exit
+{% endfor %}
+exit
+exit
diff --git a/ansible/roles/test/templates/neighbor_lag_rate_slow.j2 b/ansible/roles/test/templates/neighbor_lag_rate_slow.j2
new file mode 100644
index 00000000000..f45f4d53b1f
--- /dev/null
+++ b/ansible/roles/test/templates/neighbor_lag_rate_slow.j2
@@ -0,0 +1,9 @@
+enable
+configure
+{% for intf in neighbor_lag_intfs %}
+ interface {{ intf }}
+ lacp rate normal
+ exit
+{% endfor %}
+exit
+exit
diff --git a/ansible/roles/vm_set/library/kickstart.py b/ansible/roles/vm_set/library/kickstart.py
index 4480b343eae..a15a2dcdcca 100644
--- a/ansible/roles/vm_set/library/kickstart.py
+++ b/ansible/roles/vm_set/library/kickstart.py
@@ -126,41 +126,29 @@ def logout(self):
return
-
-def session(port, login, password, new_params):
- templates = {
- 'hostname': [
- ('hostname %s' % str(new_params['hostname']), [r'\(config\)#']),
- ],
- 'mgmt_ip': [
- ('interface management 1', [r'\(config-if-Ma1\)#']),
- ('no shutdown', [r'\(config-if-Ma1\)#']),
- ('ip address %s' % str(new_params['mgmt_ip']), [r'\(config-if-Ma1\)#']),
- ('exit', [r'\(config\)#']),
- ],
- 'mgmt_gw': [
- ('ip route 0.0.0.0/0 %s' % str(new_params['mgmt_gw']), [r'\(config\)#']),
- ],
- 'new_login': [
- ('username %s privilege 15 role network-admin secret 0 %s' % (str(new_params['new_login']), str(new_params['new_password'])), [r'\(config\)#']),
- ],
- 'new_password': [], # empty. All data in new_login
- 'new_root_password': [
- ('aaa root secret 0 %s' % str(new_params['new_root_password']), [r'\(config\)#']),
- ],
- }
-
- seq = []
- for key, param in new_params.iteritems():
- if param is not None:
- seq.extend(templates[key])
-
- debug = MyDebug('/tmp/debug.txt', enabled=False)
- ss = SerialSession(port, debug)
- ss.login(login, password)
+def session(new_params):
+ seq = [
+ ('hostname %s' % str(new_params['hostname']), [r'\(config\)#']),
+ ('vrf definition MGMT', [r'\(config-vrf-MGMT\)#']),
+ ('rd 1:1', [r'\(config-vrf-MGMT\)#']),
+ ('exit', [r'\(config\)#']),
+ ('ip routing vrf MGMT', [r'\(config\)#']),
+ ('interface management 1', [r'\(config-if-Ma1\)#']),
+ ('no shutdown', [r'\(config-if-Ma1\)#']),
+ ('vrf forwarding MGMT', [r'\(config-if-Ma1\)#']),
+ ('ip address %s' % str(new_params['mgmt_ip']), [r'\(config-if-Ma1\)#']),
+ ('exit', [r'\(config\)#']),
+ ('ip route vrf MGMT 0.0.0.0/0 %s' % str(new_params['mgmt_gw']), [r'\(config\)#']),
+ ('username %s privilege 15 role network-admin secret 0 %s' % (str(new_params['new_login']), str(new_params['new_password'])), [r'\(config\)#']),
+ ('aaa root secret 0 %s' % str(new_params['new_root_password']), [r'\(config\)#']),
+ ]
+
+ debug = MyDebug('/tmp/debug.%s.txt' % new_params['hostname'], enabled=True)
+ ss = SerialSession(new_params['telnet_port'], debug)
+ ss.login(new_params['login'], new_params['password'])
ss.enable()
ss.wait_for_warmup()
- ss.rename_boot(seq)
+ ss.rename_boot(seq) # FIXME: do we need this rename?
ss.configure(seq)
ss.wait_for_warmup()
ss.logout()
@@ -170,28 +158,7 @@ def session(port, login, password, new_params):
def core(module):
- telnet_port = module.params.get('telnet_port', None)
- login = module.params.get('login', None)
- password = module.params.get('password', None)
-
- new_params = {}
- new_params['hostname'] = module.params.get('hostname', None)
- new_params['mgmt_ip'] = module.params.get('mgmt_ip', None)
- new_params['mgmt_gw'] = module.params.get('mgmt_gw', None)
- new_params['new_login'] = module.params.get('new_login', None)
- new_params['new_password'] = module.params.get('new_password', None)
- new_params['new_root_password'] = module.params.get('new_root_password', None)
-
- if (new_params['new_login'] is not None and new_params['new_password'] is None):
- module.fail_json(msg = 'new_password is required')
-
- if (new_params['new_login'] is None and new_params['new_password'] is not None):
- module.fail_json(msg = 'new_login is required')
-
- if telnet_port is None:
- module.fail_json(msg = 'telnet port number is required')
-
- session(telnet_port, login, password, new_params)
+ session(module.params)
return {'kickstart_code': 0, 'changed': True, 'msg': 'Kickstart completed'}
@@ -202,12 +169,12 @@ def main():
telnet_port = dict(required=True),
login = dict(required=True),
password = dict(required=True),
- hostname = dict(),
- mgmt_ip = dict(),
- mgmt_gw = dict(),
- new_login = dict(),
- new_password = dict(),
- new_root_password = dict(),
+ hostname = dict(required=True),
+ mgmt_ip = dict(required=True),
+ mgmt_gw = dict(required=True),
+ new_login = dict(required=True),
+ new_password = dict(required=True),
+ new_root_password = dict(required=True),
))
try:
@@ -228,4 +195,3 @@ def main():
from ansible.module_utils.basic import *
main()
-
diff --git a/ansible/roles/vm_set/library/ptf_network_inj.py b/ansible/roles/vm_set/library/ptf_network_inj.py
deleted file mode 100644
index ee41973a2cc..00000000000
--- a/ansible/roles/vm_set/library/ptf_network_inj.py
+++ /dev/null
@@ -1,257 +0,0 @@
-#!/usr/bin/python
-
-import subprocess
-from docker import Client
-from ansible.module_utils.basic import *
-
-DOCUMENTATION = '''
----
-module: ptf_network_inj.py
-version_added: "0.1"
-author: Pavel Shirshov (pavelsh@microsoft.com)
-short_description: Generate virtual network for an injected ptf container
-description:
- - This module generates 32 (by default) fp internal network interfaces with names 'eth0'..'eth31', and internal management interface with a name 'mgmt'.
- - The internal fp network interfaces are interfaces which is 'injected' inside of vm_set openvswitch bridges
- - The management interface is connected to host mgmt bridge using veth pair.
-
-Parameters:
- - ptf_name: name of a ptf container
- - ctr_num: a number of ptf container
- - num_of_ports: number of FP ports, 32 by default
- - vlan_base: the first vlan for the network
- - fp_mtu: MTU for FP ports
- - mgmt_ip_addr: ip address for mgmt port (with network length)
- - mgmt_ip_gw: default gateway for mgmt address
- - mgmt_bridge: a name of the management bridge (host network)
-'''
-
-EXAMPLES = '''
-- name: Create internal network for the docker container
- ptf_network_inj:
- ptf_name: ptf_{{ id }}
- ctr_num: "{{ id }}"
- vlan_base: 101
- fp_mtu: 9216
- mgmt_ip_addr: "10.255.0.198"
- mgmt_ip_gw: "10.255.0.1"
- mgmt_bridge: "br1"
-
-'''
-
-
-DEFAULT_MTU = 0
-DEFAULT_N_PORTS = 32
-
-
-class PTFNetwork(object):
-
- def __init__(self, ptf_name, ctr_num, fp_mtu=DEFAULT_MTU):
- self.ptf_name = ptf_name
- self.ctr_num = ctr_num
- self.fp_mtu = fp_mtu
-
- self.pid = PTFNetwork.get_pid(ptf_name)
-
- return
-
- @staticmethod
- def get_pid(ptf_name):
- cli = Client(base_url='unix://var/run/docker.sock')
- result = cli.inspect_container(ptf_name)
-
- return result['State']['Pid']
-
- @staticmethod
- def cmd(cmdline):
- cmd = cmdline.split(' ')
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = process.communicate()
- ret_code = process.returncode
-
- if ret_code != 0:
- raise Exception("ret_code=%d, error message=%s. cmd=%s" % (ret_code, stderr, cmdline))
-
- return stdout
-
- @staticmethod
- def brctl(cmdline):
- out = PTFNetwork.cmd(cmdline)
-
- br_to_ifs = {}
- if_to_br = {}
-
- rows = out.split('\n')[1:]
- cur_br = None
- for row in rows:
- if len(row) == 0:
- continue
- terms = row.split()
- if not row[0].isspace():
- cur_br = terms[0]
- br_to_ifs[cur_br] = []
- if len(terms) > 3:
- br_to_ifs[cur_br].append(terms[3])
- if_to_br[terms[3]] = cur_br
- else:
- br_to_ifs[cur_br].append(terms[0])
- if_to_br[terms[0]] = cur_br
-
- return br_to_ifs, if_to_br
-
- @staticmethod
- def ifconfig(cmdline):
- out = PTFNetwork.cmd(cmdline)
-
- ifaces = set()
-
- rows = out.split('\n')
- for row in rows:
- if len(row) == 0:
- continue
- terms = row.split()
- if not row[0].isspace():
- ifaces.add(terms[0])
-
- return ifaces
-
- def update(self):
- self.host_br_to_ifs, self.host_if_to_br = PTFNetwork.brctl('brctl show')
- self.host_ifaces = PTFNetwork.ifconfig('ifconfig -a')
- self.ctr_ifaces = PTFNetwork.ifconfig('nsenter -t %s -n ifconfig -a' % self.pid)
-
- return
-
- def add_br_if_to_docker(self, bridge, ext_if, int_if):
- self.update()
-
- if ext_if not in self.host_ifaces:
- cmd1 = "ip link add %s type veth peer name %s" % (ext_if, int_if)
- PTFNetwork.cmd(cmd1)
-
- if ext_if not in self.host_if_to_br:
- cmd2 = "brctl addif %s %s" % (bridge, ext_if)
- PTFNetwork.cmd(cmd2)
-
- cmd3 = "ip link set %s up" % ext_if
- PTFNetwork.cmd(cmd3)
-
- self.update()
-
- if int_if in self.host_ifaces and int_if not in self.ctr_ifaces:
- cmd4 = "ip link set netns %s dev %s" % (self.pid, int_if)
- PTFNetwork.cmd(cmd4)
-
- self.update()
-
- cmd5 = "nsenter -t %s -n ip link set %s up" % (self.pid, int_if)
- PTFNetwork.cmd(cmd5)
-
- return
-
- def add_ip_to_int_if(self, int_if, mgmt_ip_addr, mgmt_gw):
- self.update()
- if int_if in self.ctr_ifaces:
- cmd_1 = "nsenter -t %s -n ip addr flush dev %s" % (self.pid, int_if)
- PTFNetwork.cmd(cmd_1)
- cmd_2 = "nsenter -t %s -n ip addr add %s dev %s" % (self.pid, mgmt_ip_addr, int_if)
- PTFNetwork.cmd(cmd_2)
- cmd_3 = "nsenter -t %s -n ip route add default via %s dev %s" % (self.pid, mgmt_gw, int_if )
- PTFNetwork.cmd(cmd_3)
-
- return
-
- def add_veth_if_to_docker(self, ext_if, int_if):
- self.update()
-
- t_int_if = int_if + '_t'
- if ext_if not in self.host_ifaces:
- cmd1 = "ip link add %s type veth peer name %s" % (ext_if, t_int_if)
- PTFNetwork.cmd(cmd1)
-
- self.update()
-
- if self.fp_mtu != DEFAULT_MTU:
- cmd = "ip link set dev %s mtu %d" % (ext_if, self.fp_mtu)
- PTFNetwork.cmd(cmd)
- if t_int_if in self.host_ifaces:
- cmd = "ip link set dev %s mtu %d" % (t_int_if, self.fp_mtu)
- PTFNetwork.cmd(cmd)
- elif t_int_if in self.ctr_ifaces:
- cmd = "nsenter -t %s -n ip link set dev %s mtu %d" % (self.pid, t_int_if, self.fp_mtu)
- PTFNetwork.cmd(cmd)
- elif int_if in self.ctr_ifaces:
- cmd = "nsenter -t %s -n ip link set dev %s mtu %d" % (self.pid, int_if, self.fp_mtu)
- PTFNetwork.cmd(cmd)
-
- cmd2 = "ip link set %s up" % ext_if
- PTFNetwork.cmd(cmd2)
-
- self.update()
-
- if t_int_if in self.host_ifaces and t_int_if not in self.ctr_ifaces and int_if not in self.ctr_ifaces:
- cmd3 = "ip link set netns %s dev %s" % (self.pid, t_int_if)
- PTFNetwork.cmd(cmd3)
-
- self.update()
-
- if t_int_if in self.ctr_ifaces and int_if not in self.ctr_ifaces:
- cmd4 = "nsenter -t %s -n ip link set dev %s name %s" % (self.pid, t_int_if, int_if)
- PTFNetwork.cmd(cmd4)
-
- cmd5 = "nsenter -t %s -n ip link set %s up" % (self.pid, int_if)
- PTFNetwork.cmd(cmd5)
-
- return
-
- def add_fp_ports(self, num_of_ports, vlan_base):
- for i in xrange(num_of_ports):
- vlan = vlan_base + i
- ext_if = 'inje-%d-%d' % (self.ctr_num, i)
- int_if = 'eth%d' % i
- self.add_veth_if_to_docker(ext_if, int_if)
-
- return
-
- def add_mgmt_port(self, mgmt_bridge, mgmt_ip, mgmt_gw):
- self.add_br_if_to_docker(mgmt_bridge, "ptf-mgmti-%d" % self.ctr_num, "mgmt")
- self.add_ip_to_int_if("mgmt", mgmt_ip, mgmt_gw)
-
- return
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- ptf_name=dict(required=True, type='str'),
- ctr_num=dict(required=True, type='int'),
- num_of_ports=dict(required=False, type='int', default=DEFAULT_N_PORTS),
- vlan_base=dict(required=True, type='int'),
- fp_mtu=dict(required=False, type='int', default=DEFAULT_MTU),
- mgmt_ip_addr=dict(required=True, type='str'),
- mgmt_ip_gw=dict(required=True, type='str'),
- mgmt_bridge=dict(required=True, type='str')),
- supports_check_mode=False)
-
- ptf_name = module.params['ptf_name']
- ctr_num = module.params['ctr_num']
- num_of_ports = module.params['num_of_ports']
- vlan_base = module.params['vlan_base']
- fp_mtu = module.params['fp_mtu']
- mgmt_ip_addr = module.params['mgmt_ip_addr']
- mgmt_ip_gw = module.params['mgmt_ip_gw']
- mgmt_bridge = module.params['mgmt_bridge']
-
- try:
- net = PTFNetwork(ptf_name, ctr_num, fp_mtu)
- net.add_mgmt_port(mgmt_bridge, mgmt_ip_addr, mgmt_ip_gw)
- net.add_fp_ports(num_of_ports, vlan_base)
-
- except Exception as error:
- module.fail_json(msg=str(error))
-
- module.exit_json(changed=True)
-
-if __name__ == "__main__":
- main()
-
diff --git a/ansible/roles/vm_set/library/vm_network.py b/ansible/roles/vm_set/library/vm_network.py
deleted file mode 100644
index 5fdddb28d83..00000000000
--- a/ansible/roles/vm_set/library/vm_network.py
+++ /dev/null
@@ -1,328 +0,0 @@
-#!/usr/bin/python
-
-import subprocess
-import re
-from docker import Client
-from ansible.module_utils.basic import *
-
-DOCUMENTATION = '''
----
-module: vm_network_create
-version_added: "0.1"
-author: Pavel Shirshov (pavelsh@microsoft.com)
-short_description: Generate virtual network for a set of VMs
-description:
- - With cmd: 'create' the module:
- - creates 32*8 ovs bridges with name template "br-vs{{ vm_set_id }}-vm{{ vm_set_dict[]['num']}}-{{ 0..7 }}" which will be used by FP port of VMs
- - creates a linux bridge with name {{ port1_bridge }} for backplane connectivity between VMs
- - With cmd: 'destroy' the module:
- - destroys 32*8 ovs bridges with name template "br-vs{{ vm_set_id }}-vm{{ vm_set_dict[]['num']}}-{{ 0..7 }}" which were used by FP port of VMs
- - destroys a linux bridge with name {{ port1_bridge }} for backplane connectivity between VMs
- - With cmd: 'bind' the module:
- - creates 32 vlan interfaces on the external interface
- - bind this interfaces to the ovs bridges which were created by 'create' command
- - bind corresponing interface from ptf_injected container to the ovs bridges
- - With cmd: 'unbind' the module:
- - destroys 32 vlan interfaces from the external interface
-
-Parameters:
- - cmd: One of the commands: 'create', 'bind', 'unbind', 'destroy'
- - vm_set_id: identifier for the VM set, a number
- - port1_bridge: name of the bridge which will be created for the backplane connectivity
- - vm_set_dict: dictionary with VM parameters. Check host_vars/STR-ACS-SERV-0x.yml for details
- - fp_mtu: MTU for FP ports
- - ext_iface: physical interface which will be used for for vlan creation
- - vlan_base: the first vlan for the network
-'''
-
-EXAMPLES = '''
-- name: Create VM set network. vm set {{ id }}
- vm_network:
- cmd: 'create'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
-'''
-
-DEFAULT_MTU = 0
-NUM_FP_VLANS_PER_FP = 8
-OVS_BRIDGE_TEMPLATE = 'br-vs%d-vm%d-%d'
-INJECTED_INTERFACES_TEMPLATE = "inje-%d-%d"
-
-class VMNetwork(object):
-
- def __init__(self, vm_set_id, port1_bridge, vm_set_dict, ext_iface, vlan_base, fp_mtu=DEFAULT_MTU):
- self.vm_set_id = vm_set_id
- self.port1_bridge = port1_bridge
- self.vm_set_dict = vm_set_dict
- self.ext_iface = ext_iface
- self.vlan_base = vlan_base
- self.fp_mtu = fp_mtu
-
- self.host_ifaces = VMNetwork.ifconfig('ifconfig -a')
-
- return
-
- def create_port1_bridge(self):
- if self.port1_bridge not in self.host_ifaces:
- VMNetwork.cmd('brctl addbr %s' % self.port1_bridge)
-
- VMNetwork.cmd('ifconfig %s up' % self.port1_bridge)
-
- return
-
- def destroy_port1_bridge(self):
- if self.port1_bridge in self.host_ifaces:
- VMNetwork.cmd('ifconfig %s down' % self.port1_bridge)
- VMNetwork.cmd('brctl delbr %s' % self.port1_bridge)
-
- return
-
- def create_fp_bridges(self):
- for vm in self.vm_set_dict.itervalues():
- for vlan_num in xrange(NUM_FP_VLANS_PER_FP):
- self.create_fp_bridge(vm["num"], vlan_num)
-
- return
-
- def create_fp_bridge(self, vm_num, vlan_num):
- vlan_name = OVS_BRIDGE_TEMPLATE % (self.vm_set_id, int(vm_num), vlan_num)
-
- if vlan_name not in self.host_ifaces:
- VMNetwork.cmd('ovs-vsctl add-br %s' % vlan_name)
-
- if self.fp_mtu != DEFAULT_MTU:
- VMNetwork.cmd('ifconfig %s mtu %d' % (vlan_name, self.fp_mtu))
-
- VMNetwork.cmd('ifconfig %s up' % vlan_name)
-
- return
-
- def destroy_fp_bridges(self):
- for vm in self.vm_set_dict.itervalues():
- for vlan_num in xrange(NUM_FP_VLANS_PER_FP):
- self.destroy_fp_bridge(vm["num"], vlan_num)
-
- return
-
-
- def destroy_fp_bridge(self, vm_num, vlan_num):
- vlan_name = OVS_BRIDGE_TEMPLATE % (self.vm_set_id, int(vm_num), vlan_num)
-
- if vlan_name in self.host_ifaces:
- VMNetwork.cmd('ifconfig %s down' % vlan_name)
- VMNetwork.cmd('ovs-vsctl del-br %s' % vlan_name)
-
- return
-
- def up_ext_iface(self):
- if self.ext_iface in self.host_ifaces:
- VMNetwork.cmd('ifconfig %s up' % self.ext_iface)
-
- return
-
- def check_vlans(self, vlans_str, vlans):
- if len(vlans) == 0:
- return
-
- if len(vlans) > 8:
- raise Exception("Wrong vlans parameter. Too many vlans. Maximum is 8: %s" % vlans_str)
-
- for vlan in vlans_str.split(','):
- if not vlan.isdigit():
- raise Exception("Wrong vlans parameter: %s" % vlans_str)
-
- for vlan in vlans:
- if int(vlan) > 31:
- raise Exception("Vlan offset %s supposed to be not more then 31: %s" % (vlan, vlans_str))
-
- return
-
- def bind(self):
- for vm in self.vm_set_dict.itervalues():
- vm_num = vm['num']
- vlans_str = vm['vlans']
- vlans = [int(vlan) for vlan in vlans_str.split(',')]
- self.check_vlans(vlans_str, vlans)
- for vlan_num, vlan in enumerate(vlans):
- vlan_id = self.vlan_base + vlan
- vlan_iface = "%s.%d" % (self.ext_iface, vlan_id)
- injected_iface = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_id, vlan)
- port0_bridge = OVS_BRIDGE_TEMPLATE % (self.vm_set_id, int(vm_num), vlan_num)
- self.create_phys_vlan(vlan_iface, vlan_id)
- self.bind_phys_vlan(port0_bridge, vlan_iface, injected_iface)
-
- return
-
- def create_phys_vlan(self, vlan_iface, vlan_id):
- if vlan_iface not in self.host_ifaces:
- VMNetwork.cmd('vconfig add %s %d' % (self.ext_iface, vlan_id))
-
- VMNetwork.cmd('ifconfig %s up' % vlan_iface)
-
- return
-
- def bind_phys_vlan(self, br_name, vlan_iface, injected_iface):
- ports = VMNetwork.get_ovs_br_ports(br_name)
-
- if injected_iface not in ports:
- VMNetwork.cmd('ovs-vsctl add-port %s %s' % (br_name, injected_iface))
-
- if vlan_iface not in ports:
- VMNetwork.cmd('ovs-vsctl add-port %s %s' % (br_name, vlan_iface))
-
- bindings = VMNetwork.get_ovs_port_bindings(br_name)
- vlan_iface_id = bindings[vlan_iface]
-
- # clear old bindings
- VMNetwork.cmd('ovs-ofctl del-flows %s' % br_name)
-
- # Add flow from a VM to an external iface
- VMNetwork.cmd("ovs-ofctl add-flow %s table=0,in_port=1,action=output:%s" % (br_name, vlan_iface_id))
-
- # Add flow from external iface to a VM and a ptf container
- VMNetwork.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:1,2" % (br_name, vlan_iface_id))
-
- # Add flow from a ptf container to an external iface
- VMNetwork.cmd("ovs-ofctl add-flow %s table=0,in_port=2,action=output:%s" % (br_name, vlan_iface_id))
-
- return
-
- def unbind(self):
- # try vlans from the host_vars
- for vm in self.vm_set_dict.itervalues():
- vm_num = vm['num']
- vlans_str = vm['vlans']
- vlans = [int(vlan) for vlan in vlans_str.split(',')]
- self.check_vlans(vlans_str, vlans)
- for vlan_num, vlan in enumerate(vlans):
- vlan_id = self.vlan_base + vlan
- vlan_iface = "%s.%d" % (self.ext_iface, vlan_id)
- injected_iface = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_id, vlan)
- port0_bridge = OVS_BRIDGE_TEMPLATE % (self.vm_set_id, int(vm_num), vlan_num)
- self.unbind_phys_vlan(port0_bridge, vlan_iface)
- self.destroy_phys_vlan(vlan_iface)
-
- # try vlans from the ovs db
- for vm in self.vm_set_dict.itervalues():
- vm_num = vm['num']
- for vlan_num in xrange(NUM_FP_VLANS_PER_FP):
- bridge_name = OVS_BRIDGE_TEMPLATE % (self.vm_set_id, int(vm_num), vlan_num)
- ports = VMNetwork.get_ovs_port_bindings(bridge_name)
- for port in ports.iterkeys():
- if self.ext_iface in port:
- self.unbind_phys_vlan(bridge_name, port)
- self.destroy_phys_vlan(port)
-
- return
-
- def destroy_phys_vlan(self, vlan_iface):
- if vlan_iface in self.host_ifaces:
- VMNetwork.cmd('ifconfig %s down' % vlan_iface)
- VMNetwork.cmd('vconfig rem %s' % vlan_iface)
-
- return
-
- def unbind_phys_vlan(self, br_name, vlan_iface):
- ports = VMNetwork.get_ovs_br_ports(br_name)
-
- if vlan_iface in ports:
- VMNetwork.cmd('ovs-vsctl del-port %s %s' % (br_name, vlan_iface))
-
- return
-
- @staticmethod
- def cmd(cmdline):
- cmd = cmdline.split(' ')
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = process.communicate()
- ret_code = process.returncode
-
- if ret_code != 0:
- raise Exception("ret_code=%d, error message=%s. cmd=%s" % (ret_code, stderr, cmdline))
-
- return stdout
-
- @staticmethod
- def get_ovs_br_ports(bridge):
- out = VMNetwork.cmd('ovs-vsctl list-ports %s' % bridge)
- return set(out.split('\n'))
-
- @staticmethod
- def get_ovs_port_bindings(bridge):
- out = VMNetwork.cmd('ovs-ofctl show %s' % bridge)
- lines = out.split('\n')
- result = {}
- for line in lines:
- matched = re.match(r'^\s+(\S+)\((\S+)\):\s+addr:.+$', line)
- if matched:
- port_id = matched.group(1)
- iface_name = matched.group(2)
- result[iface_name] = port_id
-
- return result
-
- @staticmethod
- def ifconfig(cmdline):
- out = VMNetwork.cmd(cmdline)
-
- ifaces = set()
-
- rows = out.split('\n')
- for row in rows:
- if len(row) == 0:
- continue
- terms = row.split()
- if not row[0].isspace():
- ifaces.add(terms[0])
-
- return ifaces
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- cmd=dict(required=True, choices=['create', 'bind', 'unbind', 'destroy']),
- vm_set_id=dict(required=True, type='int'),
- port1_bridge=dict(required=True, type='str'),
- vm_set_dict=dict(required=True, type='dict'),
- fp_mtu=dict(required=False, type='int', default=DEFAULT_MTU),
- ext_iface=dict(required=True, type='str'),
- vlan_base=dict(required=True, type='int')),
- supports_check_mode=False)
-
- cmd = module.params['cmd']
- vm_set_id = module.params['vm_set_id']
- port1_bridge = module.params['port1_bridge']
- vm_set_dict = module.params['vm_set_dict']
- fp_mtu = module.params['fp_mtu']
- ext_iface = module.params['ext_iface']
- vlan_base = module.params['vlan_base']
-
- try:
- net = VMNetwork(vm_set_id, port1_bridge, vm_set_dict, ext_iface, vlan_base, fp_mtu)
- if cmd == 'create':
- net.create_port1_bridge()
- net.create_fp_bridges()
- elif cmd == 'destroy':
- net.destroy_port1_bridge()
- net.destroy_fp_bridges()
- elif cmd == 'bind':
- net.up_ext_iface()
- net.bind()
- elif cmd == 'unbind':
- net.unbind()
- else:
- raise Exception("Got wrong cmd: %s. Ansible bug?" % cmd)
-
- except Exception as error:
- module.fail_json(msg=str(error))
-
- module.exit_json(changed=True)
-
-if __name__ == "__main__":
- main()
-
diff --git a/ansible/roles/vm_set/library/vm_topology.py b/ansible/roles/vm_set/library/vm_topology.py
new file mode 100644
index 00000000000..e46cabe6342
--- /dev/null
+++ b/ansible/roles/vm_set/library/vm_topology.py
@@ -0,0 +1,749 @@
+#!/usr/bin/python
+
+import subprocess
+import re
+import os
+import os.path
+from docker import Client
+from ansible.module_utils.basic import *
+import traceback
+from pprint import pprint
+
+DOCUMENTATION = '''
+---
+module: vm_topology
+version_added: "0.1"
+author: Pavel Shirshov (pavelsh@microsoft.com)
+short_description: Create a custom virtual topology for vm_sets
+description:
+ - With cmd: 'create' the module:
+ - creates a bridges for every VM name in vm_names which will be used for back plane connections
+ - creates len(vm_names)*8 ovs bridges with name template "br-{{ vm_name }}-{{ 0..7 }}" which will be used by FP port of VMs
+ - With cmd: 'destroy' the module:
+ - destroys ovs bridges which were created with 'create' cmd
+ - With cmd: 'bind' the module:
+ - inserts mgmt interface inside of the docker container with name "ptf_{{vm_set_name}}"
+ - assigns ip address and default route to the mgmt interface
+ - inserts physical vlans into the docker container to represent endhosts
+ - binds internal interfaces of the docker container to correspoinding VM ports
+ - connects interfaces "Ethernet9" of every VM in current vm set to each other
+ - connect vlan interface to bridges representing vm set fp ports
+ - with cmd: 'renumber' the module:
+ - disconnect vlan interface to bridges representing vm set fp ports
+ - inserts mgmt interface inside of the docker container with name "ptf_{{vm_set_name}}"
+ - assigns ip address and default route to the mgmt interface
+ - inserts physical vlans into the docker container to represent endhosts
+ - binds internal interfaces of the docker container to correspoinding VM ports
+ - With cmd: 'unbind' the module:
+ - destroys everything what was created with command 'bind'
+
+
+Parameters:
+ - cmd: One of the commands: 'create', 'bind', 'renumber', 'unbind', 'destroy'
+ - vm_set_name: name of the current vm set. It will be used for generation of interface names
+ - topo: dictionary with VMs topology. Check vars/topo_*.yml for details
+ - vm_names: list of VMs represented on a current host
+ - vm_base: which VM consider the first VM in the current vm set
+ - vlan_base: the first vlan for the network
+ - mgmt_ip_addr: ip address with prefixlen for the injected docker container
+ - mgmt_ip_gw: default gateway for the injected docker container
+ - mgmt_bridge: a bridge which is used as mgmt bridge on the host
+ - ext_iface: physical interface which will be used for for vlan creation
+ - fp_mtu: MTU for FP ports
+'''
+
+EXAMPLES = '''
+- name: Create VMs network
+ vm_network:
+ cmd: 'create'
+ vm_names: "{{ VM_hosts }}"
+ fp_mtu: "{{ fp_mtu_size }}"
+
+- name: Bind topology {{ topo }} to VMs. base vm = {{ VM_base }} base vlan = {{ vlan_base }}
+ vm_topology:
+ cmd: "bind"
+ vm_set_name: "{{ vm_set_name }}"
+ topo: "{{ topology }}"
+ vm_names: "{{ VM_hosts }}"
+ vm_base: "{{ VM_base }}"
+ vlan_base: "{{ vlan_base }}"
+ mgmt_ip_addr: "{{ ptf_ip }}"
+ mgmt_ip_gw: "{{ mgmt_gw }}"
+ mgmt_bridge: "{{ mgmt_bridge }}"
+ ext_iface: "{{ external_iface }}"
+ fp_mtu: "{{ fp_mtu_size }}"
+'''
+
+
+DEFAULT_MTU = 0
+NUM_FP_VLANS_PER_FP = 8
+VM_SET_NAME_MAX_LEN = 8 # used in interface names. So restricted
+MGMT_BR_NAME = 'mgmt'
+CMD_DEBUG_FNAME = '/tmp/vmtopology.cmds.txt'
+EXCEPTION_DEBUG_FNAME = '/tmp/vmtopology.exception.txt'
+
+OVS_FP_BRIDGE_TEMPLATE = 'br-%s-%d'
+OVS_FP_TAP_TEMPLATE = '%s-t%d'
+OVS_BRIDGE_BACK_TEMPLATE = 'br-%s-back'
+INJECTED_INTERFACES_TEMPLATE = 'inje-%s-%d'
+PTF_NAME_TEMPLATE = 'ptf_%s'
+PTF_MGMT_IF_TEMPLATE = 'ptf-%s-m'
+ROOT_BACK_BR_TEMPLATE = 'br-b-%s'
+PTF_FP_IFACE_TEMPLATE = 'eth%d'
+BACK_ROOT_END_IF_TEMPLATE = 'veth-bb-%s'
+BACK_VM_END_IF_TEMPLATE = 'veth-bv-%s'
+
+
+class VMTopology(object):
+
+ def __init__(self, vm_names, fp_mtu):
+ self.vm_names = vm_names
+ self.fp_mtu = fp_mtu
+
+ self.host_ifaces = VMTopology.ifconfig('ifconfig -a')
+
+ return
+
+ def init(self, vm_set_name, topo, vm_base, vlan_base, ext_iface, ptf_exists=True):
+ self.vm_set_name = vm_set_name
+ if 'VMs' in topo:
+ self.VMs = topo['VMs']
+ self.vm_base = vm_base
+ if vm_base in self.vm_names:
+ self.vm_base_index = self.vm_names.index(vm_base)
+ else:
+ raise Exception('VM_base "%s" should be presented in current vm_names: %s' % (vm_base, str(self.vm_names)))
+ else:
+ self.VMs = {}
+
+ if 'host_interfaces' in topo:
+ self.host_interfaces = topo['host_interfaces']
+ else:
+ self.host_interfaces = []
+
+ self.vlan_base = vlan_base
+ self.ext_iface = ext_iface
+
+ self.injected_fp_ports = self.extract_vm_vlans()
+
+ if ptf_exists:
+ self.pid = VMTopology.get_pid(PTF_NAME_TEMPLATE % vm_set_name)
+ else:
+ self.pid = None
+
+ self.update()
+
+ return
+
+ def update(self):
+ self.host_br_to_ifs, self.host_if_to_br = VMTopology.brctl('brctl show')
+ self.host_ifaces = VMTopology.ifconfig('ifconfig -a')
+ if self.pid is not None:
+ self.ctr_ifaces = VMTopology.ifconfig('nsenter -t %s -n ifconfig -a' % self.pid)
+ else:
+ self.ctr_ifaces = None
+
+ return
+
+ def extract_vm_vlans(self):
+ vlans = []
+ for attr in self.VMs.itervalues():
+ vlans.extend(attr['vlans'])
+
+ return vlans
+
+ def create_bridges(self):
+ for vm in self.vm_names:
+ for vlan_num in xrange(NUM_FP_VLANS_PER_FP):
+ vlan_br_name = OVS_FP_BRIDGE_TEMPLATE % (vm, vlan_num)
+ self.create_bridge(vlan_br_name)
+ port1_br_name = OVS_BRIDGE_BACK_TEMPLATE = 'br-%s-back' % vm
+ self.create_bridge(port1_br_name)
+
+ return
+
+ def create_bridge(self, vlan_name):
+ if vlan_name not in self.host_ifaces:
+ VMTopology.cmd('ovs-vsctl add-br %s' % vlan_name)
+
+ if self.fp_mtu != DEFAULT_MTU:
+ VMTopology.cmd('ifconfig %s mtu %d' % (vlan_name, self.fp_mtu))
+
+ VMTopology.cmd('ifconfig %s up' % vlan_name)
+
+ return
+
+ def destroy_bridges(self):
+ for vm in self.vm_names:
+ for vlan_num in xrange(NUM_FP_VLANS_PER_FP):
+ vlan_br_name = OVS_FP_BRIDGE_TEMPLATE % (vm, vlan_num)
+ self.destroy_bridge(vlan_br_name)
+ port1_br_name = OVS_BRIDGE_BACK_TEMPLATE = 'br-%s-back' % vm
+ self.destroy_bridge(port1_br_name)
+
+ return
+
+ def destroy_bridge(self, bridge_name):
+ if bridge_name in self.host_ifaces:
+ VMTopology.cmd('ifconfig %s down' % bridge_name)
+ VMTopology.cmd('ovs-vsctl del-br %s' % bridge_name)
+
+ return
+
+ def add_veth_ports_to_docker(self):
+ for vlan in self.injected_fp_ports:
+ ext_if = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, vlan)
+ int_if = PTF_FP_IFACE_TEMPLATE % vlan
+ self.add_veth_if_to_docker(ext_if, int_if)
+
+ return
+
+ def add_mgmt_port_to_docker(self, mgmt_bridge, mgmt_ip, mgmt_gw):
+ self.add_br_if_to_docker(mgmt_bridge, PTF_MGMT_IF_TEMPLATE % self.vm_set_name, MGMT_BR_NAME)
+ self.add_ip_to_docker_if(MGMT_BR_NAME, mgmt_ip, mgmt_gw)
+
+ return
+
+ def add_br_if_to_docker(self, bridge, ext_if, int_if):
+ self.update()
+
+ if ext_if not in self.host_ifaces:
+ VMTopology.cmd("ip link add %s type veth peer name %s" % (ext_if, int_if))
+
+ if ext_if not in self.host_if_to_br:
+ VMTopology.cmd("brctl addif %s %s" % (bridge, ext_if))
+
+ VMTopology.iface_up(ext_if)
+
+ self.update()
+ if int_if in self.host_ifaces and int_if not in self.ctr_ifaces:
+ VMTopology.cmd("ip link set netns %s dev %s" % (self.pid, int_if))
+
+ VMTopology.iface_up(int_if, self.pid)
+
+ return
+
+ def add_ip_to_docker_if(self, int_if, mgmt_ip_addr, mgmt_gw):
+ self.update()
+ if int_if in self.ctr_ifaces:
+ VMTopology.cmd("nsenter -t %s -n ip addr flush dev %s" % (self.pid, int_if))
+ VMTopology.cmd("nsenter -t %s -n ip addr add %s dev %s" % (self.pid, mgmt_ip_addr, int_if))
+ VMTopology.cmd("nsenter -t %s -n ip route add default via %s dev %s" % (self.pid, mgmt_gw, int_if))
+
+ return
+
+ def add_phy_if_to_docker(self, iface_name, vlan):
+ int_if = "%s.%d" % (self.ext_iface, vlan)
+
+ if int_if not in self.host_ifaces and iface_name not in self.ctr_ifaces and int_if not in self.ctr_ifaces:
+ VMTopology.cmd("vconfig add %s %s" % (self.ext_iface, vlan))
+
+ self.update()
+ if int_if in self.host_ifaces and int_if not in self.ctr_ifaces and iface_name not in self.ctr_ifaces:
+ VMTopology.cmd("ip link set netns %s dev %s" % (self.pid, int_if))
+
+ self.update()
+ if int_if in self.ctr_ifaces and iface_name not in self.ctr_ifaces:
+ VMTopology.cmd("nsenter -t %s -n ip link set dev %s name %s" % (self.pid, int_if, iface_name))
+
+ VMTopology.iface_up(iface_name, self.pid)
+
+ return
+
+ def add_veth_if_to_docker(self, ext_if, int_if):
+ self.update()
+
+ t_int_if = int_if + '_t'
+ if ext_if not in self.host_ifaces:
+ VMTopology.cmd("ip link add %s type veth peer name %s" % (ext_if, t_int_if))
+
+ self.update()
+
+ if self.fp_mtu != DEFAULT_MTU:
+ VMTopology.cmd("ip link set dev %s mtu %d" % (ext_if, self.fp_mtu))
+ if t_int_if in self.host_ifaces:
+ VMTopology.cmd("ip link set dev %s mtu %d" % (t_int_if, self.fp_mtu))
+ elif t_int_if in self.ctr_ifaces:
+ VMTopology.cmd("nsenter -t %s -n ip link set dev %s mtu %d" % (self.pid, t_int_if, self.fp_mtu))
+ elif int_if in self.ctr_ifaces:
+ VMTopology.cmd("nsenter -t %s -n ip link set dev %s mtu %d" % (self.pid, int_if, self.fp_mtu))
+
+ VMTopology.iface_up(ext_if)
+
+ self.update()
+
+ if t_int_if in self.host_ifaces and t_int_if not in self.ctr_ifaces and int_if not in self.ctr_ifaces:
+ VMTopology.cmd("ip link set netns %s dev %s" % (self.pid, t_int_if))
+
+ self.update()
+
+ if t_int_if in self.ctr_ifaces and int_if not in self.ctr_ifaces:
+ VMTopology.cmd("nsenter -t %s -n ip link set dev %s name %s" % (self.pid, t_int_if, int_if))
+
+ VMTopology.iface_up(int_if, self.pid)
+
+ return
+
+ def up_ext_iface(self):
+ if self.ext_iface in self.host_interfaces:
+ VMTopology.iface_up(self.ext_iface)
+
+ return
+
+ def bind_fp_ports(self):
+ for attr in self.VMs.itervalues():
+ for vlan_num, vlan in enumerate(attr['vlans']):
+ vlan_id = self.vlan_base + vlan
+ vlan_iface = "%s.%d" % (self.ext_iface, vlan_id)
+ injected_iface = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, vlan)
+ port0_bridge = OVS_FP_BRIDGE_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], vlan_num)
+ vm_tap = OVS_FP_TAP_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], vlan_num)
+ self.create_phys_vlan(vlan_iface, vlan_id)
+ self.bind_phys_vlan(port0_bridge, vlan_iface, injected_iface, vm_tap)
+
+ return
+
+ def unbind_fp_ports(self):
+ for attr in self.VMs.itervalues():
+ for vlan_num, vlan in enumerate(attr['vlans']):
+ vlan_id = self.vlan_base + vlan
+ vlan_iface = "%s.%d" % (self.ext_iface, vlan_id)
+ injected_iface = INJECTED_INTERFACES_TEMPLATE % (self.vm_set_name, vlan)
+ port0_bridge = OVS_FP_BRIDGE_TEMPLATE % (self.vm_names[self.vm_base_index + attr['vm_offset']], vlan_num)
+ self.unbind_phys_vlan(port0_bridge, injected_iface)
+ self.unbind_phys_vlan(port0_bridge, vlan_iface)
+ self.destroy_phys_vlan(vlan_iface)
+
+ return
+
+ def bind_vm_backplane(self):
+ root_back_bridge = ROOT_BACK_BR_TEMPLATE % self.vm_set_name
+
+ if root_back_bridge not in self.host_ifaces:
+ VMTopology.cmd('ovs-vsctl add-br %s' % root_back_bridge)
+
+ VMTopology.iface_up(root_back_bridge)
+
+ for attr in self.VMs.itervalues():
+ vm_name = self.vm_names[self.vm_base_index + attr['vm_offset']]
+ br_name = OVS_BRIDGE_BACK_TEMPLATE % vm_name
+
+ back_int_name = BACK_ROOT_END_IF_TEMPLATE % vm_name
+ vm_int_name = BACK_VM_END_IF_TEMPLATE % vm_name
+
+ if back_int_name not in self.host_ifaces:
+ VMTopology.cmd("ip link add %s type veth peer name %s" % (back_int_name, vm_int_name))
+
+ if vm_int_name not in VMTopology.get_ovs_br_ports(br_name):
+ VMTopology.cmd("ovs-vsctl add-port %s %s" % (br_name, vm_int_name))
+
+ if back_int_name not in VMTopology.get_ovs_br_ports(root_back_bridge):
+ VMTopology.cmd("ovs-vsctl add-port %s %s" % (root_back_bridge, back_int_name))
+
+ VMTopology.iface_up(vm_int_name)
+ VMTopology.iface_up(back_int_name)
+
+ return
+
+ def unbind_vm_backplane(self):
+ root_back_bridge = ROOT_BACK_BR_TEMPLATE % self.vm_set_name
+
+ if root_back_bridge in self.host_ifaces:
+ VMTopology.iface_down(root_back_bridge)
+ VMTopology.cmd('ovs-vsctl del-br %s' % root_back_bridge)
+
+ for attr in self.VMs.itervalues():
+ vm_name = self.vm_names[self.vm_base_index + attr['vm_offset']]
+ br_name = OVS_BRIDGE_BACK_TEMPLATE % vm_name
+
+ back_int_name = BACK_ROOT_END_IF_TEMPLATE % vm_name
+ vm_int_name = BACK_VM_END_IF_TEMPLATE % vm_name
+
+ self.unbind_phys_vlan(br_name, vm_int_name)
+
+ if back_int_name in self.host_ifaces:
+ VMTopology.iface_down(back_int_name)
+ VMTopology.cmd("ip link delete dev %s" % back_int_name)
+
+ return
+
+
+ def create_phys_vlan(self, vlan_iface, vlan_id):
+ if vlan_iface not in self.host_ifaces:
+ VMTopology.cmd('vconfig add %s %d' % (self.ext_iface, vlan_id))
+
+ VMTopology.iface_up(vlan_iface)
+
+ return
+
+ def bind_phys_vlan(self, br_name, vlan_iface, injected_iface, vm_iface):
+ ports = VMTopology.get_ovs_br_ports(br_name)
+
+ if injected_iface not in ports:
+ VMTopology.cmd('ovs-vsctl add-port %s %s' % (br_name, injected_iface))
+
+ if vlan_iface not in ports:
+ VMTopology.cmd('ovs-vsctl add-port %s %s' % (br_name, vlan_iface))
+
+ bindings = VMTopology.get_ovs_port_bindings(br_name)
+ vlan_iface_id = bindings[vlan_iface]
+ injected_iface_id = bindings[injected_iface]
+ vm_iface_id = bindings[vm_iface]
+
+ # clear old bindings
+ VMTopology.cmd('ovs-ofctl del-flows %s' % br_name)
+
+ # Add flow from a VM to an external iface
+ VMTopology.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:%s" % (br_name, vm_iface_id, vlan_iface_id))
+
+ # Add flow from external iface to a VM and a ptf container
+ VMTopology.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:%s,%s" % (br_name, vlan_iface_id, vm_iface_id, injected_iface_id))
+
+ # Add flow from a ptf container to an external iface
+ VMTopology.cmd("ovs-ofctl add-flow %s table=0,in_port=%s,action=output:%s" % (br_name, injected_iface_id, vlan_iface_id))
+
+ return
+
+ def unbind_phys_vlan(self, br_name, vlan_iface):
+ ports = VMTopology.get_ovs_br_ports(br_name)
+
+ if vlan_iface in ports:
+ VMTopology.cmd('ovs-vsctl del-port %s %s' % (br_name, vlan_iface))
+
+ return
+
+ def inject_host_ports(self):
+ self.update()
+ for vlan in self.host_interfaces:
+ self.add_phy_if_to_docker(PTF_FP_IFACE_TEMPLATE % vlan, self.vlan_base + vlan)
+
+ return
+
+ def destroy_phys_vlan(self, vlan_iface):
+ if vlan_iface in self.host_ifaces:
+ VMTopology.iface_down(vlan_iface)
+ VMTopology.cmd('vconfig rem %s' % vlan_iface)
+
+ return
+
+ @staticmethod
+ def iface_up(iface_name, pid=None):
+ return VMTopology.iface_updown(iface_name, 'up', pid)
+
+ @staticmethod
+ def iface_down(iface_name, pid=None):
+ return VMTopology.iface_updown(iface_name, 'down', pid)
+
+ @staticmethod
+ def iface_updown(iface_name, state, pid):
+ if pid is None:
+ return VMTopology.cmd('ip link set %s %s' % (iface_name, state))
+ else:
+ return VMTopology.cmd('nsenter -t %s -n ip link set %s %s' % (pid, iface_name, state))
+
+ @staticmethod
+ def cmd(cmdline):
+ with open(CMD_DEBUG_FNAME, 'a') as fp:
+ pprint("CMD: %s" % cmdline, fp)
+ cmd = cmdline.split(' ')
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ ret_code = process.returncode
+
+ if ret_code != 0:
+ raise Exception("ret_code=%d, error message=%s. cmd=%s" % (ret_code, stderr, cmdline))
+
+ with open(CMD_DEBUG_FNAME, 'a') as fp:
+ pprint("OUTPUT: %s" % stdout, fp)
+ return stdout
+
+ @staticmethod
+ def get_ovs_br_ports(bridge):
+ out = VMTopology.cmd('ovs-vsctl list-ports %s' % bridge)
+ return set(out.split('\n'))
+
+ @staticmethod
+ def get_ovs_port_bindings(bridge):
+ out = VMTopology.cmd('ovs-ofctl show %s' % bridge)
+ lines = out.split('\n')
+ result = {}
+ for line in lines:
+ matched = re.match(r'^\s+(\S+)\((\S+)\):\s+addr:.+$', line)
+ if matched:
+ port_id = matched.group(1)
+ iface_name = matched.group(2)
+ result[iface_name] = port_id
+
+ return result
+
+ @staticmethod
+ def ifconfig(cmdline):
+ out = VMTopology.cmd(cmdline)
+
+ ifaces = set()
+
+ rows = out.split('\n')
+ for row in rows:
+ if len(row) == 0:
+ continue
+ terms = row.split()
+ if not row[0].isspace():
+ ifaces.add(terms[0].rstrip(':'))
+
+ return ifaces
+
+ @staticmethod
+ def get_pid(ptf_name):
+ cli = Client(base_url='unix://var/run/docker.sock')
+ result = cli.inspect_container(ptf_name)
+
+ return result['State']['Pid']
+
+ @staticmethod
+ def brctl(cmdline):
+ out = VMTopology.cmd(cmdline)
+
+ br_to_ifs = {}
+ if_to_br = {}
+
+ rows = out.split('\n')[1:]
+ cur_br = None
+ for row in rows:
+ if len(row) == 0:
+ continue
+ terms = row.split()
+ if not row[0].isspace():
+ cur_br = terms[0]
+ br_to_ifs[cur_br] = []
+ if len(terms) > 3:
+ br_to_ifs[cur_br].append(terms[3])
+ if_to_br[terms[3]] = cur_br
+ else:
+ br_to_ifs[cur_br].append(terms[0])
+ if_to_br[terms[0]] = cur_br
+
+ return br_to_ifs, if_to_br
+
+ def find_base_vlan(self):
+ vlan_base = 0
+ for attr in self.VMs.itervalues():
+ vm_name = self.vm_names[self.vm_base_index + attr['vm_offset']]
+ if len(attr['vlans']) > 0:
+ br_name = OVS_FP_BRIDGE_TEMPLATE % (vm_name, 0)
+ out = VMTopology.cmd('ovs-vsctl list-ports %s' % br_name)
+ rows = out.split('\n')
+ for row in rows:
+ if row.startswith(self.ext_iface):
+ extracted_vlan = int(row[len(self.ext_iface)+1:])
+ return extracted_vlan - attr['vlans'][0]
+
+ raise Exception("Can't find previous vlan_base")
+
+def check_topo(topo):
+ hostif_exists = False
+ vms_exists = False
+ all_vlans = set()
+
+ if 'host_interfaces' in topo:
+ vlans = topo['host_interfaces']
+
+ if not isinstance(vlans, list):
+ raise Exception("topo['host_interfaces'] should be a list of integers")
+
+ for vlan in vlans:
+ if not isinstance(vlan, int) or vlan < 0:
+ raise Exception("topo['host_interfaces'] should be a list of integers")
+ if vlan in all_vlans:
+ raise Exception("topo['host_interfaces'] double use of vlan: %d" % vlan)
+ else:
+ all_vlans.add(vlan)
+
+ hostif_exists = True
+
+ if 'VMs' in topo:
+ VMs = topo['VMs']
+
+ if not isinstance(VMs, dict):
+ raise Exception("topo['VMs'] should be a dictionary")
+
+ for hostname, attrs in VMs.iteritems():
+ if 'vlans' not in attrs or not isinstance(attrs['vlans'], list):
+ raise Exception("topo['VMs']['%s'] should contain 'vlans' with a list of vlans" % hostname)
+
+ if 'vm_offset' not in attrs or not isinstance(attrs['vm_offset'], int):
+ raise Exception("topo['VMs']['%s'] should contain 'vm_offset' with a number" % hostname)
+
+ if len(attrs['vlans']) > NUM_FP_VLANS_PER_FP:
+ raise Exception("Wrong vlans parameter for hostname %s. Too many vlans. Maximum is %d" % (hostname, NUM_FP_VLANS_PER_FP))
+
+ for vlan in attrs['vlans']:
+ if not isinstance(vlan, int) or vlan < 0:
+ raise Exception("topo['VMs'][%s]['vlans'] should contain a list with integers" % hostname)
+ if vlan in all_vlans:
+ raise Exception("topo['VMs'][%s]['vlans'] double use of vlan: %d" % (hostname, vlan))
+ else:
+ all_vlans.add(vlan)
+
+ vms_exists = True
+
+ return hostif_exists, vms_exists
+
+def check_params(module, params, mode):
+ for param in params:
+ if param not in module.params:
+ raise Exception("Parameter %s is required in %s mode" % (param, mode))
+
+ return
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ cmd=dict(required=True, choices=['create', 'bind', 'renumber', 'unbind', 'destroy']),
+ vm_set_name=dict(required=False, type='str'),
+ topo=dict(required=False, type='dict'),
+ vm_names=dict(required=True, type='list'),
+ vm_base=dict(required=False, type='str'),
+ vlan_base=dict(required=False, type='int'),
+ mgmt_ip_addr=dict(required=False, type='str'),
+ mgmt_ip_gw=dict(required=False, type='str'),
+ mgmt_bridge=dict(required=False, type='str'),
+ ext_iface=dict(required=False, type='str'),
+ fp_mtu=dict(required=False, type='int', default=DEFAULT_MTU),
+ ),
+ supports_check_mode=False)
+
+ cmd = module.params['cmd']
+ vm_names = module.params['vm_names']
+ fp_mtu = module.params['fp_mtu']
+
+ try:
+ if os.path.exists(CMD_DEBUG_FNAME) and os.path.isfile(CMD_DEBUG_FNAME):
+ os.remove(CMD_DEBUG_FNAME)
+
+ net = VMTopology(vm_names, fp_mtu)
+
+ if cmd == 'create':
+ net.create_bridges()
+ elif cmd == 'destroy':
+ net.destroy_bridges()
+ elif cmd == 'bind':
+ check_params(module, ['vm_set_name',
+ 'topo',
+ 'mgmt_ip_addr',
+ 'mgmt_ip_gw',
+ 'mgmt_bridge',
+ 'ext_iface'], cmd)
+
+ vm_set_name = module.params['vm_set_name']
+ topo = module.params['topo']
+ ext_iface = module.params['ext_iface']
+ vlan_base = module.params['vlan_base']
+
+ if len(vm_set_name) > VM_SET_NAME_MAX_LEN:
+ raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name)))
+
+ hostif_exists, vms_exists = check_topo(topo)
+
+ if vms_exists:
+ check_params(module, ['vm_base', 'vlan_base'], cmd)
+ vm_base = module.params['vm_base']
+ else:
+ vm_base = None
+
+ net.init(vm_set_name, topo, vm_base, vlan_base, ext_iface)
+
+ mgmt_ip_addr = module.params['mgmt_ip_addr']
+ mgmt_ip_gw = module.params['mgmt_ip_gw']
+ mgmt_bridge = module.params['mgmt_bridge']
+
+ net.add_mgmt_port_to_docker(mgmt_bridge, mgmt_ip_addr, mgmt_ip_gw)
+ net.up_ext_iface()
+
+ if vms_exists:
+ net.add_veth_ports_to_docker()
+ net.bind_fp_ports()
+ net.bind_vm_backplane()
+
+ if hostif_exists:
+ net.inject_host_ports()
+ elif cmd == 'unbind':
+ check_params(module, ['vm_set_name',
+ 'topo',
+ 'ext_iface'], cmd)
+
+ vm_set_name = module.params['vm_set_name']
+ topo = module.params['topo']
+ ext_iface = module.params['ext_iface']
+ vlan_base = module.params['vlan_base']
+
+ if len(vm_set_name) > VM_SET_NAME_MAX_LEN:
+ raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name)))
+
+ _, vms_exists = check_topo(topo)
+
+ if vms_exists:
+ check_params(module, ['vm_base', 'vlan_base'], cmd)
+ vm_base = module.params['vm_base']
+ else:
+ vm_base = None
+
+ net.init(vm_set_name, topo, vm_base, vlan_base, ext_iface, False)
+
+ if vms_exists:
+ net.unbind_vm_backplane()
+ net.unbind_fp_ports()
+ elif cmd == 'renumber':
+ check_params(module, ['vm_set_name',
+ 'topo',
+ 'mgmt_ip_addr',
+ 'mgmt_ip_gw',
+ 'mgmt_bridge',
+ 'ext_iface'], cmd)
+
+ vm_set_name = module.params['vm_set_name']
+ topo = module.params['topo']
+ ext_iface = module.params['ext_iface']
+ vlan_base = module.params['vlan_base']
+
+ if len(vm_set_name) > VM_SET_NAME_MAX_LEN:
+ raise Exception("vm_set_name can't be longer than %d characters: %s (%d)" % (VM_SET_NAME_MAX_LEN, vm_set_name, len(vm_set_name)))
+
+ hostif_exists, vms_exists = check_topo(topo)
+
+ if vms_exists:
+ check_params(module, ['vm_base', 'vlan_base'], cmd)
+ vm_base = module.params['vm_base']
+ else:
+ vm_base = None
+
+ net.init(vm_set_name, topo, vm_base, vlan_base, ext_iface, True)
+
+ mgmt_ip_addr = module.params['mgmt_ip_addr']
+ mgmt_ip_gw = module.params['mgmt_ip_gw']
+ mgmt_bridge = module.params['mgmt_bridge']
+
+ net.add_mgmt_port_to_docker(mgmt_bridge, mgmt_ip_addr, mgmt_ip_gw)
+
+ if vms_exists:
+ new_vlan_base = net.vlan_base
+ net.vlan_base = net.find_base_vlan() # Use old vlan base to remove previous vlan
+ net.unbind_fp_ports()
+ net.vlan_base = new_vlan_base
+ # self.vlan_base = restore new one
+ net.add_veth_ports_to_docker()
+ net.bind_fp_ports()
+ if hostif_exists:
+ net.inject_host_ports()
+ else:
+ raise Exception("Got wrong cmd: %s. Ansible bug?" % cmd)
+
+ except Exception as error:
+ with open(EXCEPTION_DEBUG_FNAME, 'w') as fp:
+ traceback.print_exc(file=fp)
+ module.fail_json(msg=str(error))
+
+ module.exit_json(changed=True)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/ansible/roles/vm_set/tasks/add_topo.yml b/ansible/roles/vm_set/tasks/add_topo.yml
new file mode 100644
index 00000000000..134ef242d5b
--- /dev/null
+++ b/ansible/roles/vm_set/tasks/add_topo.yml
@@ -0,0 +1,28 @@
+- name: Create a docker container ptf_{{ vm_set_name }}
+ docker:
+ registry: "{{ docker_registry_host }}"
+ username: "{{ docker_registry_username }}"
+ password: "{{ docker_registry_password }}"
+ name: ptf_{{ vm_set_name }}
+ image: "{{ docker_registry_host }}/{{ ptf_imagename }}"
+ pull: always
+ state: reloaded
+ net: none
+ detach: True
+ cap_add: NET_ADMIN
+ become: yes
+
+- name: Bind topology {{ topo }} to VMs. base vm = {{ VM_base }} base vlan = {{ vlan_base }}
+ vm_topology:
+ cmd: "bind"
+ vm_set_name: "{{ vm_set_name }}"
+ topo: "{{ topology }}"
+ vm_names: "{{ VM_hosts }}"
+ vm_base: "{{ VM_base }}"
+ vlan_base: "{{ vlan_base }}"
+ mgmt_ip_addr: "{{ ptf_ip }}"
+ mgmt_ip_gw: "{{ mgmt_gw }}"
+ mgmt_bridge: "{{ mgmt_bridge }}"
+ ext_iface: "{{ external_iface }}"
+ fp_mtu: "{{ fp_mtu_size }}"
+ become: yes
diff --git a/ansible/roles/vm_set/tasks/main.yml b/ansible/roles/vm_set/tasks/main.yml
index 27e8d14d5dc..0e1c77c2458 100644
--- a/ansible/roles/vm_set/tasks/main.yml
+++ b/ansible/roles/vm_set/tasks/main.yml
@@ -4,7 +4,8 @@
# - id: sequence number for vm set on the host.
# - external_iface: interface which will be used as parent for vlan interface creation
# - vlan_base: first vlan id for the VMs
-# - VMs: a dictionary which contains hostnames of VMs as a key and a dictionary with parameters (filename, serial_port, vlan, memory) for every VM.
+# - VMs: a dictionary which contains hostnames of VMs as a key and a dictionary with parameters (num, memory, mgmt_ip) for every VM.
+# - topology: a dictionary which contains hostnames of VMs as a key and vlans value which define a topology (numbers of connected ports for every VM)
# - mgmt_bridge: linux bridge which is used for management interface connections
# - root_path: path where disk images for VMs are created
# - hdd_image_filename: base hdd image for VMs
@@ -12,9 +13,51 @@
# - vm_images_url: url where base images are located
# - vmimages_saskey: a key for Azure download service. Could be set to ''
-- name: Install necessary packages. vm set {{ id }}
- apt: pkg={{ item }} update_cache=yes cache_valid_time=3600
+# Need latest ubuntu 4.10 kernel to fix a openvswitch bug
+# https://bugs.launchpad.net/ubuntu/+source/kernel-package/+bug/1685742
+- name: Check if kernel upgrade needed
+ set_fact:
+ kernel_upgrade_needed: true
+ when:
+ - ansible_distribution == "Ubuntu"
+ - ansible_distribution_version == "17.04"
+ - ansible_kernel.find('4.10.0') != -1
+ - "{{ ansible_kernel | regex_replace('4.10.0-([0-9]+)-.*', '\\1') | int < 25 }}"
+
+- block:
+ - debug: msg="{{ ansible_kernel }}"
+
+ - name: Upgrade kernel package
+ apt: pkg={{ item }} state=latest
+ become: yes
+ with_items:
+ - linux-image-generic
+ - linux-image-extra-virtual
+
+ - name: Prompt for rebooting
+ fail:
+ msg: "Kernel upgraded, need to reboot!"
+ when: kernel_upgrade_needed is defined
+
+- name: Add docker repository for 17.04
+ apt_repository:
+ repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu zesty stable
+ state: present
+ become: yes
+ when: ansible_distribution_version == "17.04"
+
+- name: Add docker repository for 16.04
+ apt_repository:
+ repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable
+ state: present
+ become: yes
+ when: ansible_distribution_version == "16.04"
+
+- name: Install necessary packages
+ apt: pkg={{ item }} update_cache=yes cache_valid_time=86400
+ become: yes
with_items:
+ - qemu
- openvswitch-switch
- net-tools
- bridge-utils
@@ -24,31 +67,73 @@
- libvirt-bin
- python-libvirt
- python-pip
+ - apt-transport-https
+ - ca-certificates
+ - curl
+ - software-properties-common
+ - docker-ce
-- name: Install python packages. vm set {{ id }}
+- name: Install python packages
pip: name=docker-py state=present version=1.7.2
+ become: yes
environment: "{{ proxy_env | default({}) }}"
-- name: Retrieve a list of the defined VMs. vm set {{ id }}
+- name: Install br_netfilter kernel module
+ become: yes
+ modprobe: name=br_netfilter state=present
+
+- name: setup trunk port
+ template: src=trunk_port.j2
+ dest=/etc/network/interfaces.d/trunk_port
+ become: yes
+ register: trunk_port
+
+- name: bring up trunk port
+ shell: /sbin/ifup {{ external_iface }} --force
+ become: yes
+ when: trunk_port.changed
+
+- name: Ensure {{ root_path }} exists
+ file: path={{ root_path }} state=directory
+
+- name: Install cleanup script
+ template: src=cleanup.sh.j2
+ dest={{ root_path }}/cleanup.sh
+
+- name: Retrieve a list of the defined VMs
virt: command=list_vms
uri=qemu:///system
register: vm_list_defined
-- name: Retrieve a list of the running VMs. vm set {{ id }}
+- name: Retrieve a list of the running VMs
virt: command=list_vms
uri=qemu:///system
state=running
register: vm_list_running
-- name: Stop vm set {{ id }}
+- name: Find current server group
+ set_fact: current_server={{ group_names | extract_by_prefix('server_') }}
+
+- name: Extract VM names from the inventory
+ set_fact: VM_hosts={{ groups[current_server] | filter_by_prefix('VM') }}
+
+- name: Stop VMs
include: stop.yml
when: action == 'stop'
-- name: Start vm set {{ id }}
+- name: Start VMs
include: start.yml
when: action == 'start'
-- name: Renumber vm set {{ id }}
- include: renumber.yml
- when: action == 'renumber'
+- name: Add topology
+ include: add_topo.yml
+ when: action == 'add_topo'
+
+- name: Remove topology
+ include: remove_topo.yml
+ when: action == 'remove_topo'
+
+- name: Renumber topology
+ include: renumber_topo.yml
+ when: action == 'renumber_topo'
diff --git a/ansible/roles/vm_set/tasks/remove_topo.yml b/ansible/roles/vm_set/tasks/remove_topo.yml
new file mode 100644
index 00000000000..6b3558aa730
--- /dev/null
+++ b/ansible/roles/vm_set/tasks/remove_topo.yml
@@ -0,0 +1,17 @@
+- name: Remove ptf docker container ptf_{{ vm_set_name }}
+ docker:
+ name: ptf_{{ vm_set_name }}
+ image: "{{ docker_registry_host }}/{{ ptf_imagename }}"
+ state: absent
+ become: yes
+
+- name: Unbind topology {{ topo }} to VMs. base vm = {{ VM_base }} base vlan = {{ vlan_base }}
+ vm_topology:
+ cmd: "unbind"
+ vm_set_name: "{{ vm_set_name }}"
+ topo: "{{ topology }}"
+ vm_names: "{{ VM_hosts }}"
+ vm_base: "{{ VM_base }}"
+ vlan_base: "{{ vlan_base }}"
+ ext_iface: "{{ external_iface }}"
+ become: yes
diff --git a/ansible/roles/vm_set/tasks/renumber.yml b/ansible/roles/vm_set/tasks/renumber.yml
deleted file mode 100644
index b5a03537e9d..00000000000
--- a/ansible/roles/vm_set/tasks/renumber.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-- name: Unbind external ifaces to VM set. vm set {{ id }}
- vm_network:
- cmd: 'unbind'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
-
-- name: Bind external ifaces to VM set. vm set {{ id }}
- vm_network:
- cmd: 'bind'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
-
diff --git a/ansible/roles/vm_set/tasks/renumber_topo.yml b/ansible/roles/vm_set/tasks/renumber_topo.yml
new file mode 100644
index 00000000000..ebbbca1d463
--- /dev/null
+++ b/ansible/roles/vm_set/tasks/renumber_topo.yml
@@ -0,0 +1,35 @@
+- name: Remove ptf docker container ptf_{{ vm_set_name }}
+ docker:
+ name: ptf_{{ vm_set_name }}
+ image: "{{ docker_registry_host }}/{{ ptf_imagename }}"
+ state: absent
+ become: yes
+
+- name: Create a docker container ptf_{{ vm_set_name }}
+ docker:
+ registry: "{{ docker_registry_host }}"
+ username: "{{ docker_registry_username }}"
+ password: "{{ docker_registry_password }}"
+ name: ptf_{{ vm_set_name }}
+ image: "{{ docker_registry_host }}/{{ ptf_imagename }}"
+ pull: always
+ state: reloaded
+ net: none
+ detach: True
+ cap_add: NET_ADMIN
+ become: yes
+
+- name: Renumber topology {{ topo }} to VMs. base vm = {{ VM_base }} base vlan = {{ vlan_base }}
+ vm_topology:
+ cmd: "renumber"
+ vm_set_name: "{{ vm_set_name }}"
+ topo: "{{ topology }}"
+ vm_names: "{{ VM_hosts }}"
+ vm_base: "{{ VM_base }}"
+ vlan_base: "{{ vlan_base }}"
+ mgmt_ip_addr: "{{ ptf_ip }}"
+ mgmt_ip_gw: "{{ mgmt_gw }}"
+ mgmt_bridge: "{{ mgmt_bridge }}"
+ ext_iface: "{{ external_iface }}"
+ fp_mtu: "{{ fp_mtu_size }}"
+ become: yes
diff --git a/ansible/roles/vm_set/tasks/start.yml b/ansible/roles/vm_set/tasks/start.yml
index e3105ecc6db..06d530076b7 100644
--- a/ansible/roles/vm_set/tasks/start.yml
+++ b/ansible/roles/vm_set/tasks/start.yml
@@ -1,94 +1,84 @@
-- name: Create directory for vm images and vm disks. vm set {{ id }}
- file: path={{ item }} state=directory mode=0755 recurse=yes
+- name: Set sysctl bridge parameters for testbed
+ sysctl:
+ name: "{{ item }}"
+ value: 0
+ sysctl_set: yes
+ become: yes
+ with_items:
+ - net.bridge.bridge-nf-call-arptables
+ - net.bridge.bridge-nf-call-ip6tables
+ - net.bridge.bridge-nf-call-iptables
+
+- name: Set sysctl RCVBUF parameter for testbed
+ sysctl:
+ name: "net.core.rmem_max"
+ value: 509430500
+ sysctl_set: yes
+ become: yes
+
+- name: Create directory for vm images and vm disks
+ file: path={{ item }} state=directory mode=0755
with_items:
- "{{ root_path }}/images"
- "{{ root_path }}/disks"
-- name: Check hdd image. vm set {{ id }}
+- name: Check hdd image
stat: path={{ root_path }}/images/{{ hdd_image_filename }}
register: hdd_stat
-- name: Download hdd images. vm set {{ id }}
- get_url: url="{{ vm_images_url }}/{{ hdd_image_filename }}?{{ vmimages_saskey }}" dest="{{ root_path }}/images/{{ hdd_image_filename }}"
- when: not hdd_stat.stat.exists
+- name: Fail if there are no hdd image and skip image downloading is active
+ fail: msg="Please put {{ hdd_image_filename }} to {{ root_path }}/images"
+ when: not hdd_stat.stat.exists and skip_image_downloading
-- name: Check cd image. vm set {{ id }}
+- name: Download hdd image
+ get_url: url="{{ vm_images_url }}/{{ hdd_image_filename }}?{{ vmimage_saskey }}" dest="{{ root_path }}/images/{{ hdd_image_filename }}"
+ when: not hdd_stat.stat.exists and not skip_image_downloading
+
+- name: Check cd image
stat: path={{ root_path }}/images/{{ cd_image_filename }}
register: cd_stat
-- name: Download cd images. vm set {{ id }}
- get_url: url="{{ vm_images_url }}/{{ cd_image_filename }}?{{ vmimages_saskey }}" dest="{{ root_path }}/images/{{ cd_image_filename }}"
- when: not cd_stat.stat.exists
-
-- name: Create docker container for injected ports. vm set {{ id }}
- docker:
- registry: "{{ docker_registry_host }}"
- username: "{{ docker_registry_username }}"
- password: "{{ docker_registry_password }}"
- name: ptf_injected_{{ id }}
- image: "{{ docker_registry_host }}/{{ docker_image }}"
- pull: always
- state: reloaded
- net: none
- detach: True
- cap_add: NET_ADMIN
+- name: Fail if there are no cd image and skip image downloading is active
+ fail: msg="Please put {{ cd_image_filename }} to {{ root_path }}/images"
+ when: not cd_stat.stat.exists and skip_image_downloading
-- name: Create injected network for the docker container. vm set {{ id }}
- ptf_network_inj:
- ptf_name: ptf_injected_{{ id }}
- ctr_num: "{{ id }}"
- vlan_base: "{{ vlan_base }}"
- fp_mtu: "{{ fp_mtu_size }}"
- mgmt_ip_addr: "{{ vm_injected_ip }}"
- mgmt_ip_gw: "{{ mgmt_gw }}"
- mgmt_bridge: "{{ mgmt_bridge }}"
+- name: Download cd image
+ get_url: url="{{ vm_images_url }}/{{ cd_image_filename }}?{{ cdimage_saskey }}" dest="{{ root_path }}/images/{{ cd_image_filename }}"
+ when: not cd_stat.stat.exists and not skip_image_downloading
-- name: Create VM set network. vm set {{ id }}
- vm_network:
- cmd: 'create'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
+- name: Create VMs network
+ become: yes
+ vm_topology:
+ cmd: 'create'
+ vm_names: "{{ VM_hosts }}"
+ fp_mtu: "{{ fp_mtu_size }}"
-- name: Start VMs. vm set {{ id }}
+- name: Start VMs
include: start_vm.yml
vars:
- vm_name: "{{ id }}_{{ item.key }}"
- memory: "{{ item.value.memory }}"
- hostname: "{{ item.key }}"
- filename: "{{ item.value.filename }}"
- serial_port: "{{ item.value.serial_port }}"
+ vm_name: "{{ item }}"
+ hostname: "{{ vm_name }}"
+ mgmt_ip_address: "{{ hostvars[vm_name]['ansible_host'] }}"
+ serial_port: "{{ vm_console_base|int + vm_name[4:]|int }}"
disk_image: "{{ root_path }}/disks/{{ vm_name }}_hdd.vmdk"
mgmt_tap: "{{ vm_name }}-m"
- fp0_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-0"
+ fp0_bridge: "br-{{ vm_name }}-0"
fp0_tap: "{{ vm_name }}-t0"
- fp1_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-1"
+ fp1_bridge: "br-{{ vm_name }}-1"
fp1_tap: "{{ vm_name }}-t1"
- fp2_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-2"
+ fp2_bridge: "br-{{ vm_name }}-2"
fp2_tap: "{{ vm_name }}-t2"
- fp3_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-3"
+ fp3_bridge: "br-{{ vm_name }}-3"
fp3_tap: "{{ vm_name }}-t3"
- fp4_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-4"
+ fp4_bridge: "br-{{ vm_name }}-4"
fp4_tap: "{{ vm_name }}-t4"
- fp5_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-5"
+ fp5_bridge: "br-{{ vm_name }}-5"
fp5_tap: "{{ vm_name }}-t5"
- fp6_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-6"
+ fp6_bridge: "br-{{ vm_name }}-6"
fp6_tap: "{{ vm_name }}-t6"
- fp7_bridge: "br-vs{{ id }}-vm{{ item.value.num }}-7"
+ fp7_bridge: "br-{{ vm_name }}-7"
fp7_tap: "{{ vm_name }}-t7"
- port1_tap: "{{ vm_name }}-p1"
- with_dict: "{{ VMs }}"
-
-- name: Bind external ifaces to VM set. vm set {{ id }}
- vm_network:
- cmd: 'bind'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
+ port1_bridge: "br-{{ vm_name }}-back"
+ port1_tap: "{{ vm_name }}-back"
+ with_items: "{{ VM_hosts }}"
diff --git a/ansible/roles/vm_set/tasks/start_vm.yml b/ansible/roles/vm_set/tasks/start_vm.yml
index c186c345283..535438b400d 100644
--- a/ansible/roles/vm_set/tasks/start_vm.yml
+++ b/ansible/roles/vm_set/tasks/start_vm.yml
@@ -1,71 +1,66 @@
-- name: Gathering minigraph facts device {{ hostname }}. vm set {{ id }}
- minigraph_facts: host={{ hostname }} filename={{ filename }}
- become: false
- connection: local
-
- name: Device debug output
- debug: msg="hostname = {{ hostname }} serial port = {{ serial_port }} ip = {{ minigraph_mgmt_interface.addr }}"
+ debug: msg="hostname = {{ hostname }} serial port = {{ serial_port }} ip = {{ mgmt_ip_address }}"
-- name: Check destination file existance. vm set {{ id }}
+- name: Check destination file existance
stat: path={{ disk_image }}
register: file_stat
-- name: Copy arista disk image for {{ hostname }}. vm set {{ id }}
+- name: Copy arista disk image for {{ hostname }}
copy: src={{ src_disk_image }} dest={{ disk_image }} remote_src=True
when: not file_stat.stat.exists
-- name: Define vm {{ vm_name }}. vm set {{ id }}
+- name: Define vm {{ vm_name }}
virt: name={{ vm_name }}
command=define
xml="{{ lookup('template', 'templates/arista.xml.j2') }}"
uri=qemu:///system
when: vm_name not in vm_list_defined.list_vms
-- name: Start vm {{ vm_name }}. vm set {{ id }}
+- name: Start vm {{ vm_name }}
virt: name={{ vm_name }}
state=running
uri=qemu:///system
when: vm_name not in vm_list_running.list_vms
-- name: Wait until vm {{ vm_name }} is loaded. vm set {{ id }}
+- name: Wait until vm {{ vm_name }} is loaded
kickstart: telnet_port={{ serial_port }}
login={{ login }}
password={{ password }}
hostname={{ hostname }}
- mgmt_ip="{{ minigraph_mgmt_interface.addr }}/{{ minigraph_mgmt_interface.prefixlen }}"
- mgmt_gw={{ minigraph_mgmt_interface.gwaddr }}
+ mgmt_ip="{{ mgmt_ip_address }}/{{ mgmt_prefixlen }}"
+ mgmt_gw={{ mgmt_gw }}
new_login={{ new_login }}
new_password={{ new_password }}
new_root_password={{ new_root_password }}
register: kickstart_output
when: vm_name not in vm_list_running.list_vms
-- name: Destroy vm {{ vm_name }} if it hangs. vm set {{ id }}
+- name: Destroy vm {{ vm_name }} if it hangs
virt: name={{ vm_name }}
command=destroy
uri=qemu:///system
when: vm_name not in vm_list_running.list_vms and kickstart_output.kickstart_code != 0
-- name: Start vm again {{ vm_name }}. vm set {{ id }}
+- name: Start vm again {{ vm_name }}
virt: name={{ vm_name }}
state=running
uri=qemu:///system
when: vm_name not in vm_list_running.list_vms and kickstart_output.kickstart_code != 0
-- name: Wait until vm {{ vm_name }} is loaded. vm set {{ id }}
+- name: Wait until vm {{ vm_name }} is loaded
kickstart: telnet_port={{ serial_port }}
login={{ login }}
password={{ password }}
hostname={{ hostname }}
- mgmt_ip="{{ minigraph_mgmt_interface.addr }}/{{ minigraph_mgmt_interface.prefixlen }}"
- mgmt_gw={{ minigraph_mgmt_interface.gwaddr }}
+ mgmt_ip="{{ mgmt_ip_address }}/{{ mgmt_prefixlen }}"
+ mgmt_gw={{ mgmt_gw }}
new_login={{ new_login }}
new_password={{ new_password }}
new_root_password={{ new_root_password }}
register: kickstart_output_final
when: vm_name not in vm_list_running.list_vms and kickstart_output.kickstart_code != 0
-- name: Fail if kickstart gives error again vm {{ vm_name }}. vm set {{ id }}
+- name: Fail if kickstart gives error again vm {{ vm_name }}
fail: msg="Two attempts to start vm weren't succesfull"
when: '"skipped" in kickstart_output_final and "kickstart_code" in kickstart_output_final and kickstart_output_final.kickstart_code != 0'
diff --git a/ansible/roles/vm_set/tasks/stop.yml b/ansible/roles/vm_set/tasks/stop.yml
index a3fe828c287..bf2ae6b80f1 100644
--- a/ansible/roles/vm_set/tasks/stop.yml
+++ b/ansible/roles/vm_set/tasks/stop.yml
@@ -1,33 +1,12 @@
-- name: Remove VMs. vm set {{ id }}
+- name: Remove VMs.
include: stop_vm.yml
vars:
- vm_name: "{{ id }}_{{ item.key }}"
+ vm_name: "{{ item }}"
disk_image: "{{ root_path }}/disks/{{ vm_name }}_hdd.vmdk"
- with_dict: "{{ VMs }}"
+ with_items: "{{ VM_hosts }}"
-- name: Unbind external ifaces to VM set. vm set {{ id }}
- vm_network:
- cmd: 'unbind'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
-
-- name: Remove ptf docker container. vm set {{ id }}
- docker:
- name: ptf_injected_{{ id }}
- image: "{{ docker_registry_host }}/{{ docker_image }}"
- state: absent
-
-- name: Destroy VM set network. vm set {{ id }}
- vm_network:
+- name: Destroy VMs network
+ vm_topology:
cmd: 'destroy'
- vm_set_id: "{{ id }}"
- port1_bridge: "{{ port1_bridge }}"
- vm_set_dict: "{{ VMs }}"
- fp_mtu: "{{ fp_mtu_size }}"
- ext_iface: "{{ external_iface }}"
- vlan_base: "{{ vlan_base }}"
-
+ vm_names: "{{ VM_hosts }}"
+ become: yes
diff --git a/ansible/roles/vm_set/tasks/stop_vm.yml b/ansible/roles/vm_set/tasks/stop_vm.yml
index de89eb1c5d6..6bc01ef2dfc 100644
--- a/ansible/roles/vm_set/tasks/stop_vm.yml
+++ b/ansible/roles/vm_set/tasks/stop_vm.yml
@@ -1,15 +1,15 @@
-- name: Destroy VM {{ vm_name }}. vm set {{ id }}
+- name: Destroy VM {{ vm_name }}
virt: name={{ vm_name }}
state=destroyed
uri=qemu:///system
when: vm_name in vm_list_running.list_vms
-- name: Undefine VM {{ vm_name }}. vm set {{ id }}
+- name: Undefine VM {{ vm_name }}
virt: name={{ vm_name }}
command=undefine
uri=qemu:///system
when: vm_name in vm_list_defined.list_vms
-- name: Remove arista disk image for {{ vm_name }}. vm set {{ id }}
+- name: Remove arista disk image for {{ vm_name }}
file: path={{ disk_image }} state=absent
diff --git a/ansible/roles/vm_set/templates/arista.xml.j2 b/ansible/roles/vm_set/templates/arista.xml.j2
index 3ab505fc1f6..1476690c6d3 100644
--- a/ansible/roles/vm_set/templates/arista.xml.j2
+++ b/ansible/roles/vm_set/templates/arista.xml.j2
@@ -89,6 +89,7 @@
+
diff --git a/ansible/roles/vm_set/templates/cleanup.sh.j2 b/ansible/roles/vm_set/templates/cleanup.sh.j2
new file mode 100644
index 00000000000..b294f10854c
--- /dev/null
+++ b/ansible/roles/vm_set/templates/cleanup.sh.j2
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+# stop rynning VMs
+test -z "$(virsh list --state-running --name)" || virsh list --state-running --name | xargs -I % virsh destroy %
+
+# stop paused VMs
+test -z "$(virsh list --state-paused --name)" || virsh list --state-running --name | xargs -I % virsh destroy %
+
+# undefine all VMs
+test -z "$(virsh list --all --name)" || virsh list --all --name | xargs -I % virsh undefine %
+
+# remove all VM disks
+rm -f {{ root_path }}/disks/*
+
+# remove all ovs bridges
+test -z "$(ovs-vsctl list-br)" || ovs-vsctl list-br | sed -e 's/^/-- del-br /' | xargs ovs-vsctl
+
+# stop all running docker containers
+test -z "$(docker ps -q)" || docker stop $(docker ps -q)
+
+# remove all docker containers
+test -z "$(docker ps -a -q)" || docker rm $(docker ps -a -q)
+
+# remove all docker images
+test -z "$(docker images -q)" || docker rmi $(docker images -q)
+
diff --git a/ansible/roles/vm_set/templates/get_terminal_length.j2 b/ansible/roles/vm_set/templates/get_terminal_length.j2
new file mode 100644
index 00000000000..1094defc462
--- /dev/null
+++ b/ansible/roles/vm_set/templates/get_terminal_length.j2
@@ -0,0 +1,2 @@
+enable
+show terminal
diff --git a/ansible/roles/vm_set/templates/lag_lacp.j2 b/ansible/roles/vm_set/templates/lag_lacp.j2
new file mode 100644
index 00000000000..d05551acd67
--- /dev/null
+++ b/ansible/roles/vm_set/templates/lag_lacp.j2
@@ -0,0 +1,7 @@
+enable
+!
+configure
+!
+show running-config interfaces {{ show_iface }}
+!
+end
diff --git a/ansible/roles/vm_set/templates/set_terminal_length.j2 b/ansible/roles/vm_set/templates/set_terminal_length.j2
new file mode 100644
index 00000000000..2a191c9092a
--- /dev/null
+++ b/ansible/roles/vm_set/templates/set_terminal_length.j2
@@ -0,0 +1,2 @@
+enable
+terminal length {{ terminal_length_value| int }}
diff --git a/ansible/roles/vm_set/templates/trunk_port.j2 b/ansible/roles/vm_set/templates/trunk_port.j2
new file mode 100644
index 00000000000..7103f5a33ed
--- /dev/null
+++ b/ansible/roles/vm_set/templates/trunk_port.j2
@@ -0,0 +1,5 @@
+# trunk port
+auto {{ external_iface }}
+iface {{ external_iface }} inet manual
+ mtu 9216
+ up ip link set {{ external_iface }} up
diff --git a/ansible/roles/vm_set/vars/main.yml b/ansible/roles/vm_set/vars/main.yml
index 17709ae1d56..b5b80058a78 100644
--- a/ansible/roles/vm_set/vars/main.yml
+++ b/ansible/roles/vm_set/vars/main.yml
@@ -12,6 +12,5 @@ spine_memory: 2097152
port1_bridge: br-port1-{{ id }}
-docker_image: docker-ptf
fp_mtu_size: 9216
diff --git a/ansible/shell_plugins/docker.py b/ansible/shell_plugins/docker.py
index f3e5443978e..ca9f2d6aebf 100644
--- a/ansible/shell_plugins/docker.py
+++ b/ansible/shell_plugins/docker.py
@@ -24,7 +24,7 @@ def join_path(self, *args):
## We observe the interactions between ShellModule and ActionModule, and
## find the temporary directories Ansible created on remote machine. So we
## collect them and copied to docker container in build_module_command
- if len(args) >= 2 and args[0].startswith('/home/') and args[1] == '':
+ if len(args) >= 2 and (args[0].startswith('/home/') or args[0].startswith('/root/')) and args[1] == '':
self.dtemps.append(args[0])
return super(ShellModule, self).join_path(*args)
diff --git a/ansible/start_ptf_containers.yml b/ansible/start_ptf_containers.yml
deleted file mode 100644
index 39a3df63545..00000000000
--- a/ansible/start_ptf_containers.yml
+++ /dev/null
@@ -1,60 +0,0 @@
----
-# This Playbook deploys three ptf docker containers
-#
-# The ptf docker container has management interface. See ip address of the interface in host_vars
-# Also it has 32 ethX interfaces which is connected to an external port with corresponding vlans.
-# See the vlan number in host_vars
-#
-# To start all ptf containers on both servers:
-# ansible-playbook -i veos start_ptf_containers.yml --vault-password-file=~/.password
-#
-# To start all ptf_containers on the first server only:
-# ansible-playbook -i veos start_ptf_containers.yml --vault-password-file=~/.password --limit server_1
-#
-# To run second ptf container on the second server only
-# ansible-playbook -i veos start_ptf_containers.yml --vault-password-file=~/.password --limit server_2 -e ptf_2=true
-#
-# To renumber third ptf container to the new vlan range on the second server
-# Firstly destroy previous container
-# ansible-playbook -i veos stop_ptf_containers.yml --vault-password-file=~/.password --limit server_2 -e ptf_3=true
-#
-# Then start a new container with new vlan range
-# ansible-playbook -i veos start_ptf_containers.yml --vault-password-file=~/.password --limit server_2 -e ptf_3=true -e ptf_3_vlan_base=381
-#
-# To start a ptf container with saithrift packge deployed instead of raw ptf:
-# ansible-playbook -i veos start_ptf_containers.yml --vault=password-file=~/.password --limit server_1 -e ptf_3=true -e docker_image=docker-ptf-sai-{ASIC vender name}
-
-
-- hosts: servers:&vm_host
- gather_facts: no
- become: true
- vars:
- ptf_1: false
- ptf_2: false
- ptf_3: false
- ptf_4: false
- ptf_5: false
- ptf_6: false
- vars_files:
- - vars/docker_registry.yml
- - vars/azure_storage.yml
- pre_tasks:
- - name: Set "tag" variables
- set_fact:
- ptf_1: true
- ptf_2: true
- ptf_3: true
- ptf_4: true
- ptf_5: true
- ptf_6: true
- when: not (ptf_1 or ptf_2 or ptf_3 or ptf_4 or ptf_5 or ptf_6)
- roles:
- - { role: ptf_host, action: 'start', id: 1, vlan_base: "{{ ptf_1_vlan_base }}", mgmt_ip: "{{ ptf_1_mgmt_ip }}", when: ptf_1 and ptf_1_enabled }
- - { role: ptf_host, action: 'start', id: 2, vlan_base: "{{ ptf_2_vlan_base }}", mgmt_ip: "{{ ptf_2_mgmt_ip }}", when: ptf_2 and ptf_2_enabled }
- - { role: ptf_host, action: 'start', id: 3, vlan_base: "{{ ptf_3_vlan_base }}", mgmt_ip: "{{ ptf_3_mgmt_ip }}", when: ptf_3 and ptf_3_enabled }
- - { role: ptf_host, action: 'start', id: 4, vlan_base: "{{ ptf_4_vlan_base }}", mgmt_ip: "{{ ptf_4_mgmt_ip }}", when: ptf_4 and ptf_4_enabled }
- - { role: ptf_host, action: 'start', id: 5, vlan_base: "{{ ptf_5_vlan_base }}", mgmt_ip: "{{ ptf_5_mgmt_ip }}", when: ptf_5 and ptf_5_enabled }
- - { role: ptf_host, action: 'start', id: 6, vlan_base: "{{ ptf_6_vlan_base }}", mgmt_ip: "{{ ptf_6_mgmt_ip }}", when: ptf_6 and ptf_6_enabled }
-
-
-
diff --git a/ansible/start_vm_sets.yml b/ansible/start_vm_sets.yml
deleted file mode 100644
index 6271249e458..00000000000
--- a/ansible/start_vm_sets.yml
+++ /dev/null
@@ -1,59 +0,0 @@
----
-# This Playbook deploys two vm sets with 32 veos VMs each
-#
-# Every VM has three interfaces:
-# - mgmt interface which is connected to the routable physical network
-# See host_vars/STR-ACS-SERV-02.yml for the ip address
-# - Eth1/1 is connected to the external port with corresponding vlan
-# See the vlan number in host_vars/STR-ACS-SERV-02.yml
-# - Eth1/2 is connected to other VM's Eth1/2
-#
-# To start all vm_sets on both servers:
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos start_vm_sets.yml --vault-password-file=~/.password
-#
-# To run on the first server only:
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos start_vm_sets.yml --vault-password-file=~/.password --limit server_1
-#
-# To create second vm set only on the second server
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos start_vm_sets.yml --vault-password-file=~/.password --limit server_2 -e vm_set_2=true
-
-# To destroy second vm set only on the second server
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos stop_vm_sets.yml --vault-password-file=~/.password --limit server_2 -e vm_set_2=true
-
-# To renumber second vm set to new vlan range on the second server
-# ansible-playbook -i veos renumber_vm_set.yml --vault-password-file=~/.password --limit server_2 -e vm_set_2=true -e vm_2_vlan_base=233
-
-- hosts: servers:&vm_host
- gather_facts: yes
- become: true
- vars:
- vm_set_1: false
- vm_set_2: false
- vars_files:
- - vars/docker_registry.yml
- - vars/azure_storage.yml
- pre_tasks:
- - name: Set "tag" variables
- set_fact:
- vm_set_1: true
- vm_set_2: true
- when: not (vm_set_1 or vm_set_2)
- roles:
- - { role: vm_set, action: 'start', id: 1, VMs: "{{ VMs_1 }}", vlan_base: "{{ vm_1_vlan_base }}", vm_injected_ip: "{{ vm_1_injected_ip }}", when: vm_set_1 and vm_1_enabled }
- - { role: vm_set, action: 'start', id: 2, VMs: "{{ VMs_2 }}", vlan_base: "{{ vm_2_vlan_base }}", vm_injected_ip: "{{ vm_2_injected_ip }}", when: vm_set_2 and vm_2_enabled }
-
-- hosts: servers:&eos
- gather_facts: no
- vars:
- vm_set_1: false
- vm_set_2: false
- pre_tasks:
- - name: Set "tag" variables
- set_fact:
- vm_set_1: true
- vm_set_2: true
- when: not (vm_set_1 or vm_set_2)
- roles:
- - { role: eos, when: vm_set_1 and "vm_set_1" in group_names }
- - { role: eos, when: vm_set_2 and "vm_set_2" in group_names }
-
diff --git a/ansible/stop_ptf_containers.yml b/ansible/stop_ptf_containers.yml
deleted file mode 100644
index 05a8a9b6520..00000000000
--- a/ansible/stop_ptf_containers.yml
+++ /dev/null
@@ -1,44 +0,0 @@
----
-# This Playbook undeploys containers for the testbed.
-#
-# For additional details see playbook start_ptf_containers.yml
-#
-# To run on both servers with all ptf containers:
-# ansible-playbook -i veos stop_ptf_containers.yml --vault-password-file=~/.password
-#
-# To run on the first server only:
-# ansible-playbook -i veos stop_ptf_containers.yml --vault-password-file=~/.password --limit server_1
-#
-# To run on the second server and remove second container only
-# ansible-playbook -i veos stop_ptf_containers.yml --vault-password-file=~/.password --limit server_2 -e ptf_2=true
-
-- hosts: servers:&vm_host
- gather_facts: no
- become: true
- vars:
- ptf_1: false
- ptf_2: false
- ptf_3: false
- ptf_4: false
- ptf_5: false
- ptf_6: false
- vars_files:
- - vars/docker_registry.yml
- pre_tasks:
- - name: Set "tag" variables
- set_fact:
- ptf_1: true
- ptf_2: true
- ptf_3: true
- ptf_4: true
- ptf_5: true
- ptf_6: true
- when: not (ptf_1 or ptf_2 or ptf_3 or ptf_4 or ptf_5 or ptf_6)
- roles:
- - { role: ptf_host, action: 'stop', id: 1, when: ptf_1 and ptf_1_enabled }
- - { role: ptf_host, action: 'stop', id: 2, when: ptf_2 and ptf_2_enabled }
- - { role: ptf_host, action: 'stop', id: 3, when: ptf_3 and ptf_3_enabled }
- - { role: ptf_host, action: 'stop', id: 4, when: ptf_4 and ptf_4_enabled }
- - { role: ptf_host, action: 'stop', id: 5, when: ptf_5 and ptf_5_enabled }
- - { role: ptf_host, action: 'stop', id: 6, when: ptf_6 and ptf_6_enabled }
-
diff --git a/ansible/stop_vm_sets.yml b/ansible/stop_vm_sets.yml
deleted file mode 100644
index 148ed9d144d..00000000000
--- a/ansible/stop_vm_sets.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-# This Playbook undeploys the vm sets.
-#
-# For additional details see playbook start_vm_sets.yml
-#
-# To run on both servers with all VM sets and ptf containers:
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos stop_vm_sets.yml --vault-password-file=~/.password
-#
-# To run on the first server only:
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos stop_vm_sets.yml --vault-password-file=~/.password --limit server_1
-#
-# To run on the second server and remove second vm set only
-# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos stop_vm_sets.yml --vault-password-file=~/.password --limit server_2 -e vm_set_2=true
-
-- hosts: servers:&vm_host
- gather_facts: yes
- become: true
- vars:
- vm_set_1: false
- vm_set_2: false
- vars_files:
- - vars/docker_registry.yml
- pre_tasks:
- - name: Set "tag" variables
- set_fact:
- vm_set_1: true
- vm_set_2: true
- when: not (vm_set_1 or vm_set_2)
- roles:
- - { role: vm_set, action: 'stop', id: 1, VMs: "{{ VMs_1 }}", vlan_base: "{{ vm_1_vlan_base }}", when: vm_set_1 and vm_1_enabled }
- - { role: vm_set, action: 'stop', id: 2, VMs: "{{ VMs_2 }}", vlan_base: "{{ vm_2_vlan_base }}", when: vm_set_2 and vm_2_enabled }
-
diff --git a/ansible/swap_syncd.yml b/ansible/swap_syncd.yml
new file mode 100644
index 00000000000..3c1eeb80fad
--- /dev/null
+++ b/ansible/swap_syncd.yml
@@ -0,0 +1,66 @@
+# Swap docker-syncd to docker-syncd-rpc for oneimage deployed switch
+# A temporary solution during period that sonic_docker is not ready for oneimage
+# Example usage:
+# ansible-playbook swap_syncd.yml -i str --vault-password-file ~/password.txt --limit devicename
+
+- hosts: all
+ gather_facts: no
+ vars_files:
+ - vars/docker_registry.yml
+ tasks:
+
+ - name: Gathering minigraph facts about the device
+ minigraph_facts: host={{ inventory_hostname }}
+ connection: local
+ tags: always
+ become: no
+
+ - name: Set sonic_hwsku fact
+ set_fact:
+ sonic_hwsku: "{{minigraph_hwsku}}"
+ tags: always
+
+ - name: Set sonic_asic_type fact
+ set_fact:
+ sonic_asic_type: broadcom
+ docker_rpc_image_name: docker-syncd-brcm-rpc
+ docker_syncd_name: docker-syncd-brcm
+ when: sonic_hwsku in broadcom_hwskus
+ tags: always
+
+ - name: Set sonic_asic_type fact
+ set_fact:
+ sonic_asic_type: mellanox
+ docker_rpc_image_name: docker-syncd-mlnx-rpc
+ docker_syncd_name: docker-syncd-mlnx
+ when: sonic_hwsku in mellanox_hwskus
+ tags: always
+
+ - name: Stop swss service
+ become: true
+ command: systemctl stop swss
+
+ - name: Delete syncd docker
+ become: true
+ shell: docker rm syncd
+ ignore_errors: yes
+
+ - name: Set sysctl RCVBUF parameter for tests
+ sysctl:
+ name: "net.core.rmem_max"
+ value: 509430500
+ sysctl_set: yes
+
+ - name: Pull syncd-rpc docker from registry
+ shell: docker login -u {{docker_registry_username}} -p {{docker_registry_password}} -e "@" {{docker_registry_host}}; docker pull {{docker_registry_host}}/{{docker_rpc_image_name}}
+
+ - name: Tag pulled images as syncd
+ shell: docker tag {{docker_registry_host}}/{{docker_rpc_image_name}} {{docker_syncd_name}}
+
+ - name: Start swss service
+ become: true
+ command: systemctl start swss
+
+ - name: Wait for the initialization process
+ pause: seconds=60
+
diff --git a/ansible/templates/topo/dev_metadata.j2 b/ansible/templates/topo/dev_metadata.j2
new file mode 100644
index 00000000000..9aab31465c1
--- /dev/null
+++ b/ansible/templates/topo/dev_metadata.j2
@@ -0,0 +1,101 @@
+
+
+ true
+
+{% set num_of_intf = port_alias | length %}
+{% for index in range(num_of_intf) %}
+
+ DeviceInterface
+
+ true
+ true
+ 1
+ {{ port_alias[index] }}
+
+ false
+ 0
+ 0
+ {{ iface_speed }}
+
+{% endfor %}
+
+ true
+ 0
+ {{ hwsku }}
+
+
+
+
+{% set syslog_servers_str=';'.join(syslog_servers) %}
+{% set dhcp_servers_str=';'.join(dhcp_servers) %}
+{% set forced_mgmt_routes_str = ';'.join(forced_mgmt_routes) %}
+{% set ntp_servers_str = ';'.join(ntp_servers) %}
+{% set snmp_servers_str = ';'.join(snmp_servers) %}
+{% set tacacs_servers_str = ';'.join(tacacs_servers) %}
+{% set radius_servers_str = ';'.join(radius_servers) %}
+{% set erspan_dest_str = ';'.join(erspan_dest) %}
+
+
+ {{ inventory_hostname }}
+
+
+ DhcpResources
+
+ {{ dhcp_servers_str }}
+
+
+ NTPResources
+
+ {{ ntp_servers_str }}
+
+
+ DeploymentId
+
+ 1
+
+
+ QosProfile
+
+ Profile0
+
+
+ RadiusResources
+
+ {{ radius_servers_str }}
+
+
+ SnmpResources
+
+ {{ snmp_servers_str }}
+
+
+ SyslogResources
+
+ {{ syslog_servers_str }}
+
+
+ TacacsGroup
+
+ {{ tacacs_group }}
+
+
+ TacacsServer
+
+ {{ tacacs_servers_str }}
+
+
+ ForcedMgmtRoutes
+
+ {{ forced_mgmt_routes_str }}
+
+
+ ErspanDestinationIpv4
+
+ {{ erspan_dest_str }}
+
+
+
+
+
+
+
diff --git a/ansible/templates/topo/t0-64.j2 b/ansible/templates/topo/t0-64.j2
new file mode 100644
index 00000000000..49c2002f153
--- /dev/null
+++ b/ansible/templates/topo/t0-64.j2
@@ -0,0 +1,243 @@
+
+
+
+
+{% for index in range(4) %}
+
+ false
+ {{ inventory_hostname }}
+ 10.0.0.{{ index*4 }}
+ ARISTA0{{ index+1 }}T1
+ 10.0.0.{{ index*4 +1 }}
+ 1
+ 10
+ 3
+
+
+ {{ inventory_hostname }}
+ FC00::{{ ('%0x' % (index*8+1)) | upper }}
+ ARISTA0{{ index+1 }}T1
+ FC00::{{ ('%0x' % (index*8+2)) | upper }}
+ 1
+ 10
+ 3
+
+{% endfor %}
+
+
+
+ 64601
+ {{ inventory_hostname }}
+
+{% for index in range(4) %}
+
+ BGPPeer
+ 10.0.0.{{ index*4+1 }}
+
+
+
+
+
+ BGPPeer
+ FC00::{{ ('%0x' % (index*8+2)) | upper }}
+
+
+
+
+{% endfor %}
+
+ BGPPeer
+ 10.1.0.32
+
+
+
+ BGPSLBPassive
+ 10.255.0.0/27
+
+
+ BGPPeer
+ 10.1.0.32
+
+
+
+ BGPVac
+ 192.168.0.0/27
+
+
+
+
+{% for index in range(4) %}
+
+ 64802
+ ARISTA0{{ index+1 }}T1
+
+
+{% endfor %}
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::32/128
+
+ FC00:1::32/128
+
+
+
+
+ HostIP
+ eth0
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+
+ V6HostIP
+ eth0
+
+ FC00:2::32/64
+
+ FC00:2::32/64
+
+
+
+
+
+
+ {{ inventory_hostname }}
+
+{% for index in range(0,32,16) %}
+
+ PortChannelInterface
+ PortChannel{{ index }}
+ {{ port_alias[index] }};{{ port_alias[index+1] }}
+
+
+
+ PortChannelInterface
+ PortChannel{{ index+4 }}
+ {{ port_alias[index+4] }};{{ port_alias[index+5] }}
+
+
+{% endfor %}
+
+
+
+ VlanInterface
+ Vlan1000
+ {{ port_alias[6] }};{{ port_alias[7] }};{{ port_alias[8] }};{{ port_alias[9] }};{{ port_alias[10] }};{{ port_alias[11] }};{{ port_alias[12] }};{{ port_alias[13] }};{{ port_alias[14] }};{{ port_alias[15] }};{{ port_alias[22] }};{{ port_alias[23] }};{{ port_alias[24] }};{{ port_alias[25] }};{{ port_alias[26] }};{{ port_alias[27] }};{{ port_alias[28] }};{{ port_alias[29] }};{{ port_alias[30] }};{{ port_alias[31] }};{{ port_alias[32] }};{{ port_alias[36] }};{{ port_alias[37] }};{{ port_alias[38] }};{{ port_alias[39] }};{{ port_alias[40] }};{{ port_alias[41] }};{{ port_alias[42] }};{{ port_alias[48] }};{{ port_alias[52] }};{{ port_alias[53] }};{{ port_alias[54] }};{{ port_alias[55] }};{{ port_alias[56] }};{{ port_alias[57] }};{{ port_alias[58] }}
+ False
+ 0.0.0.0/0
+
+ 1000
+ 1000
+ 192.168.0.0/27
+
+
+
+{% for index in range(4) %}
+{% set po_index=index*4 if index < 2 else index*4+8 %}
+
+
+ PortChannel{{ po_index }}
+ 10.0.0.{{ index*4 }}/31
+
+
+
+ PortChannel{{ po_index }}
+ FC00::{{ ('%0x' % (index*8+1)) | upper }}/126
+
+{% endfor %}
+
+
+ Vlan1000
+ 192.168.0.1/27
+
+
+
+
+
+
+
+
+
+
+{% for index in range(2) %}
+
+ DeviceInterfaceLink
+ ARISTA0{{ index*2+1 }}T1
+ Ethernet1
+ {{ inventory_hostname }}
+ {{ port_alias[index*16] }}
+
+
+ DeviceInterfaceLink
+ ARISTA0{{ index*2+1 }}T1
+ Ethernet2
+ {{ inventory_hostname }}
+ {{ port_alias[index*16+1] }}
+
+
+ DeviceInterfaceLink
+ ARISTA0{{ index*2+2 }}T1
+ Ethernet1
+ {{ inventory_hostname }}
+ {{ port_alias[index*16+4] }}
+
+
+ DeviceInterfaceLink
+ ARISTA0{{ index*2+2 }}T1
+ Ethernet2
+ {{ inventory_hostname }}
+ {{ port_alias[index*16+5] }}
+
+{% endfor %}
+
+
+
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
+ {{ ansible_host }}
+
+
+{% if VM_topo %}
+{% for dev in neighbor_eosvm_mgmt %}
+{% if 'T1' in dev %}
+{% set dev_type = 'LeafRouter' %}
+{% elif 'T2' in dev %}
+{% set dev_type = 'SpineRouter' %}
+{% elif 'T0' in dev %}
+{% set dev_type = 'TorRouter' %}
+{% else %}
+{% set dev_ytpe = 'Unknown' %}
+{% endif %}
+
+ "{{ dev }}"
+
+ {{ neighbor_eosvm_mgmt[dev] }}
+
+ Arista-VM
+
+{% endfor %}
+{% endif %}
+
+
+{% include 'dev_metadata.j2' %}
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
diff --git a/ansible/templates/topo/t0.j2 b/ansible/templates/topo/t0.j2
new file mode 100644
index 00000000000..e7722dd0560
--- /dev/null
+++ b/ansible/templates/topo/t0.j2
@@ -0,0 +1,205 @@
+
+
+
+
+{% for index in range(4) %}
+
+ false
+ {{ inventory_hostname }}
+ 10.0.0.{{ 56 + index*2 }}
+ ARISTA0{{ index+1 }}T1
+ 10.0.0.{{ 56 + index*2 +1 }}
+ 1
+ 10
+ 3
+
+
+ {{ inventory_hostname }}
+ FC00::{{ ('%0x' % (113 + index*4)) | upper }}
+ ARISTA0{{ index+1 }}T1
+ FC00::{{ ('%0x' % (113 + index*4 +1)) | upper }}
+ 1
+ 10
+ 3
+
+{% endfor %}
+
+
+
+ 65100
+ {{ inventory_hostname }}
+
+{% for index in range(4) %}
+
+ 10.0.0.{{ 57 + index*2 }}
+
+
+
+
+{% endfor %}
+
+ BGPPeer
+ 10.1.0.32
+
+
+
+ BGPSLBPassive
+ 10.255.0.0/27
+
+
+ BGPPeer
+ 10.1.0.32
+
+
+
+ BGPVac
+ 192.168.0.0/27
+
+
+
+
+{% for index in range(4) %}
+
+ 64600
+ ARISTA0{{ index+1 }}T1
+
+
+{% endfor %}
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::32/128
+
+ FC00:1::32/128
+
+
+
+
+ HostIP
+ eth0
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+
+ V6HostIP
+ eth0
+
+ FC00:2::32/64
+
+ FC00:2::32/64
+
+
+
+
+
+
+ {{ inventory_hostname }}
+
+{% for index in range(4) %}
+
+ PortChannel0{{ index+1 }}
+ {{ port_alias[28+index] }}
+
+
+{% endfor %}
+
+
+
+ Vlan1000
+ {{ port_alias[1] }};{{ port_alias[2] }};{{ port_alias[3] }};{{ port_alias[4] }};{{ port_alias[5] }};{{ port_alias[6] }};{{ port_alias[7] }};{{ port_alias[8] }};{{ port_alias[9] }};{{ port_alias[10] }};{{ port_alias[11] }};{{ port_alias[12] }};{{ port_alias[13] }};{{ port_alias[14] }};{{ port_alias[15] }};{{ port_alias[16] }};{{ port_alias[17] }};{{ port_alias[18] }};{{ port_alias[19] }};{{ port_alias[20] }};{{ port_alias[21] }};{{ port_alias[22] }};{{ port_alias[23] }};{{ port_alias[24] }}
+ False
+ 0.0.0.0/0
+
+ 1000
+ 1000
+ 192.168.0.0/27
+
+
+
+{% for index in range(4) %}
+
+
+ PortChannel0{{ index +1 }}
+ 10.0.0.{{ 56 + index*2 }}/31
+
+
+
+ PortChannel0{{ index +1 }}
+ FC00::{{ ('%0x' % (113+index*4)) | upper }}/126
+
+{% endfor %}
+
+
+ Vlan1000
+ 192.168.0.1/27
+
+
+
+
+
+
+
+
+
+
+{% for index in range(4) %}
+
+ DeviceInterfaceLink
+ ARISTA0{{ index+1 }}T1
+ Ethernet1
+ {{ inventory_hostname }}
+ {{ port_alias[28+index] }}
+
+{% endfor %}
+
+
+
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
+ {{ ansible_host }}
+
+
+{% if VM_topo %}
+{% for dev in neighbor_eosvm_mgmt %}
+{% if 'T1' in dev %}
+{% set dev_type = 'LeafRouter' %}
+{% elif 'T2' in dev %}
+{% set dev_type = 'SpineRouter' %}
+{% elif 'T0' in dev %}
+{% set dev_type = 'TorRouter' %}
+{% else %}
+{% set dev_ytpe = 'Unknown' %}
+{% endif %}
+
+ "{{ dev }}"
+
+ {{ neighbor_eosvm_mgmt[dev] }}
+
+ Arista-VM
+
+{% endfor %}
+{% endif %}
+
+
+{% include 'dev_metadata.j2' %}
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
diff --git a/ansible/templates/topo/t1-lag.j2 b/ansible/templates/topo/t1-lag.j2
new file mode 100644
index 00000000000..9f1f0db5330
--- /dev/null
+++ b/ansible/templates/topo/t1-lag.j2
@@ -0,0 +1,235 @@
+
+
+
+
+{% for index in range(16) %}
+
+ ARISTA{{ '%02d' % (index + 1) }}T0
+ 10.0.0.{{ (32 + index * 2 + 1) }}
+ {{ inventory_hostname }}
+ 10.0.0.{{ (32 + index * 2) }}
+ 1
+ 10
+ 3
+
+
+ ARISTA{{ '%02d' % (index + 1) }}T0
+ FC00::{{ ('%0x' % (65+index*4+1)) | upper }}
+ {{ inventory_hostname }}
+ FC00::{{ ('%0x' % (65+index*4)) | upper}}
+ 1
+ 10
+ 3
+
+{% if (index%2)==0 %}
+
+ {{ inventory_hostname }}
+ 10.0.0.{{ (index*2) }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ 10.0.0.{{ (index*2+1) }}
+ 1
+ 10
+ 3
+
+
+ {{ inventory_hostname }}
+ FC00::{{ ('%0x' % (index*4 +1)) | upper }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ FC00::{{ ('%0x' % (index*4+2)) | upper }}
+ 1
+ 10
+ 3
+
+{% endif %}
+{% endfor %}
+
+
+
+ 65100
+ {{ inventory_hostname }}
+
+{% for ip in range(16) %}
+
+ 10.0.0.{{ ip*2+33 }}
+
+
+
+{% if (ip%2)==0 %}
+
+ 10.0.0.{{ ip*2+1 }}
+
+
+
+{% endif %}
+{% endfor %}
+
+
+
+{% for i in range(1,17,1) %}
+
+ 640{{ '%02d' % i }}
+ ARISTA{{ '%02d' % i }}T0
+
+
+{% if (i%2)==1 %}
+
+ 65200
+ ARISTA{{ '%02d' % i }}T2
+
+
+{% endif %}
+{% endfor %}
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::32/128
+
+ FC00:1::32/128
+
+
+
+
+ HostIP
+ eth0
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+
+ V6HostIP
+ eth0
+
+ FC00:2::32/64
+
+ FC00:2::32/64
+
+
+
+
+
+ {{ inventory_hostname }}
+
+{% for index in range(8) %}
+
+ PortChannelInterface
+ PortChannel{{ index*8 }}
+ {{ port_alias[index*2] }};{{ port_alias[index*2+1] }}
+
+
+{% endfor %}
+
+
+
+{% for index in range(8) %}
+
+ IPInterface
+
+ PortChannel{{ index*8 }}
+ 10.0.0.{{ index*4 }}/31
+
+
+ IPInterface
+
+ PortChannel{{ index*8 }}
+ FC00::{{ ('%0x' % (index*8+1)) | upper }}/126
+
+{% endfor %}
+{% for index in range(16) %}
+
+ IPInterface
+
+ {{ port_alias[16+index] }}
+ 10.0.0.{{ 32+index*2 }}/31
+
+
+ IPInterface
+
+ {{ port_alias[16+index] }}
+ FC00::{{ ('%0x' % (64+index*4 +1)) | upper }}/126
+
+{% endfor %}
+
+
+
+
+
+
+
+
+
+{% for index in range(0,16,2) %}
+
+ DeviceInterfaceLink
+ {{ inventory_hostname }}
+ {{ port_alias[index] }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ Ethernet1
+
+
+ DeviceInterfaceLink
+ {{ inventory_hostname }}
+ {{ port_alias[index+1] }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ Ethernet2
+
+{% endfor %}
+{% for index in range(16) %}
+
+ DeviceInterfaceLink
+ {{ inventory_hostname }}
+ {{ port_alias[16+index] }}
+ ARISTA{{ '%02d' % (index+1) }}T0
+ Ethernet1
+
+{% endfor %}
+
+
+
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
+ {{ ansible_host }}
+
+
+{% if VM_topo %}
+{% for dev in neighbor_eosvm_mgmt.keys()|sort %}
+{% if 'T1' in dev %}
+{% set dev_type = 'LeafRouter' %}
+{% elif 'T2' in dev %}
+{% set dev_type = 'SpineRouter' %}
+{% elif 'T0' in dev %}
+{% set dev_type = 'ToRRouter' %}
+{% else %}
+{% set dev_type = 'Unknown' %}
+{% endif %}
+
+ "{{ dev }}"
+ Arista-VM
+
+ {{ neighbor_eosvm_mgmt[dev] }}
+
+
+{% endfor %}
+{% endif %}
+
+
+{% include 'dev_metadata.j2' %}
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
diff --git a/ansible/templates/topo/t1.j2 b/ansible/templates/topo/t1.j2
new file mode 100644
index 00000000000..635e7539b4f
--- /dev/null
+++ b/ansible/templates/topo/t1.j2
@@ -0,0 +1,197 @@
+
+
+
+
+{% for index in range(16) %}
+
+ ARISTA{{ '%02d' % (index + 1) }}T0
+ 10.0.0.{{ (32 + index * 2 + 1) }}
+ {{ inventory_hostname }}
+ 10.0.0.{{ (32 + index * 2) }}
+ 1
+ 10
+ 3
+
+
+ ARISTA{{ '%02d' % (index + 1) }}T0
+ FC00::{{ ('%0x' % (65+index*4+1)) | upper }}
+ {{ inventory_hostname }}
+ FC00::{{ ('%0x' % (65+index*4)) | upper}}
+ 1
+ 10
+ 3
+
+
+ {{ inventory_hostname }}
+ 10.0.0.{{ (index*2) }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ 10.0.0.{{ (index*2+1) }}
+ 1
+ 10
+ 3
+
+
+ {{ inventory_hostname }}
+ FC00::{{ ('%0x' % (index*4 +1)) | upper }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ FC00::{{ ('%0x' % (index*4+2)) | upper }}
+ 1
+ 10
+ 3
+
+{% endfor %}
+
+
+
+ 65100
+ {{ inventory_hostname }}
+
+{% for ip in range(1,32,2) %}
+
+ 10.0.0.{{ 32+ip }}
+
+
+
+
+ 10.0.0.{{ ip }}
+
+
+
+{% endfor %}
+
+
+
+{% for i in range(1,17,1) %}
+
+ 640{{ '%02d' % i }}
+ ARISTA{{ '%02d' % i }}T0
+
+
+
+ 65200
+ ARISTA{{ '%02d' % i }}T2
+
+
+{% endfor %}
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+ HostIP1
+ Loopback0
+
+ FC00:1::32/128
+
+ FC00:1::32/128
+
+
+
+
+ HostIP
+ eth0
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+ {{ ansible_host }}/{{ mgmt_subnet_mask_length }}
+
+
+ V6HostIP
+ eth0
+
+ FC00:2::32/64
+
+ FC00:2::32/64
+
+
+
+
+
+ {{ inventory_hostname }}
+
+
+
+{% for index in range(32) %}
+
+
+ {{ port_alias[index] }}
+ 10.0.0.{{ index*2 }}/31
+
+
+
+ {{ port_alias[index] }}
+ FC00::{{ ('%0x' % (index*4 +1)) | upper }}/126
+
+{% endfor %}
+
+
+
+
+
+
+
+
+
+{% for index in range(16) %}
+
+ DeviceInterfaceLink
+ {{ inventory_hostname }}
+ {{ port_alias[index] }}
+ ARISTA{{ '%02d' % (index+1) }}T2
+ Ethernet1
+
+{% endfor %}
+{% for index in range(16) %}
+
+ DeviceInterfaceLink
+ {{ inventory_hostname }}
+ {{ port_alias[16+index] }}
+ ARISTA{{ '%02d' % (index+1) }}T0
+ Ethernet1
+
+{% endfor %}
+
+
+
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
+ {{ ansible_host }}
+
+
+{% if VM_topo %}
+{% for dev in neighbor_eosvm_mgmt.keys()|sort %}
+{% if 'T1' in dev %}
+{% set dev_type = 'LeafRouter' %}
+{% elif 'T2' in dev %}
+{% set dev_type = 'SpineRouter' %}
+{% elif 'T0' in dev %}
+{% set dev_type = 'ToRRouter' %}
+{% else %}
+{% set dev_type = 'Unknown' %}
+{% endif %}
+
+ "{{ dev }}"
+ Arista-VM
+
+ {{ neighbor_eosvm_mgmt[dev] }}
+
+
+{% endfor %}
+{% endif %}
+
+
+{% include 'dev_metadata.j2' %}
+ {{ inventory_hostname }}
+ {{ hwsku }}
+
diff --git a/ansible/testbed-cli.sh b/ansible/testbed-cli.sh
new file mode 100755
index 00000000000..8d3c2d9abf4
--- /dev/null
+++ b/ansible/testbed-cli.sh
@@ -0,0 +1,154 @@
+#!/bin/bash
+
+set -e
+
+function usage
+{
+ echo "testbed-cli. Interface to testbeds"
+ echo "Usage : $0 { start-vms | stop-vms } server-name vault-password-file"
+ echo "Usage : $0 { add-topo | remove-topo | renumber-topo } topo-name vault-password-file"
+ echo "Usage : $0 { gen-mg | deploy-mg } topo-name vault-password-file"
+ echo
+ echo "To start VMs on a server: $0 start-vms 'server-name' ~/.password"
+ echo "To stop VMs on a server: $0 stop-vms 'server-name' ~/.password"
+ echo "To deploy a topology on a server: $0 add-topo 'topo-name' ~/.password"
+ echo "To remove a topology on a server: $0 remove-topo 'topo-name' ~/.password"
+ echo "To renumber a topology on a server: $0 renumber-topo 'topo-name' ~/.password" , where topo-name is target topology
+ echo "To generate minigraph for DUT in a topology: $0 gen-mg 'topo-name' ~/.password"
+ echo "To deploy minigraph to DUT in a topology: $0 deploy-mg 'topo-name' ~/.password"
+ echo
+ echo "You should define your topology in testbed.csv file"
+ echo
+ exit
+}
+
+function read_file
+{
+ echo reading
+
+ # Filter testbed names in the first column in the testbed definition file
+ line=$(cat testbed.csv | grep "^$1,")
+
+ if [ $? -ne 0 ]
+ then
+ echo "Couldn't find topology name '$1'"
+ exit
+ fi
+
+ NL='
+'
+ case $line in
+ *"$NL"*) echo "Find more than one topology names in testbed.csv"
+ exit
+ ;;
+ *) echo Found topology $1
+ ;;
+ esac
+
+ IFS=, read -r -a line_arr <<< $line
+
+ testbed_name=${line_arr[1]}
+ topo=${line_arr[2]}
+ ptf_imagename=${line_arr[3]}
+ ptf_ip=${line_arr[4]}
+ server=${line_arr[5]}
+ vm_base=${line_arr[6]}
+ dut=${line_arr[7]}
+}
+
+function start_vms
+{
+ echo "Starting VMs on server '$1'"
+
+ ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_start_VMs.yml --vault-password-file="$2" -l "$1"
+}
+
+function stop_vms
+{
+ echo "Stopping VMs on server '$1'"
+
+ ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_stop_VMs.yml --vault-password-file="$2" -l "$1"
+}
+
+function add_topo
+{
+ echo "Deploying topology '$1'"
+
+ read_file $1
+
+ ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_add_vm_topology.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e dut_name="$dut" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename"
+
+ ansible-playbook fanout_connect.yml -i veos --limit "$server" --vault-password-file="$2" -e "dut=$dut"
+
+ echo Done
+}
+
+function remove_topo
+{
+ echo "Removing topology '$1'"
+
+ read_file $1
+
+ ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_remove_vm_topology.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e dut_name="$dut" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename"
+
+ echo Done
+}
+
+function renumber_topo
+{
+ echo "Renumbering topology '$1'"
+
+ read_file $1
+
+ ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_renumber_vm_topology.yml --vault-password-file="$2" -l "$server" -e topo_name="$topo_name" -e dut_name="$dut" -e VM_base="$vm_base" -e ptf_ip="$ptf_ip" -e topo="$topo" -e vm_set_name="$testbed_name" -e ptf_imagename="$ptf_imagename"
+
+ ansible-playbook fanout_connect.yml -i veos --limit "$server" --vault-password-file="$2" -e "dut=$dut"
+
+ echo Done
+}
+
+function generate_minigraph
+{
+ echo "Generating minigraph '$1'"
+
+ read_file $1
+
+ ansible-playbook -i lab config_sonic_basedon_testbed.yml --vault-password-file="$2" -l "$dut" -e vm_base="$vm_base" -e topo="$topo"
+
+ echo Done
+}
+
+function deploy_minigraph
+{
+ echo "Deploying minigraph '$1'"
+
+ read_file $1
+
+ ansible-playbook -i lab config_sonic_basedon_testbed.yml --vault-password-file="$2" -l "$dut" -e vm_base="$vm_base" -e topo="$topo" -e deploy=true
+
+ echo Done
+}
+
+if [ $# -lt 3 ]
+then
+ usage
+fi
+
+case "$1" in
+ start-vms) start_vms $2 $3
+ ;;
+ stop-vms) stop_vms $2 $3
+ ;;
+ add-topo) add_topo $2 $3
+ ;;
+ remove-topo) remove_topo $2 $3
+ ;;
+ renumber-topo) renumber_topo $2 $3
+ ;;
+ gen-mg) generate_minigraph $2 $3
+ ;;
+ deploy-mg) deploy_minigraph $2 $3
+ ;;
+ *) usage
+ ;;
+esac
diff --git a/ansible/testbed.csv b/ansible/testbed.csv
new file mode 100644
index 00000000000..1139b9164af
--- /dev/null
+++ b/ansible/testbed.csv
@@ -0,0 +1,4 @@
+# conf-name,group-name,topo,ptf_image_name,ptf_mgmt_ip,server,vm_base,dut,comment
+ptf1-m,ptf1,ptf32,docker-ptf-sai-mlnx,10.255.0.188/24,server_1,,str-msn2700-01,Tests ptf
+vms-t1,vms1-1,t1,docker-ptf-sai-mlnx,10.255.0.178/24,server_1,VM0100,str-msn2700-01,Tests vms
+vms-t1-lag,vms1-1,t1-lag,docker-ptf-sai-mlnx,10.255.0.178/24,server_1,VM0100,str-msn2700-01,Tests vms
diff --git a/ansible/testbed_add_vm_topology.yml b/ansible/testbed_add_vm_topology.yml
new file mode 100644
index 00000000000..f623cbb747b
--- /dev/null
+++ b/ansible/testbed_add_vm_topology.yml
@@ -0,0 +1,117 @@
+# This Playbook add a topology to a server
+#
+# Topologies are defined inside of vars/ directorie in files vars/topo_{{ topology_name}}.yml
+# This file contains three structures:
+# - topology
+# - configuration property
+# - configuration
+#
+# topology key contains a dictionary of hostnames with 'vm_offset' and 'vlans' keys in it.
+# 'vm_offset' is used to map current hostname vm_set VM to server VM (like ARISTA01T0 -> VM0300).
+# This offset is used on VM_base
+# 'vlans' is a list of vlan offsets which helps us to calculate vlan numbers which will be connected to Eth1/1..Eth1/8 interfaces.
+# These offsets are used with vlan_base
+#
+# Every topology should have a name to distinct one topology from another on the server
+# Every topology contains a ptf container which will be used as placeholder for the injected interfaces from VMs, or direct connections to PTF host
+#
+# To add a topology please use following command
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_add_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e dut_name=str-msn2700-01 -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e ptf_imagename="docker_ptf"
+#
+# Parameters
+# -l server_3 - this playbook have to be limited to run only on one server
+# -e vm_set_name=first - the name of vm_set
+# -e dut_name=str-msn2700-01 - the name of target dut
+# -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set
+# -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface
+# -e topo=t0 - the name of removed topo
+# -e ptf_imagename=docker-ptf - name of a docker-image which will be used for the ptf docker container
+
+- hosts: servers:&vm_host
+ vars_files:
+ - vars/docker_registry.yml
+ pre_tasks:
+ - name: Check for a single host
+ fail: msg="Please use -l server_X to limit this playbook to one host"
+ when: "{{ play_hosts|length }} != 1"
+
+ - name: Check that variable vm_set_name is defined
+ fail: msg="Define vm_set_name variable with -e vm_set_name=something"
+ when: vm_set_name is not defined
+
+ - name: Check that variable dut_name is defined
+ fail: msg="Define dut_name variable with -e dut_name=something"
+ when: dut_name is not defined
+
+ - name: Check that variable VM_base is defined
+ fail: msg="Define VM_base variable with -e VM_base=something"
+ when: VM_base is not defined
+
+ - name: Check that variable ptf_ip is defined
+ fail: msg="Define ptf ip variable with -e ptf_ip=something"
+ when: ptf_ip is not defined
+
+ - name: Check that variable topo is defined
+ fail: msg="Define topo variable with -e topo=something"
+ when: topo is not defined or topo not in topologies
+
+ - name: Check that variable ptf_imagename is defined
+ fail: msg="Define ptf_imagename variable with -e ptf_imagename=something"
+ when: ptf_imagename is not defined
+
+ - name: Load topo variables
+ include_vars: "vars/topo_{{ topo }}.yml"
+
+ - name: Read dut minigraph
+ conn_graph_facts: host={{ dut_name }}
+ connection: local
+
+ - name: Extracting vlan_range
+ set_fact: vlan_base={{ device_vlan_list | min }}
+
+ roles:
+ - { role: vm_set, action: 'add_topo' }
+
+- hosts: servers:&eos
+ gather_facts: no
+ pre_tasks:
+ - name: Check that variable topo is defined
+ fail: msg="Define topo variable with -e topo=something"
+ when: topo is not defined or topo not in topologies
+
+ - name: Load topo variables
+ include_vars: "vars/topo_{{ topo }}.yml"
+
+ - name: Check that variable VM_base is defined
+ fail: msg="Define VM_base variable with -e VM_base=something"
+ when: VM_base is not defined
+
+ - name: Include server vars
+ include_vars: "{{ host_var_file }}"
+
+ - name: Find current server group
+ set_fact: current_server={{ group_names | extract_by_prefix('server_') }}
+
+ - name: Extract VM names from the inventory
+ set_fact: VM_hosts={{ groups[current_server] | filter_by_prefix('VM') }}
+
+ - name: Generate vm list of target VMs
+ set_fact: VM_targets={{ VM_hosts | filter_vm_targets(topology['VMs'], VM_base) }}
+ when: topology['VMs'] is defined
+
+ - name: Generate hostname for target VM
+ set_fact: hostname={{ VM_hosts | extract_hostname(topology['VMs'], VM_base, inventory_hostname) }}
+ when: topology['VMs'] is defined
+
+ - name: Set properties list to default value, when properties are not defined
+ set_fact: properties_list=[]
+ when: configuration is not defined or configuration[hostname] is not defined or configuration[hostname]['properties'] is not defined
+
+ - name: Set properties list to values, when they're defined
+ set_fact: properties_list=configuration[hostname]['properties']
+ when: configuration and configuration[hostname] and configuration[hostname]['properties'] is defined
+
+ roles:
+ - { role: eos, when: topology.VMs is defined and inventory_hostname in VM_targets } # role eos will be executed in any case, and when will evaluate with every task
+
+
diff --git a/ansible/testbed_remove_vm_topology.yml b/ansible/testbed_remove_vm_topology.yml
new file mode 100644
index 00000000000..b17d5b8412f
--- /dev/null
+++ b/ansible/testbed_remove_vm_topology.yml
@@ -0,0 +1,61 @@
+# This Playbook remove a topology from a server
+#
+# For additional details see playbook testbed_add_vm_topology.yml
+#
+# To remove a topology please use following command
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_remove_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e -e dut_name=str-msn2700-01 -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e ptf_imagename="docker_ptf"
+#
+# Parameters
+# -l server_3 - this playbook have to be limited to run only on one server
+# -e vm_set_name=first - the name of vm_set
+# -e dut_name=str-msn2700-01 - the name of target dut
+# -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set
+# -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface
+# -e topo=t0 - the name of removed topo
+# -e ptf_imagename=docker-ptf - name of a docker-image which will be used for the ptf docker container
+
+- hosts: servers:&vm_host
+ vars_files:
+ - vars/docker_registry.yml
+ pre_tasks:
+ - name: Check for a single host
+ fail: msg="Please use -l server_X to limit this playbook to one host"
+ when: "{{ play_hosts|length }} != 1"
+
+ - name: Check that variable vm_set_name is defined
+ fail: msg="Define vm_set_name variable with -e vm_set_name=something"
+ when: vm_set_name is not defined
+
+ - name: Check that variable dut_name is defined
+ fail: msg="Define dut_name variable with -e dut_name=something"
+ when: dut_name is not defined
+
+ - name: Check that variable VM_base is defined
+ fail: msg="Define VM_base variable with -e VM_base=something"
+ when: VM_base is not defined
+
+ - name: Check that variable ptf_ip is defined
+ fail: msg="Define ptf ip variable with -e ptf_ip=something"
+ when: ptf_ip is not defined
+
+ - name: Check that variable topo is defined
+ fail: msg="Define topo variable with -e topo=something"
+ when: topo is not defined or topo not in topologies
+
+ - name: Check that variable ptf_imagename is defined
+ fail: msg="Define ptf_imagename variable with -e ptf_imagename=something"
+ when: ptf_imagename is not defined
+
+ - name: Load topo variables
+ include_vars: "vars/topo_{{ topo }}.yml"
+
+ - name: Read dut minigraph
+ conn_graph_facts: host={{ dut_name }}
+ connection: local
+
+ - name: Extracting vlan_range
+ set_fact: vlan_base={{ device_vlan_list | min }}
+
+ roles:
+ - { role: vm_set, action: 'remove_topo' }
+
diff --git a/ansible/testbed_renumber_vm_topology.yml b/ansible/testbed_renumber_vm_topology.yml
new file mode 100644
index 00000000000..727eddfef8c
--- /dev/null
+++ b/ansible/testbed_renumber_vm_topology.yml
@@ -0,0 +1,60 @@
+# This Playbook renumber a topology on a server
+#
+#
+# To renumber a topology please use following command
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_renumber_vm_topology.yml --vault-password-file=~/.password -l server_3 -e vm_set_name=first -e VM_base=VM0300 -e ptf_ip=10.255.0.255/23 -e topo=t0 -e dut_name=str-msn-2700-05 -e ptf_imagename="docker_ptf"
+#
+# Parameters
+# -l server_3 - this playbook have to be limited to run only on one server
+# -e vm_set_name=first - the name of vm_set
+# -e dut_name=str-msn2700-02 - the new value of a dut name, the dut will be connected to the current testbed
+# -e VM_base=VM0300 - the VM name which is used to as base to calculate VM name for this set
+# -e ptf_ip=10.255.0.255/23 - the ip address and prefix of ptf container mgmt interface
+# -e topo=t0 - the name of removed topo
+# -e ptf_imagename=docker-ptf - name of a docker-image which will be used for the ptf docker container
+
+- hosts: servers:&vm_host
+ vars_files:
+ - vars/docker_registry.yml
+ pre_tasks:
+ - name: Check for a single host
+ fail: msg="Please use -l server_X to limit this playbook to one host"
+ when: "{{ play_hosts|length }} != 1"
+
+ - name: Check that variable vm_set_name is defined
+ fail: msg="Define vm_set_name variable with -e vm_set_name=something"
+ when: vm_set_name is not defined
+
+ - name: Check that variable dut_name is defined
+ fail: msg="Define dut_name variable with -e dut_name=something"
+ when: dut_name is not defined
+
+ - name: Check that variable VM_base is defined
+ fail: msg="Define VM_base variable with -e VM_base=something"
+ when: VM_base is not defined
+
+ - name: Check that variable ptf_ip is defined
+ fail: msg="Define ptf ip variable with -e ptf_ip=something"
+ when: ptf_ip is not defined
+
+ - name: Check that variable topo is defined
+ fail: msg="Define topo variable with -e topo=something"
+ when: topo is not defined or topo not in topologies
+
+ - name: Check that variable ptf_imagename is defined
+ fail: msg="Define ptf_imagename variable with -e ptf_imagename=something"
+ when: ptf_imagename is not defined
+
+ - name: Load topo variables
+ include_vars: "vars/topo_{{ topo }}.yml"
+
+ - name: Read dut minigraph
+ conn_graph_facts: host={{ dut_name }}
+ connection: local
+
+ - name: Extracting vlan_range
+ set_fact: vlan_base={{ device_vlan_list | min }}
+
+ roles:
+ - { role: vm_set, action: 'renumber_topo' }
+
diff --git a/ansible/testbed_start_VMs.yml b/ansible/testbed_start_VMs.yml
new file mode 100644
index 00000000000..73afc1506b0
--- /dev/null
+++ b/ansible/testbed_start_VMs.yml
@@ -0,0 +1,23 @@
+---
+# This Playbook deploys all VMs defined in an inventory file under vms_x
+#
+# We need to run this playbook first, before we run any testbed_add script
+#
+# Every VM has 10 interfaces:
+# - mgmt interface which is connected to the routable physical network. This address is defined as ansible_host in veos playbook
+# - Eth1/1 - Eth1/8 is connected to an ovs-bridge and later it could bound by testbed_add_vm_topology.yml
+# - Eth1/9 is connected to other vm_set VMs Eth1/9
+#
+# To start all vm_sets on all servers:
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_start_VMs.yml --vault-password-file=~/.password
+#
+# To run on the first server only:
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_start_VMs.yml --vault-password-file=~/.password -l server_1
+#
+
+- hosts: servers:&vm_host
+ vars_files:
+ - vars/azure_storage.yml
+ tasks:
+ roles:
+ - { role: vm_set, action: 'start' }
diff --git a/ansible/testbed_stop_VMs.yml b/ansible/testbed_stop_VMs.yml
new file mode 100644
index 00000000000..bc413fd55ea
--- /dev/null
+++ b/ansible/testbed_stop_VMs.yml
@@ -0,0 +1,15 @@
+---
+# This Playbook removes all VMs defined in an inventory file under vms_x
+#
+# We need to run this playbook before server restart to clean up everything.
+#
+# To stop all vm_sets on all servers:
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_stop_VMs.yml --vault-password-file=~/.password
+#
+# To run this on the first server only:
+# ANSIBLE_SCP_IF_SSH=y ansible-playbook -i veos testbed_stop_VMs.yml --vault-password-file=~/.password -l server_1
+#
+
+- hosts: servers:&vm_host
+ roles:
+ - { role: vm_set, action: 'stop' }
diff --git a/ansible/vars/acl/acl_counter_traffic_test_vars.yml b/ansible/vars/acl/acl_counter_traffic_test_vars.yml
index 97ec99b6a13..ed30db51d6e 100644
--- a/ansible/vars/acl/acl_counter_traffic_test_vars.yml
+++ b/ansible/vars/acl/acl_counter_traffic_test_vars.yml
@@ -18,9 +18,11 @@ rule_name: acl_config_rule
mirror_table_name: acl_test_table_mirror
mirror_rule_name: acl_config_rule_mirror
-switch_if1_ip: 20.0.0.1
-switch_if2_ip: 21.0.0.1
-dst_mirror_subnet: 2.0.0.0/24
+switch_if1_ip: 10.0.0.0
+neighbor1_ip: 10.0.0.1
+switch_if2_ip: 10.0.0.2
+neighbor2_ip: 10.0.0.3
+dst_mirror_subnet: 2.2.2.0/24
packets_sent: 3
config_files:
diff --git a/ansible/vars/acl/acl_port_range_test_vars.yml b/ansible/vars/acl/acl_port_range_test_vars.yml
index c2e9860f70e..38ec4c637af 100644
--- a/ansible/vars/acl/acl_port_range_test_vars.yml
+++ b/ansible/vars/acl/acl_port_range_test_vars.yml
@@ -28,12 +28,12 @@ host_testdir: /tmp/ptf_tests
# traffic-test settings
table_name: acl_test_table
-rule_limited_port_range_name: acl_rule_limited_port_range
+rule_limited_port_range_name: acl_rule_limited_range
packets_sent: 3
# mirror-testing settings
-switch_if_ip: 20.0.0.1
-ptf_host_if_ip: 20.0.0.2
+switch_if_ip: 10.0.0.0
+ptf_host_if_ip: 10.0.0.1
dst_mirror_subnet: 2.0.0.0/24
config_files:
diff --git a/ansible/vars/acl/acl_traffic_test_vars.yml b/ansible/vars/acl/acl_traffic_test_vars.yml
index af8d7e80289..cb0d21dc935 100644
--- a/ansible/vars/acl/acl_traffic_test_vars.yml
+++ b/ansible/vars/acl/acl_traffic_test_vars.yml
@@ -1,11 +1,11 @@
---
-host1_ip : 21.0.0.2
-host2_ip : 22.0.0.2
-subnet1 : 21.0.0.0/24
-subnet2 : 22.0.0.0/24
-switch_ip1 : 21.0.0.1
-switch_ip2 : 22.0.0.1
+host1_ip : 10.0.0.1
+host2_ip : 10.0.0.3
+subnet1 : 10.0.0.0/31
+subnet2 : 10.0.0.2/31
+switch_ip1 : 10.0.0.0
+switch_ip2 : 10.0.0.2
host_testdir: /tmp
run_ping_test: "{{ tests_location }}/acl_traffic_test/run_ping_test.yml"
diff --git a/ansible/vars/acl/acl_vars.yml b/ansible/vars/acl/acl_vars.yml
index c7d4e5be813..a069a9c0c65 100644
--- a/ansible/vars/acl/acl_vars.yml
+++ b/ansible/vars/acl/acl_vars.yml
@@ -7,6 +7,6 @@ out_dir: /home/admin/acl_tests/results
docker_testdir: /tmp
tests_location: roles/test/tasks/acl
-run_config_test: "{{ tests_location }}/run_config_test.yml"
-run_config_cleanup: "{{ tests_location }}/run_config_cleanup.yml"
-run_loganalyzer: "{{ tests_location }}/run_loganalyzer.yml"
+run_config_test: "roles/test/tasks/run_config_test.yml"
+run_config_cleanup: "roles/test/tasks/run_config_cleanup.yml"
+run_loganalyzer: "roles/test/tasks/run_loganalyzer.yml"
diff --git a/ansible/vars/azure_storage.yml b/ansible/vars/azure_storage.yml
index 010d4380c5e..6bdae04494c 100644
--- a/ansible/vars/azure_storage.yml
+++ b/ansible/vars/azure_storage.yml
@@ -1,2 +1,4 @@
-vmimages_saskey: use_own_value
+## saskey are treated as credential in Credscan
+vmimage_saskey: use_own_value
+cdimage_saskey: use_own_value
diff --git a/ansible/vars/deployment_id_asn_map.yml b/ansible/vars/deployment_id_asn_map.yml
new file mode 100644
index 00000000000..3bf916c1316
--- /dev/null
+++ b/ansible/vars/deployment_id_asn_map.yml
@@ -0,0 +1,2 @@
+deployment_id_asn_map:
+ "1": 65432
diff --git a/ansible/vars/lag_fanout_ports_test_vars.yml b/ansible/vars/lag_fanout_ports_test_vars.yml
new file mode 100644
index 00000000000..86c122aad9f
--- /dev/null
+++ b/ansible/vars/lag_fanout_ports_test_vars.yml
@@ -0,0 +1,18 @@
+portmap_dut_fn: {
+ Ethernet0: 'ethernet 1/1',
+ Ethernet4: 'ethernet 1/2',
+ Ethernet8: 'ethernet 1/3',
+ Ethernet12: 'ethernet 1/4',
+ Ethernet16: 'ethernet 1/5',
+ Ethernet20: 'ethernet 1/6',
+ Ethernet24: 'ethernet 1/7',
+ Ethernet28: 'ethernet 1/8',
+ Ethernet32: 'ethernet 1/9',
+ Ethernet36: 'ethernet 1/10',
+ Ethernet40: 'ethernet 1/11',
+ Ethernet44: 'ethernet 1/12',
+ Ethernet48: 'ethernet 1/13',
+ Ethernet52: 'ethernet 1/14',
+ Ethernet56: 'ethernet 1/15',
+ Ethernet60: 'ethernet 1/16'
+}
diff --git a/ansible/vars/acl/run_config_test_vars.yml b/ansible/vars/run_config_test_vars.yml
similarity index 100%
rename from ansible/vars/acl/run_config_test_vars.yml
rename to ansible/vars/run_config_test_vars.yml
diff --git a/ansible/vars/acl/run_loganalyzer_vars.yml b/ansible/vars/run_loganalyzer_vars.yml
similarity index 87%
rename from ansible/vars/acl/run_loganalyzer_vars.yml
rename to ansible/vars/run_loganalyzer_vars.yml
index 78a42e42500..c7d2bf095b2 100644
--- a/ansible/vars/acl/run_loganalyzer_vars.yml
+++ b/ansible/vars/run_loganalyzer_vars.yml
@@ -12,4 +12,4 @@ ignore_file: loganalyzer_common_ignore.txt
summary_file: summary.loganalysis.{{ testname_unique }}.log
result_file: result.loganalysis.{{ testname_unique }}.log
-run_analyze_and_check: "{{ tests_location }}/run_analyze_and_check.yml"
+run_analyze_and_check: "roles/test/tasks/run_analyze_and_check.yml"
diff --git a/ansible/vars/acl/run_ping_test_vars.yml b/ansible/vars/run_ping_test_vars.yml
similarity index 52%
rename from ansible/vars/acl/run_ping_test_vars.yml
rename to ansible/vars/run_ping_test_vars.yml
index 500c76536ff..40dafcb8a7b 100644
--- a/ansible/vars/acl/run_ping_test_vars.yml
+++ b/ansible/vars/run_ping_test_vars.yml
@@ -3,5 +3,5 @@
testname_unique: "{{ testname }}.{{ ansible_date_time.date }}.{{ ansible_date_time.time }}"
test_out_dir: "{{ out_dir }}/{{ testname_unique }}"
-summary_file: "{{ 'summary.loganalysis.{{ testname_unique }}.log' }}"
-result_file: "{{ 'result.loganalysis.{{ testname_unique }}.log' }}"
+summary_file: "summary.loganalysis.{{ testname_unique }}.log"
+result_file: "result.loganalysis.{{ testname_unique }}.log"
diff --git a/ansible/vars/acl/run_ptf_test_vars.yml b/ansible/vars/run_ptf_test_vars.yml
similarity index 52%
rename from ansible/vars/acl/run_ptf_test_vars.yml
rename to ansible/vars/run_ptf_test_vars.yml
index 500c76536ff..40dafcb8a7b 100644
--- a/ansible/vars/acl/run_ptf_test_vars.yml
+++ b/ansible/vars/run_ptf_test_vars.yml
@@ -3,5 +3,5 @@
testname_unique: "{{ testname }}.{{ ansible_date_time.date }}.{{ ansible_date_time.time }}"
test_out_dir: "{{ out_dir }}/{{ testname_unique }}"
-summary_file: "{{ 'summary.loganalysis.{{ testname_unique }}.log' }}"
-result_file: "{{ 'result.loganalysis.{{ testname_unique }}.log' }}"
+summary_file: "summary.loganalysis.{{ testname_unique }}.log"
+result_file: "result.loganalysis.{{ testname_unique }}.log"
diff --git a/ansible/vars/topo_ptf32.yml b/ansible/vars/topo_ptf32.yml
new file mode 100644
index 00000000000..6a1ce974427
--- /dev/null
+++ b/ansible/vars/topo_ptf32.yml
@@ -0,0 +1,35 @@
+topology:
+ host_interfaces:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 12
+ - 13
+ - 14
+ - 15
+ - 16
+ - 17
+ - 18
+ - 19
+ - 20
+ - 21
+ - 22
+ - 23
+ - 24
+ - 25
+ - 26
+ - 27
+ - 28
+ - 29
+ - 30
+ - 31
+
diff --git a/ansible/vars/topo_ptf64.yml b/ansible/vars/topo_ptf64.yml
new file mode 100644
index 00000000000..e49c8207bda
--- /dev/null
+++ b/ansible/vars/topo_ptf64.yml
@@ -0,0 +1,67 @@
+topology:
+ host_interfaces:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 12
+ - 13
+ - 14
+ - 15
+ - 16
+ - 17
+ - 18
+ - 19
+ - 20
+ - 21
+ - 22
+ - 23
+ - 24
+ - 25
+ - 26
+ - 27
+ - 28
+ - 29
+ - 30
+ - 31
+ - 32
+ - 33
+ - 34
+ - 35
+ - 36
+ - 37
+ - 38
+ - 39
+ - 40
+ - 41
+ - 42
+ - 43
+ - 44
+ - 45
+ - 46
+ - 47
+ - 48
+ - 49
+ - 50
+ - 51
+ - 52
+ - 53
+ - 54
+ - 55
+ - 56
+ - 57
+ - 58
+ - 59
+ - 60
+ - 61
+ - 62
+ - 63
+
diff --git a/ansible/vars/topo_t0-64-32.yml b/ansible/vars/topo_t0-64-32.yml
new file mode 100644
index 00000000000..4e8d35941fd
--- /dev/null
+++ b/ansible/vars/topo_t0-64-32.yml
@@ -0,0 +1,160 @@
+topology:
+ host_interfaces:
+ - 2
+ - 3
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 12
+ - 13
+ - 14
+ - 15
+ - 18
+ - 19
+ - 22
+ - 23
+ - 24
+ - 25
+ - 26
+ - 27
+ - 28
+ - 29
+ - 30
+ - 31
+ VMs:
+ ARISTA01T1:
+ vlans:
+ - 0
+ - 1
+ vm_offset: 0
+ ARISTA02T1:
+ vlans:
+ - 4
+ - 5
+ vm_offset: 1
+ ARISTA03T1:
+ vlans:
+ - 16
+ - 17
+ vm_offset: 2
+ ARISTA04T1:
+ vlans:
+ - 20
+ - 21
+ vm_offset: 3
+
+configuration_properties:
+ common:
+ swrole: leaf
+ podset_number: 200
+ tor_number: 16
+ tor_subnet_number: 2
+ max_tor_subnet_number: 16
+ tor_subnet_size: 64
+ spine_asn: 65534
+ leaf_asn_start: 64802
+ tor_asn_start: 64601
+ failure_rate: 0
+ nhipv4: 10.10.246.100
+ nhipv6: FC0A::C9
+
+configuration:
+ ARISTA01T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.0
+ - FC00::1
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.1/32
+ ipv6: 2064:100::1/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.1/24
+ ipv6: fc0a::1/64
+ Port-Channel1:
+ ipv4: 10.0.0.1/31
+ ipv6: fc00::2/126
+
+ ARISTA02T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.4
+ - FC00::9
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.2/32
+ ipv6: 2064:100::2/128
+ Ethernet1:
+ lacp: 4
+ Ethernet2:
+ lacp: 4
+ Ethernet9:
+ ipv4: 10.10.246.2/24
+ ipv6: fc0a::2/64
+ Port-Channel4:
+ ipv4: 10.0.0.5/31
+ ipv6: fc00::a/126
+
+ ARISTA03T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.8
+ - FC00::11
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.3/32
+ ipv6: 2064:100::3/128
+ Ethernet1:
+ lacp: 16
+ Ethernet2:
+ lacp: 16
+ Ethernet9:
+ ipv4: 10.10.246.3/24
+ ipv6: fc0a::3/64
+ Port-Channel16:
+ ipv4: 10.0.0.9/31
+ ipv6: fc00::12/126
+
+ ARISTA04T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.12
+ - FC00::19
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.4/32
+ ipv6: 2064:100::4/128
+ Ethernet1:
+ lacp: 20
+ Ethernet2:
+ lacp: 20
+ Ethernet9:
+ ipv4: 10.10.246.4/24
+ ipv6: fc0a::4/64
+ Port-Channel20:
+ ipv4: 10.0.0.13/31
+ ipv6: fc00::1a/126
+
diff --git a/ansible/vars/topo_t0-64.yml b/ansible/vars/topo_t0-64.yml
new file mode 100644
index 00000000000..9c6c681878f
--- /dev/null
+++ b/ansible/vars/topo_t0-64.yml
@@ -0,0 +1,191 @@
+topology:
+ host_interfaces:
+ - 2
+ - 3
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 12
+ - 13
+ - 14
+ - 15
+ - 18
+ - 19
+ - 22
+ - 23
+ - 24
+ - 25
+ - 26
+ - 27
+ - 28
+ - 29
+ - 30
+ - 31
+ - 32
+ - 33
+ - 34
+ - 35
+ - 36
+ - 37
+ - 38
+ - 39
+ - 40
+ - 41
+ - 42
+ - 43
+ - 44
+ - 45
+ - 46
+ - 47
+ - 48
+ - 49
+ - 50
+ - 51
+ - 52
+ - 53
+ - 54
+ - 55
+ - 56
+ - 57
+ - 58
+ - 59
+ - 60
+ - 61
+ - 62
+ - 63
+ VMs:
+ ARISTA01T1:
+ vlans:
+ - 0
+ - 1
+ vm_offset: 0
+ ARISTA02T1:
+ vlans:
+ - 4
+ - 5
+ vm_offset: 1
+ ARISTA03T1:
+ vlans:
+ - 16
+ - 17
+ vm_offset: 2
+ ARISTA04T1:
+ vlans:
+ - 20
+ - 21
+ vm_offset: 3
+
+configuration_properties:
+ common:
+ swrole: leaf
+ podset_number: 200
+ tor_number: 16
+ tor_subnet_number: 2
+ max_tor_subnet_number: 16
+ tor_subnet_size: 64
+ spine_asn: 65534
+ leaf_asn_start: 64802
+ tor_asn_start: 64601
+ failure_rate: 0
+ nhipv4: 10.10.246.100
+ nhipv6: FC0A::C9
+
+configuration:
+ ARISTA01T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.0
+ - FC00::1
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.1/32
+ ipv6: 2064:100::1/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.1/24
+ ipv6: fc0a::1/64
+ Port-Channel1:
+ ipv4: 10.0.0.1/31
+ ipv6: fc00::2/126
+
+ ARISTA02T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.4
+ - FC00::9
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.2/32
+ ipv6: 2064:100::2/128
+ Ethernet1:
+ lacp: 4
+ Ethernet2:
+ lacp: 4
+ Ethernet9:
+ ipv4: 10.10.246.2/24
+ ipv6: fc0a::2/64
+ Port-Channel4:
+ ipv4: 10.0.0.5/31
+ ipv6: fc00::a/126
+
+ ARISTA03T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.8
+ - FC00::11
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.3/32
+ ipv6: 2064:100::3/128
+ Ethernet1:
+ lacp: 16
+ Ethernet2:
+ lacp: 16
+ Ethernet9:
+ ipv4: 10.10.246.3/24
+ ipv6: fc0a::3/64
+ Port-Channel16:
+ ipv4: 10.0.0.9/31
+ ipv6: fc00::12/126
+
+ ARISTA04T1:
+ properties:
+ - common
+ bgp:
+ asn: 64802
+ peers:
+ 64601:
+ - 10.0.0.12
+ - FC00::19
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.4/32
+ ipv6: 2064:100::4/128
+ Ethernet1:
+ lacp: 20
+ Ethernet2:
+ lacp: 20
+ Ethernet9:
+ ipv4: 10.10.246.4/24
+ ipv6: fc0a::4/64
+ Port-Channel20:
+ ipv4: 10.0.0.13/31
+ ipv6: fc00::1a/126
diff --git a/ansible/vars/topo_t0.yml b/ansible/vars/topo_t0.yml
new file mode 100644
index 00000000000..6a935672aa2
--- /dev/null
+++ b/ansible/vars/topo_t0.yml
@@ -0,0 +1,152 @@
+topology:
+ host_interfaces:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 12
+ - 13
+ - 14
+ - 15
+ - 16
+ - 17
+ - 18
+ - 19
+ - 20
+ - 21
+ - 22
+ - 23
+ - 24
+ - 25
+ - 26
+ - 27
+ VMs:
+ ARISTA01T1:
+ vlans:
+ - 28
+ vm_offset: 0
+ ARISTA02T1:
+ vlans:
+ - 29
+ vm_offset: 1
+ ARISTA03T1:
+ vlans:
+ - 30
+ vm_offset: 2
+ ARISTA04T1:
+ vlans:
+ - 31
+ vm_offset: 3
+
+configuration_properties:
+ common:
+ swrole: leaf
+ podset_number: 200
+ tor_number: 16
+ tor_subnet_number: 2
+ max_tor_subnet_number: 16
+ tor_subnet_size: 64
+ spine_asn: 65534
+ leaf_asn_start: 64600
+ tor_asn_start: 65100
+ failure_rate: 0
+ nhipv4: 10.10.246.100
+ nhipv6: FC0A::C9
+
+configuration:
+ ARISTA01T1:
+ properties:
+ - common
+ bgp:
+ asn: 64600
+ peers:
+ 65100:
+ - 10.0.0.56
+ - FC00::71
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.29/32
+ ipv6: 2064:100::1d/128
+ Ethernet1:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.29/24
+ ipv6: fc0a::3a/64
+ Port-Channel1:
+ ipv4: 10.0.0.57/31
+ ipv6: fc00::72/126
+
+ ARISTA02T1:
+ properties:
+ - common
+ bgp:
+ asn: 64600
+ peers:
+ 65100:
+ - 10.0.0.58
+ - FC00::75
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.30/32
+ ipv6: 2064:100::1e/128
+ Ethernet1:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.30/24
+ ipv6: fc0a::3d/64
+ Port-Channel1:
+ ipv4: 10.0.0.59/31
+ ipv6: fc00::76/126
+
+ ARISTA03T1:
+ properties:
+ - common
+ bgp:
+ asn: 64600
+ peers:
+ 65100:
+ - 10.0.0.60
+ - FC00::79
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.31/32
+ ipv6: 2064:100::1f/128
+ Ethernet1:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.31/24
+ ipv6: fc0a::3e/64
+ Port-Channel1:
+ ipv4: 10.0.0.61/31
+ ipv6: fc00::7a/126
+
+ ARISTA04T1:
+ properties:
+ - common
+ bgp:
+ asn: 64600
+ peers:
+ 65100:
+ - 10.0.0.62
+ - FC00::7D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.32/32
+ ipv6: 2064:100::20/128
+ Ethernet1:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.32/24
+ ipv6: fc0a::41/64
+ Port-Channel1:
+ ipv4: 10.0.0.63/31
+ ipv6: fc00::7e/126
+
diff --git a/ansible/vars/topo_t1-lag.yml b/ansible/vars/topo_t1-lag.yml
new file mode 100644
index 00000000000..e05e1417588
--- /dev/null
+++ b/ansible/vars/topo_t1-lag.yml
@@ -0,0 +1,676 @@
+topology:
+ VMs:
+ ARISTA01T2:
+ vlans:
+ - 0
+ - 1
+ vm_offset: 0
+ ARISTA03T2:
+ vlans:
+ - 2
+ - 3
+ vm_offset: 1
+ ARISTA05T2:
+ vlans:
+ - 4
+ - 5
+ vm_offset: 2
+ ARISTA07T2:
+ vlans:
+ - 6
+ - 7
+ vm_offset: 3
+ ARISTA09T2:
+ vlans:
+ - 8
+ - 9
+ vm_offset: 4
+ ARISTA11T2:
+ vlans:
+ - 10
+ - 11
+ vm_offset: 5
+ ARISTA13T2:
+ vlans:
+ - 12
+ - 13
+ vm_offset: 6
+ ARISTA15T2:
+ vlans:
+ - 14
+ - 15
+ vm_offset: 7
+ ARISTA01T0:
+ vlans:
+ - 16
+ vm_offset: 8
+ ARISTA02T0:
+ vlans:
+ - 17
+ vm_offset: 9
+ ARISTA03T0:
+ vlans:
+ - 18
+ vm_offset: 10
+ ARISTA04T0:
+ vlans:
+ - 19
+ vm_offset: 11
+ ARISTA05T0:
+ vlans:
+ - 20
+ vm_offset: 12
+ ARISTA06T0:
+ vlans:
+ - 21
+ vm_offset: 13
+ ARISTA07T0:
+ vlans:
+ - 22
+ vm_offset: 14
+ ARISTA08T0:
+ vlans:
+ - 23
+ vm_offset: 15
+ ARISTA09T0:
+ vlans:
+ - 24
+ vm_offset: 16
+ ARISTA10T0:
+ vlans:
+ - 25
+ vm_offset: 17
+ ARISTA11T0:
+ vlans:
+ - 26
+ vm_offset: 18
+ ARISTA12T0:
+ vlans:
+ - 27
+ vm_offset: 19
+ ARISTA13T0:
+ vlans:
+ - 28
+ vm_offset: 20
+ ARISTA14T0:
+ vlans:
+ - 29
+ vm_offset: 21
+ ARISTA15T0:
+ vlans:
+ - 30
+ vm_offset: 22
+ ARISTA16T0:
+ vlans:
+ - 31
+ vm_offset: 23
+
+configuration_properties:
+ common:
+ nhipv4: 10.10.246.100
+ nhipv6: FC0A::C9
+ spine:
+ swrole: spine
+ podset_number: 200
+ tor_number: 16
+ tor_subnet_number: 2
+ leaf_asn_start: 62001
+ tor_asn_start: 65501
+ failure_rate: 0
+ tor:
+ swrole: tor
+ tor_subnet_number: 5
+
+configuration:
+ ARISTA01T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.0
+ - FC00::1
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.1/32
+ ipv6: 2064:100::1/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.1/24
+ ipv6: fc0a::2/64
+ Port-Channel1:
+ ipv4: 10.0.0.1/31
+ ipv6: fc00::2/126
+
+ ARISTA03T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.4
+ - FC00::9
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.3/32
+ ipv6: 2064:100::3/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.3/24
+ ipv6: fc0a::6/64
+ Port-Channel1:
+ ipv4: 10.0.0.5/31
+ ipv6: fc00::a/126
+
+ ARISTA05T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.8
+ - FC00::11
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.5/32
+ ipv6: 2064:100::5/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.5/24
+ ipv6: fc0a::a/64
+ Port-Channel1:
+ ipv4: 10.0.0.9/31
+ ipv6: fc00::12/126
+
+ ARISTA07T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.12
+ - FC00::19
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.7/32
+ ipv6: 2064:100::7/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.7/24
+ ipv6: fc0a::e/64
+ Port-Channel1:
+ ipv4: 10.0.0.13/31
+ ipv6: fc00::1a/126
+
+ ARISTA09T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.16
+ - FC00::21
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.9/32
+ ipv6: 2064:100::9/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.9/24
+ ipv6: fc0a::12/64
+ Port-Channel1:
+ ipv4: 10.0.0.17/31
+ ipv6: fc00::22/126
+
+ ARISTA11T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.20
+ - FC00::29
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.11/32
+ ipv6: 2064:100::b/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.11/24
+ ipv6: fc0a::16/64
+ Port-Channel1:
+ ipv4: 10.0.0.21/31
+ ipv6: fc00::2a/126
+
+ ARISTA13T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.24
+ - FC00::31
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.13/32
+ ipv6: 2064:100::d/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.13/24
+ ipv6: fc0a::1a/64
+ Port-Channel1:
+ ipv4: 10.0.0.25/31
+ ipv6: fc00::32/126
+
+ ARISTA15T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.28
+ - FC00::39
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.15/32
+ ipv6: 2064:100::f/128
+ Ethernet1:
+ lacp: 1
+ Ethernet2:
+ lacp: 1
+ Ethernet9:
+ ipv4: 10.10.246.15/24
+ ipv6: fc0a::1e/64
+ Port-Channel1:
+ ipv4: 10.0.0.29/31
+ ipv6: fc00::3a/126
+
+ ARISTA01T0:
+ properties:
+ - common
+ - tor
+ tornum: 1
+ bgp:
+ asn: 64001
+ peers:
+ 65100:
+ - 10.0.0.32
+ - FC00::41
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.17/32
+ ipv6: 2064:100::11/128
+ Ethernet1:
+ ipv4: 10.0.0.33/31
+ ipv6: fc00::42/126
+ Ethernet9:
+ ipv4: 10.10.246.17/24
+ ipv6: fc0a::22/64
+
+ ARISTA02T0:
+ properties:
+ - common
+ - tor
+ tornum: 2
+ bgp:
+ asn: 64002
+ peers:
+ 65100:
+ - 10.0.0.34
+ - FC00::45
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.18/32
+ ipv6: 2064:100::12/128
+ Ethernet1:
+ ipv4: 10.0.0.35/31
+ ipv6: fc00::46/126
+ Ethernet9:
+ ipv4: 10.10.246.18/24
+ ipv6: fc0a::25/64
+
+ ARISTA03T0:
+ properties:
+ - common
+ - tor
+ tornum: 3
+ bgp:
+ asn: 64003
+ peers:
+ 65100:
+ - 10.0.0.36
+ - FC00::49
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.19/32
+ ipv6: 2064:100::13/128
+ Ethernet1:
+ ipv4: 10.0.0.37/31
+ ipv6: fc00::4a/126
+ Ethernet9:
+ ipv4: 10.10.246.19/24
+ ipv6: fc0a::26/64
+
+ ARISTA04T0:
+ properties:
+ - common
+ - tor
+ tornum: 4
+ bgp:
+ asn: 64004
+ peers:
+ 65100:
+ - 10.0.0.38
+ - FC00::4D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.20/32
+ ipv6: 2064:100::14/128
+ Ethernet1:
+ ipv4: 10.0.0.39/31
+ ipv6: fc00::4e/126
+ Ethernet9:
+ ipv4: 10.10.246.20/24
+ ipv6: fc0a::29/64
+
+ ARISTA05T0:
+ properties:
+ - common
+ - tor
+ tornum: 5
+ bgp:
+ asn: 64005
+ peers:
+ 65100:
+ - 10.0.0.40
+ - FC00::51
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.21/32
+ ipv6: 2064:100::15/128
+ Ethernet1:
+ ipv4: 10.0.0.41/31
+ ipv6: fc00::52/126
+ Ethernet9:
+ ipv4: 10.10.246.21/24
+ ipv6: fc0a::2a/64
+
+ ARISTA06T0:
+ properties:
+ - common
+ - tor
+ tornum: 6
+ bgp:
+ asn: 64006
+ peers:
+ 65100:
+ - 10.0.0.42
+ - FC00::55
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.22/32
+ ipv6: 2064:100::16/128
+ Ethernet1:
+ ipv4: 10.0.0.43/31
+ ipv6: fc00::56/126
+ Ethernet9:
+ ipv4: 10.10.246.22/24
+ ipv6: fc0a::2d/64
+
+ ARISTA07T0:
+ properties:
+ - common
+ - tor
+ tornum: 7
+ bgp:
+ asn: 64007
+ peers:
+ 65100:
+ - 10.0.0.44
+ - FC00::59
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.23/32
+ ipv6: 2064:100::17/128
+ Ethernet1:
+ ipv4: 10.0.0.45/31
+ ipv6: fc00::5a/126
+ Ethernet9:
+ ipv4: 10.10.246.23/24
+ ipv6: fc0a::2e/64
+
+ ARISTA08T0:
+ properties:
+ - common
+ - tor
+ tornum: 8
+ bgp:
+ asn: 64008
+ peers:
+ 65100:
+ - 10.0.0.46
+ - FC00::5D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.24/32
+ ipv6: 2064:100::18/128
+ Ethernet1:
+ ipv4: 10.0.0.47/31
+ ipv6: fc00::5e/126
+ Ethernet9:
+ ipv4: 10.10.246.24/24
+ ipv6: fc0a::31/64
+
+ ARISTA09T0:
+ properties:
+ - common
+ - tor
+ tornum: 9
+ bgp:
+ asn: 64009
+ peers:
+ 65100:
+ - 10.0.0.48
+ - FC00::61
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.25/32
+ ipv6: 2064:100::19/128
+ Ethernet1:
+ ipv4: 10.0.0.49/31
+ ipv6: fc00::62/126
+ Ethernet9:
+ ipv4: 10.10.246.25/24
+ ipv6: fc0a::32/64
+
+ ARISTA10T0:
+ properties:
+ - common
+ - tor
+ tornum: 10
+ bgp:
+ asn: 64010
+ peers:
+ 65100:
+ - 10.0.0.50
+ - FC00::65
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.26/32
+ ipv6: 2064:100::1a/128
+ Ethernet1:
+ ipv4: 10.0.0.51/31
+ ipv6: fc00::66/126
+ Ethernet9:
+ ipv4: 10.10.246.26/24
+ ipv6: fc0a::35/64
+
+ ARISTA11T0:
+ properties:
+ - common
+ - tor
+ tornum: 11
+ bgp:
+ asn: 64011
+ peers:
+ 65100:
+ - 10.0.0.52
+ - FC00::69
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.27/32
+ ipv6: 2064:100::1b/128
+ Ethernet1:
+ ipv4: 10.0.0.53/31
+ ipv6: fc00::6a/126
+ Ethernet9:
+ ipv4: 10.10.246.27/24
+ ipv6: fc0a::36/64
+
+ ARISTA12T0:
+ properties:
+ - common
+ - tor
+ tornum: 12
+ bgp:
+ asn: 64012
+ peers:
+ 65100:
+ - 10.0.0.54
+ - FC00::6D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.28/32
+ ipv6: 2064:100::1c/128
+ Ethernet1:
+ ipv4: 10.0.0.55/31
+ ipv6: fc00::6e/126
+ Ethernet9:
+ ipv4: 10.10.246.28/24
+ ipv6: fc0a::39/64
+
+ ARISTA13T0:
+ properties:
+ - common
+ - tor
+ tornum: 13
+ bgp:
+ asn: 64013
+ peers:
+ 65100:
+ - 10.0.0.56
+ - FC00::71
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.29/32
+ ipv6: 2064:100::1d/128
+ Ethernet1:
+ ipv4: 10.0.0.57/31
+ ipv6: fc00::72/126
+ Ethernet9:
+ ipv4: 10.10.246.29/24
+ ipv6: fc0a::3a/64
+
+ ARISTA14T0:
+ properties:
+ - common
+ - tor
+ tornum: 14
+ bgp:
+ asn: 64014
+ peers:
+ 65100:
+ - 10.0.0.58
+ - FC00::75
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.30/32
+ ipv6: 2064:100::1e/128
+ Ethernet1:
+ ipv4: 10.0.0.59/31
+ ipv6: fc00::76/126
+ Ethernet9:
+ ipv4: 10.10.246.30/24
+ ipv6: fc0a::3d/64
+
+ ARISTA15T0:
+ properties:
+ - common
+ - tor
+ tornum: 15
+ bgp:
+ asn: 64015
+ peers:
+ 65100:
+ - 10.0.0.60
+ - FC00::79
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.31/32
+ ipv6: 2064:100::1f/128
+ Ethernet1:
+ ipv4: 10.0.0.61/31
+ ipv6: fc00::7a/126
+ Ethernet9:
+ ipv4: 10.10.246.31/24
+ ipv6: fc0a::3e/64
+
+ ARISTA16T0:
+ properties:
+ - common
+ - tor
+ tornum: 16
+ bgp:
+ asn: 64016
+ peers:
+ 65100:
+ - 10.0.0.62
+ - FC00::7D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.32/32
+ ipv6: 2064:100::20/128
+ Ethernet1:
+ ipv4: 10.0.0.63/31
+ ipv6: fc00::7e/126
+ Ethernet9:
+ ipv4: 10.10.246.32/24
+ ipv6: fc0a::41/64
+
diff --git a/ansible/vars/topo_t1.yml b/ansible/vars/topo_t1.yml
new file mode 100644
index 00000000000..afc8560eb26
--- /dev/null
+++ b/ansible/vars/topo_t1.yml
@@ -0,0 +1,836 @@
+topology:
+ VMs:
+ ARISTA01T2:
+ vlans:
+ - 0
+ vm_offset: 0
+ ARISTA02T2:
+ vlans:
+ - 1
+ vm_offset: 1
+ ARISTA03T2:
+ vlans:
+ - 2
+ vm_offset: 2
+ ARISTA04T2:
+ vlans:
+ - 3
+ vm_offset: 3
+ ARISTA05T2:
+ vlans:
+ - 4
+ vm_offset: 4
+ ARISTA06T2:
+ vlans:
+ - 5
+ vm_offset: 5
+ ARISTA07T2:
+ vlans:
+ - 6
+ vm_offset: 6
+ ARISTA08T2:
+ vlans:
+ - 7
+ vm_offset: 7
+ ARISTA09T2:
+ vlans:
+ - 8
+ vm_offset: 8
+ ARISTA10T2:
+ vlans:
+ - 9
+ vm_offset: 9
+ ARISTA11T2:
+ vlans:
+ - 10
+ vm_offset: 10
+ ARISTA12T2:
+ vlans:
+ - 11
+ vm_offset: 11
+ ARISTA13T2:
+ vlans:
+ - 12
+ vm_offset: 12
+ ARISTA14T2:
+ vlans:
+ - 13
+ vm_offset: 13
+ ARISTA15T2:
+ vlans:
+ - 14
+ vm_offset: 14
+ ARISTA16T2:
+ vlans:
+ - 15
+ vm_offset: 15
+ ARISTA01T0:
+ vlans:
+ - 16
+ vm_offset: 16
+ ARISTA02T0:
+ vlans:
+ - 17
+ vm_offset: 17
+ ARISTA03T0:
+ vlans:
+ - 18
+ vm_offset: 18
+ ARISTA04T0:
+ vlans:
+ - 19
+ vm_offset: 19
+ ARISTA05T0:
+ vlans:
+ - 20
+ vm_offset: 20
+ ARISTA06T0:
+ vlans:
+ - 21
+ vm_offset: 21
+ ARISTA07T0:
+ vlans:
+ - 22
+ vm_offset: 22
+ ARISTA08T0:
+ vlans:
+ - 23
+ vm_offset: 23
+ ARISTA09T0:
+ vlans:
+ - 24
+ vm_offset: 24
+ ARISTA10T0:
+ vlans:
+ - 25
+ vm_offset: 25
+ ARISTA11T0:
+ vlans:
+ - 26
+ vm_offset: 26
+ ARISTA12T0:
+ vlans:
+ - 27
+ vm_offset: 27
+ ARISTA13T0:
+ vlans:
+ - 28
+ vm_offset: 28
+ ARISTA14T0:
+ vlans:
+ - 29
+ vm_offset: 29
+ ARISTA15T0:
+ vlans:
+ - 30
+ vm_offset: 30
+ ARISTA16T0:
+ vlans:
+ - 31
+ vm_offset: 31
+
+configuration_properties:
+ common:
+ nhipv4: 10.10.246.100
+ nhipv6: FC0A::C9
+ spine:
+ swrole: spine
+ podset_number: 200
+ tor_number: 16
+ tor_subnet_number: 2
+ leaf_asn_start: 62001
+ tor_asn_start: 65501
+ failure_rate: 0
+ tor:
+ swrole: tor
+ tor_subnet_number: 5
+
+configuration:
+ ARISTA01T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.0
+ - FC00::1
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.1/32
+ ipv6: 2064:100::1/128
+ Ethernet1:
+ ipv4: 10.0.0.1/31
+ ipv6: fc00::2/126
+ Ethernet9:
+ ipv4: 10.10.246.1/24
+ ipv6: fc0a::2/64
+
+ ARISTA02T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.2
+ - FC00::5
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.2/32
+ ipv6: 2064:100::2/128
+ Ethernet1:
+ ipv4: 10.0.0.3/31
+ ipv6: fc00::6/126
+ Ethernet9:
+ ipv4: 10.10.246.2/24
+ ipv6: fc0a::5/64
+
+ ARISTA03T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.4
+ - FC00::9
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.3/32
+ ipv6: 2064:100::3/128
+ Ethernet1:
+ ipv4: 10.0.0.5/31
+ ipv6: fc00::a/126
+ Ethernet9:
+ ipv4: 10.10.246.3/24
+ ipv6: fc0a::6/64
+
+ ARISTA04T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.6
+ - FC00::D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.4/32
+ ipv6: 2064:100::4/128
+ Ethernet1:
+ ipv4: 10.0.0.7/31
+ ipv6: fc00::e/126
+ Ethernet9:
+ ipv4: 10.10.246.4/24
+ ipv6: fc0a::9/64
+
+ ARISTA05T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.8
+ - FC00::11
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.5/32
+ ipv6: 2064:100::5/128
+ Ethernet1:
+ ipv4: 10.0.0.9/31
+ ipv6: fc00::12/126
+ Ethernet9:
+ ipv4: 10.10.246.5/24
+ ipv6: fc0a::a/64
+
+ ARISTA06T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.10
+ - FC00::15
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.6/32
+ ipv6: 2064:100::6/128
+ Ethernet1:
+ ipv4: 10.0.0.11/31
+ ipv6: fc00::16/126
+ Ethernet9:
+ ipv4: 10.10.246.6/24
+ ipv6: fc0a::d/64
+
+ ARISTA07T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.12
+ - FC00::19
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.7/32
+ ipv6: 2064:100::7/128
+ Ethernet1:
+ ipv4: 10.0.0.13/31
+ ipv6: fc00::1a/126
+ Ethernet9:
+ ipv4: 10.10.246.7/24
+ ipv6: fc0a::e/64
+
+ ARISTA08T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.14
+ - FC00::1D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.8/32
+ ipv6: 2064:100::8/128
+ Ethernet1:
+ ipv4: 10.0.0.15/31
+ ipv6: fc00::1e/126
+ Ethernet9:
+ ipv4: 10.10.246.8/24
+ ipv6: fc0a::11/64
+
+ ARISTA09T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.16
+ - FC00::21
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.9/32
+ ipv6: 2064:100::9/128
+ Ethernet1:
+ ipv4: 10.0.0.17/31
+ ipv6: fc00::22/126
+ Ethernet9:
+ ipv4: 10.10.246.9/24
+ ipv6: fc0a::12/64
+
+ ARISTA10T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.18
+ - FC00::25
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.10/32
+ ipv6: 2064:100::a/128
+ Ethernet1:
+ ipv4: 10.0.0.19/31
+ ipv6: fc00::26/126
+ Ethernet9:
+ ipv4: 10.10.246.10/24
+ ipv6: fc0a::15/64
+
+ ARISTA11T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.20
+ - FC00::29
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.11/32
+ ipv6: 2064:100::b/128
+ Ethernet1:
+ ipv4: 10.0.0.21/31
+ ipv6: fc00::2a/126
+ Ethernet9:
+ ipv4: 10.10.246.11/24
+ ipv6: fc0a::16/64
+
+ ARISTA12T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.22
+ - FC00::2D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.12/32
+ ipv6: 2064:100::c/128
+ Ethernet1:
+ ipv4: 10.0.0.23/31
+ ipv6: fc00::2e/126
+ Ethernet9:
+ ipv4: 10.10.246.12/24
+ ipv6: fc0a::19/64
+
+ ARISTA13T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.24
+ - FC00::31
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.13/32
+ ipv6: 2064:100::d/128
+ Ethernet1:
+ ipv4: 10.0.0.25/31
+ ipv6: fc00::32/126
+ Ethernet9:
+ ipv4: 10.10.246.13/24
+ ipv6: fc0a::1a/64
+
+ ARISTA14T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.26
+ - FC00::35
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.14/32
+ ipv6: 2064:100::e/128
+ Ethernet1:
+ ipv4: 10.0.0.27/31
+ ipv6: fc00::36/126
+ Ethernet9:
+ ipv4: 10.10.246.14/24
+ ipv6: fc0a::1d/64
+
+ ARISTA15T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.28
+ - FC00::39
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.15/32
+ ipv6: 2064:100::f/128
+ Ethernet1:
+ ipv4: 10.0.0.29/31
+ ipv6: fc00::3a/126
+ Ethernet9:
+ ipv4: 10.10.246.15/24
+ ipv6: fc0a::1e/64
+
+ ARISTA16T2:
+ properties:
+ - common
+ - spine
+ bgp:
+ asn: 65200
+ peers:
+ 65100:
+ - 10.0.0.30
+ - FC00::3D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.16/32
+ ipv6: 2064:100::10/128
+ Ethernet1:
+ ipv4: 10.0.0.31/31
+ ipv6: fc00::3e/126
+ Ethernet9:
+ ipv4: 10.10.246.16/24
+ ipv6: fc0a::21/64
+
+ ARISTA01T0:
+ properties:
+ - common
+ - tor
+ tornum: 1
+ bgp:
+ asn: 64001
+ peers:
+ 65100:
+ - 10.0.0.32
+ - FC00::41
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.17/32
+ ipv6: 2064:100::11/128
+ Ethernet1:
+ ipv4: 10.0.0.33/31
+ ipv6: fc00::42/126
+ Ethernet9:
+ ipv4: 10.10.246.17/24
+ ipv6: fc0a::22/64
+
+ ARISTA02T0:
+ properties:
+ - common
+ - tor
+ tornum: 2
+ bgp:
+ asn: 64002
+ peers:
+ 65100:
+ - 10.0.0.34
+ - FC00::45
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.18/32
+ ipv6: 2064:100::12/128
+ Ethernet1:
+ ipv4: 10.0.0.35/31
+ ipv6: fc00::46/126
+ Ethernet9:
+ ipv4: 10.10.246.18/24
+ ipv6: fc0a::25/64
+
+ ARISTA03T0:
+ properties:
+ - common
+ - tor
+ tornum: 3
+ bgp:
+ asn: 64003
+ peers:
+ 65100:
+ - 10.0.0.36
+ - FC00::49
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.19/32
+ ipv6: 2064:100::13/128
+ Ethernet1:
+ ipv4: 10.0.0.37/31
+ ipv6: fc00::4a/126
+ Ethernet9:
+ ipv4: 10.10.246.19/24
+ ipv6: fc0a::26/64
+
+ ARISTA04T0:
+ properties:
+ - common
+ - tor
+ tornum: 4
+ bgp:
+ asn: 64004
+ peers:
+ 65100:
+ - 10.0.0.38
+ - FC00::4D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.20/32
+ ipv6: 2064:100::14/128
+ Ethernet1:
+ ipv4: 10.0.0.39/31
+ ipv6: fc00::4e/126
+ Ethernet9:
+ ipv4: 10.10.246.20/24
+ ipv6: fc0a::29/64
+
+ ARISTA05T0:
+ properties:
+ - common
+ - tor
+ tornum: 5
+ bgp:
+ asn: 64005
+ peers:
+ 65100:
+ - 10.0.0.40
+ - FC00::51
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.21/32
+ ipv6: 2064:100::15/128
+ Ethernet1:
+ ipv4: 10.0.0.41/31
+ ipv6: fc00::52/126
+ Ethernet9:
+ ipv4: 10.10.246.21/24
+ ipv6: fc0a::2a/64
+
+ ARISTA06T0:
+ properties:
+ - common
+ - tor
+ tornum: 6
+ bgp:
+ asn: 64006
+ peers:
+ 65100:
+ - 10.0.0.42
+ - FC00::55
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.22/32
+ ipv6: 2064:100::16/128
+ Ethernet1:
+ ipv4: 10.0.0.43/31
+ ipv6: fc00::56/126
+ Ethernet9:
+ ipv4: 10.10.246.22/24
+ ipv6: fc0a::2d/64
+
+ ARISTA07T0:
+ properties:
+ - common
+ - tor
+ tornum: 7
+ bgp:
+ asn: 64007
+ peers:
+ 65100:
+ - 10.0.0.44
+ - FC00::59
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.23/32
+ ipv6: 2064:100::17/128
+ Ethernet1:
+ ipv4: 10.0.0.45/31
+ ipv6: fc00::5a/126
+ Ethernet9:
+ ipv4: 10.10.246.23/24
+ ipv6: fc0a::2e/64
+
+ ARISTA08T0:
+ properties:
+ - common
+ - tor
+ tornum: 8
+ bgp:
+ asn: 64008
+ peers:
+ 65100:
+ - 10.0.0.46
+ - FC00::5D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.24/32
+ ipv6: 2064:100::18/128
+ Ethernet1:
+ ipv4: 10.0.0.47/31
+ ipv6: fc00::5e/126
+ Ethernet9:
+ ipv4: 10.10.246.24/24
+ ipv6: fc0a::31/64
+
+ ARISTA09T0:
+ properties:
+ - common
+ - tor
+ tornum: 9
+ bgp:
+ asn: 64009
+ peers:
+ 65100:
+ - 10.0.0.48
+ - FC00::61
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.25/32
+ ipv6: 2064:100::19/128
+ Ethernet1:
+ ipv4: 10.0.0.49/31
+ ipv6: fc00::62/126
+ Ethernet9:
+ ipv4: 10.10.246.25/24
+ ipv6: fc0a::32/64
+
+ ARISTA10T0:
+ properties:
+ - common
+ - tor
+ tornum: 10
+ bgp:
+ asn: 64010
+ peers:
+ 65100:
+ - 10.0.0.50
+ - FC00::65
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.26/32
+ ipv6: 2064:100::1a/128
+ Ethernet1:
+ ipv4: 10.0.0.51/31
+ ipv6: fc00::66/126
+ Ethernet9:
+ ipv4: 10.10.246.26/24
+ ipv6: fc0a::35/64
+
+ ARISTA11T0:
+ properties:
+ - common
+ - tor
+ tornum: 11
+ bgp:
+ asn: 64011
+ peers:
+ 65100:
+ - 10.0.0.52
+ - FC00::69
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.27/32
+ ipv6: 2064:100::1b/128
+ Ethernet1:
+ ipv4: 10.0.0.53/31
+ ipv6: fc00::6a/126
+ Ethernet9:
+ ipv4: 10.10.246.27/24
+ ipv6: fc0a::36/64
+
+ ARISTA12T0:
+ properties:
+ - common
+ - tor
+ tornum: 12
+ bgp:
+ asn: 64012
+ peers:
+ 65100:
+ - 10.0.0.54
+ - FC00::6D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.28/32
+ ipv6: 2064:100::1c/128
+ Ethernet1:
+ ipv4: 10.0.0.55/31
+ ipv6: fc00::6e/126
+ Ethernet9:
+ ipv4: 10.10.246.28/24
+ ipv6: fc0a::39/64
+
+ ARISTA13T0:
+ properties:
+ - common
+ - tor
+ tornum: 13
+ bgp:
+ asn: 64013
+ peers:
+ 65100:
+ - 10.0.0.56
+ - FC00::71
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.29/32
+ ipv6: 2064:100::1d/128
+ Ethernet1:
+ ipv4: 10.0.0.57/31
+ ipv6: fc00::72/126
+ Ethernet9:
+ ipv4: 10.10.246.29/24
+ ipv6: fc0a::3a/64
+
+ ARISTA14T0:
+ properties:
+ - common
+ - tor
+ tornum: 14
+ bgp:
+ asn: 64014
+ peers:
+ 65100:
+ - 10.0.0.58
+ - FC00::75
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.30/32
+ ipv6: 2064:100::1e/128
+ Ethernet1:
+ ipv4: 10.0.0.59/31
+ ipv6: fc00::76/126
+ Ethernet9:
+ ipv4: 10.10.246.30/24
+ ipv6: fc0a::3d/64
+
+ ARISTA15T0:
+ properties:
+ - common
+ - tor
+ tornum: 15
+ bgp:
+ asn: 64015
+ peers:
+ 65100:
+ - 10.0.0.60
+ - FC00::79
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.31/32
+ ipv6: 2064:100::1f/128
+ Ethernet1:
+ ipv4: 10.0.0.61/31
+ ipv6: fc00::7a/126
+ Ethernet9:
+ ipv4: 10.10.246.31/24
+ ipv6: fc0a::3e/64
+
+ ARISTA16T0:
+ properties:
+ - common
+ - tor
+ tornum: 16
+ bgp:
+ asn: 64016
+ peers:
+ 65100:
+ - 10.0.0.62
+ - FC00::7D
+ interfaces:
+ Loopback0:
+ ipv4: 100.1.0.32/32
+ ipv6: 2064:100::20/128
+ Ethernet1:
+ ipv4: 10.0.0.63/31
+ ipv6: fc00::7e/126
+ Ethernet9:
+ ipv4: 10.10.246.32/24
+ ipv6: fc0a::41/64
+
diff --git a/ansible/veos b/ansible/veos
index beb4aa833c0..01cd5458981 100644
--- a/ansible/veos
+++ b/ansible/veos
@@ -2,213 +2,74 @@
STR-ACS-SERV-01 ansible_host=10.251.0.245
[vm_host_2]
-STR-ACS-SERV-02 ansible_host=10.251.0.246
+STR-ACS-SERV-02 ansible_host=10.251.0.192
[vm_host:children]
vm_host_1
vm_host_2
-[spine_1]
-10.255.0.238 hostname=ARISTA01T2 filename=01-ARISTA01T2.xml
-10.255.0.239 hostname=ARISTA02T2 filename=01-ARISTA02T2.xml
-10.255.0.240 hostname=ARISTA03T2 filename=01-ARISTA03T2.xml
-10.255.0.241 hostname=ARISTA04T2 filename=01-ARISTA04T2.xml
-10.255.0.242 hostname=ARISTA05T2 filename=01-ARISTA05T2.xml
-10.255.0.243 hostname=ARISTA06T2 filename=01-ARISTA06T2.xml
-10.255.0.244 hostname=ARISTA07T2 filename=01-ARISTA07T2.xml
-10.255.0.245 hostname=ARISTA08T2 filename=01-ARISTA08T2.xml
-10.255.0.246 hostname=ARISTA09T2 filename=01-ARISTA09T2.xml
-10.255.0.247 hostname=ARISTA10T2 filename=01-ARISTA10T2.xml
-10.255.0.248 hostname=ARISTA11T2 filename=01-ARISTA11T2.xml
-10.255.0.249 hostname=ARISTA12T2 filename=01-ARISTA12T2.xml
-10.255.0.250 hostname=ARISTA13T2 filename=01-ARISTA13T2.xml
-10.255.0.251 hostname=ARISTA14T2 filename=01-ARISTA14T2.xml
-10.255.0.252 hostname=ARISTA15T2 filename=01-ARISTA15T2.xml
-10.255.0.253 hostname=ARISTA16T2 filename=01-ARISTA16T2.xml
-
-[spine_2]
-10.255.0.206 hostname=ARISTA01T2 filename=02-ARISTA01T2.xml
-10.255.0.207 hostname=ARISTA02T2 filename=02-ARISTA02T2.xml
-10.255.0.208 hostname=ARISTA03T2 filename=02-ARISTA03T2.xml
-10.255.0.209 hostname=ARISTA04T2 filename=02-ARISTA04T2.xml
-10.255.0.210 hostname=ARISTA05T2 filename=02-ARISTA05T2.xml
-10.255.0.211 hostname=ARISTA06T2 filename=02-ARISTA06T2.xml
-10.255.0.212 hostname=ARISTA07T2 filename=02-ARISTA07T2.xml
-10.255.0.213 hostname=ARISTA08T2 filename=02-ARISTA08T2.xml
-10.255.0.214 hostname=ARISTA09T2 filename=02-ARISTA09T2.xml
-10.255.0.215 hostname=ARISTA10T2 filename=02-ARISTA10T2.xml
-10.255.0.216 hostname=ARISTA11T2 filename=02-ARISTA11T2.xml
-10.255.0.217 hostname=ARISTA12T2 filename=02-ARISTA12T2.xml
-10.255.0.218 hostname=ARISTA13T2 filename=02-ARISTA13T2.xml
-10.255.0.219 hostname=ARISTA14T2 filename=02-ARISTA14T2.xml
-10.255.0.220 hostname=ARISTA15T2 filename=02-ARISTA15T2.xml
-10.255.0.221 hostname=ARISTA16T2 filename=02-ARISTA16T2.xml
-
-[spine_3]
-10.255.0.68 hostname=ARISTA01T2 filename=03-ARISTA01T2.xml
-10.255.0.69 hostname=ARISTA02T2 filename=03-ARISTA02T2.xml
-10.255.0.70 hostname=ARISTA03T2 filename=03-ARISTA03T2.xml
-10.255.0.71 hostname=ARISTA04T2 filename=03-ARISTA04T2.xml
-10.255.0.72 hostname=ARISTA05T2 filename=03-ARISTA05T2.xml
-10.255.0.73 hostname=ARISTA06T2 filename=03-ARISTA06T2.xml
-10.255.0.74 hostname=ARISTA07T2 filename=03-ARISTA07T2.xml
-10.255.0.75 hostname=ARISTA08T2 filename=03-ARISTA08T2.xml
-10.255.0.76 hostname=ARISTA09T2 filename=03-ARISTA09T2.xml
-10.255.0.77 hostname=ARISTA10T2 filename=03-ARISTA10T2.xml
-10.255.0.78 hostname=ARISTA11T2 filename=03-ARISTA11T2.xml
-10.255.0.79 hostname=ARISTA12T2 filename=03-ARISTA12T2.xml
-10.255.0.80 hostname=ARISTA13T2 filename=03-ARISTA13T2.xml
-10.255.0.81 hostname=ARISTA14T2 filename=03-ARISTA14T2.xml
-10.255.0.82 hostname=ARISTA15T2 filename=03-ARISTA15T2.xml
-10.255.0.83 hostname=ARISTA16T2 filename=03-ARISTA16T2.xml
-
-[spine_4]
-10.255.0.108 hostname=ARISTA01T2 filename=04-ARISTA01T2.xml
-10.255.0.109 hostname=ARISTA02T2 filename=04-ARISTA02T2.xml
-10.255.0.114 hostname=ARISTA03T2 filename=04-ARISTA03T2.xml
-10.255.0.115 hostname=ARISTA04T2 filename=04-ARISTA04T2.xml
-10.255.0.116 hostname=ARISTA05T2 filename=04-ARISTA05T2.xml
-10.255.0.117 hostname=ARISTA06T2 filename=04-ARISTA06T2.xml
-10.255.0.118 hostname=ARISTA07T2 filename=04-ARISTA07T2.xml
-10.255.0.119 hostname=ARISTA08T2 filename=04-ARISTA08T2.xml
-10.255.0.120 hostname=ARISTA09T2 filename=04-ARISTA09T2.xml
-10.255.0.121 hostname=ARISTA10T2 filename=04-ARISTA10T2.xml
-10.255.0.122 hostname=ARISTA11T2 filename=04-ARISTA11T2.xml
-10.255.0.123 hostname=ARISTA12T2 filename=04-ARISTA12T2.xml
-10.255.0.124 hostname=ARISTA13T2 filename=04-ARISTA13T2.xml
-10.255.0.125 hostname=ARISTA14T2 filename=04-ARISTA14T2.xml
-10.255.0.146 hostname=ARISTA15T2 filename=04-ARISTA15T2.xml
-10.255.0.147 hostname=ARISTA16T2 filename=04-ARISTA16T2.xml
-
-[spine:children]
-spine_1
-spine_2
-spine_3
-spine_4
-
-[spine:vars]
-swrole=spine
-
-[tor_1]
-10.255.0.222 hostname=ARISTA01T0 filename=01-ARISTA01T0.xml tornum=1
-10.255.0.223 hostname=ARISTA02T0 filename=01-ARISTA02T0.xml tornum=2
-10.255.0.224 hostname=ARISTA03T0 filename=01-ARISTA03T0.xml tornum=3
-10.255.0.225 hostname=ARISTA04T0 filename=01-ARISTA04T0.xml tornum=4
-10.255.0.226 hostname=ARISTA05T0 filename=01-ARISTA05T0.xml tornum=5
-10.255.0.227 hostname=ARISTA06T0 filename=01-ARISTA06T0.xml tornum=6
-10.255.0.228 hostname=ARISTA07T0 filename=01-ARISTA07T0.xml tornum=7
-10.255.0.229 hostname=ARISTA08T0 filename=01-ARISTA08T0.xml tornum=8
-10.255.0.230 hostname=ARISTA09T0 filename=01-ARISTA09T0.xml tornum=9
-10.255.0.231 hostname=ARISTA10T0 filename=01-ARISTA10T0.xml tornum=10
-10.255.0.232 hostname=ARISTA11T0 filename=01-ARISTA11T0.xml tornum=11
-10.255.0.233 hostname=ARISTA12T0 filename=01-ARISTA12T0.xml tornum=12
-10.255.0.234 hostname=ARISTA13T0 filename=01-ARISTA13T0.xml tornum=13
-10.255.0.235 hostname=ARISTA14T0 filename=01-ARISTA14T0.xml tornum=14
-10.255.0.236 hostname=ARISTA15T0 filename=01-ARISTA15T0.xml tornum=15
-10.255.0.237 hostname=ARISTA16T0 filename=01-ARISTA16T0.xml tornum=16
-
-[tor_2]
-10.255.0.190 hostname=ARISTA01T0 filename=02-ARISTA01T0.xml tornum=1
-10.255.0.191 hostname=ARISTA02T0 filename=02-ARISTA02T0.xml tornum=2
-10.255.0.192 hostname=ARISTA03T0 filename=02-ARISTA03T0.xml tornum=3
-10.255.0.193 hostname=ARISTA04T0 filename=02-ARISTA04T0.xml tornum=4
-10.255.0.194 hostname=ARISTA05T0 filename=02-ARISTA05T0.xml tornum=5
-10.255.0.195 hostname=ARISTA06T0 filename=02-ARISTA06T0.xml tornum=6
-10.255.0.196 hostname=ARISTA07T0 filename=02-ARISTA07T0.xml tornum=7
-10.255.0.197 hostname=ARISTA08T0 filename=02-ARISTA08T0.xml tornum=8
-10.255.0.198 hostname=ARISTA09T0 filename=02-ARISTA09T0.xml tornum=9
-10.255.0.199 hostname=ARISTA10T0 filename=02-ARISTA10T0.xml tornum=10
-10.255.0.200 hostname=ARISTA11T0 filename=02-ARISTA11T0.xml tornum=11
-10.255.0.201 hostname=ARISTA12T0 filename=02-ARISTA12T0.xml tornum=12
-10.255.0.202 hostname=ARISTA13T0 filename=02-ARISTA13T0.xml tornum=13
-10.255.0.203 hostname=ARISTA14T0 filename=02-ARISTA14T0.xml tornum=14
-10.255.0.204 hostname=ARISTA15T0 filename=02-ARISTA15T0.xml tornum=15
-10.255.0.205 hostname=ARISTA16T0 filename=02-ARISTA16T0.xml tornum=16
-
-[tor_3]
-10.255.0.52 hostname=ARISTA01T0 filename=03-ARISTA01T0.xml tornum=1
-10.255.0.53 hostname=ARISTA02T0 filename=03-ARISTA02T0.xml tornum=2
-10.255.0.54 hostname=ARISTA03T0 filename=03-ARISTA03T0.xml tornum=3
-10.255.0.55 hostname=ARISTA04T0 filename=03-ARISTA04T0.xml tornum=4
-10.255.0.56 hostname=ARISTA05T0 filename=03-ARISTA05T0.xml tornum=5
-10.255.0.57 hostname=ARISTA06T0 filename=03-ARISTA06T0.xml tornum=6
-10.255.0.58 hostname=ARISTA07T0 filename=03-ARISTA07T0.xml tornum=7
-10.255.0.59 hostname=ARISTA08T0 filename=03-ARISTA08T0.xml tornum=8
-10.255.0.60 hostname=ARISTA09T0 filename=03-ARISTA09T0.xml tornum=9
-10.255.0.61 hostname=ARISTA10T0 filename=03-ARISTA10T0.xml tornum=10
-10.255.0.62 hostname=ARISTA11T0 filename=03-ARISTA11T0.xml tornum=11
-10.255.0.63 hostname=ARISTA12T0 filename=03-ARISTA12T0.xml tornum=12
-10.255.0.64 hostname=ARISTA13T0 filename=03-ARISTA13T0.xml tornum=13
-10.255.0.65 hostname=ARISTA14T0 filename=03-ARISTA14T0.xml tornum=14
-10.255.0.66 hostname=ARISTA15T0 filename=03-ARISTA15T0.xml tornum=15
-10.255.0.67 hostname=ARISTA16T0 filename=03-ARISTA16T0.xml tornum=16
-
-[tor_4]
-10.255.0.84 hostname=ARISTA01T0 filename=04-ARISTA01T0.xml tornum=1
-10.255.0.85 hostname=ARISTA02T0 filename=04-ARISTA02T0.xml tornum=2
-10.255.0.86 hostname=ARISTA03T0 filename=04-ARISTA03T0.xml tornum=3
-10.255.0.87 hostname=ARISTA04T0 filename=04-ARISTA04T0.xml tornum=4
-10.255.0.88 hostname=ARISTA05T0 filename=04-ARISTA05T0.xml tornum=5
-10.255.0.89 hostname=ARISTA06T0 filename=04-ARISTA06T0.xml tornum=6
-10.255.0.90 hostname=ARISTA07T0 filename=04-ARISTA07T0.xml tornum=7
-10.255.0.92 hostname=ARISTA08T0 filename=04-ARISTA08T0.xml tornum=8
-10.255.0.93 hostname=ARISTA09T0 filename=04-ARISTA09T0.xml tornum=9
-10.255.0.94 hostname=ARISTA10T0 filename=04-ARISTA10T0.xml tornum=10
-10.255.0.95 hostname=ARISTA11T0 filename=04-ARISTA11T0.xml tornum=11
-10.255.0.96 hostname=ARISTA12T0 filename=04-ARISTA12T0.xml tornum=12
-10.255.0.97 hostname=ARISTA13T0 filename=04-ARISTA13T0.xml tornum=13
-10.255.0.98 hostname=ARISTA14T0 filename=04-ARISTA14T0.xml tornum=14
-10.255.0.99 hostname=ARISTA15T0 filename=04-ARISTA15T0.xml tornum=15
-10.255.0.107 hostname=ARISTA16T0 filename=04-ARISTA16T0.xml tornum=16
-
-[tor:children]
-tor_1
-tor_2
-tor_3
-tor_4
-
-[tor:vars]
-swrole=tor
+[vms_1]
+VM0100 ansible_host=10.250.0.2
+VM0101 ansible_host=10.250.0.3
+VM0102 ansible_host=10.250.0.4
+VM0103 ansible_host=10.250.0.5
+VM0104 ansible_host=10.250.0.6
+VM0105 ansible_host=10.250.0.7
+VM0106 ansible_host=10.250.0.8
+VM0107 ansible_host=10.250.0.9
+VM0108 ansible_host=10.250.0.10
+VM0109 ansible_host=10.250.0.11
+VM0110 ansible_host=10.250.0.12
+VM0111 ansible_host=10.250.0.13
+VM0112 ansible_host=10.250.0.14
+VM0113 ansible_host=10.250.0.15
+VM0114 ansible_host=10.250.0.16
+VM0115 ansible_host=10.250.0.17
+VM0116 ansible_host=10.250.0.18
+VM0117 ansible_host=10.250.0.19
+VM0118 ansible_host=10.250.0.20
+VM0119 ansible_host=10.250.0.21
+VM0120 ansible_host=10.250.0.22
+VM0121 ansible_host=10.250.0.23
+VM0122 ansible_host=10.250.0.24
+VM0123 ansible_host=10.250.0.25
+VM0124 ansible_host=10.250.0.26
+VM0125 ansible_host=10.250.0.27
+VM0126 ansible_host=10.250.0.28
+VM0127 ansible_host=10.250.0.29
+VM0128 ansible_host=10.250.0.30
+VM0129 ansible_host=10.250.0.31
+VM0130 ansible_host=10.250.0.32
+VM0131 ansible_host=10.250.0.33
+
+[vms_2]
+VM0200 ansible_host=10.250.0.51
+VM0201 ansible_host=10.250.0.52
+VM0202 ansible_host=10.250.0.53
+VM0203 ansible_host=10.250.0.54
[eos:children]
-spine
-tor
-
-[leaf_topo_1:children]
-eos
-
-[eos:vars]
-nhipv4=10.10.246.100
-nhipv6=FC0A::C9
+vms_1
+vms_2
-[vm_set_1:children]
-tor_1
-tor_2
-spine_1
-spine_2
-
-[vm_set_2:children]
-tor_3
-tor_4
-spine_3
-spine_4
-
-## The groups below are helper to limit running playbooks to server_1 or server_2 only
+## The groups below are helper to limit running playbooks to server_1, server_2 or server_3 only
[server_1:children]
vm_host_1
-tor_1
-tor_3
-spine_1
-spine_3
+vms_1
+
+[server_1:vars]
+host_var_file=host_vars/STR-ACS-SERV-01.yml
[server_2:children]
vm_host_2
-tor_2
-tor_4
-spine_2
-spine_4
+vms_2
+
+[server_2:vars]
+host_var_file=host_vars/STR-ACS-SERV-02.yml
[servers:children]
server_1
server_2
+[servers:vars]
+topologies=['t1', 't1-lag', 't0', 'ptf32', 'ptf64', 't0-64', 't0-64-32']
diff --git a/ansible/veos.yml b/ansible/veos.yml
index a6f6e7aa054..c2db61f5a65 100644
--- a/ansible/veos.yml
+++ b/ansible/veos.yml
@@ -1,7 +1,7 @@
---
# This Playbook deploys vm configurations
#
-# ansible-playbook -i veos -l tor_2 veos.yml --vault-password-file password.txt
+# ansible-playbook -i veos -l vm_set_2 veos.yml --vault-password-file password.txt
- hosts: eos
gather_facts: no