diff --git a/.azure-pipelines/recover_testbed/dut_connection.py b/.azure-pipelines/recover_testbed/dut_connection.py index 9784c7d029..cef5cb9db8 100644 --- a/.azure-pipelines/recover_testbed/dut_connection.py +++ b/.azure-pipelines/recover_testbed/dut_connection.py @@ -97,7 +97,6 @@ def get_ssh_info(sonichost): host=sonichost.im.get_hosts(pattern='sonic')[0]).get("ansible_altpassword") sonic_password = [creds['sonicadmin_password'], sonicadmin_alt_password] sonic_ip = sonichost.im.get_host(sonichost.hostname).vars['ansible_host'] - logging.info("sonic username: {}, password: {}".format(sonic_username, sonic_password)) return sonic_username, sonic_password, sonic_ip diff --git a/ansible/config_sonic_basedon_testbed.yml b/ansible/config_sonic_basedon_testbed.yml index 7f6c2f341d..ea83c0e727 100644 --- a/ansible/config_sonic_basedon_testbed.yml +++ b/ansible/config_sonic_basedon_testbed.yml @@ -495,21 +495,6 @@ line: 'snmp_rocommunity: {{ snmp_rocommunity }}' 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 - register: updategraph_conf - - - name: restart automatic minigraph update service - become: true - service: - name: updategraph - state: restarted - when: updategraph_conf.changed - - name: docker status shell: docker ps register: docker_status @@ -525,6 +510,19 @@ delay: 10 until: result is not failed + - name: Cleanup /etc/sonic folder before loading new minigraph + block: + - name: Ensure /etc/sonic/acl.json is deleted + become: true + file: + path: /etc/sonic/acl.json + state: absent + - name: Ensure /etc/sonic/port_config.json is deleted + become: true + file: + path: /etc/sonic/port_config.json + state: absent + - name: execute cli "config load_minigraph -y" to apply new minigraph become: true shell: config load_minigraph -y diff --git a/ansible/plugins/connection/multi_passwd_ssh.py b/ansible/plugins/connection/multi_passwd_ssh.py index f14fd7d3ee..ade9320312 100644 --- a/ansible/plugins/connection/multi_passwd_ssh.py +++ b/ansible/plugins/connection/multi_passwd_ssh.py @@ -1,4 +1,5 @@ import imp +import logging import os from functools import wraps @@ -6,6 +7,8 @@ from ansible.plugins import connection +logger = logging.getLogger(__name__) + # HACK: workaround to import the SSH connection plugin _ssh_mod = os.path.join(os.path.dirname(connection.__file__), "ssh.py") _ssh = imp.load_source("_ssh", _ssh_mod) @@ -26,17 +29,20 @@ vars: - name: ansible_altpasswords - name: ansible_ssh_altpasswords + hostv6: + description: IPv6 address + vars: + - name: ansible_hostv6 """.lstrip("\n") def _password_retry(func): """ Decorator to retry ssh/scp/sftp in the case of invalid password - + Will retry with IPv6 addr if IPv4 addr is unavailable Will retry for password in (ansible_password, ansible_altpassword, ansible_altpasswords): """ - @wraps(func) - def wrapped(self, *args, **kwargs): + def _conn_with_multi_pwd(self, *args, **kwargs): password = self.get_option("password") or self._play_context.password conn_passwords = [password] altpassword = self.get_option("altpassword") @@ -45,7 +51,6 @@ def wrapped(self, *args, **kwargs): altpasswds = self.get_option("altpasswords") if altpasswds: conn_passwords.extend(altpasswds) - while conn_passwords: conn_password = conn_passwords.pop(0) # temporarily replace `password` for this trial @@ -61,8 +66,39 @@ def wrapped(self, *args, **kwargs): # reset `password` to its original state self.set_option("password", password) self._play_context.password = password - # retry here, need create a new pipe for sshpass + # This is a retry, so the fd/pipe for sshpass is closed, and we need a new one self.sshpass_pipe = os.pipe() + + @wraps(func) + def wrapped(self, *args, **kwargs): + try: + # First, try with original host(generally IPv4) with multi-password + return _conn_with_multi_pwd(self, *args, **kwargs) + except BaseException as e: + # If a non-authentication related exception is raised and IPv6 host is set, + # Retry with IPv6 host with multi-password + try: + hostv6 = self.get_option("hostv6") + except KeyError: + hostv6 = None + if (type(e) != AnsibleAuthenticationFailure) and hostv6: + # This is a retry, so the fd/pipe for sshpass is closed, and we need a new one + self.sshpass_pipe = os.pipe() + self._play_context.remote_addr = hostv6 + # args sample: + # ( [b'sshpass', b'-d18', b'ssh', b'-o', b'ControlMaster=auto', b'-o', b'ControlPersist=120s', b'-o', b'UserKnownHostsFile=/dev/null', b'-o', b'StrictHostKeyChecking=no', b'-o', b'StrictHostKeyChecking=no', b'-o', b'User="admin"', b'-o', b'ConnectTimeout=60', b'-o', b'ControlPath="/home/user/.ansible/cp/376bdcc730"', 'fc00:1234:5678:abcd::2', b'/bin/sh -c \'echo PLATFORM; uname; echo FOUND; command -v \'"\'"\'python3.10\'"\'"\'; command -v \'"\'"\'python3.9\'"\'"\'; command -v \'"\'"\'python3.8\'"\'"\'; command -v \'"\'"\'python3.7\'"\'"\'; command -v \'"\'"\'python3.6\'"\'"\'; command -v \'"\'"\'python3.5\'"\'"\'; command -v \'"\'"\'/usr/bin/python3\'"\'"\'; command -v \'"\'"\'/usr/libexec/platform-python\'"\'"\'; command -v \'"\'"\'python2.7\'"\'"\'; command -v \'"\'"\'/usr/bin/python\'"\'"\'; command -v \'"\'"\'python\'"\'"\'; echo ENDFOUND && sleep 0\''], None) # noqa: E501 + # args[0] are the parameters of ssh connection + ssh_args = args[0] + # Change the IPv4 host in the ssh_args to IPv6 + for idx in range(len(ssh_args)): + if type(ssh_args[idx]) == bytes and ssh_args[idx].decode() == self.host: + ssh_args[idx] = hostv6 + self.host = hostv6 + self.set_option("host", hostv6) + return _conn_with_multi_pwd(self, *args, **kwargs) + else: + raise e + return wrapped diff --git a/ansible/roles/fanout/tasks/sonic/fanout_sonic_202012.yml b/ansible/roles/fanout/tasks/sonic/fanout_sonic_202012.yml index 36c741406c..457224249c 100644 --- a/ansible/roles/fanout/tasks/sonic/fanout_sonic_202012.yml +++ b/ansible/roles/fanout/tasks/sonic/fanout_sonic_202012.yml @@ -50,3 +50,8 @@ shell: "bcmcmd 'fp detach' && bcmcmd 'fp init'" become: yes when: "'broadcom' in fanout_sonic_version.asic_type" + +- name: Run config qos reload command to load qos settings in order to fix 9332 Wdrr testcase failure + shell: config qos reload + become: yes + when: "'DellEMC-Z9332f-O32' in device_info[inventory_hostname]['HwSku']" diff --git a/ansible/roles/test/files/ptftests/py3/dhcp_relay_test.py b/ansible/roles/test/files/ptftests/py3/dhcp_relay_test.py index 1826a67e8a..e5f6d66476 100644 --- a/ansible/roles/test/files/ptftests/py3/dhcp_relay_test.py +++ b/ansible/roles/test/files/ptftests/py3/dhcp_relay_test.py @@ -795,7 +795,5 @@ def runTest(self): # Below verification will be done only when client port is set in ptf_runner if not self.dual_tor and 'other_client_port' in self.test_params: - self.verify_dhcp_relay_pkt_on_other_client_port_with_no_padding( - self.dest_mac_address, self.client_udp_src_port) self.verify_dhcp_relay_pkt_on_server_port_with_no_padding( self.dest_mac_address, self.client_udp_src_port) diff --git a/ansible/roles/vm_set/library/sonic_kickstart.py b/ansible/roles/vm_set/library/sonic_kickstart.py index 44497bfcca..e4c4920916 100644 --- a/ansible/roles/vm_set/library/sonic_kickstart.py +++ b/ansible/roles/vm_set/library/sonic_kickstart.py @@ -84,18 +84,10 @@ def logout(self): def session(new_params): - if new_params['disable_updategraph']: - seq = [ - ('while true; do if [ $(systemctl is-active swss) == "active" ]; then break; fi; ' - 'echo $(systemctl is-active swss); ' - 'sed -i -e "s/enabled=true/enabled=false/" /etc/sonic/updategraph.conf; ' - 'systemctl restart updategraph; sleep 1; done', [r'#'], 180), - ] - else: - seq = [ - ('while true; do if [ $(systemctl is-active swss) == "active" ]; then break; fi; ' - 'echo $(systemctl is-active swss); sleep 1; done', [r'#'], 180), - ] + seq = [ + ('while true; do if [ $(systemctl is-active swss) == "active" ]; then break; fi; ' + 'echo $(systemctl is-active swss); sleep 1; done', [r'#'], 180), + ] seq.extend([ ('pkill dhclient', [r'#']), @@ -145,7 +137,6 @@ def main(): mgmt_gw=dict(required=True), new_password=dict(required=True), num_asic=dict(required=True), - disable_updategraph=dict(required=True, type='bool'), )) try: diff --git a/ansible/roles/vm_set/tasks/kickstart_vm.yml b/ansible/roles/vm_set/tasks/kickstart_vm.yml index 45879b1cf1..ca74b1329a 100644 --- a/ansible/roles/vm_set/tasks/kickstart_vm.yml +++ b/ansible/roles/vm_set/tasks/kickstart_vm.yml @@ -3,10 +3,6 @@ respin_vms: [] when: respin_vms is not defined -- set_fact: - disable_updategraph: False - when: disable_updategraph is not defined - - set_fact: skip_this_vm: True @@ -65,7 +61,6 @@ mgmt_gw={{ vm_mgmt_gw | default(mgmt_gw) }} new_password={{ sonic_password }} num_asic={{ num_asic }} - disable_updategraph={{ disable_updategraph }} register: kickstart_output until: '"kickstart_code" in kickstart_output and kickstart_output.kickstart_code == 0' retries: 5 @@ -97,7 +92,6 @@ mgmt_gw={{ vm_mgmt_gw | default(mgmt_gw) }} new_password={{ sonic_password }} num_asic={{ num_asic }} - disable_updategraph={{ disable_updategraph }} register: kickstart_output_final until: '"kickstart_code" in kickstart_output_final and kickstart_output_final.kickstart_code == 0' retries: 5 diff --git a/ansible/roles/vm_set/tasks/start_sonic_vm.yml b/ansible/roles/vm_set/tasks/start_sonic_vm.yml index 94628c14b3..0f83bc7775 100644 --- a/ansible/roles/vm_set/tasks/start_sonic_vm.yml +++ b/ansible/roles/vm_set/tasks/start_sonic_vm.yml @@ -2,10 +2,6 @@ sonic_vm_storage_location: "{{ home_path }}/sonic-vm" when: sonic_vm_storage_location is not defined -- set_fact: - disable_updategraph: False - when: disable_updategraph is not defined - - name: Create directory for vm images and vm disks file: path={{ item }} state=directory mode=0755 with_items: @@ -66,7 +62,6 @@ mgmt_gw={{ vm_mgmt_gw | default(mgmt_gw) }} new_password={{ sonic_password }} num_asic={{ num_asic }} - disable_updategraph={{ disable_updategraph }} register: kickstart_output - name: Fail if kickstart gives error for {{ dut_name }} diff --git a/ansible/testbed-cli.sh b/ansible/testbed-cli.sh index 6ba8954978..73863536de 100755 --- a/ansible/testbed-cli.sh +++ b/ansible/testbed-cli.sh @@ -54,7 +54,6 @@ function usage echo "To deploy topology for specified testbed on a server: $0 add-topo 'testbed-name' ~/.password" echo " Optional argument for add-topo:" echo " -e ptf_imagetag= # Use PTF image with specified tag for creating PTF container" - echo " -e disable_updategraph= # Disable updategraph service when deploying testbed" echo "To deploy topology with the help of the last cached deployed topology for the specified testbed on a server:" echo " $0 deploy-topo-with-cache 'testbed-name' 'inventory' ~/.password" echo "To remove topology for specified testbed on a server: $0 remove-topo 'testbed-name' ~/.password" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fb65c2fdc4..9fe39cbfe4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -148,19 +148,19 @@ stages: KVM_IMAGE_BRANCH: $(BUILD_BRANCH) MGMT_BRANCH: $(BUILD_BRANCH) - - job: dpu_elastictest - displayName: "kvmtest-dpu by Elastictest" - timeoutInMinutes: 240 - continueOnError: false - pool: ubuntu-20.04 - steps: - - template: .azure-pipelines/run-test-elastictest-template.yml - parameters: - TOPOLOGY: dpu - MIN_WORKER: $(T0_SONIC_INSTANCE_NUM) - MAX_WORKER: $(T0_SONIC_INSTANCE_NUM) - KVM_IMAGE_BRANCH: $(BUILD_BRANCH) - MGMT_BRANCH: $(BUILD_BRANCH) +# - job: dpu_elastictest +# displayName: "kvmtest-dpu by Elastictest" +# timeoutInMinutes: 240 +# continueOnError: false +# pool: ubuntu-20.04 +# steps: +# - template: .azure-pipelines/run-test-elastictest-template.yml +# parameters: +# TOPOLOGY: dpu +# MIN_WORKER: $(T0_SONIC_INSTANCE_NUM) +# MAX_WORKER: $(T0_SONIC_INSTANCE_NUM) +# KVM_IMAGE_BRANCH: $(BUILD_BRANCH) +# MGMT_BRANCH: $(BUILD_BRANCH) # - job: wan_elastictest # displayName: "kvmtest-wan by Elastictest" diff --git a/docs/api_wiki/README.md b/docs/api_wiki/README.md index e5438b7ff2..20e4008f12 100644 --- a/docs/api_wiki/README.md +++ b/docs/api_wiki/README.md @@ -207,6 +207,8 @@ def test_fun(duthosts, rand_one_dut_hostname, ptfhost): - [get_vlan_intfs](sonichost_methods/get_vlan_intfs.md) - Retrieves list of interfaces belonging to a VLAN. +- [get_vlan_brief](sonichost_methods/get_vlan_brief.md) - Returns a dict contians all vlans with their brief information + - [hostname](sonichost_methods/hostname.md) - Provides hostname for device. - [is_backend_portchannel](sonichost_methods/is_backend_portchannel.md) - Returns whether or not a provided portchannel is a backend portchannel. diff --git a/docs/api_wiki/sonichost_methods/get_vlan_brief.md b/docs/api_wiki/sonichost_methods/get_vlan_brief.md new file mode 100644 index 0000000000..81109bf05e --- /dev/null +++ b/docs/api_wiki/sonichost_methods/get_vlan_brief.md @@ -0,0 +1,48 @@ +# get_vlan_brief + +- [Overview](#overview) +- [Examples](#examples) +- [Arguments](#arguments) +- [Expected Output](#expected-output) +- [Potential Exception](#potential-exception) + +## Overview + +Read vlan brief information from running config. + +## Examples + +```python +def test_fun(duthosts, rand_one_dut_hostname): + duthost = duthosts[rand_one_dut_hostname] + vlan_brief = duthost.get_vlan_brief() +``` + +## Arguments + +None + +## Expected Output + +Returns an dict, key is vlan name and value is brief information. + +Example output: + +``` +{ + "Vlan1000": { + "interface_ipv4": [ "192.168.0.1/24" ], + "interface_ipv6": [ "fc02:1000::1/64" ], + "members": ["Ethernet0", "Ethernet1"] + }, + "Vlan2000": { + "interface_ipv4": [ "192.168.1.1/24" ], + "interface_ipv6": [ "fc02:1001::1/64" ], + "members": ["Ethernet3", "Ethernet4"] + } +} +``` + +## Potential Exception + +- [Exception from function get_running_config_facts](get_running_config_facts.md) diff --git a/docs/testplan/IPv4-Port-Based-DHCP-Server-test-plan.md b/docs/testplan/IPv4-Port-Based-DHCP-Server-test-plan.md new file mode 100644 index 0000000000..6c0ef62dc3 --- /dev/null +++ b/docs/testplan/IPv4-Port-Based-DHCP-Server-test-plan.md @@ -0,0 +1,332 @@ +# IPv4 Port Based DHCP Server Test Plan + + +- [IPv4 Port Based DHCP Server Test Plan](#ipv4-port-based-dhcp-server-test-plan) + - [Related Documents](#related-documents) + - [Overview](#overview) + - [Scope](#scope) + - [Test Scenario](#test-scenario) + - [Supported Topology](#supported-topology) + - [Test Case](#test-case) + - [Common Function](#common-function) + - [send_and_verify:](#send_and_verify) + - [Test Module #1 test_dhcp_server.py](#test-module-1-test_dhcp_serverpy) + - [Port Based Common setup](#port-based-common-setup) + - [Port Based Common teardown](#port-based-common-teardown) + - [test_dhcp_server_port_based_assignment_single_ip](#test_dhcp_server_port_based_assignment_single_ip) + - [test_dhcp_server_port_based_assigenment_single_ip_mac_move](#test_dhcp_server_port_based_assigenment_single_ip_mac_move) + - [test_dhcp_server_port_based_assigenment_single_ip_mac_swap](#test_dhcp_server_port_based_assigenment_single_ip_mac_swap) + - [test_dhcp_server_port_based_assignment_range](#test_dhcp_server_port_based_assignment_range) + - [test_dhcp_server_port_based_customize_options](#test_dhcp_server_port_based_customize_options) + - [test_dhcp_server_config_change](#test_dhcp_server_config_change) + - [test_dhcp_server_config_vlan_intf_change](#test_dhcp_server_config_vlan_intf_change) + - [test_dhcp_server_config_vlan_member_change](#test_dhcp_server_config_vlan_member_change) + - [test_dhcp_server_critical_process](#test_dhcp_server_critical_process) + - [Test Module #2 test_dhcp_server_multi_vlan.py](#test-module-2-test_dhcp_server_multi_vlanpy) + - [Common setup](#common-setup) + - [Common teardown](#common-teardown) + - [test_dhcp_server_multi_vlan](#test_dhcp_server_multi_vlan) + - [Test Module #3 test_dhcp_server_stress.py](#test-module-3-test_dhcp_server_stresspy) + - [Common setup](#common-setup) + - [Common teardown](#common-teardown) + - [test_dhcp_server_stress](#test_dhcp_server_stress) + - [Test Module #4 test_dhcp_server_smart_switch.py](#test-module-4-test_dhcp_server_smart_switchpy) + - [Common setup](#common-setup) + - [Common teardown](#common-teardown) + - [test_dhcp_server_smart_switch](#test_dhcp_server_smart_switch) + + +## Related Documents + +| **Document Name** | **Link** | +|-------------------|----------| +| IPv4 Port Based DHCP_SERVER in SONiC | [port_based_dhcp_server_high_level_design.md](https://github.com/sonic-net/SONiC/blob/master/doc/dhcp_server/port_based_dhcp_server_high_level_design.md)| +|Smart Switch IP address assignment| [smart-switch-ip-address-assignment.md](https://github.com/sonic-net/SONiC/blob/master/doc/smart-switch/ip-address-assigment/smart-switch-ip-address-assignment.md)| + +## Overview + +A DHCP Server is a server on network that can automatically provide and assign IP addresses, default gateways and other network parameters to client devices. Port based DHCP server is to assign IPs based on interface index. + +## Scope + +### Test Scenario + +The tests will include: + +1. Configuration test + 1. Add related configuration into CONFIG_DB and then verify configuration and process running status. + 2. Update related tables in CONFIG_DB to see whether configuration for DHCP Server change too. +2. Functionality test + 1. Check whether dhcrelay in dhcp_relay can foward DHCP packets between client and dhcp_server container. + 2. Check whether dhcp_server container can reply DHCP reply packets as expected. + 3. Verify in multi-vlan scenario. + 4. Verify in mac change scenario. + +### Supported Topology + +Base dhcp_server functionality tests (test module [#1](#test-module-1-test_dhcp_serverpy) [#2](#test-module-2-test_dhcp_server_multi_vlanpy) [#3](#test-module-3-test_dhcp_server_stresspy)) are supported on mx topology, smart switch related test (test module [#4](#test-module-4-test_dhcp_server_smart_switchpy)) is supported on t1-smartswitch topology (A new topology on real smart switch testbed). + +## Test Case + +### Common Function + +#### send_and_verify + * Send DHCP discover packets from PTF, check whether configured port receive DHCP offer packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. + * Send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. Besides, check lease via show CLI to make sure lease is correct. + * For renew scenario, send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. Besides, check lease via show CLI to make sure lease is correct. + * Send DHCP release packets from PTF, check whether lease release via lease file inside dhcp_server container. + +### Test Module #1 test_dhcp_server.py + +#### Port Based Common setup + +* Check whether dhcrelay process running as expected (Original dhcp_relay functionality). +* Enable dhcp_server feature, and then use CLI to add DHCP Server configuration. + +#### Port Based Common teardown + +* Disable dhcp_server feature, and then check whether dhcrelay process running as expected (Original dhcp_relay functionality). +* Config reload, remove dhcp_server container. + +#### test_dhcp_server_port_based_assignment_single_ip + +* **Test objective** + + To test port based single ip assign. + + Assume that ports in DUT and PTF are connected like below: + + * DUT Ethernet0 - PTF eth0 + * DUT Ethernet1 - PTF eth1 + * DUT Ethernet2 - PTF eth2 + * DUT Ethernet3 - PTF eth3 + * DUT EThernet4 - PTF eth4 (Not configured interface) + + 3 tested scenarios: + + 1. Verify configured interface with client mac not in FDB table can successfully get IP. + 2. Verify configured interface with client mac in FDB table can successfully get IP. + 3. Verify configured interface with client mac in FDB table but ip it's learnt from another interface can successfully get IP. + 4. Verify no-configured interface cannot get IP. + +* **Setup** + + * Clear FDB table in DUT. + * Ping DUT vlan ip from eth1 and eth3 in PTF. + +* **Test detail** + + * Add a fixture to verify above scenarios: + * mac_not_in_fdb: Use `send_and_verify` to send and verify from eth0 with mac address of eth0, success to get IP. + * mac_in_fdb:Use `send_and_verify` to send and verify from eth0 with mac address of eth1, success to get IP. + * mac_learnt_from_other_interface: Use `send_and_verify` to send and verify from eth2 with mac address of eth3, success to get IP. + * no_configured_interface: Use `send_and_verify` to send and verify from eth4 with mac address of eth4, expected result: fail to get IP. + +#### test_dhcp_server_port_based_assigenment_single_ip_mac_move + +* **Test objective** + + To test port based single ip assign with client move to an interface has free IP to assign. + +* **Setup** + + Save originaly mac address in PTF. + +* **Teardown** + + Restore mac address configuration in PTF. + +* **Test detail** + + * `send_and_verify` with mac A in interface A, expected result: IP assign successfully. + * `send_and_verify` with mac A in interface B, expected result: IP assign successfully. + +#### test_dhcp_server_port_based_assigenment_single_ip_mac_swap + +* **Test objective** + + To test port based single ip assign with client swap. + +* **Setup** + + Save originaly mac address in PTF. + +* **Teardown** + + Restore mac address configuration in PTF. + +* **Test detail** + + * `send_and_verify` with mac A in interface A, expected result: client A can get correct IP. + * `send_and_verify` with mac B in interface B, expected result: client A can get correct IP. + * `send_and_verify` with mac A in interface B, expected result: client A can get correct IP. + * `send_and_verify` with mac B in interface A, expected result: client A can get correct IP. + +#### test_dhcp_server_port_based_assignment_range + +* **Test objective** + + To test port based range ip assign. + +* **Setup** + + Add range and bind range via CLI. + +* **Teardown** + + Unbind range and del range via CLI. + +* **Test detail** + + * Always send packets from 1 PTF port with different client mac, process of sending and verifying can reuse function `send_and_verify`. + * Verify that new client can get / renew / release IP from range binded. When IPs in range are all used, new client cannot get IP. + +#### test_dhcp_server_port_based_customize_options + +* **Test objective** + + To test customize options (In current design, customized options will be always sent to client). + +* **Setup** + + Add option and bind option via CLI. + +* **Teardown** + + Unbind option and del option via CLI. + +* **Test detail** + + * Send DHCP discover packets from PTF, check whether configured port receive DHCP offer packet and no-configured ports don't receive. Need to check customized options. + * Send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check customized options. + * Send DHCP release packets from PTF. + +#### test_dhcp_server_config_change + +* **Test objective** + + To test dhcp_server configuration change scenario. + +* **Test detail** + + * Use CLI to modify lease_time / netmask / gateway / customized_options in `DHCP_SEVER_IPV4` table and send discover / requset packets from PTF and check whether receive expected offer / ack packets. + * Use CLI to disable / enable DHCP interface and send discover / requset packets from PTF and check whether receive expected offer / ack packets. + * Use CLI to modify `DHCP_SERVER_IPV4_PORT` / `DHCP_SERVER_IPV4_CUSTOMIZED_OPTIONS` and send discover / requset packets from PTF and check whether receive expected offer / ack packets. + +#### test_dhcp_server_config_vlan_intf_change + +* **Test objective** + + To test vlan interface configuration change scenario. + +* **Setup** + + Modify vlan ip in `VLAN_INTERFACE` table, change to another subnet. + +* **Teardown** + + Restore vlan ip. + +* **Test detail** + + * Send discover / requset packets from PTF, expect not receive offer / ack packets because ip address configure in `DHCP_SERVER_IPV4_PORT` doesn't match vlan ip. + +#### test_dhcp_server_config_vlan_member_change + +* **Test objective** + + To test vlan member configuration change scenario. + +* **Setup** + + Delete vlan member. + +* **Teardown** + + Restore vlan member. + +* **Test detail** + + * Send discover / requset packets from PTF, expect not receive offer / ack packets because member not in vlan. + +#### test_dhcp_server_critical_process + +* **Test objective** + + To test critical processes crush scenario. + +* **Test detail** + + * Kill processes in `dhcp_relay:/etc/supervisor/critical_processes` and `dhcp_server:/etc/supervisor/critical_processes` to see whether dhcp_server and dhcp_relay container restart. + * Can refer to `tests/process_monitoring/test_critical_process_monitoring.py` + +### Test Module #2 test_dhcp_server_multi_vlan.py + +#### Common setup + +* Enable dhcp_server feature. +* Apply DHCP Server related configuration for multiple vlans (Suggest use GCU). +* Use GCU to apply different VLAN configuration (VLAN / VLAN_MEMBER / VLAN_INTERFACE). The reason use GCU is that changing VLAN configuration via CLI is complicate. + +#### Common teardown + +* Config reload, remove dhcp_server container. + +#### test_dhcp_server_multi_vlan + +* **Test objective** + + To test ip assign in multiple vlan scenario. + +* **Test detail** + + * Send DHCP discover packets from PTF, check whether configured port receive DHCP offer packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. + * Send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. Besides, check lease via show CLI to make sure lease is correct. + * For renew scenario, send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. Besides, check lease via show CLI to make sure lease is correct. + * Send DHCP release packets from PTF, check whether lease release via lease file inside dhcp_server container. + +### Test Module #3 test_dhcp_server_stress.py + +#### Common setup + +* Enable dhcp_server feature, and then add DHCP Server configuration. + +#### Common teardown + +* Config reload, remove dhcp_server container. + +#### test_dhcp_server_stress + +* **Test objective** + + To test ip assign with flooding packets. + +* **Test detail** + + * Send flooding (100/s) DHCP discover packets in PTF and verify offer packets receive (whether receive and receive time) in PTF side. + * Send flooding (100/s) DHCP request packets in PTF and verify ack packets receive (whether receive and receive time) in PTF side. + +### Test Module #4 test_dhcp_server_smart_switch.py + +#### Common setup + +* Enable dhcp_server feature. +* Add DHCP Server configuration. +* Add smart switch related configuration (`DPUS` table and `MID_PLANE` table). + +#### Common teardown + +* Config reload, remove dhcp_server container. + +#### test_dhcp_server_smart_switch + +* **Test objective** + + To test ip assign with in smart switch. + +* **Test detail** + + * Send DHCP discover packets from PTF, check whether configured port receive DHCP offer packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. + * Send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. Besides, check lease via show CLI to make sure lease is correct. + * For renew scenario, send DHCP request packets from PTF, check whether configured port receive DHCP ack packet and no-configured ports don't receive. Need to check netmask / gateway / lease_time / yiaddr. Besides, check lease via show CLI to make sure lease is correct. + * Send DHCP release packets from PTF, check whether lease release via lease file inside dhcp_server container. diff --git a/docs/testplan/pac/PAC_Topology.png b/docs/testplan/pac/PAC_Topology.png new file mode 100644 index 0000000000..f8ab4a6009 Binary files /dev/null and b/docs/testplan/pac/PAC_Topology.png differ diff --git a/docs/testplan/pac/Port_Access_Control.md b/docs/testplan/pac/Port_Access_Control.md new file mode 100644 index 0000000000..5ad9f6db41 --- /dev/null +++ b/docs/testplan/pac/Port_Access_Control.md @@ -0,0 +1,622 @@ +# Port Access Control(PAC) + +[TOC] + +## Test Plan Revision History + +| Rev | Date | Author | Change Description | +| ---- | ---------- | ----------------- | ---------------------------- | +| 1 | 18/05/2023 | Lakshminarayana D | Initial Version of test plan | + +## Definition/Abbreviation + +| **Term** | **Meaning** | +| ---------- | ---------------------------------------- | +| VLAN | Virtual Local Area Network | +| PAC | Port Access Control | +| EAPoL | Extensible Authentication Protocol over LAN | +| MAC | Media Access Control | +| MAB | Mac Authentication Bypass | +| PO | Port Channel | +| NAS | Network Access Switch | +| DUT | Device Under Test | +| RADIUS | Remote Authentication Dial In User service | +| FDB | Forwarding Database | +| Supplicant | A client that attempts to access services offered by the Authenticator | +| PAE | Port Access Entity | + +## Introduction + +### Objective + +The main objective of this document is to cover the test cases that will be executed for Port authentication methods 802.1x and MAB. Topologies and test cases for testing the feature will be discussed as part of this document. + +### Scope + +- PAC authentication of hosts on access port +- This functionality has been tested using the SPyTest framework. In order to emulate 802.1x and MAB clients, traffic generators like Ixia and Spirent will be used. FreeRADIUS is using for User Authentication. + +### Out of scope + +- Authentication on Trunk port not supported + +## Feature Overview + +Port Access Control (PAC) feature provides validation of client and user credentials to prevent unauthorized access to a specific switch port. + +Local Area Networks (LANs) are often deployed in environments that permit unauthorized devices to be physically attached to the LAN infrastructure, or permit unauthorized users to attempt to access the LAN through equipment already attached. In such environments, it may be desirable to restrict access to the services offered by the LAN to those users and devices that are permitted to use those services. Port access control makes use of the physical characteristics of LAN infrastructures in order to provide a means of authenticating and authorizing devices attached to a LAN port that has point-to-point connection characteristics and of preventing access to that port in cases in which the authentication and authorization process fails. In this context, a port is a single point of attachment to the LAN, such as Ports of MAC bridges and associations between stations or access points in IEEE 802.11 Wireless LANs. + +802.1x: + +IEEE 802.1X-2004 is an IEEE Standard for Port Access Control (PAC) that provides an authentication mechanism to devices wishing to attach to a LAN. The standard defines Extensible Authentication Protocol Over LAN (EAPoL). The 802.1X standard describes an architectural framework within which authentication and consequent actions take place. It also establishes the requirements for a protocol between the authenticator and the supplicant, as well as between the authenticator and the authentication server. + +MAC Authentication Bypass(MAB): + +Simple devices like camera or printers which do not support 802.1x authentication can make use of MAB feature where the device gets authenticated based on the device MAC address. + +## Test Framework +Using SPyTest framework to test this feature. Traffic generators like Ixia and Spirent will be using to simulate 802.1x and MAB clients. FreeRADIUS is using for User Authentication and Authorization. + +## 1 Test Focus Areas + +### 1.1 CLI Testing + + - Verify port authentication can be enabled only on physical interfaces and gets denied on VLAN, Portchannel, PO member ports and sub interfaces. + - Verify configured CLI fields are updated properly in respective show commands + +### 1.2 Functional Testing + + - Verify all data traffic is blocked when PAC is enabled on the port. + - Verify 802.1x client authentication in single-host mode and verify only first authenticated user is allowed. + - Verify 802.1x client with multi-host mode and verify all users on the port are allowed after first-user gets authenticated. + - Verify 802.1x client authentication in multi-auth mode and verify all users with valid credentials gets authenticated. + - Verify in multi-auth mode, one of the clients logoff does not impact other authenticated clients. + - Verify in multi-host mode, if primary host gets logged-off, other hosts are blocked and verify after authenticating again. + - Verify 802.1x client authentication with port-control mode as force-authorized. + - Verify 802.1x client authentication with port-control mode as force-unauthorized. + - Verify interface level 802.1x pae authenticator disable/enable. + - Verify global 802.1x system-auth-control enable/disable. + - Verify enabling re-authentication with different re-authenticate timer and disabling authentication periodic shouldn't allow re-authentication. + - Verify client authentication with MAB auth-type as EAP-MD5. + - Verify client authentication with MAB auth-type as PAP. + - Verify client authentication with MAB auth-type as CHAP. + - Verify authentication order with user-configured priorities for different authentication methods. + - Verify non-default max-users per port and check remaining clients are denied. + - Verify that when host mode changes, the authenticated clients gets removed and traffic is blocked. + - Verify that when authentication order is set to 802.1x, then only 802.1x client allowed to authenticate. + - Verify that when authentication order is set to MAB, then 802.1x client authentication is not successful. + - Verify MAB client authentication with port-control mode toggle between force authorized/unauthorized and auto. + - Verify that 802.1x and MAB client is not authenticated if it's RADIUS assigned VLAN is not available statically on the authenticator switch. + - Verify 802.1x and MAB client is not authenticated if RADIUS does not assign a VLAN and the port is configured with tagged VLAN. + - Verify a port with Multi-auth mode can have authenticated clients in different radius assigned VLANs. + - Verify that 802.1x and MAB client is not authenticated if RADIUS does not assign a VLAN and the port's configured untagged VLAN (Access VLAN) is not available + - Verify the same MAB client authentication on different port after authenticated and verify MAC movement of the client + - Verify the same 802.1x client authentication on different port after authenticated and verify MAC movement of the client + - Verify the same 802.1x and MAB client authentication when PAC and ACLs applied on a same port + +### 1.3 Reboot and Trigger Testing + + - Verify Client authentication after reboot + - Verify Client authentication after warmboot + - Verify Client authentication after config reload + - Verify Client authentication after port toggle + +### 1.4 Scale Testing + + - Verify 128 max supported 802.1x clients on DUT. + - Verify 128 max supported MAB clients on DUT. + - Verify that the 128 maximum supported clients on DUT can be authenticated by using both 802.1x and MAB clients. + + +## 2 Topologies + +## 2.1 Topology 1 + +![PAC](PAC_topology.png "Figure 1: Topology 1") + +## 3 Test Case and objectives + +### **3.1 CLI Test Cases** + +### 3.1.1 Verify port authentication can be enabled only on physical interfaces and gets denied on VLAN, Portchannel, Po member ports and sub interfaces + +| **Test ID** | **PAC_CLI_001** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify port authentication can be enabled only on physical interfaces and gets denied on VLAN, Portchannel, PO member ports and sub interfaces** | +| **Test Setup** | **Topology1** | +| **Type** | **CLI** | +| **Steps** | 1. Verify port authentication configuration gets denied for VLAN interface,Sub interface and Portchannel interfaces
2. Verify authentication can not be enabled on Portchannel member ports
3. Enable authentication on physical port and add it to Portchannel and verify it is not allowed
4. Enable authentication on loopback port and verify it is not allowed
| + + +### 3.1.2 Verify configured CLI fields are updated properly in respective show commands + +| **Test ID** | **PAC_CLI_002** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify configured CLI fields are updated properly in respective show commands** | +| **Test Setup** | **Topology1** | +| **Type** | **CLI** | +| **Steps** | 1. Enable 802.1x globally using command "config dot1x system-auth-control enable" and verify administrative mode as enabled in "show dot1x" command
2. Disable 802.1x globally using command "config dot1x system-auth-control disable" and verify administrative mode as disabled in "show dot1x" command
3. Configure port-control mode to auto using command "config authentication port-control interface auto Ethernet0" and verify port control mode is changed to auto from force-authorized in "show authentication interface Ethernet0"
4. Configure port-control mode to force-unauthorized using command "config authentication port-control interface force-unauthorized Ethernet0" and verify port control mode is changed to force-unauthorized
5. Enable pae role as authenticator on interface using command "config dot1x pae interface authenticator Ethernet0" and verify pae mode is changed to authenticator in "show dot1x detail Ethernet0" and "show dot1x detail all"
6. Disable pae role on interface using command "config dot1x pae interface none Ethernet0" and verify pae mode is changed to none in "show dot1x detail Ethernet0" and "show dot1x detail all"
7. Configure host-mode to multi-auth using command "config authentication host-mode interface multi-auth Ethernet0" and verify host mode is changed to multi-auth from multi-host in "show authentication interface Ethernet0"
8. Configure host-mode to single-host using command "config authentication host-mode interface single-host Ethernet0" and verify host mode is changed to single-host from multi-host in "show authentication interface Ethernet0"
9. Configure max-users to non-default value using command "config authentication max-users interface 8 Ethernet0" and verify max-users field is changed to 8 from 16 in "show authentication interface Ethernet0"
10. Enable authentication periodic using command "config authentication periodic interface enable Ethernet0" and verify re-authentication periodic is enabled in "show authentication interface Ethernet0"
11. Disable authentication periodic command "config authentication periodic interface disable Ethernet0" and verify re-authentication periodic is disabled in "show authentication interface Ethernet0"
12. Configure authentication timer command "config authentication timer re-authenticate 100 Ethernet0" and verify re-authentication period is updated properly in "show authentication interface Ethernet0"
13. Configure authentication order to 802.1x using command "config authentication order interface dot1x Ethernet0" and verify configured method order is updated to 802.1x in "show authentication interface Ethernet0"
14. Configure authentication priority to 802.1x using command "config authentication priority interface dot1x Ethernet0" and verify configured method priority is updated to 802.1x in "show authentication interface Ethernet0"
15. Enable MAB with auth-type pap on interface using command "config MAB interface enable auth-type pap Ethernet0" and verify MAB admin mode is enabled with auth-type pap in "show mab Ethernet0" or "show mab"
16. Disable MAB on interface using command "config mab interface disable Ethernet0" and verify MAB admin mode is disabled in "show mab Ethernet0" and "show mab"
| + + +### **3.2 Functional Test Cases** + +### 3.2.1 Verify all data traffic is blocked when PAC is enabled on the port. + +| **Test ID** | **PAC_FUNC_001** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify all data traffic is blocked when PAC is enabled on the port** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on an interface
2. Verify all data traffic is blocked when PAC is enabled on the port
3. Verify EAPoL packets are not dropped
| + + +### 3.2.2 Verify 802.1x authentication in single-host mode and verify only first authenticated user is allowed. + +| **Test ID** | **PAC_FUNC_002** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 802.1x authentication in single-host mode and verify only first authenticated user is allowed.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on interface on DUT
2. Configure RADIUS server on the authenticator.
3. Enable authentication host mode to single-host mode on the interface.
4. Initiate Authentication from 802.1x supplicant and Verify Authenticator encapsulates EAP packets and sends it to RADIUS server
5. Verify Authenticator moves client to Authenticated state after sending EAP success, once authenticator receives Access-accept from RADIUS server
6. Verify "show authentication clients all" to see the client authentication state
7. Verify static MAC FDB entry gets populated with client mac address
8. Verify traffic gets forwarded from the client after it gets authenticated on the port and Verify client's traffic forwarding from the RADIUS assigned VLAN if not port's untagged VLAN is used for authorizing the client.
9. Verify Client2 is blocked from accessing the server in single-host mode
10. Do clear mac address table, and check statically created FDB entry for the client is not cleared and client authentication is not disturb.
11. Logoff client1 and verify FDB entry gets deleted and client1 gets blocked for all the traffic
12. Verify once client1 is deleted, client2 with single-host mode can be authenticated
13. Clear the clients using command 'sonic-clear authentication sessions interface and verify client gets deleted on the device
| + + +### 3.2.3 Verify 802.1x with multi-host mode and verify all users on the port are allowed after first-user gets authenticated. + +| **Test ID** | **PAC_FUNC_003** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 802.1x with multi-host mode and verify all users on the port are allowed after first-user gets authenticated.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on interface.
2. Configure RADIUS server on the authenticator.
3. Enable authentication host mode to multi-host mode
4. Initiate Authentication from 802.1x supplicant and Verify Authenticator encapsulates EAP packets and sends it to RADIUS server
6. Verify Authenticator moves client to Authenticated state after sending EAP success, once authenticator receives Access-accept from RADIUS server
7. Verify "show authentication clients all" to see the client state
8. Verify client's MAC FDB entry is populated once the client sends traffic after client gets authenticated
9. Verify untagged and tagged traffic gets forwarded from the client's RADIUS assigned VLAN if not port's untagged VLAN after it gets authenticated on the port, check non matching tagged traffic is not allowed.
10. Verify all the subsequent Clients traffic connected to port also gets access and check MAC address gets updated for all those clients
11. Logoff client1 and verify all the clients connected to the port gets blocked
| + + +### 3.2.4 Verify 802.1x client authentication in multi-auth mode and verify all users with valid credentials gets authenticated. + +| **Test ID** | **PAC_FUNC_004** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 802.1x in multi-auth mode and verify all users with valid credentials gets authenticated.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on interface.
2. Configure RADIUS server on the authenticator.
3. Enable authentication host mode to multi-auth mode
4. Initiate Authentication from multiple 802.1x supplicants connected to the same NAS port
5. Verify Authenticator encapsulates EAP packets and sends it to RADIUS server
6. Verify Authenticator moves all the clients to Authenticated state after sending EAP success, once authenticator receives Access-accept from RADIUS server for each client
7. Verify "show authentication clients all" to see the clients authentication state
8. Verify MAC FDB entry gets populated with client mac addresses, check clear mac address table, don't clear this statically created FDB entry and client authentication should not be disturbed.
9. Verify traffic gets forwarded for all the authenticated Clients on the port
10. Clear the clients using command 'sonic-clear authentication sessions interface all'
12. verify all clients gets deleted on the device and their access is blocked
| + + +### 3.2.5 Verify in multi-auth mode, one of the clients logoff does not impact other authenticated clients. + +| **Test ID** | **PAC_FUNC_005** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify in multi-auth mode, one of the clients logoff does not impact other authenticated clientss.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on port in multi-auth mode
2. Verify multiple Clients gets authenticated individually
3. Logoff first client and verify other clients are still in authenticated state
4. Verify only Client1 blocked access and other clients are allowed access to server and traffic gets forwarded
5. Try authenticate client1 again and check authentication is successful and existing clients authentication should not be disturbed.
6. Clear the one of the clients using command 'sonic-clear authentication sessions mac ' and check only its authentication is cleared and remaining are not disturbed.
| + + +### 3.2.6 Verify in multi-host mode, if primary host gets logged-off, other hosts are blocked and verify after authenticating again. + +| **Test ID** | **PAC_FUNC_006** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify in multi-host mode, if primary host gets logged-off,other hosts are blocked and verify after authenticating again.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on port in multi-host method
2. Verify First Client gets authenticated and all subsequent clients are allowed access to server
3. Logoff the primary Client1 and verify all Clients blocked access
4. Try authenticating Client2 as first user and verify all Clients are allowed access | + + +### 3.2.7 Verify 802.1x client authentication with port-control mode as force-authorized. + +| **Test ID** | **PAC_FUNC_007** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 802.1x client authentication with port-control mode as force-authorized.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1.Enable 802.1x globally and at interface level
2. Configure RADIUS Server on the authenticator.
3. Change the port control mode of the interface to force-authorized. Verify the same using “show authentication interface
4. Verify the client is not required to authenticate and is set to "force-authorized"
5. Try accessing the server from 802.1x client. Client should be able to access the server
| + + +### 3.2.8 Verify 802.1x client authentication with port-control mode as force-unauthorized. + +| **Test ID** | **PAC_FUNC_008** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 802.1x client authentication with port-control mode as force-unauthorized.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x globally and at interface level
2. Configure RADIUS Server on the authenticator.
3. Change the port control mode of the interface to force-unauthorized. Verify the same using “show authentication interface
4. Try accessing the server from 802.1x client. Client should not be able to access the server. Also verify that there is no EAPoL packets exchange between DUT and client
| + + +### 3.2.9 Verify interface level 802.1x pae authenticator disable/enable. + +| **Test ID** | **PAC_FUNC_009** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify interface level 802.1x pae authenticator disable/enable.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable authentication ('config dot1x pae interface authenticator ') on interfaces .
2. Enable 802.1x single-host on one port and multi-host on another port
3. Initiate Authentication from 802.1x Supplicant and Verify 802.1x aware clients gets authorized on the ports
4. Verify client gets access to server
5. Disable authentication ('config dot1x pae interface none ') at interface level with 802.1x clients authenticated
6. Verify 802.1x configurations are still present under interface
7. Re-enable authentication and verify all 802.1x clients gets authenticated and gets access to server
| + + +### 3.2.10 Verify global 802.1x system-auth-control enable/disable. + +| **Test ID** | **PAC_FUNC_010** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify global 802.1x authentication enable/disable.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication ('config dot1x system-auth-control enable') at global level.
2. Enable 802.1x authentication with single-host on one port and multi-host on another port
3. Initiate Authentication from 802.1x Supplicant and Verify 802.1x aware clients gets authorized on all the ports
4. Verify client gets access to server
5. Disable 802.1x authentication ('config dot1x system-auth-control disable') at global level with 802.1x clients authenticated
6. Verify 802.1x configurations still present under interface and ports move to unauthorized state
7. Verify authenticated 802.1x clients cleared on the authenticator
8. Re-enable global 802.1x authentication and verify all 802.1x clients gets authenticated
| + + +### 3.2.11 Verify enabling re-authentication with different re-authenticate timer and disabling authentication periodic shouldn't allow re-authentication. + +| **Test ID** | **PAC_FUNC_011** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify enabling re-authentication with different re-authenticate timer and disabling authentication periodic shouldn't allow re-authentication.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x globally and at interface level
2. Configure RADIUS sever on the authenticator.
3. Verify Clients connected to NAS port gets authenticated
4. Verify by default no re-authentication happens for any of the authenticated clients
5. Enable "config authentication periodic interface enable " on the port(authentication time is server on the port by default, session termination action is set to default).
6. Verify client initiates re-authentication after Session-Timeout value, the client authentication is failed because the session termination action is set to default on client.
7. Configure re-authentication timer using "config authentication timer re-authenticate interface " on DUT between 1 to 65535 in seconds and verify client gets re-authenticated as per configured re-auth timer expires on that specific port
8. Modify the RADIUS server configuration such that the client authentication failed.
9. Verify clients gets deleted in re-authentication process after re-auth timer expires.
10. Remove re-authentication timer configuration on a port and verify client initiates re-authentication as authentication periodic enabled on the port after server supplied timeout value, the client authentication is failed because the session termination action is set to default on client.
11. Disable authentication periodic on one port and verify authenticator do not attempt any re-authentication only for that specific port
| + + +### 3.2.12 Verify client authentication with MAB auth-type as EAP-MD5. + +| **Test ID** | **PAC_FUNC_012** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify client authentication with MAB auth-type as EAP-MD5.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable authentication on interface.
2. Configure RADIUS server on the authenticator.
3. Enable MAB with auth-type as EAP-MD5 and single-host mode on interface
4. Initiate Authentication from 802.1x Supplicant or Send data packets from client, Verify Authenticator (DUT) sends Access-Request to RADIUS server with username and password as Mac address learnt on the port
5. Verify DUT moves client to authenticated state once RADIUS server responds with Access-accept
6. Verify "show authentication clients all" to see the client state
7. Verify MAC FDB entry gets populated with client mac address, check clear mac address table don't clear this mac entry and client authentication is not disturbed.
8. Verify traffic gets forwarded after client gets authenticated on the port
9. Verify Client2 is blocked from accessing the server in single-Host mode
10. Logoff client1 and verify FDB entry gets deleted and client1 gets blocked for all the traffic
| + + +### 3.2.13 Verify client authentication with MAB auth-type as PAP. + +| **Test ID** | **PAC_FUNC_013** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify client authentication with MAB auth-type as PAP.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable authentication on interface.
2. Configure RADIUS server on the authenticator.
3. Enable MAB with auth-type as PAP and multi-host mode on interface
4. Initiate Authentication from 802.1x Supplicant or Send data packets from client, Verify Authenticator (DUT) sends Access-Request to RADIUS server with username and password as Mac address learnt on the port
5. Verify DUT moves client to Authenticated state once RADIUS server responds with Access-accept
6. Verify "show authentication clients all" to see the client state
7. Verify other clients connected to same port gets access to server
8. Verify MAC FDB entry gets populated with all the mac addresses
9. Verify traffic gets forwarded after client gets authenticated on the port
10. Logoff client1 and verify FDB entry gets deleted for the client on the port and access blocked for all the hosts
| + + +### 3.2.14 Verify client authentication with MAB auth-type as CHAP. + +| **Test ID** | **PAC_FUNC_014** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify client authentication with MAB auth-type as CHAP.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable authentication on interface.
2. Configure RADIUS server on the authenticator.
3. Enable MAB with auth-type as CHAP and multi-auth mode on interface
4. Initiate Authentication from multiple 802.1x Supplicant or Send data packets from multiple clients connected to the same NAS port
5. Verify Authenticator (DUT) sends Access-request to RADIUS server with mac address as username and password
6. Verify DUT moves client to Authenticated state after authenticator receives Access-accept from RADIUS server
7. Verify "show authentication clients all" to see the clients authentication state
8. Verify MAC FDB entry gets populated with client mac addresses
9. Verify traffic gets forwarded for all the authenticated Clients on the port
10. Verify unauthenticated new Host on the port not granted access
11. Logoff all the clients and verify Clients move to Unauthenticated state and access blocked
| + + +### 3.2.15 Verify authentication order with user-configured priorities for different authentication methods. + +| **Test ID** | **PAC_FUNC_015** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify authentication order with user-configured priorities for different authentication methods.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable both 802.1x and MAB authentication on an interface
2. Configure-authentication priority as [dot1x, mab]
3. Send data packets from client and Verify client authenticated as a MAB client as per the authentication order
4. Try authenticate the same client using 802.1x and verify authentication is successful with 802.1x(has higher priority on the interface)
| + + +### 3.2.16 Verify non-default max-users per port and check remaining clients are denied + +| **Test ID** | **PAC_FUNC_016** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify non-default max-users per port and check remaining clients are denied** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable PAC at interface
2. Configure max-users as 10 on the interface
3. Verify only 10 hosts are authenticated in multi-auth mode and proper log message generated indicating max-users reached.
4. Verify 11th host will not be authenticated
5. Logoff one of the clients and try to authenticate that new 11th client now, check that it is authenticated successfully.
6. Delete max-user config and verify it resets to default 16 and all 16 clients got authenticated
| + + +### 3.2.17 Verify that when host mode changes, the authenticated clients gets removed and traffic is blocked. + +| **Test ID** | **PAC_FUNC_017** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify that when host mode changes, the authenticated clients gets removed and traffic is blocked.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication on port in multi-auth mode
2. Verify multiple Clients gets authenticated individually
3. Verify that traffic corresponding to those clients gets forwarded.
4. While clients are authenticated and traffic is forwarding, change the mode to multi-host mode on the interface.
5. Verify that change of mode config is successful, authenticated clients gets removed and traffic is blocked from the client on the interface
6. Now with port in multi-host mode, authenticate a single client and check traffic forwarding corresponding to this client and other clients also is successful.
7. While traffic is forwarding, change the mode to single-host mode and check config is successful and earlier client authentication gets removed and traffic is blocked.
8. With port in single-host mode, authenticate a client and check traffic forwarding is successful.
9. While traffic is forwarding, change the mode to multi-auth and check earlier client authentication is removed and traffic is blocked.
10. With port in multi-auth mode, authenticate multiple clients and check the corresponding clients traffic forwarding is successful.
| + + +### 3.2.18 Verify that when authentication order is set to 802.1x and host mode is set to multi-auth, then only 802.1x client allowed to authenticate. + +| **Test ID** | **PAC_FUNC_018** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify that when authentication order is set to 802.1x and host mode is set to multi-auth, then only 802.1x client allowed to authenticate.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x globally and on interface.
2. Configure 'config authentication order interface dot1x ' with mode as multi-auth and also enable MAB.
3. Initiate a 802.1x client and check authentication is successful.
4. Try initiate traffic for MAB client, and check it is rejected and MAB client should not get authenticated.
5. Try authenticating another 802.1x client, and check authentication is successful.
6. Verify that traffic from these 802.1x clients is forwarded.
| + + +### 3.2.19 Verify that when authentication order is set to MAB and host mode is set to multi-auth, then 802.1x client authentication is not successful. + +| **Test ID** | **PAC_FUNC_019** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify that when authentication order is set to MAB and host mode is set to multi-auth, then 802.1x client authentication is not successful.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x globally and on interface.
2. Configure 'config authentication order interface MAB ' with mode as multi-auth and also enable MAB.
3. Initiate a 802.1x client and check authentication is not successful as 802.1x method is not enabled.
4. Try initiate traffic for MAB client, and check its authentication is successful.
5. Try authenticating another MAB client, and check authentication is successful.
6. Verify that traffic from these MAB clients is forwarded.
| + + +### 3.2.20 Verify MAB client authentication with port-control mode toggle between force authorized/unauthorized and auto. + +| **Test ID** | **PAC_FUNC_020** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify MAB client authentication with port-control mode toggle between force -authorized/unauthorized and auto.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x globally and at interface level, enable MAB on the interface
2. Configure the port control mode to force-authorized and verify port is set to force-authorized and client gets access to server without any authentication
3. Change the port control mode to "auto" and verify Client requires authentication before granting server access
4. Change the port control mode to force-unauthorized and verify no clients on the port gets authenticated
5. Change it to "auto" and verify Client gets authenticated and then granted access to server
| + + +### 3.2.21 Verify that 802.1x and MAB client is not authenticated if it's RADIUS assigned VLAN is not available statically on the authenticator switch. + +| **Test ID** | **PAC_FUNC_021** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify that 802.1x and MAB client is not authenticated if it's RADIUS assigned VLAN is not available statically on the authenticator switch.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system auth control globally and enable pae authenticator on interface.
2. Configure host mode as multi-auth, enable 802.1x and MAB on the interface.
3. Configure RADIUS server as VLAN attribute to non-existing VLAN ID in NAS.
4. Authenticate 802.1x and MAB clients and check authentication is not successful.
5. Create RADIUS assigned VLAN on NAS.
6. Try to authenticate same 802.1x and MAB client and verify authentication is successful.
| + + +### 3.2.22 Verify 802.1x and MAB client is not authenticated if RADIUS does not assign a VLAN and the port is configured with tagged VLAN. + +| **Test ID** | **PAC_FUNC_022** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 802.1x and MAB client is not authenticated if RADIUS does not assign a VLAN and the port is configured with tagged VLAN.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system-auth-control globally and enable pae authenticator on interface.
2. Configure host mode as multi-host, enable 802.1x and MAB on the interface.
3. Configure RADIUS server as VLAN attribute to existing VLAN ID in NAS.
4. Add switchport trunk VLAN configuration on 802.1x and MAB enabled interfaces.
5. Authenticate 802.1x and MAB clients and check authentication is not successful.
6. Change the port participation from truck to access mode on the 802.1x and MAB enabled interfaces.
7. Try to authenticate same 802.1x and MAB client and verify authentication is successful.
| + + +### 3.2.23 Verify a port with Multi-auth mode can have authenticated clients in different radius assigned VLANs. + +| **Test ID** | **PAC_FUNC_023** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify a port with Multi-auth mode can have authenticated clients in different radius assigned VLANs.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system auth control globally and enable pae authenticator on interface.
2. Configure host mode as multi-auth, enable 802.1x and MAB on the interface.
3. Configure multiple users with different VLANs in RADIUS server.
4. Try to authenticate client1 and verify client authentication is successful, port added in RADIUS assigned VLAN.
5. Try to Authenticate client2 with different RADIUS assigned VLAN and verify authentication is not successful.
6. Change the VLAN attribute to Client2 as Client1 in RADIUS server.
7. Try to authenticate Client2 again and verify authentication is successful.
| + + +### 3.2.24 Verify that 802.1x and MAB client is not authenticated if RADIUS does not assign a VLAN and the port's configured untagged VLAN (Access VLAN) is not available + +| **Test ID** | **PAC_FUNC_024** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify that 802.1x and MAB client is not authenticated if it's RADIUS assigned VLAN is not available statically on the authenticator switch.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system auth control globally and enable pae authenticator on interface.
2. Configure host mode as multi-host, enable 802.1x and MAB on the interface.
3. Configure users to without VLAN attribute in RADIUS server.
4. Add switchport access VLAN configuration on 802.1x and MAB enabled interfaces, do not create configured VLAN on the the switch
5. Authenticate 802.1x and MAB clients and check authentication is not successful.
6. Create RADIUS assigned VLAN on NAS.
7. Try to authenticate same 802.1x and MAB client and verify authentication is successful.
| + + +### 3.2.25 Verify the same MAB client authentication on different port after authenticated and verify MAC movement of the client +| **Test ID** | **PAC_FUNC_025** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify the same MAB client authentication on different port after authenticated and verify MAC movement of the client.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system auth control globally and enable pae authenticator on interface.
2. Configure host mode as multi-host, enable MAB on the two interface port-1 and port-2.
3. Authenticate MAB client on port-1 and check authentication is successful.
4. Verify the FDB entry is installed properly on port-1.
5. Try to authenticate same MAB client on port-2 and verify authentication is successful on port-2.
6. Verify MAC is moved from port-1 to port-2 properly and verify traffic is forwarded to uplink port.
7. Now again, try to authenticate same MAB client on port-1 and verify authentication is successful on port-1.
6. Verify MAC is moved from port-2 to port-1 properly and verify traffic is forwarded to uplink port.
| + + +### 3.2.26 Verify the same 802.1x client authentication on different port after authenticated and verify MAC movement of the client +| **Test ID** | **PAC_FUNC_026** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify the same 802.1x client authentication on different port after authenticated and verify MAC movement of the client.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system auth control globally and enable pae authenticator on interface.
2. Configure host mode as multi-host, enable 802.1x on the two interface port-1 and port-2.
3. Authenticate 802.1x client on port-1 and check authentication is successful.
4. Verify the FDB entry is installed properly on port-1.
5. Try to authenticate same 802.1x client on port-2 and verify authentication is successful on port-2.
6. Verify MAC is moved from port-1 to port-2 properly and verify traffic is forwarded to uplink port.
7. Now again, try to authenticate same 802.1x client on port-1 and verify authentication is successful on port-1.
6. Verify MAC is moved from port-2 to port-1 properly and verify traffic is forwarded to uplink port.
| + +### 3.2.27 Verify the same 802.1x and MAB client authentication when PAC and ACLs applied on a same port +| **Test ID** | **PAC_FUNC_027** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify the same 802.1x and MAB client authentication when PAC and ACLs applied on a same port.** | +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x system auth control globally and enable pae authenticator on interface.
2. Configure host mode as multi-host, enable 802.1x on the two interface port-1 and port-2.
3. Create static ACL and applied on PAC enabled port and verify the ACLs applied properly.
4. The traffic is dropped to uplink port before clients authentication.
5. Authenticate 802.1x client on port-1 and check authentication is successful.
6. Send the traffic matching to configured ACL rules and verify the traffic is forwarded properly.
7. Delete assign the ACLs on the port and verify the authenticated clients won't be impacted.
8. Logoff the clients and verify clients removed on the port without any issue.
.9. Verify applied ACLs on a port is retained and traffic forwarding to uplink port as per rules.
| + + +### **3.3 Reboot and Trigger Test Cases** + +### 3.3.1 Verify Client authentication after reboot + +| **Test ID** | **PAC_FUNC_TRIGGER_001** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify Client authentication after reboot**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Define RADIUS server
2. Enable 802.1x/MAB globally and at interface level
3. Authenticate to the DUT with multiple 802.1x clients and MAB clients
4. Do config save and "reboot"
5. 802.1x/MAB clients are removed and authenticated again.
6. Initiate 802.1x and MAB clients and verify that 802.1x/MAB clients authentication is successful after reboot.
| + + +### 3.3.2 Verify Client authentication after warmboot + +| **Test ID** | **PAC_FUNC_TRIGGER_002** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify Client authentication after warmboot**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Define RADIUS server
2. Enable 802.1x/MAB globally and at interface level
3. Authenticate to the DUT with multiple 802.1x clients and MAB clients
4. Do config save and warmboot
5. 802.1x/MAB clients are removed and authenticated again.
6. Initiate 802.1x and MAB clients and verify that 802.1x/MAB clients authentication is successful after warm-reboot.
| + + +### 3.3.3 Verify Client authentication after config reload + +| **Test ID** | **PAC_FUNC_TRIGGER_003** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify Client authentication after config reload**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Define RADIUS server
2. Enable 802.1x/MAB globally and at interface level
3. Authenticate to the DUT with multiple 802.1x clients and MAB clients
4. Do config save and perform config-reload
5. 802.1x/MAB clients are removed and authenticated again.
6. Initiate 802.1x and MAB clients and verify that 802.1x/MAB clients authentication is successful after config-reload.
| + + +### 3.3.4 Verify Client authentication after port toggle + +| **Test ID** | **PAC_FUNC_TRIGGER_004** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify Client authentication after port toggle**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Define RADIUS server
2. Enable 802.1x/MAB globally and at interface level
3. Authenticate to the DUT with multiple 802.1x clients and MAB clients
4. Perform shutdown and no shutdown on client authenticated port.
5. 802.1x/MAB clients are removed and authenticated again.
6. Initiate 802.1x and MAB clients and verify that 802.1x/MAB clients authentication is successful after port flap.
| + + +### **3.4 Scale Test Cases** + +### 3.4.1 Verify 128 max supported 802.1x clients on DUT. + +| **Test ID** | **PAC_SCAL_001** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 128 max supported 802.1x clients on DUT.**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication globally and at interface level on multiple ports
2. Configure host mode as multi-auth on multiple ports on the DUT.
3. Try authentication 128 802.1x clients across multiple interfaces(at least 16 clients from one or two interfaces to cover max clients per port) and verify 128 802.1x authenticated clients
4. Verify FDB entries for all 128 clients
5. Verify all client traffic gets allowed after authentication
6. Logoff all the 128 clients and verify clients move to unauthorized state and gets blocked from accessing the server.
7. Reinitiate the clients and check all are authenticated successfully.
8. Log off the clients again and check all are cleared.
| + + +### 3.4.2 Verify 128 max supported MAB clients on DUT. + +| **Test ID** | **PAC_SCAL_002** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify 128 max supported MAB clients on DUT.**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication globally and at interface level on multiple ports
2. Configure host mode as multi-auth on multiple ports on the DUT.
3.Try authentication 128 MAB clients across multiple interfaces and verify 128 MAB authenticated clients
4. Verify FDB entries for all 128 clients
5. Verify all client traffic gets allowed after authentication
6. Logoff all the 128 clients and verify clients move to unauthorized state and gets blocked from accessing the server
7. Reinitiate the clients and check all are authenticated successfully.
8. With max clients authenticated, perform save and reload.
9. Check that after DUT comes up, all clients are authenticated successfully.
| + + +### 3.4.3 Verify that the 128 maximum supported clients on DUT can be authenticated by using both 802.1x and MAB clients. + +| **Test ID** | **PAC_SCAL_003** | +| -------------- | :--------------------------------------- | +| **Test Name** | **Verify that the 128 maximum supported clients on DUT can be authenticated by using both 802.1x and MAB clients.**| +| **Test Setup** | **Topology1** | +| **Type** | **Functional** | +| **Steps** | 1. Enable 802.1x authentication globally and at interface level on multiple ports
2. Configure host mode as multi-auth and MAB on multiple ports on the DUT.
3. Try to validate the authentication of a combination of 802.1x and MAB clients across different interfaces, accommodating a scale of up to 128 clients and verify that all 802.1x and MAB clients authenticated properly on different ports.
4. Verify FDB entries for all 128 clients installed properly.
5. Verify all client traffic gets allowed after authentication.
6. Logoff all the 128 clients and verify clients move to unauthorized state and gets blocked from accessing the server
7. Reinitiate the clients and check all are authenticated successfully.
| + +## **4 Sample Outputs** + +### 4.1 Sample configuration commands +``` +config authentication port-control interface +config dot1x pae interface +config authentication host-mode interface +config dot1x system-auth-control +config authentication max-users interface +config mab interface \[ auth-type \] +config authentication periodic interface +config authentication timer reauthenticate interface +config authentication order interface +config authentication priority interface +``` + + +### 4.2 Sample clear commands +``` +sonic-clear authentication sessions \>\> | \> +``` + + +### 4.3 Sample show outputs +``` +admin@sonic:~$ show authentication clients all + +--------------------------------------------------------------------------------------------------------------------------------------------- +Interface User Name MAC-Address Method Host Mode Control Mode VLAN Assigned Reason +--------------------------------------------------------------------------------------------------------------------------------------------- +Ethernet0 Userv11 00:00:00:41:22:33 802.1x single-host auto Radius (20) +Ethernet1 Userv21 00:00:00:42:22:33 802.1x multi-host auto Radius (30) + + +admin@sonic:~$ show authentication clients Ethernet1 + +Mac Address ........................................ 00:00:00:42:22:33 +User Name .......................................... Userv21 +VLAN Assigned Reason ............................... Radius (30) +Host Mode .......................................... multi-host +Method ............................................. 802.1x +Session time ....................................... 147 +Session timeout .................................... 60 +Time left for Session Termination Action ........... Not Applicable +Session Termination Action ......................... Default + + +admin@sonic:~$ show authentication interface Ethernet0 + +Interface ..................................... Eth1/46 +Port Control Mode.............................. auto +Host Mode...................................... single-host +Configured method order........................ dot1x mab +Enabled method order........................... dot1x mab +Configured method priority..................... dot1x mab +Enabled method priority........................ dot1x mab +Reauthentication Enabled....................... TRUE +Reauthentication Period (secs)................. 90 +Maximum Users.................................. 1 +PAE role ...................................... Authenticator + + +admin@sonic:~$ show mab interface Ethernet0 + +Interface ..................................... Ethernet0 +Admin mode ..................................... Enabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + + +admin@sonic:~$ show mab + +Interface ..................................... Ethernet0 +Admin mode ..................................... Disabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + +Interface ..................................... Ethernet1 +Admin mode ..................................... Enabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + +Interface ..................................... Ethernet2 +Admin mode ..................................... Disabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + +Interface ..................................... Ethernet3 +Admin mode ..................................... Enabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + +Interface ..................................... Ethernet4 +Admin mode ..................................... Disabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + +Interface ..................................... Ethernet5 +Admin mode ..................................... Enabled +mab_auth_type .................................. EAP_MD5 +Server Timeout(secs) ........................... 30 + + +admin@sonic:~$ show dot1x detail Ethernet0 + +Interface ..................................... Ethernet0 +PAE Capabilities .............................. authenticator +Server Timeout(secs) .......................... 30 +Quiet Period(secs)............................. 30 + + +admin@sonic:~$ show dot1x detail all + +Interface ..................................... Ethernet0 +PAE Capabilities .............................. none +Server Timeout(secs) .......................... 30 +Quiet Period(secs)............................. 30 + +Interface ..................................... Ethernet1 +PAE Capabilities .............................. none +Server Timeout(secs) .......................... 30 +Quiet Period(secs)............................. 30 + +Interface ..................................... Ethernet2 +PAE Capabilities .............................. none +Server Timeout(secs) .......................... 30 +Quiet Period(secs)............................. 30 + +Interface ..................................... Ethernet3 +PAE Capabilities .............................. none +Server Timeout(secs) .......................... 30 +Quiet Period(secs)............................. 30 + +Interface ..................................... Ethernet4 +PAE Capabilities .............................. none +Server Timeout(secs) .......................... 30 +``` + +## **Reference Links** + +https://github.com/sonic-net/SONiC/pull/1315 diff --git a/tests/acl/templates/acltb_test_rules.j2 b/tests/acl/templates/acltb_test_rules.j2 index 0119fc83bb..ee9bd39874 100644 --- a/tests/acl/templates/acltb_test_rules.j2 +++ b/tests/acl/templates/acltb_test_rules.j2 @@ -510,7 +510,41 @@ "destination-ip-address": "192.168.0.122/32" } } +{% if dualtor == True -%} + }, + "34": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 34 + }, + "ip": { + "config": { + "destination-ip-address": "{{Loopback2}}/32" + } + } + }, + "35": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 35 + }, + "ip": { + "config": { + "destination-ip-address": "{{Loopback3}}/32" + } + } + } +{%- else -%} } +{%- endif %} } } } diff --git a/tests/acl/templates/acltb_test_rules_part_1.j2 b/tests/acl/templates/acltb_test_rules_part_1.j2 index 4583a14977..4946866fbe 100644 --- a/tests/acl/templates/acltb_test_rules_part_1.j2 +++ b/tests/acl/templates/acltb_test_rules_part_1.j2 @@ -125,7 +125,41 @@ "destination-port": "179" } } +{% if dualtor == True -%} + }, + "29": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 29 + }, + "ip": { + "config": { + "destination-ip-address": "{{Loopback2}}/32" + } + } + }, + "30": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 30 + }, + "ip": { + "config": { + "destination-ip-address": "{{Loopback3}}/32" + } + } + } +{%- else -%} } +{%- endif %} } } } diff --git a/tests/acl/templates/acltb_test_rules_part_2.j2 b/tests/acl/templates/acltb_test_rules_part_2.j2 index 0119fc83bb..ee9bd39874 100644 --- a/tests/acl/templates/acltb_test_rules_part_2.j2 +++ b/tests/acl/templates/acltb_test_rules_part_2.j2 @@ -510,7 +510,41 @@ "destination-ip-address": "192.168.0.122/32" } } +{% if dualtor == True -%} + }, + "34": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 34 + }, + "ip": { + "config": { + "destination-ip-address": "{{Loopback2}}/32" + } + } + }, + "35": { + "actions": { + "config": { + "forwarding-action": "ACCEPT" + } + }, + "config": { + "sequence-id": 35 + }, + "ip": { + "config": { + "destination-ip-address": "{{Loopback3}}/32" + } + } + } +{%- else -%} } +{%- endif %} } } } diff --git a/tests/acl/test_acl.py b/tests/acl/test_acl.py index 3d4b5928b2..5920d69bc3 100644 --- a/tests/acl/test_acl.py +++ b/tests/acl/test_acl.py @@ -25,6 +25,7 @@ from tests.common.fixtures.conn_graph_facts import conn_graph_facts # noqa F401 from tests.common.platform.processes_utils import wait_critical_processes from tests.common.platform.interface_utils import check_all_interface_information +from tests.common.utilities import is_ipv4_address logger = logging.getLogger(__name__) @@ -604,7 +605,7 @@ class BaseAclTest(six.with_metaclass(ABCMeta, object)): ACL_COUNTERS_UPDATE_INTERVAL_SECS = 10 @abstractmethod - def setup_rules(self, dut, acl_table, ip_version): + def setup_rules(self, dut, acl_table, ip_version, tbinfo): """Setup ACL rules for testing. Args: @@ -669,7 +670,7 @@ def acl_rules(self, duthosts, localhost, setup, acl_table, populate_vlan_arp_ent # Ignore any other errors to reduce noise loganalyzer.ignore_regex = [r".*"] with loganalyzer: - self.setup_rules(duthost, acl_table, ip_version) + self.setup_rules(duthost, acl_table, ip_version, tbinfo) # Give the dut some time for the ACL rules to be applied and LOG message generated time.sleep(30) @@ -1168,7 +1169,7 @@ def _verify_acl_traffic(self, setup, direction, ptfadapter, pkt, dropped, ip_ver class TestBasicAcl(BaseAclTest): """Test Basic functionality of ACL rules (i.e. setup with full update on a running device).""" - def setup_rules(self, dut, acl_table, ip_version): + def setup_rules(self, dut, acl_table, ip_version, tbinfo): """Setup ACL rules for testing. Args: @@ -1176,6 +1177,23 @@ def setup_rules(self, dut, acl_table, ip_version): acl_table: Configuration info for the ACL table. """ + + if 'dualtor' in tbinfo['topo']['name']: + dut.host.options["variable_manager"].extra_vars.update({"dualtor": True}) + sonichost = dut.get_asic_or_sonic_host(None) + config_facts = sonichost.get_running_config_facts() + tor_ipv4_address = [_ for _ in config_facts["LOOPBACK_INTERFACE"]["Loopback2"] + if is_ipv4_address(_.split("/")[0])][0] + tor_ipv4_address = tor_ipv4_address.split("/")[0] + dut.host.options["variable_manager"].extra_vars.update({"Loopback2": tor_ipv4_address}) + + tor_ipv4_address = [_ for _ in config_facts["LOOPBACK_INTERFACE"]["Loopback3"] + if is_ipv4_address(_.split("/")[0])][0] + tor_ipv4_address = tor_ipv4_address.split("/")[0] + dut.host.options["variable_manager"].extra_vars.update({"Loopback3": tor_ipv4_address}) + else: + dut.host.options["variable_manager"].extra_vars.update({"dualtor": False}) + table_name = acl_table["table_name"] dut.host.options["variable_manager"].extra_vars.update({"acl_table_name": table_name}) @@ -1196,7 +1214,7 @@ class TestIncrementalAcl(BaseAclTest): multiple parts. """ - def setup_rules(self, dut, acl_table, ip_version): + def setup_rules(self, dut, acl_table, ip_version, tbinfo): """Setup ACL rules for testing. Args: @@ -1204,6 +1222,21 @@ def setup_rules(self, dut, acl_table, ip_version): acl_table: Configuration info for the ACL table. """ + if 'dualtor' in tbinfo['topo']['name']: + dut.host.options["variable_manager"].extra_vars.update({"dualtor": True}) + sonichost = dut.get_asic_or_sonic_host(None) + config_facts = sonichost.get_running_config_facts() + tor_ipv4_address = [_ for _ in config_facts["LOOPBACK_INTERFACE"]["Loopback2"] + if is_ipv4_address(_.split("/")[0])][0] + tor_ipv4_address = tor_ipv4_address.split("/")[0] + dut.host.options["variable_manager"].extra_vars.update({"Loopback2": tor_ipv4_address}) + tor_ipv4_address = [_ for _ in config_facts["LOOPBACK_INTERFACE"]["Loopback3"] + if is_ipv4_address(_.split("/")[0])][0] + tor_ipv4_address = tor_ipv4_address.split("/")[0] + dut.host.options["variable_manager"].extra_vars.update({"Loopback3": tor_ipv4_address}) + else: + dut.host.options["variable_manager"].extra_vars.update({"dualtor": False}) + table_name = acl_table["table_name"] dut.host.options["variable_manager"].extra_vars.update({"acl_table_name": table_name}) diff --git a/tests/arp/conftest.py b/tests/arp/conftest.py index 3eb30ecf3c..be8354a596 100644 --- a/tests/arp/conftest.py +++ b/tests/arp/conftest.py @@ -311,6 +311,9 @@ def proxy_arp_enabled(rand_selected_dut, config_facts): proxy_arp_del_cmd = 'sonic-db-cli CONFIG_DB HDEL "VLAN_INTERFACE|Vlan{}" proxy_arp' for vid, proxy_arp_val in list(old_proxy_arp_vals.items()): if 'enabled' not in proxy_arp_val: + # Disable proxy_arp explicitly + duthost.shell(proxy_arp_config_cmd.format(vid, 'disabled')) + time.sleep(2) # Delete the DB entry instead of using the config command to satisfy check_dut_health_status duthost.shell(proxy_arp_del_cmd.format(vid)) diff --git a/tests/common/config_reload.py b/tests/common/config_reload.py index 4f2159b897..89a131ba1e 100644 --- a/tests/common/config_reload.py +++ b/tests/common/config_reload.py @@ -127,9 +127,13 @@ def _config_reload_cmd_wrapper(cmd, executable): sonic_host.shell(cmd, executable="/bin/bash") elif config_source == 'running_golden_config': - cmd = 'config reload -y -l /etc/sonic/running_golden_config.json &>/dev/null' + golden_path = '/etc/sonic/running_golden_config.json' + if sonic_host.is_multi_asic: + for asic in sonic_host.asics: + golden_path = f'{golden_path},/etc/sonic/running_golden_config{asic.asic_index}.json' + cmd = f'config reload -y -l {golden_path} &>/dev/null' if config_force_option_supported(sonic_host): - cmd = 'config reload -y -f -l /etc/sonic/running_golden_config.json &>/dev/null' + cmd = f'config reload -y -f -l {golden_path} &>/dev/null' sonic_host.shell(cmd, executable="/bin/bash") modular_chassis = sonic_host.get_facts().get("modular_chassis") diff --git a/tests/common/devices/duthosts.py b/tests/common/devices/duthosts.py index 1fe548e5fa..8474a424c1 100644 --- a/tests/common/devices/duthosts.py +++ b/tests/common/devices/duthosts.py @@ -54,9 +54,15 @@ def __init__(self, ansible_adhoc, tbinfo, duts): DUTs in the testbed should be used """ + self.ansible_adhoc = ansible_adhoc + self.tbinfo = tbinfo + self.duts = duts + self.__initialize_nodes() + + def __initialize_nodes(self): # TODO: Initialize the nodes in parallel using multi-threads? - self.nodes = self._Nodes([MultiAsicSonicHost(ansible_adhoc, hostname, self, tbinfo['topo']['type']) - for hostname in tbinfo["duts"] if hostname in duts]) + self.nodes = self._Nodes([MultiAsicSonicHost(self.ansible_adhoc, hostname, self, self.tbinfo['topo']['type']) + for hostname in self.tbinfo["duts"] if hostname in self.duts]) self.supervisor_nodes = self._Nodes([node for node in self.nodes if node.is_supervisor_node()]) self.frontend_nodes = self._Nodes([node for node in self.nodes if node.is_frontend_node()]) @@ -125,3 +131,6 @@ def config_facts(self, *module_args, **complex_args): complex_args['host'] = node.hostname result[node.hostname] = node.config_facts(*module_args, **complex_args)['ansible_facts'] return result + + def reset(self): + self.__initialize_nodes() diff --git a/tests/common/devices/sonic.py b/tests/common/devices/sonic.py index bc8b6e8241..901b28e9f5 100644 --- a/tests/common/devices/sonic.py +++ b/tests/common/devices/sonic.py @@ -1762,6 +1762,41 @@ def get_vlan_intfs(self): return vlan_intfs + def get_vlan_brief(self): + """ + Get vlan brief + Sample output: + { + "Vlan1000": { + "interface_ipv4": [ "192.168.0.1/24" ], + "interface_ipv6": [ "fc02:1000::1/64" ], + "members": ["Ethernet0", "Ethernet1"] + }, + "Vlan2000": { + "interface_ipv4": [ "192.168.1.1/24" ], + "interface_ipv6": [ "fc02:1001::1/64" ], + "members": ["Ethernet3", "Ethernet4"] + } + } + """ + config = self.get_running_config_facts() + vlan_brief = {} + for vlan_name, members in config["VLAN_MEMBER"].items(): + vlan_brief[vlan_name] = { + "interface_ipv4": [], + "interface_ipv6": [], + "members": list(members.keys()) + } + for vlan_name, vlan_info in config["VLAN_INTERFACE"].items(): + if vlan_name not in vlan_brief: + continue + for prefix in vlan_info.keys(): + if '.' in prefix: + vlan_brief[vlan_name]["interface_ipv4"].append(prefix) + elif ':' in prefix: + vlan_brief[vlan_name]["interface_ipv6"].append(prefix) + return vlan_brief + def get_interfaces_status(self): ''' Get intnerfaces status by running 'show interfaces status' on the DUT, and parse the result into a dict. diff --git a/tests/common/fixtures/duthost_utils.py b/tests/common/fixtures/duthost_utils.py index fb4007d644..09bfbe9e2b 100644 --- a/tests/common/fixtures/duthost_utils.py +++ b/tests/common/fixtures/duthost_utils.py @@ -1,3 +1,6 @@ +from typing import Dict, List + +import paramiko import pytest import logging import itertools @@ -5,10 +8,14 @@ import ipaddress import time import json + +from paramiko.ssh_exception import AuthenticationException + +from tests.common import config_reload from tests.common.helpers.assertions import pytest_assert from tests.common.utilities import wait_until from jinja2 import Template -from netaddr import valid_ipv4 +from netaddr import valid_ipv4, valid_ipv6 logger = logging.getLogger(__name__) @@ -598,3 +605,147 @@ def check_bgp_router_id(duthost, mgFacts): return False except Exception as e: logger.error("Error loading BGP routerID - {}".format(e)) + + +@pytest.fixture(scope="module") +def convert_and_restore_config_db_to_ipv6_only(duthosts): + """Back up the existing config_db.json file and restore it once the test ends. + + Some cases will update the running config during the test and save the config + to be recovered after reboot. In such a case we need to backup config_db.json before + the test starts and then restore it after the test ends. + """ + config_db_file = "/etc/sonic/config_db.json" + config_db_bak_file = "/etc/sonic/config_db.json.before_ipv6_only" + + # Sample MGMT_INTERFACE: + # "MGMT_INTERFACE": { + # "eth0|192.168.0.2/24": { + # "forced_mgmt_routes": [ + # "192.168.1.1/24" + # ], + # "gwaddr": "192.168.0.1" + # }, + # "eth0|fc00:1234:5678:abcd::2/64": { + # "gwaddr": "fc00:1234:5678:abcd::1", + # "forced_mgmt_routes": [ + # "fc00:1234:5678:abc1::1/64" + # ] + # } + # } + + # duthost_name: config_db_modified + config_db_modified: Dict[str, bool] = {duthost.hostname: False + for duthost in duthosts.nodes} + # duthost_name: [ip_addr] + ipv4_address: Dict[str, List] = {duthost.hostname: [] + for duthost in duthosts.nodes} + ipv6_address: Dict[str, List] = {duthost.hostname: [] + for duthost in duthosts.nodes} + # Check IPv6 mgmt-ip is set and available, otherwise the DUT will lose control after v4 mgmt-ip is removed + for duthost in duthosts.nodes: + mgmt_interface = json.loads(duthost.shell(f"jq '.MGMT_INTERFACE' {config_db_file}", + module_ignore_errors=True)["stdout"]) + # Use list() to make a copy of mgmt_interface.keys() to avoid + # "RuntimeError: dictionary changed size during iteration" error + ssh_client = paramiko.SSHClient() + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + has_available_ipv6_addr = False + for key in list(mgmt_interface): + ip_addr = key.split("|")[1] + ip_addr_without_mask = ip_addr.split('/')[0] + if ip_addr: + is_ipv6 = valid_ipv6(ip_addr_without_mask) + if is_ipv6: + logger.info(f"Host[{duthost.hostname}] IPv6[{ip_addr}]") + ipv6_address[duthost.hostname].append(ip_addr_without_mask) + try: + ssh_client.connect(ip_addr_without_mask, + username="WRONG_USER", password="WRONG_PWD", timeout=15) + except AuthenticationException: + logger.info(f"Host[{duthost.hostname}] IPv6[{ip_addr_without_mask}] mgmt-ip is available") + has_available_ipv6_addr = has_available_ipv6_addr or True + except BaseException: + pass + finally: + ssh_client.close() + + pytest_assert(len(ipv6_address[duthost.hostname]) > 0, + f"{duthost.hostname} doesn't have IPv6 Management IP address") + pytest_assert(has_available_ipv6_addr, + f"{duthost.hostname} doesn't have available IPv6 Management IP address") + + # Remove IPv4 mgmt-ip + for duthost in duthosts.nodes: + logger.info(f"Backup {config_db_file} to {config_db_bak_file} on {duthost.hostname}") + duthost.shell(f"cp {config_db_file} {config_db_bak_file}") + mgmt_interface = json.loads(duthost.shell(f"jq '.MGMT_INTERFACE' {config_db_file}", + module_ignore_errors=True)["stdout"]) + + # Use list() to make a copy of mgmt_interface.keys() to avoid + # "RuntimeError: dictionary changed size during iteration" error + for key in list(mgmt_interface): + ip_addr = key.split("|")[1] + ip_addr_without_mask = ip_addr.split('/')[0] + if ip_addr: + is_ipv4 = valid_ipv4(ip_addr_without_mask) + if is_ipv4: + ipv4_address[duthost.hostname].append(ip_addr_without_mask) + logger.info(f"Removing host[{duthost.hostname}] IPv4[{ip_addr}]") + duthost.shell(f"""jq 'del(."MGMT_INTERFACE"."{key}")' {config_db_file} > temp.json""" + f"""&& mv temp.json {config_db_file}""", module_ignore_errors=True) + config_db_modified[duthost.hostname] = True + config_reload(duthost, wait=120) + duthosts.reset() + + # Verify mgmt-interface status + mgmt_intf_name = "eth0" + for duthost in duthosts.nodes: + logger.info(f"Checking host[{duthost.hostname}] mgmt interface[{mgmt_intf_name}]") + mgmt_intf_ifconfig = duthost.shell(f"ifconfig {mgmt_intf_name}", module_ignore_errors=True)["stdout"] + assert_addr_in_ifconfig(addr_set=ipv4_address, hostname=duthost.hostname, + expect_exists=False, ifconfig_output=mgmt_intf_ifconfig) + assert_addr_in_ifconfig(addr_set=ipv6_address, hostname=duthost.hostname, + expect_exists=True, ifconfig_output=mgmt_intf_ifconfig) + + yield + + # Recover IPv4 mgmt-ip + for duthost in duthosts.nodes: + if config_db_modified[duthost.hostname]: + logger.info(f"Restore {config_db_file} with {config_db_bak_file} on {duthost.hostname}") + duthost.shell(f"mv {config_db_bak_file} {config_db_file}") + config_reload(duthost, safe_reload=True) + duthosts.reset() + + # Verify mgmt-interface status + for duthost in duthosts.nodes: + logger.info(f"Checking host[{duthost.hostname}] mgmt interface[{mgmt_intf_name}]") + mgmt_intf_ifconfig = duthost.shell(f"ifconfig {mgmt_intf_name}", module_ignore_errors=True)["stdout"] + assert_addr_in_ifconfig(addr_set=ipv4_address, hostname=duthost.hostname, + expect_exists=True, ifconfig_output=mgmt_intf_ifconfig) + assert_addr_in_ifconfig(addr_set=ipv6_address, hostname=duthost.hostname, + expect_exists=True, ifconfig_output=mgmt_intf_ifconfig) + + +def assert_addr_in_ifconfig(addr_set: Dict[str, List], hostname: str, expect_exists: bool, ifconfig_output: str): + """ + Assert the address status in the ifconfig output, + if status not as expected, assert as failure + + @param addr_set: addr_set, key is dut hostname, value is the list of ip addresses + @param hostname: hostname + @param expect_exists: Expectation of the ip, + True means expect all ip addresses in addr_set appears in the output of ifconfig + False means expect no ip addresses in addr_set appears in the output of ifconfig + @param ifconfig_output: output of 'ifconfig' + """ + for addr in addr_set[hostname]: + if expect_exists: + pytest_assert(addr in ifconfig_output, + f"{addr} not appeared in {hostname} mgmt interface") + logger.info(f"{addr} exists in the output of ifconfig") + else: + pytest_assert(addr not in ifconfig_output, + f"{hostname} mgmt interface still with addr {addr}") + logger.info(f"{addr} not exists in the output of ifconfig which is expected") diff --git a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml index 11f1d88023..48d209bb2b 100644 --- a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml +++ b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml @@ -616,9 +616,11 @@ generic_config_updater: generic_config_updater/test_dhcp_relay.py: skip: - reason: "Need to skip for platform x86_64-8111_32eh_o-r0" + reason: "Need to skip for platform x86_64-8111_32eh_o-r0 or backend topology" + conditions_logical_operator: "OR" conditions: - "platform in ['x86_64-8111_32eh_o-r0']" + - "'backend' in topo_name" generic_config_updater/test_ecn_config_update.py::test_ecn_config_updates: skip: @@ -757,6 +759,12 @@ ip/test_ip_packet.py::TestIPPacket::test_forward_ip_packet_with_0xffff_chksum_to conditions: - "asic_type in ['mellanox'] or asic_subtype in ['broadcom-dnx']" +ip/test_mgmt_ipv6_only.py::test_image_download_ipv6_only: + skip: + reason: "Skipping mgmt ipv6 test for mgmt topo" + conditions: + - "topo_type in ['m0', 'mx']" + ####################################### ##### ipfwd ##### ####################################### diff --git a/tests/common/snappi_tests/common_helpers.py b/tests/common/snappi_tests/common_helpers.py index ebe1021fd6..6ca2aef4f6 100644 --- a/tests/common/snappi_tests/common_helpers.py +++ b/tests/common/snappi_tests/common_helpers.py @@ -485,8 +485,15 @@ def enable_ecn(host_ans, prio, asic_value=None): """ if asic_value is None: host_ans.shell('sudo ecnconfig -q {} on'.format(prio)) + results = host_ans.shell('ecnconfig -q {}'.format(prio)) + if re.search("queue {}: on".format(prio), results['stdout']): + return True else: host_ans.shell('sudo ip netns exec {} ecnconfig -q {} on'.format(asic_value, prio)) + results = host_ans.shell('sudo ip netns exec {} ecnconfig {}'.format(asic_value, prio)) + if re.search("queue {}: on".format(prio), results['stdout']): + return True + return False def disable_ecn(host_ans, prio, asic_value=None): diff --git a/tests/crm/conftest.py b/tests/crm/conftest.py index 3a318a30d3..0e000da208 100755 --- a/tests/crm/conftest.py +++ b/tests/crm/conftest.py @@ -217,3 +217,26 @@ def collector(duthosts, enum_rand_one_per_hwsku_frontend_hostname): data[asic.asic_index] = {} yield data + + +@pytest.fixture(scope="function") +def cleanup_ptf_interface(duthosts, ip_ver, enum_rand_one_per_hwsku_frontend_hostname, + enum_frontend_asic_index, ptfhost): + + duthost = duthosts[enum_rand_one_per_hwsku_frontend_hostname] + asichost = duthost.asic_instance(enum_frontend_asic_index) + if ip_ver == "4": + ip_remove_cmd = "config interface ip remove Ethernet1 2.2.2.1/24" + else: + ip_remove_cmd = "config interface ip remove Ethernet1 2001::2/64" + check_vlan_cmd = "show vlan br | grep -w 'Ethernet1'" + + yield + + if duthost.facts["asic_type"] == "marvell": + asichost.shell(ip_remove_cmd) + # Check if member not removed + output = asichost.shell(check_vlan_cmd, module_ignore_errors=True) + if "Ethernet1" not in output['stdout']: + asichost.sonichost.add_member_to_vlan(1000, 'Ethernet1', is_tagged=False) + ptfhost.remove_ip_addresses() diff --git a/tests/crm/test_crm.py b/tests/crm/test_crm.py index 6bb275d12c..0a2365f339 100755 --- a/tests/crm/test_crm.py +++ b/tests/crm/test_crm.py @@ -603,7 +603,7 @@ def get_expected_crm_stats_route_available(crm_stats_route_available, crm_stats_ @pytest.mark.parametrize("ip_ver,nexthop", [("4", "2.2.2.2"), ("6", "2001::1")]) def test_crm_nexthop(duthosts, enum_rand_one_per_hwsku_frontend_hostname, - enum_frontend_asic_index, crm_interface, ip_ver, nexthop, ptfhost): + enum_frontend_asic_index, crm_interface, ip_ver, nexthop, ptfhost, cleanup_ptf_interface): duthost = duthosts[enum_rand_one_per_hwsku_frontend_hostname] asichost = duthost.asic_instance(enum_frontend_asic_index) RESTORE_CMDS["crm_threshold_name"] = "ipv{ip_ver}_nexthop".format(ip_ver=ip_ver) diff --git a/tests/dash/gnmi_utils.py b/tests/dash/gnmi_utils.py index 3f548344a6..68860d61ee 100644 --- a/tests/dash/gnmi_utils.py +++ b/tests/dash/gnmi_utils.py @@ -370,9 +370,9 @@ def apply_gnmi_file(localhost, duthost, ptfhost, dest_path=None, config_json=Non keys = k.split(":", 1) k = keys[0] + "[key=" + keys[1] + "]" if proto_utils.ENABLE_PROTO: - path = "/APPL_DB/%s:$/root/%s" % (k, filename) + path = "/APPL_DB/localhost/%s:$/root/%s" % (k, filename) else: - path = "/APPL_DB/%s:@/root/%s" % (k, filename) + path = "/APPL_DB/localhost/%s:@/root/%s" % (k, filename) update_list.append(path) elif operation["OP"] == "DEL": for k, v in operation.items(): @@ -380,7 +380,7 @@ def apply_gnmi_file(localhost, duthost, ptfhost, dest_path=None, config_json=Non continue keys = k.split(":", 1) k = keys[0] + "[key=" + keys[1] + "]" - path = "/APPL_DB/%s" % (k) + path = "/APPL_DB/localhost/%s" % (k) delete_list.append(path) else: logger.info("Invalid operation %s" % operation["OP"]) diff --git a/tests/dhcp_relay/test_dhcp_relay.py b/tests/dhcp_relay/test_dhcp_relay.py index 1206186c69..adbe4e6f4a 100644 --- a/tests/dhcp_relay/test_dhcp_relay.py +++ b/tests/dhcp_relay/test_dhcp_relay.py @@ -344,8 +344,8 @@ def test_dhcp_relay_default(ptfhost, dut_dhcp_relay_data, validate_dut_routes_ex expected_agg_counter_message = ( r".*dhcp_relay#dhcpmon\[[0-9]+\]: " r"\[\s*Agg-%s\s*-[\sA-Za-z0-9]+\s*rx/tx\] " - r"Discover: +1/ +%d, Offer: +1/ +1, Request: +3/ +%d, ACK: +1/ +1+" - ) % (dhcp_relay['downlink_vlan_iface']['name'], dhcp_server_num, dhcp_server_num * 3) + r"Discover: +1/ +%d, Offer: +1/ +1, Request: +2/ +%d, ACK: +1/ +1+" + ) % (dhcp_relay['downlink_vlan_iface']['name'], dhcp_server_num, dhcp_server_num * 2) loganalyzer = LogAnalyzer(ansible_host=duthost, marker_prefix="dhcpmon counter") marker = loganalyzer.init() loganalyzer.expect_regex = [expected_agg_counter_message] diff --git a/tests/gnmi/test_gnmi_appldb.py b/tests/gnmi/test_gnmi_appldb.py index def12cb3b2..145ee9e7ec 100644 --- a/tests/gnmi/test_gnmi_appldb.py +++ b/tests/gnmi/test_gnmi_appldb.py @@ -22,12 +22,12 @@ def test_gnmi_appldb_01(duthosts, rand_one_dut_hostname, localhost): with open(file_name, 'w') as file: file.write(text) # Add DASH_VNET_TABLE - update_list = ["/sonic-db:APPL_DB/DASH_VNET_TABLE:@./%s" % (file_name)] + update_list = ["/sonic-db:APPL_DB/localhost/DASH_VNET_TABLE:@./%s" % (file_name)] ret, msg = gnmi_set(duthost, localhost, [], update_list, []) assert ret == 0, msg # Check gnmi_get result - path_list1 = ["/sonic-db:APPL_DB/DASH_VNET_TABLE/Vnet1/vni"] - path_list2 = ["/sonic-db:APPL_DB/_DASH_VNET_TABLE/Vnet1/vni"] + path_list1 = ["/sonic-db:APPL_DB/localhost/DASH_VNET_TABLE/Vnet1/vni"] + path_list2 = ["/sonic-db:APPL_DB/localhost/_DASH_VNET_TABLE/Vnet1/vni"] ret1, msg_list1 = gnmi_get(duthost, localhost, path_list1) ret2, msg_list2 = gnmi_get(duthost, localhost, path_list2) output = "" @@ -38,12 +38,12 @@ def test_gnmi_appldb_01(duthosts, rand_one_dut_hostname, localhost): assert output == "\"1000\"", output # Remove DASH_VNET_TABLE - delete_list = ["/sonic-db:APPL_DB/DASH_VNET_TABLE/Vnet1"] + delete_list = ["/sonic-db:APPL_DB/localhost/DASH_VNET_TABLE/Vnet1"] ret, msg = gnmi_set(duthost, localhost, delete_list, [], []) assert ret == 0, msg # Check gnmi_get result - path_list1 = ["/sonic-db:APPL_DB/DASH_VNET_TABLE/Vnet1/vni"] - path_list2 = ["/sonic-db:APPL_DB/_DASH_VNET_TABLE/Vnet1/vni"] + path_list1 = ["/sonic-db:APPL_DB/localhost/DASH_VNET_TABLE/Vnet1/vni"] + path_list2 = ["/sonic-db:APPL_DB/localhost/_DASH_VNET_TABLE/Vnet1/vni"] ret1, msg_list1 = gnmi_get(duthost, localhost, path_list1) ret2, msg_list2 = gnmi_get(duthost, localhost, path_list2) assert ret1 != 0 and ret2 != 0, msg_list1[0] + msg_list2[0] diff --git a/tests/gnmi/test_gnmi_configdb.py b/tests/gnmi/test_gnmi_configdb.py index f365471321..78e3f0a24e 100644 --- a/tests/gnmi/test_gnmi_configdb.py +++ b/tests/gnmi/test_gnmi_configdb.py @@ -50,8 +50,8 @@ def test_gnmi_configdb_incremental_01(duthosts, rand_one_dut_hostname, localhost file_name = "port.txt" interface = get_first_interface(duthost) assert interface is not None, "Invalid interface" - update_list = ["/sonic-db:CONFIG_DB/PORT/%s/admin_status:@./%s" % (interface, file_name)] - path_list = ["/sonic-db:CONFIG_DB/PORT/%s/admin_status" % (interface)] + update_list = ["/sonic-db:CONFIG_DB/localhost/PORT/%s/admin_status:@./%s" % (interface, file_name)] + path_list = ["/sonic-db:CONFIG_DB/localhost/PORT/%s/admin_status" % (interface)] # Shutdown interface text = "\"down\"" @@ -87,7 +87,7 @@ def test_gnmi_configdb_incremental_02(duthosts, rand_one_dut_hostname, localhost ''' duthost = duthosts[rand_one_dut_hostname] file_name = "port.txt" - update_list = ["/sonic-db:CONFIG_DB/PORTABC/Ethernet100/admin_status:@./%s" % (file_name)] + update_list = ["/sonic-db:CONFIG_DB/localhost/PORTABC/Ethernet100/admin_status:@./%s" % (file_name)] # GNMI set request with invalid path text = "\"down\"" @@ -117,8 +117,8 @@ def test_gnmi_configdb_full_01(duthosts, rand_one_dut_hostname, localhost): filename = "full.txt" with open(filename, 'w') as file: json.dump(dic, file) - delete_list = ["/sonic-db:CONFIG_DB/"] - update_list = ["/sonic-db:CONFIG_DB/:@%s" % filename] + delete_list = ["/sonic-db:CONFIG_DB/localhost/"] + update_list = ["/sonic-db:CONFIG_DB/localhost/:@%s" % filename] ret, msg = gnmi_set(duthost, localhost, delete_list, update_list, []) assert ret == 0, msg # Check interface status and gnmi_get result diff --git a/tests/ip/test_mgmt_ipv6_only.py b/tests/ip/test_mgmt_ipv6_only.py new file mode 100644 index 0000000000..a80ae631c4 --- /dev/null +++ b/tests/ip/test_mgmt_ipv6_only.py @@ -0,0 +1,80 @@ +import pytest + +from tests.common.fixtures.duthost_utils import convert_and_restore_config_db_to_ipv6_only # noqa F401 +from tests.common.helpers.assertions import pytest_assert, pytest_require + +pytestmark = [ + pytest.mark.topology('any'), + pytest.mark.device_type('vs') +] + + +def test_bgp_facts_ipv6_only(duthosts, enum_frontend_dut_hostname, enum_asic_index, + convert_and_restore_config_db_to_ipv6_only): # noqa F811 + """compare the bgp facts between observed states and target state""" + + duthost = duthosts[enum_frontend_dut_hostname] + + bgp_facts = duthost.bgp_facts(instance_id=enum_asic_index)['ansible_facts'] + namespace = duthost.get_namespace_from_asic_id(enum_asic_index) + config_facts = duthost.config_facts(host=duthost.hostname, source="running", namespace=namespace)['ansible_facts'] + sonic_db_cmd = "sonic-db-cli {}".format("-n " + namespace if namespace else "") + for k, v in list(bgp_facts['bgp_neighbors'].items()): + # Verify bgp sessions are established + assert v['state'] == 'established' + # Verify local ASNs in bgp sessions + assert v['local AS'] == int(config_facts['DEVICE_METADATA']['localhost']['bgp_asn'].encode().decode("utf-8")) + # Check bgpmon functionality by validate STATE DB contains this neighbor as well + state_fact = duthost.shell('{} STATE_DB HGET "NEIGH_STATE_TABLE|{}" "state"' + .format(sonic_db_cmd, k), module_ignore_errors=False)['stdout_lines'] + peer_type = duthost.shell('{} STATE_DB HGET "NEIGH_STATE_TABLE|{}" "peerType"' + .format(sonic_db_cmd, k), + module_ignore_errors=False)['stdout_lines'] + assert state_fact[0] == "Established" + assert peer_type[0] == "i-BGP" if v['remote AS'] == v['local AS'] else "e-BGP" + + # In multi-asic, would have 'BGP_INTERNAL_NEIGHBORS' and possibly no 'BGP_NEIGHBOR' (ebgp) neighbors. + nbrs_in_cfg_facts = {} + nbrs_in_cfg_facts.update(config_facts.get('BGP_NEIGHBOR', {})) + nbrs_in_cfg_facts.update(config_facts.get('BGP_INTERNAL_NEIGHBOR', {})) + # In VoQ Chassis, we would have BGP_VOQ_CHASSIS_NEIGHBOR as well. + nbrs_in_cfg_facts.update(config_facts.get('BGP_VOQ_CHASSIS_NEIGHBOR', {})) + for k, v in list(nbrs_in_cfg_facts.items()): + # Compare the bgp neighbors name with config db bgp neighbors name + assert v['name'] == bgp_facts['bgp_neighbors'][k]['description'] + # Compare the bgp neighbors ASN with config db + assert int(v['asn'].encode().decode("utf-8")) == bgp_facts['bgp_neighbors'][k]['remote AS'] + + +def test_show_features_ipv6_only(duthosts, enum_dut_hostname, convert_and_restore_config_db_to_ipv6_only): # noqa F811 + """Verify show features command output against CONFIG_DB + """ + + duthost = duthosts[enum_dut_hostname] + features_dict, succeeded = duthost.get_feature_status() + pytest_assert(succeeded, "failed to obtain feature status") + for cmd_key, cmd_value in list(features_dict.items()): + redis_value = duthost.shell('/usr/bin/redis-cli -n 4 --raw hget "FEATURE|{}" "state"' + .format(cmd_key), module_ignore_errors=False)['stdout'] + pytest_assert(redis_value.lower() == cmd_value.lower(), + "'{}' is '{}' which does not match with config_db".format(cmd_key, cmd_value)) + + +def test_image_download_ipv6_only(creds, duthosts, enum_dut_hostname, + convert_and_restore_config_db_to_ipv6_only): # noqa F811 + """ + Test image download in mgmt ipv6 only scenario + """ + duthost = duthosts[enum_dut_hostname] + image_url = creds.get("test_image_url", {}).get("ipv6", "") + pytest_require(len(image_url) != 0, "Cannot get image url") + cfg_facts = duthost.config_facts(host=duthost.hostname, source="running")['ansible_facts'] + mgmt_interfaces = cfg_facts.get("MGMT_INTERFACE", {}).keys() + for mgmt_interface in mgmt_interfaces: + output = duthost.shell("curl --fail --interface {} {}".format(mgmt_interface, image_url), + module_ignore_errors=True) + if output["rc"] == 0: + break + else: + pytest.fail("Failed to download image from image_url {} via any of {}" + .format(image_url, list(mgmt_interfaces))) diff --git a/tests/platform_tests/test_memory_exhaustion.py b/tests/platform_tests/test_memory_exhaustion.py index b829baab40..141df3dc65 100644 --- a/tests/platform_tests/test_memory_exhaustion.py +++ b/tests/platform_tests/test_memory_exhaustion.py @@ -64,6 +64,12 @@ def test_memory_exhaustion(self, duthosts, enum_rand_one_per_hwsku_hostname, loc # background process. # * Some DUTs with few free memory may reboot before ansible receive the result of shell # command, so we add `sleep 5` to ensure ansible receive the result first. + # Swapping is turned off so the OOM is triggered in a shorter time. + + res = duthost.command("sudo swapoff -a") + if res['rc']: + logging.error("Swapoff command failed: {}".format(res)) + cmd = 'nohup bash -c "sleep 5 && tail /dev/zero" &' res = duthost.shell(cmd) if not res.is_successful: diff --git a/tests/platform_tests/test_reboot.py b/tests/platform_tests/test_reboot.py index f1925ec115..4dcaa97343 100644 --- a/tests/platform_tests/test_reboot.py +++ b/tests/platform_tests/test_reboot.py @@ -96,7 +96,7 @@ def reboot_and_check(localhost, dut, interfaces, xcvr_skip_list, def check_interfaces_and_services(dut, interfaces, xcvr_skip_list, - interfaces_wait_time=MAX_WAIT_TIME_FOR_INTERFACES, reboot_type=None): + interfaces_wait_time=None, reboot_type=None): """ Perform a further check after reboot-cause, including transceiver status, interface status @param localhost: The Localhost object. @@ -106,6 +106,9 @@ def check_interfaces_and_services(dut, interfaces, xcvr_skip_list, logging.info("Wait until all critical services are fully started") wait_critical_processes(dut) + if interfaces_wait_time is None: + interfaces_wait_time = MAX_WAIT_TIME_FOR_INTERFACES + if dut.is_supervisor_node(): logging.info("skipping interfaces related check for supervisor") else: diff --git a/tests/scripts/sai_qualify/DUTScript/tests/mlnx-saiserver-files/usr/lib/systemd/system/saiserver.service b/tests/scripts/sai_qualify/DUTScript/tests/mlnx-saiserver-files/usr/lib/systemd/system/saiserver.service index 7d46da42c4..dcfd2e6ee2 100644 --- a/tests/scripts/sai_qualify/DUTScript/tests/mlnx-saiserver-files/usr/lib/systemd/system/saiserver.service +++ b/tests/scripts/sai_qualify/DUTScript/tests/mlnx-saiserver-files/usr/lib/systemd/system/saiserver.service @@ -5,8 +5,8 @@ After=database.service -Requires=updategraph.service -After=updategraph.service +Requires=config-setup.service +After=config-setup.service After=interfaces-config.service BindsTo=sonic.target After=sonic.target diff --git a/tests/scripts/sai_qualify/DUTScript/tests/mlnx-syncd-files/usr/lib/systemd/system/syncd.service b/tests/scripts/sai_qualify/DUTScript/tests/mlnx-syncd-files/usr/lib/systemd/system/syncd.service index 14c16d3d2a..12b43cfaa4 100644 --- a/tests/scripts/sai_qualify/DUTScript/tests/mlnx-syncd-files/usr/lib/systemd/system/syncd.service +++ b/tests/scripts/sai_qualify/DUTScript/tests/mlnx-syncd-files/usr/lib/systemd/system/syncd.service @@ -5,8 +5,8 @@ After=database.service After=swss.service -Requires=updategraph.service -After=updategraph.service +Requires=config-setup.service +After=config-setup.service After=interfaces-config.service BindsTo=sonic.target After=sonic.target diff --git a/tests/snappi_tests/multidut/ecn/__init__.py b/tests/snappi_tests/multidut/ecn/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/snappi_tests/multidut/ecn/files/__init__.py b/tests/snappi_tests/multidut/ecn/files/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/snappi_tests/multidut/ecn/files/multidut_helper.py b/tests/snappi_tests/multidut/ecn/files/multidut_helper.py new file mode 100644 index 0000000000..a9bca73098 --- /dev/null +++ b/tests/snappi_tests/multidut/ecn/files/multidut_helper.py @@ -0,0 +1,180 @@ +import logging +from tests.common.helpers.assertions import pytest_assert +from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts # noqa: F401 +from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ + snappi_api # noqa: F401 +from tests.common.snappi_tests.snappi_helpers import get_dut_port_id +from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector, config_wred, \ + enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging, \ + config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate # noqa: F401 +from tests.common.snappi_tests.read_pcap import get_ip_pkts +from tests.common.snappi_tests.snappi_test_params import SnappiTestParams +from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ + generate_pause_flows, run_traffic # noqa: F401 + +logger = logging.getLogger(__name__) + +EXP_DURATION_SEC = 1 +DATA_START_DELAY_SEC = 0.1 +SNAPPI_POLL_DELAY_SEC = 2 +PAUSE_FLOW_NAME = 'Pause Storm' +DATA_FLOW_NAME = 'Data Flow' + + +def run_ecn_test(api, + testbed_config, + port_config_list, + conn_data, + fanout_data, + dut_port, + lossless_prio, + prio_dscp_map, + iters, + snappi_extra_params=None): + """ + Run multidut ECN test + + Args: + api (obj): SNAPPI session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + lossless_prio (int): lossless priority + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + + Returns: + Return captured IP packets (list of list) + """ + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + duthost1 = snappi_extra_params.multi_dut_params.duthost1 + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + duthost2 = snappi_extra_params.multi_dut_params.duthost2 + tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + iters = snappi_extra_params.test_iterations + + pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') + + logger.info("Stopping PFC watchdog") + stop_pfcwd(duthost1, rx_port['asic_value']) + stop_pfcwd(duthost2, tx_port['asic_value']) + logger.info("Disabling packet aging if necessary") + disable_packet_aging(duthost1) + disable_packet_aging(duthost2) + + # Configure WRED/ECN thresholds + logger.info("Configuring WRED and ECN thresholds") + config_result = config_wred(host_ans=duthost1, + kmin=snappi_extra_params.ecn_params["kmin"], + kmax=snappi_extra_params.ecn_params["kmax"], + pmax=snappi_extra_params.ecn_params["pmax"]) + pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + config_result = config_wred(host_ans=duthost2, + kmin=snappi_extra_params.ecn_params["kmin"], + kmax=snappi_extra_params.ecn_params["kmax"], + pmax=snappi_extra_params.ecn_params["pmax"]) + pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + + # Enable ECN marking + logger.info("Enabling ECN markings") + pytest_assert(enable_ecn(host_ans=duthost1, prio=lossless_prio), 'Unable to enable ecn') + pytest_assert(enable_ecn(host_ans=duthost2, prio=lossless_prio), 'Unable to enable ecn') + + config_result = config_ingress_lossless_buffer_alpha(host_ans=duthost1, + alpha_log2=3) + + pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') + config_result = config_ingress_lossless_buffer_alpha(host_ans=duthost2, + alpha_log2=3) + + pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') + + # Get the ID of the port to test + port_id = get_dut_port_id(dut_hostname=duthost1.hostname, + dut_port=dut_port, + conn_data=conn_data, + fanout_data=fanout_data) + + pytest_assert(port_id is not None, + 'Failed to get ID for port {}'.format(dut_port)) + + speed_str = testbed_config.layer1[0].speed + speed_gbps = int(speed_str.split('_')[1]) + + # Generate base traffic config + port_id = 0 + logger.info("Generating base flow config") + snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + + logger.info("Setting test flow config params") + snappi_extra_params.traffic_flow_config.data_flow_config.update({ + "flow_name": DATA_FLOW_NAME, + "flow_rate_percent": 100, + "flow_delay_sec": DATA_START_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS + }) + + logger.info("Setting pause flow config params") + snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": EXP_DURATION_SEC, + "flow_rate_percent": None, + "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": None, + "flow_delay_sec": 0, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + # Generate traffic config of one test flow and one pause storm + logger.info("Generating test flows") + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=[lossless_prio], + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params) + + logger.info("Generating pause flows") + generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=[lossless_prio], + global_pause=False, + snappi_extra_params=snappi_extra_params) + + flows = testbed_config.flows + + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + + logger.info("Setting packet capture port to {}".format(testbed_config.ports[port_id].name)) + snappi_extra_params.packet_capture_ports = [testbed_config.ports[port_id].name] + + result = [] + logger.info("Running {} iteration(s)".format(iters)) + for i in range(iters): + logger.info("Running iteration {}".format(i)) + snappi_extra_params.packet_capture_file = "ECN_cap-{}".format(i) + logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) + + config_capture_pkt(testbed_config=testbed_config, + port_names=snappi_extra_params.packet_capture_ports, + capture_type=snappi_extra_params.packet_capture_type, + capture_name=snappi_extra_params.packet_capture_file) + + logger.info("Running traffic") + run_traffic(duthost=duthost1, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=EXP_DURATION_SEC, + snappi_extra_params=snappi_extra_params) + + result.append(get_ip_pkts(snappi_extra_params.packet_capture_file + ".pcapng")) + + return result diff --git a/tests/snappi_tests/multidut/ecn/test_multidut_dequeue_ecn_with_snappi.py b/tests/snappi_tests/multidut/ecn/test_multidut_dequeue_ecn_with_snappi.py new file mode 100644 index 0000000000..60aab367ed --- /dev/null +++ b/tests/snappi_tests/multidut/ecn/test_multidut_dequeue_ecn_with_snappi.py @@ -0,0 +1,124 @@ +import pytest +import random +import logging + +from tests.common.helpers.assertions import pytest_assert, pytest_require +from tests.common.fixtures.conn_graph_facts import conn_graph_facts, \ + fanout_graph_facts # noqa: F401 +from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ + snappi_api, snappi_dut_base_config, get_tgen_peer_ports, get_multidut_snappi_ports, \ + get_multidut_tgen_peer_port_set, cleanup_config # noqa: F401 +from tests.common.snappi_tests.qos_fixtures import prio_dscp_map, lossless_prio_list # noqa F401 + +from tests.snappi_tests.variables import config_set, line_card_choice +from tests.snappi_tests.multidut.ecn.files.multidut_helper import run_ecn_test +from tests.common.snappi_tests.read_pcap import is_ecn_marked +from tests.snappi_tests.files.helper import skip_ecn_tests +from tests.common.snappi_tests.common_helpers import packet_capture +from tests.common.config_reload import config_reload +from tests.common.snappi_tests.snappi_test_params import SnappiTestParams +logger = logging.getLogger(__name__) +pytestmark = [pytest.mark.topology('multidut-tgen')] + + +@pytest.mark.parametrize('line_card_choice', [line_card_choice]) +@pytest.mark.parametrize('linecard_configuration_set', [config_set]) +def test_dequeue_ecn(request, + snappi_api, # noqa: F811 + conn_graph_facts, # noqa: F811 + fanout_graph_facts, # noqa: F811 + duthosts, + rand_one_dut_lossless_prio, + line_card_choice, + linecard_configuration_set, + get_multidut_snappi_ports, # noqa: F811 + prio_dscp_map): # noqa: F811 + """ + Test if the device under test (DUT) performs ECN marking at the egress + + Args: + request (pytest fixture): pytest request object + snappi_api (pytest fixture): SNAPPI session + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + duthosts (pytest fixture): list of DUTs + rand_one_dut_lossless_prio (str): name of lossless priority to test, e.g., 's6100-1|3' + line_card_choice: Line card choice to be mentioned in the variable.py file + linecard_configuration_set : Line card classification, (min 1 or max 2 hostnames and asics to be given) + prio_dscp_map (pytest fixture): priority vs. DSCP map (key = priority). + + Returns: + N/A + """ + + if line_card_choice not in linecard_configuration_set.keys(): + pytest_require(False, "Invalid line_card_choice value passed in parameter") + + if (len(linecard_configuration_set[line_card_choice]['hostname']) == 2): + dut_list = random.sample(duthosts, 2) + duthost1, duthost2 = dut_list + elif (len(linecard_configuration_set[line_card_choice]['hostname']) == 1): + dut_list = [dut for dut in duthosts if + linecard_configuration_set[line_card_choice]['hostname'] == [dut.hostname]] + duthost1, duthost2 = dut_list[0], dut_list[0] + else: + pytest_require(False, "Hostname can't be an empty list") + + snappi_port_list = get_multidut_snappi_ports(line_card_choice=line_card_choice, + line_card_info=linecard_configuration_set[line_card_choice]) + if len(snappi_port_list) < 2: + pytest_require(False, "Need Minimum of 2 ports for the test") + + snappi_ports = get_multidut_tgen_peer_port_set(line_card_choice, snappi_port_list, config_set, 2) + + testbed_config, port_config_list, snappi_ports = snappi_dut_base_config(dut_list, + snappi_ports, + snappi_api) + + _, lossless_prio = rand_one_dut_lossless_prio.split('|') + skip_ecn_tests(duthost1) + skip_ecn_tests(duthost2) + lossless_prio = int(lossless_prio) + snappi_extra_params = SnappiTestParams() + snappi_extra_params.multi_dut_params.duthost1 = duthost1 + snappi_extra_params.multi_dut_params.duthost2 = duthost2 + snappi_extra_params.multi_dut_params.multi_dut_ports = snappi_ports + snappi_extra_params.packet_capture_type = packet_capture.IP_CAPTURE + snappi_extra_params.is_snappi_ingress_port_cap = True + snappi_extra_params.ecn_params = {'kmin': 50000, 'kmax': 51000, 'pmax': 100} + data_flow_pkt_size = 1024 + data_flow_pkt_count = 101 + logger.info("Running ECN dequeue test with params: {}".format(snappi_extra_params.ecn_params)) + + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": data_flow_pkt_count + } + + ip_pkts = run_ecn_test(api=snappi_api, + testbed_config=testbed_config, + port_config_list=port_config_list, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts, + dut_port=snappi_ports[0]['peer_port'], + lossless_prio=lossless_prio, + prio_dscp_map=prio_dscp_map, + iters=1, + snappi_extra_params=snappi_extra_params)[0] + + logger.info("Running verification for ECN dequeue test") + # Check if all the packets are captured + pytest_assert(len(ip_pkts) == data_flow_pkt_count, + 'Only capture {}/{} IP packets'.format(len(ip_pkts), data_flow_pkt_count)) + + # Check if the first packet is ECN marked + pytest_assert(is_ecn_marked(ip_pkts[0]), "The first packet should be marked") + + # Check if the last packet is not ECN marked + pytest_assert(not is_ecn_marked(ip_pkts[-1]), + "The last packet should not be marked") + + # Teardown ECN config through a reload + logger.info("Reloading config to teardown ECN config") + config_reload(sonic_host=duthost1, config_source='config_db', safe_reload=True) + config_reload(sonic_host=duthost2, config_source='config_db', safe_reload=True) diff --git a/tests/telemetry/events/swss_events.py b/tests/telemetry/events/swss_events.py index a322ec9e5c..56615b3e82 100644 --- a/tests/telemetry/events/swss_events.py +++ b/tests/telemetry/events/swss_events.py @@ -4,6 +4,7 @@ import time from run_events_test import run_test +from tests.common.utilities import wait_until logger = logging.getLogger(__name__) tag = "sonic-events-swss" @@ -48,9 +49,15 @@ def shutdown_interface(duthost): ret = duthost.shell("config interface shutdown {}".format(if_state_test_port)) assert ret["rc"] == 0, "Failing to shutdown interface {}".format(if_state_test_port) + # Wait until port goes down + wait_until(15, 1, 0, verify_port_admin_oper_status, duthost, if_state_test_port, "down") + ret = duthost.shell("config interface startup {}".format(if_state_test_port)) assert ret["rc"] == 0, "Failing to startup interface {}".format(if_state_test_port) + # Wait until port comes back up + wait_until(15, 1, 0, verify_port_admin_oper_status, duthost, if_state_test_port, "up") + def generate_pfc_storm(duthost): logger.info("Generating pfc storm") @@ -89,3 +96,10 @@ def trigger_crm_threshold_exceeded(duthost): duthost.shell("crm config thresholds ipv4 route type free") duthost.shell("crm config thresholds ipv4 route low {}".format(CRM_DEFAULT_IPV4_ROUTE_LOW)) duthost.shell("crm config thresholds ipv4 route high {}".format(CRM_DEFAULT_IPV4_ROUTE_HIGH)) + + +def verify_port_admin_oper_status(duthost, interface, state): + interface_facts = duthost.get_interfaces_status()[interface] + admin_status = interface_facts["admin"] + oper_status = interface_facts["oper"] + return admin_status == state and oper_status == state diff --git a/tests/telemetry/test_telemetry.py b/tests/telemetry/test_telemetry.py index a25593709e..36c6c2d601 100644 --- a/tests/telemetry/test_telemetry.py +++ b/tests/telemetry/test_telemetry.py @@ -190,11 +190,10 @@ def test_virtualdb_table_streaming(duthosts, enum_rand_one_per_hwsku_hostname, p "Timestamp markers for each update message in:\n{0}".format(result)) -def invoke_py_cli_from_ptf(ptfhost, cmd, results): +def invoke_py_cli_from_ptf(ptfhost, cmd, callback): ret = ptfhost.shell(cmd) assert ret["rc"] == 0, "PTF docker did not get a response" - if results is not None and len(results) > 0: - results[0] = ret["stdout"] + callback(ret["stdout"]) def test_on_change_updates(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, localhost, gnxi_path): @@ -205,7 +204,6 @@ def test_on_change_updates(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, cmd = generate_client_cli(duthost=duthost, gnxi_path=gnxi_path, method=METHOD_SUBSCRIBE, submode=SUBMODE_ONCHANGE, update_count=2, xpath="NEIGH_STATE_TABLE", target="STATE_DB") - results = [""] bgp_nbrs = list(duthost.get_bgp_neighbors().keys()) bgp_neighbor = random.choice(bgp_nbrs) @@ -213,22 +211,23 @@ def test_on_change_updates(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, original_state = bgp_info["bgpState"] new_state = "Established" if original_state.lower() == "active" else "Active" - client_thread = threading.Thread(target=invoke_py_cli_from_ptf, args=(ptfhost, cmd, results,)) + def callback(result): + logger.info("Assert that ptf client output is non empty and contains on change update") + try: + assert result != "", "Did not get output from PTF client" + finally: + duthost.shell("sonic-db-cli STATE_DB HSET \"NEIGH_STATE_TABLE|{}\" \"state\" {}".format(bgp_neighbor, + original_state)) + ret = parse_gnmi_output(result, 1, bgp_neighbor) + assert ret is True, "Did not find key in update" + + client_thread = threading.Thread(target=invoke_py_cli_from_ptf, args=(ptfhost, cmd, callback,)) client_thread.start() wait_until(5, 1, 0, check_gnmi_cli_running, ptfhost) duthost.shell("sonic-db-cli STATE_DB HSET \"NEIGH_STATE_TABLE|{}\" \"state\" {}".format(bgp_neighbor, new_state)) - - client_thread.join(30) - - try: - assert results[0] != "", "Did not get output from PTF client" - finally: - duthost.shell("sonic-db-cli STATE_DB HSET \"NEIGH_STATE_TABLE|{}\" \"state\" {}".format(bgp_neighbor, - original_state)) - ret = parse_gnmi_output(results[0], 1, bgp_neighbor) - assert ret is True, "Did not find key in update" + client_thread.join(60) # max timeout of 60s, expect update to come in <=30s @pytest.mark.disable_loganalyzer