Skip to content

Commit d334a41

Browse files
authored
[pfcwd]: Iterate functional test over all ports (#490)
* [pfcwd]: Iterate functional test over all ports Signed-off-by: Sihui Han <[email protected]> * stablize the test and support t0-64 topo * Get minigraph facts from DUT instead of local
1 parent cfe9532 commit d334a41

16 files changed

+499
-171
lines changed

ansible/roles/test/files/ptftests/pfc_wd.py

+70-24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import random
44
import socket
55
import sys
6+
import struct
7+
import ipaddress
8+
import re
69

710
import ptf
811
import ptf.packet as scapy
@@ -13,6 +16,7 @@
1316
from ptf.mask import Mask
1417
from ptf.testutils import *
1518

19+
1620
class PfcWdTest(BaseTest):
1721
def __init__(self):
1822
BaseTest.__init__(self)
@@ -24,41 +28,83 @@ def setUp(self):
2428
self.queue_index = int(self.test_params['queue_index'])
2529
self.pkt_count = int(self.test_params['pkt_count'])
2630
self.port_src = int(self.test_params['port_src'])
27-
self.ip_src = self.test_params['ip_src']
31+
self.port_dst = self.test_params['port_dst']
2832
self.ip_dst = self.test_params['ip_dst']
33+
self.port_type = self.test_params['port_type']
2934
self.wd_action = self.test_params.get('wd_action', 'drop')
3035

3136
def runTest(self):
3237
ecn = 1
3338
dscp = self.queue_index
3439
tos = dscp << 2
3540
tos |= ecn
36-
dst_port_list = range(0,32)
37-
sport = random.randint(0, 65535)
38-
dport = random.randint(0, 65535)
41+
42+
matches = re.findall('\[([\d\s]+)\]', self.port_dst)
43+
44+
dst_port_list = []
45+
for match in matches:
46+
for port in match.split():
47+
dst_port_list.append(int(port))
3948
src_mac = self.dataplane.get_mac(0, 0)
4049

41-
pkt = simple_tcp_packet(
42-
eth_dst=self.router_mac,
43-
eth_src=src_mac,
44-
ip_src=self.ip_src,
45-
ip_dst=self.ip_dst,
46-
ip_tos = tos,
47-
tcp_sport=sport,
48-
tcp_dport=dport,
49-
ip_ttl=64)
50-
exp_pkt = simple_tcp_packet(
51-
eth_src=self.router_mac,
52-
ip_src=self.ip_src,
53-
ip_dst=self.ip_dst,
54-
ip_tos = tos,
55-
tcp_sport=sport,
56-
tcp_dport=dport,
57-
ip_ttl=63)
58-
masked_exp_pkt = Mask(exp_pkt)
59-
masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
50+
if self.port_type == "portchannel":
51+
for x in range(0, self.pkt_count):
52+
sport = random.randint(0, 65535)
53+
dport = random.randint(0, 65535)
54+
ip_src = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
55+
ip_src =ipaddress.IPv4Address(unicode(ip_src,'utf-8'))
56+
while ip_src == ipaddress.IPv4Address(unicode(self.ip_dst,'utf-8')) or ip_src.is_multicast or ip_src.is_private or ip_src.is_global or ip_src.is_reserved:
57+
ip_src = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
58+
ip_src =ipaddress.IPv4Address(unicode(ip_src,'utf-8'))
59+
60+
ip_src = str(ip_src)
61+
pkt = simple_tcp_packet(
62+
eth_dst=self.router_mac,
63+
eth_src=src_mac,
64+
ip_src=ip_src,
65+
ip_dst=self.ip_dst,
66+
ip_tos = tos,
67+
tcp_sport=sport,
68+
tcp_dport=dport,
69+
ip_ttl=64)
70+
exp_pkt = simple_tcp_packet(
71+
eth_src=self.router_mac,
72+
ip_src=ip_src,
73+
ip_dst=self.ip_dst,
74+
ip_tos = tos,
75+
tcp_sport=sport,
76+
tcp_dport=dport,
77+
ip_ttl=63)
78+
masked_exp_pkt = Mask(exp_pkt)
79+
masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
80+
81+
send_packet(self, self.port_src, pkt, 1)
82+
else:
83+
sport = random.randint(0, 65535)
84+
dport = random.randint(0, 65535)
85+
ip_src = "1.1.1.1"
86+
87+
pkt = simple_tcp_packet(
88+
eth_dst=self.router_mac,
89+
eth_src=src_mac,
90+
ip_src=ip_src,
91+
ip_dst=self.ip_dst,
92+
ip_tos = tos,
93+
tcp_sport=sport,
94+
tcp_dport=dport,
95+
ip_ttl=64)
96+
exp_pkt = simple_tcp_packet(
97+
eth_src=self.router_mac,
98+
ip_src=ip_src,
99+
ip_dst=self.ip_dst,
100+
ip_tos = tos,
101+
tcp_sport=sport,
102+
tcp_dport=dport,
103+
ip_ttl=63)
104+
masked_exp_pkt = Mask(exp_pkt)
105+
masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst")
60106

61-
send_packet(self, self.port_src, pkt, self.pkt_count)
107+
send_packet(self, self.port_src, pkt, self.pkt_count)
62108

63109
if self.wd_action == 'drop':
64110
return verify_no_packet_any(self, masked_exp_pkt, dst_port_list)

ansible/roles/test/tasks/interface.yml

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
- name: Gather minigraph facts about the device
2+
minigraph_facts: host={{inventory_hostname}}
3+
14
- name: Get interface facts
25
interface_facts: up_ports={{minigraph_ports}}
36

ansible/roles/test/tasks/pfc_wd.yml

+68-6
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,86 @@
3939
- set_fact:
4040
neighbors: "{{device_conn}}"
4141

42+
- set_fact:
43+
ansible_eth0_ipv4_addr: "{{ansible_eth0['ipv4']['address']}}"
44+
ansible_ethernet0_mac_addr: "{{ansible_Ethernet0['macaddress']}}"
45+
46+
- set_fact:
47+
used: false
48+
first_pair: false
49+
pfc_wd_rx_port: "rx"
50+
pfc_wd_test_port: "test"
51+
52+
- set_fact:
53+
test_ports: {}
54+
55+
- name: Iterate all interfaces to get all interface ports info if exists
56+
include: roles/test/tasks/pfc_wd/iterate_interfaces.yml
57+
with_items: "{{minigraph_interfaces}}"
58+
when: item['addr'] | ipv4
59+
60+
- set_fact:
61+
restart: True
62+
when: minigraph_portchannels| length > 0
63+
64+
- name: Iterate all the portchannels to get all portchanel member ports info if exists.
65+
include: roles/test/tasks/pfc_wd/iterate_portchannels.yml
66+
with_dict: "{{minigraph_portchannels}}"
67+
68+
- name: Generate ips in VLAN range
69+
get_ip_in_range: num=1 prefix="{{minigraph_vlan_interfaces[0]['addr']}}/{{minigraph_vlan_interfaces[0]['prefixlen']}}" exclude_ips="{{minigraph_vlan_interfaces[0]['addr']}}"
70+
become: no
71+
connection: local
72+
failed_when: False
73+
when: minigraph_vlans | length >0
74+
75+
- name: Set unique MACs to PTF interfaces
76+
script: roles/test/files/helpers/change_mac.sh
77+
delegate_to: "{{ptf_host}}"
78+
when: minigraph_vlans | length >0
79+
80+
- set_fact:
81+
vlan_members: "{{minigraph_vlans[minigraph_vlans.keys()[0]]['members']}}"
82+
when: minigraph_vlans | length >0
83+
84+
- name: Iterate all vlan members to get all vlan member ports info if exists.
85+
include: roles/test/tasks/pfc_wd/iterate_vlans.yml
86+
with_items: "{{vlan_members | default([])}}"
87+
when: minigraph_vlans | length >0
88+
89+
- name: Flush vlan ips route
90+
command: ip route flush {{generated_ips[0].split('/')[0]}}/32
91+
become: yes
92+
when: minigraph_vlans | length >0
93+
94+
- name: Add vlan ips route
95+
command: ip route add {{generated_ips[0].split('/')[0]}}/32 dev {{minigraph_vlan_interfaces[0]['attachto']}}
96+
become: yes
97+
when: minigraph_vlans | length >0
98+
99+
- name: "Update ARP entry on DUT"
100+
shell: ping {{minigraph_vlan_interfaces[0]['addr']}} -c 5
101+
delegate_to: "{{ptf_host}}"
102+
when: minigraph_vlans | length >0
103+
104+
- debug: msg="{{test_ports}}"
105+
42106
#****************************************#
43107
# Start tests #
44108
#****************************************#
45109

46110
- block:
47-
- name: Choose random port for testing
48-
include: roles/test/tasks/pfc_wd/choose_test_port.yml
49-
50111
- name: Test PFC WD configuration validation.
51112
vars:
52113
pfc_wd_template: roles/test/templates/pfc_wd_config.j2
53114
include: roles/test/tasks/pfc_wd/config_test/config_test.yml
54115

55116
- name: Test PFC WD Functional tests.
56-
vars:
57-
pfc_wd_template: roles/test/templates/pfc_wd_config.j2
58-
peer_device: "{{ neighbors[pfc_wd_test_port]['peerdevice'] }}"
59117
include: roles/test/tasks/pfc_wd/functional_test/functional_test.yml
118+
with_dict: "{{test_ports}}"
119+
120+
- name: Test PFC WD Timer accuracy.
121+
include: roles/test/tasks/pfc_wd/functional_test/check_timer_accuracy_test.yml
60122

61123
- name: Test PFC WD extreme case when all ports have storm
62124
include: roles/test/tasks/pfc_wd/functional_test/storm_all_test.yml

ansible/roles/test/tasks/pfc_wd/config_test/config_test.yml

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
- set_fact:
2+
pfc_wd_test_port: "{{test_ports.keys()[0]}}"
3+
14
- name: Generate config file for forward action test.
25
vars:
36
pfc_wd_interface_list: "{{ pfc_wd_test_port }}"
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
r, ".* Port counter .* not implemented"
22
r, ".* Port counter .* not supported"
33
r, ".* Invalid port counter .*"
4+
r, ".* Unknown stat.*"
5+
r, ".* snmpd .*"
46
r, ".* Trying to remove nonexisting queue from flex counter .*"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Verify timers
2+
- set_fact:
3+
pfc_wd_test_port: "{{test_ports.keys()[0]}}"
4+
5+
- block:
6+
- name: Apply config with proper timers to {{ pfc_wd_test_port }}.
7+
vars:
8+
command_to_run: "pfcwd start --action drop --restoration-time {{ pfc_wd_restore_time }} {{ ports }} {{ pfc_wd_detect_time }}"
9+
errors_expected: false
10+
include: roles/test/tasks/run_command_with_log_analyzer.yml
11+
12+
- name: Enable routing from mgmt interface to localhost
13+
sysctl:
14+
name: net.ipv4.conf.eth0.route_localnet
15+
value: 1
16+
sysctl_set: yes
17+
become: true
18+
19+
# Cannot use iptables module, because it does not support to_destination in 2.0
20+
- name: Add iptables rule to forward syslog packets from mgmt interface to localhost
21+
shell: "iptables -t nat -I PREROUTING -p udp -d {{ansible_eth0_ipv4_addr}} --dport 514 -j DNAT --to-destination 127.0.0.1:514"
22+
become: true
23+
24+
- set_fact:
25+
detect_time_list: []
26+
restore_time_list: []
27+
28+
- set_fact:
29+
pfc_frames_number: 300000
30+
31+
- name: Calculate detection and restoration timings
32+
include: roles/test/tasks/pfc_wd/functional_test/timer_test.yml
33+
with_sequence: start=1 end=20
34+
35+
- debug:
36+
var: "{{item}}"
37+
with_items:
38+
- detect_time_list
39+
- restore_time_list
40+
41+
- name: Verify that real detection time is not greater than configured
42+
fail:
43+
msg: Real detection time is greater than configured
44+
when: "{{(detect_time_list | sum)/20 > pfc_wd_detect_time + pfc_wd_poll_time}}"
45+
46+
- name: Verify that real detection time is not less than configured
47+
fail:
48+
msg: Real detection time is less than configured
49+
when: "{{(detect_time_list | sum)/20 < pfc_wd_detect_time}}"
50+
51+
- name: Verify that real restoration time is not less than configured
52+
fail:
53+
msg: Real restoration time is less than configured
54+
when: "{{(restore_time_list | sum)/20 < pfc_wd_restore_time}}"
55+
56+
- name: Verify that real restoration time is less than configured
57+
fail:
58+
msg: Real restoration time is greater than configured
59+
when: "{{(restore_time_list | sum)/20 > pfc_wd_restore_time + pfc_wd_poll_time}}"
60+
61+
always:
62+
- name: Clean up config
63+
vars:
64+
command_to_run: "pfcwd stop"
65+
errors_expected: false
66+
include: roles/test/tasks/run_command_with_log_analyzer.yml

0 commit comments

Comments
 (0)