Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ansible/README.test.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,8 @@ ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags
ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags syslog
```

### BGP GR helper mode test
```
ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} --become --tags bgp_gr_helper --extra-vars "testbed_type={TESTBED_TYPE}"
```

3 changes: 2 additions & 1 deletion ansible/group_vars/eos/eos.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# snmp variables
snmp_rocommunity: strcommunity
snmp_location: str

# Default value. Should be adjusted based on PTF host capabilities
bgp_gr_timer: 300
14 changes: 14 additions & 0 deletions ansible/library/bgp_facts.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ def parse_neighbors(self):
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})')
regex_cap_gr = re.compile(r'.*Graceful Restart Capabilty: (\w+)')
regex_cap_gr_peer_restart_time = re.compile(r'.*Remote Restart timer is (\d+)')
regex_cap_gr_peer_af_ip4 = re.compile(r'.*IPv4 Unicast\((.*)\)')
regex_cap_gr_peer_af_ip6 = re.compile(r'.*IPv6 Unicast\((.*)\)')

neighbors = {}

try:
Expand All @@ -114,6 +119,7 @@ def parse_neighbors(self):
# ignore empty rows
if 'BGP' in n:
neighbor = {}
capabilities = {}
message_stats = {}
n = "BGP neighbor is" + n
lines = n.splitlines()
Expand All @@ -132,6 +138,11 @@ def parse_neighbors(self):
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_cap_gr.match(line): capabilities['graceful restart'] = regex_cap_gr.match(line).group(1).lower()
if regex_cap_gr_peer_restart_time.match(line): capabilities['peer restart timer'] = int(regex_cap_gr_peer_restart_time.match(line).group(1))
if regex_cap_gr_peer_af_ip4.match(line): capabilities['peer af ipv4 unicast'] = regex_cap_gr_peer_af_ip4.match(line).group(1).lower()
if regex_cap_gr_peer_af_ip6.match(line): capabilities['peer af ipv6 unicast'] = regex_cap_gr_peer_af_ip6.match(line).group(1).lower()

if regex_stats.match(line):
key, values = line.split(':')
key = key.lstrip()
Expand All @@ -141,6 +152,9 @@ def parse_neighbors(self):
value_dict['rcvd'] = int(rcvd)
message_stats[key] = value_dict

if capabilities:
neighbor['capabilities'] = capabilities

if message_stats:
neighbor['message statistics'] = message_stats

Expand Down
3 changes: 3 additions & 0 deletions ansible/roles/eos/templates/t1-lag-spine.j2
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
router bgp {{ host['bgp']['asn'] }}
router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
!
graceful-restart restart-time {{ bgp_gr_timer }}
graceful-restart
!
{% for asn, remote_ips in host['bgp']['peers'].items() %}
{% for remote_ip in remote_ips %}
neighbor {{ remote_ip }} remote-as {{ asn }}
Expand Down
3 changes: 3 additions & 0 deletions ansible/roles/eos/templates/t1-lag-tor.j2
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ interface {{ name }}
router bgp {{ host['bgp']['asn'] }}
router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
!
graceful-restart restart-time {{ bgp_gr_timer }}
graceful-restart
!
{% for asn, remote_ips in host['bgp']['peers'].items() %}
{% for remote_ip in remote_ips %}
neighbor {{ remote_ip }} remote-as {{ asn }}
Expand Down
3 changes: 3 additions & 0 deletions ansible/roles/eos/templates/t1-spine.j2
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ route-map PREPENDAS permit {{ 2 * (podset * props.tor_number + tor + 1) + 1 }}
router bgp {{ host['bgp']['asn'] }}
router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
!
graceful-restart restart-time {{ bgp_gr_timer }}
graceful-restart
!
{% for asn, remote_ips in host['bgp']['peers'].items() %}
{% for remote_ip in remote_ips %}
neighbor {{ remote_ip }} remote-as {{ asn }}
Expand Down
3 changes: 3 additions & 0 deletions ansible/roles/eos/templates/t1-tor.j2
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ interface {{ name }}
router bgp {{ host['bgp']['asn'] }}
router-id {{ host['interfaces']['Loopback0']['ipv4'] | ipaddr('address') }}
!
graceful-restart restart-time {{ bgp_gr_timer }}
graceful-restart
!
{% for asn, remote_ips in host['bgp']['peers'].items() %}
{% for remote_ip in remote_ips %}
neighbor {{ remote_ip }} remote-as {{ asn }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,28 @@

- 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}}

Expand Down
Empty file.
34 changes: 31 additions & 3 deletions ansible/roles/test/files/tools/loganalyzer/loganalyzer_init.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}"
Expand Down
102 changes: 102 additions & 0 deletions ansible/roles/test/tasks/bgp_gr_helper.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#-----------------------------------------
# Run BGP GR helper mode 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: Get VM info.
include: "roles/test/tasks/bgp_gr_helper/get_vm_info.yml"

- name: Gather facts from bgp container.
bgp_facts:

- name: Get VM GR timer.
set_fact:
bgp_gr_timer: "{{ bgp_neighbors[peer_ip]['capabilities']['peer restart timer'] }}"

- name: Set default value for GR simulation time in seconds.
set_fact:
bgp_gr_simulation_timer: 100

- set_fact:
testname: "bgp_gr_helper"
run_dir: /tmp
out_dir: /tmp/ansible-loganalyzer-results
tests_location: "{{ 'roles/test/tasks' }}"

- include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
vars:
test_match_file: routes_update_match.txt

- name: Set log level to INFO bo be able to catch route update messages from orchagent
command: "swssloglevel -l INFO -c orchagent"

- name: Define stalepath time. Should be at least 30 seconds grater than graceful restart time.
set_fact:
bgp_gr_stalepath_timer: "{{ (bgp_gr_timer|int + 30) }}"

- name: Set bgp stalepath timer.
command: vtysh -c "conf t" -c "router bgp {{ minigraph_bgp_asn }}" -c "bgp graceful-restart stalepath-time {{ bgp_gr_stalepath_timer }}"

# When RIBD up and send bgp open message it will set F bit to 1. Which means that during restart
# all routes were preserved in FIB. When DUT receives open message with F bit set to 1 it also
# should preserve all routes (no route update should happens).
- name: Force stop RIBD to simulate GR.
shell: "killall -9 ribd; sleep 0.5; ifconfig et1 down"
delegate_to: "{{ vm_ip }}"

- name: Simulate GR.
pause:
seconds: "{{ bgp_gr_simulation_timer if (bgp_gr_timer|int - 30) > bgp_gr_simulation_timer else (bgp_gr_timer|int - 30) }}"

- name: Up interface to allow RIBD to send open message. End of GR.
command: ifconfig et1 up
delegate_to: "{{ vm_ip }}"

- name: Wait for BGP session state update.
pause:
seconds: 2

- name: Gather facts from bgp container.
bgp_facts:

- name: Verify bgp session is established
assert: { that: "'{{ bgp_neighbors[peer_ip]['state'] }}' == 'established'" }

- name: Verify that IPv4 unicast routes were preserved during GR.
assert: { that: "'{{ bgp_neighbors[peer_ip]['capabilities']['peer af ipv4 unicast'] }}' == 'preserved'" }

- include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
vars:
test_match_file: routes_update_match.txt

- include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml
vars:
test_expect_file: routes_update_expect.txt

- name: Restart the VM
shell: killall -9 ribd ; reboot
delegate_to: "{{ vm_ip }}"

- local_action: wait_for port=22 host="{{ vm_ip }}" delay=20 timeout="{{ bgp_gr_timer }}" state=started

- name: Wait for BGP session state update.
pause:
seconds: 2

- name: Gather facts from bgp container.
bgp_facts:

- name: Verify bgp session is established
assert: { that: "'{{ bgp_neighbors[peer_ip]['state'] }}' == 'established'" }

- name: Verify that IPv4 unicast routes were not preserved during GR. FIB should be updated.
assert: { that: "'{{ bgp_neighbors[peer_ip]['capabilities']['peer af ipv4 unicast'] }}' == 'not preserved'" }

- include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
vars:
test_expect_file: routes_update_expect.txt
39 changes: 39 additions & 0 deletions ansible/roles/test/tasks/bgp_gr_helper/get_vm_info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
- name: Gathering lab graph facts about the device
conn_graph_facts: host={{ ansible_host }}
connection: local
tags: always

- name: Init variables.
set_fact:
vm_name: ""
vm_intf: ""
vm_ip: ""
peer_ip: ""

- name: Get neighbor VM info.
set_fact:
vm_name: "{{ item.value.name }}"
vm_intf: "{{ item.key }}"
with_dict: "{{ minigraph_neighbors }}"
when: "testbed_type in ['t1-lag', 't1'] and 'T0' in item.value.name and not vm_name"

- name: Get neighbor IP address.
set_fact:
peer_ip: "{{ item.addr }}"
with_items: "{{ minigraph_bgp }}"
when: "item.name == vm_name and item.addr|ipv4"

- name: Gather information from LLDP
include: "roles/test/tasks/lldp.yml"

- name: Get VM IP address.
set_fact:
vm_ip: "{{ lldp[vm_intf]['chassis']['mgmt-ip'] }}"

- debug:
var: vm_name
- debug:
var: vm_intf
- debug:
var: vm_ip

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
r, ".*Set Route next hop.*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
r, ".*Remove route.*"
r, ".*Create route.*"
r, ".*Set route.*"
4 changes: 4 additions & 0 deletions ansible/roles/test/tasks/sonic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,7 @@
- name: ACL test
include: acltb.yml
tags: acl

- name: BGP GR helper test
include: bgp_gr_helper.yml
tags: bgp_gr_helper