-
Notifications
You must be signed in to change notification settings - Fork 1k
[TestLAG] add additional/alternative lag_2 test #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
78bfc27
d7fb072
0180b8b
dd0e239
bb364cf
ab9b6e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 ncorrectly | ||
| assert: { that: "'{{ lag_facts.lags[po]['po_intf_stat'] }}' == 'Up' "} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| ### 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' | ||
|
|
||
| - set_fact: | ||
| peer_host: "{{ lldp[flap_intf]['chassis']['mgmt-ip'] }}" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please mark this as todo, we should really use the testbed info to deduce the mgmt ip of the arista vm, not using lldp.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, will add it later |
||
|
|
||
| - 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 seending rate is 30 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 seending rate is 30 seconds | ||
| include: lag_lacp_timing_test.yml | ||
| vars: | ||
| vm_name: "{{ peer_device }}" | ||
| lacp_timer: 30 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| enable | ||
| configure | ||
| {% for intf in neighbor_lag_intfs %} | ||
| interface {{ intf }} | ||
| lacp rate fast | ||
| exit | ||
| {% endfor %} | ||
| exit | ||
| exit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
incorrectly