diff --git a/ansible/roles/test/files/acstests/acltb_test_dell.py b/ansible/roles/test/files/acstests/acltb_test_dell.py new file mode 100644 index 0000000000..5a67ec8807 --- /dev/null +++ b/ansible/roles/test/files/acstests/acltb_test_dell.py @@ -0,0 +1,303 @@ +''' +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'] + self.testbed_type = self.test_params['testbed_type'] + + #--------------------------------------------------------------------- + + ''' + 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") + + #Creates a ICMP packet + pkt0 = simple_icmp_packet( + eth_dst = self.router_mac, + eth_src = self.dataplane.get_mac(0, 0), + ip_src = "10.0.0.1", + ip_dst = dst_ip, + icmp_type=8, + icmp_code=0, + ip_ttl = 64 + ) + #exp_pkt = pkt.deepcopy() + exp_pkt0 = simple_icmp_packet( + eth_dst = self.dataplane.get_mac(0, 0), + eth_src = self.router_mac, + ip_src = "10.0.0.1", + ip_dst = dst_ip, + icmp_type=8, + icmp_code=0, + ip_ttl = 63 + ) + + # Test #12 - Verify IP protocol & 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" + pkt['IP'].proto=0x1 + exp_pkt['IP'].proto=0x1 + res = self.runSendReceiveTest(pkt, src_port, exp_pkt, dst_ports) + tests_passed += (0 if res else 1) + print "Test #12 %s" % ("FAILED" if res else "PASSED") + 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() + if self.testbed_type in [ 't1', 't1-lag' ]: + 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) + elif self.testbed_type == 't0': + src_port = map(int, self.switch_info[0].rstrip(",\n").split(",")) + dst_ports = map(int, self.switch_info[1].rstrip(",\n").split(",")) + dst_ip = self.switch_info[2].strip() + dst_ip_blocked = self.switch_info[3].strip() + + (tests_passed, tests_total) = self.runAclTests(dst_ip, dst_ip_blocked, src_port[0], dst_ports) + assert(tests_passed == tests_total) + diff --git a/ansible/roles/test/tasks/acl/acltb_test_rules_1.json b/ansible/roles/test/tasks/acl/acltb_test_rules_1.json new file mode 100644 index 0000000000..0ebc5a946e --- /dev/null +++ b/ansible/roles/test/tasks/acl/acltb_test_rules_1.json @@ -0,0 +1,210 @@ +{ + "acl": { + "acl-sets": { + "acl-set": { + "dataacl": { + "acl-entries": { + "acl-entry": { + "1": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 1 + }, + "ip": { + "config": { + "source-ip-address": "10.0.0.2/32" + } + } + }, + "2": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 2 + }, + "ip": { + "config": { + "source-ip-address": "192.168.0.16/32" + } + } + }, + "3": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 3 + }, + "transport": { + "config": { + "source-port": "4661" + } + } + }, + "4": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 4 + }, + "ip": { + "config": { + "protocol": 126 + } + } + }, + "5": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 5 + }, + "transport": { + "config": { + "tcp-flags": ["TCP_ACK", "TCP_SYN"] + } + } + }, + "6": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 6 + }, + "ip": { + "config": { + "source-ip-address": "10.0.0.3/32" + } + } + }, + "7": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 7 + }, + "ip": { + "config": { + "source-ip-address": "10.0.0.3/32" + } + } + }, + "8": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 8 + }, + "transport": { + "config": { + "destination-port": "4661" + } + } + }, + "9": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 9 + }, + "l2": { + "config": { + "ethertype": "4660" + } + } + }, + "10": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 10 + }, + "transport": { + "config": { + "source-port": "4656..4671" + } + } + }, + "11": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 11 + }, + "transport": { + "config": { + "destination-port": "4640..4687" + } + } + }, + "12": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 12 + }, + "ip": { + "config": { + "protocol":1, + "source-ip-address": "10.0.0.2/32" + } + } + }, + "13": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 13 + }, + "l2": { + "config": { + "ethertype": "ETHERTYPE_IPV4" + } + } + } + } + } + } + } + } + } +} diff --git a/ansible/roles/test/tasks/acl/acltb_test_rules_part_3.json b/ansible/roles/test/tasks/acl/acltb_test_rules_part_3.json new file mode 100644 index 0000000000..0ebc5a946e --- /dev/null +++ b/ansible/roles/test/tasks/acl/acltb_test_rules_part_3.json @@ -0,0 +1,210 @@ +{ + "acl": { + "acl-sets": { + "acl-set": { + "dataacl": { + "acl-entries": { + "acl-entry": { + "1": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 1 + }, + "ip": { + "config": { + "source-ip-address": "10.0.0.2/32" + } + } + }, + "2": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 2 + }, + "ip": { + "config": { + "source-ip-address": "192.168.0.16/32" + } + } + }, + "3": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 3 + }, + "transport": { + "config": { + "source-port": "4661" + } + } + }, + "4": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 4 + }, + "ip": { + "config": { + "protocol": 126 + } + } + }, + "5": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 5 + }, + "transport": { + "config": { + "tcp-flags": ["TCP_ACK", "TCP_SYN"] + } + } + }, + "6": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 6 + }, + "ip": { + "config": { + "source-ip-address": "10.0.0.3/32" + } + } + }, + "7": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 7 + }, + "ip": { + "config": { + "source-ip-address": "10.0.0.3/32" + } + } + }, + "8": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 8 + }, + "transport": { + "config": { + "destination-port": "4661" + } + } + }, + "9": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 9 + }, + "l2": { + "config": { + "ethertype": "4660" + } + } + }, + "10": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 10 + }, + "transport": { + "config": { + "source-port": "4656..4671" + } + } + }, + "11": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 11 + }, + "transport": { + "config": { + "destination-port": "4640..4687" + } + } + }, + "12": { + "actions": { + "config": { + "forwarding-action": "DROP" + } + }, + "config": { + "sequence-id": 12 + }, + "ip": { + "config": { + "protocol":1, + "source-ip-address": "10.0.0.2/32" + } + } + }, + "13": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 13 + }, + "l2": { + "config": { + "ethertype": "ETHERTYPE_IPV4" + } + } + } + } + } + } + } + } + } +} diff --git a/ansible/roles/test/tasks/acltb_dell.yml b/ansible/roles/test/tasks/acltb_dell.yml new file mode 100644 index 0000000000..a755251833 --- /dev/null +++ b/ansible/roles/test/tasks/acltb_dell.yml @@ -0,0 +1,103 @@ +# Set facts for the loganalizer +- set_fact: + out_dir: /tmp/ + testname: acl + run_dir: /tmp/ + +# 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 + +# Copy ACL config to the switch +- name: Copy ACL config file to the DUT + copy: src="roles/test/tasks/acl/{{ item }}" dest="/tmp/" + with_items: + - "acltb_test_rules_1.json" + - "acltb_test_rules_allow_all.json" + - "acltb_test_rules-del.json" + - "acltb_test_rules_part_1.json" + - "acltb_test_rules_part_3.json" + +# 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 }}" + +- block: + - name: Apply allow all rule + vars: + command_to_run: "acl-loader update full /tmp/acltb_test_rules_allow_all.json" + errors_expected: false + include: roles/test/tasks/run_command_with_log_analyzer.yml + + - name: Apply test rules + vars: + command_to_run: "acl-loader update full /tmp/acltb_test_rules_1.json" + errors_expected: false + include: roles/test/tasks/run_command_with_log_analyzer.yml + + - name: copy acsbase files + copy: src=roles/test/files/acstests + dest=/root + delegate_to: "{{ ptf_host }}" + + - name: Run the test + include: ptf_runner.yml + vars: + ptf_test_name: ACL Test + ptf_test_dir: acstests + ptf_test_path: acltb_test_dell.AclTest + ptf_platform: remote + ptf_test_params: + - verbose=True + - router_mac=\"{{ ansible_Ethernet0['macaddress'] }}\" + - switch_info=\"/tmp/acltb_switch_info.txt\" + - testbed_type=\"{{ testbed_type }}\" + + - name: Clean up ACL rules. + vars: + command_to_run: "acl-loader update full /tmp/acltb_test_rules-del.json" + errors_expected: false + include: roles/test/tasks/run_command_with_log_analyzer.yml + + - name: Apply part 1 of ACL rules. + vars: + command_to_run: "acl-loader update incremental /tmp/acltb_test_rules_part_1.json" + errors_expected: false + include: roles/test/tasks/run_command_with_log_analyzer.yml + + - name: Apply part 2 of ACL rules. + vars: + command_to_run: "acl-loader update incremental /tmp/acltb_test_rules_part_3.json" + errors_expected: false + include: roles/test/tasks/run_command_with_log_analyzer.yml + + - name: Run the test + include: ptf_runner.yml + vars: + ptf_test_name: ACL Test + ptf_test_dir: acstests + ptf_test_path: acltb_test_dell.AclTest + ptf_platform: remote + ptf_test_params: + - verbose=True + - router_mac=\"{{ ansible_Ethernet0['macaddress'] }}\" + - switch_info=\"/tmp/acltb_switch_info.txt\" + - testbed_type=\"{{ testbed_type }}\" + + always: + - name: Clean up ACL rules. + vars: + command_to_run: "acl-loader update full /tmp/acltb_test_rules-del.json" + errors_expected: false + include: roles/test/tasks/run_command_with_log_analyzer.yml diff --git a/ansible/roles/test/tasks/test_sonic_by_tag.yml b/ansible/roles/test/tasks/test_sonic_by_tag.yml index c72f0af4c1..f1e625df2e 100644 --- a/ansible/roles/test/tasks/test_sonic_by_tag.yml +++ b/ansible/roles/test/tasks/test_sonic_by_tag.yml @@ -158,6 +158,10 @@ include: acltb.yml tags: acl +- name: ACL test Dell version with ICMP testcase + include: acltb_dell.yml + tags: dell + - name: PFC Watchdog test include: pfc_wd.yml tags: pfc_wd @@ -166,6 +170,7 @@ include: ecn_wred.yml tags: ecn_wred + ### when calling this test, please add command line of testbed_type ### -e testbed_type=t1 - name: BGP multipath relax