From 78270ceb4933327a36491e3176734444778a24eb Mon Sep 17 00:00:00 2001 From: Chris Sommers <31145757+chrispsommers@users.noreply.github.com> Date: Wed, 14 Dec 2022 09:21:59 -0800 Subject: [PATCH 1/5] [doc]: Fix links to external SAI PTF documents (#299) Previous dev branches moved/disappeared. Links now point to master branch. Co-authored-by: Chris Sommers --- test/docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/docs/README.md b/test/docs/README.md index e88335a61..a07276b06 100644 --- a/test/docs/README.md +++ b/test/docs/README.md @@ -5,8 +5,8 @@ | [High-Level Description (HLD) Test Specification](dash-test-HLD.md) | High-level design for the testing of devices which conform to the SONiC-DASH requirements.| | [Dash Test Maturity Stages](dash-test-maturity-stages.md) | Describes a progressive approach to DASH testing.| | [DASH SAI-Thrift Test Workflow](dash-test-workflow-saithrift.md) | DASH test workflow with SAI-thrift. | -| [SAI PTF Design](https://github.com/reshmaintel/SAI/blob/dash-ptf/doc/SAI-Proposal-SAI-PTF.md) | SAI Thrift auto-generated Python based testing framework doc. | -| [SAI PTF User Guide](https://github.com/opencomputeproject/SAI/blob/master/ptf/SAI_PTF_user-guide.md) | SAI Thrift Server User Guide to autogenerate test frame work. | +| [SAI PTF Design](https://github.com/opencomputeproject/SAI/blob/master/doc/SAI-Proposal-SAI-PTF.md) | SAI Thrift auto-generated Python based testing framework doc. | +| [SAI PTF User Guides](https://github.com/opencomputeproject/SAI/tree/master/ptf/docs) | SAI Thrift Server User Guide to autogenerate test frame work. | | [DASH P4 SAI-Thrift Test Workflow](dash-test-workflow-p4-saithrift.md) | Use of P4-based simulators or SW data planes to verify DASH behavior, using saithrift API. | | [Testbed](testbed/README.md) | Describes the setup and configuration of a DASH testbed.| | [snappi and SAI-Challenger based tests](dash-test-sai-challenger.md) | How to run scalable tests using SAI-Challenger and snappi. The scalability is achieved with additional DASH/SAI abstraction level in test code to simplify high scale DUT configuration. | From 0fac5d1657187d93ffa60595cbebdba1df384316 Mon Sep 17 00:00:00 2001 From: Anton Putria Date: Wed, 21 Dec 2022 19:26:16 +0200 Subject: [PATCH 2/5] Updated run-functional-tests.sh (#305) * Updated run-functional-tests.sh Added options: - SAI Server IP address - Paths to port map and port config files - Underlay/Overlay tests selection - Hardware/BMv2 selection - Interfaces specifing Signed-off-by: Yuriy Harhas * Moved run-test.sh script the to functional/ptf folder. Signed-off-by: Anton Putria Signed-off-by: Yuriy Harhas Signed-off-by: Anton Putria Co-authored-by: Yuriy Harhas --- dash-pipeline/Makefile | 4 +- test/test-cases/functional/ptf/run-tests.sh | 87 +++++++++++++++++++++ test/test-cases/run-functional-tests.sh | 10 --- 3 files changed, 89 insertions(+), 12 deletions(-) create mode 100755 test/test-cases/functional/ptf/run-tests.sh delete mode 100755 test/test-cases/run-functional-tests.sh diff --git a/dash-pipeline/Makefile b/dash-pipeline/Makefile index 587cd9204..fcd3636dc 100644 --- a/dash-pipeline/Makefile +++ b/dash-pipeline/Makefile @@ -429,7 +429,7 @@ run-saithrift-ptftests: disable-ipv6 $(DOCKER_RUN_SAITHRIFT_CLIENT) \ -w /tests/ \ $(DOCKER_SAITHRIFT_CLIENT_IMG) \ - ./run-functional-tests.sh + ./functional/ptf/run-tests.sh # Run "dev" PTF tests mounted from host # Note - if add ixia-c usage to PTF tests, add dependency deploy-ixiac @@ -438,7 +438,7 @@ run-saithrift-dev-ptftests: disable-ipv6 -v $(PWD)/../test/test-cases/:/tests-dev/ \ -w /tests-dev/ \ $(DOCKER_SAITHRIFT_CLIENT_IMG) \ - ./run-functional-tests.sh + ./functional/ptf/run-tests.sh run-saithrift-client-bash: $(DOCKER_RUN_SAITHRIFT_CLIENT) \ diff --git a/test/test-cases/functional/ptf/run-tests.sh b/test/test-cases/functional/ptf/run-tests.sh new file mode 100755 index 000000000..bb91fc954 --- /dev/null +++ b/test/test-cases/functional/ptf/run-tests.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# To be run inside saithrift-client container, assumes SAI repo portions exist under /SAI directory + +SCRIPT=$0 +BMV2="True" +TEST_DIR="functional/ptf" +EXTRA_PARAMETERS="" +INTERFACES="veth1,veth3" +TIMEOUT=1800 +TEST_PARAMS="" + +function show_help_and_exit() +{ + echo "Usage ${SCRIPT} [options]" + echo " options with (*) must be provided" + echo " -h -? : get this help" + echo " -s : specify thrift server IP address (e.g. -s 192.168.1.1)" + echo " -p : specify path to port map file (e.g. -p /tests-dev/config/front-map.ini)" + echo " -c : specify path to port config file (e.g. -c /tests-dev/config/port-map.ini)" + echo " -U : specify to run PTF underlay test cases. (default: run PTF overlay test cases)" + echo " -I : specify comma-separated DUT 2 interfaces names (default: veth1,veth3)" + echo " -H : specify if tests are run on real hardware" + echo " -e : specify extra parameter(s) (default: none)" + echo -e " -t : specify timeout for test case execution\n" + + exit $1 +} + +function validate_parameters() +{ + RET=0 + + if [[ ${#iface_array[@]} < 2 ]] || [[ ${#iface_array[@]} > 2 ]]; then + echo -e "\nTwo interfaces names must be specified (e.g. -I iface1, iface2)." + echo -e "Instead received - ${#iface_array[@]}: $INTERFACES\n" + RET=1 + fi + + if [[ ${RET} != 0 ]]; then + show_help_and_exit ${RET} + fi +} + +while getopts "h?UHI:s:p:c:e:t:" opt; do + case ${opt} in + h|\? ) + show_help_and_exit 0 + ;; + U ) + TEST_DIR="/SAI/ptf" + ;; + H ) + BMV2="False" + ;; + I ) + INTERFACES=${OPTARG} + ;; + s ) + TEST_PARAMS="${TEST_PARAMS}thrift_server='${OPTARG}';" + ;; + p ) + TEST_PARAMS="${TEST_PARAMS}port_map_file='${OPTARG}';" + ;; + c ) + TEST_PARAMS="${TEST_PARAMS}port_config_ini='${OPTARG}';" + ;; + e ) + EXTRA_PARAMETERS="${EXTRA_PARAMETERS} ${OPTARG}" + ;; + t ) + TIMEOUT=${OPTARG} + esac +done + +IFS="," read -a iface_array <<< $INTERFACES + +validate_parameters + +set -x +ptf \ + --test-dir ${TEST_DIR}\ + --pypath /SAI/ptf \ + --interface 0@${iface_array[0]} \ + --interface 1@${iface_array[1]} \ + --test-case-timeout=${TIMEOUT} \ + --test-params="bmv2=${BMV2};${TEST_PARAMS}" \ + ${EXTRA_PARAMETERS} diff --git a/test/test-cases/run-functional-tests.sh b/test/test-cases/run-functional-tests.sh deleted file mode 100755 index 42efa420f..000000000 --- a/test/test-cases/run-functional-tests.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# To be run inside saithrift-client container, assumes SAI repo portions exist under /SAI directory - -ptf \ - --test-dir functional \ - --pypath /SAI/ptf \ - --interface 0@veth1 --interface 1@veth3 \ - --test-case-timeout=1800 \ - --test-params="bmv2=True" \ - $@ From f3f335e9d8f8aaa452e1971d335f87966d449cd1 Mon Sep 17 00:00:00 2001 From: Chris Sommers <31145757+chrispsommers@users.noreply.github.com> Date: Wed, 21 Dec 2022 14:36:16 -0800 Subject: [PATCH 3/5] Saichallenger infra for func tests (#306) * Create test infra for sai challenger functional tests. New directory tests/test-cases/functional/saic and tests/test-cases/utils which will receive more files in future. * spellcheck * Add comment. Co-authored-by: Chris Sommers --- .wordlist.txt | 1 + dash-pipeline/Makefile | 23 ++++++--- test/test-cases/functional/saic/conftest.py | 49 +++++++++++++++++++ test/test-cases/functional/saic/empty_test.py | 7 +++ test/test-cases/functional/saic/pytest.ini | 4 ++ .../saic/run-tests.sh} | 0 .../saic/sai_dpu_client_server_ptf.json | 41 ++++++++++++++++ .../saic/sai_dpu_client_server_snappi.json | 42 ++++++++++++++++ test/test-cases/run-functional-tests.sh | 10 ++++ test/test-cases/scale/saic/conftest.py | 4 ++ test/test-cases/scale/saic/run-tests.sh | 3 ++ test/test-cases/utils/README.md | 2 + 12 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 test/test-cases/functional/saic/conftest.py create mode 100644 test/test-cases/functional/saic/empty_test.py create mode 100644 test/test-cases/functional/saic/pytest.ini rename test/test-cases/{scale/saic/run_vnet_tests.sh => functional/saic/run-tests.sh} (100%) create mode 100755 test/test-cases/functional/saic/sai_dpu_client_server_ptf.json create mode 100755 test/test-cases/functional/saic/sai_dpu_client_server_snappi.json create mode 100755 test/test-cases/run-functional-tests.sh create mode 100755 test/test-cases/scale/saic/run-tests.sh create mode 100644 test/test-cases/utils/README.md diff --git a/.wordlist.txt b/.wordlist.txt index f080de187..554e1e2ec 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -584,6 +584,7 @@ Unpair untracked upcasting upstreaming +utils vcpus veth VFP diff --git a/dash-pipeline/Makefile b/dash-pipeline/Makefile index fcd3636dc..161ffffa7 100644 --- a/dash-pipeline/Makefile +++ b/dash-pipeline/Makefile @@ -584,7 +584,7 @@ SAI_CHALLENGER_SETUP_FILE := sai_dpu_client_server_snappi.json endif # If test's name isn't passed, set it to the default. ifeq ($(SAI_CHALLENGER_TEST),) -SAI_CHALLENGER_TEST := test_sai_vnet_*.py +SAI_CHALLENGER_TEST := . endif DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG_TAG = $(shell cat dockerfiles/Dockerfile.saichallenger-client-bldr | sha1sum | awk '{print substr($$1,0,11);}') @@ -618,7 +618,9 @@ docker-saichallenger-client: DOCKER_RUN_SAI_CHALLENGER_CLIENT=docker run \ -v $(SAI_CHALLENGER_PATH):/sai-challenger \ - -v $(SAI_CHALLENGER_PATH)/../test-cases/scale/saic/:/sai-challenger/dash_tests \ + -v $(SAI_CHALLENGER_PATH)/../test-cases/scale/saic/:/sai-challenger/dash_tests/scale \ + -v $(SAI_CHALLENGER_PATH)/../test-cases/functional/saic/:/sai-challenger/dash_tests/functional \ + -v $(SAI_CHALLENGER_PATH)/../test-cases/utils/:/sai-challenger/dash_tests/utils \ -v $(PWD)/../:/dash \ --cap-add=NET_ADMIN \ --device /dev/net/tun:/dev/net/tun \ @@ -642,12 +644,21 @@ run-saichallenger-client-bash: deploy-ixiac kill-saichallenger-client: -docker kill $(CONTAINER_SAI_CHALLENGER_CLIENT_NAME) -run-saichallenger-tests: deploy-ixiac +run-saichallenger-tests: run-saichallenger-functional-tests run-saichallenger-scale-tests + +run-saichallenger-functional-tests: deploy-ixiac $(DOCKER_RUN_SAI_CHALLENGER_CLIENT) \ - -w /sai-challenger/dash_tests \ + -w /sai-challenger/dash_tests/functional \ + $(DOCKER_FLAGS) \ + $(DOCKER_SAI_CHALLENGER_CLIENT_IMG) \ + ./run-tests.sh --setup=$(SAI_CHALLENGER_SETUP_FILE) $(SAI_CHALLENGER_TEST) + +run-saichallenger-scale-tests: deploy-ixiac + $(DOCKER_RUN_SAI_CHALLENGER_CLIENT) \ + -w /sai-challenger/dash_tests/scale \ $(DOCKER_FLAGS) \ $(DOCKER_SAI_CHALLENGER_CLIENT_IMG) \ - ./run_vnet_tests.sh --setup=$(SAI_CHALLENGER_SETUP_FILE) $(SAI_CHALLENGER_TEST) + ./run-tests.sh --setup=$(SAI_CHALLENGER_SETUP_FILE) $(SAI_CHALLENGER_TEST) ############################### # ENVIRONMENT SETUP TARGETS @@ -655,4 +666,4 @@ run-saichallenger-tests: deploy-ixiac install-docker-compose: sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$$(uname -s)-$$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose \ No newline at end of file diff --git a/test/test-cases/functional/saic/conftest.py b/test/test-cases/functional/saic/conftest.py new file mode 100644 index 000000000..bbd92ecee --- /dev/null +++ b/test/test-cases/functional/saic/conftest.py @@ -0,0 +1,49 @@ +import logging +import pytest + +from saichallenger.common.sai_dpu import SaiDpu +from saichallenger.common.sai_environment import init_setup + +def pytest_addoption(parser): + parser.addoption("--traffic", action="store_true", default=False, help="run tests with traffic") + parser.addoption("--loglevel", action="store", default='NOTICE', help="syncd logging level") + parser.addoption("--setup", action="store", default=None, help="Setup description (Path to the json file).") + + +@pytest.fixture(scope="session") +def exec_params(request): + config_param = {} + config_param["setup"] = init_setup(request.config) + config_param["traffic"] = request.config.getoption("--traffic") + config_param["loglevel"] = request.config.getoption("--loglevel") + logging.getLogger().setLevel(getattr(logging, config_param["loglevel"].upper(), "INFO")) + return config_param + + +@pytest.fixture(scope="session") +def dpu(exec_params) -> SaiDpu: + dpu = exec_params["setup"]["DPU"][0] + if dpu is not None: + dpu.reset() + return dpu + + +@pytest.fixture(scope="session") +def dataplane_session(exec_params): + dataplane = exec_params["setup"]["DATAPLANE"][0] + # Set up the dataplane + dataplane.init() + yield dataplane + # Shutdown the dataplane + dataplane.remove() + + +@pytest.fixture(scope="session") +def confgen(): + return dpugen.sai.SaiConfig() + +@pytest.fixture(scope="function") +def dataplane(dataplane_session): + dataplane_session.setUp() + yield dataplane_session + dataplane_session.tearDown() diff --git a/test/test-cases/functional/saic/empty_test.py b/test/test-cases/functional/saic/empty_test.py new file mode 100644 index 000000000..2e6150a6c --- /dev/null +++ b/test/test-cases/functional/saic/empty_test.py @@ -0,0 +1,7 @@ +# Empty test-case to verify infra +# Delete this when we have some actual tests. +import pytest + +def test_placeholder(): + print('test_placeholder') + pass \ No newline at end of file diff --git a/test/test-cases/functional/saic/pytest.ini b/test/test-cases/functional/saic/pytest.ini new file mode 100644 index 000000000..f9eb33c53 --- /dev/null +++ b/test/test-cases/functional/saic/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +markers = + ptf: traffic tests supported by PTF. snappi should work as well. + snappi: traffic tests that requires snappi only. \ No newline at end of file diff --git a/test/test-cases/scale/saic/run_vnet_tests.sh b/test/test-cases/functional/saic/run-tests.sh similarity index 100% rename from test/test-cases/scale/saic/run_vnet_tests.sh rename to test/test-cases/functional/saic/run-tests.sh diff --git a/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json b/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json new file mode 100755 index 000000000..80c55496a --- /dev/null +++ b/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json @@ -0,0 +1,41 @@ +{"DPU": [ + { + "alias": "dash", + "asic": "generic", + "target": "bmv2", + "type": null, + "sku": null, + "mode": "client-server", + "sai_server_ip": "127.0.0.1", + "client": { + "type": "thrift", + "config": { + "ip": "127.0.0.1", + "port": "9092" + } + }, + "port_groups": [{"1x10G": "Ethernet0", "init": "1x10G", "alias": 0}, + {"1x10G": "Ethernet1", "init": "1x10G", "alias": 1} + ], + "sai_dataplane": "ptf_nn" + } +], + +"DATAPLANE": [ + { + "alias": "ptf", + "type": "ptf", + "mode": "eth", + "port_groups": [{"10G": "veth1", "init": "10G", "alias": 0}, + {"10G": "veth2", "init": "10G", "alias": 1} + ] + } +], + +"CONNECTIONS": { + "ptf->dash": [[0, 0], + [1, 1] + ] +} + +} diff --git a/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json b/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json new file mode 100755 index 000000000..67abe70e4 --- /dev/null +++ b/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json @@ -0,0 +1,42 @@ +{"DPU": [ + { + "alias": "dash", + "asic": "generic", + "target": "bmv2", + "type": null, + "sku": null, + "mode": "client-server", + "sai_server_ip": "127.0.0.1", + "client": { + "type": "thrift", + "config": { + "ip": "127.0.0.1", + "port": "9092" + } + }, + "port_groups": [{"1x10G": "Ethernet0", "init": "1x10G", "alias": 0}, + {"1x10G": "Ethernet1", "init": "1x10G", "alias": 1} + ], + "sai_dataplane": "ptf_nn" + } +], + +"DATAPLANE": [ + { + "alias": "ixia", + "type": "snappi", + "mode": "ixia_c", + "controller": "https://127.0.0.1:443", + "port_groups": [{"10G": "veth1", "init": "10G", "alias": 0}, + {"10G": "veth3", "init": "10G", "alias": 1} + ] + } +], + +"CONNECTIONS": { + "ixia->dash": [[0, 0], + [1, 1] + ] +} + +} diff --git a/test/test-cases/run-functional-tests.sh b/test/test-cases/run-functional-tests.sh new file mode 100755 index 000000000..56c414760 --- /dev/null +++ b/test/test-cases/run-functional-tests.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# To be run inside saithrift-client container, assumes SAI repo portions exist under /SAI directory + +ptf \ + --test-dir functional/ptf \ + --pypath /SAI/ptf \ + --interface 0@veth1 --interface 1@veth3 \ + --test-case-timeout=1800 \ + --test-params="bmv2=True" \ + $@ diff --git a/test/test-cases/scale/saic/conftest.py b/test/test-cases/scale/saic/conftest.py index ffe46e572..5832c99dd 100644 --- a/test/test-cases/scale/saic/conftest.py +++ b/test/test-cases/scale/saic/conftest.py @@ -38,6 +38,10 @@ def dataplane_session(exec_params): dataplane.remove() +@pytest.fixture(scope="session") +def confgen(): + return dpugen.sai.SaiConfig() + @pytest.fixture(scope="function") def dataplane(dataplane_session): dataplane_session.setUp() diff --git a/test/test-cases/scale/saic/run-tests.sh b/test/test-cases/scale/saic/run-tests.sh new file mode 100755 index 000000000..32eeaadda --- /dev/null +++ b/test/test-cases/scale/saic/run-tests.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +PYTHONPATH=. pytest -sv $@ diff --git a/test/test-cases/utils/README.md b/test/test-cases/utils/README.md new file mode 100644 index 000000000..9788f9918 --- /dev/null +++ b/test/test-cases/utils/README.md @@ -0,0 +1,2 @@ +# utils +This directory contains miscellaneous utilities used in tests. \ No newline at end of file From 220dbbeed067601b2c45b34a907a4f8a06b83bde Mon Sep 17 00:00:00 2001 From: Andriy Kokhan Date: Mon, 2 Jan 2023 18:31:15 +0200 Subject: [PATCH 4/5] Updated SAI-C related scripts as per changes in SAI-C repo (#307) * Updated SAI-C related scripts as per changes in SAI-C repo Signed-off-by: Andriy Kokhan * Update branch name in .gitmodules Signed-off-by: Andriy Kokhan * Initialize SAI-C submodules from Makefile Signed-off-by: Andriy Kokhan * Revert "Initialize SAI-C submodules from Makefile" This reverts commit 51960021cac1b78dae881a8863224a7ca744971d. * Fixed DASH check for SAI-C * Updated SAI-C submodule to main branch Signed-off-by: Andriy Kokhan * Re-worked SAI-C target build Signed-off-by: Andriy Kokhan * Updated SAI-C TB description files Signed-off-by: Andriy Kokhan Signed-off-by: Andriy Kokhan --- .gitmodules | 2 +- dash-pipeline/Makefile | 7 +- .../DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG.env | 2 +- .../Dockerfile.saichallenger-client | 3 +- .../Dockerfile.saichallenger-client-bldr | 1 + test/SAI-Challenger | 2 +- test/test-cases/functional/saic/conftest.py | 73 ++++++++++++------ .../saic/sai_dpu_client_server_ptf.json | 59 ++++++--------- .../saic/sai_dpu_client_server_snappi.json | 61 +++++++-------- test/test-cases/scale/saic/conftest.py | 75 ++++++++++++------- .../saic/dash_helper/vnet2vnet_helper.py | 2 +- .../scale/saic/sai_dpu_client_server_ptf.json | 59 ++++++--------- .../saic/sai_dpu_client_server_snappi.json | 61 +++++++-------- .../scale/saic/test_sai_vnet_inbound.py | 8 +- .../saic/test_sai_vnet_outbound_scale.py | 2 +- .../saic/test_sai_vnet_outbound_simple.py | 12 +-- 16 files changed, 217 insertions(+), 212 deletions(-) diff --git a/.gitmodules b/.gitmodules index f10d24641..42aae0be4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,4 +5,4 @@ [submodule "test/SAI-Challenger"] path = test/SAI-Challenger url = https://github.com/opencomputeproject/SAI-Challenger - branch = multiple-api-support + branch = main diff --git a/dash-pipeline/Makefile b/dash-pipeline/Makefile index 161ffffa7..20d6b8a45 100644 --- a/dash-pipeline/Makefile +++ b/dash-pipeline/Makefile @@ -592,7 +592,7 @@ DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG = $(DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG_ docker-saichallenger-client-bldr: { [ x$(ENABLE_DOCKER_PULL) == xy ] && docker pull $(DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG); } || \ - { pushd $(SAI_CHALLENGER_PATH) && ./build.sh -i client && popd; \ + { pushd $(SAI_CHALLENGER_PATH) && git submodule update --init && ./build.sh -i client && popd; \ docker build \ -f dockerfiles/Dockerfile.saichallenger-client-bldr \ -t $(DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG) \ @@ -609,8 +609,7 @@ docker-publish-saichallenger-client-bldr: docker-pull-saichallenger-client-bldr: docker pull $(DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG) -docker-saichallenger-client: - cd $(SAI_CHALLENGER_PATH) && ./build.sh -i client +docker-saichallenger-client: docker-saichallenger-client-bldr docker build \ -f dockerfiles/Dockerfile.saichallenger-client \ -t $(DOCKER_SAI_CHALLENGER_CLIENT_IMG) \ @@ -666,4 +665,4 @@ run-saichallenger-scale-tests: deploy-ixiac install-docker-compose: sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$$(uname -s)-$$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose \ No newline at end of file + sudo chmod +x /usr/local/bin/docker-compose diff --git a/dash-pipeline/dockerfiles/DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG.env b/dash-pipeline/dockerfiles/DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG.env index c94dd0dc5..21441e845 100644 --- a/dash-pipeline/dockerfiles/DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG.env +++ b/dash-pipeline/dockerfiles/DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG.env @@ -2,4 +2,4 @@ # Changing this will cause build/publish to occur in CI actions export DASH_ACR_REGISTRY=sonicdash.azurecr.io export DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG_NAME=${DASH_ACR_REGISTRY}/dash-saichallenger-client-bldr -export DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG_CTAG?=221209 +export DOCKER_SAI_CHALLENGER_CLIENT_BLDR_IMG_CTAG?=221228 diff --git a/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client b/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client index e7688ff7c..12d5a8b52 100644 --- a/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client +++ b/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client @@ -1,4 +1,4 @@ -FROM sonicdash.azurecr.io/dash-saichallenger-client-bldr:221109 +FROM sonicdash.azurecr.io/dash-saichallenger-client-bldr:221228 ENV SAI_CHALLENGER_PATH /sai-challenger ENV DASH_PATH /dash @@ -20,7 +20,6 @@ RUN cd /saithrift-0.9 && \ rm -rf thrift-0.11.0 && \ cd /SAI/test/ptf && \ python3 setup.py install && \ - ln -s ${SAI_CHALLENGER_PATH} /usr/local/lib/python3.7/dist-packages/saichallenger && \ ln -s ${DASH_PATH}/test/test-cases/scale/saic ${SAI_CHALLENGER_PATH}/dash_tests CMD ["/usr/bin/supervisord"] diff --git a/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client-bldr b/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client-bldr index 74ac210d1..ce25999f3 100644 --- a/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client-bldr +++ b/dash-pipeline/dockerfiles/Dockerfile.saichallenger-client-bldr @@ -1,3 +1,4 @@ +# Requires or something FROM sc-client ADD tests/ /tests/ diff --git a/test/SAI-Challenger b/test/SAI-Challenger index e1f1d5bac..8e608c147 160000 --- a/test/SAI-Challenger +++ b/test/SAI-Challenger @@ -1 +1 @@ -Subproject commit e1f1d5bac518f92dae4d0700931e65a280c7bb99 +Subproject commit 8e608c147442ca92777b32a12867ab9f195ea64e diff --git a/test/test-cases/functional/saic/conftest.py b/test/test-cases/functional/saic/conftest.py index bbd92ecee..e5b67b19d 100644 --- a/test/test-cases/functional/saic/conftest.py +++ b/test/test-cases/functional/saic/conftest.py @@ -1,49 +1,74 @@ -import logging +import os import pytest + +curdir = os.path.dirname(os.path.realpath(__file__)) + from saichallenger.common.sai_dpu import SaiDpu -from saichallenger.common.sai_environment import init_setup +from saichallenger.common.sai_testbed import SaiTestbed def pytest_addoption(parser): parser.addoption("--traffic", action="store_true", default=False, help="run tests with traffic") - parser.addoption("--loglevel", action="store", default='NOTICE', help="syncd logging level") parser.addoption("--setup", action="store", default=None, help="Setup description (Path to the json file).") @pytest.fixture(scope="session") def exec_params(request): - config_param = {} - config_param["setup"] = init_setup(request.config) - config_param["traffic"] = request.config.getoption("--traffic") - config_param["loglevel"] = request.config.getoption("--loglevel") - logging.getLogger().setLevel(getattr(logging, config_param["loglevel"].upper(), "INFO")) + config_param = { + # Generic parameters + "traffic": request.config.getoption("--traffic"), + "testbed": request.config.getoption("--setup"), + } return config_param @pytest.fixture(scope="session") -def dpu(exec_params) -> SaiDpu: - dpu = exec_params["setup"]["DPU"][0] - if dpu is not None: - dpu.reset() - return dpu +def testbed_instance(exec_params): + testbed_json = exec_params.get("testbed", None) + if testbed_json is None: + yield None + else: + testbed = SaiTestbed(f"{curdir}/../..", testbed_json, exec_params["traffic"]) + testbed.init() + yield testbed + testbed.deinit() + + +@pytest.fixture(scope="function") +def testbed(testbed_instance): + if testbed_instance: + testbed_instance.setup() + yield testbed_instance + testbed_instance.teardown() + else: + yield None @pytest.fixture(scope="session") -def dataplane_session(exec_params): - dataplane = exec_params["setup"]["DATAPLANE"][0] - # Set up the dataplane - dataplane.init() - yield dataplane - # Shutdown the dataplane - dataplane.remove() +def dpu(exec_params, testbed_instance) -> SaiDpu: + if len(testbed_instance.dpu) == 1: + return testbed_instance.dpu[0] + return None + + +@pytest.fixture(scope="session") +def dataplane_instance(testbed_instance): + if len(testbed_instance.dataplane) == 1: + yield testbed_instance.dataplane[0] + else: + yield None @pytest.fixture(scope="session") def confgen(): return dpugen.sai.SaiConfig() + @pytest.fixture(scope="function") -def dataplane(dataplane_session): - dataplane_session.setUp() - yield dataplane_session - dataplane_session.tearDown() +def dataplane(dataplane_instance): + if dataplane_instance: + dataplane_instance.setup() + yield dataplane_instance + dataplane_instance.teardown() + else: + yield None diff --git a/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json b/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json index 80c55496a..585c91ca8 100755 --- a/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json +++ b/test/test-cases/functional/saic/sai_dpu_client_server_ptf.json @@ -1,41 +1,30 @@ -{"DPU": [ - { - "alias": "dash", - "asic": "generic", - "target": "bmv2", - "type": null, - "sku": null, - "mode": "client-server", - "sai_server_ip": "127.0.0.1", - "client": { +{ + "dpu": [ + { + "alias": "dash", + "asic": "generic", + "target": "bmv2", + "sku": null, + "client": { "type": "thrift", "config": { - "ip": "127.0.0.1", - "port": "9092" + "ip": "127.0.0.1", + "port": "9092" } - }, - "port_groups": [{"1x10G": "Ethernet0", "init": "1x10G", "alias": 0}, - {"1x10G": "Ethernet1", "init": "1x10G", "alias": 1} - ], - "sai_dataplane": "ptf_nn" - } -], + } + } + ], -"DATAPLANE": [ - { - "alias": "ptf", - "type": "ptf", - "mode": "eth", - "port_groups": [{"10G": "veth1", "init": "10G", "alias": 0}, - {"10G": "veth2", "init": "10G", "alias": 1} - ] - } -], - -"CONNECTIONS": { - "ptf->dash": [[0, 0], - [1, 1] - ] -} + "dataplane": [ + { + "alias": "ptf", + "type": "ptf", + "mode": "eth", + "port_groups": [ + {"alias": 0, "name": "veth1"}, + {"alias": 1, "name": "veth2"} + ] + } + ] } diff --git a/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json b/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json index 67abe70e4..035743583 100755 --- a/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json +++ b/test/test-cases/functional/saic/sai_dpu_client_server_snappi.json @@ -1,42 +1,31 @@ -{"DPU": [ - { - "alias": "dash", - "asic": "generic", - "target": "bmv2", - "type": null, - "sku": null, - "mode": "client-server", - "sai_server_ip": "127.0.0.1", - "client": { +{ + "dpu": [ + { + "alias": "dash", + "asic": "generic", + "target": "bmv2", + "sku": null, + "client": { "type": "thrift", "config": { - "ip": "127.0.0.1", - "port": "9092" + "ip": "127.0.0.1", + "port": "9092" } - }, - "port_groups": [{"1x10G": "Ethernet0", "init": "1x10G", "alias": 0}, - {"1x10G": "Ethernet1", "init": "1x10G", "alias": 1} - ], - "sai_dataplane": "ptf_nn" - } -], + } + } + ], -"DATAPLANE": [ - { - "alias": "ixia", - "type": "snappi", - "mode": "ixia_c", - "controller": "https://127.0.0.1:443", - "port_groups": [{"10G": "veth1", "init": "10G", "alias": 0}, - {"10G": "veth3", "init": "10G", "alias": 1} - ] - } -], - -"CONNECTIONS": { - "ixia->dash": [[0, 0], - [1, 1] - ] -} + "dataplane": [ + { + "alias": "ixia", + "type": "snappi", + "mode": "ixia_c", + "controller": "https://127.0.0.1:443", + "port_groups": [ + {"alias": 0, "name": "veth1", "speed": "10G"}, + {"alias": 1, "name": "veth3", "speed": "10G"} + ] + } + ] } diff --git a/test/test-cases/scale/saic/conftest.py b/test/test-cases/scale/saic/conftest.py index 5832c99dd..e5b67b19d 100644 --- a/test/test-cases/scale/saic/conftest.py +++ b/test/test-cases/scale/saic/conftest.py @@ -1,49 +1,74 @@ -import logging +import os import pytest + +curdir = os.path.dirname(os.path.realpath(__file__)) + from saichallenger.common.sai_dpu import SaiDpu -from saichallenger.common.sai_environment import init_setup +from saichallenger.common.sai_testbed import SaiTestbed def pytest_addoption(parser): parser.addoption("--traffic", action="store_true", default=False, help="run tests with traffic") - parser.addoption("--loglevel", action="store", default='NOTICE', help="syncd logging level") parser.addoption("--setup", action="store", default=None, help="Setup description (Path to the json file).") @pytest.fixture(scope="session") def exec_params(request): - config_param = {} - config_param["setup"] = init_setup(request.config) - config_param["traffic"] = request.config.getoption("--traffic") - config_param["loglevel"] = request.config.getoption("--loglevel") - logging.getLogger().setLevel(getattr(logging, config_param["loglevel"].upper(), "INFO")) + config_param = { + # Generic parameters + "traffic": request.config.getoption("--traffic"), + "testbed": request.config.getoption("--setup"), + } return config_param @pytest.fixture(scope="session") -def dpu(exec_params) -> SaiDpu: - dpu = exec_params["setup"]["DPU"][0] - if dpu is not None: - dpu.reset() - return dpu +def testbed_instance(exec_params): + testbed_json = exec_params.get("testbed", None) + if testbed_json is None: + yield None + else: + testbed = SaiTestbed(f"{curdir}/../..", testbed_json, exec_params["traffic"]) + testbed.init() + yield testbed + testbed.deinit() + + +@pytest.fixture(scope="function") +def testbed(testbed_instance): + if testbed_instance: + testbed_instance.setup() + yield testbed_instance + testbed_instance.teardown() + else: + yield None + + +@pytest.fixture(scope="session") +def dpu(exec_params, testbed_instance) -> SaiDpu: + if len(testbed_instance.dpu) == 1: + return testbed_instance.dpu[0] + return None @pytest.fixture(scope="session") -def dataplane_session(exec_params): - dataplane = exec_params["setup"]["DATAPLANE"][0] - # Set up the dataplane - dataplane.init() - yield dataplane - # Shutdown the dataplane - dataplane.remove() +def dataplane_instance(testbed_instance): + if len(testbed_instance.dataplane) == 1: + yield testbed_instance.dataplane[0] + else: + yield None @pytest.fixture(scope="session") def confgen(): return dpugen.sai.SaiConfig() - + + @pytest.fixture(scope="function") -def dataplane(dataplane_session): - dataplane_session.setUp() - yield dataplane_session - dataplane_session.tearDown() +def dataplane(dataplane_instance): + if dataplane_instance: + dataplane_instance.setup() + yield dataplane_instance + dataplane_instance.teardown() + else: + yield None diff --git a/test/test-cases/scale/saic/dash_helper/vnet2vnet_helper.py b/test/test-cases/scale/saic/dash_helper/vnet2vnet_helper.py index d7cb53ce4..4ae3fe26f 100644 --- a/test/test-cases/scale/saic/dash_helper/vnet2vnet_helper.py +++ b/test/test-cases/scale/saic/dash_helper/vnet2vnet_helper.py @@ -1,5 +1,5 @@ import snappi -import saichallenger.dataplane.traffic_utils as tu +import saichallenger.common.sai_dataplane.utils.traffic_utils as tu from collections import namedtuple diff --git a/test/test-cases/scale/saic/sai_dpu_client_server_ptf.json b/test/test-cases/scale/saic/sai_dpu_client_server_ptf.json index 80c55496a..585c91ca8 100755 --- a/test/test-cases/scale/saic/sai_dpu_client_server_ptf.json +++ b/test/test-cases/scale/saic/sai_dpu_client_server_ptf.json @@ -1,41 +1,30 @@ -{"DPU": [ - { - "alias": "dash", - "asic": "generic", - "target": "bmv2", - "type": null, - "sku": null, - "mode": "client-server", - "sai_server_ip": "127.0.0.1", - "client": { +{ + "dpu": [ + { + "alias": "dash", + "asic": "generic", + "target": "bmv2", + "sku": null, + "client": { "type": "thrift", "config": { - "ip": "127.0.0.1", - "port": "9092" + "ip": "127.0.0.1", + "port": "9092" } - }, - "port_groups": [{"1x10G": "Ethernet0", "init": "1x10G", "alias": 0}, - {"1x10G": "Ethernet1", "init": "1x10G", "alias": 1} - ], - "sai_dataplane": "ptf_nn" - } -], + } + } + ], -"DATAPLANE": [ - { - "alias": "ptf", - "type": "ptf", - "mode": "eth", - "port_groups": [{"10G": "veth1", "init": "10G", "alias": 0}, - {"10G": "veth2", "init": "10G", "alias": 1} - ] - } -], - -"CONNECTIONS": { - "ptf->dash": [[0, 0], - [1, 1] - ] -} + "dataplane": [ + { + "alias": "ptf", + "type": "ptf", + "mode": "eth", + "port_groups": [ + {"alias": 0, "name": "veth1"}, + {"alias": 1, "name": "veth2"} + ] + } + ] } diff --git a/test/test-cases/scale/saic/sai_dpu_client_server_snappi.json b/test/test-cases/scale/saic/sai_dpu_client_server_snappi.json index 67abe70e4..035743583 100755 --- a/test/test-cases/scale/saic/sai_dpu_client_server_snappi.json +++ b/test/test-cases/scale/saic/sai_dpu_client_server_snappi.json @@ -1,42 +1,31 @@ -{"DPU": [ - { - "alias": "dash", - "asic": "generic", - "target": "bmv2", - "type": null, - "sku": null, - "mode": "client-server", - "sai_server_ip": "127.0.0.1", - "client": { +{ + "dpu": [ + { + "alias": "dash", + "asic": "generic", + "target": "bmv2", + "sku": null, + "client": { "type": "thrift", "config": { - "ip": "127.0.0.1", - "port": "9092" + "ip": "127.0.0.1", + "port": "9092" } - }, - "port_groups": [{"1x10G": "Ethernet0", "init": "1x10G", "alias": 0}, - {"1x10G": "Ethernet1", "init": "1x10G", "alias": 1} - ], - "sai_dataplane": "ptf_nn" - } -], + } + } + ], -"DATAPLANE": [ - { - "alias": "ixia", - "type": "snappi", - "mode": "ixia_c", - "controller": "https://127.0.0.1:443", - "port_groups": [{"10G": "veth1", "init": "10G", "alias": 0}, - {"10G": "veth3", "init": "10G", "alias": 1} - ] - } -], - -"CONNECTIONS": { - "ixia->dash": [[0, 0], - [1, 1] - ] -} + "dataplane": [ + { + "alias": "ixia", + "type": "snappi", + "mode": "ixia_c", + "controller": "https://127.0.0.1:443", + "port_groups": [ + {"alias": 0, "name": "veth1", "speed": "10G"}, + {"alias": 1, "name": "veth3", "speed": "10G"} + ] + } + ] } diff --git a/test/test-cases/scale/saic/test_sai_vnet_inbound.py b/test/test-cases/scale/saic/test_sai_vnet_inbound.py index 30fccdd2b..d71488462 100644 --- a/test/test-cases/scale/saic/test_sai_vnet_inbound.py +++ b/test/test-cases/scale/saic/test_sai_vnet_inbound.py @@ -7,10 +7,10 @@ from pprint import pprint import pytest -from saichallenger.dataplane.ptf_testutils import (send_packet, - simple_udp_packet, - simple_vxlan_packet, - verify_packet) +from saichallenger.common.sai_dataplane.utils.ptf_testutils import (send_packet, + simple_udp_packet, + simple_vxlan_packet, + verify_packet) current_file_dir = Path(__file__).parent diff --git a/test/test-cases/scale/saic/test_sai_vnet_outbound_scale.py b/test/test-cases/scale/saic/test_sai_vnet_outbound_scale.py index 3b9e1a242..d282fb4b2 100755 --- a/test/test-cases/scale/saic/test_sai_vnet_outbound_scale.py +++ b/test/test-cases/scale/saic/test_sai_vnet_outbound_scale.py @@ -29,7 +29,7 @@ from pprint import pprint import pytest -import saichallenger.dataplane.snappi.snappi_traffic_utils as stu +import saichallenger.common.sai_dataplane.snappi.snappi_traffic_utils as stu import dash_helper.vnet2vnet_helper as dh current_file_dir = Path(__file__).parent diff --git a/test/test-cases/scale/saic/test_sai_vnet_outbound_simple.py b/test/test-cases/scale/saic/test_sai_vnet_outbound_simple.py index 38f2d352f..effc17dfe 100644 --- a/test/test-cases/scale/saic/test_sai_vnet_outbound_simple.py +++ b/test/test-cases/scale/saic/test_sai_vnet_outbound_simple.py @@ -4,12 +4,12 @@ from pprint import pprint import pytest -import saichallenger.dataplane.snappi.snappi_traffic_utils as stu -from saichallenger.dataplane.ptf_testutils import (send_packet, - simple_udp_packet, - simple_vxlan_packet, - verify_no_other_packets, - verify_packet) +import saichallenger.common.sai_dataplane.snappi.snappi_traffic_utils as stu +from saichallenger.common.sai_dataplane.utils.ptf_testutils import (send_packet, + simple_udp_packet, + simple_vxlan_packet, + verify_no_other_packets, + verify_packet) import dash_helper.vnet2vnet_helper as dh From 5d8744ce4e453a786fd034828a8dcb6b5e65aec6 Mon Sep 17 00:00:00 2001 From: Anton Putria Date: Fri, 6 Jan 2023 21:41:41 +0200 Subject: [PATCH 5/5] Dash ENI create/remove tests (#293) * Added ENI test cases and utils modules. saidasheni.py: - test module with ENI creation/deletion and scale verification sai_dash_utils.py: - added classes for storing test configuration - added mixin class with traffic verification methods - fixed VnetAPI issues saidashvnet.py: - moved VnetObjects and VnetAPI to a separate file sai_dash_utils.py Signed-off-by: Yuriy Harhas * Skipped tests that are not applicable for BMv2. Signed-off-by: Anton Putria * Fixed CreateDeleteEniTest and EniScaleTest Signed-off-by: Yuriy Harhas * saidasheni: Updated EniScaleTest Signed-off-by: Yuriy Harhas Signed-off-by: Yuriy Harhas Signed-off-by: Anton Putria Co-authored-by: Yuriy Harhas --- test/docs/testplans/eni.md | 85 ++ test/test-cases/functional/ptf/saidasheni.py | 1126 ++++++++++++++++++ 2 files changed, 1211 insertions(+) create mode 100644 test/docs/testplans/eni.md create mode 100644 test/test-cases/functional/ptf/saidasheni.py diff --git a/test/docs/testplans/eni.md b/test/docs/testplans/eni.md new file mode 100644 index 000000000..09cb750bd --- /dev/null +++ b/test/docs/testplans/eni.md @@ -0,0 +1,85 @@ +# Table of content + +1. [Objectives](#objectives) +2. [Requirements](#requirements) +3. [Automation](#automation) +4. [Test Suites](#test-suites) + - [ENI creation](#eni-creation) + - [ENI removal](#eni-removal) + - [ENI scale](#eni-scale) + +--- + +# Objectives + +Verify proper CRUD API operations and scaling for Elastic Network Interface (ENI). + +# Requirements + +| Item | Expected value | +|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ENI per card | 64 | +| Bulk operations | Yes | +| Admin state | When the ENI is admin-state down, the packets destined to this ENI shall be dropped. | +| Remove | - During ENI delete, implementation must support ability to delete all mappings or routes in a single API call.
- Deleting an object that doesn't exists shall not return an error and shall not perform any force-deletions or delete dependencies implicitly. Sonic implementation shall validate the entire API as pre-checks before applying and return accordingly | +| Memory | Flexible memory allocation for ENI and not reserve max scale during initial create. (To allow oversubscription) | +| Error handling | Implementation must not have silent failures for APIs. | + +# Automation + +Test cases are automated using SAI PTF test framework. + +# Test suites + +## ENI creation + +Verifies create operations, an association with VNI, MAC. + +| # | Test case | Test Class.Method | +|-----|---------------------------------------------------------------|---------------------------------------------------------------------------------------------------| +| 1 | create inbound/outbound DASH ACL groups entries | `CreateDeleteEniTest.createInOutAclGroupsTest` | +| 2 | create VNET entry | `CreateDeleteEniTest.createVnetTest` | +| 3 | create Direction lookup entry | `CreateDeleteEniTest.createDirectionLookupTest` | +| 4 | create ENI entry | `CreateDeleteEniTest.createEniTest` | +| 5 | create ENI Ether address map entry | `CreateDeleteEniTest.createEniEtherAddressMapTest` | +| 6 | create Inbound routing entry | `CreateDeleteEniTest.createInboundRoutingEntryTest` | +| 7 | create PA validation entry | `CreateDeleteEniTest.createPaValidationTest` | +| 8 | create Outbound routing entry | `CreateDeleteEniTest.createOutboundRoutingEntryTest` | +| 9 | create Outbound CA to PA entry | `CreateDeleteEniTest.createCa2PaEntryTest` | +| 10 | verify DASH ACL Group entry attributes getting/setting | `CreateDeleteEniTest.dashAclGroupAttributesTest` | +| 11 | verify VNET entry attributes getting/setting | `CreateDeleteEniTest.vnetAttributesTest` | +| 12 | verify Direction lookup entry attributes getting/setting | `CreateDeleteEniTest.directionLookupAttributesTest` | +| 13 | verify Inbound routing entry attributes getting/setting | `CreateDeleteEniTest.inboundRoutingEntryAttributesTest` | +| 14 | verify ENI attributes getting/setting | `CreateDeleteEniTest.eniGetAttributesTest`
`CreateDeleteEniTest.eniSetAndGetAttributesTest` | +| 15 | verify ENI Ether address map entry attributes getting/setting | `CreateDeleteEniTest.eniEtherAddressMapAttributesTest` | +| 16 | verify PA validation entry attributes getting/setting | `CreateDeleteEniTest.paValidationEntryAttributesTest` | +| 17 | verify Outbound routing entry attributes getting/setting | `CreateDeleteEniTest.outboundRoutingEntryAttributesTest` | +| 18 | verify Outbound CA to PA entry attributes getting/setting | `CreateDeleteEniTest.outboundCa2PaEntryAttributesTest` | + +## ENI removal + +Verifies remove operations. + +| # | Test case | Test Class.Method | +|-----|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| +| 1 | normal delete:
verify deletion of: inbound/outbound DASH ACL groups, VNET, ENI, ENI Ether address map entry, PA validation entry, inbound/outbound routing entry | Is a part of `CreateDeleteEniTest.destroy_teardown_obj` | +| 2 | error if mapped rules exist:
verify VNET cannot be deleted when map exist | `CreateDeleteEniTest.deleteVnetWhenMapExistTest` | +| 3 | duplicated deletion
no errors expected | Is a part of `CreateDeleteEniTest.destroy_teardown_obj` | +| 4 | ENI deletion when map exists: no errors, related entries also deleted(To clarify: list of entries that must be deleted) | `CreateDeleteEniTest.deleteEniWhenMapExistTest` | +| 5 | normal bulk delete | - | +| 6 | bulk delete does not remove any if there is a mapping for some ENI | - | + +## ENI scale. + +Verifies basic ENI scale, create/remove/recreate maximum number of ENIs . + +| # | Test case | Test Class.Method | +|-----|------------------------------------------------------------------|-----------------------------| +| 1 | Create/remove a max number of ENI entries | `EniScaleTest.eniScaleTest` | +| 2 | Recreate (repeated creation/removal a max number of ENI entries) | `EniScaleTest.eniScaleTest` | + +## ENI negative + +| # | Test case purpose | Test Class.Method | Test description | +|:---:|:---------------------------------------------------------------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------| +| 1 | Verifies failure in case of creation the same ENIs in one VNET | `CreateTwoSameEnisNegativeTest`.
`enisCreationTest` | Create two same ENIs in the single VNET and verify creation failure.
**To clarify:** exact step to expect failure | diff --git a/test/test-cases/functional/ptf/saidasheni.py b/test/test-cases/functional/ptf/saidasheni.py new file mode 100644 index 000000000..115b28997 --- /dev/null +++ b/test/test-cases/functional/ptf/saidasheni.py @@ -0,0 +1,1126 @@ +# Copyright 2022-present Intel Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Thrift SAI interface ENI tests +""" + +from unittest import skipIf + +from ptf.testutils import test_param_get +from sai_dash_utils import * +from sai_thrift.sai_headers import * + + +class CreateDeleteEniTest(VnetAPI): + """ + Verifies ENI creation/deletion and association with MAC and VNI + + Configuration: + Empty configuration + """ + + def setUp(self): + super(CreateDeleteEniTest, self).setUp() + + self.cps = 10000 # ENI connections per second + self.pps = 100000 # ENI packets per seconds + self.flows = 100000 # ENI flows + self.admin_state = True # ENI admin state + self.vm_vni = 10 # ENI VM VNI + self.eni_mac = '00:11:22:33:44:55' # ENI MAC address + self.vm_underlay_dip = sai_ipaddress('192.168.1.5') # ENI VM underlay DIP + + self.sip = '10.0.1.2' # PA validation entry SIP address + + def runTest(self): + # Not all tests are interdependent, + # so they must be run in the following sequence: + + # Create verification + self.createInOutAclGroupsTest() + self.createVnetTest() + self.createDirectionLookupTest() + self.createEniTest() + self.createEniEtherAddressMapTest() + if not test_param_get('bmv2'): + # Issue #233 + self.createInboundRoutingEntryTest() + self.createPaValidationTest() + self.createOutboundRoutingEntryTest() + self.createCa2PaEntryTest() + + # Attributes verification + if not test_param_get('bmv2'): + # TODO: add issue + self.dashAclGroupAttributesTest() + self.vnetAttributesTest() + self.directionLookupAttributesTest() + self.eniGetAttributesTest() + self.eniSetAndGetAttributesTest() + self.eniEtherAddressMapAttributesTest() + self.inboundRoutingEntryAttributesTest() + self.paValidationEntryAttributesTest() + self.outboundRoutingEntryAttributesTest() + self.outboundCa2PaEntryAttributesTest() + + # Remove verification + if not test_param_get('bmv2'): + # TODO: add issue + self.deleteVnetWhenMapExistTest() + self.deleteEniWhenMapExistTest() + # verify all entries can be removed with status success + self.destroy_teardown_obj() + # clear teardown_objects not to remove all entries again in tearDown + self.teardown_objects.clear() + + def tearDown(self): + super(CreateDeleteEniTest, self).tearDown() + + def createInOutAclGroupsTest(self): + """ + Verifies ACL groups creation needed for ENI creation + + Note: test should be run before createEniTest + """ + + self.in_acl_group_id = self.dash_acl_group_create() + self.out_acl_group_id = self.dash_acl_group_create() + + def createVnetTest(self): + """ + Verifies VNET creation + + Note: test should be run before createEniTest + """ + + # vnet for ENI creation + self.vm_vnet = self.vnet_create(vni=self.vm_vni) + + # src_vnet for Inbound routing entry + self.outbound_vnet = self.vnet_create(vni=10000) + + def createDirectionLookupTest(self): + """ + Verifies Direction Lookup creation + """ + self.dir_lookup = self.direction_lookup_create(vni=self.outbound_vnet) + + def createEniTest(self): + """ + Verifies ENI entry creation + + Note: ENI entry deletion is in deleteEniTest + """ + + self.eni = self.eni_create(cps=self.cps, + pps=self.pps, + flows=self.flows, + admin_state=self.admin_state, + vm_underlay_dip=self.vm_underlay_dip, + vm_vni=self.vm_vni, + vnet_id=self.vm_vnet, + inbound_v4_stage1_dash_acl_group_id=self.in_acl_group_id, + inbound_v4_stage2_dash_acl_group_id=self.in_acl_group_id, + inbound_v4_stage3_dash_acl_group_id=self.in_acl_group_id, + inbound_v4_stage4_dash_acl_group_id=self.in_acl_group_id, + inbound_v4_stage5_dash_acl_group_id=self.in_acl_group_id, + outbound_v4_stage1_dash_acl_group_id=self.out_acl_group_id, + outbound_v4_stage2_dash_acl_group_id=self.out_acl_group_id, + outbound_v4_stage3_dash_acl_group_id=self.out_acl_group_id, + outbound_v4_stage4_dash_acl_group_id=self.out_acl_group_id, + outbound_v4_stage5_dash_acl_group_id=self.out_acl_group_id, + inbound_v6_stage1_dash_acl_group_id=0, + inbound_v6_stage2_dash_acl_group_id=0, + inbound_v6_stage3_dash_acl_group_id=0, + inbound_v6_stage4_dash_acl_group_id=0, + inbound_v6_stage5_dash_acl_group_id=0, + outbound_v6_stage1_dash_acl_group_id=0, + outbound_v6_stage2_dash_acl_group_id=0, + outbound_v6_stage3_dash_acl_group_id=0, + outbound_v6_stage4_dash_acl_group_id=0, + outbound_v6_stage5_dash_acl_group_id=0) + + def createEniEtherAddressMapTest(self): + """ + Verifies Eni Ether Address Map entry creation + + Note: test should be run after createEniTest + """ + + self.eni_mac_map_entry = self.eni_mac_map_create(eni_id=self.eni, + mac=self.eni_mac) + + def createInboundRoutingEntryTest(self): + """ + Verifies Inbound routing entry creation + + Note: test should be run after createEniTest + """ + + self.inbound_routing_entry = self.inbound_routing_decap_validate_create( + eni_id=self.eni, vni=self.vm_vni, + sip=self.sip, sip_mask="255.255.255.0", + src_vnet_id=self.outbound_vnet + ) + + def createPaValidationTest(self): + """ + Verifies PA validation entry creation + + Note: test should be run after createEniTest + """ + + self.pa_valid_entry = self.pa_validation_create(sip=self.sip, + vnet_id=self.outbound_vnet) + + def createOutboundRoutingEntryTest(self): + """ + Verifies Outbound routing entry creation + + Note: test should be run after createEniTest + """ + self.overlay_ip = "192.168.2.22" + + self.outbound_routing_entry = self.outbound_routing_vnet_direct_create( + eni_id=self.eni, + lpm="192.168.2.0/24", + dst_vnet_id=self.outbound_vnet, + overlay_ip=self.overlay_ip) + # TODO: add counter + + def createCa2PaEntryTest(self): + """ + Verifies Outbound CA to PA entry creation + + Note: test should be run after createOutboundRoutingEntryTest + """ + + self.underlay_dip = '192.168.10.10' + self.overlay_dmac = '55:44:33:22:11:00' + + self.ca_to_pa_entry = self.outbound_ca_to_pa_create( + dst_vnet_id=self.outbound_vnet, + dip=self.overlay_ip, + underlay_dip=self.underlay_dip, + overlay_dmac=self.overlay_dmac, + use_dst_vnet_vni=True + ) + # TODO: add counter + + def dashAclGroupAttributesTest(self): + """ + Verifies getting and setting Dash ACL group entry attributes + + Note: createInOutAclGroupsTest should be run first + """ + # verify Dash ACL group entry original attributes + attr = sai_thrift_get_dash_acl_group_attribute(self.client, + self.in_acl_group_id, + ip_addr_family=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['ip_addr_family'], SAI_IP_ADDR_FAMILY_IPV4) + + # set and verify new values + try: + sai_thrift_set_dash_acl_group_attribute(self.client, + self.in_acl_group_id, + ip_addr_family=SAI_IP_ADDR_FAMILY_IPV6) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + attr = sai_thrift_get_dash_acl_group_attribute(self.client, + self.in_acl_group_id, + ip_addr_family=True) + self.assertEqual(attr['ip_addr_family'], SAI_IP_ADDR_FAMILY_IPV6) + finally: + # set original value + sai_thrift_set_dash_acl_group_attribute(self.client, + self.in_acl_group_id, + ip_addr_family=SAI_IP_ADDR_FAMILY_IPV4) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + attr = sai_thrift_get_dash_acl_group_attribute(self.client, + self.in_acl_group_id, + ip_addr_family=True) + self.assertEqual(attr['ip_addr_family'], SAI_IP_ADDR_FAMILY_IPV4) + + def vnetAttributesTest(self): + """ + Verifies getting and setting VNET entry attributes + + Note: createVnetTest should be run first + """ + # verify VNET entry original attributes + attr = sai_thrift_get_vnet_attribute(self.client, + self.vm_vnet, + vni=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['vni'], self.vm_vni) + + # set and verify new values + test_vni = 632 + try: + sai_thrift_set_vnet_attribute(self.client, + self.vm_vnet, + vni=test_vni) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + attr = sai_thrift_get_vnet_attribute(self.client, + self.vm_vnet, + vni=True) + self.assertEqual(attr['vni'], test_vni) + finally: + # set original value + sai_thrift_set_vnet_attribute(self.client, + self.vm_vnet, + vni=self.vm_vni) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + attr = sai_thrift_get_vnet_attribute(self.client, + self.vm_vnet, + vni=True) + self.assertEqual(attr['vni'], self.vm_vni) + + def directionLookupAttributesTest(self): + """ + Verifies getting Direction lookup entry attributes + + Note: createDirectionLookupTest should be run first + """ + # verify Direction lookup entry original attributes + attr = sai_thrift_get_direction_lookup_entry_attribute(self.client, + self.dir_lookup, + action=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['action'], SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION) + + # setting new value cannot be verified as only one action + # for direction lookup is available (SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION) + + def eniGetAttributesTest(self): + """ + Verifies getting ENI entry attributes + + Note: createEniTest should be run first to create ENI entry + """ + # verify attributes initially created ENI + attr = sai_thrift_get_eni_attribute(self.client, + self.eni, + cps=True, + pps=True, + flows=True, + admin_state=True, + vm_underlay_dip=True, + vm_vni=True, + vnet_id=True, + inbound_v4_stage1_dash_acl_group_id=True, + inbound_v4_stage2_dash_acl_group_id=True, + inbound_v4_stage3_dash_acl_group_id=True, + inbound_v4_stage4_dash_acl_group_id=True, + inbound_v4_stage5_dash_acl_group_id=True, + inbound_v6_stage1_dash_acl_group_id=True, + inbound_v6_stage2_dash_acl_group_id=True, + inbound_v6_stage3_dash_acl_group_id=True, + inbound_v6_stage4_dash_acl_group_id=True, + inbound_v6_stage5_dash_acl_group_id=True, + outbound_v4_stage1_dash_acl_group_id=True, + outbound_v4_stage2_dash_acl_group_id=True, + outbound_v4_stage3_dash_acl_group_id=True, + outbound_v4_stage4_dash_acl_group_id=True, + outbound_v4_stage5_dash_acl_group_id=True, + outbound_v6_stage1_dash_acl_group_id=True, + outbound_v6_stage2_dash_acl_group_id=True, + outbound_v6_stage3_dash_acl_group_id=True, + outbound_v6_stage4_dash_acl_group_id=True, + outbound_v6_stage5_dash_acl_group_id=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + self.assertEqual(attr['cps'], self.cps) + self.assertEqual(attr['pps'], self.pps) + self.assertEqual(attr['flows'], self.flows) + self.assertEqual(attr['admin_state'], self.admin_state) + self.assertEqual(attr['vm_underlay_dip'], self.vm_underlay_dip.addr.ip4) + self.assertEqual(attr['vm_vni'], self.vm_vni) + self.assertEqual(attr['vnet_id'], self.vm_vnet) + self.assertEqual(attr['inbound_v4_stage1_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage2_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage3_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage4_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage5_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v6_stage1_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage2_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage3_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage4_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage5_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v4_stage1_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage2_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage3_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage4_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage5_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v6_stage1_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage2_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage3_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage4_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage5_dash_acl_group_id'], 0) + + def eniSetAndGetAttributesTest(self): + """ + Verifies setting ENI entry attributes + + Note: createEniTest should be run first to create ENI entry + """ + + test_cps = self.cps * 2 + test_pps = self.pps * 2 + test_flows = self.flows * 2 + test_admin_state = False + test_vm_vni = 5 + + test_vm_underlay_dip = sai_ipaddress('172.2.1.5') + + test_vnet = self.vnet_create(vni=test_vm_vni) + + test_ipv6_in_acl_group_id = self.dash_acl_group_create(ipv6=True) + test_ipv6_out_acl_group_id = self.dash_acl_group_create(ipv6=True) + + try: + # set and verify new cps value + sai_thrift_set_eni_attribute(self.client, self.eni, cps=test_cps) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, cps=True) + self.assertEqual(attr['cps'], test_cps) + + # set and verify new pps value + sai_thrift_set_eni_attribute(self.client, self.eni, pps=test_pps) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, pps=True) + self.assertEqual(attr['pps'], test_pps) + + # set and verify new flow value + sai_thrift_set_eni_attribute(self.client, self.eni, flows=test_flows) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, flows=True) + self.assertEqual(attr['flows'], test_flows) + + # set and verify new admin_state value + sai_thrift_set_eni_attribute(self.client, self.eni, admin_state=test_admin_state) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, admin_state=True) + self.assertEqual(attr['admin_state'], test_admin_state) + + # set and verify new vm_underlay_dip value + sai_thrift_set_eni_attribute(self.client, self.eni, vm_underlay_dip=test_vm_underlay_dip) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, vm_underlay_dip=True) + self.assertEqual(attr['vm_underlay_dip'], test_vm_underlay_dip.addr.ip) + + # set and verify new vm_vni value + sai_thrift_set_eni_attribute(self.client, self.eni, vm_vni=test_vm_vni) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, vm_vni=True) + self.assertEqual(attr['vm_vni'], test_vm_vni) + + # set and verify new vnet_id value + sai_thrift_set_eni_attribute(self.client, self.eni, vnet_id=test_vnet) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, vnet_id=True) + self.assertEqual(attr['vnet_id'], test_vnet) + + # set and verify new inbound_v4_stage1_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v4_stage1_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v4_stage1_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v4_stage1_dash_acl_group_id'], 0) + + # set and verify new inbound_v4_stage2_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v4_stage2_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v4_stage2_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v4_stage2_dash_acl_group_id'], 0) + + # set and verify new inbound_v4_stage3_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v4_stage3_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v4_stage3_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v4_stage3_dash_acl_group_id'], 0) + + # set and verify new inbound_v4_stage4_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v4_stage4_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v4_stage4_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v4_stage4_dash_acl_group_id'], 0) + + # set and verify new inbound_v4_stage5_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v4_stage5_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v4_stage5_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v4_stage5_dash_acl_group_id'], 0) + + # set and verify new inbound_v6_stage1_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v6_stage1_dash_acl_group_id=test_ipv6_in_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v6_stage1_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v6_stage1_dash_acl_group_id'], test_ipv6_in_acl_group_id) + + # set and verify new inbound_v6_stage2_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v6_stage2_dash_acl_group_id=test_ipv6_in_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v6_stage2_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v6_stage2_dash_acl_group_id'], test_ipv6_in_acl_group_id) + + # set and verify new inbound_v6_stage3_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v6_stage3_dash_acl_group_id=test_ipv6_in_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v6_stage3_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v6_stage3_dash_acl_group_id'], test_ipv6_in_acl_group_id) + + # set and verify new inbound_v6_stage4_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v6_stage4_dash_acl_group_id=test_ipv6_in_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v6_stage4_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v6_stage4_dash_acl_group_id'], test_ipv6_in_acl_group_id) + + # set and verify new inbound_v6_stage5_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v6_stage5_dash_acl_group_id=test_ipv6_in_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, inbound_v6_stage5_dash_acl_group_id=True) + self.assertEqual(attr['inbound_v6_stage5_dash_acl_group_id'], test_ipv6_in_acl_group_id) + + # set and verify new outbound_v4_stage1_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v4_stage1_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v4_stage1_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v4_stage1_dash_acl_group_id'], 0) + + # set and verify new outbound_v4_stage2_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v4_stage2_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v4_stage2_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v4_stage2_dash_acl_group_id'], 0) + + # set and verify new outbound_v4_stage3_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v4_stage3_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v4_stage3_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v4_stage3_dash_acl_group_id'], 0) + + # set and verify new outbound_v4_stage4_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v4_stage4_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v4_stage4_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v4_stage4_dash_acl_group_id'], 0) + + # set and verify new outbound_v4_stage5_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v4_stage5_dash_acl_group_id=0) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v4_stage5_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v4_stage5_dash_acl_group_id'], 0) + + # set and verify new outbound_v6_stage1_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v6_stage1_dash_acl_group_id=test_ipv6_out_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v6_stage1_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v6_stage1_dash_acl_group_id'], test_ipv6_out_acl_group_id) + + # set and verify new outbound_v6_stage2_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v6_stage2_dash_acl_group_id=test_ipv6_out_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v6_stage2_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v6_stage2_dash_acl_group_id'], test_ipv6_out_acl_group_id) + + # set and verify new outbound_v6_stage3_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v6_stage3_dash_acl_group_id=test_ipv6_out_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v6_stage3_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v6_stage3_dash_acl_group_id'], test_ipv6_out_acl_group_id) + + # set and verify new outbound_v6_stage4_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v6_stage4_dash_acl_group_id=test_ipv6_out_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v6_stage4_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v6_stage4_dash_acl_group_id'], test_ipv6_out_acl_group_id) + + # set and verify new outbound_v6_stage5_dash_acl_group_id value + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v6_stage5_dash_acl_group_id=test_ipv6_out_acl_group_id) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_attribute(self.client, self.eni, outbound_v6_stage5_dash_acl_group_id=True) + self.assertEqual(attr['outbound_v6_stage5_dash_acl_group_id'], test_ipv6_out_acl_group_id) + + finally: + # set ENI attributes to the original values + sai_thrift_set_eni_attribute(self.client, self.eni, cps=self.cps) + sai_thrift_set_eni_attribute(self.client, self.eni, pps=self.pps) + sai_thrift_set_eni_attribute(self.client, self.eni, flows=self.flows) + sai_thrift_set_eni_attribute(self.client, self.eni, admin_state=self.admin_state) + sai_thrift_set_eni_attribute(self.client, self.eni, vm_underlay_dip=self.vm_underlay_dip) + sai_thrift_set_eni_attribute(self.client, self.eni, vm_vni=self.vm_vni) + sai_thrift_set_eni_attribute(self.client, self.eni, vnet_id=self.vm_vnet) + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v4_stage1_dash_acl_group_id=self.in_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v4_stage2_dash_acl_group_id=self.in_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v4_stage3_dash_acl_group_id=self.in_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v4_stage4_dash_acl_group_id=self.in_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + inbound_v4_stage5_dash_acl_group_id=self.in_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v6_stage1_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v6_stage2_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v6_stage3_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v6_stage4_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, inbound_v6_stage5_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v4_stage1_dash_acl_group_id=self.out_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v4_stage2_dash_acl_group_id=self.out_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v4_stage3_dash_acl_group_id=self.out_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v4_stage4_dash_acl_group_id=self.out_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, + outbound_v4_stage5_dash_acl_group_id=self.out_acl_group_id) + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v6_stage1_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v6_stage2_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v6_stage3_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v6_stage4_dash_acl_group_id=0) + sai_thrift_set_eni_attribute(self.client, self.eni, outbound_v6_stage5_dash_acl_group_id=0) + + attr = sai_thrift_get_eni_attribute(self.client, + self.eni, + cps=True, + pps=True, + flows=True, + admin_state=True, + vm_underlay_dip=True, + vm_vni=True, + vnet_id=True, + inbound_v4_stage1_dash_acl_group_id=True, + inbound_v4_stage2_dash_acl_group_id=True, + inbound_v4_stage3_dash_acl_group_id=True, + inbound_v4_stage4_dash_acl_group_id=True, + inbound_v4_stage5_dash_acl_group_id=True, + inbound_v6_stage1_dash_acl_group_id=True, + inbound_v6_stage2_dash_acl_group_id=True, + inbound_v6_stage3_dash_acl_group_id=True, + inbound_v6_stage4_dash_acl_group_id=True, + inbound_v6_stage5_dash_acl_group_id=True, + outbound_v4_stage1_dash_acl_group_id=True, + outbound_v4_stage2_dash_acl_group_id=True, + outbound_v4_stage3_dash_acl_group_id=True, + outbound_v4_stage4_dash_acl_group_id=True, + outbound_v4_stage5_dash_acl_group_id=True, + outbound_v6_stage1_dash_acl_group_id=True, + outbound_v6_stage2_dash_acl_group_id=True, + outbound_v6_stage3_dash_acl_group_id=True, + outbound_v6_stage4_dash_acl_group_id=True, + outbound_v6_stage5_dash_acl_group_id=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + self.assertEqual(attr['cps'], self.cps) + self.assertEqual(attr['pps'], self.pps) + self.assertEqual(attr['flows'], self.flows) + self.assertEqual(attr['admin_state'], self.admin_state) + self.assertEqual(attr['vm_underlay_dip'], self.vm_underlay_dip.addr.ip4) + self.assertEqual(attr['vm_vni'], self.vm_vni) + self.assertEqual(attr['vnet_id'], self.vm_vnet) + self.assertEqual(attr['inbound_v4_stage1_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage2_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage3_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage4_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v4_stage5_dash_acl_group_id'], self.in_acl_group_id) + self.assertEqual(attr['inbound_v6_stage1_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage2_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage3_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage4_dash_acl_group_id'], 0) + self.assertEqual(attr['inbound_v6_stage5_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v4_stage1_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage2_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage3_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage4_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v4_stage5_dash_acl_group_id'], self.out_acl_group_id) + self.assertEqual(attr['outbound_v6_stage1_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage2_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage3_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage4_dash_acl_group_id'], 0) + self.assertEqual(attr['outbound_v6_stage5_dash_acl_group_id'], 0) + + def eniEtherAddressMapAttributesTest(self): + """ + Verifies getting and setting ENI MAC map entry attributes + + Note: createEniTest should be run first to create eni_ether_address_map_entry entry + """ + # verify attributes initially created eni_ether_address_map_entry + attr = sai_thrift_get_eni_ether_address_map_entry_attribute(self.client, + eni_ether_address_map_entry=self.eni_mac_map_entry, + eni_id=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['eni_id'], self.eni) + + try: + # create test eni to verify set method + test_cps = 500 + test_pps = 500 + test_flows = 500 + test_vm_underlay_ip = sai_ipaddress('172.0.15.15') + + test_eni = self.eni(cps=test_cps, + pps=test_pps, + flows=test_flows, + admin_state=True, + vm_underlay_dip=test_vm_underlay_ip, + vm_vni=self.vm_vni, + vnet_id=self.vm_vnet, + inbound_v4_stage1_dash_acl_group_id=0, + inbound_v4_stage2_dash_acl_group_id=0, + inbound_v4_stage3_dash_acl_group_id=0, + inbound_v4_stage4_dash_acl_group_id=0, + inbound_v4_stage5_dash_acl_group_id=0, + outbound_v4_stage1_dash_acl_group_id=0, + outbound_v4_stage2_dash_acl_group_id=0, + outbound_v4_stage3_dash_acl_group_id=0, + outbound_v4_stage4_dash_acl_group_id=0, + outbound_v4_stage5_dash_acl_group_id=0, + inbound_v6_stage1_dash_acl_group_id=0, + inbound_v6_stage2_dash_acl_group_id=0, + inbound_v6_stage3_dash_acl_group_id=0, + inbound_v6_stage4_dash_acl_group_id=0, + inbound_v6_stage5_dash_acl_group_id=0, + outbound_v6_stage1_dash_acl_group_id=0, + outbound_v6_stage2_dash_acl_group_id=0, + outbound_v6_stage3_dash_acl_group_id=0, + outbound_v6_stage4_dash_acl_group_id=0, + outbound_v6_stage5_dash_acl_group_id=0) + + sai_thrift_set_eni_ether_address_map_entry_attribute( + self.client, eni_ether_address_map_entry=self.eni_mac_map_entry, eni_id=test_eni) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_ether_address_map_entry_attribute( + self.client, eni_ether_address_map_entry=self.eni_mac_map_entry, eni_id=True) + self.assertEqual(attr['eni_id'], test_eni) + + finally: + # set map back to original ENI + sai_thrift_set_eni_ether_address_map_entry_attribute( + self.client, eni_ether_address_map_entry=self.eni_mac_map_entry, eni_id=self.eni) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_eni_ether_address_map_entry_attribute( + self.client, eni_ether_address_map_entry=self.eni_mac_map_entry, eni_id=True) + self.assertEqual(attr['eni_id'], self.eni) + + def paValidationEntryAttributesTest(self): + """ + Verifies getting PA validation entry attribute + + Note: setting new attribute value cannot be verified + because PA Validation entry has only 1 attribute value + + Note: createPaValidationTest should be run first to create PA validation entry + """ + + # verify original attributes + attr = sai_thrift_get_pa_validation_entry_attribute(self.client, + pa_validation_entry=self.pa_valid_entry, + action=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['action'], SAI_PA_VALIDATION_ENTRY_ACTION_PERMIT) + + def inboundRoutingEntryAttributesTest(self): + """ + Verifies getting and setting Inbound routing entry attributes + + Note: createInboundRoutingEntryTest should be run first to create Inbound routing entry + """ + + # verify original attributes + attr = sai_thrift_get_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + action=True, + src_vnet_id=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['action'], SAI_INBOUND_ROUTING_ENTRY_ACTION_VXLAN_DECAP_PA_VALIDATE) + self.assertEqual(attr['src_vnet_id'], self.outbound_vnet) + + try: + # set and verify new action + sai_thrift_set_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + action=SAI_INBOUND_ROUTING_ENTRY_ACTION_VXLAN_DECAP) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + action=True) + self.assertEqual(attr['action'], SAI_INBOUND_ROUTING_ENTRY_ACTION_VXLAN_DECAP) + + # set and verify new src_vnet_id value + test_vnet = self.vnet_create(vni=500) + + sai_thrift_set_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + src_vnet_id=test_vnet) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + src_vnet_id=True) + self.assertEqual(attr['src_vnet_id'], test_vnet) + finally: + # set back original attribute value + sai_thrift_set_inbound_routing_entry_attribute( + self.client, + inbound_routing_entry=self.inbound_routing_entry, + action=SAI_INBOUND_ROUTING_ENTRY_ACTION_VXLAN_DECAP_PA_VALIDATE) + sai_thrift_set_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + src_vnet_id=self.outbound_vnet) + + attr = sai_thrift_get_inbound_routing_entry_attribute(self.client, + inbound_routing_entry=self.inbound_routing_entry, + action=True, + src_vnet_id=True) + self.assertEqual(attr['action'], SAI_INBOUND_ROUTING_ENTRY_ACTION_VXLAN_DECAP_PA_VALIDATE) + self.assertEqual(attr['src_vnet_id'], self.outbound_vnet) + + def outboundRoutingEntryAttributesTest(self): + """ + Verifies getting and setting Outbound routing entry attributes + + Note: createOutboundRoutingEntryTest should be run first to create Outbound routing entry + """ + + # verify original attributes + attr = sai_thrift_get_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + action=True, + dst_vnet_id=True, + overlay_ip=True) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['action'], SAI_OUTBOUND_ROUTING_ENTRY_ACTION_ROUTE_VNET_DIRECT) + self.assertEqual(attr['dst_vnet_id'], self.outbound_vnet) + self.assertEqual(attr['overlay_ip'], self.overlay_ip) + # TODO: add get counter verification + + try: + test_action = SAI_OUTBOUND_ROUTING_ENTRY_ACTION_ROUTE_VNET + test_dst_vnet = self.vnet_create(vni=9999) + test_overlay_ip = "9.9.9.9" + + # set and verify new action + sai_thrift_set_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + action=test_action) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + sai_thrift_set_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + dst_vnet_id=test_dst_vnet) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + sai_thrift_set_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + overlay_ip=sai_ipaddress(test_overlay_ip)) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + # verify that all set correct + attr = sai_thrift_get_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + action=True, + dst_vnet_id=True, + overlay_ip=True) + self.assertEqual(attr['action'], test_action) + self.assertEqual(attr['dst_vnet_id'], test_dst_vnet) + self.assertEqual(attr['overlay_ip'], test_overlay_ip) + + finally: + # verify that original values can be set back + sai_thrift_set_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + action=SAI_OUTBOUND_ROUTING_ENTRY_ACTION_ROUTE_VNET_DIRECT) + sai_thrift_set_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + dst_vnet_id=self.outbound_vnet) + sai_thrift_set_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + overlay_ip=self.overlay_ip) + + # verify original attributes + attr = sai_thrift_get_outbound_routing_entry_attribute(self.client, + self.outbound_routing_entry, + action=True, + dst_vnet_id=True, + overlay_ip=True) + self.assertEqual(attr['action'], SAI_OUTBOUND_ROUTING_ENTRY_ACTION_ROUTE_VNET_DIRECT) + self.assertEqual(attr['dst_vnet_id'], self.outbound_vnet) + self.assertEqual(attr['overlay_ip'], self.overlay_ip) + + def outboundCa2PaEntryAttributesTest(self): + """ + Verifies getting and setting Outbound CA to PA entry attributes + + Note: createCa2PaEntryTest should be run first + """ + + # verify original attributes + attr = sai_thrift_get_outbound_ca_to_pa_entry_attribute( + self.client, + self.ca_to_pa_entry, + underlay_dip=True, + overlay_dmac=True, + use_dst_vnet_vni=True + ) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + self.assertEqual(attr['underlay_dip'], self.underlay_dip) + self.assertEqual(attr['overlay_dmac'], self.overlay_dmac) + self.assertEqual(attr['use_dst_vnet_vni'], True) + # TODO: add get counter verification + + test_dip = "10.10.10.1" + test_overlay_dmac = "AA:11:BB:22:CC:33" + + # set and verify new values + sai_thrift_set_outbound_ca_to_pa_entry_attribute(self.client, + self.ca_to_pa_entry, + underlay_dip=sai_ipaddress(test_dip)) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + sai_thrift_set_outbound_ca_to_pa_entry_attribute(self.client, + self.ca_to_pa_entry, + overlay_dmac=test_overlay_dmac) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + sai_thrift_set_outbound_ca_to_pa_entry_attribute(self.client, + self.ca_to_pa_entry, + use_dst_vnet_vni=False) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + attr = sai_thrift_get_outbound_ca_to_pa_entry_attribute( + self.client, + self.ca_to_pa_entry, + underlay_dip=True, + overlay_dmac=True, + use_dst_vnet_vni=True + ) + self.assertEqual(attr['underlay_dip'], test_dip) + self.assertEqual(attr['overlay_dmac'], test_overlay_dmac) + self.assertEqual(attr['use_dst_vnet_vni'], False) + + def deleteVnetWhenMapExistTest(self): + """ + Verifies Vnet entry deletion attempt when mapping with ENI exists + Expect that Vnet entry cannot be deleted + + Note: createVnetTest and createEniTest should be run first + """ + sai_thrift_remove_vnet(self.client, self.vm_vnet) + self.assertEqual(self.status(), SAI_STATUS_OBJECT_IN_USE) + + def deleteEniWhenMapExistTest(self): + """ + Verifies ENI entry deletion when mappings exist + (e.g. vnet, eni_ether_address_map, inbound/outbound routing entries) + Expect that ENI entry and other entries will be deleted successfully + + # TODO: clarify how to verify that other objects also has been deleted + + Note: createEniTest should be run first to create ENI + """ + sai_thrift_remove_eni(self.client, eni_oid=self.eni) + self.assertEqual(self.status(), SAI_STATUS_SUCCESS) + + +@skipIf(test_param_get('bmv2'), "Blocked by Issue #233. Inbound Routing is not supported in BMv2.") +class EniScaleTest(VnetAPI): + """ + Verifies ENI scaling: + - creation/deletion a min required number of ENI entries + - recreation (repeated creation/deletion a min required number of ENI entries) + + Configuration: + Empty configuration + """ + def setUp(self): + super(EniScaleTest, self).setUp() + + self.MIN_ENI = 64 # Expected min number of ENI entries per card + self.vm_vni = 0 # ENI VM VNI (increments during ENIs creation) + self.outbound_vni = 100 # VNI for inbound/outbound routing entries creation + self.vm_underlay_dip = sai_ipaddress("10.10.0.1") + + # Create list with MIN_ENI number of unique MAC addresses for ENI creation + self.eni_mac_list = [] + i = 0 + for last_octet in range(0, 256): + self.eni_mac_list.append('01:01:01:00:00:' + + ('%02x' % last_octet)) + i += 1 + if i == self.MIN_ENI: + break + + def runTest(self): + self.eniScaleTest() + + print("\n\tClear configuration") + self.destroy_teardown_obj() # remove all created entries + self.teardown_objects.clear() # clear teardown_objects to not remove all entries again in tearDown + print("PASS") + + self.vm_vni = 0 # reset values + self.outbound_vni = 100 + + self.eniScaleTest() # verify that the min required number on ENI entries can be created again + + def eniScaleTest(self): + """ + Verifies creating and deleting a min required number of ENI entries. + Also creates: vnet, inbound and outbound dash acl groups, eni ether address map entries, + outbound and inbound routing entries. + + Min required number of ENI entries hardcoded in MIN_ENI value. + """ + + print(f"\n\tEni Scale Test") + + for indx in range(self.MIN_ENI): + try: + # create ACL groups for ENI + in_acl_group_id = self.dash_acl_group_create() + out_acl_group_id = self.dash_acl_group_create() + + # create VNET + self.vm_vni += 1 + vm_vnet = self.vnet_create(vni=self.vm_vni) + + # create ENI + eni = self.eni_create(vm_underlay_dip=self.vm_underlay_dip, + vm_vni=self.vm_vni, + vnet_id=vm_vnet, + inbound_v4_stage1_dash_acl_group_id=in_acl_group_id, + inbound_v4_stage2_dash_acl_group_id=in_acl_group_id, + inbound_v4_stage3_dash_acl_group_id=in_acl_group_id, + inbound_v4_stage4_dash_acl_group_id=in_acl_group_id, + inbound_v4_stage5_dash_acl_group_id=in_acl_group_id, + outbound_v4_stage1_dash_acl_group_id=out_acl_group_id, + outbound_v4_stage2_dash_acl_group_id=out_acl_group_id, + outbound_v4_stage3_dash_acl_group_id=out_acl_group_id, + outbound_v4_stage4_dash_acl_group_id=out_acl_group_id, + outbound_v4_stage5_dash_acl_group_id=out_acl_group_id) + + # create eni_ether_address_map_entry + self.eni_mac_map_create(eni_id=eni, mac=self.eni_mac_list[indx]) + + self.outbound_vni += 1 + outbound_vnet = self.vnet_create(vni=self.outbound_vni) + + # create inbound_routing_entry + self.inbound_routing_decap_create(eni_id=eni, + vni=self.outbound_vni, + sip="10.10.2.0", + sip_mask="255.255.255.0") + + # create outbound_routing_entry + self.outbound_routing_vnet_direct_create(eni_id=eni, + lpm="192.168.1.0/24", + dst_vnet_id=outbound_vnet, + overlay_ip="192.168.1.10") + + except AssertionError as ae: + if self.status() == SAI_STATUS_INSUFFICIENT_RESOURCES: + print(f"\nSAI_STATUS_INSUFFICIENT_RESOURCES: failed on iteration # {self.vm_vni}\n") + raise ae + else: + print(f"\nFailed on iteration # {self.vm_vni}\n") + raise ae + + print("PASS") + + +@skipIf(test_param_get('bmv2'), "Blocked by Issue #233. Inbound Routing is not supported in BMv2.") +class CreateTwoSameEnisNegativeTest(VnetAPI): + """ + Verifies failure in case of creation the same ENIs in one VNET + """ + + def runTest(self): + + vip = "10.1.1.1" + vm_vni = 1 + vm_underlay_dip = "10.10.1.10" + eni_mac = "00:01:00:00:03:14" + + self.vip_create(vip=vip) + + self.direction_lookup_create(vni=vm_vni) + + vnet = self.vnet_create(vni=vm_vni) + + # first eni and eni mac mapping + eni_id_0 = self.eni_create(admin_state=True, + vm_underlay_dip=sai_ipaddress(vm_underlay_dip), + vm_vni=vm_vni, + vnet_id=vnet) + + self.eni_mac_map_create(eni_id_0, eni_mac) + + # second eni and eni mac mapping + eni_id_1 = self.eni_create(admin_state=True, + vm_underlay_dip=sai_ipaddress(vm_underlay_dip), + vm_vni=vm_vni, + vnet_id=vnet) + + # create ENI 1 mac mapping and expect failure + eni_ether_address_map_entry = sai_thrift_eni_ether_address_map_entry_t( + switch_id=self.switch_id, + address=eni_mac) + sai_thrift_create_eni_ether_address_map_entry(self.client, + eni_ether_address_map_entry, + eni_id=eni_id_1) + + self.assertEqual(self.status(), SAI_STATUS_FAILURE)