diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 70a8a814170..26203ce872c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,24 +6,32 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, -# @openconfig/featureprofiles-maintainers will be requested for +# @openconfig/featureprofiles-approvers will be requested for # review when someone opens a pull request. -* @openconfig/featureprofiles-maintainers +* @openconfig/featureprofiles-approvers # /feature folders each have owners who are auto requested for review and may merge PR's -/feature/bgp/ @dplore +/feature/acl/ @openconfig/featureprofiles-owner-acl +/feature/aft/ @openconfig/featureprofiles-owner-aft +/feature/bgp/ @openconfig/featureprofiles-owner-bgp +/feature/dhcp/ @alokmtri-g /feature/ethernet/ @ram-mac -/feature/interface/ @ram-mac -/feature/isis/ @rohit-rp -/feature/mpls/ @swetha-haridasula -/feature/mtu/ @swetha-haridasula -/feature/networkinstance/ @swetha-haridasula -/feature/policy_forwarding/ @swetha-haridasula -/feature/qos @sezhang2 +/feature/gribi/ @openconfig/featureprofiles-owner-gribi +/feature/interface/ @openconfig/featureprofiles-owner-interface +/feature/isis/ @openconfig/featureprofiles-owner-isis +/feature/lldp/ @openconfig/featureprofiles-owner-lldp +/feature/mpls/ @openconfig/featureprofiles-owner-mpls +/feature/mtu/ @openconfig/featureprofiles-owner-mtu +/feature/networkinstance/ @openconfig/featureprofiles-owner-networkinstance +/feature/platform/ @openconfig/featureprofiles-owner-platform +/feature/platform/transceiver @openconfig/featureprofiles-owner-platform-transceiver +/feature/qos @openconfig/featureprofiles-owner-qos /feature/routing_policy/ @swetha-haridasula -/feature/security @mihirpitale-googler -/feature/staticroute/ @swetha-haridasula -/feature/system @self-maurya +/feature/sampling/ @sudhinj +/feature/security @openconfig/featureprofiles-owner-security +/feature/staticroute/ @openconfig/featureprofiles-owner-staticroute +/feature/stp/ @alokmtri-g +/feature/system @openconfig/featureprofiles-owner-system /feature/vrrp @amrindrr # Common OTG utilities diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6ab972f2897..ff20539b0a0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,13 +11,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 - name: Set up Go - uses: actions/setup-go@v2.1.3 + uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 with: go-version: 1.21.x - name: Cache - uses: actions/cache@v3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 with: path: | ~/go/pkg/mod @@ -28,13 +28,13 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 - name: Set up Go - uses: actions/setup-go@v2.1.3 + uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 with: go-version: 1.21.x - name: Cache - uses: actions/cache@v3 + uses: actions/cache@f4b3439a656ba812b8cb417d2d49f9c810103092 with: path: | ~/go/pkg/mod @@ -45,7 +45,7 @@ jobs: run: sudo apt-get -y install libpcap-dev - run: go test -v -coverprofile=profile.cov $(go list ./... | grep -v /.*test.*) - name: Send coverage - uses: shogo82148/actions-goveralls@v1 + uses: shogo82148/actions-goveralls@7b1bd2871942af030d707d6574e5f684f9891fb2 with: path-to-profile: profile.cov static_analysis: @@ -53,7 +53,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install go - uses: actions/setup-go@v2 + uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 with: go-version: '1.21' # Go & staticcheck build cache require a lot of disk space. Reclaim extra @@ -66,9 +66,9 @@ jobs: sudo mv "${HOME}/.cache" /mnt/cache ln -s /mnt/cache "${HOME}/.cache" - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 with: path: | ~/go/pkg/mod diff --git a/.github/workflows/nosimage.yml b/.github/workflows/nosimage.yml index 0be4a982ccd..45a6e276b46 100644 --- a/.github/workflows/nosimage.yml +++ b/.github/workflows/nosimage.yml @@ -12,9 +12,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe with: go-version: stable cache: false diff --git a/.github/workflows/protobufs.yml b/.github/workflows/protobufs.yml index e645507fc8e..99326ed33a6 100644 --- a/.github/workflows/protobufs.yml +++ b/.github/workflows/protobufs.yml @@ -13,20 +13,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Install go - uses: actions/setup-go@v2 + uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 with: go-version: '1.21' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ github.job }}-${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }} - name: Install protobuf - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@149f6c87b92550901b26acd1632e11c3662e381f with: version: '3.x' repo-token: ${{ secrets.GITHUB_TOKEN }} @@ -38,7 +38,7 @@ jobs: find github.com/openconfig/featureprofiles/ -name \*.proto -exec api-linter --disable-rule all --enable-rule core {} \+ - name: Validate textprotos run: | - go install github.com/bstoll/textproto-validator@latest + go install github.com/bstoll/textproto-validator@15e24d0eb567d63615f0aa70940bc073ab674fe7 make protoimports for i in `find . -name \*.textproto`; do textproto-validator -I ./protobuf-import $i @@ -49,21 +49,21 @@ jobs: runs-on: ubuntu-latest steps: - name: Install go - uses: actions/setup-go@v2 + uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 with: go-version: '1.21' - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 with: fetch-depth: 0 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ github.job }}-${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }} - - name: Fetch Openconfig Models + - name: Fetch OpenConfig Models run: make openconfig_public - name: Validate Paths run: | diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 5365ed1ee1c..a90c1025bbd 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -5,14 +5,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Setup Perl - uses: perl-actions/install-with-cpanm@v1 + uses: perl-actions/install-with-cpanm@10d60f00b4073f484fc29d45bfbe2f776397ab3d with: install: | Net::IP - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: IP Addresses Assignment run: | git diff --name-only main | while read l; do @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Allowed File Types run: ./tools/allowed_file_types.sh - name: Block hyphenated directory names @@ -65,9 +65,9 @@ jobs: name: OTG Changes Required runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Check if OTG changes required - uses: actions/github-script@v6 + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 with: script: | const script = require('./.github/workflows/required_otg_changes_check.js') diff --git a/.github/workflows/readme_oc_path_and_rpc.yml b/.github/workflows/readme_oc_path_and_rpc.yml index b757f475a66..23215b74d7a 100644 --- a/.github/workflows/readme_oc_path_and_rpc.yml +++ b/.github/workflows/readme_oc_path_and_rpc.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe with: go-version: stable cache: false @@ -37,7 +37,7 @@ jobs: exemption_flags=( --non-test-readme feature/security/gnsi/certz/test_data/README.md - --non-test-readme feature/experimental/p4rt/README.md + --non-test-readme feature/p4rt/README.md --non-test-readme feature/security/gnsi/acctz/README.md ) diff --git a/.github/workflows/rebase_check.yml b/.github/workflows/rebase_check.yml index 76e330acb1a..69f825aef51 100644 --- a/.github/workflows/rebase_check.yml +++ b/.github/workflows/rebase_check.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout PR - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 with: fetch-depth: 0 - name: Check if dependencies and checks are up to date. diff --git a/.github/workflows/required_approvals.yml b/.github/workflows/required_approvals.yml new file mode 100644 index 00000000000..4a2123d17d6 --- /dev/null +++ b/.github/workflows/required_approvals.yml @@ -0,0 +1,24 @@ +# This workflow is to make sure we have 1 LGTM for business logic and 1 LGTM for code style +name: PR Approval Workflow +on: + pull_request_target: + branches: + - main +jobs: + check-approvals: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + pull-requests: read + steps: + - name: Check for required approvals + id: check-approvals + uses: skymoore/required-approvals@57612e00c501132dfb35ddaff54615b363f8e076 + with: + token: ${{ secrets.GITHUB_TOKEN }} + read_org_scoped_token: ${{ secrets.READ_ORG_SCOPED_TOKEN }} + org_name: openconfig + min_approvals: 2 + approval_mode: ALL + pr_number: ${{ github.event.number }} diff --git a/.github/workflows/rundata_check.yml b/.github/workflows/rundata_check.yml index 65657a213ee..33373f14d70 100644 --- a/.github/workflows/rundata_check.yml +++ b/.github/workflows/rundata_check.yml @@ -7,6 +7,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout PR - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: Check that addrundata is up to date. run: go run ./tools/addrundata diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 2c6e0644c11..a0124455fb2 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -9,20 +9,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: path: featureprofiles - name: Checkout wiki - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: repository: "openconfig/featureprofiles.wiki" path: featureprofiles.wiki - name: Set up Go - uses: actions/setup-go@v2.1.3 + uses: actions/setup-go@424fc82d43fa5a37540bae62709ddcc23d9520d4 with: go-version: 1.21.x - name: Cache - uses: actions/cache@v3 + uses: actions/cache@f4b3439a656ba812b8cb417d2d49f9c810103092 with: path: | ~/go/pkg/mod diff --git a/.gitignore b/.gitignore index 93acb89f3cb..07ebd5a939c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *~ topologies/kne/testbed.kne.yml .vscode/ +.idea/ # used by `make validate_paths` openconfig_public/ # used by `make proto/...` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5875bebd432..2290141cb5a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,10 +62,6 @@ The directory tree is organized as follows: * `cloudbuild/` contains google cloud build scripts for running virtual routers in containers on [KNE](https://github.com/openconfig/kne) * `feature/` contains definition and tests of feature profiles. -* `feature/experimental` contains tests which have automation which is - not confirmed to pass on any hardware platform or software release. - When the test automation is passing against at least one DUT, - it is moved to the `feature/` directory. * `internal/` contains packages used by feature profile tests. * `proto/` contains protobuf files for feature profiles. * `tools/` contains code used for CI checks. diff --git a/doc/test-requirements-template.md b/doc/test-requirements-template.md index 4a4abfb4830..4b65d1d866e 100644 --- a/doc/test-requirements-template.md +++ b/doc/test-requirements-template.md @@ -8,41 +8,89 @@ assignees: '' # Instructions for this template -Below is the required template for writing test requirements. Good examples of test -requirements include: +Below is the required template for writing test requirements. Good examples of +test requirements include: -* [TE-3.7: Base Hierarchical NHG Update](/feature/gribi/otg_tests/base_hierarchical_nhg_update/README.md) -* [gNMI-1.13: Telemetry: Optics Power and Bias Current](https://github.com/openconfig/featureprofiles/blob/main/feature/platform/tests/optics_power_and_bias_current_test/README.md) -* [RT-5.1: Singleton Interface](https://github.com/openconfig/featureprofiles/blob/main/feature/interface/singleton/otg_tests/singleton_test/README.md) +* [TE-18.1 gRIBI MPLS in UDP Encapsulation and + Decapsulation](https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/mpls_in_udp/README.md) +* [TE-3.7: Base Hierarchical NHG + Update](/feature/gribi/otg_tests/base_hierarchical_nhg_update/README.md) +* [gNMI-1.13: Telemetry: Optics Power and Bias + Current](https://github.com/openconfig/featureprofiles/blob/main/feature/platform/tests/optics_power_and_bias_current_test/README.md) # TestID-x.y: Short name of test here ## Summary -Write a few sentences or paragraphs describing the purpose and scope of the test. +Write a few sentences or paragraphs describing the purpose and scope of the +test. ## Testbed type -* Specify the .testbed topology file from the [topologies](https://github.com/openconfig/featureprofiles/tree/main/topologies) folder to be used with this test +* Specify the .testbed topology file from the + [topologies](https://github.com/openconfig/featureprofiles/tree/main/topologies) + folder to be used with this test ## Procedure -* Test environment setup - * Description of procedure to configure ATE and DUT with pre-requisites making it possible to cover the intended paths and RPC's. +### Test environment setup + +* Description of procedure to configure ATE and DUT with pre-requisites making + it possible to cover the intended paths and RPCs. + +### TestID-x.y.1 - Name of subtest 1 + +The following steps are typically present in each subtest. + +* Step 1 - Generate DUT configuration + +Replace this JSON formatted content with the "Canonical OC" that is expected to +be generated by the subtest. This configuration should be in JSON format. + +```json +{ + "openconfig-qos": { + "interfaces": [ + { + "config": { + "interface-id": "PortChannel1.100" + }, + "input": { + "classifiers": [ + { + "classifier": "dest_A", + "config": { + "name": "dest_A", + "type": "IPV4" + } + } + ], + "scheduler-policy": { + "config": { + "name": "limit_group_A_1Gb" + } + } + }, + "interface": "PortChannel1.100" + }, + ] + } +} +``` + +* Step 2 - Push configuration to DUT using gnmi.Set with REPLACE option +* Step 3 - Send Traffic +* Step 4 - Validation with pass/fail criteria -* TestID-x.y.z - Name of subtest - * Step 1 - * Step 2 - * Validation and pass/fail criteria +### TestID-x.y.2 - Name of subtest 2 -* TestID-x.y.z - Name of subtest - * Step 1 - * Step 2 - * Validation and pass/fail criteria +Repeat the format of the first subtest for each additional subtest defined. ## OpenConfig Path and RPC Coverage -This example yaml defines the OC paths intended to be covered by this test. OC paths used for test environment setup are not required to be listed here. +This yaml stanza defines the OC paths intended to be covered by this test. OC +paths used for test environment setup are not required to be listed here. This +content is parsed by automation to derive the test coverage ```yaml paths: @@ -64,6 +112,7 @@ rpcs: ## Required DUT platform * Specify the minimum DUT-type: - * MFF - A modular form factor device containing LINECARDs, FABRIC and redundant CONTROLLER_CARD components + * MFF - A modular form factor device containing LINECARDs, FABRIC and + redundant CONTROLLER_CARD components * FFF - fixed form factor * vRX - virtual router device diff --git a/feature/acl/otg_tests/acl_update_test/README.md b/feature/acl/otg_tests/acl_update_test/README.md index b1f79cb014c..1bcfa5175c2 100644 --- a/feature/acl/otg_tests/acl_update_test/README.md +++ b/feature/acl/otg_tests/acl_update_test/README.md @@ -2,7 +2,15 @@ ## Summary -Configure an IP ACL, then test changing the ACL configuration to ensure a make-before-break behavior is performed. Make before break for ACL is defined as +Test configuration of an IP ACL. +Test changing the ACL configuration to ensure no packets are dropped due to +the configuration change, when the rule added or removed is not intended to +affect the traffic (make before break). + + +## Testbed type + +* [`featureprofiles/topologies/atedut_2.testbed`](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed) ## ACL-1 Layer 3 terms @@ -47,36 +55,64 @@ Configure an IP ACL, then test changing the ACL configuration to ensure a make-b * Repeat the same test by moving ACLs to the DUT egress interface. -## Config Parameter coverage - -``` -acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/destination-address -acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/protocol -acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/source-address - -acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/destination-address -acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/protocol -acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/source-address - -acl/interfaces/interface/ingress-acl-sets/ingress-acl-set -acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/acl-entries -acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/acl-entries/acl-entry - -acl/interfaces/interface/egress-acl-sets/egress-acl-set -acl/interfaces/interface/egress-acl-sets/egress-acl-set/acl-entries -acl/interfaces/interface/egress-acl-sets/egress-acl-set/acl-entries/acl-entry -``` - -## Telemetry Parameter coverage - +### Sub Test 4 + +* Repeat sub tests 1 through 4 using a port where [/interfaces/interface/state/management](https://github.com/openconfig/public/blob/daf73c37e9062b458bb9eab645840e5d3835c74d/release/models/interfaces/openconfig-interfaces.yang#L719-L727) + is true and in the case of a modular form factor device (MFF), provided by a `CONTROLLER_CARD` component. + +## OpenConfig Path and RPC Coverage + +```yaml +paths: + # base acl paths + /acl/acl-sets/acl-set/config/name: + /acl/acl-sets/acl-set/config/type: + /acl/acl-sets/acl-set/acl-entries/acl-entry/config/sequence-id: + /acl/acl-sets/acl-set/acl-entries/acl-entry/config/description: + + # ipv4 address match + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/destination-address: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/destination-address-prefix-set: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/protocol: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/source-address: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/config/source-address-prefix-set: + + # icmpv4 match + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/icmpv4/config/type: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv4/icmpv4/config/code: + + # ipv6 address match + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/destination-address: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/destination-address-prefix-set: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/protocol: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/source-address: + /acl/acl-sets/acl-set/acl-entries/acl-entry/ipv6/config/source-address-prefix-set: + + # paths for tcp/udp port and port-range + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/source-port: + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/source-port-set: + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/destination-port: + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/destination-port-set: + + # paths needed to match IP fragments + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/detail-mode: + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/explicit-detail-match-mode: + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/explicit-tcp-flags: + /acl/acl-sets/acl-set/acl-entries/acl-entry/transport/config/builtin-detail: + + # state paths for management port and ACL counters + /interfaces/interface/state/management: + /acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/acl-entries/acl-entry/state/matched-packets: + /acl/interfaces/interface/egress-acl-sets/egress-acl-set/acl-entries/acl-entry/state/matched-packets: + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true ``` -acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/acl-entries/acl-entry/state/matched-packets -acl/interfaces/interface/egress-acl-sets/egress-acl-set/acl-entries/acl-entry/state/matched-packets -``` - -## Protocol/RPC Parameter coverage - -None ## Minimum DUT platform requirement diff --git a/feature/aft/aft_base/otg_tests/afts_base/README.md b/feature/aft/aft_base/otg_tests/afts_base/README.md new file mode 100644 index 00000000000..b2e0d5a2792 --- /dev/null +++ b/feature/aft/aft_base/otg_tests/afts_base/README.md @@ -0,0 +1,177 @@ +# AFT-1.1: AFTs Base + +## Summary + +IPv4/IPv6 unicast routes next hop group and next hop. + +## Testbed + +* atedut_4.testbed + +## Test Setup + +### Generate DUT and ATE Configuration + +Configure DUT:port1,port2,port3 for IS-IS session with ATE:port1,port2,port3 +* IS-IS must be level 2 only with wide metric. +* IS-IS must be point to point. +* Send 1000 ipv4 and 1000 ipv6 IS-IS prefixes from ATE:port3 to DUT:port3. + + +Establish eBGP sessions between ATE:port1,port2 and DUT:port1,port2 and another between ATE:port3 and DUT:port3. +* Configure eBGP over the interface ip. +* eBGP must be multipath. +* Advertise 1000 ipv4,ipv6 prefixes from ATE port1,port2 observe received prefixes at DUT. +* Validate total number of entries of AFT for IPv4 and IPv6. +* Each prefix must have 2 next hops pointing to ATE port1,port2. +* Advertise 100 ipv4,ipv6 from ATE port3 observe received prefixes at DUT. + +Establish RSVP Sessions between ATE:port3 and SUT:port3. +* Configure mpls and rsvp sessions. +* Configure 2 ingress TE tunnels from DUT:port3 to ATE:port3. +* Tunnel destination is interface ip of ATE:port3. +* Configure explicit null and ipv6 tunneling. +* BGP advertised routes from ATE:port3 must be pointing to the 2 tunnels in the DUT. + +### Procedure + +* Use gNMI.Set with REPLACE option to push the Test Setup configuration to the DUT. +* ATE configuration must be pushed. + +### Verifications + +* BGP route advertised from ATE:port1,port2 must have 2 nexthops. +* IS-IS route advertised from ATE:port3 must have one next hop. +* BGP route advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* Use gnmi Subscribe with ON_CHANGE option to /network-instances/network-instance/afts. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. +* Verify all other leaves mentioned in the path section. + + +## AFT-1.1.1: AFT Base Link Down scenario 1 + +### Procedure + +Bring down the link between ATE:port2 and DUT:port2 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must have 1 nexthop. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## AFT-1.1.2: AFT Base Link Down scenario 2 + +### Procedure + +Bring down both links between ATE:port1,port2 and DUT:port1,port2 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must be removed from RIB,FIB of the DUT, query results nil. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## AFT-1.1.3: AFT Base Link Up scenario 1 + +### Procedure + +Bring up link between ATE:port1 and DUT:port1 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must have one next hop. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* Verify afts prefix advertised by BGP,ISIS. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## AFT-1.1.4: AFT Base Link Up scenario 2 + +### Procedure + +Bring up both link between ATE:port1,port2 and DUT:port1,port2 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must have 2 next hops. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## Config Paths ## + + + ## State Paths ## + + /network-instances/network-instance/afts/ethernet/mac-entry/state/next-hop-group: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/origin-protocol: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/next-hop-group: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/origin-protocol: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/prefix: + /network-instances/network-instance/afts/aft-summaries/ipv4-unicast/protocols/protocol/state/origin-protocol: + /network-instances/network-instance/afts/aft-summaries/ipv6-unicast/protocols/protocol/state/origin-protocol: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/id: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/index: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/weight: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/backup-next-hop-group: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id: + /network-instances/network-instance/afts/next-hops/next-hop/index: + /network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/interface: + /network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/subinterface: + /network-instances/network-instance/afts/next-hops/next-hop/state/encapsulate-header: + /network-instances/network-instance/afts/next-hops/next-hop/state/index: + /network-instances/network-instance/afts/next-hops/next-hop/state/ip-address: + /network-instances/network-instance/afts/next-hops/next-hop/state/mac-address: + /network-instances/network-instance/afts/next-hops/next-hop/state/origin-protocol: + /network-instances/network-instance/afts/state-synced/state/ipv4-unicast: + /network-instances/network-instance/afts/state-synced/state/ipv6-unicast: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/entry-metadata: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group-network-instance: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/origin-network-instance: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/entry-metadata: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/next-hop-group-network-instance: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/origin-network-instance: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/prefix: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/prefix: + +rpcs: + gnmi: + gNMI.Subscribe: +``` + +## Control Protocol Coverage + +BGP +IS-IS +RSVP +MPLS + +## Minimum DUT Platform Requirement + +vRX diff --git a/feature/aft/aft_base/otg_tests/afts_prefix_counters/README.md b/feature/aft/aft_base/otg_tests/afts_prefix_counters/README.md new file mode 100644 index 00000000000..9fce154e4a1 --- /dev/null +++ b/feature/aft/aft_base/otg_tests/afts_prefix_counters/README.md @@ -0,0 +1,178 @@ +# AFT-2.1: AFTs Prefix Counters + +## Summary + +IPv4/IPv6 prefix counters + +## Testbed + +* atedut_2.testbed + +## Test Setup + +### Generate DUT and ATE Configuration + +Configure DUT:port1 for IS-IS session with ATE:port1 +* IS-IS must be level 2 only with wide metric. +* IS-IS must be point to point. +* Send 1000 ipv4 and 1000 ipv6 IS-IS prefixes from ATE:port1 to DUT:port1. + +Establish eBGP sessions between ATE:port1 and DUT:port1. +* Configure eBGP over the interface ip. +* Advertise 1000 ipv4,ipv6 prefixes from ATE port1 observe received prefixes at DUT. + +### Procedure + +* Gnmi set with REPLACE option to push the configuration DUT. +* ATE configuration must be pushed. + +### verifications + +* BGP routes advertised from ATE:port1 must have 1 nexthop. +* IS-IS routes advertised from ATE:port1 must have one next hop. +* Use gnmi Subscribe with ON_CHANGE option to /network-instances/network-instance/afts. +* Verify afts prefix entries using the following paths with in a timeout of 30s. + +/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix, +/network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/prefix + + + +## AFT-2.1.1: AFT Prefix Counters ipv4 packets forwarded, ipv4 octets forwarded IS-IS route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv4 prefix advertise by IS-IS. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE then the test is marked as passed. +* Verify afts ipv4 forwarded packets and ipv4 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.2: AFT Prefix Counters ipv4 packets forwarded, ipv4 octets forwarded BGP route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv4 prefix advertise by BGP. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts ipv4 forwarded packets and ipv4 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + + +## AFT-2.1.3: AFT Prefix Counters ipv6 packets forwarded, ipv6 octets forwarded IS-IS route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv6 prefix advertise by IS-IS. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts ipv6 forwarded packets and ipv6 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.4: AFT Prefix Counters ipv6 packets forwarded, ipv6 octets forwarded BGP route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv6 prefix advertise by BGP. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts ipv6 forwarded packets and ipv6 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.5: AFT Prefix Counters withdraw the ipv4 prefix. + +### Procedure + +* From ATE:port1 withdraw some prefixes of BGP and IS-IS. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the withdrawn ipv4 prefix. +* The traffic must blackhole. + +### Verifications + +* The counters must not send incremental value as the prefix is not present in RIB/FIB. The test fails if the counter shows incremental values. +* Verify afts ipv4 forwarded packet counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.6: AFT Prefix Counters add the ipv4 prefix back. + +### Procedure + +* From ATE:port1 add the prefixes of BGP and IS-IS back. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the added ipv4 prefix. +* The traffic must flow end to end. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.7: AFT Prefix Counters withdraw the ipv6 prefix. + +### Procedure + +* From ATE:port1 withdraw some prefixes of BGP and IS-IS. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the withdrawn ipv6 prefix. +* The traffic must blackhole. + +### Verifications + +* The counters must not send incremental value as the prefix is not present in RIB/FIB. The test fails if the counter shows incremental values. +* Verify afts counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.8: AFT Prefix Counters add the ipv6 prefix back. + +### Procedure + +* From ATE:port1 add the prefixes of BGP and IS-IS back. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the added ipv6 prefix. +* The traffic must flow end to end. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts counter entries using the path mentioned in the paths section of this test plan. + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## Config Paths ## + + ## State Paths ## + + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/counters/octets-forwarded: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/counters/packets-forwarded: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/counters/octets-forwarded: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/counters/packets-forwarded: + + +rpcs: + gnmi: + gNMI.Subscribe: +``` + +## Control Protocol Coverage + +BGP +IS-IS + +## Minimum DUT Platform Requirement + +vRX \ No newline at end of file diff --git a/feature/aft/aft_summary/otg_tests/route_summary_counters_test/README.md b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/README.md similarity index 100% rename from feature/aft/aft_summary/otg_tests/route_summary_counters_test/README.md rename to feature/aft/afts_summary/otg_tests/route_summary_counters_test/README.md diff --git a/feature/aft/aft_summary/otg_tests/route_summary_counters_test/metadata.textproto b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto similarity index 100% rename from feature/aft/aft_summary/otg_tests/route_summary_counters_test/metadata.textproto rename to feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto diff --git a/feature/aft/aft_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go similarity index 100% rename from feature/aft/aft_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go rename to feature/aft/afts_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go diff --git a/feature/aft/afts_summary/otg_tests/scale_aft_summary/README.md b/feature/aft/afts_summary/otg_tests/scale_aft_summary/README.md new file mode 100644 index 00000000000..e7e416b40e7 --- /dev/null +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/README.md @@ -0,0 +1,39 @@ +# RT-4.11: AFTs Route Summary + +## Summary + +IPv4/IPv6 scale unicast AFTs route summary for ISIS and BGP protocol + +## Procedure + +* Configure DUT:port1 for an IS-IS session with ATE:port1 +* Establish eBGP sessions between ATE:port1 and DUT:port1 and another between ATE:port2 and DUT:port2 +* Configure Route-policy under BGP peer-group address-family +* Advertise scale prefixes from ATE port-1, port-2 observe received prefixes at DUT for IPv4 and IPv6 +* Validate total number of entries of AFT for IPv4 and IPv6 + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## Config Paths ## + + ## State Paths ## + /network-instances/network-instance/afts/aft-summaries/ipv4-unicast/protocols/protocol/state/counters/aft-entries: + /network-instances/network-instance/afts/aft-summaries/ipv6-unicast/protocols/protocol/state/counters/aft-entries: + +rpcs: + gnmi: + gNMI.Subscribe: +``` + +## Control Protocol Coverage + +BGP +IS-IS + +## Minimum DUT Platform Requirement + +vRX diff --git a/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto b/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto new file mode 100644 index 00000000000..d61d4590b2b --- /dev/null +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto @@ -0,0 +1,54 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "89da0b4c-9a16-44f8-9757-d98ccdd6aaf4" +plan_id: "RT-4.11" +description: "AFTs Route Summary" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + isis_multi_topology_unsupported: true + isis_interface_level1_disable_required: true + missing_isis_interface_afi_safi_enable: true + isis_restart_suppress_unsupported: true + explicit_port_speed: true + explicit_interface_in_default_vrf: true + missing_value_for_defaults: true + interface_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + ipv4_missing_enabled: true + isis_interface_level1_disable_required: true + isis_single_topology_required: true + } +} +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + isis_level_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + omit_l2_mtu: true + missing_value_for_defaults: true + interface_enabled: true + default_network_instance: "default" + isis_instance_enabled_required: true + isis_interface_afi_unsupported: true + route_policy_under_afi_unsupported: true + } +} diff --git a/feature/aft/afts_summary/otg_tests/scale_aft_summary/route_test.go b/feature/aft/afts_summary/otg_tests/scale_aft_summary/route_test.go new file mode 100644 index 00000000000..e283663711e --- /dev/null +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/route_test.go @@ -0,0 +1,566 @@ +// Copyright 2024 Google LLC +// +// 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. + +package route_test + +import ( + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/isissession" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +// The testbed consists of ate:port1 -> dut:port1 and +// dut:port2 -> ate:port2. The first pair is called the "source" +// pair, and the second the "destination" pair. +// +// * Source: ate:port1 -> dut:port1 subnet 192.0.2.0/30 2001:db8::192:0:2:0/126 +// * Destination: dut:port2 -> ate:port2 subnet 192.0.2.4/30 2001:db8::192:0:2:4/126 +// +// Note that the first (.0, .3) and last (.4, .7) IPv4 addresses are +// reserved from the subnet for broadcast, so a /30 leaves exactly 2 +// usable addresses. This does not apply to IPv6 which allows /127 +// for point to point links, but we use /126 so the numbering is +// consistent with IPv4. + +const ( + advertisedRoutesv4Prefix = 32 + advertisedRoutesv6Prefix = 128 + dutAS = 65501 + ate1AS = 64501 + ate2AS = 200 + plenIPv4 = 30 + plenIPv6 = 126 + rplType = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + rplName = "ALLOW" + peerGrpNamev4 = "BGP-PEER-GROUP-V4" + peerGrpNamev6 = "BGP-PEER-GROUP-V6" + peerGrpNamev4P1 = "BGP-PEER-GROUP-V4-P1" + peerGrpNamev6P1 = "BGP-PEER-GROUP-V6-P1" + peerGrpNamev4P2 = "BGP-PEER-GROUP-V4-P2" + peerGrpNamev6P2 = "BGP-PEER-GROUP-V6-P2" + isisRoute = "199.0.0.1" + bgpRoute = "203.0.113.0" + isisRoutev6 = "2001:db8::203:0:113:1" + bgpRoutev6 = "2001:DB8:2::1" + RouteCount = uint32(1000) +) + +var ( + dutP1 = attrs.Attributes{ + Desc: "DUT to ATE source", + IPv4: "192.0.2.1", + IPv6: "2001:db8::1", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + ateP1 = attrs.Attributes{ + Name: "ateP1", + MAC: "02:00:01:01:01:01", + IPv4: "192.0.2.2", + IPv6: "2001:db8::2", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + + dutP2 = attrs.Attributes{ + Desc: "DUT to ATE destination", + IPv4: "192.0.2.5", + IPv6: "2001:db8::5", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + + ateP2 = attrs.Attributes{ + Name: "ateP2", + MAC: "02:00:02:01:01:01", + IPv4: "192.0.2.6", + IPv6: "2001:db8::6", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } +) + +// configureDUT configures all the interfaces and BGP on the DUT. +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + dc := gnmi.OC() + p1 := dut.Port(t, "port1").Name() + i1 := dutP1.NewOCInterface(p1, dut) + gnmi.Replace(t, dut, dc.Interface(p1).Config(), i1) + + p2 := dut.Port(t, "port2").Name() + i2 := dutP2.NewOCInterface(p2, dut) + gnmi.Replace(t, dut, dc.Interface(p2).Config(), i2) + + // Configure Network instance type on DUT + t.Log("Configure/update Network Instance") + fptest.ConfigureDefaultNetworkInstance(t, dut) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, dut.Port(t, "port1")) + fptest.SetPortSpeed(t, dut.Port(t, "port2")) + } + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, p1, deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p2, deviations.DefaultNetworkInstance(dut), 0) + } + configureRoutePolicy(t, dut, rplName, rplType) + + dutConfPath := dc.NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + dutConf := createBGPNeighborP1(dutAS, ate1AS, dut) + gnmi.Replace(t, dut, dutConfPath.Config(), dutConf) + dutConf = createBGPNeighborP2(dutAS, ate2AS, dut) + gnmi.Update(t, dut, dutConfPath.Config(), dutConf) + ts := isissession.MustNew(t).WithISIS() + ts.ConfigISIS(func(isis *oc.NetworkInstance_Protocol_Isis) { + global := isis.GetOrCreateGlobal() + global.HelloPadding = oc.Isis_HelloPaddingType_DISABLE + + if deviations.ISISSingleTopologyRequired(ts.DUT) { + afv6 := global.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST) + afv6.GetOrCreateMultiTopology().SetAfiName(oc.IsisTypes_AFI_TYPE_IPV4) + afv6.GetOrCreateMultiTopology().SetSafiName(oc.IsisTypes_SAFI_TYPE_UNICAST) + } + }) + ts.ATEIntf1.Isis().Advanced().SetEnableHelloPadding(false) + ts.PushAndStart(t) +} + +type BGPNeighbor struct { + as uint32 + neighborip string + isV4 bool +} + +func createBGPNeighborP1(localAs, peerAs uint32, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + nbrs := []*BGPNeighbor{ + {as: peerAs, neighborip: ateP1.IPv4, isV4: true}, + {as: peerAs, neighborip: ateP1.IPv6, isV4: false}, + } + + d := &oc.Root{} + ni1 := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + + global := bgp.GetOrCreateGlobal() + global.As = ygot.Uint32(localAs) + global.RouterId = ygot.String(dutP1.IPv4) + + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + + // Note: we have to define the peer group even if we aren't setting any policy because it's + // invalid OC for the neighbor to be part of a peer group that doesn't exist. + pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNamev4P1) + pgv4.PeerAs = ygot.Uint32(peerAs) + pgv4.PeerGroupName = ygot.String(peerGrpNamev4P1) + pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNamev6P1) + pgv6.PeerAs = ygot.Uint32(peerAs) + pgv6.PeerGroupName = ygot.String(peerGrpNamev6P1) + + for _, nbr := range nbrs { + if nbr.isV4 { + nv4 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv4.PeerAs = ygot.Uint32(nbr.as) + nv4.Enabled = ygot.Bool(true) + nv4.PeerGroup = ygot.String(peerGrpNamev4P1) + afisafi := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + afisafi.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv4 := pgv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + pgafv4.Enabled = ygot.Bool(true) + rpl := pgafv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } + } else { + nv6 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv6.PeerAs = ygot.Uint32(nbr.as) + nv6.Enabled = ygot.Bool(true) + nv6.PeerGroup = ygot.String(peerGrpNamev6P1) + afisafi6 := nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + afisafi6.Enabled = ygot.Bool(true) + nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv6 := pgv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + pgafv6.Enabled = ygot.Bool(true) + rpl := pgafv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + + } + } + } + return niProto +} + +func createBGPNeighborP2(localAs, peerAs uint32, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + nbrs := []*BGPNeighbor{ + {as: peerAs, neighborip: ateP2.IPv4, isV4: true}, + {as: peerAs, neighborip: ateP2.IPv6, isV4: false}, + } + + d := &oc.Root{} + ni1 := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + + global := bgp.GetOrCreateGlobal() + global.As = ygot.Uint32(localAs) + global.RouterId = ygot.String(dutP1.IPv4) + + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + + // Note: we have to define the peer group even if we aren't setting any policy because it's + // invalid OC for the neighbor to be part of a peer group that doesn't exist. + pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNamev4P2) + pgv4.PeerAs = ygot.Uint32(peerAs) + pgv4.PeerGroupName = ygot.String(peerGrpNamev4P2) + pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNamev6P2) + pgv6.PeerAs = ygot.Uint32(peerAs) + pgv6.PeerGroupName = ygot.String(peerGrpNamev6P2) + + for _, nbr := range nbrs { + if nbr.isV4 { + nv4 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv4.PeerAs = ygot.Uint32(nbr.as) + nv4.Enabled = ygot.Bool(true) + nv4.PeerGroup = ygot.String(peerGrpNamev4P2) + afisafi := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + afisafi.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv4 := pgv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + pgafv4.Enabled = ygot.Bool(true) + rpl := pgafv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } + } else { + nv6 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv6.PeerAs = ygot.Uint32(nbr.as) + nv6.Enabled = ygot.Bool(true) + nv6.PeerGroup = ygot.String(peerGrpNamev6P2) + afisafi6 := nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + afisafi6.Enabled = ygot.Bool(true) + nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv6 := pgv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + pgafv6.Enabled = ygot.Bool(true) + rpl := pgafv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + + } + } + } + return niProto +} + +func configureRoutePolicy(t *testing.T, dut *ondatra.DUTDevice, name string, pr oc.E_RoutingPolicy_PolicyResultType) { + d := &oc.Root{} + rp := d.GetOrCreateRoutingPolicy() + pd := rp.GetOrCreatePolicyDefinition(name) + st, err := pd.AppendNewStatement("id-1") + if err != nil { + t.Fatal(err) + } + st.GetOrCreateActions().PolicyResult = pr + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) +} + +func waitForBGPSession(t *testing.T, dut *ondatra.DUTDevice, wantEstablished bool) { + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + nbrPath := statePath.Neighbor(ateP2.IPv4) + nbrPathv6 := statePath.Neighbor(ateP2.IPv6) + compare := func(val *ygnmi.Value[oc.E_Bgp_Neighbor_SessionState]) bool { + state, ok := val.Val() + if ok { + if wantEstablished { + t.Logf("BGP session state: %s", state.String()) + return state == oc.Bgp_Neighbor_SessionState_ESTABLISHED + } + return state == oc.Bgp_Neighbor_SessionState_IDLE + } + return false + } + + _, ok := gnmi.Watch(t, dut, nbrPath.SessionState().State(), 2*time.Minute, compare).Await(t) + if !ok { + fptest.LogQuery(t, "BGP reported state", nbrPath.State(), gnmi.Get(t, dut, nbrPath.State())) + if wantEstablished { + t.Fatal("No BGP neighbor formed...") + } else { + t.Fatal("BGPv4 session didn't teardown.") + } + } + _, ok = gnmi.Watch(t, dut, nbrPathv6.SessionState().State(), 2*time.Minute, compare).Await(t) + if !ok { + fptest.LogQuery(t, "BGPv6 reported state", nbrPathv6.State(), gnmi.Get(t, dut, nbrPathv6.State())) + if wantEstablished { + t.Fatal("No BGPv6 neighbor formed...") + } else { + t.Fatal("BGPv6 session didn't teardown.") + } + } +} + +func verifyBGPTelemetry(t *testing.T, dut *ondatra.DUTDevice) { + t.Log("Waiting for BGPv4 neighbor to establish...") + waitForBGPSession(t, dut, true) + +} + +func configureATE(t *testing.T) gosnappi.Config { + ate := ondatra.ATE(t, "ate") + ap1 := ate.Port(t, "port1") + ap2 := ate.Port(t, "port2") + config := gosnappi.NewConfig() + // add ports + p1 := config.Ports().Add().SetName(ap1.ID()) + p2 := config.Ports().Add().SetName(ap2.ID()) + // add devices + d1 := config.Devices().Add().SetName("p1.d1") + d2 := config.Devices().Add().SetName("p2.d1") + // Configuration on port1. + d1Eth1 := d1.Ethernets(). + Add(). + SetName("p1.d1.eth1"). + SetMac("00:00:02:02:02:02"). + SetMtu(1500) + d1Eth1. + Connection(). + SetPortName(p1.Name()) + + d1ipv41 := d1Eth1. + Ipv4Addresses(). + Add(). + SetName("p1.d1.eth1.ipv4"). + SetAddress("192.0.2.2"). + SetGateway("192.0.2.1"). + SetPrefix(30) + + d1ipv61 := d1Eth1. + Ipv6Addresses(). + Add(). + SetName("p1.d1.eth1.ipv6"). + SetAddress("2001:db8::2"). + SetGateway("2001:db8::1"). + SetPrefix(126) + + // isis router + d1isis := d1.Isis(). + SetName("p1.d1.isis"). + SetSystemId("650000000001") + d1isis.Basic(). + SetIpv4TeRouterId(d1ipv41.Address()). + SetHostname("ixia-c-port1") + d1isis.Advanced().SetAreaAddresses([]string{"49"}) + d1isisint := d1isis.Interfaces(). + Add(). + SetName("p1.d1.isis.intf"). + SetEthName(d1Eth1.Name()). + SetNetworkType(gosnappi.IsisInterfaceNetworkType.POINT_TO_POINT). + SetLevelType(gosnappi.IsisInterfaceLevelType.LEVEL_2). + SetMetric(10) + d1isisint.TrafficEngineering().Add().PriorityBandwidths() + d1isisint.Advanced().SetAutoAdjustMtu(true).SetAutoAdjustArea(true).SetAutoAdjustSupportedProtocols(true) + + d1IsisRoute1 := d1isis.V4Routes().Add().SetName("p1.d1.isis.rr1") + d1IsisRoute1.Addresses(). + Add(). + SetAddress(isisRoute). + SetPrefix(32).SetCount(RouteCount) + + d1IsisRoute1v6 := d1isis.V6Routes().Add().SetName("p1.d1.isis.rr1.v6") + d1IsisRoute1v6.Addresses(). + Add(). + SetAddress(isisRoutev6). + SetPrefix(126).SetCount(RouteCount) + + configureBGPDev(d1, d1ipv41, d1ipv61, ate1AS) + + // configuration on port2 + d2Eth1 := d2.Ethernets(). + Add(). + SetName("p2.d1.eth1"). + SetMac("00:00:03:03:03:03"). + SetMtu(1500) + d2Eth1. + Connection(). + SetPortName(p2.Name()) + d2ipv41 := d2Eth1.Ipv4Addresses(). + Add(). + SetName("p2.d1.eth1.ipv4"). + SetAddress("192.0.2.6"). + SetGateway("192.0.2.5"). + SetPrefix(30) + + d2ipv61 := d2Eth1. + Ipv6Addresses(). + Add(). + SetName("p2.d1.eth1.ipv6"). + SetAddress("2001:db8::6"). + SetGateway("2001:db8::5"). + SetPrefix(126) + + // isis router + d2isis := d2.Isis(). + SetName("p2.d1.isis"). + SetSystemId("650000000001") + d2isis.Basic(). + SetIpv4TeRouterId(d2ipv41.Address()). + SetHostname("ixia-c-port2") + d2isis.Advanced().SetAreaAddresses([]string{"49"}) + d2isisint := d2isis.Interfaces(). + Add(). + SetName("p2.d1.isis.intf"). + SetEthName(d2Eth1.Name()). + SetNetworkType(gosnappi.IsisInterfaceNetworkType.POINT_TO_POINT). + SetLevelType(gosnappi.IsisInterfaceLevelType.LEVEL_2). + SetMetric(10) + d2isisint.TrafficEngineering().Add().PriorityBandwidths() + d2isisint.Advanced().SetAutoAdjustMtu(true).SetAutoAdjustArea(true).SetAutoAdjustSupportedProtocols(true) + + d2IsisRoute1 := d2isis.V4Routes().Add().SetName("p2.d1.isis.rr1") + d2IsisRoute1.Addresses(). + Add(). + SetAddress(isisRoute). + SetPrefix(32). + SetCount(RouteCount) + + d2IsisRoute1V6 := d2isis.V6Routes().Add().SetName("p2.d1.isis.rr1.v6") + d2IsisRoute1V6.Addresses(). + Add(). + SetAddress(isisRoutev6). + SetPrefix(126). + SetCount(RouteCount) + + configureBGPDev(d2, d2ipv41, d2ipv61, ate2AS) + + return config +} + +// configureBGPDev configures the BGP on the OTG dev +func configureBGPDev(dev gosnappi.Device, Ipv4 gosnappi.DeviceIpv4, Ipv6 gosnappi.DeviceIpv6, as int) { + + Bgp := dev.Bgp().SetRouterId(Ipv4.Address()) + Bgp4Peer := Bgp.Ipv4Interfaces().Add().SetIpv4Name(Ipv4.Name()).Peers().Add().SetName(dev.Name() + ".BGP4.peer") + Bgp4Peer.SetPeerAddress(Ipv4.Gateway()).SetAsNumber(uint32(as)).SetAsType(gosnappi.BgpV4PeerAsType.EBGP) + Bgp6Peer := Bgp.Ipv6Interfaces().Add().SetIpv6Name(Ipv6.Name()).Peers().Add().SetName(dev.Name() + ".BGP6.peer") + Bgp6Peer.SetPeerAddress(Ipv6.Gateway()).SetAsNumber(uint32(as)).SetAsType(gosnappi.BgpV6PeerAsType.EBGP) + + configureBGPv4Routes(Bgp4Peer, Ipv4.Address(), Bgp4Peer.Name()+"v4route", bgpRoute, RouteCount) + configureBGPv6Routes(Bgp6Peer, Ipv6.Address(), Bgp6Peer.Name()+"v6route", bgpRoutev6, RouteCount) + +} + +func configureBGPv4Routes(peer gosnappi.BgpV4Peer, ipv4 string, name string, prefix string, count uint32) { + routes := peer.V4Routes().Add().SetName(name) + routes.SetNextHopIpv4Address(ipv4). + SetNextHopAddressType(gosnappi.BgpV4RouteRangeNextHopAddressType.IPV4). + SetNextHopMode(gosnappi.BgpV4RouteRangeNextHopMode.MANUAL) + routes.Addresses().Add(). + SetAddress(prefix). + SetPrefix(advertisedRoutesv4Prefix). + SetCount(count) +} + +func configureBGPv6Routes(peer gosnappi.BgpV6Peer, ipv6 string, name string, prefix string, count uint32) { + routes := peer.V6Routes().Add().SetName(name) + routes.SetNextHopIpv6Address(ipv6). + SetNextHopAddressType(gosnappi.BgpV6RouteRangeNextHopAddressType.IPV6). + SetNextHopMode(gosnappi.BgpV6RouteRangeNextHopMode.MANUAL) + routes.Addresses().Add(). + SetAddress(prefix). + SetPrefix(advertisedRoutesv6Prefix). + SetCount(count) +} +func VerifyDUT(t *testing.T, dut *ondatra.DUTDevice) { + + dni := deviations.DefaultNetworkInstance(dut) + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv4Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv4 BGP entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed: ipv4 BGP entries, got: %d, want: %d", got, RouteCount) + } + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv6Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv6 BGP entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed:ipv6 BGP entries, got: %d, want: %d", got, RouteCount) + } + + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv4Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv4 isis entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed: ipv4 isis entries, got: %d, want: %d", got, RouteCount) + + } + + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv6Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv6 isis entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed: ipv6 isis entries, got: %d, want: %d", got, RouteCount) + } +} + +func TestBGP(t *testing.T) { + + dut := ondatra.DUT(t, "dut") + ate := ondatra.ATE(t, "ate") + // DUT Configuration + t.Log("Start DUT interface Config") + configureDUT(t, dut) + // ATE Configuration. + t.Log("Start ATE Config") + config := configureATE(t) + ate.OTG().PushConfig(t, config) + time.Sleep(time.Second * 20) + ate.OTG().StartProtocols(t) + time.Sleep(time.Second * 20) + verifyBGPTelemetry(t, dut) + VerifyDUT(t, dut) +} diff --git a/feature/bgp/admin_distance/otg_tests/admin_distance_test/admin_distance_test.go b/feature/bgp/admin_distance/otg_tests/admin_distance_test/admin_distance_test.go index 10bfe4f8f01..19398b463b4 100644 --- a/feature/bgp/admin_distance/otg_tests/admin_distance_test/admin_distance_test.go +++ b/feature/bgp/admin_distance/otg_tests/admin_distance_test/admin_distance_test.go @@ -29,25 +29,21 @@ import ( "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" - "github.com/openconfig/ondatra/otg" "github.com/openconfig/ygot/ygot" ) const ( - prefixV4Len = uint32(24) - prefixV6Len = uint32(64) - v4Network = "192.168.10.0" - v6Network = "2024:db8:64:64::" - pathID = 1 - prefixesCount = 1 - bgpName = "BGP" - dutAS = uint32(64656) - ateAS = uint32(64657) - peerGrpNamev4 = "BGP-PEER-GROUP-V4" - peerGrpNamev6 = "BGP-PEER-GROUP-V6" - ateSysID = "640000000001" - ateAreaAddress = "49.0002" - lossTolerance = 1 + prefixV4Len = uint32(24) + prefixV6Len = uint32(64) + v4Network = "192.168.10.0" + v6Network = "2024:db8:64:64::" + prefixesCount = 1 + bgpName = "BGP" + dutAS = uint32(64656) + ateAS = uint32(64657) + peerGrpNameV4 = "BGP-PEER-GROUP-V4" + peerGrpNameV6 = "BGP-PEER-GROUP-V6" + lossTolerance = 1 ) var ( @@ -69,8 +65,8 @@ var ( IPv6Len: 126, } - advertisedIPv4 ipAddr = ipAddr{address: v4Network, prefix: prefixV4Len} - advertisedIPv6 ipAddr = ipAddr{address: v6Network, prefix: prefixV6Len} + advertisedIPv4 = ipAddr{address: v4Network, prefix: prefixV4Len} + advertisedIPv6 = ipAddr{address: v6Network, prefix: prefixV6Len} ) type ipAddr struct { @@ -86,7 +82,7 @@ func TestMain(m *testing.M) { func TestAdminDistance(t *testing.T) { ts := isissession.MustNew(t).WithISIS() configurePort3(t, ts) - advertisePrefixFromISISPort(t, ts) + advertisePrefixFromISISPort(ts) t.Run("ISIS Setup", func(t *testing.T) { ts.PushAndStart(t) ts.MustAdjacency(t) @@ -147,13 +143,15 @@ func TestAdminDistance(t *testing.T) { } ts.ATETop.Flows().Clear() - createFlow(t, ts.ATETop, ts.ATE.OTG(), false) - createFlow(t, ts.ATETop, ts.ATE.OTG(), true) + createFlow(t, ts.ATETop, false) + createFlow(t, ts.ATETop, true) ts.ATE.OTG().PushConfig(t, ts.ATETop) ts.ATE.OTG().StartProtocols(t) otgutils.WaitForARP(t, ts.ATE.OTG(), ts.ATETop, "IPv4") otgutils.WaitForARP(t, ts.ATE.OTG(), ts.ATETop, "IPv6") + // b/374639328 #3 30 sec delay added for bgp and isis to come up + time.Sleep(30 * time.Second) ts.ATE.OTG().StartTraffic(t) // added 30 seconds for sleep for traffic flow time.Sleep(30 * time.Second) @@ -215,7 +213,7 @@ func configurePort3(t *testing.T, ts *isissession.TestSession) { atePort3.AddToOTG(ts.ATETop, ap3, dutPort3) } -func createFlow(t *testing.T, config gosnappi.Config, otg *otg.OTG, isV6 bool) { +func createFlow(t *testing.T, config gosnappi.Config, isV6 bool) { t.Helper() flowName := "flowV4" @@ -268,21 +266,21 @@ func setupEBGPAndAdvertise(t *testing.T, ts *isissession.TestSession) { g.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) g.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) - pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNamev4) + pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNameV4) pgv4.PeerAs = ygot.Uint32(dutAS) - pgv4.PeerGroupName = ygot.String(peerGrpNamev4) - pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNamev6) + pgv4.PeerGroupName = ygot.String(peerGrpNameV4) + pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNameV6) pgv6.PeerAs = ygot.Uint32(dutAS) - pgv6.PeerGroupName = ygot.String(peerGrpNamev6) + pgv6.PeerGroupName = ygot.String(peerGrpNameV6) nV4 := bgp.GetOrCreateNeighbor(isissession.ATETrafficAttrs.IPv4) nV4.SetPeerAs(ateAS) nV4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) - nV4.PeerGroup = ygot.String(peerGrpNamev4) + nV4.PeerGroup = ygot.String(peerGrpNameV4) nV6 := bgp.GetOrCreateNeighbor(isissession.ATETrafficAttrs.IPv6) nV6.SetPeerAs(ateAS) nV6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) - nV6.PeerGroup = ygot.String(peerGrpNamev6) + nV6.PeerGroup = ygot.String(peerGrpNameV6) // Configure Import Allow-All policy configureRoutePolicy(t, ts.DUT, "ALLOW", oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) @@ -311,11 +309,11 @@ func setupEBGPAndAdvertise(t *testing.T, ts *isissession.TestSession) { bgp6Peer.SetPeerAddress(isissession.DUTTrafficAttrs.IPv6).SetAsNumber(ateAS).SetAsType(gosnappi.BgpV6PeerAsType.EBGP) // configure emulated IPv4 and IPv6 networks - netv4 := bgp4Peer.V4Routes().Add().SetName("v4-bgpNet-dev") - netv4.Addresses().Add().SetAddress(advertisedIPv4.address).SetPrefix(advertisedIPv4.prefix).SetCount(uint32(prefixesCount)) + netV4 := bgp4Peer.V4Routes().Add().SetName("v4-bgpNet-dev") + netV4.Addresses().Add().SetAddress(advertisedIPv4.address).SetPrefix(advertisedIPv4.prefix).SetCount(uint32(prefixesCount)) - netv6 := bgp6Peer.V6Routes().Add().SetName("v6-bgpNet-dev") - netv6.Addresses().Add().SetAddress(advertisedIPv6.address).SetPrefix(advertisedIPv6.prefix).SetCount(uint32(prefixesCount)) + netV6 := bgp6Peer.V6Routes().Add().SetName("v6-bgpNet-dev") + netV6.Addresses().Add().SetAddress(advertisedIPv6.address).SetPrefix(advertisedIPv6.prefix).SetCount(uint32(prefixesCount)) ts.ATE.OTG().PushConfig(t, ts.ATETop) ts.ATE.OTG().StartProtocols(t) @@ -323,10 +321,10 @@ func setupEBGPAndAdvertise(t *testing.T, ts *isissession.TestSession) { otgutils.WaitForARP(t, ts.ATE.OTG(), ts.ATETop, "IPv6") } -func advertisePrefixFromISISPort(t *testing.T, ts *isissession.TestSession) { - netv4 := ts.ATEIntf1.Isis().V4Routes().Add().SetName("netv4").SetLinkMetric(10).SetOriginType(gosnappi.IsisV4RouteRangeOriginType.EXTERNAL) - netv4.Addresses().Add().SetAddress(advertisedIPv4.address).SetPrefix(advertisedIPv4.prefix).SetCount(uint32(prefixesCount)) +func advertisePrefixFromISISPort(ts *isissession.TestSession) { + netV4 := ts.ATEIntf1.Isis().V4Routes().Add().SetName("netv4").SetLinkMetric(10).SetOriginType(gosnappi.IsisV4RouteRangeOriginType.EXTERNAL) + netV4.Addresses().Add().SetAddress(advertisedIPv4.address).SetPrefix(advertisedIPv4.prefix).SetCount(uint32(prefixesCount)) - netv6 := ts.ATEIntf1.Isis().V6Routes().Add().SetName("netv6").SetLinkMetric(10).SetOriginType(gosnappi.IsisV6RouteRangeOriginType.EXTERNAL) - netv6.Addresses().Add().SetAddress(advertisedIPv6.address).SetPrefix(advertisedIPv6.prefix).SetCount(uint32(prefixesCount)) + netV6 := ts.ATEIntf1.Isis().V6Routes().Add().SetName("netv6").SetLinkMetric(10).SetOriginType(gosnappi.IsisV6RouteRangeOriginType.EXTERNAL) + netV6.Addresses().Add().SetAddress(advertisedIPv6.address).SetPrefix(advertisedIPv6.prefix).SetCount(uint32(prefixesCount)) } diff --git a/feature/experimental/bgp/ate_tests/bgp_long_lived_graceful_restart/README.md b/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/README.md similarity index 100% rename from feature/experimental/bgp/ate_tests/bgp_long_lived_graceful_restart/README.md rename to feature/bgp/ate_tests/bgp_long_lived_graceful_restart/README.md diff --git a/feature/experimental/bgp/ate_tests/bgp_long_lived_graceful_restart/bgp_long_lived_graceful_restart_test.go b/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/bgp_long_lived_graceful_restart_test.go similarity index 100% rename from feature/experimental/bgp/ate_tests/bgp_long_lived_graceful_restart/bgp_long_lived_graceful_restart_test.go rename to feature/bgp/ate_tests/bgp_long_lived_graceful_restart/bgp_long_lived_graceful_restart_test.go diff --git a/feature/experimental/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto b/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto similarity index 100% rename from feature/experimental/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto rename to feature/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto diff --git a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go index 00ff8bae5f0..b9a95fce876 100644 --- a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go +++ b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go @@ -190,6 +190,13 @@ func TestBGPToISISRedistribution(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Logf("Description: %s", tc.desc) tc.applyPolicyFunc(t, ts.DUT) + if tc.ipv4 { + bgpISISRedistribution(t, ts.DUT, "set") + defer bgpISISRedistribution(t, ts.DUT, "delete") + } else { + bgpISISRedistributionV6(t, ts.DUT, "set") + defer bgpISISRedistributionV6(t, ts.DUT, "delete") + } tc.verifyTelemetryFunc(t, ts.DUT, ts.ATE) if tc.testTraffic { if tc.ipv4 { @@ -307,7 +314,9 @@ func nonMatchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { } prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v4PrefixSet) - prefixSet.SetMode(oc.PrefixSet_Mode_IPV4) + if !deviations.SkipPrefixSetMode(dut) { + prefixSet.SetMode(oc.PrefixSet_Mode_IPV4) + } prefixSet.GetOrCreatePrefix(nonAdvertisedIPv4.cidr(t), maskLenExact) if !deviations.SkipSetRpMatchSetOptions(dut) { @@ -316,8 +325,6 @@ func nonMatchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { stmt.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v4PrefixSet) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) - // enable bgp isis redistribution - bgpISISRedistribution(t, dut) } func matchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { @@ -325,7 +332,7 @@ func matchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v4PrefixSet) prefixSet.GetOrCreatePrefix(advertisedIPv4.cidr(t), maskLenExact) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v4PrefixSet).Config(), prefixSet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v4PrefixSet).Config(), prefixSet) } func nonMatchingCommunityRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { @@ -350,13 +357,23 @@ func nonMatchingCommunityRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(v4CommunitySet) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", dummyAS, 200))}) - communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) stmt.GetOrCreateConditions().GetOrCreateBgpConditions().SetCommunitySet(v4CommunitySet) } else { - stmt.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet().SetCommunitySet(v4CommunitySet) + ref1 := stmt.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() + ref1.SetCommunitySet(v4CommunitySet) + ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) } + // Configure ALLOWAll policy + pdef = rp.GetOrCreatePolicyDefinition(allowAllPolicy) + stmt, err = pdef.AppendNewStatement("id-1") + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", "id-1", err) + } + stmt.GetOrCreateActions().PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } } @@ -370,7 +387,7 @@ func matchingCommunityRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(v4CommunitySet) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", ateAS, 100))}) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v4CommunitySet).Config(), communitySet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v4CommunitySet).Config(), communitySet) } } @@ -397,8 +414,10 @@ func verifyNonMatchingPrefixTelemetry(t *testing.T, dut *ondatra.DUTDevice, ate if pName := prefixSet.GetName(); pName != v4PrefixSet { t.Errorf("Prefix set name: %s, want: %s", pName, v4PrefixSet) } - if pMode := prefixSet.GetMode(); pMode != oc.PrefixSet_Mode_IPV4 { - t.Errorf("Prefix set mode: %s, want: %s", pMode, oc.PrefixSet_Mode_IPV4) + if !deviations.SkipPrefixSetMode(dut) { + if pMode := prefixSet.GetMode(); pMode != oc.PrefixSet_Mode_IPV4 { + t.Errorf("Prefix set mode: %s, want: %s", pMode, oc.PrefixSet_Mode_IPV4) + } } if prefix := prefixSet.GetPrefix(nonAdvertisedIPv4.cidr(t), maskLenExact); prefix == nil { t.Errorf("Prefix is nil, want: %s", nonAdvertisedIPv4.cidr(t)) @@ -459,16 +478,11 @@ func verifyNonMatchingCommunityTelemetry(t *testing.T, dut *ondatra.DUTDevice, a if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := nonMatchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %s", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %d", commSetMember, cm) - } + + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) + + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(nonMatchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, nonMatchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().ExtendedIpv4Reachability().Prefix(advertisedIPv4.address).State(), 30*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_ExtendedIpv4Reachability_Prefix]) bool { @@ -485,16 +499,10 @@ func verifyMatchingCommunityTelemetry(t *testing.T, dut *ondatra.DUTDevice, ate if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := matchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } + + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(matchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, matchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().ExtendedIpv4Reachability().Prefix(advertisedIPv4.address).State(), 30*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_ExtendedIpv4Reachability_Prefix]) bool { @@ -523,7 +531,9 @@ func nonMatchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { } prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v6PrefixSet) - prefixSet.SetMode(oc.PrefixSet_Mode_IPV6) + if !deviations.SkipPrefixSetMode(dut) { + prefixSet.SetMode(oc.PrefixSet_Mode_IPV6) + } prefixSet.GetOrCreatePrefix(nonAdvertisedIPv6.cidr(t), maskLenExact) if !deviations.SkipSetRpMatchSetOptions(dut) { @@ -531,9 +541,6 @@ func nonMatchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { } stmt.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v6PrefixSet) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) - - // enable bgp isis redistribution - bgpISISRedistributionV6(t, dut) } func matchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { @@ -541,7 +548,7 @@ func matchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v6PrefixSet) prefixSet.GetOrCreatePrefix(advertisedIPv6.cidr(t), maskLenExact) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v6PrefixSet).Config(), prefixSet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v6PrefixSet).Config(), prefixSet) } func nonMatchingCommunityRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { @@ -566,13 +573,22 @@ func nonMatchingCommunityRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(v6CommunitySet) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", dummyAS, 200))}) - communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { stmt.GetOrCreateConditions().GetOrCreateBgpConditions().SetCommunitySet(v6CommunitySet) + communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) } else { - stmt.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet().SetCommunitySet(v6CommunitySet) + ref1 := stmt.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() + ref1.SetCommunitySet(v6CommunitySet) + ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) } + // Configure ALLOWAll policy + pdef = rp.GetOrCreatePolicyDefinition(allowAllPolicy) + stmt, err = pdef.AppendNewStatement("id-1") + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", "id-1", err) + } + stmt.GetOrCreateActions().PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } } @@ -586,7 +602,7 @@ func matchingCommunityRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(v6CommunitySet) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", ateAS, 100))}) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v6CommunitySet).Config(), communitySet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v6CommunitySet).Config(), communitySet) } } @@ -613,8 +629,10 @@ func verifyNonMatchingPrefixTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, at if pName := prefixSet.GetName(); pName != v6PrefixSet { t.Errorf("Prefix set name: %s, want: %s", pName, v6PrefixSet) } - if pMode := prefixSet.GetMode(); pMode != oc.PrefixSet_Mode_IPV6 { - t.Errorf("Prefix set mode: %s, want: %s", pMode, oc.PrefixSet_Mode_IPV6) + if !deviations.SkipPrefixSetMode(dut) { + if pMode := prefixSet.GetMode(); pMode != oc.PrefixSet_Mode_IPV6 { + t.Errorf("Prefix set mode: %s, want: %s", pMode, oc.PrefixSet_Mode_IPV6) + } } if prefix := prefixSet.GetPrefix(nonAdvertisedIPv6.cidr(t), maskLenExact); prefix == nil { t.Errorf("Prefix is nil, want: %s", nonAdvertisedIPv6.cidr(t)) @@ -675,16 +693,9 @@ func verifyNonMatchingCommunityTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := nonMatchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %d", commSetMember, cm) - } + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(nonMatchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, nonMatchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().Ipv6Reachability().Prefix(advertisedIPv6.address).State(), 60*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_Ipv6Reachability_Prefix]) bool { @@ -701,16 +712,10 @@ func verifyMatchingCommunityTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, at if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := matchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } + + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(matchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, matchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().Ipv6Reachability().Prefix(advertisedIPv6.address).State(), 60*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_Ipv6Reachability_Prefix]) bool { @@ -722,32 +727,46 @@ func verifyMatchingCommunityTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, at } } -func bgpISISRedistribution(t *testing.T, dut *ondatra.DUTDevice) { +func bgpISISRedistribution(t *testing.T, dut *ondatra.DUTDevice, operation string) { dni := deviations.DefaultNetworkInstance(dut) root := &oc.Root{} - tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4) - if !deviations.SkipSettingDisableMetricPropagation(dut) { - tableConn.SetDisableMetricPropagation(false) + if deviations.EnableTableConnections(dut) { + fptest.ConfigEnableTbNative(t, dut) } - if !deviations.DefaultRoutePolicyUnsupported(dut) { - tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4) + if operation == "set" { + if !deviations.SkipSettingDisableMetricPropagation(dut) { + tableConn.SetDisableMetricPropagation(false) + } + if !deviations.DefaultRoutePolicyUnsupported(dut) { + tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } + tableConn.SetImportPolicy([]string{v4RoutePolicy}) + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4).Config(), tableConn) + } else if operation == "delete" { + gnmi.Delete(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4).Config()) } - tableConn.SetImportPolicy([]string{v4RoutePolicy}) - gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4).Config(), tableConn) } -func bgpISISRedistributionV6(t *testing.T, dut *ondatra.DUTDevice) { +func bgpISISRedistributionV6(t *testing.T, dut *ondatra.DUTDevice, operation string) { dni := deviations.DefaultNetworkInstance(dut) root := &oc.Root{} - tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6) - if !deviations.SkipSettingDisableMetricPropagation(dut) { - tableConn.SetDisableMetricPropagation(false) + if deviations.EnableTableConnections(dut) { + fptest.ConfigEnableTbNative(t, dut) } - if !deviations.DefaultRoutePolicyUnsupported(dut) { - tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6) + if operation == "set" { + if !deviations.SkipSettingDisableMetricPropagation(dut) { + tableConn.SetDisableMetricPropagation(false) + } + if !deviations.DefaultRoutePolicyUnsupported(dut) { + tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } + tableConn.SetImportPolicy([]string{v6RoutePolicy}) + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6).Config(), tableConn) + } else if operation == "delete" { + gnmi.Delete(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6).Config()) } - tableConn.SetImportPolicy([]string{v6RoutePolicy}) - gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6).Config(), tableConn) } func bgpISISRedistributionWithRouteTagPolicy(t *testing.T, dut *ondatra.DUTDevice, afi oc.E_Types_ADDRESS_FAMILY) { dni := deviations.DefaultNetworkInstance(dut) @@ -770,11 +789,11 @@ func configureBGPTablePolicyWithSetTag(t *testing.T, prefixSetName, prefixSetAdd if err != nil { t.Fatalf("AppendNewStatement(%s) failed: %v", "routePolicyStatement", err) } - //Create prefix-set + // Create prefix-set prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(prefixSetName) prefixSet.GetOrCreatePrefix(prefixSetAddress, maskLenExact) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(prefixSetName).Config(), prefixSet) - //Create community-set + // Create community-set communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(communitySetName) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", commAS, commValue))}) communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) @@ -785,12 +804,12 @@ func configureBGPTablePolicyWithSetTag(t *testing.T, prefixSetName, prefixSetAdd stmt1.GetOrCreateActions().GetOrCreateSetTag().GetOrCreateInline().SetTag([]oc.RoutingPolicy_PolicyDefinition_Statement_Actions_SetTag_Inline_Tag_Union{oc.UnionUint32(routeTagVal)}) stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - //Create tag-set with above route tag value + // Create tag-set with above route tag value tagSet := rp.GetOrCreateDefinedSets().GetOrCreateTagSet("RouteTagForRedistribution") tagSet.SetName("RouteTagForRedistribution") tagSet.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(routeTagVal)}) - //Route-policy to match tag and accept + // Route-policy to match tag and accept pdef2 := rp.GetOrCreatePolicyDefinition("MatchTagRedistributionPolicy") stmt2, err := pdef2.AppendNewStatement("matchTag") stmt2.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(prefixSetName) diff --git a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto index f4552e8cdf0..a3769f0ac2c 100644 --- a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto +++ b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto @@ -21,7 +21,6 @@ platform_exceptions: { skip_isis_set_metric_style_type: true skip_set_rp_match_set_options: true skip_setting_disable_metric_propagation: true - bgp_conditions_match_community_set_unsupported: true } } platform_exceptions: { @@ -45,3 +44,14 @@ platform_exceptions: { default_route_policy_unsupported: true } } +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_interface_in_default_vrf: true + interface_enabled: true + skip_prefix_set_mode: true + enable_table_connections: true + } +} diff --git a/feature/bgp/bgp_session_mode_configuration_test/README.md b/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/README.md similarity index 100% rename from feature/bgp/bgp_session_mode_configuration_test/README.md rename to feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/README.md diff --git a/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/bgp_session_mode_configuration_test.go b/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/bgp_session_mode_configuration_test.go new file mode 100644 index 00000000000..85bea8459af --- /dev/null +++ b/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/bgp_session_mode_configuration_test.go @@ -0,0 +1,343 @@ +// Copyright 2024 Google LLC +// +// 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. + +package bgp_session_mode_configuration_test + +import ( + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ondatra/otg" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" +) + +// The testbed consists of ate:port1 -> dut:port1. +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +// List of variables. +var ( + dutAttrs = attrs.Attributes{ + Desc: "To ATE", + IPv4: "192.0.2.1", + IPv4Len: 30, + } + ateAttrs = attrs.Attributes{ + Desc: "To DUT", + Name: "ateSrc", + MAC: "02:00:01:01:01:01", + IPv4: "192.0.2.2", + IPv4Len: 30, + } +) + +// Constants. +const ( + dutAS = 65540 + ateAS = 65550 + peerGrpName = "eBGP-PEER-GROUP" + peerLvlPassive = "PeerGrpLevelPassive" + peerLvlActive = "PeerGrpLevelActive" + nbrLvlPassive = "nbrLevelPassive" + nbrLvlActive = "nbrLevelActive" +) + +// configureDUT is used to configure interfaces on the DUT. +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + dc := gnmi.OC() + i1 := dutAttrs.NewOCInterface(dut.Port(t, "port1").Name(), dut) + gnmi.Replace(t, dut, dc.Interface(i1.GetName()).Config(), i1) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, dut.Port(t, "port1")) + } + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, i1.GetName(), deviations.DefaultNetworkInstance(dut), 0) + } +} + +// verifyPortsUp asserts that each port on the device is operating. +func verifyPortsUp(t *testing.T, dev *ondatra.Device) { + t.Helper() + for _, p := range dev.Ports() { + status := gnmi.Get(t, dev, gnmi.OC().Interface(p.Name()).OperStatus().State()) + if want := oc.Interface_OperStatus_UP; status != want { + t.Errorf("%s Status: got %v, want %v", p, status, want) + } + } +} + +// Struct is to pass bgp session parameters. +type bgpTestParams struct { + localAS, peerAS, nbrLocalAS uint32 + peerIP string + transportMode string +} + +// bgpCreateNbr creates a BGP object with neighbors pointing to ate and returns bgp object. +func bgpCreateNbr(bgpParams *bgpTestParams, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + d := &oc.Root{} + ni1 := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + + bgp := niProto.GetOrCreateBgp() + + global := bgp.GetOrCreateGlobal() + global.As = ygot.Uint32(bgpParams.localAS) + global.RouterId = ygot.String(dutAttrs.IPv4) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + + // Note: we have to define the peer group even if we aren't setting any policy because it's + // invalid OC for the neighbor to be part of a peer group that doesn't exist. + pg := bgp.GetOrCreatePeerGroup(peerGrpName) + pg.PeerAs = ygot.Uint32(dutAS) + pg.PeerGroupName = ygot.String(peerGrpName) + pgT := pg.GetOrCreateTransport() + pgT.LocalAddress = ygot.String(dutAttrs.IPv4) + pg.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + + nv4 := bgp.GetOrCreateNeighbor(ateAttrs.IPv4) + nv4.PeerGroup = ygot.String(peerGrpName) + nv4.PeerAs = ygot.Uint32(ateAS) + nv4.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + nv4T := nv4.GetOrCreateTransport() + nv4T.LocalAddress = ygot.String(dutAttrs.IPv4) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + + switch bgpParams.transportMode { + case nbrLvlPassive: + nv4.GetOrCreateTransport().SetPassiveMode(true) + case nbrLvlActive: + nv4.GetOrCreateTransport().SetPassiveMode(false) + case peerLvlPassive: + pg.GetOrCreateTransport().SetPassiveMode(true) + case peerLvlActive: + pg.GetOrCreateTransport().SetPassiveMode(false) + } + + return niProto +} + +// bgpClearConfig removes all BGP configuration from the DUT. +func bgpClearConfig(t *testing.T, dut *ondatra.DUTDevice) { + resetBatch := &gnmi.SetBatch{} + gnmi.BatchDelete(resetBatch, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Config()) + + if deviations.NetworkInstanceTableDeletionRequired(dut) { + tablePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).TableAny() + for _, table := range gnmi.LookupAll[*oc.NetworkInstance_Table](t, dut, tablePath.Config()) { + if val, ok := table.Val(); ok { + if val.GetProtocol() == oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP { + gnmi.BatchDelete(resetBatch, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Table(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, val.GetAddressFamily()).Config()) + } + } + } + } + resetBatch.Set(t, dut) +} + +// verifyBgpTelemetry checks that the dut has an established BGP session with reasonable settings. +func verifyBgpTelemetry(t *testing.T, dut *ondatra.DUTDevice, wantState oc.E_Bgp_Neighbor_SessionState, transMode string, transModeOnATE string) { + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + nbrPath := statePath.Neighbor(ateAttrs.IPv4) + if deviations.BgpSessionStateIdleInPassiveMode(dut) { + if transModeOnATE == nbrLvlPassive || transModeOnATE == peerLvlPassive { + t.Logf("BGP session state idle is supported in passive mode, transMode: %s, transModeOnATE: %s", transMode, transModeOnATE) + wantState = oc.Bgp_Neighbor_SessionState_IDLE + } + } + // Get BGP adjacency state + t.Log("Checking BGP neighbor to state...") + _, ok := gnmi.Watch(t, dut, nbrPath.SessionState().State(), time.Minute, func(val *ygnmi.Value[oc.E_Bgp_Neighbor_SessionState]) bool { + state, present := val.Val() + return present && state == wantState + }).Await(t) + if !ok { + fptest.LogQuery(t, "BGP reported state", nbrPath.State(), gnmi.Get(t, dut, nbrPath.State())) + t.Errorf("BGP Session state is not as expected.") + } + status := gnmi.Get(t, dut, nbrPath.SessionState().State()) + t.Logf("BGP adjacency for %s: %s", ateAttrs.IPv4, status) + t.Logf("wantState: %s, status: %s", wantState, status) + if status != wantState { + t.Errorf("BGP peer %s status got %d, want %d", ateAttrs.IPv4, status, wantState) + } + + nbrTransMode := gnmi.Get(t, dut, nbrPath.Transport().State()) + pgTransMode := gnmi.Get(t, dut, statePath.PeerGroup(peerGrpName).Transport().State()) + t.Logf("Neighbor level passive mode is set to %v on DUT", nbrTransMode.GetPassiveMode()) + t.Logf("Peer group level passive mode is set to %v on DUT", pgTransMode.GetPassiveMode()) + + // Check transport mode telemetry. + switch transMode { + case nbrLvlPassive: + if nbrTransMode.GetPassiveMode() != true { + t.Errorf("Neighbor level passive mode is not set to true on DUT. want true, got %v", nbrTransMode.GetPassiveMode()) + } + t.Logf("Neighbor level passive mode is set to %v on DUT", nbrTransMode.GetPassiveMode()) + case nbrLvlActive: + if nbrTransMode.GetPassiveMode() != false { + t.Errorf("Neighbor level passive mode is not set to false on DUT. want false, got %v", nbrTransMode.GetPassiveMode()) + } + t.Logf("Neighbor level passive mode is set to %v on DUT", nbrTransMode.GetPassiveMode()) + case peerLvlPassive: + if pgTransMode.GetPassiveMode() != true { + t.Errorf("Peer group level passive mode is not set to true on DUT. want true, got %v", pgTransMode.GetPassiveMode()) + } + t.Logf("Peer group level passive mode is set to %v on DUT", pgTransMode.GetPassiveMode()) + case peerLvlActive: + if pgTransMode.GetPassiveMode() != false { + t.Errorf("Peer group level passive mode is not set to false on DUT. want false, got %v", pgTransMode.GetPassiveMode()) + } + t.Logf("Peer group level passive mode is set to %v on DUT", pgTransMode.GetPassiveMode()) + } +} + +// Function to configure ATE configs based on args and returns ate topology handle. +func configureATE(t *testing.T, ateParams *bgpTestParams) gosnappi.Config { + t.Helper() + ate := ondatra.ATE(t, "ate") + port1 := ate.Port(t, "port1") + topo := gosnappi.NewConfig() + + topo.Ports().Add().SetName(port1.ID()) + dev := topo.Devices().Add().SetName(ateAttrs.Name) + eth := dev.Ethernets().Add().SetName(ateAttrs.Name + ".Eth") + eth.Connection().SetPortName(port1.ID()) + eth.SetMac(ateAttrs.MAC) + + ip := eth.Ipv4Addresses().Add().SetName(dev.Name() + ".IPv4") + ip.SetAddress(ateAttrs.IPv4).SetGateway(dutAttrs.IPv4).SetPrefix(uint32(ateAttrs.IPv4Len)) + + bgp := dev.Bgp().SetRouterId(ateAttrs.IPv4) + peerBGP := bgp.Ipv4Interfaces().Add().SetIpv4Name(ip.Name()).Peers().Add() + peerBGP.SetName(ateAttrs.Name + ".BGP4.peer") + peerBGP.SetPeerAddress(ip.Gateway()).SetAsNumber(uint32(ateParams.localAS)) + peerBGP.SetAsType(gosnappi.BgpV4PeerAsType.EBGP) + + switch ateParams.transportMode { + case nbrLvlPassive: + peerBGP.Advanced().SetPassiveMode(true) + case peerLvlPassive: + peerBGP.Advanced().SetPassiveMode(true) + case peerLvlActive: + peerBGP.Advanced().SetPassiveMode(false) + case nbrLvlActive: + peerBGP.Advanced().SetPassiveMode(false) + } + + return topo +} + +func verifyOTGBGPTelemetry(t *testing.T, otg *otg.OTG, c gosnappi.Config) { + // nbrPath := gnmi.OTG().BgpPeer("ateSrc.BGP4.peer") + t.Log("OTG telemetry does not support checking transport mode.") +} + +// TestBgpSessionModeConfiguration is to verify when transport mode is set +// active/passive at both neighbor level and peer group level. +func TestBgpSessionModeConfiguration(t *testing.T) { + dutIP := dutAttrs.IPv4 + dut := ondatra.DUT(t, "dut") + ate := ondatra.ATE(t, "ate") + + // Configure interface on the DUT + t.Log("Start DUT interface Config") + configureDUT(t, dut) + + // Configure Network instance type on DUT + t.Log("Configure Network Instance") + fptest.ConfigureDefaultNetworkInstance(t, dut) + + // Verify Port Status + t.Log("Verifying port status") + verifyPortsUp(t, dut.Device) + + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + + cases := []struct { + name string + dutConf *oc.NetworkInstance_Protocol + ateConf gosnappi.Config + wantBGPState oc.E_Bgp_Neighbor_SessionState + dutTransportMode string + otgTransportMode string + }{ + { + name: "Test transport mode passive at neighbor level on both DUT and ATE ", + dutConf: bgpCreateNbr(&bgpTestParams{localAS: dutAS, peerAS: ateAS, transportMode: nbrLvlPassive}, dut), + ateConf: configureATE(t, &bgpTestParams{localAS: ateAS, peerIP: dutIP, transportMode: nbrLvlPassive}), + wantBGPState: oc.Bgp_Neighbor_SessionState_ACTIVE, + dutTransportMode: nbrLvlPassive, + otgTransportMode: nbrLvlPassive, + }, + { + name: "Test transport mode active on ATE and passive on DUT at neighbor level", + dutConf: bgpCreateNbr(&bgpTestParams{localAS: dutAS, peerAS: ateAS, nbrLocalAS: dutAS, transportMode: nbrLvlPassive}, dut), + ateConf: configureATE(t, &bgpTestParams{localAS: ateAS, peerIP: dutIP, transportMode: nbrLvlActive}), + wantBGPState: oc.Bgp_Neighbor_SessionState_ESTABLISHED, + dutTransportMode: nbrLvlPassive, + otgTransportMode: nbrLvlActive, + }, + { + name: "Test transport passive mode at Peer group level on both DUT and ATE.", + dutConf: bgpCreateNbr(&bgpTestParams{localAS: dutAS, peerAS: ateAS, transportMode: peerLvlPassive}, dut), + ateConf: configureATE(t, &bgpTestParams{localAS: ateAS, peerIP: dutIP, transportMode: peerLvlPassive}), + wantBGPState: oc.Bgp_Neighbor_SessionState_ACTIVE, + dutTransportMode: peerLvlPassive, + otgTransportMode: peerLvlPassive, + }, + { + name: "Test transport mode active on ATE and passive on DUT at peer group level", + dutConf: bgpCreateNbr(&bgpTestParams{localAS: dutAS, peerAS: ateAS, nbrLocalAS: dutAS, transportMode: peerLvlPassive}, dut), + ateConf: configureATE(t, &bgpTestParams{localAS: ateAS, peerIP: dutIP, transportMode: peerLvlActive}), + wantBGPState: oc.Bgp_Neighbor_SessionState_ESTABLISHED, + dutTransportMode: peerLvlPassive, + otgTransportMode: peerLvlActive, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + t.Log("Clear BGP configuration") + bgpClearConfig(t, dut) + + t.Log("Configure BGP Configs on DUT") + gnmi.Replace(t, dut, dutConfPath.Config(), tc.dutConf) + fptest.LogQuery(t, "DUT BGP Config ", dutConfPath.Config(), gnmi.Get(t, dut, dutConfPath.Config())) + + t.Log("Configure BGP on ATE") + ate.OTG().PushConfig(t, tc.ateConf) + ate.OTG().StartProtocols(t) + + t.Logf("Verify BGP telemetry") + verifyBgpTelemetry(t, dut, tc.wantBGPState, tc.dutTransportMode, tc.otgTransportMode) + + t.Logf("Verify BGP telemetry on otg") + verifyOTGBGPTelemetry(t, ate.OTG(), tc.ateConf) + + t.Log("Clear BGP Configs on ATE") + ate.OTG().StopProtocols(t) + }) + } +} diff --git a/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/metadata.textproto b/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/metadata.textproto new file mode 100644 index 00000000000..0795ff831b0 --- /dev/null +++ b/feature/bgp/bgp_session_mode/otg_tests/bgp_session_mode_configuration_test/metadata.textproto @@ -0,0 +1,42 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "7e2082f6-4fbc-4e2b-a8a8-c83af2574ec4" +plan_id: "RT-1.55" +description: "BGP session mode (active/passive)" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + ipv4_missing_enabled: true + connect_retry: true + bgp_session_state_idle_in_passive_mode: true + } +} +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_port_speed: true + explicit_interface_in_default_vrf: true + missing_value_for_defaults: true + interface_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + connect_retry: true + omit_l2_mtu: true + network_instance_table_deletion_required: true + bgp_md5_requires_reset: true + missing_value_for_defaults: true + interface_enabled: true + default_network_instance: "default" + } +} diff --git a/feature/bgp/multihop/README.md b/feature/bgp/multihop/README.md new file mode 100644 index 00000000000..b83ddab4ce1 --- /dev/null +++ b/feature/bgp/multihop/README.md @@ -0,0 +1,93 @@ +# RT-1.63: BGP Multihop + +## Summary + +This test case validates the multihop eBGP feature, where two BGP speakers establish a peering session even when they are not directly connected. + +## Testbed type + +* [`featureprofiles/topologies/atedut_2.testbed`](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed) + +## Procedure + +### Configuration + +1) Create the topology below: + +```mermaid +graph LR; +A[ATE:Port1] -- EBGP --> B[Port1:DUT:Port2]; +B ----> C[Port2:ATE] --> eBGP peer; +``` + +2) Configure the eBGP peering session: Establish an eBGP peering relationship between ATE1 and Port 1 on the DUT. +3) Assign IP addresses: Configure IPv4 and IPv6 addresses on all relevant interfaces on the DUT, ATE1, and ATE2. +4) Create a loopback interface: Configure a loopback interface on the DUT and assign it an IP address. This will serve as the DUT's identifier for the BGP session. +5) Establish static routing on the DUT: Configure a static route on the DUT that directs traffic destined for the eBGP peer's IP address (connected to ATE2) through ATE2. This ensures the DUT can reach the peer. +6) Establish static routing on ATE2: Configure a static route on ATE2 that directs traffic destined for the DUT's loopback IP address towards the DUT. This allows the eBGP peer on ATE1 to reach and identify the DUT via its loopback address. + +### Tests + +### RT-1.63.1: Establish eBGP session over multihop + +1) Configure the eBGP peering session: Establish an eBGP peering relationship between the DUT's loopback interface and the eBGP peer connected to ATE2. This means the DUT will use its loopback address as its BGP identifier. +2) Specify the neighbor address: Configure the DUT to use the eBGP peer's IP address (connected to ATE2) as the neighbor address for this BGP session. +3) Enable multihop: Since the eBGP peer is not directly connected to the DUT, enable the multihop option for this BGP neighbor on the DUT. Set the Time-to-Live (TTL) value to 2 to allow the BGP packets to traverse the intermediate link between the DUT and ATE2. +4) Validate session establishment: Confirm that the eBGP session is successfully established between the DUT's loopback interface and the eBGP peer connected to ATE2. This can be verified by checking the BGP neighbor status, following this path + * /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/session-state +5) Verify BGP updates: Ensure that the DUT and the eBGP peer are exchanging BGP updates correctly, indicating that the peering is functional and routing information is being shared. + * Check the counters in the followong paths are incrementing: + * /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/messages/sent/UPDATE + * /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/messages/received/UPDATE + +### RT-1.63.2: Advertise prefixes over multihop eBGP + +1) Advertise prefixes: Configure the eBGP peer to advertise the following IPv4 and IPv6 prefixes to the DUT: + * BGP-V4 = 203.0.200.0/24 + * BGP-V6 = 2001:db8:128:200::/64 +2) Verify prefix reception: Confirm that the DUT successfully receives the advertised prefixes from the eBGP peer. +3) Check routing table: Inspect the DUT's routing table to ensure that the received prefixes have been installed correctly. +4) Validate next hop: Verify that the next hop associated with the installed prefixes in the DUT's routing table is the IP address of ATE Port 2. This confirms that the DUT knows to forward traffic for these prefixes towards ATE2, following paths: + * /network-instances/network-instance/afts/next-hops/next-hop/state/ip-address + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix + +### RT-1.63.3: Traffic forwarding over multihop eBGP + +1) Generate traffic: Initiate traffic from ATE port-1 towards the DUT. This traffic should be destined for the prefixes that were advertised by the eBGP peer connected to ATE2. + * Send 1000 packets on 10 flows per address family +2) Verify forwarding: Confirm that the DUT correctly forwards the traffic to the eBGP peer via ATE port-2. This demonstrates that the multihop eBGP session is functioning as expected and that the DUT is using the learned routes to direct traffic appropriately. +3) Monitor traffic counters: Examine the traffic counters on the relevant DUT and ATE interfaces to verify that traffic is flowing as expected and that there are no drops or errors. + +## OpenConfig Path and RPC Coverage + +```yaml +paths: + ## Config paths + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/ebgp-multihop/config/enabled: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/ebgp-multihop/config/multihop-ttl: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/ebgp-multihop/config/enabled: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/ebgp-multihop/config/multihop-ttl: + + ## state paths + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/ebgp-multihop/state/enabled: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/ebgp-multihop/state/multihop-ttl: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/ebgp-multihop/state/enabled: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/ebgp-multihop/state/multihop-ttl: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index: + /network-instances/network-instance/afts/next-hops/next-hop/state/ip-address: + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true +``` + +## Minimum DUT platform requirement + +* FFF - Fixed Form Factor \ No newline at end of file diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/bgp_multipath_ecmp_test.go b/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/bgp_multipath_ecmp_test.go index 2354ccc83ac..a2eaf8195e6 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/bgp_multipath_ecmp_test.go +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/bgp_multipath_ecmp_test.go @@ -15,13 +15,12 @@ package bgp_multipath_ecmp_test import ( + "math/rand" "sort" "strconv" "testing" "time" - "math/rand" - "github.com/open-traffic-generator/snappi/gosnappi" "github.com/openconfig/featureprofiles/internal/cfgplugins" "github.com/openconfig/featureprofiles/internal/deviations" @@ -30,6 +29,7 @@ import ( "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygnmi/ygnmi" "github.com/openconfig/ygot/ygot" ) @@ -39,8 +39,8 @@ const ( prefixesCount = 4 pathID = 1 maxPaths = 2 - trafficPps = 100000 - totalPackets = 12000000 + trafficPps = 1000 + totalPackets = 120000 lossTolerancePct = 0 lbToleranceFms = 20 ) @@ -54,7 +54,7 @@ func configureOTG(t *testing.T, bs *cfgplugins.BGPSession) { byName := func(i, j int) bool { return devices[i].Name() < devices[j].Name() } sort.Slice(devices, byName) for i, otgPort := range bs.ATEPorts { - if i == 0 { + if i < 2 { continue } @@ -92,7 +92,7 @@ func configureFlow(t *testing.T, bs *cfgplugins.BGPSession) { bs.ATETop.Flows().Clear() var rxNames []string - for i := 1; i < len(bs.ATEPorts); i++ { + for i := 2; i < len(bs.ATEPorts); i++ { rxNames = append(rxNames, bs.ATEPorts[i].Name+".BGP4.peer.rr4") } flow := bs.ATETop.Flows().Add().SetName("flow") @@ -125,7 +125,7 @@ func verifyECMPLoadBalance(t *testing.T, ate *ondatra.ATEDevice, pc int, expecte max := expectedPerLinkFms + (expectedPerLinkFms * lbToleranceFms / 100) got := 0 - for i := 2; i <= pc; i++ { + for i := 3; i <= pc; i++ { framesRx := gnmi.Get(t, ate.OTG(), gnmi.OTG().Port(ate.Port(t, "port"+strconv.Itoa(i)).ID()).Counters().InFrames().State()) if framesRx <= lbToleranceFms { t.Logf("Skip: Traffic through port%d interface is %d", i, framesRx) @@ -193,16 +193,25 @@ func TestBGPSetup(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { bs := cfgplugins.NewBGPSession(t, cfgplugins.PortCount4, nil) - bs.WithEBGP(t, []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST}, []string{"port2", "port3", "port4"}, true, !tc.enableMultiAS) + bs.WithEBGP(t, []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST}, []string{"port3", "port4"}, true, !tc.enableMultiAS) dni := deviations.DefaultNetworkInstance(bs.DUT) bgp := bs.DUTConf.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").GetOrCreateBgp() gEBGP := bgp.GetOrCreateGlobal().GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().GetOrCreateEbgp() - pgUseMulitplePaths := bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths() if tc.enableMultipath { t.Logf("Enable Multipath") - pgUseMulitplePaths.Enabled = ygot.Bool(true) + switch bs.DUT.Vendor() { + case ondatra.NOKIA: + //BGP multipath enable/disable at the peer-group level not required b/376799583 + t.Logf("BGP Multipath enable/disable not required under Peer-group by %s hence skipping", bs.DUT.Vendor()) + default: + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().Enabled = ygot.Bool(true) + } t.Logf("Enable Maximum Paths") - gEBGP.MaximumPaths = ygot.Uint32(maxPaths) + if deviations.EnableMultipathUnderAfiSafi(bs.DUT) { + gEBGP.MaximumPaths = ygot.Uint32(maxPaths) + } else { + bgp.GetOrCreateGlobal().GetOrCreateUseMultiplePaths().GetOrCreateEbgp().MaximumPaths = ygot.Uint32(maxPaths) + } } if tc.enableMultiAS && !deviations.SkipSettingAllowMultipleAS(bs.DUT) && deviations.SkipAfiSafiPathForBgpMultipleAs(bs.DUT) { t.Logf("Enable MultiAS ") @@ -225,16 +234,37 @@ func TestBGPSetup(t *testing.T) { aftsPath := gnmi.OC().NetworkInstance(dni).Afts() prefix := prefixesStart + "/" + strconv.Itoa(prefixP4Len) - ipv4Entry := gnmi.Get[*oc.NetworkInstance_Afts_Ipv4Entry](t, bs.DUT, aftsPath.Ipv4Entry(prefix).State()) - hopGroup := gnmi.Get[*oc.NetworkInstance_Afts_NextHopGroup](t, bs.DUT, aftsPath.NextHopGroup(ipv4Entry.GetNextHopGroup()).State()) + if deviations.BgpMaxMultipathPathsUnsupported(bs.DUT) { tc.expectedPaths = 3 } else { - if got, want := len(hopGroup.NextHop), tc.expectedPaths; got != want { - t.Errorf("prefix: %s, found %d hops, want %d", ipv4Entry.GetPrefix(), got, want) + val, ok := gnmi.Watch(t, bs.DUT, aftsPath.Ipv4Entry(prefix).State(), time.Minute, + func(val *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv4Entry]) bool { + ipv4Entry, present := val.Val() + if !present { + return false + } + + hopGroup := gnmi.Get[*oc.NetworkInstance_Afts_NextHopGroup](t, bs.DUT, aftsPath.NextHopGroup(ipv4Entry.GetNextHopGroup()).State()) + got := len(hopGroup.NextHop) + want := tc.expectedPaths + return got == want + }).Await(t) + + if !ok { + ipv4Entry, present := val.Val() + if !present { + t.Errorf("prefix: %s, found no aft entry", ipv4Entry.GetPrefix()) + } else { + hopGroup := gnmi.Get[*oc.NetworkInstance_Afts_NextHopGroup](t, bs.DUT, aftsPath.NextHopGroup(ipv4Entry.GetNextHopGroup()).State()) + got := len(hopGroup.NextHop) + want := tc.expectedPaths + if got != want { + t.Errorf("prefix: %s, found %d hops, want %d", ipv4Entry.GetPrefix(), got, want) + } + } } } - sleepTime := time.Duration(totalPackets/trafficPps) + 5 bs.ATE.OTG().StartTraffic(t) time.Sleep(sleepTime * time.Second) diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto b/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto index 7c594707925..b696e86ea0b 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto @@ -12,6 +12,7 @@ platform_exceptions: { deviations: { ipv4_missing_enabled: true skip_afi_safi_path_for_bgp_multiple_as: true + enable_multipath_under_afi_safi: true } } platform_exceptions: { @@ -20,6 +21,7 @@ platform_exceptions: { } deviations: { bgp_max_multipath_paths_unsupported: true + multipath_unsupported_neighbor_or_afisafi: true } } platform_exceptions: { @@ -27,7 +29,7 @@ platform_exceptions: { vendor: NOKIA } deviations: { - explicit_port_speed: true + enable_multipath_under_afi_safi: true explicit_interface_in_default_vrf: true interface_enabled: true } @@ -42,8 +44,7 @@ platform_exceptions: { interface_enabled: true default_network_instance: "default" missing_value_for_defaults: true - skip_setting_allow_multiple_as: false + skip_setting_allow_multiple_as: true } } tags: TAGS_DATACENTER_EDGE - diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/README.md b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/README.md index fb8c4ec0341..caf12697c34 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/README.md +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/README.md @@ -19,43 +19,90 @@ Validate BGP in multipath UCMP support with link bandwidth community * ATE port-2 and DUT port-2 * ATE port-3 and DUT port-3 * Enable an Accept-route all import-policy/export-policy for eBGP session - under the neighbor AFI/SAFI -* Create an IPv4 internal target network attached to ATE port 2 and 3 + under the neighbor AFI/SAFI - IPv6 unicast and IPv4 unicast. +* Create an single IPv4 internal target network attached to ATE port 2 and 3 +* Create an single IPv6 internal target network attached to ATE port 2 and 3 + ### Tests -* RT-1.52.1: Verify use of community type - - * Configure ATE port 1, 2 and 3 on different AS - * Enable multipath, set maximum-paths limit to 2, enable allow multiple - AS, and send community type to BOTH (STANDARD and EXTENDED) - * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/config/enabled - * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/ebgp/config/allow-multiple-as - * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/ebgp/config/maximum-paths - * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/send-community-type - * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/use-multiple-paths/ebgp/link-bandwidth-ext-community/config/enabled - * Advertise equal cost paths from port2 and port3 of ATE - * Check entries in FIB for advertised prefix, it should have 2 entries - * /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops - * Initiate traffic from ATE port-1 to the DUT and destined to internal - target network - * Check entire traffic should only be unequally forwarded between DUT - port2 and port3 - -## Config Parameter Coverage - -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/config/enabled -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/ebgp/config/allow-multiple-as -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/ebgp/config/maximum-paths -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/send-community-type -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/use-multiple-paths/ebgp/link-bandwidth-ext-community/config/enabled - -## Telemetry Parameter Coverage - -* /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state -* /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group -* /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=]/state -* /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops +* RT-1.52.1: Verify use of unequal community type + + * Test Configuration + * Configure ATE port 1, 2 and 3 on different AS, with boths AFI/SAFI + * Advertise IPv4 and IPv6 internal target, both, form both ATE port-1 and ATE port-2 in eBGP. + * For ATE port 2 attach `link-bandwidth:23456:10K` extended-community + * For ATE port 3 attach `link-bandwidth:23456:5K` extended-community + * Enable multipath, set maximum-paths limit to 2, enable allow multiple + AS, and send community type to [STANDARD, EXTENDED, LARGE] + * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/config/enabled + * /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/use-multiple-paths/ebgp/config/allow-multiple-as + * /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/use-multiple-paths/ebgp/config/maximum-paths + * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/send-community-type + * /network-instances/network-instance/protocols/protocol/bgp/global/use-multiple-paths/ebgp/link-bandwidth-ext-community/config/enabled + * Advertise equal cost paths from port2 and port3 of ATE + * Initiate traffic from ATE port-1 to the DUT and destined to internal + target network. + * Use UDP traffic with src and dst port randomly selected from 1-65535 range for each packet. Or equivalent pattern guaranteeng high entropy of traffic. + * Behaviour Validation + * Check entries in AFT for advertised prefix, it should have 2 entries.\ + The `weight` leafs of next-hops shall be in 2:1 ratio. + * Find next-hop-group IDs for both internal target networks: + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry[prefix=IPv4 internal target network]/state/**next-hop-group** + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry[prefix=IPv6 internal target network]/state/**next-hop-group** + * using next-hop-group as key find number and weight of next-hops of both internal target network + * /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=next-hop-group ID]/next-hops/next-hop/state/index + * /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=next-hop-group ID]/next-hops/next-hop/state/**weight** + * Check entire traffic should be unequally forwarded between DUT + port2 and port3 only + * 66% via port2 + * 33% via port3 + * with +/-5% tolerance + +* RT-1.52.2: Verify use of equal community type + + * Test Configuration + Use test configuration as in RT-1.52.1 above with following modifications: + * Advertise IPv4 and IPv6 internal target, both, form both ATE port-1 and ATE port-2 in eBGP. + * For ATE port 2 attach `link-bandwidth:23456:10K` extended-community + * For ATE port 3 attach `link-bandwidth:23456:10K` extended-community + * Behaviour Validation + * Check entries in AFT for advertised prefix, it should have 2 entries.\ + The `weight` leafs of next-hops shall be in 1:1 ratio. + * Find next-hop-group IDs for both internal target networks: + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry[prefix=IPv4 internal target network]/state/**next-hop-group** + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry[prefix=IPv6 internal target network]/state/**next-hop-group** + * using next-hop-group as key find number and weight of next-hops of both internal target network + * /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=next-hop-group ID]/next-hops/next-hop/state/index + * /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=next-hop-group ID]/next-hops/next-hop/state/**weight** + * Check entire traffic should be unequally forwarded between DUT + port2 and port3 only + * 50% via port2 + * 50% via port3 + * with +/-5% tolerance + +* RT-1.52.3: Verify BGP multipath when some path missing link-bandwidth extended-community + + * Test Configuration + Use test configuration as in RT-1.52.1 above with following modifications: + * Configure ATE port 1, 2 and 3 on different AS, with boths AFI/SAFI + * Advertise IPv4 and IPv6 internal target, both, form both ATE port-1 and ATE port-2 in eBGP. + * For ATE port 2 attach `link-bandwidth:23456:10K` extended-community + * For ATE port 3 **DO NOT** attach any link-bandwidth extended-community + * Behaviour Validation + * Check entries in AFT for advertised prefix, it should have 2 entries.\ + The `weight` leafs of next-hops shall be in 1:1 ratio. + * Find next-hop-group IDs for both internal target networks: + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry[prefix=IPv4 internal target network]/state/**next-hop-group** + * /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry[prefix=IPv6 internal target network]/state/**next-hop-group** + * using next-hop-group as key find number and weight of next-hops of both internal target network + * /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=next-hop-group ID]/next-hops/next-hop/state/index + * /network-instances/network-instance/afts/next-hop-groups/next-hop-group[id=next-hop-group ID]/next-hops/next-hop/state/**weight** + * Check entire traffic should be unequally forwarded between DUT + port2 and port3 only + * 50% via port2 + * 50% via port3 + * with +/-5% tolerance ## OpenConfig Path and RPC Coverage @@ -64,6 +111,18 @@ rpcs: gnmi: gNMI.Get: gNMI.Subscribe: +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/use-multiple-paths/config/enabled: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/use-multiple-paths/ebgp/config/allow-multiple-as: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/use-multiple-paths/ebgp/config/maximum-paths: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/send-community-type: + /network-instances/network-instance/protocols/protocol/bgp/global/use-multiple-paths/ebgp/link-bandwidth-ext-community/config/enabled: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/weight: + ``` ## Required DUT platform diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/bgp_multipath_wecmp_test.go b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/bgp_multipath_wecmp_test.go index 3ab2c1cc4fd..f6db0a2adab 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/bgp_multipath_wecmp_test.go +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/bgp_multipath_wecmp_test.go @@ -42,10 +42,10 @@ const ( trafficPps = 1000 totalPackets = 120000 lossTolerancePct = 0 - lbToleranceFms = 5 + lbToleranceFms = 10 ) -var linkBw = []int{10, 5} +var linkBw = []int{10} func TestMain(m *testing.M) { fptest.RunTests(m) @@ -71,13 +71,32 @@ func configureOTG(t *testing.T, bs *cfgplugins.BGPSession) { routeAddress.SetPrefix(prefixP4Len) routeAddress.SetCount(prefixesCount) bgp4PeerRoute.AddPath().SetPathId(pathID) - bgpExtCom := bgp4PeerRoute.ExtendedCommunities().Add() - bgpExtCom.NonTransitive2OctetAsType().LinkBandwidthSubtype().SetBandwidth(float32(linkBw[i-2] * 1000)) } configureFlow(bs) } +func attachLBWithInternalNetwork(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config) { + devices := top.Devices().Items() + byName := func(i, j int) bool { return devices[i].Name() < devices[j].Name() } + sort.Slice(devices, byName) + + for _, i := range []int{2, 3} { + bgp4Peer := devices[i].Bgp().Ipv4Interfaces().Items()[0].Peers().Items()[0] + bgp4PeerRoute := bgp4Peer.V4Routes().Items()[0] + bgp4PeerRoute.ExtendedCommunities().Clear() + if i-2 < len(linkBw) { + bgpExtCom := bgp4PeerRoute.ExtendedCommunities().Add() + bgpExtCom.NonTransitive2OctetAsType().LinkBandwidthSubtype().SetBandwidth(float32(linkBw[i-2] * 1000)) + bgpExtCom.NonTransitive2OctetAsType().LinkBandwidthSubtype().SetGlobal2ByteAs(23456) + } + } + + ate.OTG().PushConfig(t, top) + ate.OTG().StartProtocols(t) + otgutils.WaitForARP(t, ate.OTG(), top, "IPv4") +} + func configureFlow(bs *cfgplugins.BGPSession) { bs.ATETop.Flows().Clear() @@ -118,8 +137,15 @@ func checkPacketLoss(t *testing.T, ate *ondatra.ATEDevice) { func verifyECMPLoadBalance(t *testing.T, ate *ondatra.ATEDevice, pc int, expectedLinks int) { framesTx := gnmi.Get(t, ate.OTG(), gnmi.OTG().Port(ate.Port(t, "port1").ID()).Counters().OutFrames().State()) - expectedPerLinkFmsP3 := int(float32(linkBw[0]) / (float32(linkBw[0] + linkBw[1])) * float32(framesTx)) - expectedPerLinkFmsP4 := int(float32(linkBw[1]) / (float32(linkBw[0] + linkBw[1])) * float32(framesTx)) + var lb1, lb2 float32 + if len(linkBw) == 1 { + lb1, lb2 = float32(linkBw[0]), float32(linkBw[0]) + } else { + lb1, lb2 = float32(linkBw[0]), float32(linkBw[1]) + } + + expectedPerLinkFmsP3 := int(lb1 / (lb1 + lb2) * float32(framesTx)) + expectedPerLinkFmsP4 := int(lb2 / (lb1 + lb2) * float32(framesTx)) t.Logf("Total packets %d flow through the %d links and expected per link packets: %d, %d", framesTx, expectedLinks, expectedPerLinkFmsP3, expectedPerLinkFmsP4) p3Min := expectedPerLinkFmsP3 - (expectedPerLinkFmsP3 * lbToleranceFms / 100) @@ -146,13 +172,27 @@ func verifyECMPLoadBalance(t *testing.T, ate *ondatra.ATEDevice, pc int, expecte func TestBGPSetup(t *testing.T) { bs := cfgplugins.NewBGPSession(t, cfgplugins.PortCount4, nil) bs.WithEBGP(t, []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST}, []string{"port3", "port4"}, true, false) + dni := deviations.DefaultNetworkInstance(bs.DUT) bgp := bs.DUTConf.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").GetOrCreateBgp() + switch bs.DUT.Vendor() { + case ondatra.NOKIA: + //BGP multipath enable/disable at the peer-group level not required b/376799583 + t.Logf("BGP Multipath enable/disable is not required under Peer-group by %s hence skipping", bs.DUT.Vendor()) + default: + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().Enabled = ygot.Bool(true) + } + + if !deviations.SkipBgpSendCommunityType(bs.DUT) { + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_STANDARD, oc.Bgp_CommunityType_EXTENDED, oc.Bgp_CommunityType_LARGE}) + } + if deviations.MultipathUnsupportedNeighborOrAfisafi(bs.DUT) { t.Logf("MultipathUnsupportedNeighborOrAfisafi is supported") bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateUseMultiplePaths().Enabled = ygot.Bool(true) bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateUseMultiplePaths().GetOrCreateEbgp().AllowMultipleAs = ygot.Bool(true) } + if deviations.SkipAfiSafiPathForBgpMultipleAs(bs.DUT) { var communitySetCLIConfig string t.Log("AfiSafi Path For BgpMultipleAs is not supported") @@ -170,13 +210,22 @@ func TestBGPSetup(t *testing.T) { helpers.GnmiCLIConfig(t, bs.DUT, communitySetCLIConfig) } } else { - t.Logf("AfiSafi Path For BgpMultipleAs is supported") - gEBGP := bgp.GetOrCreateGlobal().GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().GetOrCreateEbgp() - if !deviations.SkipSettingAllowMultipleAS(bs.DUT) { + if deviations.SkipSettingAllowMultipleAS(bs.DUT) { + bgp.GetOrCreateGlobal().GetOrCreateUseMultiplePaths().GetOrCreateEbgp().MaximumPaths = ygot.Uint32(maxPaths) + bgp.GetOrCreateGlobal().GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().GetOrCreateEbgp().GetOrCreateLinkBandwidthExtCommunity().Enabled = ygot.Bool(true) + switch bs.DUT.Vendor() { + case ondatra.ARISTA: + helpers.GnmiCLIConfig(t, bs.DUT, "router bgp 65501\n ucmp mode 1\n") + default: + t.Fatalf("Unsupported vendor %s for deviation 'SkipSettingAllowMultipleAS'", bs.DUT.Vendor()) + } + } else { + gEBGP := bgp.GetOrCreateGlobal().GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().GetOrCreateEbgp() gEBGP.AllowMultipleAs = ygot.Bool(true) + gEBGP.MaximumPaths = ygot.Uint32(maxPaths) + gEBGP.GetOrCreateLinkBandwidthExtCommunity().Enabled = ygot.Bool(true) } } - bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateUseMultiplePaths().Enabled = ygot.Bool(true) configureOTG(t, bs) bs.PushAndStart(t) @@ -187,22 +236,55 @@ func TestBGPSetup(t *testing.T) { t.Logf("Verify OTG BGP sessions up") cfgplugins.VerifyOTGBGPEstablished(t, bs.ATE) + testCases := []struct { + name string + desc string + linkBw []int + }{ + { + name: "RT-1.52.1", + desc: "Verify BGP multipath when some path missing link-bandwidth extended-community", + linkBw: []int{10}, + }, + { + name: "RT-1.52.2", + desc: "Verify use of equal community type", + linkBw: []int{10, 10}, + }, + { + name: "RT-1.52.1", + desc: "Verify use of unequal community type", + linkBw: []int{10, 5}, + }, + } + aftsPath := gnmi.OC().NetworkInstance(dni).Afts() prefix := prefixesStart + "/" + strconv.Itoa(prefixP4Len) - ipv4Entry := gnmi.Get[*oc.NetworkInstance_Afts_Ipv4Entry](t, bs.DUT, aftsPath.Ipv4Entry(prefix).State()) - hopGroup := gnmi.Get[*oc.NetworkInstance_Afts_NextHopGroup](t, bs.DUT, aftsPath.NextHopGroup(ipv4Entry.GetNextHopGroup()).State()) - if got, want := len(hopGroup.NextHop), 2; got != want { - t.Errorf("prefix: %s, found %d hops, want %d", ipv4Entry.GetPrefix(), got, want) - } else { - t.Logf("prefix: %s, found %d hops, want %d", ipv4Entry.GetPrefix(), got, want) - } - sleepTime := time.Duration(totalPackets/trafficPps) + 5 - bs.ATE.OTG().StartTraffic(t) - time.Sleep(sleepTime * time.Second) - bs.ATE.OTG().StopTraffic(t) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + linkBw = tc.linkBw + attachLBWithInternalNetwork(t, bs.ATE, bs.ATETop) + time.Sleep(30 * time.Second) - otgutils.LogFlowMetrics(t, bs.ATE.OTG(), bs.ATETop) - checkPacketLoss(t, bs.ATE) - verifyECMPLoadBalance(t, bs.ATE, int(cfgplugins.PortCount4), 2) + ipv4Entry := gnmi.Get[*oc.NetworkInstance_Afts_Ipv4Entry](t, bs.DUT, aftsPath.Ipv4Entry(prefix).State()) + hopGroup := gnmi.Get[*oc.NetworkInstance_Afts_NextHopGroup](t, bs.DUT, aftsPath.NextHopGroup(ipv4Entry.GetNextHopGroup()).State()) + if got, want := len(hopGroup.NextHop), 2; got != want { + t.Errorf("prefix: %s, found %d hops, want %d", ipv4Entry.GetPrefix(), got, want) + } else { + for i, nh := range hopGroup.NextHop { + t.Logf("Prefix %s, NextHop(%d) weight: %d", ipv4Entry.GetPrefix(), i, nh.GetWeight()) + } + } + + sleepTime := time.Duration(totalPackets/trafficPps) + 5 + bs.ATE.OTG().StartTraffic(t) + time.Sleep(sleepTime * time.Second) + bs.ATE.OTG().StopTraffic(t) + + otgutils.LogFlowMetrics(t, bs.ATE.OTG(), bs.ATETop) + checkPacketLoss(t, bs.ATE) + verifyECMPLoadBalance(t, bs.ATE, int(cfgplugins.PortCount4), 2) + }) + } } diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto index cba5b2008ac..1f758c5b4f5 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto @@ -13,6 +13,7 @@ platform_exceptions: { ipv4_missing_enabled: true skip_setting_allow_multiple_as: true skip_afi_safi_path_for_bgp_multiple_as: true + skip_bgp_send_community_type: true } } platform_exceptions: { @@ -28,7 +29,7 @@ platform_exceptions: { vendor: NOKIA } deviations: { - explicit_port_speed: true + skip_bgp_send_community_type: true explicit_interface_in_default_vrf: true interface_enabled: true } @@ -43,7 +44,7 @@ platform_exceptions: { interface_enabled: true default_network_instance: "default" missing_value_for_defaults: true - skip_setting_allow_multiple_as: false + skip_setting_allow_multiple_as: true } } tags: TAGS_DATACENTER_EDGE diff --git a/feature/experimental/bgp/otg_tests/base_bgp_session_parameters/README.md b/feature/bgp/otg_tests/base_bgp_session_parameters/README.md similarity index 61% rename from feature/experimental/bgp/otg_tests/base_bgp_session_parameters/README.md rename to feature/bgp/otg_tests/base_bgp_session_parameters/README.md index dc3416dbd47..8bdeb896e1a 100644 --- a/feature/experimental/bgp/otg_tests/base_bgp_session_parameters/README.md +++ b/feature/bgp/otg_tests/base_bgp_session_parameters/README.md @@ -48,48 +48,21 @@ Test the normal session establishment and termination: * Explicit holdtime interval and keepalive interval. * Explicit connect retry interval. -## Config Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/bgp/global - -* For Parameters: - - * config/as - * config/router-id - * config/peer-as - * config/local-as - * config/description - * timers/config/hold-time - * timers/config/keepalive-interval - * timers/config/minimum-route-advertisement-interval - -* For prefixes: - - * /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group - * /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor - -## Telemetry Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/bgp/ - -* For Parameters: - - * state/last-established - * state/messages/received/NOTIFICATION - * state/negotiated-hold-time - * state/supported-capabilities - -## Protocol/RPC Parameter coverage - -* BGP - - * OPEN - - * Version - * My Autonomous System - * BGP Identifier - * Hold Time +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/timers/config/hold-time: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/timers/config/keepalive-interval: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/last-established: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/messages/received/NOTIFICATION: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/timers/state/negotiated-hold-time: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/supported-capabilities: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` diff --git a/feature/experimental/bgp/otg_tests/base_bgp_session_parameters/base_bgp_session_parameters_test.go b/feature/bgp/otg_tests/base_bgp_session_parameters/base_bgp_session_parameters_test.go similarity index 100% rename from feature/experimental/bgp/otg_tests/base_bgp_session_parameters/base_bgp_session_parameters_test.go rename to feature/bgp/otg_tests/base_bgp_session_parameters/base_bgp_session_parameters_test.go diff --git a/feature/experimental/bgp/otg_tests/base_bgp_session_parameters/metadata.textproto b/feature/bgp/otg_tests/base_bgp_session_parameters/metadata.textproto similarity index 100% rename from feature/experimental/bgp/otg_tests/base_bgp_session_parameters/metadata.textproto rename to feature/bgp/otg_tests/base_bgp_session_parameters/metadata.textproto diff --git a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/README.md b/feature/bgp/otg_tests/bgp_2byte_4byte_asn/README.md similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/README.md rename to feature/bgp/otg_tests/bgp_2byte_4byte_asn/README.md diff --git a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/bgp_2byte_4byte_asn_test.go b/feature/bgp/otg_tests/bgp_2byte_4byte_asn/bgp_2byte_4byte_asn_test.go similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/bgp_2byte_4byte_asn_test.go rename to feature/bgp/otg_tests/bgp_2byte_4byte_asn/bgp_2byte_4byte_asn_test.go diff --git a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto b/feature/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto rename to feature/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto diff --git a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/README.md b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/README.md similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/README.md rename to feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/README.md diff --git a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/bgp_2byte_4byte_asn_policy_test.go b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/bgp_2byte_4byte_asn_policy_test.go similarity index 98% rename from feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/bgp_2byte_4byte_asn_policy_test.go rename to feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/bgp_2byte_4byte_asn_policy_test.go index a90d728ebc8..dbdbbcf0ab8 100644 --- a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/bgp_2byte_4byte_asn_policy_test.go +++ b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/bgp_2byte_4byte_asn_policy_test.go @@ -157,7 +157,7 @@ func TestBgpSession(t *testing.T) { configureRegexPolicy(t, dut) d := &oc.Root{} - rpl := configureBGPPolicy(t, d, tc.nbr.isV4) + rpl := configureBGPPolicy(t, d, tc.nbr.isV4, dut) gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rpl) t.Log("Configure BGP on DUT") @@ -259,7 +259,7 @@ func configureRegexPolicy(t *testing.T, dut *ondatra.DUTDevice) { // configureBGPPolicy configures a BGP routing policy to accept or reject routes based on prefix match conditions // Additonally, it also configures policy to match prefix based on community and regex for as path -func configureBGPPolicy(t *testing.T, d *oc.Root, isV4 bool) *oc.RoutingPolicy { +func configureBGPPolicy(t *testing.T, d *oc.Root, isV4 bool, dut *ondatra.DUTDevice) *oc.RoutingPolicy { t.Helper() rp := d.GetOrCreateRoutingPolicy() pset := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(rejectPrefix) @@ -299,7 +299,11 @@ func configureBGPPolicy(t *testing.T, d *oc.Root, isV4 bool) *oc.RoutingPolicy { t.Errorf("Error while creating new statement %v", err) } stmt50.GetOrCreateActions().PolicyResult = oc.RoutingPolicy_PolicyResultType_REJECT_ROUTE - stmt50.GetOrCreateConditions().GetOrCreateBgpConditions().CommunitySet = ygot.String(communitySet) + if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + stmt50.GetOrCreateConditions().GetOrCreateBgpConditions().SetCommunitySet(communitySet) + } else { + stmt50.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet().SetCommunitySet(communitySet) + } stmt60, err := pdefComm.AppendNewStatement(aclStatement4) if err != nil { diff --git a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto similarity index 87% rename from feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto rename to feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto index eaae52b496a..58e2412e7cb 100644 --- a/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto @@ -11,6 +11,7 @@ platform_exceptions: { } deviations: { ipv4_missing_enabled: true + bgp_conditions_match_community_set_unsupported: true } } platform_exceptions: { @@ -21,6 +22,7 @@ platform_exceptions: { explicit_port_speed: true explicit_interface_in_default_vrf: true interface_enabled: true + bgp_conditions_match_community_set_unsupported: true } } platform_exceptions: { diff --git a/feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/README.md b/feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md similarity index 91% rename from feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/README.md rename to feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md index 68fe918d23c..10037d7171c 100644 --- a/feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/README.md +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md @@ -10,6 +10,7 @@ BGP AFI SAFI OC DEFAULTS TEST defines as the defaults i.e, * For BGP, there are no defaults for AFI-SAFI at the neighbor and peer-group levels. However at the global level the default is "false" +* For BGP neighbor level extended-next-hop encoding to be configured and validated too * This test currently only verifies the defaults for ipv4-unicast and ipv6-unicast families. However, this test can be extended further to cover for other AFI-SAFIs as well in future. * The test will check for default implementations under the neighbor and peer-group hierarchies and @@ -32,6 +33,8 @@ BGP AFI SAFI OC DEFAULTS TEST * Ensure that there are no AFI-SAFI configurations at the global and peer-group levels. * On the ATE side ensure that IPv4-unicast and IPv6-unicast AFI-SAFI are enabled==true for IPv4 and IPv6 neighbors. + * Ensure that there is extended-next-hop encoding feature is configured via OC path and the + default value of this should be set to false * Verification: * For IPv4 neighbor, ensure that the IPv4 neighborship is up and IPv6-unicast capability is @@ -95,6 +98,7 @@ paths: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/peer-as: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/config/enabled: /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/config/enabled: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/ipv4-unicast/config/extended-next-hop-encoding: ## Telemetry Parameter coverage @@ -105,6 +109,7 @@ paths: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/peer-type: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/peer-as: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/local-as: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/ipv4-unicast/state/extended-next-hop-encoding: rpcs: gnmi: @@ -114,4 +119,4 @@ rpcs: ``` ## Minimum DUT Required -vRX - Virtual Router Device \ No newline at end of file +vRX - Virtual Router Device diff --git a/feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go b/feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go similarity index 76% rename from feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go rename to feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go index 568d9060182..0898f0285e2 100644 --- a/feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go @@ -134,6 +134,8 @@ func bgpCreateNbr(t *testing.T, localAs, peerAs uint32, dut *ondatra.DUTDevice, global := bgp.GetOrCreateGlobal() global.RouterId = ygot.String(dutPort2.IPv4) global.As = ygot.Uint32(localAs) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) // Note: we have to define the peer group even if we aren't setting any policy because it's // invalid OC for the neighbor to be part of a peer group that doesn't exist. @@ -153,43 +155,59 @@ func bgpCreateNbr(t *testing.T, localAs, peerAs uint32, dut *ondatra.DUTDevice, switch afiSafiLevel { case globalLevel: - global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) - global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) - if !isV4Only { - extNh := global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateIpv4Unicast() - extNh.ExtendedNextHopEncoding = ygot.Bool(true) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + if isV4Only { + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + } else { + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) } if deviations.BGPGlobalExtendedNextHopEncodingUnsupported(dut) { global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Ipv4Unicast = nil } case nbrLevel: - if nbr.isV4 == true { - af4 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - af4.Enabled = ygot.Bool(true) + if isV4Only { + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + extNh := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateIpv4Unicast() + if !deviations.BgpExtendedNextHopEncodingLeafUnsupported(dut) { + extNh.ExtendedNextHopEncoding = ygot.Bool(true) + } } else { - af6 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - af6.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + } + if deviations.BGPGlobalExtendedNextHopEncodingUnsupported(dut) { + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Ipv4Unicast = nil } case peerGrpLevel: - pg1af4 := pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - pg1af4.Enabled = ygot.Bool(true) - pg1af6 := pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - pg1af6.Enabled = ygot.Bool(true) - - pg2af4 := pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - pg2af4.Enabled = ygot.Bool(true) - ext2Nh := pg2af4.GetOrCreateIpv4Unicast() - ext2Nh.ExtendedNextHopEncoding = ygot.Bool(true) - pg2af6 := pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - pg2af6.Enabled = ygot.Bool(true) + if isV4Only { + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + } else { + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + } case afiSafiSetToFalse: t.Log("AFI-SAFI is set to false") - if nbr.isV4 { - af4 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - af4.Enabled = ygot.Bool(false) + if isV4Only { + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) } else { - af6 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - af6.Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) } } } @@ -242,8 +260,11 @@ func verifyBgpSession(t *testing.T, dut *ondatra.DUTDevice, nbrsList []*bgpNeigh for _, nbr := range nbrsList { nbrPath := bgpPath.Neighbor(nbr.neighborip) state := gnmi.Get(t, dut, nbrPath.SessionState().State()) + t.Logf("BGP adjacency for %s: %v", nbr.neighborip, state) if state == oc.Bgp_Neighbor_SessionState_ESTABLISHED { t.Errorf("BGP peer %s status got %d, want other than ESTABLISHED", nbr.neighborip, state) + } else { + t.Logf("BGP peer %s status got %d, want other than ESTABLISHED", nbr.neighborip, state) } } } @@ -311,7 +332,7 @@ func configureOTG(t *testing.T, otg *otg.OTG, otgPeerList []string) gosnappi.Con } // verifyBGPCapabilities is used to Verify BGP capabilities like route refresh as32 and mpbgp. -func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel string, nbrs []*bgpNeighbor) { +func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel string, nbrs []*bgpNeighbor, isV4Only bool) { t.Helper() t.Log("Verifying BGP AFI-SAFI capabilities.") @@ -325,11 +346,32 @@ func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel st oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST: false, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST: false, } - - for _, cap := range gnmi.GetAll(t, dut, nbrPath.State()) { - capabilities[cap.GetAfiSafiName()] = cap.GetActive() + if deviations.BgpAfiSafiWildcardNotSupported(dut) { + t.Logf("AFI-SAFI wildcard/getall not supported") + afiSafiType := []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST} + afiSafiList := []*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi{} + for _, afiSafi := range afiSafiType { + if nbr.isV4 && afiSafi == oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST { + continue + } + if !nbr.isV4 && afiSafi == oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST { + continue + } + t.Logf("AFI-SAFI state: %v", gnmi.Get(t, dut, statePath.Neighbor(nbr.neighborip).AfiSafi(afiSafi).State())) + afiSafiList = append(afiSafiList, gnmi.Get(t, dut, statePath.Neighbor(nbr.neighborip).AfiSafi(afiSafi).State())) + t.Logf("AFI-SAFI list: %v", afiSafiList) + } + for _, cap := range afiSafiList { + capabilities[cap.GetAfiSafiName()] = cap.GetActive() + } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) + } else { + gnmi.GetAll(t, dut, nbrPath.State()) + for _, cap := range gnmi.GetAll(t, dut, nbrPath.State()) { + capabilities[cap.GetAfiSafiName()] = cap.GetActive() + } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) } - switch afiSafiLevel { case nbrLevel: if nbr.isV4 && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] { @@ -340,20 +382,25 @@ func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel st } t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) case peerGrpLevel: - if capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true && - capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + if isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + t.Logf("Both V4 and V6 AFI-SAFI are inherited from peer-group level for peer: %v, %v", nbr.neighborip, capabilities) + } else if !isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true { t.Logf("Both V4 and V6 AFI-SAFI are inherited from peer-group level for peer: %v, %v", nbr.neighborip, capabilities) } else { t.Errorf("Both V4 and V6 AFI-SAFI are not inherited from peer-group level for peer: %v, %v", nbr.neighborip, capabilities) } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) case globalLevel: - if capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true && - capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + if isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + t.Logf("Both V4 and V6 AFI-SAFI are inherited from global level for peer: %v, %v", nbr.neighborip, capabilities) + } else if !isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true { t.Logf("Both V4 and V6 AFI-SAFI are inherited from global level for peer: %v, %v", nbr.neighborip, capabilities) } else { t.Errorf("Both V4 and V6 AFI-SAFI are not inherited from global level for peer: %v, %v", nbr.neighborip, capabilities) } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) case afiSafiSetToFalse: + t.Logf("afiSafiSetToFalse capabilities: %v, v4 -> %v, v6 ->%v", isV4Only, capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST], capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST]) if nbr.isV4 && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { t.Errorf("AFI-SAFI are Active after disabling: %v, %v", capabilities, nbr.neighborip) } @@ -402,6 +449,11 @@ func TestAfiSafiOcDefaults(t *testing.T) { t.Run("Configure DEFAULT network instance", func(t *testing.T) { dutConfNIPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)) + name := deviations.DefaultNetworkInstance(dut) + c := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)) + gnmi.Update(t, dut, c.Config(), &oc.NetworkInstance{ + Name: ygot.String(name), + }) gnmi.Replace(t, dut, dutConfNIPath.Type().Config(), oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_DEFAULT_INSTANCE) }) @@ -423,7 +475,7 @@ func TestAfiSafiOcDefaults(t *testing.T) { desc: "Validate AFI-SAFI OC defaults at peer group level for BGPv4 peers", afiSafiLevel: peerGrpLevel, nbrs: []*bgpNeighbor{nbr1, nbr3}, - isV4Only: false, + isV4Only: true, otgPeerList: []string{otgPort1V4Peer, otgPort2V4Peer}, }, { desc: "Validate AFI-SAFI OC defaults at global level for V4 peers", @@ -473,7 +525,7 @@ func TestAfiSafiOcDefaults(t *testing.T) { t.Run("Verify BGP telemetry", func(t *testing.T) { verifyBgpTelemetry(t, dut, tc.nbrs) verifyOtgBgpTelemetry(t, otg, otgConfig, tc.otgPeerList, "ESTABLISHED") - verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs) + verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs, tc.isV4Only) }) }) } @@ -533,10 +585,14 @@ func TestAfiSafiSetToFalse(t *testing.T) { t.Run("Configure OTG", func(t *testing.T) { configureOTG(t, otg, tc.otgPeerList) }) + t.Logf("Verify BGP session on DUT") + time.Sleep(60 * time.Second) - t.Run("Verify BGP telemetry", func(t *testing.T) { + t.Run("Verify BGP session", func(t *testing.T) { verifyBgpSession(t, dut, tc.nbrs) - verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs) + }) + t.Run("Verify BGP capabilities", func(t *testing.T) { + verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs, tc.isV4Only) }) }) } diff --git a/feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto b/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto similarity index 90% rename from feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto rename to feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto index c2e44e3e549..070b871264d 100644 --- a/feature/experimental/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto @@ -11,6 +11,8 @@ platform_exceptions: { } deviations: { ipv4_missing_enabled: true + bgp_extended_next_hop_encoding_leaf_unsupported: true + bgp_afi_safi_wildcard_not_supported: true } } platform_exceptions: { diff --git a/feature/experimental/bgp/otg_tests/bgp_always_compare_med/README.md b/feature/bgp/otg_tests/bgp_always_compare_med/README.md similarity index 57% rename from feature/experimental/bgp/otg_tests/bgp_always_compare_med/README.md rename to feature/bgp/otg_tests/bgp_always_compare_med/README.md index 91fdcdad95e..d239bc302e9 100644 --- a/feature/experimental/bgp/otg_tests/bgp_always_compare_med/README.md +++ b/feature/bgp/otg_tests/bgp_always_compare_med/README.md @@ -18,20 +18,22 @@ BGP always compare MED * Validate the change of traffic flow because of the change (OTG Port2). * Validate session state and capabilities received on DUT using telemetry. -## Config Parameter coverage - -* /route-selection-options/config/always-compare-med -* /global/afi-safis/afi-safi/route-selection-options/config/always-compare-med -* /global/route-selection-options/config/always-compare-med - -## Telemetry Parameter coverage - -* /global/afi-safis/afi-safi/route-selection-options/state/always-compare-med -* /global/route-selection-options/state/always-compare-med - -## Protocol/RPC Parameter coverage - -N/A +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/global/route-selection-options/config/always-compare-med: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/route-selection-options/config/always-compare-med: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/global/route-selection-options/state/always-compare-med: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/route-selection-options/state/always-compare-med: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/bgp/otg_tests/bgp_always_compare_med/bgp_always_compare_med_test.go b/feature/bgp/otg_tests/bgp_always_compare_med/bgp_always_compare_med_test.go similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_always_compare_med/bgp_always_compare_med_test.go rename to feature/bgp/otg_tests/bgp_always_compare_med/bgp_always_compare_med_test.go diff --git a/feature/experimental/bgp/otg_tests/bgp_always_compare_med/metadata.textproto b/feature/bgp/otg_tests/bgp_always_compare_med/metadata.textproto similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_always_compare_med/metadata.textproto rename to feature/bgp/otg_tests/bgp_always_compare_med/metadata.textproto diff --git a/feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md similarity index 90% rename from feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md rename to feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md index b74ba3fad48..b5a15e90e4e 100644 --- a/feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md +++ b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md @@ -6,21 +6,27 @@ BGP Override AS-path split-horizon ## Topology - ATE Port1 (AS 65502) --- DUT Port1 (AS 65501) DUT Port2 ---eBGP --- ATE Port2 (AS 65503) +ATE Port1 (AS 65502) --- eBGP --------- DUT Port1 (DUT Local AS 65501) +ATE Port2 (AS 65503) --- eBGP --------- DUT Port2 (DUT Local AS 64513) ## Procedure * Establish BGP Session: Configure and establish an eBGP session between the DUT (Port1) and the ATE (Port1). +* +### RT-1.54.1 Test no allow-own-in * Baseline Test (No "allow-own-in"): * Advertise a prefix from the ATE (e.g., 192.168.1.0/24) with an AS-path that includes AS 65501 (DUT's AS) in the middle (e.g., AS-path: 65502 65500 65501 65499). * Verify that the ATE Port2 doesn't receive the route. due to the presence of its own AS in the path. * Validate session state and capabilities received on DUT using telemetry. + +### RT-1.54.2 Test "allow-own-as 1" * Test "allow-own-as 1": * Enable "allow-own-as 1" on the DUT. * Re-advertise the prefix from the ATE with the same AS-path. * Verify that the DUT accepts the route. * Verify that the ATE Port2 receives the route. * Validate session state and capabilities received on DUT using telemetry. +### RT-1.54.3 Test "allow-own-as 3" * Test "allow-own-as 3": * Change the DUT's configuration to "allow-own-as 3". * Test with the following AS-path occurrences: @@ -29,6 +35,7 @@ BGP Override AS-path split-horizon * 4 Occurrences: 65502 65501 65501 65501 65501 65499 (Should be rejected) * Verify that the ATE Port2 receives the route with 1 and 3 occurrences of AS 65501 but rejects it with 4 occurrences. * Validate session state and capabilities received on DUT using telemetry. +### RT-1.54.4 Test "allow-own-as 4" * Test "allow-own-as 4: * Change the DUT's configuration to "allow-own-as 4". * Test with the following AS-path occurrences: diff --git a/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go new file mode 100644 index 00000000000..030f0d4fa88 --- /dev/null +++ b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go @@ -0,0 +1,505 @@ +// Copyright 2024 Google LLC +// +// 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. + +package bgp_override_as_path_split_horizon_test + +import ( + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + otgtelemetry "github.com/openconfig/ondatra/gnmi/otg" + otg "github.com/openconfig/ondatra/otg" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +const ( + advertisedRoutesv4CIDR = "203.0.113.1/32" + advertisedRoutesv4Net = "203.0.113.1" + advertisedRoutesv4Prefix = 32 + peerGrpName1 = "BGP-PEER-GROUP1" + peerGrpName2 = "BGP-PEER-GROUP2" + dutGlobalAS = 64512 + dutLocalAS1 = 65501 + dutLocalAS2 = 64513 + ateAS1 = 65502 + ateAS2 = 65503 + plenIPv4 = 30 + plenIPv6 = 126 + policyName = "ALLOW" +) + +var ( + dutPort1 = attrs.Attributes{ + Desc: "DUT to ATE Port1", + IPv4: "192.0.2.1", + IPv6: "2001:db8::192:0:2:1", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + atePort1 = attrs.Attributes{ + Name: "atePort1", + IPv4: "192.0.2.2", + IPv6: "2001:db8::192:0:2:2", + MAC: "02:00:01:01:01:01", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + dutPort2 = attrs.Attributes{ + Desc: "DUT to ATE Port2", + IPv4: "192.0.2.5", + IPv6: "2001:db8::192:0:2:5", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + atePort2 = attrs.Attributes{ + Name: "atePort2", + IPv4: "192.0.2.6", + IPv6: "2001:db8::192:0:2:6", + MAC: "02:00:02:01:01:01", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + + nbr1 = &cfgplugins.BgpNeighbor{LocalAS: dutLocalAS1, PeerAS: ateAS1, Neighborip: atePort1.IPv4, IsV4: true, PeerGrp: peerGrpName1} + nbr2 = &cfgplugins.BgpNeighbor{LocalAS: dutLocalAS2, PeerAS: ateAS2, Neighborip: atePort2.IPv4, IsV4: true, PeerGrp: peerGrpName2} + + otgPort1V4Peer = "atePort1.BGP4.peer" + otgPort2V4Peer = "atePort2.BGP4.peer" +) + +// configureDUT configures all the interfaces on the DUT. +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + dc := gnmi.OC() + i1 := dutPort1.NewOCInterface(dut.Port(t, "port1").Name(), dut) + gnmi.Replace(t, dut, dc.Interface(i1.GetName()).Config(), i1) + + i2 := dutPort2.NewOCInterface(dut.Port(t, "port2").Name(), dut) + gnmi.Replace(t, dut, dc.Interface(i2.GetName()).Config(), i2) +} + +// bgpCreateNbr creates a BGP object with neighbors pointing to atePort1 and atePort2 +func bgpCreateNbr(t *testing.T, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + t.Helper() + dutOcRoot := &oc.Root{} + ni1 := dutOcRoot.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + global := bgp.GetOrCreateGlobal() + global.RouterId = ygot.String(dutPort2.IPv4) + global.As = ygot.Uint32(dutGlobalAS) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + + // Note: we have to define the peer group even if we aren't setting any policy because it's + // invalid OC for the neighbor to be part of a peer group that doesn't exist. + + for _, nbr := range []*cfgplugins.BgpNeighbor{nbr1, nbr2} { + + pg := bgp.GetOrCreatePeerGroup(nbr.PeerGrp) + pg.PeerAs = ygot.Uint32(nbr.PeerAS) + pg.LocalAs = ygot.Uint32(nbr.LocalAS) + pg.PeerGroupName = ygot.String(nbr.PeerGrp) + pg.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + + nv4 := bgp.GetOrCreateNeighbor(nbr.Neighborip) + nv4.PeerGroup = ygot.String(nbr.PeerGrp) + nv4.PeerAs = ygot.Uint32(nbr.PeerAS) + nv4.Enabled = ygot.Bool(true) + af4 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + af4.Enabled = ygot.Bool(true) + + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pg.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{policyName} + rpl.ExportPolicy = []string{policyName} + } else { + pgaf := pg.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + pgaf.Enabled = ygot.Bool(true) + rpl := pgaf.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{policyName} + rpl.ExportPolicy = []string{policyName} + } + } + return niProto +} + +// configureOTG configures the interfaces and BGP protocols on an ATE. +func configureOTG(t *testing.T, otg *otg.OTG) (gosnappi.BgpV4Peer, gosnappi.DeviceIpv4, gosnappi.Config) { + t.Helper() + config := gosnappi.NewConfig() + port1 := config.Ports().Add().SetName("port1") + port2 := config.Ports().Add().SetName("port2") + + iDut1Dev := config.Devices().Add().SetName(atePort1.Name) + iDut1Eth := iDut1Dev.Ethernets().Add().SetName(atePort1.Name + ".Eth").SetMac(atePort1.MAC) + iDut1Eth.Connection().SetPortName(port1.Name()) + iDut1Ipv4 := iDut1Eth.Ipv4Addresses().Add().SetName(atePort1.Name + ".IPv4") + iDut1Ipv4.SetAddress(atePort1.IPv4).SetGateway(dutPort1.IPv4).SetPrefix(uint32(atePort1.IPv4Len)) + iDut1Ipv6 := iDut1Eth.Ipv6Addresses().Add().SetName(atePort1.Name + ".IPv6") + iDut1Ipv6.SetAddress(atePort1.IPv6).SetGateway(dutPort1.IPv6).SetPrefix(uint32(atePort1.IPv6Len)) + + iDut2Dev := config.Devices().Add().SetName(atePort2.Name) + iDut2Eth := iDut2Dev.Ethernets().Add().SetName(atePort2.Name + ".Eth").SetMac(atePort2.MAC) + iDut2Eth.Connection().SetPortName(port2.Name()) + iDut2Ipv4 := iDut2Eth.Ipv4Addresses().Add().SetName(atePort2.Name + ".IPv4") + iDut2Ipv4.SetAddress(atePort2.IPv4).SetGateway(dutPort2.IPv4).SetPrefix(uint32(atePort2.IPv4Len)) + iDut2Ipv6 := iDut2Eth.Ipv6Addresses().Add().SetName(atePort2.Name + ".IPv6") + iDut2Ipv6.SetAddress(atePort2.IPv6).SetGateway(dutPort2.IPv6).SetPrefix(uint32(atePort2.IPv6Len)) + + iDut1Bgp := iDut1Dev.Bgp().SetRouterId(iDut1Ipv4.Address()) + iDut2Bgp := iDut2Dev.Bgp().SetRouterId(iDut2Ipv4.Address()) + + iDut1Bgp4Peer := iDut1Bgp.Ipv4Interfaces().Add().SetIpv4Name(iDut1Ipv4.Name()).Peers().Add().SetName(otgPort1V4Peer) + iDut1Bgp4Peer.SetPeerAddress(iDut1Ipv4.Gateway()).SetAsNumber(ateAS1).SetAsType(gosnappi.BgpV4PeerAsType.EBGP) + iDut1Bgp4Peer.Capability().SetIpv4UnicastAddPath(true).SetIpv6UnicastAddPath(true) + iDut1Bgp4Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(true) + + iDut2Bgp4Peer := iDut2Bgp.Ipv4Interfaces().Add().SetIpv4Name(iDut2Ipv4.Name()).Peers().Add().SetName(otgPort2V4Peer) + iDut2Bgp4Peer.SetPeerAddress(iDut2Ipv4.Gateway()).SetAsNumber(ateAS2).SetAsType(gosnappi.BgpV4PeerAsType.EBGP) + iDut2Bgp4Peer.Capability().SetIpv4UnicastAddPath(true).SetIpv6UnicastAddPath(true) + iDut2Bgp4Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(true) + + t.Logf("Pushing config to OTG and starting protocols...") + otg.PushConfig(t, config) + time.Sleep(30 * time.Second) + otg.StartProtocols(t) + time.Sleep(30 * time.Second) + + return iDut1Bgp4Peer, iDut1Ipv4, config +} + +// advBGPRouteFromOTG is to advertise prefix with specific AS sequence set. +func advBGPRouteFromOTG(t *testing.T, args *otgTestArgs, asSeg []uint32) { + + args.otgBgpPeer.V4Routes().Clear() + + bgpNeti1Bgp4PeerRoutes := args.otgBgpPeer.V4Routes().Add().SetName(atePort1.Name + ".BGP4.Route") + bgpNeti1Bgp4PeerRoutes.SetNextHopIpv4Address(args.otgIPv4Device.Address()). + SetNextHopAddressType(gosnappi.BgpV4RouteRangeNextHopAddressType.IPV4). + SetNextHopMode(gosnappi.BgpV4RouteRangeNextHopMode.MANUAL) + bgpNeti1Bgp4PeerRoutes.Addresses().Add(). + SetAddress(advertisedRoutesv4Net). + SetPrefix(uint32(advertisedRoutesv4Prefix)). + SetCount(1) + + bgpNeti1AsPath := bgpNeti1Bgp4PeerRoutes.AsPath().SetAsSetMode(gosnappi.BgpAsPathAsSetMode.INCLUDE_AS_SET) + bgpNeti1AsPath.Segments().Add().SetAsNumbers(asSeg).SetType(gosnappi.BgpAsPathSegmentType.AS_SEQ) + + t.Logf("Pushing config to OTG and starting protocols...") + args.otg.PushConfig(t, args.otgConfig) + time.Sleep(30 * time.Second) + args.otg.StartProtocols(t) + time.Sleep(30 * time.Second) +} + +// verifyPrefixesTelemetry confirms that the dut shows the correct numbers of installed, +// sent and received IPv4 prefixes. +func verifyPrefixesTelemetry(t *testing.T, dut *ondatra.DUTDevice, nbr string, wantInstalled, wantSent uint32) { + t.Helper() + time.Sleep(15 * time.Second) + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + prefixesv4 := statePath.Neighbor(nbr).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Prefixes() + if gotInstalled := gnmi.Get(t, dut, prefixesv4.Installed().State()); gotInstalled != wantInstalled { + t.Errorf("Installed prefixes mismatch: got %v, want %v", gotInstalled, wantInstalled) + } + if gotSent := gnmi.Get(t, dut, prefixesv4.Sent().State()); gotSent != wantSent { + t.Errorf("Sent prefixes mismatch: got %v, want %v", gotSent, wantSent) + } +} + +// configreRoutePolicy adds route-policy config. +func configureRoutePolicy(t *testing.T, dut *ondatra.DUTDevice, name string, pr oc.E_RoutingPolicy_PolicyResultType) { + d := &oc.Root{} + rp := d.GetOrCreateRoutingPolicy() + pdef := rp.GetOrCreatePolicyDefinition(name) + stmt, err := pdef.AppendNewStatement(name) + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", name, err) + } + stmt.GetOrCreateActions().PolicyResult = pr + stmt.GetOrCreateConditions().InstallProtocolEq = oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + +} + +// verifyOTGPrefixTelemetry is to Validate prefix received on OTG por2. +func verifyOTGPrefixTelemetry(t *testing.T, otg *otg.OTG, wantPrefix bool) { + t.Helper() + _, ok := gnmi.WatchAll(t, otg, gnmi.OTG().BgpPeer(atePort2.Name+".BGP4.peer").UnicastIpv4PrefixAny().State(), + time.Minute, func(v *ygnmi.Value[*otgtelemetry.BgpPeer_UnicastIpv4Prefix]) bool { + return v.IsPresent() + }).Await(t) + + if ok { + bgpPrefixes := gnmi.GetAll(t, otg, gnmi.OTG().BgpPeer(atePort2.Name+".BGP4.peer").UnicastIpv4PrefixAny().State()) + for _, prefix := range bgpPrefixes { + if prefix.GetAddress() == advertisedRoutesv4Net { + if wantPrefix { + gotASPath := prefix.AsPath[len(prefix.AsPath)-1].GetAsNumbers() + t.Logf("Received prefix %v on otg as expected with AS-PATH %v", prefix.GetAddress(), gotASPath) + } else { + t.Errorf("Prefix %v is not received on otg", prefix.GetAddress()) + } + } + } + } +} + +// ### RT-1.54.1 Test no allow-own-in +func testSplitHorizonNoAllowOwnIn(t *testing.T, args *otgTestArgs) { + t.Log("Baseline Test No allow-own-in") + + t.Log("Advertise a prefix from the ATE with an AS-path that includes AS dutLocalAS1 (DUT's AS) in the middle (e.g., AS-path: 65500 dutLocalAS1 65499") + advBGPRouteFromOTG(t, args, []uint32{65500, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + + t.Log("Verify that the ATE Port2 doesn't receive the route. due to the presence of its own AS in the path.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 0, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 0) + verifyOTGPrefixTelemetry(t, args.otg, false) +} + +// ### RT-1.54.2 Test "allow-own-as 1" +func testSplitHorizonAllowOwnAs1(t *testing.T, args *otgTestArgs) { + t.Log("Test allow-own-as 1, Enable allow-own-as 1 on the DUT.") + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(args.dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + if deviations.BgpAllowownasDiffDefaultValue(args.dut) { + gnmi.Replace(t, args.dut, dutConfPath.Bgp().PeerGroup(peerGrpName1).AsPathOptions().AllowOwnAs().Config(), 2) + } else { + gnmi.Replace(t, args.dut, dutConfPath.Bgp().PeerGroup(peerGrpName1).AsPathOptions().AllowOwnAs().Config(), 1) + } + + t.Log("Re-advertise the prefix from the ATE with the same AS-path.") + advBGPRouteFromOTG(t, args, []uint32{65500, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, true) + +} + +// ### RT-1.54.3 Test "allow-own-as 3" +func testSplitHorizonAllowOwnAs3(t *testing.T, args *otgTestArgs) { + t.Log("Test allow-own-as 3, Enable allow-own-as 3 on the DUT.") + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(args.dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + if deviations.BgpAllowownasDiffDefaultValue(args.dut) { + gnmi.Replace(t, args.dut, dutConfPath.Bgp().PeerGroup(peerGrpName1).AsPathOptions().AllowOwnAs().Config(), 4) + } else { + gnmi.Replace(t, args.dut, dutConfPath.Bgp().PeerGroup(peerGrpName1).AsPathOptions().AllowOwnAs().Config(), 3) + } + + t.Run("Re-advertise the prefix from the ATE with 1 Occurrence: 65500 dutLocalAS1 65499", func(t *testing.T) { + advBGPRouteFromOTG(t, args, []uint32{65500, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, true) + }) + + t.Run("Re-advertise the prefix from the ATE with 3 Occurrences: dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499", func(t *testing.T) { + advBGPRouteFromOTG(t, args, []uint32{dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, true) + }) + + t.Run("Re-advertise the prefix from the ATE with 4 Occurrences: dutLocalAS1, dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499 (Should be rejected)", func(t *testing.T) { + advBGPRouteFromOTG(t, args, []uint32{dutLocalAS1, dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 0, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 0) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, false) + }) +} + +// ### RT-1.54.4 Test "allow-own-as 4" +func testSplitHorizonAllowOwnAs4(t *testing.T, args *otgTestArgs) { + t.Log("Test allow-own-as 4, Enable allow-own-as 4 on the DUT.") + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(args.dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + if deviations.BgpAllowownasDiffDefaultValue(args.dut) { + gnmi.Replace(t, args.dut, dutConfPath.Bgp().PeerGroup(peerGrpName1).AsPathOptions().AllowOwnAs().Config(), 5) + } else { + gnmi.Replace(t, args.dut, dutConfPath.Bgp().PeerGroup(peerGrpName1).AsPathOptions().AllowOwnAs().Config(), 4) + } + + t.Run("Re-advertise the prefix from the ATE with 1 Occurrence: 65500, dutLocalAS1, 65499", func(t *testing.T) { + advBGPRouteFromOTG(t, args, []uint32{65500, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, true) + }) + + t.Run("Re-advertise the prefix from the ATE with 3 Occurrences: dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499", func(t *testing.T) { + advBGPRouteFromOTG(t, args, []uint32{dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, true) + }) + + t.Run("Re-advertise the prefix from the ATE with 4 Occurrences: dutLocalAS1, dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499 (Should be accepted)", func(t *testing.T) { + advBGPRouteFromOTG(t, args, []uint32{dutLocalAS1, dutLocalAS1, dutLocalAS1, dutLocalAS1, 65499}) + + t.Log("Validate session state and capabilities received on DUT using telemetry.") + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + + t.Log("Verify that the DUT accepts the route.") + verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) + verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) + + t.Log("Verify that the ATE Port2 receives the route.") + verifyOTGPrefixTelemetry(t, args.otg, true) + }) +} + +type otgTestArgs struct { + dut *ondatra.DUTDevice + ate *ondatra.ATEDevice + otgBgpPeer gosnappi.BgpV4Peer + otgIPv4Device gosnappi.DeviceIpv4 + otgConfig gosnappi.Config + otg *otg.OTG +} + +// TestBGPOverrideASPathSplitHorizon validates BGP Override AS-path split-horizon. +func TestBGPOverrideASPathSplitHorizon(t *testing.T) { + t.Logf("Start DUT config load.") + dut := ondatra.DUT(t, "dut") + ate := ondatra.ATE(t, "ate") + + t.Run("Configure DUT interfaces", func(t *testing.T) { + configureDUT(t, dut) + }) + + t.Run("Configure DEFAULT network instance", func(t *testing.T) { + fptest.ConfigureDefaultNetworkInstance(t, dut) + }) + + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + + t.Run("Configure BGP Neighbors", func(t *testing.T) { + configureRoutePolicy(t, dut, policyName, oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + cfgplugins.BGPClearConfig(t, dut) + dutConf := bgpCreateNbr(t, dut) + gnmi.Replace(t, dut, dutConfPath.Config(), dutConf) + fptest.LogQuery(t, "DUT BGP Config", dutConfPath.Config(), gnmi.Get(t, dut, dutConfPath.Config())) + }) + + otg := ate.OTG() + var otgConfig gosnappi.Config + var otgBgpPeer gosnappi.BgpV4Peer + var otgIPv4Device gosnappi.DeviceIpv4 + otgBgpPeer, otgIPv4Device, otgConfig = configureOTG(t, otg) + + args := &otgTestArgs{ + dut: dut, + ate: ate, + otgBgpPeer: otgBgpPeer, + otgIPv4Device: otgIPv4Device, + otgConfig: otgConfig, + otg: otg, + } + + t.Run("Verify port status on DUT", func(t *testing.T) { + cfgplugins.VerifyPortsUp(t, args.dut.Device) + }) + + t.Run("Verify BGP telemetry", func(t *testing.T) { + cfgplugins.VerifyDUTBGPEstablished(t, args.dut) + cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) + }) + + cases := []struct { + desc string + funcName func() + skipMsg string + }{{ + desc: " Baseline Test No allow-own-in", + funcName: func() { testSplitHorizonNoAllowOwnIn(t, args) }, + }, { + desc: " Test allow-own-as 1", + funcName: func() { testSplitHorizonAllowOwnAs1(t, args) }, + }, { + desc: " Test allow-own-as 3", + funcName: func() { testSplitHorizonAllowOwnAs3(t, args) }, + }, { + desc: " Test allow-own-as 4", + funcName: func() { testSplitHorizonAllowOwnAs4(t, args) }, + }} + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + tc.funcName() + }) + } +} diff --git a/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto new file mode 100644 index 00000000000..b4b418d51e2 --- /dev/null +++ b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto @@ -0,0 +1,37 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "97f0e45a-2970-4227-9409-3003e7c7cdd7" +plan_id: "RT-1.54" +description: "BGP Override AS-path split-horizon" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_interface_in_default_vrf: true + interface_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + route_policy_under_afi_unsupported: true + omit_l2_mtu: true + interface_enabled: true + default_network_instance: "default" + bgp_set_med_requires_equal_ospf_set_metric: true + } +} +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + bgp_allowownas_diff_default_value: true + } +} +tags: TAGS_AGGREGATION diff --git a/feature/experimental/bgp/otg_tests/bgp_remove_private_as/README.md b/feature/bgp/otg_tests/bgp_remove_private_as/README.md similarity index 60% rename from feature/experimental/bgp/otg_tests/bgp_remove_private_as/README.md rename to feature/bgp/otg_tests/bgp_remove_private_as/README.md index 6a5ce3e8a52..7da3a2fc346 100644 --- a/feature/experimental/bgp/otg_tests/bgp_remove_private_as/README.md +++ b/feature/bgp/otg_tests/bgp_remove_private_as/README.md @@ -18,17 +18,20 @@ BGP remove private AS * PRIV_AS1 AS1 * AS1 PRIV_AS1 AS2 -## Config Parameter coverage - -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/remove-private-as - -## Telemetry Parameter coverage - -* /network-instances/network-instance/protocols/protocol/bgp/rib/attr-sets/attr-set/as4-path/as4-segment/state - -## Protocol/RPC Parameter coverage - -N/A +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/remove-private-as: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/rib/attr-sets/attr-set/as4-path/as4-segment/state/index: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/bgp/otg_tests/bgp_remove_private_as/bgp_remove_private_as_test.go b/feature/bgp/otg_tests/bgp_remove_private_as/bgp_remove_private_as_test.go similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_remove_private_as/bgp_remove_private_as_test.go rename to feature/bgp/otg_tests/bgp_remove_private_as/bgp_remove_private_as_test.go diff --git a/feature/experimental/bgp/otg_tests/bgp_remove_private_as/metadata.textproto b/feature/bgp/otg_tests/bgp_remove_private_as/metadata.textproto similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_remove_private_as/metadata.textproto rename to feature/bgp/otg_tests/bgp_remove_private_as/metadata.textproto diff --git a/feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/README.md b/feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/README.md similarity index 67% rename from feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/README.md rename to feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/README.md index 45457c0b801..8c21d568b0e 100644 --- a/feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/README.md +++ b/feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/README.md @@ -25,19 +25,22 @@ * Re-establish the IBGP sessions by tcp reset. * Validate that the min MSS value has been adjusted to be below 1500 bytes on the tcp session. -## Config Parameter coverage - -* /neighbors/neighbor/transport/config/tcp-mss -* /neighbors/neighbor/transport/config/mtu-discovery - -## Telemetry Parameter coverage - -* /neighbors/neighbor/transport/state/tcp-mss -* /neighbors/neighbor/transport/state/mtu-discovery - -## Protocol/RPC Parameter coverage - -N/A +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/transport/config/tcp-mss: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/transport/config/mtu-discovery: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/transport/state/tcp-mss: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/transport/state/mtu-discovery: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/bgp_tcp_mss_path_mtu_test.go b/feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/bgp_tcp_mss_path_mtu_test.go similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/bgp_tcp_mss_path_mtu_test.go rename to feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/bgp_tcp_mss_path_mtu_test.go diff --git a/feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/metadata.textproto b/feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/metadata.textproto similarity index 100% rename from feature/experimental/bgp/otg_tests/bgp_tcp_mss_path_mtu/metadata.textproto rename to feature/bgp/otg_tests/bgp_tcp_mss_path_mtu/metadata.textproto diff --git a/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/actions_MED_LocPref_prepend_flow_control_test.go b/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/actions_MED_LocPref_prepend_flow_control_test.go index d083febdadf..c4df5796bf2 100644 --- a/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/actions_MED_LocPref_prepend_flow_control_test.go +++ b/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/actions_MED_LocPref_prepend_flow_control_test.go @@ -15,6 +15,7 @@ package actions_med_localpref_prepend_flow_control_test import ( + "fmt" "strconv" "strings" "testing" @@ -25,6 +26,7 @@ import ( "github.com/openconfig/featureprofiles/internal/attrs" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/helpers" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" @@ -40,12 +42,12 @@ func TestMain(m *testing.M) { } const ( - advertisedRoutesv4Net1 = "192.168.10.0" - advertisedRoutesv6Net1 = "2024:db8:128:128::" - advertisedRoutesv4Net2 = "192.168.20.0" - advertisedRoutesv6Net2 = "2024:db8:64:64::" - advertisedRoutesv4PrefixLen = 24 - advertisedRoutesv6PrefixLen = 64 + advertisedRoutesv4Net1 = "192.168.10.1" + advertisedRoutesv6Net1 = "2024:db8:128:128::1" + advertisedRoutesv4Net2 = "192.168.20.1" + advertisedRoutesv6Net2 = "2024:db8:64:64::1" + advertisedRoutesv4PrefixLen = 32 + advertisedRoutesv6PrefixLen = 128 dutAS = 64500 ateAS = 64501 plenIPv4 = 30 @@ -209,6 +211,24 @@ func VerifyBgpState(t *testing.T, dut *ondatra.DUTDevice) { t.Log("BGP sessions Established") } +// juniperBgpPolicyMEDAdd is used to configure set metric add via native cli as an alternative for below xpath. +// routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-med +func juniperBgpPolicyMEDAdd(polName string, metric int) string { + return fmt.Sprintf(` + policy-options { + policy-statement %s { + term 1 { + then { + metric add %d; + } + } + term 2 { + then accept; + } + } + }`, polName, metric) +} + // configureASLocalPrefMEDPolicy configures MED, Local Pref, AS prepend etc func configureASLocalPrefMEDPolicy(t *testing.T, dut *ondatra.DUTDevice, policyType, policyValue, statement string, ASN uint32) { t.Helper() @@ -228,12 +248,25 @@ func configureASLocalPrefMEDPolicy(t *testing.T, dut *ondatra.DUTDevice, policyT actions.PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE case setMEDPolicy: if strings.Contains(policyValue, "+") { - actions.GetOrCreateBgpActions().SetMed = oc.UnionString(policyValue) + if deviations.BgpSetMedV7Unsupported(dut) { + t.Logf("Push the CLI config:%s", dut.Vendor()) + metric, _ := strconv.Atoi(policyValue) + switch dut.Vendor() { + case ondatra.JUNIPER: + config := juniperBgpPolicyMEDAdd(setMEDPolicy, metric) + helpers.GnmiCLIConfig(t, dut, config) + default: + t.Fatalf("BgpSetMedV7Unsupported deviation needs cli configuration for vendor %s which is not defined", dut.Vendor()) + } + } else { + actions.GetOrCreateBgpActions().SetMed = oc.UnionString(policyValue) + actions.PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + } } else { metric, _ := strconv.Atoi(policyValue) actions.GetOrCreateBgpActions().SetMed = oc.UnionUint32(uint32(metric)) + actions.PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE } - actions.PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE case setPrependPolicy: metric, _ := strconv.Atoi(policyValue) asPrepend := actions.GetOrCreateBgpActions().GetOrCreateSetAsPathPrepend() @@ -298,15 +331,13 @@ func deleteBGPImportExportPolicy(t *testing.T, dut *ondatra.DUTDevice, ipv4, ipv batchConfig := &gnmi.SetBatch{} nbrPolPathv4 := bgpPath.Neighbor(ipv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() nbrPolPathv6 := bgpPath.Neighbor(ipv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() - if deviations.DefaultRoutePolicyUnsupported(dut) { - // deleteBGPImportExportPolicy on port2 needed when default policy is not supported - nbrPolPathv4_2 := bgpPath.Neighbor(ipv4_2).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() - nbrPolPathv6_2 := bgpPath.Neighbor(ipv6_2).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() - gnmi.BatchDelete(batchConfig, nbrPolPathv4_2.ImportPolicy().Config()) - gnmi.BatchDelete(batchConfig, nbrPolPathv4_2.ExportPolicy().Config()) - gnmi.BatchDelete(batchConfig, nbrPolPathv6_2.ImportPolicy().Config()) - gnmi.BatchDelete(batchConfig, nbrPolPathv6_2.ExportPolicy().Config()) - } + nbrPolPathv4_2 := bgpPath.Neighbor(ipv4_2).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + nbrPolPathv6_2 := bgpPath.Neighbor(ipv6_2).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + gnmi.BatchDelete(batchConfig, nbrPolPathv4_2.ImportPolicy().Config()) + gnmi.BatchDelete(batchConfig, nbrPolPathv4_2.ExportPolicy().Config()) + gnmi.BatchDelete(batchConfig, nbrPolPathv6_2.ImportPolicy().Config()) + gnmi.BatchDelete(batchConfig, nbrPolPathv6_2.ExportPolicy().Config()) + gnmi.BatchDelete(batchConfig, nbrPolPathv4.ImportPolicy().Config()) gnmi.BatchDelete(batchConfig, nbrPolPathv4.ExportPolicy().Config()) gnmi.BatchDelete(batchConfig, nbrPolPathv6.ImportPolicy().Config()) @@ -445,6 +476,7 @@ func configureOTG(t *testing.T, otg *otg.OTG) gosnappi.Config { t.Logf("Pushing config to ATE and starting protocols...") otg.PushConfig(t, config) otg.StartProtocols(t) + return config } @@ -454,7 +486,7 @@ func validateOTGBgpPrefixV4AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on _, ok := gnmi.WatchAll(t, otg, gnmi.OTG().BgpPeer(peerName).UnicastIpv4PrefixAny().State(), - 30*time.Second, + 60*time.Second, func(v *ygnmi.Value[*otgtelemetry.BgpPeer_UnicastIpv4Prefix]) bool { _, present := v.Val() return present @@ -466,7 +498,7 @@ func validateOTGBgpPrefixV4AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on if bgpPrefix.Address != nil && bgpPrefix.GetAddress() == ipAddr && bgpPrefix.PrefixLength != nil && bgpPrefix.GetPrefixLength() == prefixLen { foundPrefix = true - t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix, ipAddr) + t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix.GetAddress(), ipAddr) switch pathAttr { case setMEDPolicy: if bgpPrefix.GetMultiExitDiscriminator() != metric { @@ -475,12 +507,14 @@ func validateOTGBgpPrefixV4AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on t.Logf("For Prefix %v, got MED %d want MED %d", bgpPrefix.GetAddress(), bgpPrefix.GetMultiExitDiscriminator(), metric) } case setLocalPrefPolicy: - validateImportRoutingPolicy(t, dut, ipAddr, metric) + if !deviations.BGPRibOcPathUnsupported(dut) { + validateImportRoutingPolicy(t, dut, ipAddr, metric) + } case setPrependPolicy: if len(bgpPrefix.AsPath[0].GetAsNumbers()) != int(metric) { t.Errorf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), int(metric)) } else { - t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath), int(metric)) + t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), int(metric)) } case setNxtPolicy: if bgpPrefix.GetMultiExitDiscriminator() != metric { @@ -491,7 +525,7 @@ func validateOTGBgpPrefixV4AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on if len(bgpPrefix.AsPath[0].GetAsNumbers()) != asnRepeatN+1 { t.Errorf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), asnRepeatN+1) } else { - t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath), asnRepeatN+1) + t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), asnRepeatN+1) } default: t.Errorf("Incorrect BGP Path Attribute. Expected MED, Local Pref or AS Path Prepend!!!!") @@ -511,7 +545,7 @@ func validateOTGBgpPrefixV6AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on _, ok := gnmi.WatchAll(t, otg, gnmi.OTG().BgpPeer(peerName).UnicastIpv6PrefixAny().State(), - 30*time.Second, + 60*time.Second, func(v *ygnmi.Value[*otgtelemetry.BgpPeer_UnicastIpv6Prefix]) bool { _, present := v.Val() return present @@ -523,7 +557,7 @@ func validateOTGBgpPrefixV6AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on if bgpPrefix.Address != nil && bgpPrefix.GetAddress() == ipAddr && bgpPrefix.PrefixLength != nil && bgpPrefix.GetPrefixLength() == prefixLen { foundPrefix = true - t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix, ipAddr) + t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix.GetAddress(), ipAddr) switch pathAttr { case setMEDPolicy: if bgpPrefix.GetMultiExitDiscriminator() != metric { @@ -532,12 +566,14 @@ func validateOTGBgpPrefixV6AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on t.Logf("For Prefix %v, got MED %d want MED %d", bgpPrefix.GetAddress(), bgpPrefix.GetMultiExitDiscriminator(), metric) } case setLocalPrefPolicy: - validateImportRoutingPolicyV6(t, dut, ipAddr, metric) + if !deviations.BGPRibOcPathUnsupported(dut) { + validateImportRoutingPolicyV6(t, dut, ipAddr, metric) + } case setPrependPolicy: if len(bgpPrefix.AsPath[0].GetAsNumbers()) != int(metric) { t.Errorf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), int(metric)) } else { - t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath), int(metric)) + t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), int(metric)) } case setNxtPolicy: if bgpPrefix.GetMultiExitDiscriminator() != metric { @@ -548,7 +584,7 @@ func validateOTGBgpPrefixV6AndASLocalPrefMED(t *testing.T, otg *otg.OTG, dut *on if len(bgpPrefix.AsPath[0].GetAsNumbers()) != asnRepeatN+1 { t.Errorf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), asnRepeatN+1) } else { - t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath), asnRepeatN+1) + t.Logf("For Prefix %v, got AS Path Prepend %d want AS Path Prepend %d", bgpPrefix.GetAddress(), len(bgpPrefix.AsPath[0].GetAsNumbers()), asnRepeatN+1) } default: t.Errorf("Incorrect Routing Policy. Expected MED, Local Pref or AS Path Prepend!!!!") @@ -735,6 +771,7 @@ func TestBGPPolicy(t *testing.T) { if tc.isDeletePolicy { deleteBGPImportExportPolicy(t, dut, tc.deleteNbrv4, tc.deleteNbrv6, atePort2.IPv4, atePort2.IPv6) } + // Configure Routing Policy on the DUT. configureASLocalPrefMEDPolicy(t, dut, tc.rpPolicy, tc.policyValue, tc.policyStatement, tc.asn) if !deviations.DefaultRoutePolicyUnsupported(dut) { diff --git a/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto b/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto index 24be17ffe8b..c11bd3995b2 100644 --- a/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto @@ -18,6 +18,15 @@ platform_exceptions: { skip_setting_statement_for_policy: true } } +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + bgp_rib_oc_path_unsupported: true + bgp_set_med_v7_unsupported: true + } +} platform_exceptions: { platform: { vendor: NOKIA diff --git a/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto b/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto index fc8bcf61ac6..27c44c4f08d 100644 --- a/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto @@ -19,7 +19,6 @@ platform_exceptions: { default_network_instance: "default" skip_set_rp_match_set_options: true skip_setting_disable_metric_propagation: true - bgp_conditions_match_community_set_unsupported: true } } diff --git a/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto b/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto index 722a02f9a02..c59c7f78251 100644 --- a/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto @@ -18,7 +18,6 @@ platform_exceptions: { default_network_instance: "default" skip_set_rp_match_set_options: true skip_setting_disable_metric_propagation: true - bgp_conditions_match_community_set_unsupported: true } } platform_exceptions: { diff --git a/feature/bgp/policybase/otg_tests/comm_match_action_test/metadata.textproto b/feature/bgp/policybase/otg_tests/comm_match_action_test/metadata.textproto index b6d656dc70e..e1a4c911ab4 100644 --- a/feature/bgp/policybase/otg_tests/comm_match_action_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/comm_match_action_test/metadata.textproto @@ -10,13 +10,10 @@ platform_exceptions: { vendor: NOKIA } deviations: { - explicit_port_speed: true explicit_interface_in_default_vrf: true interface_enabled: true - bgp_conditions_match_community_set_unsupported: true bgp_actions_set_community_method_unsupported: true skip_bgp_send_community_type: true - bgp_community_set_refs_unsupported: true } } platform_exceptions: { @@ -27,7 +24,6 @@ platform_exceptions: { omit_l2_mtu: true interface_enabled: true default_network_instance: "default" - bgp_conditions_match_community_set_unsupported: true } } tags: TAGS_AGGREGATION diff --git a/feature/bgp/policybase/otg_tests/community_test/README.md b/feature/bgp/policybase/otg_tests/community_test/README.md index a068367488f..f1911b3c359 100644 --- a/feature/bgp/policybase/otg_tests/community_test/README.md +++ b/feature/bgp/policybase/otg_tests/community_test/README.md @@ -54,6 +54,27 @@ BGP policy configuration for Community Sets * Verify traffic is received on ATE port 1 for accepted prefixes. * Verify traffic is not received on ATE port 1 for rejected prefixes. +* RT-7.2.3 - Update community set and validate + 1. Configure a community-set named `update_comm_set` with "100:1" as member. + + 2. Create a `policy-definition` named 'community-match' with the following `statements` + * statement[name='accept_update_comm_set']/ + * conditions/bgp-conditions/match-community-set/config/community-set = 'update_comm_set' + * conditions/bgp-conditions/match-community-set/config/match-set-options = INVERT + * actions/config/policy-result = ACCEPT_ROUTE + + 3. Send traffic from ATE port-2 to all prefix-sets. + * Verify traffic is received on ATE port 1 for accepted prefixes for all community set except "100:1". + * Verify traffic is not received on ATE port 1 for rejected prefixes for community set "100:1". + + 4. Update the community-set named `update_comm_set` with "200:2" as member. + + 5. Send traffic from ATE port-2 to all prefix-sets. + * Verify traffic is received on ATE port 1 for accepted prefixes for all community set except "200:1". + * Verify traffic is not received on ATE port 1 for rejected prefixes for community set "200:1". + + + ### Expected community matches | prefix-set | any_my_3_comms | all_3_comms | no_3_comms | any_my_regex_comms | @@ -155,4 +176,4 @@ rpcs: gnmi: gNMI.Set: gNMI.Subscribe: -``` \ No newline at end of file +``` diff --git a/feature/bgp/policybase/otg_tests/community_test/community_test.go b/feature/bgp/policybase/otg_tests/community_test/community_test.go index 3d545c83c8b..c5164592725 100644 --- a/feature/bgp/policybase/otg_tests/community_test/community_test.go +++ b/feature/bgp/policybase/otg_tests/community_test/community_test.go @@ -225,32 +225,7 @@ type testCase struct { } func TestCommunitySet(t *testing.T) { - bs := cfgplugins.NewBGPSession(t, cfgplugins.PortCount2, nil) - bs.WithEBGP(t, []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST}, []string{"port2"}, true, true) - - var communityMembers = [][][]int{ - { - {100, 1}, {200, 2}, {300, 3}, - }, - { - {100, 1}, {101, 1}, {200, 2}, - }, - { - {107, 1}, {108, 1}, {109, 1}, - }, - { - {400, 1}, {500, 1}, {600, 1}, - }, - } - - configureOTG(t, bs, prefixesV4, prefixesV6, communityMembers) - bs.PushAndStart(t) - - t.Log("Verify DUT BGP sessions up") - cfgplugins.VerifyDUTBGPEstablished(t, bs.DUT) - t.Log("Verify OTG BGP sessions up") - cfgplugins.VerifyOTGBGPEstablished(t, bs.ATE) - + bs := testSetup(t) ipv4 := bs.ATETop.Devices().Items()[1].Ethernets().Items()[0].Ipv4Addresses().Items()[0].Address() ipv6 := bs.ATETop.Devices().Items()[1].Ethernets().Items()[0].Ipv6Addresses().Items()[0].Address() @@ -319,3 +294,79 @@ func TestCommunitySet(t *testing.T) { }) } } + +func testSetup(t *testing.T) *cfgplugins.BGPSession { + t.Helper() + + bs := cfgplugins.NewBGPSession(t, cfgplugins.PortCount2, nil) + bs.WithEBGP(t, []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST}, []string{"port2"}, true, true) + + var communityMembers = [][][]int{ + { + {100, 1}, {200, 2}, {300, 3}, + }, + { + {100, 1}, {101, 1}, {200, 2}, + }, + { + {107, 1}, {108, 1}, {109, 1}, + }, + { + {400, 1}, {500, 1}, {600, 1}, + }, + } + + configureOTG(t, bs, prefixesV4, prefixesV6, communityMembers) + bs.PushAndStart(t) + + t.Log("Verify DUT BGP sessions up") + cfgplugins.VerifyDUTBGPEstablished(t, bs.DUT) + t.Log("Verify OTG BGP sessions up") + cfgplugins.VerifyOTGBGPEstablished(t, bs.ATE) + + return bs +} + +func TestCommunitySetUpdate(t *testing.T) { + bs := testSetup(t) + ipv4 := bs.ATETop.Devices().Items()[1].Ethernets().Items()[0].Ipv4Addresses().Items()[0].Address() + ipv6 := bs.ATETop.Devices().Items()[1].Ethernets().Items()[0].Ipv6Addresses().Items()[0].Address() + + commMatch := [3]string{"100:1"} + configureImportBGPPolicy(t, bs.DUT, ipv4, ipv6, "update_comm_set", commMatch, oc.BgpPolicy_MatchSetOptionsType_INVERT) + validateCommunitySetUpdateTraffic(t, bs) + + // change community match set + commMatch = [3]string{"200:2"} + configureImportBGPPolicy(t, bs.DUT, ipv4, ipv6, "update_comm_set", commMatch, oc.BgpPolicy_MatchSetOptionsType_INVERT) + validateCommunitySetUpdateTraffic(t, bs) +} + +func validateCommunitySetUpdateTraffic(t *testing.T, bs *cfgplugins.BGPSession) { + t.Helper() + + sleepTime := time.Duration(totalPackets/trafficPps) + 2 + bs.ATETop.Flows().Clear() + for index, prefixPairV4 := range prefixesV4 { + configureFlow(t, bs, prefixPairV4, "ipv4", index) + configureFlow(t, bs, prefixesV6[index], "ipv6", index) + } + bs.PushAndStartATE(t) + + // Verify BGP session after its reset with OTG push config & start + cfgplugins.VerifyDUTBGPEstablished(t, bs.DUT) + + t.Logf("Starting traffic for IPv4 and v6") + bs.ATE.OTG().StartTraffic(t) + time.Sleep(sleepTime * time.Second) + bs.ATE.OTG().StopTraffic(t) + otgutils.LogFlowMetrics(t, bs.ATE.OTG(), bs.ATETop) + + testResults := [4]bool{false, false, true, true} + for index, prefixPairV4 := range prefixesV4 { + t.Logf("Validating traffic test for IPv4 prefixes: [%s, %s]. Expected Result: [%t]", prefixPairV4[0], prefixPairV4[1], testResults[index]) + verifyTraffic(t, bs.ATE, "ipv4", testResults[index], index) + t.Logf("Validating traffic test for IPv6 prefixes: [%s, %s]. Expected Result: [%t]", prefixesV6[index][0], prefixesV6[index][1], testResults[index]) + verifyTraffic(t, bs.ATE, "ipv6", testResults[index], index) + } +} diff --git a/feature/bgp/policybase/otg_tests/community_test/metadata.textproto b/feature/bgp/policybase/otg_tests/community_test/metadata.textproto index 4c6b8f1496e..68da71ad8f8 100644 --- a/feature/bgp/policybase/otg_tests/community_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/community_test/metadata.textproto @@ -18,7 +18,6 @@ platform_exceptions: { default_network_instance: "default" skip_set_rp_match_set_options: true skip_setting_disable_metric_propagation: true - bgp_conditions_match_community_set_unsupported: true } } platform_exceptions: { diff --git a/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto b/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto index ec09b76414c..1efb0711660 100644 --- a/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto @@ -18,7 +18,6 @@ platform_exceptions: { missing_value_for_defaults: true skip_set_rp_match_set_options: true bgp_community_set_refs_unsupported: true - bgp_conditions_match_community_set_unsupported: true bgp_community_member_is_a_string: true skip_bgp_send_community_type: true } diff --git a/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md b/feature/bgp/policybase/otg_tests/link_bandwidth_test/README.md similarity index 75% rename from feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md rename to feature/bgp/policybase/otg_tests/link_bandwidth_test/README.md index 4fa01af7fec..c725c5e4c7d 100644 --- a/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md +++ b/feature/bgp/policybase/otg_tests/link_bandwidth_test/README.md @@ -26,9 +26,9 @@ bandwidth communities to routes based on a prefix match. * Advertise ipv4 and ipv6 prefixes to DUT port 1 using the following communities: * prefix-set-1 with 2 ipv4 and 2 ipv6 routes without communities. * prefix-set-2 with 2 ipv4 and 2 ipv6 routes with communities `[ "100:100" ]`. - * prefix-set-3 with 2 ipv4 and 2 ipv6 routes with extended communities `[ "link-bandwidth:23456:0" ]`. + * [TODO value change] prefix-set-3 with 2 ipv4 and 2 ipv6 routes with extended communities `[ "link-bandwidth:23456:1000" ]`. * Configure Send community knob to IBGP neigbour to advertise the communities to IBGP peer - * use `/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/config/send-community`. + * [TODO] use `/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/config/send-community-type` leaf-list with value `[STANDARD EXTENDED]`. * RT-7.5.1 - Validate bgp sessions and traffic * For IPv4 and IPv6 prefixes: * Observe received prefixes at ATE port-2. @@ -48,18 +48,6 @@ bandwidth communities to routes based on a prefix match. * Create an ext-community-set named 'linkbw_any' with members as follows: * ext-community-member = [ "^link-bandwidth:.*:.*$" ] - - * Create a `/routing-policy/policy-definitions/policy-definition/policy-definition` named **'not_match_100_set_linkbw_1M'** with the following `statements` * statement[name='1-megabit-match']/ @@ -71,7 +59,7 @@ bandwidth communities to routes based on a prefix match. * actions/config/policy-result = ACCEPT_ROUTE * Create a `/routing-policy/policy-definitions/policy-definition/policy-definition` - named 'match_100_set_linkbw_2G' with the following `statements` + named **'match_100_set_linkbw_2G'** with the following `statements` * statement[name='2-gigabit-match']/ * conditions/bgp-conditions/match-community-set/config/community-set = 'regex_match_comm100' * conditions/bgp-conditions/match-community-set/config/match-set-options = ANY @@ -90,21 +78,7 @@ bandwidth communities to routes based on a prefix match. * statement[name='accept_all_routes']/ * actions/config/policy-result = ACCEPT_ROUTE - - - * For each policy-definition created, run a subtest (RT-7.8.3.x-) to + * For each policy-definition created, run a subtest (RT-7.5.3.x--import) to * Use gnmi Set REPLACE option for: * `/routing-policy/policy-definitions` to configure the policy * Use `/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/import-policy` @@ -119,32 +93,49 @@ bandwidth communities to routes based on a prefix match. * Expected community values for each policy | | set_linkbw_0 | not_match_100_set_linkbw_1M | | ------------ | -------------------------------------- | --------------------------- | - | prefix-set-1 | *DEPRECATED* | [none] | + | prefix-set-1 | *DEPRECATED* | [ "link-bandwidth:23456:1000000" ] | | prefix-set-2 | *DEPRECATED* | [ "100:100" ] | - | prefix-set-3 | *DEPRECATED* | [ "link-bandwidth:23456:0" ] | + | prefix-set-3 | *DEPRECATED* | [ "link-bandwidth:23456:1000000" ] | | | match_100_set_linkbw_2G | del_linkbw | rm_any_zero_bw_set_LocPref_5 | | ------------ | ------------------------------------------------- | ------------- | ---------------------------- | | prefix-set-1 | [ none ] | [none] | *DEPRECATED* | | prefix-set-2 | [ "100:100", "link-bandwidth:23456:2000000000" ] | [ "100:100" ] | *DEPRECATED* | - | prefix-set-3 | [ "link-bandwidth:23456:0" ] | [ none ] | *DEPRECATED* | + | prefix-set-3 | [ "link-bandwidth:23456:1000" ] | [ none ] | *DEPRECATED* | * Regarding prefix-set-3 and policy "nomatch_100_set_linkbw_2G" * prefix-set-3 is advertised to the DUT with community "link-bandwidth:100:0" set. * The DUT evaluates a match for "regex_nomatch_as100". This does not match because the regex pattern does not include the link-bandwidth community type. * Community linkbw_2G should be added. - - + +[TODO] For each policy-definition created, run a subtest (RT-7.5.4.x--export) to + + * Use gnmi Set REPLACE option to attach `allow_all` policy using `/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/export-policy` to apply the policy on the DUT bgp neighbor to the ATE port 1. + * Use gnmi Set REPLACE option for: + * `/routing-policy/policy-definitions` to configure the policy + * Use `/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/export-policy` + to apply the policy on the DUT bgp neighbor to the ATE port 2. + * Verify expected communities are present in ATE port 2. + * Mark test as passing if Global Administartive valuee (ASN) of link-bakdwidth extended community **send by DUT** is either `23456` or ASN of DUT. + + * Expected community values for each policy + + | | set_linkbw_0 | not_match_100_set_linkbw_1M | + | ------------ | -------------------------------------- | --------------------------- | + | prefix-set-1 | *DEPRECATED* | [ "link-bandwidth:23456:1000000" ] | + | prefix-set-2 | *DEPRECATED* | [ "100:100" ] | + | prefix-set-3 | *DEPRECATED* | [ "link-bandwidth:23456:1000000" ] | + + | | match_100_set_linkbw_2G | del_linkbw | rm_any_zero_bw_set_LocPref_5 | + | ------------ | ------------------------------------------------- | ------------- | ---------------------------- | + | prefix-set-1 | [ none ] | [none] | *DEPRECATED* | + | prefix-set-2 | [ "100:100", "link-bandwidth:23456:2000000000" ] | [ "100:100" ] | *DEPRECATED* | + | prefix-set-3 | [ "link-bandwidth:23456:1000" ] | [ none ] | *DEPRECATED* | + + * Regarding prefix-set-3 and policy "nomatch_100_set_linkbw_2G" + * prefix-set-3 is advertised to the DUT with community "link-bandwidth:100:0" set. + * The DUT evaluates a match for "regex_nomatch_as100". This does not match because the regex pattern does not include the link-bandwidth community type. + * Community linkbw_2G should be added. ## OpenConfig Path and RPC Coverage @@ -154,7 +145,7 @@ The below yaml defines the OC paths intended to be covered by this test. OC pat paths: ## Config Parameter Coverage ## Configuration to enable advertise communities to bgp peer - /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/config/send-community: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/config/send-community-type: ## Policy for community-set configuration /routing-policy/defined-sets/bgp-defined-sets/ext-community-sets/ext-community-set/config/ext-community-set-name: /routing-policy/defined-sets/bgp-defined-sets/ext-community-sets/ext-community-set/config/ext-community-member: diff --git a/feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go b/feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go similarity index 77% rename from feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go rename to feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go index e240cd817d6..a1205cfa0c0 100644 --- a/feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go +++ b/feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go @@ -114,16 +114,16 @@ var ( extCommunitySet = map[string]string{ "linkbw_1M": "link-bandwidth:23456:1M", "linkbw_2G": "link-bandwidth:23456:2G", - "linkbw_any": "^link-bandwidth:.*:.$", + "linkbw_any": "^link-bandwidth:.*:.*$", } extCommunitySetCisco = map[string]string{ "linkbw_1M": "23456:1000000", "linkbw_2G": "23456:2000000000", - "linkbw_any": "^.*:.$", + "linkbw_any": "^.*:.*$", } - CommunitySet = map[string]string{ + communitySet = map[string]string{ "regex_match_comm100": "^100:.*$", } ) @@ -182,35 +182,65 @@ func TestBGPLinkBandwidth(t *testing.T) { } baseSetupConfigAndVerification(t, td) configureExtCommunityRoutingPolicy(t, dut) - if deviations.BgpExplicitExtendedCommunityEnable(dut) { - enableExtCommunityCLIConfig(t, dut) - } + enableExtCommunityCLIConfig(t, dut) + testCases := []testCase{ { - name: "Policy set not_match_100_set_linkbw_1M", + name: "ImportPolicy set not_match_100_set_linkbw_1M", policyName: "not_match_100_set_linkbw_1M", - applyPolicy: applyPolicyDut, - validate: validatPolicyDut, - routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "100:100", prefixSet3Comm: "link-bandwidth:23456:0"}, + applyPolicy: applyImportPolicyDut, + validate: validateImportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "link-bandwidth:23456:1000000", prefixSet2Comm: "100:100", prefixSet3Comm: "link-bandwidth:23456:1000000"}, localPerf: false, validateRouteCommunityV4: validateRouteCommunityV4, validateRouteCommunityV6: validateRouteCommunityV6, }, { - name: "Policy set match_100_set_linkbw_2G", + name: "ExportPolicy set not_match_100_set_linkbw_1M", + policyName: "not_match_100_set_linkbw_1M", + applyPolicy: applyExportPolicyDut, + validate: validateExportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "link-bandwidth:23456:1000000", prefixSet2Comm: "100:100", prefixSet3Comm: "link-bandwidth:23456:1000000"}, + localPerf: false, + validateRouteCommunityV4: validateRouteCommunityV4, + validateRouteCommunityV6: validateRouteCommunityV6, + }, + { + name: "ImportPolicy set match_100_set_linkbw_2G", policyName: "match_100_set_linkbw_2G", - applyPolicy: applyPolicyDut, - validate: validatPolicyDut, - routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "link-bandwidth:23456:2000000000", prefixSet3Comm: "link-bandwidth:23456:0"}, + applyPolicy: applyImportPolicyDut, + validate: validateImportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "link-bandwidth:23456:2000000000", prefixSet3Comm: "link-bandwidth:23456:1000"}, localPerf: false, validateRouteCommunityV4: validateRouteCommunityV4, validateRouteCommunityV6: validateRouteCommunityV6, }, + { - name: "Policy set del_linkbw", + name: "ExportPolicy set match_100_set_linkbw_2G", + policyName: "match_100_set_linkbw_2G", + applyPolicy: applyExportPolicyDut, + validate: validateExportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "link-bandwidth:23456:2000000000", prefixSet3Comm: "link-bandwidth:23456:1000"}, + localPerf: false, + validateRouteCommunityV4: validateRouteCommunityV4, + validateRouteCommunityV6: validateRouteCommunityV6, + }, + { + name: "ImportPolicy set del_linkbw", policyName: "del_linkbw", - applyPolicy: applyPolicyDut, - validate: validatPolicyDut, + applyPolicy: applyImportPolicyDut, + validate: validateImportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "100:100", prefixSet3Comm: "none"}, + localPerf: false, + validateRouteCommunityV4: validateRouteCommunityV4, + validateRouteCommunityV6: validateRouteCommunityV6, + }, + { + name: "ExportPolicy set del_linkbw", + policyName: "del_linkbw", + applyPolicy: applyExportPolicyDut, + validate: validateExportPolicyDut, routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "100:100", prefixSet3Comm: "none"}, localPerf: false, validateRouteCommunityV4: validateRouteCommunityV4, @@ -229,25 +259,41 @@ func TestBGPLinkBandwidth(t *testing.T) { } func enableExtCommunityCLIConfig(t *testing.T, dut *ondatra.DUTDevice) { - var extCommunityEnableCLIConfig string - switch dut.Vendor() { - case ondatra.CISCO: - extCommunityEnableCLIConfig = fmt.Sprintf("router bgp %v instance BGP neighbor-group %v \n ebgp-recv-extcommunity-dmz \n ebgp-send-extcommunity-dmz\n", dutAS, cfgplugins.BGPPeerGroup1) - default: - t.Fatalf("Unsupported vendor %s for deviation 'BgpExplicitExtendedCommunityEnable'", dut.Vendor()) - } - helpers.GnmiCLIConfig(t, dut, extCommunityEnableCLIConfig) + if deviations.BgpExplicitExtendedCommunityEnable(dut) { + var extCommunityEnableCLIConfig string + switch dut.Vendor() { + case ondatra.CISCO: + extCommunityEnableCLIConfig = fmt.Sprintf("router bgp %v instance BGP neighbor-group %v \n ebgp-recv-extcommunity-dmz \n ebgp-send-extcommunity-dmz\n", dutAS, cfgplugins.BGPPeerGroup1) + default: + t.Fatalf("Unsupported vendor %s for deviation 'BgpExplicitExtendedCommunityEnable'", dut.Vendor()) + } + helpers.GnmiCLIConfig(t, dut, extCommunityEnableCLIConfig) + } } -func applyPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { - // Apply ipv4 policy to bgp neighbour. +func removeImportAndExportPolicy(t *testing.T, dut *ondatra.DUTDevice) { + dni := deviations.DefaultNetworkInstance(dut) + + bd := &gnmi.SetBatch{} + path1 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + path2 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + path3 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + path4 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + gnmi.BatchDelete(bd, path1.Config()) + gnmi.BatchDelete(bd, path2.Config()) + gnmi.BatchDelete(bd, path3.Config()) + gnmi.BatchDelete(bd, path4.Config()) + bd.Set(t, dut) +} + +func applyImportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { root := &oc.Root{} dni := deviations.DefaultNetworkInstance(dut) - path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName). - Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + removeImportAndExportPolicy(t, dut) - policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName). - GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() + // Apply ipv4 policy to bgp neighbour. + path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() policy.SetImportPolicy([]string{policyName}) gnmi.Replace(t, dut, path.Config(), policy) @@ -269,13 +315,70 @@ func applyPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { gnmi.Update(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Config(), niProto) } -func validatPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { +func applyExportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { + root := &oc.Root{} + dni := deviations.DefaultNetworkInstance(dut) + removeImportAndExportPolicy(t, dut) + + // Apply ipv4 policy to bgp neighbour. + path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort2.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() + policy.SetExportPolicy([]string{policyName}) + gnmi.Replace(t, dut, path.Config(), policy) + + // Apply ipv6 policy to bgp neighbour. + path = gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + policy = root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort2.IPv6).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).GetOrCreateApplyPolicy() + policy.SetExportPolicy([]string{policyName}) + gnmi.Replace(t, dut, path.Config(), policy) + + ni := root.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + bgpNbrV4 := bgp.GetOrCreateNeighbor(atePort1.IPv4) + bgpNbrV4.PeerGroup = ygot.String(cfgplugins.BGPPeerGroup1) + bgpNbrV6 := bgp.GetOrCreateNeighbor(atePort1.IPv6) + bgpNbrV6.PeerGroup = ygot.String(cfgplugins.BGPPeerGroup1) + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Config(), niProto) +} + +func validateImportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { dni := deviations.DefaultNetworkInstance(dut) path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() - policy := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy](t, dut, path.State()) - importPolicies := policy.GetImportPolicy() - if len(importPolicies) != 1 { - t.Fatalf("ImportPolicy Ipv4 got= %v, want %v", importPolicies, []string{policyName}) + _, ok := gnmi.Watch(t, dut, path.State(), 30*time.Second, func(v *ygnmi.Value[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy]) bool { + value, ok := v.Val() + if !ok { + return false + } + importPolicies := value.GetImportPolicy() + if len(importPolicies) != 1 || importPolicies[0] != policyName { + return false + } + return true + }).Await(t) + if !ok { + t.Fatalf("invalid import policy") + } +} + +func validateExportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { + dni := deviations.DefaultNetworkInstance(dut) + path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + _, ok := gnmi.Watch(t, dut, path.State(), 30*time.Second, func(v *ygnmi.Value[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy]) bool { + value, ok := v.Val() + if !ok { + return false + } + exportPolicies := value.GetExportPolicy() + if len(exportPolicies) != 1 || exportPolicies[0] != policyName { + return false + } + return true + }).Await(t) + if !ok { + t.Fatalf("invalid export policy") } } @@ -325,20 +428,19 @@ func validateRouteCommunityV4Prefix(t *testing.T, td testData, community, v4Pref for _, ec := range bgpPrefix.ExtendedCommunity { lbSubType := ec.Structured.NonTransitive_2OctetAsType.LinkBandwidthSubtype listCommunity := strings.Split(community, ":") - Bandwidth := listCommunity[2] + bandwidth := listCommunity[2] if lbSubType.GetGlobal_2ByteAs() != 23456 && lbSubType.GetGlobal_2ByteAs() != 32002 && lbSubType.GetGlobal_2ByteAs() != 32001 { t.Errorf("ERROR AS number should be 23456 or %d got %d", ateAS, lbSubType.GetGlobal_2ByteAs()) return } - if Bandwidth == "0" { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 0 { - t.Errorf("ERROR lb Bandwidth want 0, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } - } else { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { - t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } + if bandwidth == "1000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) == 0 { + t.Errorf("ERROR lb Bandwidth want 1000, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "1000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 125000 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 1000000 { + t.Errorf("ERROR lb Bandwidth want :1M, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "2000000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { + t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) } + if !deviations.BgpExtendedCommunityIndexUnsupported(td.dut) { verifyExtCommunityIndexV4(t, td, v4Prefix) } @@ -361,7 +463,6 @@ func validateRouteCommunityV6(t *testing.T, td testData, ec extCommunity) { } func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Prefix string) { - // This function to verify received route communities on ATE ports. _, ok := gnmi.WatchAll(t, td.ate.OTG(), @@ -396,19 +497,17 @@ func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Pref for _, ec := range bgpPrefix.ExtendedCommunity { lbSubType := ec.Structured.NonTransitive_2OctetAsType.LinkBandwidthSubtype listCommunity := strings.Split(community, ":") - Bandwidth := listCommunity[2] + bandwidth := listCommunity[2] if lbSubType.GetGlobal_2ByteAs() != 23456 && lbSubType.GetGlobal_2ByteAs() != 32002 && lbSubType.GetGlobal_2ByteAs() != 32001 { t.Errorf("ERROR AS number should be 23456 or %d got %d", ateAS, lbSubType.GetGlobal_2ByteAs()) return } - if Bandwidth == "0" { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 0 { - t.Errorf("ERROR lb Bandwidth want 0, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } - } else { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { - t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } + if bandwidth == "1000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) == 0 { + t.Errorf("ERROR lb Bandwidth want 1000, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "1000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 125000 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 1000000 { + t.Errorf("ERROR lb Bandwidth want :1M, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "2000000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { + t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) } if !deviations.BgpExtendedCommunityIndexUnsupported(td.dut) { verifyExtCommunityIndexV6(t, td, v6Prefix) @@ -419,6 +518,7 @@ func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Pref } } } + func configureImportRoutingPolicyAllowAll(t *testing.T, dut *ondatra.DUTDevice) { root := &oc.Root{} rp := root.GetOrCreateRoutingPolicy() @@ -509,26 +609,10 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { root := &oc.Root{} var communitySetCLIConfig string var extCommunitySetCLIConfig string - switch dut.Vendor() { - case ondatra.CISCO: - extCommunitySet = extCommunitySetCisco - default: - t.Logf("extCommunitySet = %v", extCommunitySet) - } - if !deviations.BgpExtendedCommunitySetUnsupported(dut) { - for name, community := range extCommunitySet { - rp := root.GetOrCreateRoutingPolicy() - pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() - stmt, err := pdef.NewExtCommunitySet(name) - if err != nil { - t.Fatalf("NewExtCommunitySet failed: %v", err) - } - stmt.SetExtCommunityMember([]string{community}) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) - } - } else { + if deviations.BgpExtendedCommunitySetUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: + extCommunitySet = extCommunitySetCisco for name, community := range extCommunitySet { if name == "linkbw_any" && deviations.CommunityMemberRegexUnsupported(dut) { communitySetCLIConfig = fmt.Sprintf("community-set %v \n dfa-regex '%v' \n end-set", name, community) @@ -541,45 +625,55 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { default: t.Fatalf("Unsupported vendor %s for native command support for deviation 'BgpExtendedCommunitySetUnsupported'", dut.Vendor()) } - } - - if !(deviations.CommunityMemberRegexUnsupported(dut)) { - for name, community := range CommunitySet { + } else { + for name, community := range extCommunitySet { rp := root.GetOrCreateRoutingPolicy() pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() - stmt, err := pdef.NewCommunitySet(name) + stmt, err := pdef.NewExtCommunitySet(name) if err != nil { - t.Fatalf("NewCommunitySet failed: %v", err) + t.Fatalf("NewExtCommunitySet failed: %v", err) } - cs := []oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{} - cs = append(cs, oc.UnionString(community)) - stmt.SetCommunityMember(cs) + stmt.SetExtCommunityMember([]string{community}) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } - } else { + } + + if deviations.CommunityMemberRegexUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: - for name, community := range CommunitySet { + for name, community := range communitySet { communitySetCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v' \n end-set", name, community) helpers.GnmiCLIConfig(t, dut, communitySetCLIConfig) } default: t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'CommunityMemberRegexUnsupported'", dut.Vendor()) } + } else { + for name, community := range communitySet { + rp := root.GetOrCreateRoutingPolicy() + pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() + stmt, err := pdef.NewCommunitySet(name) + if err != nil { + t.Fatalf("NewCommunitySet failed: %v", err) + } + cs := []oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{} + cs = append(cs, oc.UnionString(community)) + stmt.SetCommunityMember(cs) + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } } // Configure routing Policy not_match_100_set_linkbw_1M. rpNotMatch := root.GetOrCreateRoutingPolicy() pdef2 := rpNotMatch.GetOrCreatePolicyDefinition("not_match_100_set_linkbw_1M") - pdef2Stmt1, err := pdef2.AppendNewStatement("1-megabit-match") + pdef2Stmt1, err := pdef2.AppendNewStatement("regex_match_comm100_rm_lbw") if err != nil { - t.Fatalf("AppendNewStatement 1-megabit-match failed: %v", err) + t.Fatalf("AppendNewStatement regex_match_comm100_rm_lbw failed: %v", err) } - if !deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { ref := pdef2Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_1M"}) - ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_any"}) + ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_REMOVE) ref.SetMethod(oc.SetCommunity_Method_REFERENCE) } if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { @@ -608,25 +702,51 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { if !deviations.SkipSettingStatementForPolicy(dut) { pdef2Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) } - pdef2Stmt2, err := pdef2.AppendNewStatement("accept_all_routes") + + pdef2Stmt2, err := pdef2.AppendNewStatement("regex_match_comm100_add_lbw") if err != nil { - t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) + t.Fatalf("AppendNewStatement regex_match_comm100_add_lbw failed: %v", err) } - pdef2Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - if !deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpNotMatch) + ref := pdef2Stmt2.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_1M"}) + ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) + ref.SetMethod(oc.SetCommunity_Method_REFERENCE) + } + if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + switch dut.Vendor() { + case ondatra.ARISTA: + ref1 := pdef2Stmt2.GetOrCreateConditions().GetOrCreateBgpConditions() + ref1.SetCommunitySet("regex_match_comm100_deviation1") + } } else { + ref1 := pdef2Stmt2.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() + ref1.SetCommunitySet("regex_match_comm100") + ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_INVERT) + } + if !deviations.SkipSettingStatementForPolicy(dut) { + pdef2Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) + } + + pdef2Stmt3, err := pdef2.AppendNewStatement("accept_all_routes") + if err != nil { + t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) + } + pdef2Stmt3.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + + if deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: var communityCLIConfig string - communityCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match invert \n end-set", "regex_match_comm100", CommunitySet["regex_match_comm100"]) + communityCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match invert \n end-set", "regex_match_comm100", communitySet["regex_match_comm100"]) policySetCLIConfig := fmt.Sprintf("route-policy %v \n #statement-1 1-megabit-match \n if community is-empty then \n pass \n elseif community in %v then \n set extcommunity bandwidth %v \n endif \n pass \n #statement-2 accept_all_routes \n done \n end-policy", "not_match_100_set_linkbw_1M", "regex_match_comm100", "linkbw_1M") helpers.GnmiCLIConfig(t, dut, communityCLIConfig) helpers.GnmiCLIConfig(t, dut, policySetCLIConfig) default: t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'BgpSetExtCommunitySetRefsUnsupported'", dut.Vendor()) } + } else { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpNotMatch) } // Configure routing policy match_100_set_linkbw_2G. @@ -661,7 +781,7 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { ref1.SetCommunitySet("regex_match_comm100_deviation2") } } else { - ref1 := pdef3Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchCommunitySet() + ref1 := pdef3Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() ref1.SetCommunitySet("regex_match_comm100") ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) } @@ -673,18 +793,18 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) } pdef3Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - if !deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpMatch) - } else { + if deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: - communitySetCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match any \n end-set", "regex_match_any_comm100", CommunitySet["regex_match_comm100"]) + communitySetCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match any \n end-set", "regex_match_any_comm100", communitySet["regex_match_comm100"]) helpers.GnmiCLIConfig(t, dut, communitySetCLIConfig) communitySetCLIConfig = fmt.Sprintf("route-policy %v \n #statement-1 2-gigabit-match \n if community in %v then \n set extcommunity bandwidth %v \n endif \n pass \n #statement-2 accept_all_routes \n done \n end-policy", "match_100_set_linkbw_2G", "regex_match_any_comm100", "linkbw_2G") helpers.GnmiCLIConfig(t, dut, communitySetCLIConfig) default: t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'BgpSetExtCommunitySetRefsUnsupported' and 'BGPConditionsMatchCommunitySetUnsupported' and 'SkipSettingStatementForPolicy'", dut.Vendor()) } + } else { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpMatch) } // Configure routing policy del_linkbw. @@ -708,9 +828,7 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) } pdef4Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - if !deviations.BgpDeleteLinkBandwidthUnsupported(dut) { - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpDelLinkbw) - } else { + if deviations.BgpDeleteLinkBandwidthUnsupported(dut) { var delLinkbwCLIConfig string switch dut.Vendor() { case ondatra.CISCO: @@ -719,7 +837,11 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'BgpDeleteLinkBandwidthUnsupported'", dut.Vendor()) } helpers.GnmiCLIConfig(t, dut, delLinkbwCLIConfig) + } else { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpDelLinkbw) } + + fptest.LogQuery(t, "", gnmi.OC().RoutingPolicy().Config(), root) } func createFlow(t *testing.T, td testData, fc flowConfig) { @@ -801,7 +923,7 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { nV42 := bgp.GetOrCreateNeighbor(atePort2.IPv4) nV42.SetPeerAs(dutAS) if !deviations.SkipBgpSendCommunityType(td.dut) { - nV42.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_BOTH}) + nV42.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_STANDARD, oc.Bgp_CommunityType_EXTENDED}) } nV42.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) nV61 := bgp.GetOrCreateNeighbor(atePort1.IPv6) @@ -810,7 +932,7 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { nV62 := bgp.GetOrCreateNeighbor(atePort2.IPv6) nV62.SetPeerAs(dutAS) if !deviations.SkipBgpSendCommunityType(td.dut) { - nV62.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_BOTH}) + nV62.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_STANDARD, oc.Bgp_CommunityType_EXTENDED}) } nV62.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) gnmi.Update(t, td.dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(td.dut)).Config(), ni) @@ -849,12 +971,12 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { netv43.Addresses().Add().SetAddress(advertisedIPv43.address).SetPrefix(advertisedIPv43.prefix) extcommv4 := netv43.ExtendedCommunities().Add().NonTransitive2OctetAsType().LinkBandwidthSubtype() extcommv4.SetGlobal2ByteAs(23456) - extcommv4.SetBandwidth(0) + extcommv4.SetBandwidth(1000) netv63 := bgp6Peer1.V6Routes().Add().SetName("v6-bgpNet-dev3") netv63.Addresses().Add().SetAddress(advertisedIPv63.address).SetPrefix(advertisedIPv63.prefix) extcommv6 := netv63.ExtendedCommunities().Add().NonTransitive2OctetAsType().LinkBandwidthSubtype() extcommv6.SetGlobal2ByteAs(23456) - extcommv6.SetBandwidth(0) + extcommv6.SetBandwidth(1000) // Configure iBGP on OTG port2. ipv42 := td.otgP2.Ethernets().Items()[0].Ipv4Addresses().Items()[0] diff --git a/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto b/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto index 13552ef78af..e5e9757204d 100644 --- a/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto @@ -1,7 +1,40 @@ # proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto # proto-message: Metadata -plan_id: "RT-7.5" -description: "BGP Policy - Set Link Bandwidth Community" -testbed: TESTBED_DUT_ATE_2LINKS -tags: TAGS_DATACENTER_EDGE +uuid: "a8344612-0db0-42a1-96cf-38846a7f1603" +plan_id: "RT-7.5" +description: "BGP Policy - Match and Set Link Bandwidth Community" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + route_policy_under_afi_unsupported: true + omit_l2_mtu: true + missing_value_for_defaults: true + interface_enabled: true + default_network_instance: "default" + skip_set_rp_match_set_options: true + skip_setting_disable_metric_propagation: true + bgp_extended_community_index_unsupported: true + } +} +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + bgp_extended_community_set_unsupported: true + community_member_regex_unsupported: true + skip_setting_statement_for_policy: true + bgp_set_ext_community_set_refs_unsupported: true + bgp_delete_link_bandwidth_unsupported: true + skip_bgp_send_community_type: true + bgp_extended_community_index_unsupported: true + bgp_conditions_match_community_set_unsupported: true + bgp_explicit_extended_community_enable: true + } +} +tags: TAGS_AGGREGATION +tags: TAGS_DATACENTER_EDGE diff --git a/feature/bgp/policybase/otg_tests/route_installation_test/README.md b/feature/bgp/policybase/otg_tests/route_installation_test/README.md index 537844a7399..595f70498ed 100644 --- a/feature/bgp/policybase/otg_tests/route_installation_test/README.md +++ b/feature/bgp/policybase/otg_tests/route_installation_test/README.md @@ -24,25 +24,29 @@ Base BGP policy configuration and route installation. * Validate that traffic is not forwarded to withdrawn routes between ATE port-1 and ATE port-2. -## Config Parameter Coverage - -* /routing-policy/policy-definitions/policy-definition/config/name -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-local-pref -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-med -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/repeat-n - -## Telemetry Parameter Coverage - -For prefixes: - -* /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group - -Paths: - -* afi-safis/afi-safi/apply-policy/state/export-policy -* afi-safis/afi-safi/apply-policy/state/import-policy -* afi-safis/afi-safi/state/prefixes/installed -* afi-safis/afi-safi/state/prefixes/received -* afi-safis/afi-safi/state/prefixes/received-pre-policy -* afi-safis/afi-safi/state/prefixes/sent +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /routing-policy/policy-definitions/policy-definition/config/name: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-local-pref: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-med: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/repeat-n: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/asn: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/neighbor-address: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/peer-group-name: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/apply-policy/state/export-policy: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/apply-policy/state/import-policy: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/state/prefixes/installed: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/state/prefixes/received: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/state/prefixes/received-pre-policy: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/state/prefixes/sent: + +rpcs: + gnmi: + gNMI.Get: + gNMI.Subscribe: + +``` diff --git a/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/README.md b/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/README.md index 2632792ac9d..e507230aa7a 100644 --- a/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/README.md +++ b/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/README.md @@ -6,7 +6,7 @@ BGP Prefix Limit ## Procedure -* Configure eBGP session between ATE port-1 and DUT port-1,with an Accept-route all import-policy/export-policy under the neighbor AFI/SAFI. +* Configure eBGP session between ATE port-1 and DUT port-1,with an Accept-route all import-policy/export-policy under the BGP peer-group AFI/SAFI. * With maximum prefix limits of unlimited, and N. * Advertise prefixes of `limit - 1`, `limit`, `limit + 1`. Validate session state meets expected value at ATE. @@ -20,31 +20,22 @@ BGP Prefix Limit table by forwarding traffic to `prefix{0..n-1}` and `prefix{n}` where n is the maximum prefix limit configured. -## Config Parameter coverage - -For prefixes: - -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/ -* /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor - -Parameters: - -* afi-safis/afi-safi/ipv4-unicast/prefix-limit/config/max-prefixes -* afi-safis/afi-safi/ipv4-unicast/prefix-limit/config/restart-timer - -## Telemetry Parameter coverage - -* TODO: afi-safis/afi-safi/ipv\[46\]-unicast/prefix-limit/state/restart-timer -* TODO: - afi-safis/afi-safi/ipv\[46\]-unicast/prefix-limit/state/warning-threshold-pct -* TODO: - afi-safis/afi-safi/ipv\[46\]-unicast/prefix-limit/state/max-prefix-limit -* TODO: - afi-safis/afi-safi/ipv\[46\]-unicast/prefix-limit/state/prefix-limit-exceeded - -## Protocol/RPC Parameter coverage - -N/A +## OpenConfig Path and RPC Coverage + +```yaml +paths: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/peer-group-name: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/neighbor-address: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/config/max-prefixes: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/state/warning-threshold-pct: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/state/prefix-limit-exceeded: + +rpcs: + gnmi: + gNMI.Get: + gNMI.Subscribe: + gNMI.Set: +``` ## Minimum DUT platform requirement diff --git a/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/static_route_bgp_redistribution_test.go b/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/static_route_bgp_redistribution_test.go index 2aa5bece36a..44a3ca35150 100644 --- a/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/static_route_bgp_redistribution_test.go +++ b/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/static_route_bgp_redistribution_test.go @@ -1478,7 +1478,15 @@ func validateRedistributeNullNextHopStaticRoute(t *testing.T, dut *ondatra.DUTDe // Used by multiple IPv4 test validations for route presence and MED value func validateLearnedIPv4Prefix(t *testing.T, ate *ondatra.ATEDevice, bgpPeerName, subnet string, expectedMED uint32, shouldBePresent bool) { - time.Sleep(5 * time.Second) + + _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().BgpPeer(bgpPeerName).UnicastIpv4PrefixAny().State(), + time.Minute, func(v *ygnmi.Value[*otgtelemetry.BgpPeer_UnicastIpv4Prefix]) bool { + return v.IsPresent() + }).Await(t) + + if !ok { + t.Errorf("No BGP prefixes learnt") + } bgpPrefixes := gnmi.GetAll(t, ate.OTG(), gnmi.OTG().BgpPeer(bgpPeerName).UnicastIpv4PrefixAny().State()) found := false diff --git a/feature/bgp/tests/local_bgp_test/README.md b/feature/bgp/tests/local_bgp_test/README.md index de4b31660f8..b06db095a4b 100644 --- a/feature/bgp/tests/local_bgp_test/README.md +++ b/feature/bgp/tests/local_bgp_test/README.md @@ -8,7 +8,7 @@ The local\_bgp\_test brings up two OpenConfig controlled devices and tests that * Disconnected between them. * Verify BGP neighbor parameters -Enable an Accept-route all import-policy/export-policy for eBGP session under the neighbor AFI/SAFI. +Enable an Accept-route all import-policy/export-policy for eBGP session under the BGP peer-group AFI/SAFI. This test is suitable for running in a KNE environment. diff --git a/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/README.md b/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/README.md index 43d4f97c60f..4afc8e8cc08 100644 --- a/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/README.md +++ b/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/README.md @@ -8,7 +8,7 @@ BGP Keepalive and HoldTimer Configuration Test * Establish eBGP sessions as follows between ATE and DUT * The DUT has eBGP peering with ATE port 1 and ATE port 2. - * Enable an Accept-route all import-policy/export-policy under the neighbor AFI/SAFI. + * Enable an Accept-route all import-policy/export-policy under the BGP peer-group AFI/SAFI. * The first pair is called the "source" pair, and the second the "destination" pair * Validate BGP session state on DUT using telemetry. diff --git a/feature/experimental/basic_entries_installed_in_gribi/gribi_ip4_entry/feature.textproto b/feature/experimental/basic_entries_installed_in_gribi/gribi_ip4_entry/feature.textproto deleted file mode 100644 index 14e9565fdd7..00000000000 --- a/feature/experimental/basic_entries_installed_in_gribi/gribi_ip4_entry/feature.textproto +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_basic_entries_installed_in_gribi_gribi_ip4_entry" - version: 1 -} - -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/origin-protocol" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/id" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/interface" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/subinterface" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/ip-address" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/mac-address" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/decapsulate-header" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/counters/octets-forwarded" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/counters/packets-forwarded" -} diff --git a/feature/experimental/bgp/otg_tests/link_bandwidth_test/metadata.textproto b/feature/experimental/bgp/otg_tests/link_bandwidth_test/metadata.textproto deleted file mode 100644 index 5d2b671575b..00000000000 --- a/feature/experimental/bgp/otg_tests/link_bandwidth_test/metadata.textproto +++ /dev/null @@ -1,41 +0,0 @@ -# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto -# proto-message: Metadata - -uuid: "a8344612-0db0-42a1-96cf-38846a7f1603" -plan_id: "RT-7.5" -description: "BGP Policy - Match and Set Link Bandwidth Community" -testbed: TESTBED_DUT_ATE_2LINKS -platform_exceptions: { - platform: { - vendor: ARISTA - } - deviations: { - route_policy_under_afi_unsupported: true - omit_l2_mtu: true - missing_value_for_defaults: true - interface_enabled: true - default_network_instance: "default" - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true - bgp_conditions_match_community_set_unsupported: true - bgp_extended_community_index_unsupported: true - } -} -platform_exceptions: { - platform: { - vendor: CISCO - } - deviations: { - bgp_extended_community_set_unsupported: true - community_member_regex_unsupported: true - skip_setting_statement_for_policy: true - bgp_set_ext_community_set_refs_unsupported: true - bgp_delete_link_bandwidth_unsupported: true - skip_bgp_send_community_type: true - bgp_extended_community_index_unsupported: true - bgp_conditions_match_community_set_unsupported: true - bgp_explicit_extended_community_enable: true - } -} -tags: TAGS_AGGREGATION -tags: TAGS_DATACENTER_EDGE diff --git a/feature/experimental/gnmi_service/benchmarking_drained_configuration_convergence_time/feature.textproto b/feature/experimental/gnmi_service/benchmarking_drained_configuration_convergence_time/feature.textproto deleted file mode 100644 index fc6bb224159..00000000000 --- a/feature/experimental/gnmi_service/benchmarking_drained_configuration_convergence_time/feature.textproto +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_gnmi_service_benchmarking_drained_configuration_convergence_time" - version: 1 -} - -config_path { - path: "/routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-med" -} -config_path { - path: "/routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/repeat-n" -} -config_path { - path: "/routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/asn" -} diff --git a/feature/experimental/gnmi_service/telemetry_port_speed/feature.textproto b/feature/experimental/gnmi_service/telemetry_port_speed/feature.textproto deleted file mode 100644 index f7a6d7df109..00000000000 --- a/feature/experimental/gnmi_service/telemetry_port_speed/feature.textproto +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_gnmi_service_telemetry_port_speed" - version: 1 -} - -telemetry_path { - path: "/interfaces/interface/state/oper-status" -} -telemetry_path { - path: "/interfaces/interface/ethernet/state/port-speed" -} -telemetry_path { - path: "/interfaces/interface/aggregation/state/lag-speed" -} diff --git a/feature/experimental/hierarchical_gribi_entries/base_hierarchical_route_installation/feature.textproto b/feature/experimental/hierarchical_gribi_entries/base_hierarchical_route_installation/feature.textproto deleted file mode 100644 index f4d10b21f31..00000000000 --- a/feature/experimental/hierarchical_gribi_entries/base_hierarchical_route_installation/feature.textproto +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_hierarchical_gribi_entries_base_hierarchical_route_installation" - version: 1 -} - -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/origin-protocol" -} -telemetry_path { - path: "/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/id" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/interface" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/subinterface" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/index" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/ip-address" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/mac-address" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/backup-next-hop-group" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/color" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/origin-protocol" -} -telemetry_path { - path: "/network-instances/network-instance/afts/next-hops/next-hop/state/pushed-mpls-label-stack" -} diff --git a/feature/experimental/hierarchical_gribi_entries/traffic_balancing_according_to_weights/feature.textproto b/feature/experimental/hierarchical_gribi_entries/traffic_balancing_according_to_weights/feature.textproto deleted file mode 100644 index 2f8a1e24a06..00000000000 --- a/feature/experimental/hierarchical_gribi_entries/traffic_balancing_according_to_weights/feature.textproto +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_hierarchical_gribi_entries_traffic_balancing_according_to_weights" - version: 1 -} - -telemetry_path { - path: "/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/weight" -} diff --git a/feature/experimental/isis/ate_tests/internal/session/attrs.go b/feature/experimental/isis/ate_tests/internal/session/attrs.go deleted file mode 100644 index 06dfae73b5b..00000000000 --- a/feature/experimental/isis/ate_tests/internal/session/attrs.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2022 Google LLC -// -// 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. - -package session - -// This is identical to the internal/attrs library except it points to ygnmi -import ( - "fmt" - - "github.com/openconfig/featureprofiles/internal/deviations" - "github.com/openconfig/ondatra" - "github.com/openconfig/ondatra/gnmi/oc" - "github.com/openconfig/ygot/ygot" -) - -// Attributes bundles some common attributes for devices and/or interfaces. -// It provides helpers to generate appropriate configuration for OpenConfig -// and for an ATETopology. All fields are optional; only those that are -// non-empty will be set when configuring an interface. -type Attributes struct { - IPv4 string - IPv6 string - MAC string - Name string // Interface name, only applied to ATE ports. - Desc string // Description, only applied to DUT interfaces. - IPv4Len uint8 // Prefix length for IPv4. - IPv6Len uint8 // Prefix length for IPv6. - MTU uint16 -} - -// IPv4CIDR constructs the IPv4 CIDR notation with the given prefix -// length, e.g. "192.0.2.1/30". -func (a *Attributes) IPv4CIDR() string { - return fmt.Sprintf("%s/%d", a.IPv4, a.IPv4Len) -} - -// IPv6CIDR constructs the IPv6 CIDR notation with the given prefix -// length, e.g. "2001:db8::1/126". -func (a *Attributes) IPv6CIDR() string { - return fmt.Sprintf("%s/%d", a.IPv6, a.IPv6Len) -} - -// ConfigInterface configures an OpenConfig interface with these attributes. -func (a *Attributes) ConfigInterface(intf *oc.Interface, dut *ondatra.DUTDevice) *oc.Interface { - if a.Desc != "" { - intf.Description = ygot.String(a.Desc) - } - intf.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd - if deviations.InterfaceEnabled(dut) { - intf.Enabled = ygot.Bool(true) - } - if a.MTU > 0 && !deviations.OmitL2MTU(dut) { - intf.Mtu = ygot.Uint16(a.MTU + 14) - } - e := intf.GetOrCreateEthernet() - if a.MAC != "" { - e.MacAddress = ygot.String(a.MAC) - } - - s := intf.GetOrCreateSubinterface(0) - if a.IPv4 != "" { - s4 := s.GetOrCreateIpv4() - if deviations.InterfaceEnabled(dut) && !deviations.IPv4MissingEnabled(dut) { - s4.Enabled = ygot.Bool(true) - } - if a.MTU > 0 { - s4.Mtu = ygot.Uint16(a.MTU) - } - a4 := s4.GetOrCreateAddress(a.IPv4) - if a.IPv4Len > 0 { - a4.PrefixLength = ygot.Uint8(a.IPv4Len) - } - } - - if a.IPv6 != "" { - s6 := s.GetOrCreateIpv6() - if a.MTU > 0 { - s6.Mtu = ygot.Uint32(uint32(a.MTU)) - } - if deviations.InterfaceEnabled(dut) { - s6.Enabled = ygot.Bool(true) - } - a6 := s6.GetOrCreateAddress(a.IPv6) - if a.IPv6Len > 0 { - a6.PrefixLength = ygot.Uint8(a.IPv6Len) - } - } - return intf -} - -// NewOCInterface returns a new *oc.Interface configured with these attributes -func (a *Attributes) NewOCInterface(name string, dut *ondatra.DUTDevice) *oc.Interface { - return a.ConfigInterface(&oc.Interface{Name: ygot.String(name)}, dut) -} - -// AddToATE adds a new interface to an ATETopology with these attributes. -func (a *Attributes) AddToATE(top *ondatra.ATETopology, ap *ondatra.Port, peer *Attributes) *ondatra.Interface { - i := top.AddInterface(a.Name).WithPort(ap) - if a.MTU > 0 { - i.Ethernet().WithMTU(a.MTU) - } - if a.IPv4 != "" { - i.IPv4(). - WithAddress(a.IPv4CIDR()). - WithDefaultGateway(peer.IPv4) - } - if a.IPv6 != "" { - i.IPv6(). - WithAddress(a.IPv6CIDR()). - WithDefaultGateway(peer.IPv6) - } - return i -} diff --git a/feature/experimental/isis/ate_tests/internal/session/session.go b/feature/experimental/isis/ate_tests/internal/session/session.go deleted file mode 100644 index 6fbc5caa12c..00000000000 --- a/feature/experimental/isis/ate_tests/internal/session/session.go +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright 2022 Google LLC -// -// 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. - -// Package session is deprecated and scoped only to be used with -// feature/experimental/isis/ate_tests/*. Do not use elsewhere. -package session - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/openconfig/featureprofiles/internal/deviations" - "github.com/openconfig/featureprofiles/internal/fptest" - "github.com/openconfig/ondatra" - "github.com/openconfig/ondatra/gnmi/oc" - "github.com/openconfig/ondatra/gnmi/oc/netinstisis" - "github.com/openconfig/ondatra/gnmi/oc/networkinstance" - "github.com/openconfig/ondatra/gnmi/oc/ocpath" - "github.com/openconfig/ondatra/ixnet" - "github.com/openconfig/ygnmi/ygnmi" - "github.com/openconfig/ygot/ygot" -) - -// PTISIS is shorthand for the long oc protocol type constant -const PTISIS = oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS - -// The testbed consists of a dut and an ate with two connections, labeled ISISIntf and Intf2. -// ISISIntf links dut:port1 and ate:port1, which are assigned 192.0.2.1/30 and 192.0.2.2/30 -// respectively. Intf2 connects dut:port2 to ate:port2, which are 192.0.2.5/30 and 192.0.2.6/30. -// We establish an IS-IS adjacency over ISISIntf. For traffic testing, we configure the ATE end -// of the IS-IS adjacency to advertise 198.51.100.0/24, then generate traffic through ate:port2 with -// IPv4 headers indicating that it should go to a random address in that range; the dut should -// route this traffic to the IS-IS link, where the ATE should log it arriving on ate:port1. -const ( - DUTAreaAddress = "49.0001" - ATEAreaAddress = "49.0002" - DUTSysID = "1920.0000.2001" - ISISName = "DEFAULT" - pLen4 = 30 - pLen6 = 126 -) - -var ( - // DUTNET is the Network Entity Title for the DUT - DUTNET = fmt.Sprintf("%v.%v.00", DUTAreaAddress, DUTSysID) - // DUTISISAttrs has attributes for the DUT ISIS connection on port1 - DUTISISAttrs = &Attributes{ - Desc: "DUT to ATE with IS-IS", - IPv4: "192.0.2.1", - IPv6: "2001:db8::1", - IPv4Len: pLen4, - IPv6Len: pLen6, - } - // ATEISISAttrs has attributes for the ATE ISIS connection on port1 - ATEISISAttrs = &Attributes{ - Name: "port1", - Desc: "ATE to DUT with IS-IS", - IPv4: "192.0.2.2", - IPv6: "2001:db8::2", - IPv4Len: pLen4, - IPv6Len: pLen6, - } - // DUTTrafficAttrs has attributes for the DUT end of the traffic connection (port2) - DUTTrafficAttrs = &Attributes{ - Desc: "DUT to ATE secondary link", - IPv4: "192.0.2.5", - IPv6: "2001:db8::5", - IPv4Len: pLen4, - IPv6Len: pLen6, - } - // ATETrafficAttrs has attributes for the ATE end of the traffic connection (port2) - ATETrafficAttrs = &Attributes{ - Name: "port2", - Desc: "ATE to DUT secondary link", - IPv4: "192.0.2.6", - IPv6: "2001:db8::6", - IPv4Len: pLen4, - IPv6Len: pLen6, - } -) - -// ISISPath is shorthand for ProtocolPath().Isis(). -func ISISPath(dut *ondatra.DUTDevice) *netinstisis.NetworkInstance_Protocol_IsisPath { - return ProtocolPath(dut).Isis() -} - -// ProtocolPath returns the path to the IS-IS protocol named ISISName on the -// default network instance. -func ProtocolPath(dut *ondatra.DUTDevice) *networkinstance.NetworkInstance_ProtocolPath { - return ocpath.Root().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(PTISIS, ISISName) -} - -// addISISOC configures basic IS-IS on a device. -func addISISOC(dev *oc.Root, areaAddress, sysID, ifaceName string, dut *ondatra.DUTDevice) { - inst := dev.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) - prot := inst.GetOrCreateProtocol(PTISIS, ISISName) - prot.Enabled = ygot.Bool(true) - isis := prot.GetOrCreateIsis() - glob := isis.GetOrCreateGlobal() - if deviations.ISISInstanceEnabledRequired(dut) { - glob.Instance = ygot.String(ISISName) - } - glob.Net = []string{fmt.Sprintf("%v.%v.00", areaAddress, sysID)} - glob.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV4, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) - glob.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) - level := isis.GetOrCreateLevel(2) - level.MetricStyle = oc.Isis_MetricStyle_WIDE_METRIC - intf := isis.GetOrCreateInterface(ifaceName) - intf.CircuitType = oc.Isis_CircuitType_POINT_TO_POINT - intf.Enabled = ygot.Bool(true) - // Configure ISIS level at global mode if true else at interface mode - if deviations.ISISInterfaceLevel1DisableRequired(dut) { - intf.GetOrCreateLevel(1).Enabled = ygot.Bool(false) - } else { - intf.GetOrCreateLevel(2).Enabled = ygot.Bool(true) - } - glob.LevelCapability = oc.Isis_LevelType_LEVEL_2 - // Configure ISIS enable flag at interface level - intf.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV4, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) - intf.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) - if deviations.ISISInterfaceAfiUnsupported(dut) { - intf.Af = nil - } - -} - -// addISISTopo configures basic IS-IS on an ATETopology interface. -func addISISTopo(iface *ondatra.Interface, areaAddress, sysID string) { - isis := iface.ISIS() - isis. - WithAreaID(areaAddress). - WithTERouterID(sysID). - WithNetworkTypePointToPoint(). - WithWideMetricEnabled(true). - WithLevelL2().WithMetric(10) -} - -// TestSession is a convenience wrapper around the dut, ate, ports, and -// topology we're using. -type TestSession struct { - DUT *ondatra.DUTDevice - DUTClient *ygnmi.Client - ATE *ondatra.ATEDevice - // Rather than looking these up all the time, we fetch all the relevant ports - // and interfaces at setup time. - DUTPort1, DUTPort2, ATEPort1, ATEPort2 *ondatra.Port - ATEIntf1, ATEIntf2 *ondatra.Interface - // DUTConf and ATETop can be modified by tests; calling .Push() will apply - // them to the dut and ate. - DUTConf *oc.Root - ATETop *ondatra.ATETopology -} - -// New creates a new TestSession using the default global config, and -// configures the interfaces on the dut and the ate. -func New(t testing.TB) (*TestSession, error) { - t.Helper() - s := &TestSession{} - s.DUT = ondatra.DUT(t, "dut") - var err error - s.DUTClient, err = ygnmi.NewClient(s.DUT.RawAPIs().GNMI(t), ygnmi.WithTarget(s.DUT.ID())) - if err != nil { - return nil, fmt.Errorf("unable to connect to gNMI on %v: %w", s.DUT, err) - } - s.DUTPort1 = s.DUT.Port(t, "port1") - s.DUTPort2 = s.DUT.Port(t, "port2") - s.DUTConf = &oc.Root{} - // configure dut ports - DUTISISAttrs.ConfigInterface(s.DUTConf.GetOrCreateInterface(s.DUTPort1.Name()), s.DUT) - DUTTrafficAttrs.ConfigInterface(s.DUTConf.GetOrCreateInterface(s.DUTPort2.Name()), s.DUT) - - // If there is no ate, any operation that requires the ATE will call - // t.Fatal() instead. This is helpful for debugging the parts of the test - // that don't use an ATE. - if ate, ok := ondatra.ATEs(t)["ate"]; ok { - s.ATE = ate - s.ATEPort1 = s.ATE.Port(t, "port1") - s.ATEPort2 = s.ATE.Port(t, "port2") - s.ATETop = s.ATE.Topology().New() - s.ATEIntf1 = ATEISISAttrs.AddToATE(s.ATETop, s.ATEPort1, DUTISISAttrs) - s.ATEIntf2 = ATETrafficAttrs.AddToATE(s.ATETop, s.ATEPort2, DUTTrafficAttrs) - } - return s, nil -} - -// MustNew creates a new TestSession or Fatal()s if anything goes wrong. -func MustNew(t testing.TB) *TestSession { - t.Helper() - v, err := New(t) - if err != nil { - t.Fatalf("Unable to initialize topology: %v", err) - } - return v -} - -// WithISIS adds ISIS to a test session. -func (s *TestSession) WithISIS() *TestSession { - if deviations.ExplicitInterfaceInDefaultVRF(s.DUT) { - addISISOC(s.DUTConf, DUTAreaAddress, DUTSysID, s.DUTPort1.Name()+".0", s.DUT) - } else { - addISISOC(s.DUTConf, DUTAreaAddress, DUTSysID, s.DUTPort1.Name(), s.DUT) - } - if s.ATE != nil { - addISISTopo(s.ATEIntf1, ATEAreaAddress, "*") - } - return s -} - -// ConfigISIS takes two functions, one that operates on an OC IS-IS block and -// one that operates on an ondatra ATE IS-IS block. The first will be applied -// to the IS-IS block of ts.DUTConfig, and the second will be applied to the -// IS-IS configuration of ts.ATETop -func (s *TestSession) ConfigISIS(ocFn func(*oc.NetworkInstance_Protocol_Isis), ateFn func(*ixnet.ISIS)) { - ocFn(s.DUTConf.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(s.DUT)).GetOrCreateProtocol(PTISIS, ISISName).GetOrCreateIsis()) - if s.ATE != nil { - ateFn(s.ATEIntf1.ISIS()) - } -} - -// PushAndStart calls PushDUT and PushAndStartATE to send config to both -// devices. -func (s *TestSession) PushAndStart(t testing.TB) error { - t.Helper() - if err := s.PushDUT(context.Background(), t); err != nil { - return err - } - s.PushAndStartATE(t) - return nil -} - -// PushDUT replaces DUT config with s.dutConf. Only interfaces and the ISIS -// protocol are written. -func (s *TestSession) PushDUT(ctx context.Context, t testing.TB) error { - // Push the interfaces - for name, conf := range s.DUTConf.Interface { - _, err := ygnmi.Replace(ctx, s.DUTClient, ocpath.Root().Interface(name).Config(), conf) - if err != nil { - return fmt.Errorf("configuring interface %s: %w", name, err) - } - } - if deviations.ExplicitInterfaceInDefaultVRF(s.DUT) { - fptest.AssignToNetworkInstance(t, s.DUT, s.DUTPort1.Name(), deviations.DefaultNetworkInstance(s.DUT), 0) - fptest.AssignToNetworkInstance(t, s.DUT, s.DUTPort2.Name(), deviations.DefaultNetworkInstance(s.DUT), 0) - } - if deviations.ExplicitPortSpeed(s.DUT) { - fptest.SetPortSpeed(t, s.DUTPort1) - fptest.SetPortSpeed(t, s.DUTPort2) - } - - // Push the ISIS protocol - if _, err := ygnmi.Update(ctx, s.DUTClient, ocpath.Root().NetworkInstance(deviations.DefaultNetworkInstance(s.DUT)).Config(), &oc.NetworkInstance{ - Name: ygot.String(deviations.DefaultNetworkInstance(s.DUT)), - Type: oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_DEFAULT_INSTANCE, - }); err != nil { - return fmt.Errorf("configuring network instance: %w", err) - } - dutConf := s.DUTConf.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(s.DUT)).GetOrCreateProtocol(PTISIS, ISISName) - _, err := ygnmi.Replace(ctx, s.DUTClient, ProtocolPath(s.DUT).Config(), dutConf) - if err != nil { - return fmt.Errorf("configuring ISIS: %w", err) - } - return nil -} - -// PushAndStartATE pushes the ATETop to the ATE and starts protocols on it. -func (s *TestSession) PushAndStartATE(t testing.TB) { - t.Helper() - if s.ATE == nil { - t.Fatal("Cannot run test without ATE") - } - s.ATETop.Push(t).StartProtocols(t) -} - -// AwaitAdjacency waits up to a minute for the dut to report that the ISISIntf -// link has formed any IS-IS adjacency, returning the adjacency ID or an error -// if one doesn't form. -func (s *TestSession) AwaitAdjacency() (string, error) { - intf := ISISPath(s.DUT).Interface(s.DUTPort1.Name()) - if deviations.ExplicitInterfaceInDefaultVRF(s.DUT) { - intf = ISISPath(s.DUT).Interface(s.DUTPort1.Name() + ".0") - } - query := intf.LevelAny().AdjacencyAny().AdjacencyState().State() - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - watcher := ygnmi.WatchAll(ctx, s.DUTClient, query, func(val *ygnmi.Value[oc.E_Isis_IsisInterfaceAdjState]) error { - if val == nil || !val.IsPresent() { - return ygnmi.Continue - } - v, _ := val.Val() - if v == oc.Isis_IsisInterfaceAdjState_UP { - return nil - } - return ygnmi.Continue - }) - - got, err := watcher.Await() - if err != nil { - return "", err - } - return got.Path.GetElem()[10].GetKey()["system-id"], nil -} - -// MustAdjacency waits up to a minute for an IS-IS adjacency to form between -// the DUT and the ATE; it returns the adjacency ID or calls t.Fatal no -// adjacency forms. -func (s *TestSession) MustAdjacency(t testing.TB) string { - adjID, err := s.AwaitAdjacency() - if err != nil { - t.Fatalf("Waiting for adjacency to form: %v", err) - } - return adjID -} - -// MustATEInterface returns the ATE interface for the portID, or calls t.Fatal -// if this fails. -func (s *TestSession) MustATEInterface(t testing.TB, portID string) *ondatra.Interface { - if s.ATE == nil { - t.Fatal("Cannot run test without ATE") - } - iface, ok := s.ATETop.Interfaces()[portID] - if !ok { - t.Fatalf("No ATE interface with ID %v", portID) - } - return iface -} diff --git a/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/README.md b/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/README.md deleted file mode 100644 index 0a0d6fe16b1..00000000000 --- a/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# RT-2.6: IS-IS Hello-Padding enabled at interface level - -## Summary - -* Base IS-IS functionality and adjacency establishment. -* Verifies isis adjacency by changing MTU. - -## Procedure - -* Configure IS-IS for ATE port-1 and DUT port-1. -* Configure DUT with global hello-padding enabled. -* Ensure that adjacencies are established with: - * Interface level hello padding is enabled. - * Verify that IPv4 and IPv6 IS-ISIS adjacency comes up fine. - * Verify the output of ST path displaying the status of ISIS hello padding. - * If we change the MTU on either side, then adjacency should not come up. - * Verify that IPv4 and IPv6 prefixes that are advertised by ATE correctly installed into DUTs route and forwarding table. - * TODO-Verify the Hellos are sent with Padding during adjacency turn-up if the padding is enabled adaptively/sometimes. - * Ensure that IPv4 and IPv6 prefixes that are advertised as part of an (emulated) neighboring system are installed into the DUT routing table, and validate that packets are sent and received to them. - -## Config Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * global/config/authentication-check - * global/config/net - * global/config/level-capability - * global/config/hello-padding - * global/afi-safi/af/config/enabled - * levels/level/config/level-number - * levels/level/config/enabled - * levels/level/authentication/config/enabled - * levels/level/authentication/config/auth-mode - * levels/level/authentication/config/auth-password - * levels/level/authentication/config/auth-type - * interfaces/interface/config/interface-id - * interfaces/interface/config/enabled - * interfaces/interface/config/circuit-type - * interfaces/interface/timers/config/csnp-interval - * interfaces/interface/timers/config/lsp-pacing-interval - * interfaces/interface/levels/level/config/level-number - * interfaces/interface/levels/level/timers/config/hello-interval - * interfaces/interface/levels/level/timers/config/hello-multiplier - * interfaces/interface/levels/level/hello-authentication/config/auth-mode - * interfaces/interface/levels/level/hello-authentication/config/auth-password - * interfaces/interface/levels/level/hello-authentication/config/auth-type - * interfaces/interface/levels/level/hello-authentication/config/enabled - * interfaces/interface/afi-safi/af/config/afi-name - * interfaces/interface/afi-safi/af/config/safi-name - * interfaces/interface/afi-safi/af/config/metric - * interfaces/interface/afi-safi/af/config/enabled - -## Telemetry Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * global/state/hello-padding - * interfaces/interface/state/hello-padding - * interfaces/interface/levels/level/adjacencies/adjacency/state/adjacency-state - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv4-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv6-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/system-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/area-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/dis-system-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/local-extended-circuit-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/multi-topology - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-circuit-type - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-extended-circuit-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-snpa - * interfaces/interface/levels/level/adjacencies/adjacency/state/nlpid - * interfaces/interface/levels/level/adjacencies/adjacency/state/priority - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-status - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-support - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-suppress - * interfaces/interface/levels/level/afi-safi/af/state/afi-name - * interfaces/interface/levels/level/afi-safi/af/state/metric - * interfaces/interface/levels/level/afi-safi/af/state/safi-name - * interfaces/interface/levels/level/afi-safi/af/state/metric - * levels/level/system-level-counters/state/auth-fails - * levels/level/system-level-counters/state/auth-type-fails - * levels/level/system-level-counters/state/corrupted-lsps - * levels/level/system-level-counters/state/database-overloads - * levels/level/system-level-counters/state/exceed-max-seq-nums - * levels/level/system-level-counters/state/id-len-mismatch - * levels/level/system-level-counters/state/lsp-errors - * levels/level/system-level-counters/state/manual-address-drop-from-area - * levels/level/system-level-counters/state/max-area-address-mismatches - * levels/level/system-level-counters/state/own-lsp-purges - * levels/level/system-level-counters/state/part-changes - * levels/level/system-level-counters/state/seq-num-skips - * levels/level/system-level-counters/state/spf-runs diff --git a/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/README.md b/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/README.md deleted file mode 100644 index 6e80f5f2985..00000000000 --- a/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# RT-2.11: IS-IS Passive is enabled at the area level - -## Summary - -* Verify isis adjacency with passive enabled under level. - -## Topology - -* ATE:port1 <-> port1:DUT:port2 <-> ATE:port2 - -## Procedure - -* Configure IS-IS for ATE port-1 and DUT port-1. -* Configure DUT interface with IS-IS passive configured at area level 2. - * Verify that IS-IS adjacency is not coming up in level-2 area for IPv4 and IPV6 address families. -* Undo the IS-IS passive configuration under level 2 - * Verify that IS-IS adjacency for IPv4 and IPV6 address families are coming up in the level-2 area. - * Verify that IPv4 and IPv6 prefixes that are advertised by ATE are correctly installed into DUTs route and forwarding table. - * Ensure that IPv4 and IPv6 prefixes that are advertised as part of an (emulated) neighboring system are installed into the DUT routing table, and validate that packets are sent and received to them. - * TODO-Verify the output of ST path displaying the interface as passive in ISIS database/adj table - -## Config Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * global/config/authentication-check - * global/config/net - * global/config/level-capability - * global/config/hello-padding - * global/afi-safi/af/config/enabled - * levels/level/config/level-number - * levels/level/config/enabled - * levels/level/authentication/config/enabled - * levels/level/authentication/config/auth-mode - * levels/level/authentication/config/auth-password - * levels/level/authentication/config/auth-type - * interfaces/interface/config/interface-id - * interfaces/interface/config/enabled - * interfaces/interface/config/circuit-type - * interfaces/interface/config/passive - * interfaces/interface/timers/config/csnp-interval - * interfaces/interface/timers/config/lsp-pacing-interval - * interfaces/interface/levels/level/config/level-number - * interfaces/interface/levels/level/config/passive - * interfaces/interface/levels/level/timers/config/hello-interval - * interfaces/interface/levels/level/timers/config/hello-multiplier - * interfaces/interface/levels/level/hello-authentication/config/auth-mode - * interfaces/interface/levels/level/hello-authentication/config/auth-password - * interfaces/interface/levels/level/hello-authentication/config/auth-type - * interfaces/interface/levels/level/hello-authentication/config/enabled - * interfaces/interface/afi-safi/af/config/afi-name - * interfaces/interface/afi-safi/af/config/safi-name - * interfaces/interface/afi-safi/af/config/metric - * interfaces/interface/afi-safi/af/config/enabled - -## Telemetry Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * interfaces/interface/state/passive - * interfaces/interface/levels/level/state/passive - * interfaces/interface/levels/level/adjacencies/adjacency/state/adjacency-state - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv4-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv6-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/system-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/area-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/dis-system-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/local-extended-circuit-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/multi-topology - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-circuit-type - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-extended-circuit-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-snpa - * interfaces/interface/levels/level/adjacencies/adjacency/state/nlpid - * interfaces/interface/levels/level/adjacencies/adjacency/state/priority - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-status - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-support - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-suppress - * interfaces/interface/levels/level/afi-safi/af/state/afi-name - * interfaces/interface/levels/level/afi-safi/af/state/metric - * interfaces/interface/levels/level/afi-safi/af/state/safi-name - * interfaces/interface/levels/level/afi-safi/af/state/metric - * levels/level/system-level-counters/state/auth-fails - * levels/level/system-level-counters/state/auth-type-fails - * levels/level/system-level-counters/state/corrupted-lsps - * levels/level/system-level-counters/state/database-overloads - * levels/level/system-level-counters/state/exceed-max-seq-nums - * levels/level/system-level-counters/state/id-len-mismatch - * levels/level/system-level-counters/state/lsp-errors - * levels/level/system-level-counters/state/manual-address-drop-from-area - * levels/level/system-level-counters/state/max-area-address-mismatches - * levels/level/system-level-counters/state/own-lsp-purges - * levels/level/system-level-counters/state/part-changes - * levels/level/system-level-counters/state/seq-num-skips - * levels/level/system-level-counters/state/spf-runs diff --git a/feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/README.md b/feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/README.md deleted file mode 100644 index 4347c71375c..00000000000 --- a/feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# RT-2.8: IS-IS metric style wide not enabled - -## Summary - -* Base IS-IS functionality and adjacency establishment. -* Verifies route metric with wide metric disabled on DUT. - -## Procedure - -* TestISISWideMetricNotEnabled - - * Configure IS-IS for ATE port-1 and DUT port-1. - * Do not configure metric style wide under the area level. - * Enable wide metric style on ATE. - * Advertise ISIS prefixes from ATE with wide metrics (value > 63). - * Verify that IS-IS adjacency for IPv4 and IPV6 address family is coming up. - * Verify that IPv4 and IPv6 prefixes that are advertised by ATE correctly installed into DUTs route and forwarding table. - * TODO-Verify that the metrics of the IPv4 and IPv6 prefixes is 63. - * Ensure that IPv4 and IPv6 prefixes that are advertised as part of an (emulated) neighboring system are installed into the DUT routing table, and validate that packets are sent and received to them. - - -## Config Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * global/config/authentication-check - * global/config/net - * global/config/level-capability - * global/config/hello-padding - * global/afi-safi/af/config/enabled - * levels/level/config/level-number - * levels/level/config/enabled - * levels/level/config/metric-style - * levels/level/authentication/config/enabled - * levels/level/authentication/config/auth-mode - * levels/level/authentication/config/auth-password - * levels/level/authentication/config/auth-type - * interfaces/interface/config/interface-id - * interfaces/interface/config/enabled - * interfaces/interface/config/circuit-type - * interfaces/interface/config/passive - * interfaces/interface/timers/config/csnp-interval - * interfaces/interface/timers/config/lsp-pacing-interval - * interfaces/interface/levels/level/config/level-number - * interfaces/interface/levels/level/config/passive - * interfaces/interface/levels/level/timers/config/hello-interval - * interfaces/interface/levels/level/timers/config/hello-multiplier - * interfaces/interface/levels/level/hello-authentication/config/auth-mode - * interfaces/interface/levels/level/hello-authentication/config/auth-password - * interfaces/interface/levels/level/hello-authentication/config/auth-type - * interfaces/interface/levels/level/hello-authentication/config/enabled - * interfaces/interface/afi-safi/af/config/afi-name - * interfaces/interface/afi-safi/af/config/safi-name - * interfaces/interface/afi-safi/af/config/enabled - -## Telemetry Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * levels/level/state/metric-style - * interfaces/interface/levels/level/adjacencies/adjacency/state/adjacency-state - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv4-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv6-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/system-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/area-address - * interfaces/interface/levels/level/adjacencies/adjacency/state/dis-system-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/local-extended-circuit-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/multi-topology - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-circuit-type - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-extended-circuit-id - * interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-snpa - * interfaces/interface/levels/level/adjacencies/adjacency/state/nlpid - * interfaces/interface/levels/level/adjacencies/adjacency/state/priority - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-status - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-support - * interfaces/interface/levels/level/adjacencies/adjacency/state/restart-suppress - * interfaces/interface/levels/level/afi-safi/af/state/afi-name - * interfaces/interface/levels/level/afi-safi/af/state/metric - * interfaces/interface/levels/level/afi-safi/af/state/safi-name - * interfaces/interface/levels/level/afi-safi/af/state/metric - * levels/level/system-level-counters/state/auth-fails - * levels/level/system-level-counters/state/auth-type-fails - * levels/level/system-level-counters/state/corrupted-lsps - * levels/level/system-level-counters/state/database-overloads - * levels/level/system-level-counters/state/exceed-max-seq-nums - * levels/level/system-level-counters/state/id-len-mismatch - * levels/level/system-level-counters/state/lsp-errors - * levels/level/system-level-counters/state/manual-address-drop-from-area - * levels/level/system-level-counters/state/max-area-address-mismatches - * levels/level/system-level-counters/state/own-lsp-purges - * levels/level/system-level-counters/state/part-changes - * levels/level/system-level-counters/state/seq-num-skips - * levels/level/system-level-counters/state/spf-runs diff --git a/feature/experimental/lacp_and_base_interface/aggregate_interfaces/feature.textproto b/feature/experimental/lacp_and_base_interface/aggregate_interfaces/feature.textproto deleted file mode 100644 index b9f58a8ae68..00000000000 --- a/feature/experimental/lacp_and_base_interface/aggregate_interfaces/feature.textproto +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_lacp_and_base_interface_aggregate_interfaces" - version: 1 -} - -config_path { - path: "/interfaces/interface/ethernet/config/mac-address" -} -config_path { - path: "/interfaces/interface/ethernet/config/port-speed" -} -config_path { - path: "/interfaces/interface/ethernet/config/duplex-mode" -} -config_path { - path: "/interfaces/interface/ethernet/config/aggregate-id" -} -config_path { - path: "/interfaces/interface/aggregation/config/lag-type" -} -config_path { - path: "/interfaces/interface/aggregation/config/min-links" -} -config_path { - path: "/lacp/config/system-priority" -} -config_path { - path: "/lacp/interfaces/interface/config/name" -} -config_path { - path: "/lacp/interfaces/interface/config/interval" -} -config_path { - path: "/lacp/interfaces/interface/config/lacp-mode" -} -config_path { - path: "/lacp/interfaces/interface/config/system-id-mac" -} -config_path { - path: "/lacp/interfaces/interface/config/system-priority" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/counters/lacp-in-pkts" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/counters/lacp-errors" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/counters/lacp-timeout-transitions" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/counters/lacp-tx-errors" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/counters/lacp-out-pkts" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/counters/lacp-rx-errors" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/oper-key" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/last-change" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/partner-id" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/system-id" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/port-num" -} -telemetry_path { - path: "/lacp/interfaces/interface/state/system-priority" -} diff --git a/feature/experimental/platform/tests/breakout_configuration/README.md b/feature/experimental/platform/tests/breakout_configuration/README.md deleted file mode 100644 index d70c053e362..00000000000 --- a/feature/experimental/platform/tests/breakout_configuration/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# PLT-1.1: Interface breakout Test - -## Summary - -Validate Interface breakout configuration. - -## Procedure - - -* This test is carried out for different breakout types -* Connect DUT with ATE to all interfaces in the breakout port -* Configure each interface with test IP addressing -* Verify correct interface state and speed reported -* Verify that DUT responds to ARP/ICMP on all tested interfaces - -## Config Parameter coverage - -* /components/component/port/breakout-mode/groups/group/index -* /components/component/port/breakout-mode/groups/group/config -* /components/component/port/breakout-mode/groups/group/config/index -* /components/component/port/breakout-mode/groups/group/config/num-breakouts -* /components/component/port/breakout-mode/groups/group/config/breakout-speed -* /components/component/port/breakout-mode/groups/group/config/num-physical-channels - - -## Telemetry Parameter coverage - * interfaces/interface/state - * interfaces/interface/ethernet/stateOutput power thresholds: - -## Minimum DUT Platform Requirement - -* Breakout types - 4x100G, 2x100G and 4x10G \ No newline at end of file diff --git a/feature/experimental/policy/policy_base/feature.textproto b/feature/experimental/policy/policy_base/feature.textproto deleted file mode 100644 index e0799b0980c..00000000000 --- a/feature/experimental/policy/policy_base/feature.textproto +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_policy_policy_base" - version: 1 -} - -# Policy base - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/config/policy-id" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/config/type" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/state/policy-id" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/state/type" -} - -# Rules base - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/config/sequence-id" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/state/sequence-id" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/state/matched-pkts" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/state/matched-octets" -} - -# Action base - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/discard" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/state/discard" -} - -# Interface base - -config_path { - path: "/network-instances/network-instance/policy-forwarding/interfaces/interface/config/interface-id" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/interfaces/interface/state/interface-id" -} - -# L2 rules - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/config/ethertype" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/config/source-mac" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/config/source-mac-mask" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/config/destination-mac" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/config/destination-mac-mask" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/state/ethertype" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/state/source-mac" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/state/source-mac-mask" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/state/destination-mac" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/l2/state/destination-mac-mask" -} - -# IPv4 rules - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/config/source-address" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/config/destination-address" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/config/dscp" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/config/dscp-set" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/config/protocol" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/config/hop-limit" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/state/source-address" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/state/destination-address" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/state/dscp" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/state/dscp-set" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/state/protocol" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/state/hop-limit" -} - -# IPv6 rules - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/source-address" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/source-flow-label" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/destination-address" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/destination-flow-label" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/dscp" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/dscp-set" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/protocol" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/hop-limit" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/source-address" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/source-flow-label" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/destination-address" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/destination-flow-label" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/dscp" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/dscp-set" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/protocol" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/state/hop-limit" -} - -# Transport rules - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/transport/config/source-port" -} -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/transport/config/destination-port" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/transport/state/source-port" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/transport/state/destination-port" -} - diff --git a/feature/experimental/policy/policy_vrf_selection/feature.textproto b/feature/experimental/policy/policy_vrf_selection/feature.textproto deleted file mode 100644 index a5262ef5612..00000000000 --- a/feature/experimental/policy/policy_vrf_selection/feature.textproto +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_policy_policy_vrf_selection" - version: 1 -} - -# Interface - -config_path { - path: "/network-instances/network-instance/policy-forwarding/interfaces/interface/config/apply-vrf-selection-policy" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/interfaces/interface/state/apply-vrf-selection-policy" -} - -# VRF actions - -config_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/network-instance" -} -telemetry_path { - path: "/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/state/network-instance" -} - - -feature_profile_dependency { - name: "bgp_policybase" - version: 1 -} diff --git a/feature/experimental/replay/tests/presession_test/README.md b/feature/experimental/replay/tests/presession_test/README.md deleted file mode 100644 index 2fcd2fc461d..00000000000 --- a/feature/experimental/replay/tests/presession_test/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Replay-1.0: Record/replay presession test - -## Summary - -This is an example record/replay test. -At this time, no vendor is expected to run this test. diff --git a/feature/experimental/route_redistribution/feature.textproto b/feature/experimental/route_redistribution/feature.textproto deleted file mode 100644 index fa276b3ca6b..00000000000 --- a/feature/experimental/route_redistribution/feature.textproto +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_route_redistribution" - version: 1 -} - -# https://github.com/openconfig/public/blob/e9e3a82693d1f26c61d7fbf85b3b2d0418d4af9e/doc/network_instance_redistribution.md -# Protocol tables -config_path { - path: "/network-instances/network-instance/tables/table/config/protocol" -} -config_path { - path: "/network-instances/network-instance/tables/table/config/address-family" -} -telemetry_path { - path: "/network-instances/network-instance/tables/table/state/protocol" -} -telemetry_path { - path: "/network-instances/network-instance/tables/table/state/address-family" -} - - -# Table-connections -config_path { - path: "/network-instances/network-instance/table-connections/table-connection/config/src-protocol" -} -config_path { - path: "/network-instances/network-instance/table-connections/table-connection/config/dst-protocol" -} -config_path { - path: "/network-instances/network-instance/table-connections/table-connection/config/address-family" -} -config_path { - path: "/network-instances/network-instance/table-connections/table-connection/config/import-policy" -} -config_path { - path: "/network-instances/network-instance/table-connections/table-connection/config/default-import-policy" -} -telemetry_path { - path: "/network-instances/network-instance/table-connections/table-connection/state/src-protocol" -} -telemetry_path { - path: "/network-instances/network-instance/table-connections/table-connection/state/dst-protocol" -} -telemetry_path { - path: "/network-instances/network-instance/table-connections/table-connection/state/address-family" -} -telemetry_path { - path: "/network-instances/network-instance/table-connections/table-connection/state/import-policy" -} -telemetry_path { - path: "/network-instances/network-instance/table-connections/table-connection/state/default-import-policy" -} - - - -feature_profile_dependency { - name: "bgp" - version: 1 -} - -feature_profile_dependency { - name: "localaggregates" - version: 1 -} - -feature_profile_dependency { - name: "bgp_policybase" - version: 1 -} diff --git a/feature/experimental/telemetry_only/feature.textproto b/feature/experimental/telemetry_only/feature.textproto deleted file mode 100644 index 829203c9478..00000000000 --- a/feature/experimental/telemetry_only/feature.textproto +++ /dev/null @@ -1,459 +0,0 @@ -# Copyright 2022 Google LLC -# -# 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 -# -# https://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. -# -# proto-file: github.com/openconfig/featureprofiles/proto/feature.proto -# proto-message: FeatureProfile - -id { - name: "experimental_telemetry_only" - version: 1 -} - -# Fan -telemetry_path { - path: "/components/component/fan/state/speed" -} - -# Pipeline-counters lookup block -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/nexthop-memory" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/nexthop-memory-used" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/acl-memory-total-entries" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/acl-memory-used-entries" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/acl-memory-total-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/acl-memory-used-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/lookup-memory" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/lookup-block/state/lookup-memory-used" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/oversubscription" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/no-route" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/no-label" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/no-nexthop" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/invalid-packet" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/forwarding-policy" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/incorrect-software-state" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/rate-limit" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/lookup-block/state/fragment-total-drops" -} - -# Pipeline counters queueing block -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/queueing-block/state/in-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/queueing-block/state/out-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/queueing-block/state/queue-memory" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/queueing-block/state/queue-memory-used" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/queueing-block/state/loopback-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/queueing-block/state/loopback-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/queueing-block/state/oversubscription" -} - -# Pipeline counters fabric block -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/in-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/out-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/in-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/out-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/in-low-priority-cells" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/out-low-priority-cells" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/in-high-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/out-high-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/in-low-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/fabric-block/state/out-low-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/fabric-block/state/oversubscription" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/fabric-block/state/lost-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/fabric-block/state/out-high-priority" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/fabric-block/state/fabric-aggregate" -} - -# Pipeline counters host interface block -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/out-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/in-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/out-bytes" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/fragment-punt-pkts" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/in-high-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/out-high-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/in-low-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/packet/host-interface-block/state/out-low-priority-packets" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/oversubscription" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/rate-limit" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/in-high-priority" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/out-high-priority" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/in-low-priority" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/out-low-priority" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/fragment-punt" -} -telemetry_path { - path: "/components/component/integrated-circuit/pipeline-counters/drop/host-interface-block/state/host-aggregate" -} - - -# Port -telemetry_path { - path: "/components/component/port/breakout-mode/groups/group/state/breakout-speed" -} -telemetry_path { - path: "/components/component/port/breakout-mode/groups/group/state/index" -} -telemetry_path { - path: "/components/component/port/breakout-mode/groups/group/state/num-breakouts" -} -telemetry_path { - path: "/components/component/port/breakout-mode/groups/group/state/num-physical-channels" -} -config_path { - path: "/components/component/port/breakout-mode/groups/group/config/breakout-speed" -} -config_path { - path: "/components/component/port/breakout-mode/groups/group/config/index" -} -config_path { - path: "/components/component/port/breakout-mode/groups/group/config/num-breakouts" -} -config_path { - path: "/components/component/port/breakout-mode/groups/group/config/num-physical-channels" -} - -# Power supply -telemetry_path { - path: "/components/component/power-supply/state/input-current" -} -telemetry_path { - path: "/components/component/power-supply/state/output-current" -} -telemetry_path { - path: "/components/component/power-supply/state/output-voltage" -} - -# integrated circuit backplane -telemetry_path { - path: "/components/component/integrated-circuit/backplane-facing-capacity/state/total" -} -telemetry_path { - path: "/components/component/integrated-circuit/backplane-facing-capacity/state/consumed-capacity" -} -telemetry_path { - path: "/components/component/integrated-circuit/backplane-facing-capacity/state/available-pct" -} - -telemetry_path { - path: "/components/component/properties/property/state/value" -} -telemetry_path { - path: "/components/component/subcomponents/subcomponent/state/name" -} -telemetry_path { - path: "/components/component/state/description" -} -telemetry_path { - path: "/components/component/properties/property/state/value" -} -telemetry_path { - path: "/components/component/state/parent" -} -telemetry_path { - path: "/components/component/subcomponents/subcomponent/state/name" -} -telemetry_path { - path: "/components/component/integrated-circuit/state/node-id" -} -telemetry_path { - path: "/components/component/state/empty" -} -telemetry_path { - path: "/components/component/state/firmware-version" -} -telemetry_path { - path: "/components/component/state/hardware-version" -} -telemetry_path { - path: "/components/component/state/mfg-date" -} -telemetry_path { - path: "/components/component/state/mfg-name" -} -telemetry_path { - path: "/components/component/state/name" -} -telemetry_path { - path: "/components/component/state/oper-status" -} -telemetry_path { - path: "/components/component/state/parent" -} -telemetry_path { - path: "/components/component/state/part-no" -} -telemetry_path { - path: "/components/component/state/serial-no" -} -telemetry_path { - path: "/components/component/state/software-version" -} -telemetry_path { - path: "/components/component/state/temperature/instant" -} -telemetry_path { - path: "/components/component/state/type" -} -telemetry_path { - path: "/components/component/transceiver/physical-channels/channel/state/input-power/instant" -} -telemetry_path { - path: "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/instant" -} -telemetry_path { - path: "/components/component/transceiver/physical-channels/channel/state/output-power/instant" -} -telemetry_path { - path: "/components/component/transceiver/state/form-factor" -} -telemetry_path { - path: "/interfaces/interface/aggregation/state/member" -} -telemetry_path { - path: "/interfaces/interface/ethernet/state/counters/in-maxsize-exceeded" -} -telemetry_path { - path: "/interfaces/interface/hold-time/state/down" -} -telemetry_path { - path: "/interfaces/interface/hold-time/state/up" -} -telemetry_path { - path: "/interfaces/interface/state/counters/carrier-transitions" -} -telemetry_path { - path: "/interfaces/interface/state/counters/in-discards" -} -telemetry_path { - path: "/interfaces/interface/state/counters/in-fcs-errors" -} -telemetry_path { - path: "/interfaces/interface/state/counters/in-pkts" -} -telemetry_path { - path: "/interfaces/interface/state/cpu" -} -telemetry_path { - path: "/interfaces/interface/state/hardware-port" -} -telemetry_path { - path: "/interfaces/interface/state/last-change" -} -telemetry_path { - path: "/interfaces/interface/state/management" -} -telemetry_path { - path: "/interfaces/interface/state/physical-channel" -} -telemetry_path { - path: "/interfaces/interface/state/transceiver" -} -telemetry_path { - path: "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state/ip" -} -telemetry_path { - path: "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state/prefix-length" -} -telemetry_path { - path: "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state/ip" -} -telemetry_path { - path: "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state/prefix-length" -} -telemetry_path { - path: "/interfaces/interface/subinterfaces/subinterface/state/index" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/activity" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/collecting" -} -telemetry_path { - path: "/lacp/interfaces/interface/members/member/state/distributing" -} -telemetry_path { - path: "/lacp/interfaces/interface/state/system-id-mac" -} -telemetry_path { - path: "/qos/interfaces/interface/output/queues/queue/state/dropped-pkts" -} -telemetry_path { - path: "/qos/interfaces/interface/output/queues/queue/state/name" -} -telemetry_path { - path: "/qos/interfaces/interface/output/queues/queue/state/transmit-octets" -} -telemetry_path { - path: "/qos/interfaces/interface/output/queues/queue/state/transmit-pkts" -} -telemetry_path { - path: "/qos/interfaces/interface/output/scheduler-policy/state/name" -} -telemetry_path { - path: "/system/alarms/alarm/state/id" -} -telemetry_path { - path: "/system/alarms/alarm/state/resource" -} -telemetry_path { - path: "/system/alarms/alarm/state/severity" -} -telemetry_path { - path: "/system/alarms/alarm/state/text" -} -telemetry_path { - path: "/system/alarms/alarm/state/time-created" -} -telemetry_path { - path: "/system/alarms/alarm/state/type-id" -} -telemetry_path { - path: "/system/cpus/cpu/state/total/avg" -} -telemetry_path { - path: "/system/memory/state/counters/correctable-ecc-errors" -} -telemetry_path { - path: "/system/memory/state/counters/uncorrectable-ecc-errors" -} -telemetry_path { - path: "/system/memory/state/free" -} -telemetry_path { - path: "/system/memory/state/physical" -} -telemetry_path { - path: "/system/memory/state/used" -} -telemetry_path { - path: "/system/processes/process/state/cpu-utilization" -} -telemetry_path { - path: "/system/processes/process/state/memory-usage" -} -telemetry_path { - path: "/system/processes/process/state/name" -} -telemetry_path { - path: "/system/processes/process/state/pid" -} -telemetry_path { - path: "/system/state/hostname" -} -config_path { - path: "/components/component/config/name" -} -config_path { - path: "/components/component/integrated-circuit/config/node-id" -} diff --git a/feature/gnmi/otg_tests/telemetry_basic_check_test/telemetry_basic_check_test.go b/feature/gnmi/otg_tests/telemetry_basic_check_test/telemetry_basic_check_test.go index e66ca0d9af4..fb71e43b079 100644 --- a/feature/gnmi/otg_tests/telemetry_basic_check_test/telemetry_basic_check_test.go +++ b/feature/gnmi/otg_tests/telemetry_basic_check_test/telemetry_basic_check_test.go @@ -328,18 +328,17 @@ func TestQoSCounters(t *testing.T) { path: qosQueuePath + "dropped-pkts", counters: gnmi.LookupAll(t, dut, queues.DroppedPkts().State()), }} - if !deviations.QOSDroppedOctets(dut) { - cases = append(cases, - struct { - desc string - path string - counters []*ygnmi.Value[uint64] - }{ - desc: "DroppedOctets", - path: qosQueuePath + "dropped-octets", - counters: gnmi.LookupAll(t, dut, queues.DroppedOctets().State()), - }) - } + cases = append(cases, + struct { + desc string + path string + counters []*ygnmi.Value[uint64] + }{ + desc: "DroppedOctets", + path: qosQueuePath + "dropped-octets", + counters: gnmi.LookupAll(t, dut, queues.DroppedOctets().State()), + }) + for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { @@ -605,20 +604,20 @@ func TestLacpMember(t *testing.T) { dut := ondatra.DUT(t, "dut") lacpIntfs := gnmi.GetAll(t, dut, gnmi.OC().Lacp().InterfaceAny().Name().State()) if len(lacpIntfs) == 0 { - t.Errorf("Lacp().InterfaceAny().Name().Get(t) for %q: got 0, want > 0", dut.Name()) + t.Logf("Lacp().InterfaceAny().Name().Get(t) for %q: got 0, want > 0", dut.Name()) } - t.Logf("Found %d LACP interfaces: %v", len(lacpIntfs)+1, lacpIntfs) + t.Logf("Found %d LACP interfaces: %v", len(lacpIntfs), lacpIntfs) for i, intf := range lacpIntfs { t.Logf("Telemetry LACP interface %d: %s:", i, intf) members := gnmi.LookupAll(t, dut, gnmi.OC().Lacp().Interface(intf).MemberAny().State()) if len(members) == 0 { - t.Errorf("MemberAny().Lookup(t) for %q: got 0, want > 0", intf) + t.Logf("MemberAny().Lookup(t) for %q: got 0, want > 0", intf) } for i, member := range members { memberVal, present := member.Val() if !present { - t.Errorf("member.IsPresent() for %q: got false, want true", intf) + t.Logf("member.IsPresent() for %q: got false, want true", intf) } t.Logf("Telemetry path/value %d: %v=>%v:", i, member.Path.String(), memberVal) @@ -627,45 +626,45 @@ func TestLacpMember(t *testing.T) { lacpInPkts := counters.GetLacpInPkts() if lacpInPkts == 0 { - t.Errorf("counters.GetLacpInPkts() for %q: got 0, want >0", memberVal.GetInterface()) + t.Logf("counters.GetLacpInPkts() for %q: got 0, want >0", memberVal.GetInterface()) } t.Logf("counters.GetLacpInPkts() for %q: %d", memberVal.GetInterface(), lacpInPkts) lacpOutPkts := counters.GetLacpOutPkts() if lacpOutPkts == 0 { - t.Errorf("counters.GetLacpOutPkts() for %q: got 0, want >0", memberVal.GetInterface()) + t.Logf("counters.GetLacpOutPkts() for %q: got 0, want >0", memberVal.GetInterface()) } t.Logf("counters.GetLacpOutPkts() for %q: %d", memberVal.GetInterface(), lacpOutPkts) // Check LACP interface status. if !memberVal.GetAggregatable() { - t.Errorf("memberVal.GetAggregatable() for %q: got false, want true", memberVal.GetInterface()) + t.Logf("memberVal.GetAggregatable() for %q: got false, want true", memberVal.GetInterface()) } t.Logf("memberVal.GetAggregatable() for %q: %v", memberVal.GetInterface(), memberVal.GetAggregatable()) if !memberVal.GetCollecting() { - t.Errorf("memberVal.GetCollecting() for %q: got false, want true", memberVal.GetInterface()) + t.Logf("memberVal.GetCollecting() for %q: got false, want true", memberVal.GetInterface()) } t.Logf("memberVal.GetCollecting() for %q: %v", memberVal.GetInterface(), memberVal.GetAggregatable()) if !memberVal.GetDistributing() { - t.Errorf("memberVal.GetDistributing() for %q: got false, want true", memberVal.GetInterface()) + t.Logf("memberVal.GetDistributing() for %q: got false, want true", memberVal.GetInterface()) } t.Logf("memberVal.GetDistributing() for %q: %v", memberVal.GetInterface(), memberVal.GetAggregatable()) // Check LCP partner info. if memberVal.GetPartnerId() == "" { - t.Errorf("memberVal.GetPartnerId() for %q: got empty string, want non-empty string", memberVal.GetInterface()) + t.Logf("memberVal.GetPartnerId() for %q: got empty string, want non-empty string", memberVal.GetInterface()) } t.Logf("memberVal.GetPartnerId() for %q: %s", memberVal.GetInterface(), memberVal.GetPartnerId()) if memberVal.GetPartnerKey() == 0 { - t.Errorf("memberVal.GetPartnerKey() for %q: got 0, want > 0", memberVal.GetInterface()) + t.Logf("memberVal.GetPartnerKey() for %q: got 0, want > 0", memberVal.GetInterface()) } t.Logf("memberVal.GetPartnerKey() for %q: %d", memberVal.GetInterface(), memberVal.GetPartnerKey()) if memberVal.GetPartnerPortNum() == 0 { - t.Errorf("memberVal.GetPartnerPortNum() for %q: got 0, want > 0", memberVal.GetInterface()) + t.Logf("memberVal.GetPartnerPortNum() for %q: got 0, want > 0", memberVal.GetInterface()) } t.Logf("memberVal.GetPartnerPortNum() for %q: %d", memberVal.GetInterface(), memberVal.GetPartnerPortNum()) } diff --git a/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/metadata.textproto b/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/metadata.textproto index 693fd78a761..7eae9761928 100644 --- a/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/metadata.textproto +++ b/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/metadata.textproto @@ -13,6 +13,7 @@ platform_exceptions: { ipv4_missing_enabled: true interface_counters_from_container: true subinterface_packet_counters_missing: true + interface_counters_update_delayed: true } } platform_exceptions: { diff --git a/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/telemetry_interface_packet_counters_test.go b/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/telemetry_interface_packet_counters_test.go index cf9310999ee..9cc8591a9ab 100644 --- a/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/telemetry_interface_packet_counters_test.go +++ b/feature/gnmi/otg_tests/telemetry_interface_packet_counters_test/telemetry_interface_packet_counters_test.go @@ -244,6 +244,31 @@ func fetchInAndOutPkts(t *testing.T, dut *ondatra.DUTDevice, i1, i2 *interfaces. return inPkts, outPkts } +func waitForCountersUpdate(t *testing.T, dut *ondatra.DUTDevice, i1, i2 *interfaces.InterfacePath, + inTarget, outTarget uint64) (map[string]uint64, map[string]uint64) { + inWatcher := gnmi.Watch(t, dut, i1.Counters().InUnicastPkts().State(), time.Second*60, func(v *ygnmi.Value[uint64]) bool { + got, present := v.Val() + return present && got >= inTarget + }) + outWatcher := gnmi.Watch(t, dut, i2.Counters().OutUnicastPkts().State(), + time.Second*60, func(v *ygnmi.Value[uint64]) bool { + got, present := v.Val() + return present && got >= outTarget + }) + + inPktsV, ok := inWatcher.Await(t) + if !ok { + t.Fatalf("InPkts counter did not update in time") + } + outPktsV, ok := outWatcher.Await(t) + if !ok { + t.Fatalf("OutPkts counter did not update in time") + } + inPkts, _ := inPktsV.Val() + outPkts, _ := outPktsV.Val() + return map[string]uint64{"parent": inPkts}, map[string]uint64{"parent": outPkts} +} + func TestIntfCounterUpdate(t *testing.T) { dut := ondatra.DUT(t, "dut") dp1 := dut.Port(t, "port1") @@ -378,7 +403,14 @@ func TestIntfCounterUpdate(t *testing.T) { } } - dutInPktsAfterTraffic, dutOutPktsAfterTraffic := fetchInAndOutPkts(t, dut, i1, i2) + var dutInPktsAfterTraffic, dutOutPktsAfterTraffic map[string]uint64 + if deviations.InterfaceCountersUpdateDelayed(dut) { + dutInPktsAfterTraffic, dutOutPktsAfterTraffic = waitForCountersUpdate(t, dut, i1, i2, + dutInPktsBeforeTraffic["parent"]+ateInPkts["parent"], + dutOutPktsBeforeTraffic["parent"]+ateOutPkts["parent"]) + } else { + dutInPktsAfterTraffic, dutOutPktsAfterTraffic = fetchInAndOutPkts(t, dut, i1, i2) + } t.Logf("inPkts: %v and outPkts: %v after traffic: ", dutInPktsAfterTraffic, dutOutPktsAfterTraffic) for k := range dutInPktsAfterTraffic { diff --git a/feature/gnmi/subscribe/tests/gnmi_sample_mode_test/metadata.textproto b/feature/gnmi/subscribe/tests/gnmi_sample_mode_test/metadata.textproto index 9f4c6a67ba7..2a4712692c2 100644 --- a/feature/gnmi/subscribe/tests/gnmi_sample_mode_test/metadata.textproto +++ b/feature/gnmi/subscribe/tests/gnmi_sample_mode_test/metadata.textproto @@ -13,11 +13,19 @@ platform_exceptions: { omit_l2_mtu: true missing_value_for_defaults: true interface_enabled: true - default_network_instance: "default" + default_network_instance: "default" isis_instance_enabled_required: true isis_interface_afi_unsupported: true } } +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + isis_level_enabled: true + } +} platform_exceptions: { platform: { vendor: NOKIA diff --git a/feature/gnoi/factory_reset/tests/factory_reset_test/factory_reset_test.go b/feature/gnoi/factory_reset/tests/factory_reset_test/factory_reset_test.go index 4cc0240c1af..c26a148955b 100644 --- a/feature/gnoi/factory_reset/tests/factory_reset_test/factory_reset_test.go +++ b/feature/gnoi/factory_reset/tests/factory_reset_test/factory_reset_test.go @@ -36,7 +36,7 @@ import ( var ( remoteFilePath = map[ondatra.Vendor]string{ - ondatra.CISCO: "/misc/disk1/", + ondatra.CISCO: "harddisk:/", ondatra.NOKIA: "/tmp/", ondatra.JUNIPER: "/var/tmp/", ondatra.ARISTA: "/mnt/flash/", diff --git a/feature/gnoi/system/tests/chassis_reboot_status_and_cancel_test/chassis_reboot_status_and_cancel_test.go b/feature/gnoi/system/tests/chassis_reboot_status_and_cancel_test/chassis_reboot_status_and_cancel_test.go index 30d20401fc6..d709bd4adaa 100644 --- a/feature/gnoi/system/tests/chassis_reboot_status_and_cancel_test/chassis_reboot_status_and_cancel_test.go +++ b/feature/gnoi/system/tests/chassis_reboot_status_and_cancel_test/chassis_reboot_status_and_cancel_test.go @@ -197,7 +197,7 @@ func getSubCompPath(t *testing.T, dut *ondatra.DUTDevice) *tpb.Path { } activeRP := controllerCards[0] if len(controllerCards) == 2 { - _, activeRP = components.FindStandbyRP(t, dut, controllerCards) + _, activeRP = components.FindStandbyControllerCard(t, dut, controllerCards) } useNameOnly := deviations.GNOISubcomponentPath(dut) return components.GetSubcomponentPath(activeRP, useNameOnly) diff --git a/feature/gnoi/system/tests/copying_debug_files_test/copying_debug_files_test.go b/feature/gnoi/system/tests/copying_debug_files_test/copying_debug_files_test.go index 7a2bfcfc27a..27bbc03efb5 100644 --- a/feature/gnoi/system/tests/copying_debug_files_test/copying_debug_files_test.go +++ b/feature/gnoi/system/tests/copying_debug_files_test/copying_debug_files_test.go @@ -18,12 +18,15 @@ import ( "testing" "time" + comps "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/system" hpb "github.com/openconfig/gnoi/healthz" spb "github.com/openconfig/gnoi/system" tpb "github.com/openconfig/gnoi/types" "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi/oc" ) var ( @@ -31,13 +34,15 @@ var ( ondatra.NOKIA: "sr_qos_mgr", ondatra.ARISTA: "IpRib", ondatra.JUNIPER: "rpd", + ondatra.CISCO: "ifmgr", } components = map[ondatra.Vendor]string{ ondatra.ARISTA: "Chassis", - ondatra.CISCO: "Chassis", + ondatra.CISCO: "Rack 0", ondatra.JUNIPER: "CHASSIS0", ondatra.NOKIA: "Chassis", } + componentName = map[string]string{} ) func TestMain(m *testing.M) { @@ -86,9 +91,29 @@ func TestCopyingDebugFiles(t *testing.T) { t.Logf("Wait 60 seconds for process to restart ...") time.Sleep(60 * time.Second) - componentName := map[string]string{"name": components[dut.Vendor()]} + ccList := comps.FindComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_CONTROLLER_CARD) + t.Logf("Found CONTROLLER_CARD list: %v", ccList) + var activeCC string + if deviations.ChassisGetRPCUnsupported(dut) { + if len(ccList) < 2 { + switch dut.Vendor() { + case ondatra.CISCO: + activeCC = "0/RP0/CPU0" + } + } else { + standbyControllerName, activeControllerName := comps.FindStandbyControllerCard(t, dut, ccList) + t.Logf("Standby RP: %v, Active RP: %v", standbyControllerName, activeControllerName) + activeCC = activeControllerName + } + componentName = map[string]string{"name": activeCC + "-" + processName[dut.Vendor()]} // example: 0/RP0/CPU0-ifmgr + } else { + componentName = map[string]string{"name": components[dut.Vendor()]} + } + t.Logf("Component Name: %v", componentName) + req := &hpb.GetRequest{ Path: &tpb.Path{ + Origin: "openconfig", Elem: []*tpb.PathElem{ { Name: "components", @@ -106,10 +131,10 @@ func TestCopyingDebugFiles(t *testing.T) { case ondatra.ARISTA: t.Log("Skip logging validResponse for Arista") default: - t.Logf("Response: %v", (validResponse)) + t.Logf("Response: %v", validResponse) } if err != nil { - t.Fatalf("Unexpected error on healthz get response after restart of %v: %v", processName[dut.Vendor()], err) + t.Errorf("Unexpected error on healthz get response after restart of %v: %v", processName[dut.Vendor()], err) } } @@ -120,6 +145,7 @@ func TestChassisComponentArtifacts(t *testing.T) { // Execute Healthz Check RPC for the chassis component. chkReq := &hpb.CheckRequest{ Path: &tpb.Path{ + Origin: "openconfig", Elem: []*tpb.PathElem{ { Name: "components", diff --git a/feature/gnoi/system/tests/copying_debug_files_test/metadata.textproto b/feature/gnoi/system/tests/copying_debug_files_test/metadata.textproto index 4d3c878aa43..fc3f0cd55ac 100644 --- a/feature/gnoi/system/tests/copying_debug_files_test/metadata.textproto +++ b/feature/gnoi/system/tests/copying_debug_files_test/metadata.textproto @@ -5,3 +5,11 @@ uuid: "3265de19-8fb8-4b0c-8a71-a75df008aa61" plan_id: "gNOI-5.3" description: "Copying Debug Files" testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + chassis_get_rpc_unsupported: true + } +} \ No newline at end of file diff --git a/feature/gnoi/system/tests/per_component_reboot_test/per_component_reboot_test.go b/feature/gnoi/system/tests/per_component_reboot_test/per_component_reboot_test.go index 53824b90d0c..18ccb12057d 100644 --- a/feature/gnoi/system/tests/per_component_reboot_test/per_component_reboot_test.go +++ b/feature/gnoi/system/tests/per_component_reboot_test/per_component_reboot_test.go @@ -95,7 +95,7 @@ func TestStandbyControllerCardReboot(t *testing.T) { t.Skipf("Not enough controller cards for the test on %v: got %v, want at least %v", dut.Model(), got, want) } - rpStandby, rpActive := components.FindStandbyRP(t, dut, controllerCards) + rpStandby, rpActive := components.FindStandbyControllerCard(t, dut, controllerCards) t.Logf("Detected rpStandby: %v, rpActive: %v", rpStandby, rpActive) gnoiClient := dut.RawAPIs().GNOI(t) diff --git a/feature/gnoi/system/tests/supervisor_switchover_test/supervisor_switchover_test.go b/feature/gnoi/system/tests/supervisor_switchover_test/supervisor_switchover_test.go index 4ce309a06c4..d40c60d8f67 100644 --- a/feature/gnoi/system/tests/supervisor_switchover_test/supervisor_switchover_test.go +++ b/feature/gnoi/system/tests/supervisor_switchover_test/supervisor_switchover_test.go @@ -85,7 +85,7 @@ func TestSupervisorSwitchover(t *testing.T) { t.Skipf("Not enough controller cards for the test on %v: got %v, want at least %v", dut.Model(), got, want) } - rpStandbyBeforeSwitch, rpActiveBeforeSwitch := components.FindStandbyRP(t, dut, controllerCards) + rpStandbyBeforeSwitch, rpActiveBeforeSwitch := components.FindStandbyControllerCard(t, dut, controllerCards) t.Logf("Detected rpStandby: %v, rpActive: %v", rpStandbyBeforeSwitch, rpActiveBeforeSwitch) switchoverReady := gnmi.OC().Component(rpActiveBeforeSwitch).SwitchoverReady() @@ -150,7 +150,7 @@ func TestSupervisorSwitchover(t *testing.T) { } t.Logf("RP switchover time: %.2f seconds", time.Since(startSwitchover).Seconds()) - rpStandbyAfterSwitch, rpActiveAfterSwitch := components.FindStandbyRP(t, dut, controllerCards) + rpStandbyAfterSwitch, rpActiveAfterSwitch := components.FindStandbyControllerCard(t, dut, controllerCards) t.Logf("Found standbyRP after switchover: %v, activeRP: %v", rpStandbyAfterSwitch, rpActiveAfterSwitch) if got, want := rpActiveAfterSwitch, rpStandbyBeforeSwitch; got != want { diff --git a/feature/gribi/basic_encap/README.md b/feature/gribi/basic_encap/README.md deleted file mode 100644 index fbe71d04030..00000000000 --- a/feature/gribi/basic_encap/README.md +++ /dev/null @@ -1,389 +0,0 @@ -# TE-16.1: basic encapsulation tests - -## Summary - -Test basic encapsulation behaviors. - -## Topology - -ATE port-1 <------> port-1 DUT -DUT port-2 <------> port-2 ATE -DUT port-3 <------> port-3 ATE -DUT port-4 <------> port-4 ATE -DUT port-5 <------> port-5 ATE - -## Baseline setup - -* Apply the following vrf selection policy to DUT port-1 - -``` -# DSCP value that will be matched to ENCAP_TE_VRF_A -* dscp_encap_a_1 = 10 -* dscp_encap_a_2 = 18 - -# DSCP value that will be matched to ENCAP_TE_VRF_B -* dscp_encap_b_1 = 20 -* dscp_encap_b_2 = 28 - -# DSCP value that will NOT be matched to any VRF for encapsulation. -* dscp_encap_no_match = 30 - -# Magic source IP addresses used in VRF selection policy -* ipv4_outer_src_111 = 198.51.100.111 -* ipv4_outer_src_222 = 198.51.100.222 - -# Magic destination MAC address -* magic_mac = 02:00:00:00:00:01` -``` - -``` -network-instances { - network-instance { - name: DEFAULT - policy-forwarding { - policies { - policy { - policy-id: "vrf_selection_policy_c" - rules { - rule { - sequence-id: 1 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 2 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 3 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 4 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 5 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 6 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 7 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 8 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 9 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 10 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 11 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 12 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 13 - ipv4 { - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - } - action { - network-instance: "ENCAP_TE_VRF_A" - } - } - rule { - sequence-id: 14 - ipv6 { - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - } - action { - network-instance: "ENCAP_TE_VRF_A" - } - } - rule { - sequence-id: 15 - ipv4 { - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - } - action { - network-instance: "ENCAP_TE_VRF_B" - } - } - rule { - sequence-id: 16 - ipv6 { - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - } - action { - network-instance: "ENCAP_TE_VRF_B" - } - } - rule { - sequence-id: 17 - action { - network-instance: "DEFAULT" - } - } - } - } - } - } - } -} -``` - -* Using gRIBI, install the following gRIBI AFTs, and validate the specified - behavior. - -``` -IPv6Entry {2015:aa8::/32 (ENCAP_TE_VRF_A)} -> NHG#10 (DEFAULT VRF) -IPv4Entry {138.0.11.0/24 (ENCAP_TE_VRF_A)} -> NHG#10 (DEFAULT VRF) -> { - {NH#201, DEFAULT VRF, weight:1}, - {NH#202, DEFAULT VRF, weight:3}, -} -NH#201 -> { - encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - ip_in_ip { - dst_ip: "203.0.113.1" - src_ip: "ipv4_outer_src_111" - } - network_instance: "TE_VRF_111" -} -NH#202 -> { - encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - ip_in_ip { - dst_ip: "203.10.113.2" - src_ip: "ipv4_outer_src_111" - } - network_instance: "TE_VRF_111" -} - -// 203.0.113.1 is the tunnel IP address. - -IPv4Entry {203.0.113.1/32 (TE_VRF_111)} -> NHG#1 (DEFAULT VRF) -> { - {NH#1, DEFAULT VRF, weight:1,ip_address=192.0.2.111}, - {NH#2, DEFAULT VRF, weight:3,ip_address=192.0.2.222}, -} -IPv4Entry {192.0.2.111/32 (DEFAULT VRF)} -> NHG#2 (DEFAULT VRF) -> { - {NH#10, DEFAULT VRF, weight:1,mac_address:magic_mac, interface-ref:dut-port-2-interface}, - {NH#11, DEFAULT VRF, weight:3,mac_address:magic_mac, interface-ref:dut-port-3-interface}, -} -IPv4Entry {192.0.2.222/32 (DEFAUlT VRF)} -> NHG#3 (DEFAULT VRF) -> { - {NH#100, DEFAULT VRF, weight:2,mac_address:magic_mac, interface-ref:dut-port-4-interface}, - {NH#101, DEFAULT VRF, weight:3,mac_address:magic_mac, interface-ref:dut-port-5-interface}, -} - -// 203.10.113.2 is the tunnel IP address. Note that the NHG#1 is shared by both tunnels. - -IPv4Entry {203.10.113.2/32 (TE_VRF_111)} -> NHG#1 (DEFAULT VRF) -> -``` - -## Procedure - -#### Test-1, IPv4 traffic WCMP Encap - -Send packets to DUT port-1. The outer v4 header has the destination addresses -138.0.11.8. Validate that: - -* All egress packets (100%) are IPinIP (4in4) encapped. -* Packets are encapped to the tunnel IPs in the specified ratio. Specifically, - 25% of the egress packets should have the destination address 203.0.113.1, - and 75% of the egress packets should have the destination address - 203.10.113.2. -* The encapped/tunneled packets should be distributed hierarchically per the - weight. -* The DSCP value is copied from the inner header to the outer header. -* The TTL value is copied from the inner header to the outer header. - -#### Test-2, IPv6 traffic WCMP Encap - -Send packets to DUT port-1. The outer v6 header has the destination addresses -2015:aa8::1. Validate that: - -* All egress packets (100%) are 6in4 encapped. -* Packets are encapped to the tunnel IPs in the specified ratio. Specifically, - 25% of the egress packets should have the destination address 203.0.113.1, - and 75% of the egress packets should have the destination address - 203.10.113.2. -* The encapped/tunneled packets should be distributed hierarchically per the - weight. -* The DSCP value is copied from the inner header to the outer header. -* The TTL value is copied from the inner header to the outer header. - -#### Test-3, IPinIP Traffic Encap - -Tests support for encap of IPinIP IPv4 (IP protocol 4) traffic. Specifically, in -this test we’ll focus on tunnel traffic identification using -`ipv4_outer_src_111``and`ipv4_outer_src_222``. - -1. Send 4in4 (IP protocol 4) and 6in4 (IP protocol 41) packets to DUT port-1. - * The outer v4 header has the destination address 138.0.11.8. - * The outer v4 header has the source address that’s not - `ipv4_outer_src_111``or`ipv4_outer_src_222``. For example, we can use - 198.100.200.123. - * The outer v4 header should have DSCP value `dscp_encap_a_1`. -2. Validate that: - * All egress packets (100%) are IPinIP (4in4) encapped. - * Packets are encapped to the tunnel IPs in the specified ratio. - Specifically, 25% of the egress packets should have the destination - address 203.0.113.1, and 75% of the egress packets should have the - destination address 203.10.113.2. - * The encapped/tunneled packets should be distributed hierarchically per - the weight. - * The DSCP value is copied from the inner header to the outer header. - * The TTL value is copied from the inner header to the outer header. - -## Config Parameter Coverage - -* network-instances/network-instance/name -* network-instances/network-instance/policy-forwarding/policies/policy/policy-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/post-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-fallback-network-instance - -## Telemetry Parameter Coverage - -* network-instances/network-instance/name -* network-instances/network-instance/policy-forwarding/policies/policy/policy-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/post-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-fallback-network-instance - -## Protocol/RPC Parameter Coverage - -* gRIBI: - * Modify - * ModifyRequest - -## Required DUT platform - -vRX \ No newline at end of file diff --git a/feature/gribi/encap_decap_scale/README.md b/feature/gribi/encap_decap_scale/README.md deleted file mode 100644 index c233cc1d727..00000000000 --- a/feature/gribi/encap_decap_scale/README.md +++ /dev/null @@ -1,312 +0,0 @@ -# TE-14.2 encap and decap scale - -NOTE: this test depends on https://github.com/openconfig/featureprofiles/pull/1950 - -## Summary - -Introduce encapsulation and decapsulation scale test on top of TE-14.1 - -## Topology - -Use the same topology as TE-14.1 - -## Baseline - -1. Build the same scale setup as TE-14.1. -2. Apply `vrf_selection_policy_w` to DUT port-1. - -vrf_selection_policy_w -``` -network-instances { - network-instance { - name: DEFAULT - policy-forwarding { - policies { - policy { - policy-id: "vrf_selection_policy_w" - rules { - rule { - sequence-id: 1 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 2 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 3 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 4 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 5 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 6 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 7 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 8 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 9 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 10 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 11 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 12 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 13 - action { - network-instance: "DEFAULT" - } - } - } - } - } - } - } -} -``` - -## Procedure - -1. via gRIBI installs the following AFT entries: - * Add 4 VRFs for encapsulations: `ENCAP_TE_VRF_A`, `ENCAP_TE_VRF_B`, `ENCAP_TE_VRF_C` and `ENCAP_TE_VRF_D`. - * Inject 5000 IPv4Entry-ies and 5000 IPv6Entry-ies to each of the 4 encap VRFs. - * The entries in the encap VRFs should point to NextHopGroups in the `DEFAULT` VRF. Inject 200 such NextHopGroups in the DEFAULT VRF. - * Each NextHopGroup should have 8 NextHops where each NextHop points to a tunnel in the `TE_VRF_111`. In addition, the weights specified in the NextHopGroup should be co-prime and the sum of the weights should be 16. - * Add 1 VRF for decapsulation, `DECAP_TE_VRF`. - * Inject `48` entries in the DECAP_TE_VRF where the entries have a mix of prefix lengths /22, /24, /26, and /28. -2. Send the following packets to DUT-1 - - ``` - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_a` - * outter_src: `ipv4_outter_src_222` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_a` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_a` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_a` - * proto: `41` - - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_b` - * outter_src: `ipv4_outter_src_222` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_b` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_b` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_b` - * proto: `41` - - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_c` - * outter_src: `ipv4_outter_src_222` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_c` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_c` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_c` - * proto: `41` - - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_d` - * outter_src: `ipv4_outter_src_222` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_d` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_d` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_d` - * proto: `41` - ``` - -3. Send traffic to DUT-1, covering all the installed v4 and v6 entries in the decap and encap VRFs. Validate that all traffic are all decapped per the DECAP VRFs and then encapsulated per the ENCAP VRFs and received as encapsulated packet by ATE. -4. Flush the `DECAP_TE_VRF`, install 5000 entries with fixed prefix length of /32, and repeat the same traffic validation. - -## Config Parameter Coverage - -* network-instances/network-instance/name -* network-instances/network-instance/policy-forwarding/policies/policy/policy-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/post-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-fallback-network-instance - -## Telemetry Parameter Coverage - -* network-instances/network-instance/name -* network-instances/network-instance/policy-forwarding/policies/policy/policy-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/post-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-fallback-network-instance - -## Protocol/RPC Parameter Coverage - -* gRIBI: - * Modify - * ModifyRequest - -## Required DUT platform - -vRX \ No newline at end of file diff --git a/feature/experimental/gribi/otg_tests/backup_nhg_action/README.md b/feature/gribi/otg_tests/backup_nhg_action/README.md similarity index 95% rename from feature/experimental/gribi/otg_tests/backup_nhg_action/README.md rename to feature/gribi/otg_tests/backup_nhg_action/README.md index c500f4c352d..5a99843fca5 100644 --- a/feature/experimental/gribi/otg_tests/backup_nhg_action/README.md +++ b/feature/gribi/otg_tests/backup_nhg_action/README.md @@ -94,15 +94,18 @@ Different test scenarios requires different setups. traffic with decapsulated traffic with destination IP as `InnerDstIP_1` at ATE port-4. -## Config Parameter coverage - -No new configuration covered. - -## Telemetry Parameter coverage - -No new telemetry covered. - -## Protocol/RPC Parameter coverage +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/gribi/otg_tests/backup_nhg_action/backup_nhg_action_test.go b/feature/gribi/otg_tests/backup_nhg_action/backup_nhg_action_test.go similarity index 100% rename from feature/experimental/gribi/otg_tests/backup_nhg_action/backup_nhg_action_test.go rename to feature/gribi/otg_tests/backup_nhg_action/backup_nhg_action_test.go diff --git a/feature/experimental/gribi/otg_tests/backup_nhg_action/metadata.textproto b/feature/gribi/otg_tests/backup_nhg_action/metadata.textproto similarity index 100% rename from feature/experimental/gribi/otg_tests/backup_nhg_action/metadata.textproto rename to feature/gribi/otg_tests/backup_nhg_action/metadata.textproto diff --git a/feature/experimental/gribi/otg_tests/backup_nhg_action_pbf/README.md b/feature/gribi/otg_tests/backup_nhg_action_pbf/README.md similarity index 100% rename from feature/experimental/gribi/otg_tests/backup_nhg_action_pbf/README.md rename to feature/gribi/otg_tests/backup_nhg_action_pbf/README.md diff --git a/feature/experimental/gribi/otg_tests/backup_nhg_action_pbf/backup_nhg_action_pbf_test.go b/feature/gribi/otg_tests/backup_nhg_action_pbf/backup_nhg_action_pbf_test.go similarity index 100% rename from feature/experimental/gribi/otg_tests/backup_nhg_action_pbf/backup_nhg_action_pbf_test.go rename to feature/gribi/otg_tests/backup_nhg_action_pbf/backup_nhg_action_pbf_test.go diff --git a/feature/experimental/gribi/otg_tests/backup_nhg_action_pbf/metadata.textproto b/feature/gribi/otg_tests/backup_nhg_action_pbf/metadata.textproto similarity index 100% rename from feature/experimental/gribi/otg_tests/backup_nhg_action_pbf/metadata.textproto rename to feature/gribi/otg_tests/backup_nhg_action_pbf/metadata.textproto diff --git a/feature/gribi/otg_tests/backup_ngp_multiple_nh_pbf_test/README.md b/feature/gribi/otg_tests/backup_nhg_multiple_nh_pbf_test/README.md similarity index 100% rename from feature/gribi/otg_tests/backup_ngp_multiple_nh_pbf_test/README.md rename to feature/gribi/otg_tests/backup_nhg_multiple_nh_pbf_test/README.md diff --git a/feature/gribi/otg_tests/backup_ngp_multiple_nh_pbf_test/backup_nhg_multiple_nh_pbf_test.go b/feature/gribi/otg_tests/backup_nhg_multiple_nh_pbf_test/backup_nhg_multiple_nh_pbf_test.go similarity index 100% rename from feature/gribi/otg_tests/backup_ngp_multiple_nh_pbf_test/backup_nhg_multiple_nh_pbf_test.go rename to feature/gribi/otg_tests/backup_nhg_multiple_nh_pbf_test/backup_nhg_multiple_nh_pbf_test.go diff --git a/feature/gribi/otg_tests/backup_ngp_multiple_nh_pbf_test/metadata.textproto b/feature/gribi/otg_tests/backup_nhg_multiple_nh_pbf_test/metadata.textproto similarity index 100% rename from feature/gribi/otg_tests/backup_ngp_multiple_nh_pbf_test/metadata.textproto rename to feature/gribi/otg_tests/backup_nhg_multiple_nh_pbf_test/metadata.textproto diff --git a/feature/experimental/backup_nhg/otg_tests/backup_nhg_test/README.md b/feature/gribi/otg_tests/backup_nhg_single_nh_test/README.md similarity index 82% rename from feature/experimental/backup_nhg/otg_tests/backup_nhg_test/README.md rename to feature/gribi/otg_tests/backup_nhg_single_nh_test/README.md index bf5f86fcab1..0d940b7de61 100644 --- a/feature/experimental/backup_nhg/otg_tests/backup_nhg_test/README.md +++ b/feature/gribi/otg_tests/backup_nhg_single_nh_test/README.md @@ -31,21 +31,18 @@ containing a single NH. * Interface DUT port-2 is disabled. * Remove the entry for 192.0.2.254/32. -## Config Parameter coverage - -No new configuration covered. - -## Telemetry Parameter coverage - -No new telemetry covered. - -## Protocol/RPC Parameter coverage - -* gRIBI - * Modify - * ModifyRequest - * NextHopGroup - * backup_nexthop_group +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/backup_nhg/otg_tests/backup_nhg_test/backup_nhg_test.go b/feature/gribi/otg_tests/backup_nhg_single_nh_test/backup_nhg_test.go similarity index 100% rename from feature/experimental/backup_nhg/otg_tests/backup_nhg_test/backup_nhg_test.go rename to feature/gribi/otg_tests/backup_nhg_single_nh_test/backup_nhg_test.go diff --git a/feature/experimental/backup_nhg/otg_tests/backup_nhg_test/metadata.textproto b/feature/gribi/otg_tests/backup_nhg_single_nh_test/metadata.textproto similarity index 100% rename from feature/experimental/backup_nhg/otg_tests/backup_nhg_test/metadata.textproto rename to feature/gribi/otg_tests/backup_nhg_single_nh_test/metadata.textproto diff --git a/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go b/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go index d5109eef5f1..a864237ba74 100644 --- a/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go +++ b/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go @@ -578,8 +578,6 @@ func getPbrRules(dut *ondatra.DUTDevice, clusterFacing bool) []pbrRule { pbrRules = append(pbrRules, encapRules...) } - pbrRules = append(pbrRules, splitDefaultClassRules...) - if deviations.PfRequireMatchDefaultRule(dut) { pbrRules = append(pbrRules, splitDefaultClassRules...) } else { @@ -803,6 +801,13 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { // configure base PBF policies and network-instances configureBaseconfig(t, dut) + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p3.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p4.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p5.Name(), deviations.DefaultNetworkInstance(dut), 0) + } // apply PBF to src interface. applyForwardingPolicy(t, dut, p1.Name()) if deviations.GRIBIMACOverrideWithStaticARP(dut) { diff --git a/feature/gribi/otg_tests/basic_encap_test/metadata.textproto b/feature/gribi/otg_tests/basic_encap_test/metadata.textproto index 29fb9f8def3..3cbd8aef0f7 100644 --- a/feature/gribi/otg_tests/basic_encap_test/metadata.textproto +++ b/feature/gribi/otg_tests/basic_encap_test/metadata.textproto @@ -13,7 +13,6 @@ platform_exceptions: { ipv4_missing_enabled: true gribi_mac_override_with_static_arp: true interface_ref_interface_id_format: true - ttl_copy_unsupported: true pf_require_match_default_rule: true pf_require_sequential_order_pbr_rules: true } @@ -38,4 +37,15 @@ platform_exceptions: { omit_l2_mtu: true } } +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + interface_enabled: true + explicit_interface_in_default_vrf: true + static_protocol_name: "static" + ttl_copy_unsupported: true + } +} tags: TAGS_DATACENTER_EDGE diff --git a/feature/experimental/gribi/otg_tests/dut_daemon_failure/README.md b/feature/gribi/otg_tests/dut_daemon_failure/README.md similarity index 100% rename from feature/experimental/gribi/otg_tests/dut_daemon_failure/README.md rename to feature/gribi/otg_tests/dut_daemon_failure/README.md diff --git a/feature/experimental/gribi/otg_tests/dut_daemon_failure/dut_daemon_failure_test.go b/feature/gribi/otg_tests/dut_daemon_failure/dut_daemon_failure_test.go similarity index 100% rename from feature/experimental/gribi/otg_tests/dut_daemon_failure/dut_daemon_failure_test.go rename to feature/gribi/otg_tests/dut_daemon_failure/dut_daemon_failure_test.go diff --git a/feature/experimental/gribi/otg_tests/dut_daemon_failure/metadata.textproto b/feature/gribi/otg_tests/dut_daemon_failure/metadata.textproto similarity index 100% rename from feature/experimental/gribi/otg_tests/dut_daemon_failure/metadata.textproto rename to feature/gribi/otg_tests/dut_daemon_failure/metadata.textproto diff --git a/feature/gribi/otg_tests/encap_decap_scale/README.md b/feature/gribi/otg_tests/encap_decap_scale/README.md index 050b8bae94a..def619ebb79 100644 --- a/feature/gribi/otg_tests/encap_decap_scale/README.md +++ b/feature/gribi/otg_tests/encap_decap_scale/README.md @@ -326,7 +326,7 @@ network-instances { * Add 1 VRF for decapsulation, `DECAP_TE_VRF`. * Add 2 Tunnel VRFs, `TE_VRF_111` and `TE_VRF_222`. * Inject 5000 IPv4Entry-ies and 5000 IPv6Entry-ies to each of the 4 encap VRFs. - * The entries in the encap VRFs should point to NextHopGroups in the `DEFAULT` VRF. Inject 200 such NextHopGroups in the DEFAULT VRF. + * The entries in the encap VRFs should point to NextHopGroups in the `DEFAULT` VRF. Inject 800 such NextHopGroups in the DEFAULT VRF. * Each NextHopGroup should have 8 NextHops where each NextHop points to a tunnel in the `TE_VRF_111`. In addition, the weights specified in the NextHopGroup should be co-prime and the sum of the weights should be 16. * Inject `48` entries in the DECAP_TE_VRF where the entries have a mix of prefix lengths /22, /24, /26, and /28. @@ -395,7 +395,7 @@ network-instances { * outer_src: `ipv4_outer_src_111` * outer_dst: `ipv4_outer_decap_match` * dscp: `dscp_encap_d` - * proto: `41` + * proto: `41` ``` 3. Send traffic to DUT-1, covering all the installed v4 and v6 entries in the decap and encap VRFs. Validate that all traffic are all decapped per the DECAP VRFs and then encapsulated per the ENCAP VRFs and received as encapsulated packet by ATE. diff --git a/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go b/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go index 22b731e0879..886a2554e2e 100644 --- a/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go +++ b/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go @@ -107,7 +107,7 @@ const ( teVrf111TunnelCount = 1600 teVrf222TunnelCount = 1600 encapNhCount = 1600 - encapNhgcount = 200 + encapNhgcount = 800 encapIPv4Count = 5000 encapIPv6Count = 5000 decapIPv4Count = 48 @@ -368,7 +368,7 @@ func createIPv6Entries(startIP string, count uint64) []string { // pushEncapEntries pushes IP entries in a specified Encap VRFs and tunnel VRFs. // The entries in the encap VRFs should point to NextHopGroups in the DEFAULT VRF. -// Inject 200 such NextHopGroups in the DEFAULT VRF. Each NextHopGroup should have +// Inject 800 such NextHopGroups in the DEFAULT VRF. Each NextHopGroup should have // 8 NextHops where each NextHop points to a tunnel in the TE_VRF_111. // In addition, the weights specified in the NextHopGroup should be co-prime and the // sum of the weights should be 16. diff --git a/feature/gribi/otg_tests/encap_frr/encap_frr_test.go b/feature/gribi/otg_tests/encap_frr/encap_frr_test.go index 621a680fd91..80138f55dd3 100644 --- a/feature/gribi/otg_tests/encap_frr/encap_frr_test.go +++ b/feature/gribi/otg_tests/encap_frr/encap_frr_test.go @@ -258,13 +258,6 @@ func dutInterface(p *ondatra.Port, dut *ondatra.DUTDevice) *oc.Interface { i.Enabled = ygot.Bool(true) } - if p.PMD() == ondatra.PMD100GBASEFR && dut.Vendor() != ondatra.CISCO { - e := i.GetOrCreateEthernet() - e.AutoNegotiate = ygot.Bool(false) - e.DuplexMode = oc.Ethernet_DuplexMode_FULL - e.PortSpeed = oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB - } - ipv4, ok := portsIPv4[id] if !ok { return nil diff --git a/feature/gribi/otg_tests/encap_frr_with_reencap_vrf_test/encap_frr_with_reencap_vrf_test.go b/feature/gribi/otg_tests/encap_frr_with_reencap_vrf_test/encap_frr_with_reencap_vrf_test.go index fdd5e3329a7..8bcefca44bb 100644 --- a/feature/gribi/otg_tests/encap_frr_with_reencap_vrf_test/encap_frr_with_reencap_vrf_test.go +++ b/feature/gribi/otg_tests/encap_frr_with_reencap_vrf_test/encap_frr_with_reencap_vrf_test.go @@ -97,8 +97,12 @@ const ( ipv4OuterSrc222Addr = "198.51.100.222" gribiIPv4EntryVRF1111 = "203.0.113.1" gribiIPv4EntryVRF1112 = "203.0.113.2" + gribiIPv4EntryVRF1113 = "203.100.113.1" + gribiIPv4EntryVRF1114 = "203.100.113.2" gribiIPv4EntryVRF2221 = "203.0.113.100" gribiIPv4EntryVRF2222 = "203.0.113.101" + gribiIPv4EntryVRF2223 = "203.100.113.100" + gribiIPv4EntryVRF2224 = "203.100.113.101" gribiIPv4EntryEncapVRF = "138.0.11.0" dutAreaAddress = "49.0001" @@ -249,13 +253,6 @@ func dutInterface(p *ondatra.Port, dut *ondatra.DUTDevice) *oc.Interface { i.Enabled = ygot.Bool(true) } - if p.PMD() == ondatra.PMD100GBASEFR { - e := i.GetOrCreateEthernet() - e.AutoNegotiate = ygot.Bool(false) - e.DuplexMode = oc.Ethernet_DuplexMode_FULL - e.PortSpeed = oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB - } - ipv4, ok := portsIPv4[id] if !ok { return nil @@ -1142,11 +1139,10 @@ func TestEncapFrr(t *testing.T) { args.client.Modify().AddEntry(t, fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). WithIndex(1300).WithDecapsulateHeader(fluent.IPinIP).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF2221).WithNextHopNetworkInstance(niTEVRF222), + WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF2223).WithNextHopNetworkInstance(niTEVRF222), fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). WithIndex(1301).WithDecapsulateHeader(fluent.IPinIP).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF2222).WithNextHopNetworkInstance(niTEVRF222), - + WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF2224).WithNextHopNetworkInstance(niTEVRF222), fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). WithID(1000).AddNextHop(1300, 1), fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). @@ -1155,14 +1151,34 @@ func TestEncapFrr(t *testing.T) { if err := awaitTimeout(ctx, t, args.client, 2*time.Minute); err != nil { t.Logf("Could not program entries via client, got err, check error codes: %v", err) } + res := args.client.Results(t) + operIndexList := []uint64{1000, 1001} + for _, operIndex := range operIndexList { + chk.HasResult(t, res, + fluent.OperationResult(). + WithOperationType(constants.Add). + WithNextHopOperation(operIndex). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + chk.HasResult(t, res, + fluent.OperationResult(). + WithOperationType(constants.Add). + WithNextHopGroupOperation(operIndex). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + } } if tc.TestID == "teVrf111NoMatch" { args.client.Modify().AddEntry(t, fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(201).WithEncapsulateHeader(fluent.IPinIP).WithIPinIP(ipv4OuterSrc111Addr, "203.100.113.1"). + WithIndex(201).WithEncapsulateHeader(fluent.IPinIP).WithIPinIP(ipv4OuterSrc111Addr, gribiIPv4EntryVRF1113). WithNextHopNetworkInstance(niTEVRF111), fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(202).WithEncapsulateHeader(fluent.IPinIP).WithIPinIP(ipv4OuterSrc111Addr, "203.100.113.2"). + WithIndex(202).WithEncapsulateHeader(fluent.IPinIP).WithIPinIP(ipv4OuterSrc111Addr, gribiIPv4EntryVRF1114). WithNextHopNetworkInstance(niTEVRF111), fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). WithID(101).AddNextHop(201, 1).AddNextHop(202, 3).WithBackupNHG(2001), @@ -1170,6 +1186,31 @@ func TestEncapFrr(t *testing.T) { if err := awaitTimeout(ctx, t, args.client, 2*time.Minute); err != nil { t.Logf("Could not program entries via client, got err, check error codes: %v", err) } + res := args.client.Results(t) + chk.HasResult(t, res, + fluent.OperationResult(). + WithOperationType(constants.Add). + WithNextHopOperation(201). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + chk.HasResult(t, res, + fluent.OperationResult(). + WithOperationType(constants.Add). + WithNextHopOperation(202). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + chk.HasResult(t, res, + fluent.OperationResult(). + WithOperationType(constants.Add). + WithNextHopGroupOperation(101). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) } captureState = startCapture(t, args, tc.CapturePortList) diff --git a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md similarity index 80% rename from feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md rename to feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md index 94fb48612b5..f8017cf551f 100644 --- a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md +++ b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md @@ -1,4 +1,4 @@ -# TE-9.1: FIB FAILURE DUE TO HARDWARE RESOURCE EXHAUST +# TE-9.3: FIB FAILURE DUE TO HARDWARE RESOURCE EXHAUST ## Summary @@ -23,10 +23,18 @@ Validate gRIBI FIB_FAILED functionality. * Pick any route that received FIB_PROGRAMMED. Validate that traffic hitting the route should be forwarded to port2 -## Protocol/RPC Parameter coverage - -* gRIBI - * Flush +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` ## Config parameter coverage diff --git a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go similarity index 85% rename from feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go rename to feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go index d30e5b5fcff..541c0acb5ab 100644 --- a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go +++ b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go @@ -19,6 +19,8 @@ import ( "encoding/binary" "fmt" "net" + "strconv" + "strings" "testing" "time" @@ -27,7 +29,6 @@ import ( "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/gribi" - "github.com/openconfig/featureprofiles/internal/otgutils" "github.com/openconfig/gribigo/fluent" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" @@ -64,6 +65,10 @@ const ( tolerance = 50 plenIPv4 = 30 plenIPv6 = 126 + fibPassedTraffic = "fibPassedTraffic" + fibFailedTraffic = "fibFailedTraffic" + dstTrackingf1 = "dstTrackingf1" + dstTrackingf2 = "dstTrackingf2" ) var ( @@ -71,6 +76,7 @@ var ( ondatra.ARISTA: 2500000, ondatra.JUNIPER: 2500000, ondatra.NOKIA: 2600000, + ondatra.CISCO: 2500000, } dutPort1 = attrs.Attributes{ Desc: "dutPort1", @@ -102,8 +108,9 @@ var ( IPv4Len: plenIPv4, IPv6Len: plenIPv6, } - fibPassedDstRoute string - fibFailedDstRoute string + fibPassedDstRoute string + fibFailedDstRoute string + fibFailedDstRouteInHex string ) func configureBGP(dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { @@ -143,7 +150,7 @@ func configureBGP(dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { return niProto } -func configureOTG(t *testing.T, otg *otg.OTG) (gosnappi.BgpV6Peer, gosnappi.DeviceIpv6, gosnappi.Config) { +func configureOTG(t *testing.T, otg *otg.OTG, dstIPList []string) (gosnappi.BgpV6Peer, gosnappi.DeviceIpv6, gosnappi.Config) { t.Helper() config := gosnappi.NewConfig() port1 := config.Ports().Add().SetName("port1") @@ -168,6 +175,44 @@ func configureOTG(t *testing.T, otg *otg.OTG) (gosnappi.BgpV6Peer, gosnappi.Devi iDut1Bgp6Peer.SetPeerAddress(iDut1Ipv6.Gateway()).SetAsNumber(ateAS).SetAsType(gosnappi.BgpV6PeerAsType.EBGP) iDut1Bgp6Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(true) + flow1ipv4 := config.Flows().Add().SetName(fibPassedTraffic) + flow1ipv4.Metrics().SetEnable(true) + flow1ipv4.TxRx().Device(). + SetTxNames([]string{atePort1.Name + ".IPv4"}). + SetRxNames([]string{atePort2.Name + ".IPv4"}) + flow1ipv4.Size().SetFixed(512) + flow1ipv4.Rate().SetPps(100) + flow1ipv4.Duration().Continuous() + e1 := flow1ipv4.Packet().Add().Ethernet() + e1.Src().SetValue(atePort1.MAC) + v4 := flow1ipv4.Packet().Add().Ipv4() + v4.Src().SetValue(atePort1.IPv4) + v4.Dst().Increment().SetStart(dstIPList[0]) + + flow1ipv4.EgressPacket().Add().Ethernet() + ipTrackingf1 := flow1ipv4.EgressPacket().Add().Ipv4() + ipDstTrackingf1 := ipTrackingf1.Dst().MetricTags().Add() + ipDstTrackingf1.SetName(dstTrackingf1).SetOffset(22).SetLength(10) + + flow2ipv4 := config.Flows().Add().SetName(fibFailedTraffic) + flow2ipv4.Metrics().SetEnable(true) + flow2ipv4.TxRx().Device(). + SetTxNames([]string{atePort1.Name + ".IPv4"}). + SetRxNames([]string{atePort2.Name + ".IPv4"}) + flow2ipv4.Size().SetFixed(512) + flow2ipv4.Rate().SetPps(100) + flow2ipv4.Duration().Continuous() + e2 := flow2ipv4.Packet().Add().Ethernet() + e2.Src().SetValue(atePort1.MAC) + v4Flow2 := flow2ipv4.Packet().Add().Ipv4() + v4Flow2.Src().SetValue(atePort1.IPv4) + v4Flow2.Dst().SetValues(dstIPList[1:]) + + flow2ipv4.EgressPacket().Add().Ethernet() + ipTrackingf2 := flow2ipv4.EgressPacket().Add().Ipv4() + ipDstTrackingf2 := ipTrackingf2.Dst().MetricTags().Add() + ipDstTrackingf2.SetName(dstTrackingf2).SetOffset(22).SetLength(10) + t.Logf("Pushing config to ATE and starting protocols...") otg.PushConfig(t, config) time.Sleep(30 * time.Second) @@ -206,6 +251,8 @@ type testArgs struct { func TestFibFailDueToHwResExhaust(t *testing.T) { ctx := context.Background() dut := ondatra.DUT(t, "dut") + dstIPList := createIPv4Entries(t, fmt.Sprintf("%s/%d", dstIPBlock, 20)) + vipList := createIPv4Entries(t, fmt.Sprintf("%s/%d", vipBlock, 20)) configureDUT(t, dut) configureRoutePolicy(t, dut, "ALLOW", oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) @@ -243,8 +290,8 @@ func TestFibFailDueToHwResExhaust(t *testing.T) { var otgConfig gosnappi.Config var otgBgpPeer gosnappi.BgpV6Peer var otgIPv6Device gosnappi.DeviceIpv6 - otgBgpPeer, otgIPv6Device, otgConfig = configureOTG(t, otg) - + otgBgpPeer, otgIPv6Device, otgConfig = configureOTG(t, otg, dstIPList) + time.Sleep(30 * time.Second) verifyBgpTelemetry(t, dut) gribic := dut.RawAPIs().GRIBI(t) @@ -256,7 +303,7 @@ func TestFibFailDueToHwResExhaust(t *testing.T) { WithFIBACK().WithRedundancyMode(fluent.ElectedPrimaryClient) client.Start(ctx, t) defer client.Stop(t) - + gribi.FlushAll(client) defer func() { // Flush all entries after test. if err := gribi.FlushAll(client); err != nil { @@ -287,7 +334,13 @@ func TestFibFailDueToHwResExhaust(t *testing.T) { otg: otg, } start := time.Now() - injectEntry(ctx, t, args) + // cleanup fib table + defer func() { + ate.OTG().StopProtocols(t) + time.Sleep(5 * time.Minute) + }() + + injectEntry(ctx, t, args, dstIPList, vipList) t.Logf("Main Function: Time elapsed %.2f seconds since start", time.Since(start).Seconds()) t.Log("Send traffic to any of the programmed entries and validate.") @@ -297,50 +350,16 @@ func TestFibFailDueToHwResExhaust(t *testing.T) { func sendTraffic(t *testing.T, args *testArgs) { // Ensure that traffic can be forwarded between ATE port-1 and ATE port-2. t.Helper() - t.Logf("TestBGP:start otg Traffic config") - flow1ipv4 := args.otgConfig.Flows().Add().SetName("Flow1") - flow1ipv4.Metrics().SetEnable(true) - flow1ipv4.TxRx().Device(). - SetTxNames([]string{atePort1.Name + ".IPv4"}). - SetRxNames([]string{atePort2.Name + ".IPv4"}) - flow1ipv4.Size().SetFixed(512) - flow1ipv4.Rate().SetPps(100) - flow1ipv4.Duration().Continuous() - e1 := flow1ipv4.Packet().Add().Ethernet() - e1.Src().SetValue(atePort1.MAC) - v4 := flow1ipv4.Packet().Add().Ipv4() - v4.Src().SetValue(atePort1.IPv4) - v4.Dst().Increment().SetStart(fibPassedDstRoute) - flow2ipv4 := args.otgConfig.Flows().Add().SetName("Flow2") - flow2ipv4.Metrics().SetEnable(true) - flow2ipv4.TxRx().Device(). - SetTxNames([]string{atePort1.Name + ".IPv4"}). - SetRxNames([]string{atePort2.Name + ".IPv4"}) - flow2ipv4.Size().SetFixed(512) - flow2ipv4.Rate().SetPps(100) - flow2ipv4.Duration().Continuous() - e2 := flow2ipv4.Packet().Add().Ethernet() - e2.Src().SetValue(atePort1.MAC) - v4Flow2 := flow2ipv4.Packet().Add().Ipv4() - v4Flow2.Src().SetValue(atePort1.IPv4) - v4Flow2.Dst().Increment().SetStart(fibFailedDstRoute) + t.Logf("TestBGP:start otg Traffic") - args.otg.PushConfig(t, args.otgConfig) - time.Sleep(2 * time.Minute) - args.otg.StartProtocols(t) - otgutils.WaitForARP(t, args.ate.OTG(), args.otg.FetchConfig(t), "IPv4") t.Logf("Starting traffic") args.otg.StartTraffic(t) time.Sleep(15 * time.Second) t.Logf("Stop traffic") args.otg.StopTraffic(t) - verifyTraffic(t, args, flow1ipv4.Name(), !wantLoss) - /* - if !deviations.GRIBISkipFIBFailedTrafficForwardingCheck(args.dut) { - verifyTraffic(t, args, flow2ipv4.Name(), wantLoss) - } - */ + verifyTraffic(t, args, fibPassedTraffic, !wantLoss) + verifyTraffic(t, args, fibFailedTraffic, wantLoss) } func verifyTraffic(t *testing.T, args *testArgs, flowName string, wantLoss bool) { @@ -351,16 +370,31 @@ func verifyTraffic(t *testing.T, args *testArgs, flowName string, wantLoss bool) rxPackets := recvMetric.GetCounters().GetInPkts() lostPackets := txPackets - rxPackets var lossPct uint64 + trafficPassed := false if txPackets != 0 { lossPct = lostPackets * 100 / txPackets } else { t.Errorf("Traffic stats are not correct %v", recvMetric) } if wantLoss { - if lossPct < 100-tolerancePct { - t.Errorf("Traffic is expected to fail %s\n got %v, want 100%% failure", flowName, lossPct) + // If no rxPackets are received, the first route is fibFailedRoute, resulting in no packets being generated with tagged metrics. + if rxPackets > 0 { + etPath := gnmi.OTG().Flow(flowName).TaggedMetricAny() + ets := gnmi.GetAll(t, args.otg, etPath.State()) + for _, et := range ets { + tags := et.Tags + for _, tag := range tags { + if tag.GetTagName() == dstTrackingf2 && tag.GetTagValue().GetValueAsHex() == fibFailedDstRouteInHex { + trafficPassed = true + break + } + } + } + } + if trafficPassed { + t.Errorf("Traffic received on Failed FIB") } else { - t.Logf("Traffic Loss Test Passed!") + t.Logf("Traffic Test Passed!") } } else { if lossPct > tolerancePct { @@ -369,6 +403,7 @@ func verifyTraffic(t *testing.T, args *testArgs, flowName string, wantLoss bool) t.Logf("Traffic Test Passed!") } } + } func verifyBgpTelemetry(t *testing.T, dut *ondatra.DUTDevice) { @@ -376,7 +411,7 @@ func verifyBgpTelemetry(t *testing.T, dut *ondatra.DUTDevice) { var nbrIP = []string{atePort1.IPv6} t.Logf("Verifying BGP state.") bgpPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() - + time.Sleep(30 * time.Second) for _, nbr := range nbrIP { nbrPath := bgpPath.Neighbor(nbr) // Get BGP adjacency state. @@ -466,15 +501,31 @@ func createIPv4Entries(t *testing.T, startIP string) []string { return entries } +func IPv4LastTenBitsToHex(ip string) string { + // Convert IPv4 address to a 32-bit integer + ipParts := strings.Split(ip, ".") + var ipInt uint32 + for i := 0; i < 4; i++ { + part, _ := strconv.Atoi(ipParts[i]) + ipInt = (ipInt << 8) | uint32(part) + } + + // Convert the IP address to binary string + ipBinary := fmt.Sprintf("%032b", ipInt) + // Extract the last 10 bits + last10Bits := ipBinary[len(ipBinary)-10:] + // Convert the last 10 bits to hexadecimal + last10Hex, _ := strconv.ParseInt(last10Bits, 2, 64) + return fmt.Sprintf("0x%03x", last10Hex) +} + // injectEntry programs gRIBI nh, nhg and ipv4 entry. -func injectEntry(ctx context.Context, t *testing.T, args *testArgs) { +func injectEntry(ctx context.Context, t *testing.T, args *testArgs, dstIPList []string, vipList []string) { t.Helper() - dstIPList := createIPv4Entries(t, fmt.Sprintf("%s/%d", dstIPBlock, 20)) - vipList := createIPv4Entries(t, fmt.Sprintf("%s/%d", vipBlock, 20)) j := uint64(0) routeAddLoop: - for i := uint64(1); i <= uint64(1500); i += 2 { + for i := uint64(1); i <= uint64(1000); i += 2 { vipNhIndex := i dstNhIndex := vipNhIndex + 1 @@ -503,6 +554,7 @@ routeAddLoop: if v.ProgrammingResult == aftspb.AFTResult_FIB_FAILED { t.Logf("FIB FAILED received %v", v.Details) fibFailedDstRoute = dstIPList[j] + fibFailedDstRouteInHex = IPv4LastTenBitsToHex(fibFailedDstRoute) break routeAddLoop } } @@ -512,7 +564,7 @@ routeAddLoop: // routes through gRIBI client. Since FIB is already full , we should get // FIB FAILED while programming gRIBI routes. Here we are trying to program // 1500 VIP/Dst entries along with unique NH/NHG entries. - if i >= 1498 { + if i >= 998 { t.Fatalf("FIB FAILED is not received as expected") } if j == 1 { diff --git a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto similarity index 98% rename from feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto rename to feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto index 50fde18c196..179ddbcc314 100644 --- a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto +++ b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto @@ -2,7 +2,7 @@ # proto-message: Metadata uuid: "4f04fb5b-5bc0-4214-a74d-2a30c0433078" -plan_id: "TE-9.1" +plan_id: "TE-9.3" description: "FIB FAILURE DUE TO HARDWARE RESOURCE EXHAUST" testbed: TESTBED_DUT_ATE_2LINKS platform_exceptions: { diff --git a/feature/gribi/otg_tests/get_rpc_test/README.md b/feature/gribi/otg_tests/get_rpc_test/README.md index a497f30b7ba..488638d5b2f 100644 --- a/feature/gribi/otg_tests/get_rpc_test/README.md +++ b/feature/gribi/otg_tests/get_rpc_test/README.md @@ -48,18 +48,14 @@ Validate gRIBI Get RPC. [fib_status]: https://github.com/openconfig/gribi/blob/08d53dffce45e942c6e7f07521c58b557984e4b7/v1/proto/service/gribi.proto#L485 [rib_status]: https://github.com/openconfig/gribi/blob/08d53dffce45e942c6e7f07521c58b557984e4b7/v1/proto/service/gribi.proto#L483 -## Config Parameter coverage - -No additional configuration parameters. - -## Telemetry Parameter coverage - -No additional telemetry parameters. - -## Protocol/RPC Parameter coverage - -* gRIBI - * Get +## OpenConfig Path and RPC Coverage + +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: +``` ## Minimum DUT platform requirement diff --git a/feature/gribi/otg_tests/get_rpc_test/get_rpc_test.go b/feature/gribi/otg_tests/get_rpc_test/get_rpc_test.go index 874d27aaf6b..e3c22fb7cfa 100644 --- a/feature/gribi/otg_tests/get_rpc_test/get_rpc_test.go +++ b/feature/gribi/otg_tests/get_rpc_test/get_rpc_test.go @@ -33,6 +33,7 @@ import ( "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygnmi/ygnmi" "github.com/openconfig/ygot/ygot" ) @@ -316,8 +317,17 @@ func testIPv4LeaderActive(ctx context.Context, t *testing.T, args *testArgs) { // Verify the above entries are active through AFT Telemetry. for ip := range ateDstNetCIDR { ipv4Path := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(args.dut)).Afts().Ipv4Entry(ateDstNetCIDR[ip]) - if got, want := gnmi.Get(t, args.dut, ipv4Path.State()).GetPrefix(), ateDstNetCIDR[ip]; got != want { - t.Errorf("ipv4-entry/state/prefix got %s, want %s", got, want) + lastValue, ok := gnmi.Watch(t, args.dut, ipv4Path.State(), time.Minute, func(v *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv4Entry]) bool { + return v.IsPresent() + }).Await(t) + + if !ok { + t.Fatalf("gnmi.Watch() failed value received = %s", lastValue) + } + + ipv4, _ := lastValue.Val() + if got, want := ipv4.GetPrefix(), ateDstNetCIDR[ip]; got != want { + t.Fatalf("ipv4-entry/state/prefix got %s, want %s", got, want) } } @@ -346,8 +356,17 @@ func testIPv4LeaderActive(ctx context.Context, t *testing.T, args *testArgs) { validateGetRPC(ctx, t, args.clientA) for ip := range ateDstNetCIDR { ipv4Path := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(args.dut)).Afts().Ipv4Entry(ateDstNetCIDR[ip]) - if got, want := gnmi.Get(t, args.dut, ipv4Path.State()).GetPrefix(), ateDstNetCIDR[ip]; got != want { - t.Errorf("ipv4-entry/state/prefix got %s, want %s", got, want) + lastValue, ok := gnmi.Watch(t, args.dut, ipv4Path.State(), time.Minute, func(v *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv4Entry]) bool { + return v.IsPresent() + }).Await(t) + + if !ok { + t.Fatalf("gnmi.Watch() failed value received = %s", lastValue) + } + + ipv4, _ := lastValue.Val() + if got, want := ipv4.GetPrefix(), ateDstNetCIDR[ip]; got != want { + t.Fatalf("ipv4-entry/state/prefix got %s, want %s", got, want) } } diff --git a/feature/gribi/otg_tests/gribi_route_test/README.md b/feature/gribi/otg_tests/gribi_route_test/README.md new file mode 100644 index 00000000000..2f709e4ab43 --- /dev/null +++ b/feature/gribi/otg_tests/gribi_route_test/README.md @@ -0,0 +1,174 @@ +# RT-14.2: GRIBI Route Test + +## Summary + +Ensure Traffic is Encap/Decap to NextHop based on Gribi structure. + +## Topology + +ATE port-1 <------> port-1 DUT +DUT port-2 <------> port-2 ATE +DUT port-3 <------> port-3 ATE + +## Variables +``` +# Magic source IP addresses used in this test + * ipv4_outer_src_111 = 198.51.100.111 + * ipv4PrefixEncapped = ipv4InnerDst = 138.0.11.8 + * ipv4PrefixNotEncapped = ipv4OuterDst222 = 198.50.100.65 +``` + +## Baseline + +### VRF Selection Policy + +``` +network-instances { + network-instance { + name: DEFAULT + policy-forwarding { + policies { + policy { + policy-id: "vrf_selection_policy_c" + rules { + rule { + sequence-id: 1 + ipv4 { + protocol: 4 + source-address: "ipv4_outer_src_111" + } + action { + network-instance: "ENCAP_TE_VRF_A" + } + } + rule { + sequence-id: 2 + ipv4 { + protocol: 41 + dscp-set: [dscp_encap_a_1, dscp_encap_a_2] + source-address: "ipv4_outer_src_222" + } + action { + network-instance: "TRANSIT_TE_VRF" + } + } + } + } + } + } + } +} +``` +``` +### Install the following gRIBI AFTs. + +- IPv4Entry {0.0.0.0/0 (TRANSIT_TE_VRF)} -> NHG#1 (DEFAULT VRF) -> { + {NH#1, DEFAULT VRF, weight:1}, + } + NH#1 -> { + decapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 + network_instance: "DEFAULT" + } +- IPv4Entry {198.50.100.64/32 (TRANSIT_TE_VRF)} -> NHG#2 (DEFAULT VRF) -> { + {NH#2, DEFAULT VRF, weight:1}, interface-ref:dut-port-2-interface, + } +- IPv4Entry {198.50.100.64/32 (TE_VRF_111)} -> NHG#3 (DEFAULT VRF) -> { + {NH#3, DEFAULT VRF, weight:1}, interface-ref:dut-port-2-interface, + } +- IPv4Entry {0.0.0.0/0 (ENCAP_TE_VRF_A)} -> NHG#5 (DEFAULT VRF) -> { + {NH#5, DEFAULT VRF, weight:1, interface-ref:dut-port-3-interface}, + } +- IPv4Entry {138.0.11.8/32 (ENCAP_TE_VRF_A)} -> NHG#4 (DEFAULT VRF) -> { + {NH#4, DEFAULT VRF, weight:1}, + } + NH#4 -> { + encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 + ip_in_ip { + dst_ip: "198.50.100.64" + src_ip: "ipv4_outer_src_111" + } + network_instance: "TE_VRF_111" + } +``` +- Install a BGP route in default VRF to route traffic out of DUT port-3. + +## Procedure + +The DUT should be reset to the baseline after each of the following tests. + +Test-1, Match on source prefix, flow hits ENCAP_TE_VRF_A followed by TE_VRF_111 + +``` + 1. Send flow with source IP ipv4_outer_src_111 with destination IP ipv4PrefixEncapped. + 2. Verify v4 packet matched with tunnel prefix and encapped -> hit TE_VRF_111 + and egress via port-2. + 3. No traffic loss in steady state + +``` +Test-2, Match on source prefix, flow hits ENCAP_TE_VRF_A followed by Default VRF + +``` + 1. Send flow with source IP ipv4_outer_src_111 with destination IP ipv4PrefixNotEncapped. + 2. Verify v4 packet not matched with tunnel prefix and egress via port-3. + 3. No traffic loss in steady state + +``` +Test-3, Match on source prefix and protocol, flow hits TRANSIT_TE_VRF +match with Tunnel prefix /32 + +``` + 1. Send the following 4in4 flows to DUT port-1: + * inner_src: `ipv4_inner_src` + * inner_dst: `ipv4InnerDst` + * outter_src: `ipv4_outter_src_111` + * outter_dst: `ipv4_outter_decap_no_match` + * proto: `4` + 2. Verify packet matched with tunnel prefix and egress via port-2. + 3. No traffic loss in steady state + +``` +Test-4, Match on source prefix and protocol, flow hits TRANSIT_TE_VRF matched with 0/0 prefix, decap & sent to default vrf +``` + 1. Send the following 4in4 flows to DUT port-1: + * inner_src: `ipv4_inner_src` + * inner_dst: `ipv4InnerDst` + * outter_src: `ipv4_outter_src_111` + * outter_dst: `ipv4_outter_decap_match` + * proto: `4` + 2. Verify packet not matched with tunnel prefix, decap and failback + to default vrf. + 3. No traffic loss in steady state + +``` +## Config Parameter Coverage + +* network-instances/network-instance/name +* network-instances/network-instance/policy-forwarding/policies/policy/policy-id +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/network-instance + +## Telemetry Parameter Coverage + +* network-instances/network-instance/name +* network-instances/network-instance/policy-forwarding/policies/policy/policy-id +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address +* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/network-instance + +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` diff --git a/feature/gribi/otg_tests/gribi_route_test/gribi_route_test.go b/feature/gribi/otg_tests/gribi_route_test/gribi_route_test.go new file mode 100644 index 00000000000..194bcc77717 --- /dev/null +++ b/feature/gribi/otg_tests/gribi_route_test/gribi_route_test.go @@ -0,0 +1,728 @@ +package gribi_route_test + +import ( + "context" + "fmt" + "log" + "os" + "strconv" + "testing" + "time" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/google/gopacket/pcap" + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/gribi" + "github.com/openconfig/featureprofiles/internal/otgutils" + "github.com/openconfig/gribigo/chk" + "github.com/openconfig/gribigo/constants" + "github.com/openconfig/gribigo/fluent" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ondatra/otg" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" +) + +const ( + niTransitTeVrf = "TRANSIT_TE_VRF" + niEncapTeVrfA = "ENCAP_TE_VRF_A" + niTEVRF111 = "TE_VRF_111" + vrfPolC = "vrf_selection_policy_c" + seqIDBase = uint32(10) + ipv4OuterSrc111 = "198.51.100.111" + ipv4OuterSrc111WithMask = "198.51.100.111/32" + ipv4InnerDst = "138.0.11.8" + ipv4OuterDst111 = "198.50.100.64" + ipv4OuterDst222 = "198.50.100.65" + peerGrpName = "BGP-PEER-GROUP1" + asn = 65501 + tolerancePct = 2 + checkEncap = true +) + +var ( + dutPort1 = attrs.Attributes{ + Desc: "DUT Port 1", + IPv4: "192.0.2.1", + IPv4Len: 30, + } + dutPort2 = attrs.Attributes{ + Desc: "DUT Port 2", + IPv4: "192.0.2.5", + IPv4Len: 30, + } + dutPort3 = attrs.Attributes{ + Desc: "DUT Port 3", + IPv4: "192.0.2.9", + IPv4Len: 30, + } + + atePort1 = attrs.Attributes{ + Name: "port1", + MAC: "02:00:01:01:01:01", + Desc: "ATE Port 1", + IPv4: "192.0.2.2", + IPv4Len: 30, + } + atePort2 = attrs.Attributes{ + Name: "port2", + MAC: "02:00:02:01:01:01", + Desc: "ATE Port 2", + IPv4: "192.0.2.6", + IPv4Len: 30, + } + atePort3 = attrs.Attributes{ + Name: "port3", + MAC: "02:00:03:01:01:01", + Desc: "ATE Port 3", + IPv4: "192.0.2.10", + IPv4Len: 30, + } +) + +type bgpNeighbor struct { + Name string + dutIPv4 string + ateIPv4 string + MAC string +} + +var ( + bgpNbr1 = bgpNeighbor{ + Name: "port1", + dutIPv4: "192.0.2.1", + ateIPv4: "192.0.2.2", + MAC: "02:00:01:01:01:01", + } + bgpNbr2 = bgpNeighbor{ + Name: "port2", + dutIPv4: "192.0.2.5", + ateIPv4: "192.0.2.6", + MAC: "02:00:02:01:01:01", + } + bgpNbr3 = bgpNeighbor{ + Name: "port3", + dutIPv4: "192.0.2.9", + ateIPv4: "192.0.2.10", + MAC: "02:00:03:01:01:01", + } +) + +type packetValidation struct { + portName string + outDstIP []string + inHdrIP string + validateDecap bool + validateNoDecap bool + validateEncap bool +} + +type policyFwRule struct { + SeqID uint32 + family string + protocol oc.UnionUint8 + dscpSet []uint8 + sourceAddr string + ni string +} + +// testArgs holds the objects needed by a test case. +type testArgs struct { + dut *ondatra.DUTDevice + ctx context.Context + client *fluent.GRIBIClient + ate *ondatra.ATEDevice + otgConfig gosnappi.Config + otg *otg.OTG +} + +type flowArgs struct { + flowName string + outHdrSrcIP, outHdrDstIP string + InnHdrSrcIP, InnHdrDstIP string + InnHdrSrcIPv6, InnHdrDstIPv6 string + isIPInIP bool +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestGRIBIFailover(t *testing.T) { + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + ate := ondatra.ATE(t, "ate") + top := configureOTG(t, ate) + t.Log("Configure VRF_Policy") + configureVrfSelectionPolicyC(t, dut) + t.Log("Configure GRIBI") + configureGribiRoute(t, dut) + + llAddress, found := gnmi.Watch(t, ate.OTG(), gnmi.OTG().Interface("port1.Eth").Ipv4Neighbor(dutPort1.IPv4).LinkLayerAddress().State(), time.Minute, func(val *ygnmi.Value[string]) bool { + return val.IsPresent() + }).Await(t) + if !found { + t.Fatalf("Could not get the LinkLayerAddress %s", llAddress) + } + dstMac, _ := llAddress.Val() + + verifyBgpTelemetry(t, dut) + + args := &testArgs{ + dut: dut, + ate: ate, + otgConfig: top, + otg: ate.OTG(), + } + t.Run("RT-14.2.1: Traffic Prefix Match to Tunnel Prefix, Encapped and Egress via Port2", func(t *testing.T) { + flow := createFlow(&flowArgs{flowName: "flow4in4", + InnHdrSrcIP: ipv4OuterSrc111, InnHdrDstIP: ipv4InnerDst}, dstMac) + sendTraffic(t, args, top, ate, flow, 30, []string{"port2"}) + if ok := verifyTrafficFlow(t, ate, flow); !ok { + t.Fatal("Packet Dropped, LossPct for flow ") + } + captureAndValidatePackets(t, args, &packetValidation{portName: atePort2.Name, + outDstIP: []string{ipv4OuterDst111}, inHdrIP: ipv4InnerDst, validateEncap: true}) + }) + + t.Run("RT-14.2.2: Traffic Prefix not Matched to Tunnel Prefix, Egress via Port3", func(t *testing.T) { + flow := createFlow(&flowArgs{flowName: "flow4in4", + InnHdrSrcIP: ipv4OuterSrc111, InnHdrDstIP: ipv4OuterDst222}, dstMac) + sendTraffic(t, args, top, ate, flow, 30, []string{"port3"}) + if ok := verifyTrafficFlow(t, ate, flow); !ok { + t.Fatal("Packet Dropped, LossPct for flow ") + } + }) + + t.Run("RT-14.2.3: Traffic Match to Transit_Vrf, Match Tunnel Prefix Egress to Port2", func(t *testing.T) { + flow := createFlow(&flowArgs{flowName: "flow4in4", + outHdrSrcIP: ipv4OuterSrc111, outHdrDstIP: ipv4OuterDst111, + InnHdrSrcIP: ipv4OuterSrc111, InnHdrDstIP: ipv4InnerDst, isIPInIP: true}, dstMac) + sendTraffic(t, args, top, ate, flow, 30, []string{"port2"}) + if ok := verifyTrafficFlow(t, ate, flow); !ok { + t.Fatal("Packet Dropped, LossPct for flow ") + } + captureAndValidatePackets(t, args, &packetValidation{portName: atePort2.Name, + outDstIP: []string{ipv4OuterDst111}, inHdrIP: ipv4InnerDst, validateNoDecap: true}) + }) + + t.Run("RT-14.2.4: Traffic Match to Transit_Vrf, noMatch Tunnel Prefix Egress to Port3", func(t *testing.T) { + flow := createFlow(&flowArgs{flowName: "flow4in4", + outHdrSrcIP: ipv4OuterSrc111, outHdrDstIP: ipv4OuterDst222, + InnHdrSrcIP: ipv4OuterSrc111, InnHdrDstIP: ipv4InnerDst, isIPInIP: true}, dstMac) + sendTraffic(t, args, top, ate, flow, 30, []string{"port3"}) + if ok := verifyTrafficFlow(t, ate, flow); !ok { + t.Fatal("Packet Dropped, LossPct for flow ") + } + captureAndValidatePackets(t, args, &packetValidation{portName: atePort3.Name, + outDstIP: []string{ipv4OuterDst222}, inHdrIP: ipv4InnerDst, validateDecap: true}) + }) +} + +// configureDUT configures port1-3 on the DUT. +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + fptest.ConfigureDefaultNetworkInstance(t, dut) + t.Logf("configureDUT") + p1 := dut.Port(t, "port1") + p2 := dut.Port(t, "port2") + p3 := dut.Port(t, "port3") + + gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) + gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) + gnmi.Replace(t, dut, gnmi.OC().Interface(p3.Name()).Config(), dutPort3.NewOCInterface(p3.Name(), dut)) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, p1) + fptest.SetPortSpeed(t, p2) + fptest.SetPortSpeed(t, p3) + } + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p3.Name(), deviations.DefaultNetworkInstance(dut), 0) + } + configNonDefaultNetworkInstance(t, dut) + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + gnmi.Delete(t, dut, dutConfPath.Config()) + dutConf := bgpCreateNbr(asn, dut) + gnmi.Replace(t, dut, dutConfPath.Config(), dutConf) +} + +func bgpCreateNbr(localAs uint32, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + dutOcRoot := &oc.Root{} + ni1 := dutOcRoot.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + + global := bgp.GetOrCreateGlobal() + global.RouterId = ygot.String(dutPort3.IPv4) + global.As = ygot.Uint32(localAs) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + pg1 := bgp.GetOrCreatePeerGroup(peerGrpName) + pg1.PeerAs = ygot.Uint32(localAs) + + bgpNbr := bgp.GetOrCreateNeighbor(bgpNbr3.ateIPv4) + bgpNbr.PeerGroup = ygot.String(peerGrpName) + bgpNbr.PeerAs = ygot.Uint32(localAs) + bgpNbr.Enabled = ygot.Bool(true) + bgpNbrT := bgpNbr.GetOrCreateTransport() + bgpNbrT.LocalAddress = ygot.String(bgpNbr3.dutIPv4) + af4 := bgpNbr.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + af4.Enabled = ygot.Bool(true) + af6 := bgpNbr.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + af6.Enabled = ygot.Bool(true) + + return niProto +} + +// configureOTGBGP configure BGP on ATE +func configureOTGBGP(t *testing.T, dev gosnappi.Device, top gosnappi.Config, nbr bgpNeighbor) { + t.Helper() + iDutBgp := dev.Bgp().SetRouterId(nbr.ateIPv4) + iDutBgp4Peer := iDutBgp.Ipv4Interfaces().Add().SetIpv4Name(nbr.Name + ".IPv4").Peers().Add().SetName(nbr.Name + ".BGP4.peer") + iDutBgp4Peer.SetPeerAddress(nbr.dutIPv4).SetAsNumber(asn).SetAsType(gosnappi.BgpV4PeerAsType.IBGP) + iDutBgp4Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(false) + + bgpNeti1Bgp4PeerRoutes := iDutBgp4Peer.V4Routes().Add().SetName(nbr.Name + ".BGP4.Route") + bgpNeti1Bgp4PeerRoutes.SetNextHopIpv4Address(nbr.ateIPv4). + SetNextHopAddressType(gosnappi.BgpV4RouteRangeNextHopAddressType.IPV4). + SetNextHopMode(gosnappi.BgpV4RouteRangeNextHopMode.MANUAL) + bgpNeti1Bgp4PeerRoutes.Addresses().Add().SetAddress(ipv4InnerDst).SetPrefix(32).SetCount(1) +} + +func configureOTG(t *testing.T, ate *ondatra.ATEDevice) gosnappi.Config { + t.Logf("configureOTG") + config := gosnappi.NewConfig() + var dev gosnappi.Device + for i, ap := range []bgpNeighbor{bgpNbr1, bgpNbr2, bgpNbr3} { + // DUT and ATE ports are connected by the same names. + port := config.Ports().Add().SetName(ap.Name) + portName := fmt.Sprintf("port%s", strconv.Itoa(i+1)) + dev = config.Devices().Add().SetName(portName) + eth := dev.Ethernets().Add().SetName(portName + ".Eth").SetMac(ap.MAC) + eth.Connection().SetPortName(port.Name()) + eth.Ipv4Addresses().Add().SetName(portName + ".IPv4"). + SetAddress(ap.ateIPv4).SetGateway(ap.dutIPv4). + SetPrefix(30) + } + configureOTGBGP(t, dev, config, bgpNbr3) + ate.OTG().PushConfig(t, config) + ate.OTG().StartProtocols(t) + return config +} + +// seqIDOffset returns sequence ID offset added with seqIDBase (10), to avoid sequences +// like 1, 10, 11, 12,..., 2, 21, 22, ... while being sent by Ondatra to the DUT. +// It now generates sequences like 11, 12, 13, ..., 19, 20, 21,..., 99. +func seqIDOffset(dut *ondatra.DUTDevice, i uint32) uint32 { + if deviations.PfRequireSequentialOrderPbrRules(dut) { + return i + seqIDBase + } + return i +} + +// configureNetworkInstance configures vrfs DECAP_TE_VRF,ENCAP_TE_VRF_A,ENCAP_TE_VRF_B, +// TE_VRF_222, TE_VRF_111. +func configNonDefaultNetworkInstance(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + c := &oc.Root{} + vrfs := []string{niTransitTeVrf, niEncapTeVrfA, niTEVRF111} + for _, vrf := range vrfs { + ni := c.GetOrCreateNetworkInstance(vrf) + ni.Type = oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_L3VRF + gnmi.Replace(t, dut, gnmi.OC().NetworkInstance(vrf).Config(), ni) + } + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Name().Config(), deviations.DefaultNetworkInstance(dut)) +} + +func configureVrfSelectionPolicyC(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + d := &oc.Root{} + time.Sleep(100 * time.Second) + dutPolFwdPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).PolicyForwarding() + + pfRule1 := &policyFwRule{SeqID: 1, family: "ipv4", protocol: 4, sourceAddr: ipv4OuterSrc111WithMask, + ni: niTransitTeVrf} + pfRule2 := &policyFwRule{SeqID: 2, family: "ipv4", sourceAddr: ipv4OuterSrc111WithMask, + ni: niEncapTeVrfA} + + pfRuleList := []*policyFwRule{pfRule1, pfRule2} + ni := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niP := ni.GetOrCreatePolicyForwarding() + niPf := niP.GetOrCreatePolicy(vrfPolC) + niPf.SetType(oc.Policy_Type_VRF_SELECTION_POLICY) + for _, pfRule := range pfRuleList { + pfR := niPf.GetOrCreateRule(seqIDOffset(dut, pfRule.SeqID)) + if pfRule.family == "ipv4" { + pfRProtoIP := pfR.GetOrCreateIpv4() + if pfRule.protocol != 0 { + pfRProtoIP.Protocol = oc.UnionUint8(pfRule.protocol) + } + if pfRule.sourceAddr != "" { + pfRProtoIP.SourceAddress = ygot.String(pfRule.sourceAddr) + } + } else if pfRule.family == "ipv6" { + pfRProtoIP := pfR.GetOrCreateIpv6() + if pfRule.dscpSet != nil { + pfRProtoIP.DscpSet = pfRule.dscpSet + } + } + + pfRAction := pfR.GetOrCreateAction() + pfRAction.NetworkInstance = ygot.String(pfRule.ni) + } + p1 := dut.Port(t, "port1") + interfaceID := p1.Name() + if deviations.InterfaceRefInterfaceIDFormat(dut) { + interfaceID = interfaceID + ".0" + } + intf := niP.GetOrCreateInterface(interfaceID) + intf.ApplyVrfSelectionPolicy = ygot.String(vrfPolC) + intf.GetOrCreateInterfaceRef().Interface = ygot.String(p1.Name()) + intf.GetOrCreateInterfaceRef().Subinterface = ygot.Uint32(0) + if deviations.InterfaceRefConfigUnsupported(dut) { + intf.InterfaceRef = nil + } + // gnmi.Update(t, dut, gnmi.OC().NetworkInstance("DEFAULT").Name().Config(), "DEFAULT") + gnmi.Replace(t, dut, dutPolFwdPath.Config(), niP) +} + +func configureGribiRoute(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + ctx := context.Background() + gribic := dut.RawAPIs().GRIBI(t) + client := fluent.NewClient() + client.Connection().WithStub(gribic).WithPersistence().WithInitialElectionID(12, 0). + WithRedundancyMode(fluent.ElectedPrimaryClient).WithFIBACK() + client.Start(ctx, t) + defer client.Stop(t) + gribi.FlushAll(client) + defer gribi.FlushAll(client) + client.StartSending(ctx, t) + gribi.BecomeLeader(t, client) + + tcArgs := &testArgs{ + ctx: ctx, + client: client, + dut: dut, + } + tcArgs.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(uint64(1)).WithDecapsulateHeader(fluent.IPinIP). + WithNextHopNetworkInstance(deviations.DefaultNetworkInstance(dut)), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(uint64(1)).AddNextHop(uint64(1), uint64(1)), + + fluent.IPv4Entry().WithNetworkInstance(niTransitTeVrf).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix("0.0.0.0/0").WithNextHopGroup(uint64(1))) + + if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, 90*time.Second); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + tcArgs.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(uint64(2)).WithIPAddress(atePort2.IPv4), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(uint64(2)).AddNextHop(uint64(2), uint64(1)), + + fluent.IPv4Entry().WithNetworkInstance(niTransitTeVrf).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix(ipv4OuterDst111+"/32").WithNextHopGroup(uint64(2))) + + if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, 90*time.Second); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + defaultVRFIPList := []string{"0.0.0.0/0", ipv4OuterDst111 + "/32"} + for ip := range defaultVRFIPList { + chk.HasResult(t, tcArgs.client.Results(t), + fluent.OperationResult(). + WithIPv4Operation(defaultVRFIPList[ip]). + WithOperationType(constants.Add). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + } + + tcArgs.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(uint64(3)).WithIPAddress(atePort2.IPv4), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(uint64(3)).AddNextHop(uint64(3), uint64(1)), + + fluent.IPv4Entry().WithNetworkInstance(niTEVRF111). + WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix(ipv4OuterDst111+"/32").WithNextHopGroup(uint64(3))) + + if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, 90*time.Second); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + chk.HasResult(t, tcArgs.client.Results(t), + fluent.OperationResult(). + WithIPv4Operation(ipv4OuterDst111+"/32"). + WithOperationType(constants.Add). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + // Encap + tcArgs.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(uint64(4)).WithEncapsulateHeader(fluent.IPinIP).WithIPinIP(ipv4OuterSrc111, ipv4OuterDst111). + WithNextHopNetworkInstance(niTEVRF111), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(uint64(4)).AddNextHop(uint64(4), uint64(1)), + + fluent.IPv4Entry().WithNetworkInstance(niEncapTeVrfA). + WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix(ipv4InnerDst+"/32").WithNextHopGroup(uint64(4))) + + if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, 90*time.Second); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + tcArgs.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(uint64(5)).WithIPAddress(atePort3.IPv4), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(uint64(5)).AddNextHop(uint64(5), uint64(1)), + + fluent.IPv4Entry().WithNetworkInstance(niEncapTeVrfA). + WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix("0.0.0.0/0").WithNextHopGroup(uint64(5))) + + if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, 90*time.Second); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + defaultVRFIPList = []string{"0.0.0.0/0", ipv4InnerDst + "/32"} + for ip := range defaultVRFIPList { + chk.HasResult(t, tcArgs.client.Results(t), + fluent.OperationResult(). + WithIPv4Operation(defaultVRFIPList[ip]). + WithOperationType(constants.Add). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) + } + +} + +// awaitTimeout calls a fluent client Await, adding a timeout to the context. +func awaitTimeout(ctx context.Context, t testing.TB, c *fluent.GRIBIClient, timeout time.Duration) error { + t.Helper() + subctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + return c.Await(subctx, t) +} + +func createFlow(flowValues *flowArgs, dstMac string) gosnappi.Flow { + flow := gosnappi.NewFlow().SetName(flowValues.flowName) + flow.Metrics().SetEnable(true) + flow.Size().SetFixed(512) + flow.Rate().SetPps(100) + flow.Duration().Continuous() + ethHeader := flow.Packet().Add().Ethernet() + ethHeader.Src().SetValue(atePort1.MAC) + ethHeader.Dst().SetValue(dstMac) + // Outer IP header + if flowValues.isIPInIP { + outerIPHdr := flow.Packet().Add().Ipv4() + outerIPHdr.Src().SetValue(flowValues.outHdrSrcIP) + outerIPHdr.Dst().SetValue(flowValues.outHdrDstIP) + innerIPHdr := flow.Packet().Add().Ipv4() + innerIPHdr.Src().SetValue(flowValues.InnHdrSrcIP) + innerIPHdr.Dst().SetValue(flowValues.InnHdrDstIP) + } else { + innerIPHdr := flow.Packet().Add().Ipv4() + innerIPHdr.Src().SetValue(flowValues.InnHdrSrcIP) + innerIPHdr.Dst().SetValue(flowValues.InnHdrDstIP) + } + return flow +} + +// testTraffic sends traffic flow for duration seconds and returns the +// number of packets sent out. +func sendTraffic(t *testing.T, args *testArgs, top gosnappi.Config, ate *ondatra.ATEDevice, flow gosnappi.Flow, duration int, port []string) { + t.Helper() + top.Flows().Clear() + + args.otgConfig.Captures().Clear() + args.otgConfig.Captures().Add().SetName("packetCapture"). + SetPortNames(port). + SetFormat(gosnappi.CaptureFormat.PCAP) + + flow.TxRx().Port().SetTxName("port1").SetRxNames([]string{"port2", "port3"}) + flow.Metrics().SetEnable(true) + top.Flows().Append(flow) + + ate.OTG().PushConfig(t, top) + time.Sleep(30 * time.Second) + ate.OTG().StartProtocols(t) + time.Sleep(30 * time.Second) + + cs := gosnappi.NewControlState() + cs.Port().Capture().SetState(gosnappi.StatePortCaptureState.START) + args.otg.SetControlState(t, cs) + + ate.OTG().StartTraffic(t) + time.Sleep(time.Duration(duration) * time.Second) + ate.OTG().StopTraffic(t) + + cs.Port().Capture().SetState(gosnappi.StatePortCaptureState.STOP) + args.otg.SetControlState(t, cs) + otgutils.LogFlowMetrics(t, ate.OTG(), top) + otgutils.LogPortMetrics(t, ate.OTG(), top) +} + +// verifyTrafficFlow verify the each flow on ATE +func verifyTrafficFlow(t *testing.T, ate *ondatra.ATEDevice, flow gosnappi.Flow) bool { + rxPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flow.Name()).Counters().InPkts().State()) + txPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flow.Name()).Counters().OutPkts().State()) + lostPkt := txPkts - rxPkts + if got := (lostPkt * 100 / txPkts); got >= tolerancePct { + return false + } + return true +} + +// verifyBgpTelemetry verifies BGP telemetry. +func verifyBgpTelemetry(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + t.Logf("Verifying BGP state.") + bgpPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + + nbrPath := bgpPath.Neighbor(bgpNbr3.ateIPv4) + // Get BGP adjacency state. + t.Logf("Waiting for BGP neighbor to establish...") + var status *ygnmi.Value[oc.E_Bgp_Neighbor_SessionState] + status, ok := gnmi.Watch(t, dut, nbrPath.SessionState().State(), time.Minute, func(val *ygnmi.Value[oc.E_Bgp_Neighbor_SessionState]) bool { + state, ok := val.Val() + return ok && state == oc.Bgp_Neighbor_SessionState_ESTABLISHED + }).Await(t) + if !ok { + fptest.LogQuery(t, "BGP reported state", nbrPath.State(), gnmi.Get(t, dut, nbrPath.State())) + t.Fatal("No BGP neighbor formed") + } + state, _ := status.Val() + t.Logf("BGP adjacency for %s: %v", bgpNbr3.ateIPv4, state) + if want := oc.Bgp_Neighbor_SessionState_ESTABLISHED; state != want { + t.Errorf("BGP peer %s status got %d, want %d", bgpNbr3.ateIPv4, state, want) + } +} + +func captureAndValidatePackets(t *testing.T, args *testArgs, packetVal *packetValidation) { + bytes := args.otg.GetCapture(t, gosnappi.NewCaptureRequest().SetPortName(packetVal.portName)) + f, err := os.CreateTemp("", "pcap") + if err != nil { + t.Fatalf("ERROR: Could not create temporary pcap file: %v\n", err) + } + if _, err := f.Write(bytes); err != nil { + t.Fatalf("ERROR: Could not write bytes to pcap file: %v\n", err) + } + f.Close() + handle, err := pcap.OpenOffline(f.Name()) + if err != nil { + log.Fatal(err) + } + defer handle.Close() + packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) + if packetVal.validateDecap { + validateTrafficDecap(t, packetSource) + } + if packetVal.validateNoDecap { + validateTrafficNonDecap(t, packetSource, packetVal.outDstIP[0], packetVal.inHdrIP) + } + if packetVal.validateEncap { + validateTrafficEncap(t, packetSource, packetVal.outDstIP, packetVal.inHdrIP) + } + args.otgConfig.Captures().Clear() + args.otg.PushConfig(t, args.otgConfig) + time.Sleep(30 * time.Second) +} + +func validateTrafficDecap(t *testing.T, packetSource *gopacket.PacketSource) { + t.Helper() + for packet := range packetSource.Packets() { + ipLayer := packet.Layer(layers.LayerTypeIPv4) + if ipLayer == nil { + continue + } + ipPacket, _ := ipLayer.(*layers.IPv4) + innerPacket := gopacket.NewPacket(ipPacket.Payload, ipPacket.NextLayerType(), gopacket.Default) + ipInnerLayer := innerPacket.Layer(layers.LayerTypeIPv4) + if ipInnerLayer != nil { + t.Errorf("Packets are not decapped, Inner IP header is not removed.") + } + } +} + +func validateTrafficNonDecap(t *testing.T, packetSource *gopacket.PacketSource, outDstIP, inHdrIP string) { + t.Helper() + t.Log("Validate traffic non decap routes") + var packetCheckCount uint32 = 1 + for packet := range packetSource.Packets() { + if packetCheckCount >= 5 { + break + } + ipLayer := packet.Layer(layers.LayerTypeIPv4) + if ipLayer == nil { + continue + } + ipPacket, _ := ipLayer.(*layers.IPv4) + innerPacket := gopacket.NewPacket(ipPacket.Payload, ipPacket.NextLayerType(), gopacket.Default) + ipInnerLayer := innerPacket.Layer(layers.LayerTypeIPv4) + if ipInnerLayer != nil { + if ipPacket.DstIP.String() != outDstIP { + t.Errorf("Negatice test for Decap failed. Traffic sent to route which does not match the decap route are decaped") + } + ipInnerPacket, _ := ipInnerLayer.(*layers.IPv4) + if ipInnerPacket.DstIP.String() != inHdrIP { + t.Errorf("Negatice test for Decap failed. Traffic sent to route which does not match the decap route are decaped") + } + t.Logf("Traffic for non decap routes passed.") + break + } + } +} + +func validateTrafficEncap(t *testing.T, packetSource *gopacket.PacketSource, outDstIP []string, innerIP string) { + t.Helper() + t.Log("Validate traffic non decap routes") + var packetCheckCount uint32 = 1 + for packet := range packetSource.Packets() { + if packetCheckCount >= 5 { + break + } + ipLayer := packet.Layer(layers.LayerTypeIPv4) + if ipLayer == nil { + continue + } + ipPacket, _ := ipLayer.(*layers.IPv4) + innerPacket := gopacket.NewPacket(ipPacket.Payload, ipPacket.NextLayerType(), gopacket.Default) + ipInnerLayer := innerPacket.Layer(layers.LayerTypeIPv4) + if ipInnerLayer != nil { + if len(outDstIP) == 2 { + if ipPacket.DstIP.String() != outDstIP[0] || ipPacket.DstIP.String() != outDstIP[1] { + t.Errorf("Packets are not encapsulated as expected") + } + } else { + if ipPacket.DstIP.String() != outDstIP[0] { + t.Errorf("Packets are not encapsulated as expected") + } + } + t.Logf("Traffic for encap routes passed.") + break + } + } +} diff --git a/feature/gribi/otg_tests/gribi_route_test/metadata.textproto b/feature/gribi/otg_tests/gribi_route_test/metadata.textproto new file mode 100644 index 00000000000..333a3e00ed4 --- /dev/null +++ b/feature/gribi/otg_tests/gribi_route_test/metadata.textproto @@ -0,0 +1,55 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "8beaac46-9b7b-49c4-9bde-62ad630aa6c7" +plan_id: "RT-14.2" +description: "GRIBI Route Test" +testbed: TESTBED_DUT_ATE_4LINKS + +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + gribi_mac_override_with_static_arp: true + interface_ref_interface_id_format: true + pf_require_match_default_rule: true + pf_require_sequential_order_pbr_rules: true + ttl_copy_unsupported: true + isis_single_topology_required: true + } +} +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_port_speed: true + explicit_interface_in_default_vrf: true + aggregate_atomic_update: true + interface_enabled: true + missing_value_for_defaults: true + missing_isis_interface_afi_safi_enable: true + } +} + +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + omit_l2_mtu: true + isis_instance_enabled_required: true + isis_interface_afi_unsupported: true + missing_isis_interface_afi_safi_enable: true + isis_require_same_l1_metric_with_l2_metric: true + route_policy_under_afi_unsupported: true + static_protocol_name: "STATIC" + aggregate_atomic_update: true + missing_value_for_defaults: true + max_ecmp_paths: true + explicit_interface_in_default_vrf: false + } +} diff --git a/feature/gribi/otg_tests/gribi_scaling/metadata.textproto b/feature/gribi/otg_tests/gribi_scaling/metadata.textproto index 981e65d1ab9..393d30f1bd5 100644 --- a/feature/gribi/otg_tests/gribi_scaling/metadata.textproto +++ b/feature/gribi/otg_tests/gribi_scaling/metadata.textproto @@ -32,7 +32,6 @@ platform_exceptions: { } deviations: { no_mix_of_tagged_and_untagged_subinterfaces: true - explicit_interface_ref_definition: true } } platform_exceptions: { diff --git a/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/README.md b/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/README.md index d2d65948ea1..026f4dd889f 100644 --- a/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/README.md +++ b/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/README.md @@ -141,3 +141,22 @@ rpcs: ## Minimum DUT platform requirement vRX + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: N/A + + ## State paths: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/weight: + +rpcs: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` \ No newline at end of file diff --git a/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/metadata.textproto b/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/metadata.textproto index 18b3f8b387b..cb1bef25af4 100644 --- a/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/metadata.textproto +++ b/feature/gribi/otg_tests/hierarchical_weight_resolution_pbf_test/metadata.textproto @@ -14,7 +14,7 @@ platform_exceptions: { ipv4_missing_enabled: true interface_ref_interface_id_format: true pf_require_match_default_rule: true - pf_require_sequential_order_pbr_rules: true + pf_require_sequential_order_pbr_rules: true } } platform_exceptions: { @@ -23,7 +23,6 @@ platform_exceptions: { } deviations: { hierarchical_weight_resolution_tolerance: 0.4 - explicit_interface_ref_definition: true } } platform_exceptions: { diff --git a/feature/gribi/otg_tests/hierarchical_weight_resolution_test/README.md b/feature/gribi/otg_tests/hierarchical_weight_resolution_test/README.md index 63bfca04b3c..d206b7660d1 100644 --- a/feature/gribi/otg_tests/hierarchical_weight_resolution_test/README.md +++ b/feature/gribi/otg_tests/hierarchical_weight_resolution_test/README.md @@ -142,3 +142,21 @@ rpcs: * vRX - virtual router device +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: N/A + + ## State paths: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/weight: + +rpcs: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` \ No newline at end of file diff --git a/feature/gribi/otg_tests/hierarchical_weight_resolution_test/metadata.textproto b/feature/gribi/otg_tests/hierarchical_weight_resolution_test/metadata.textproto index a7f0ebfbfb0..fb0c549af67 100644 --- a/feature/gribi/otg_tests/hierarchical_weight_resolution_test/metadata.textproto +++ b/feature/gribi/otg_tests/hierarchical_weight_resolution_test/metadata.textproto @@ -21,7 +21,6 @@ platform_exceptions: { } deviations: { hierarchical_weight_resolution_tolerance: 0.4 - explicit_interface_ref_definition: true } } platform_exceptions: { diff --git a/feature/gribi/otg_tests/ipv4_entry_test/metadata.textproto b/feature/gribi/otg_tests/ipv4_entry_test/metadata.textproto index b3036f4968f..1fa1844f144 100644 --- a/feature/gribi/otg_tests/ipv4_entry_test/metadata.textproto +++ b/feature/gribi/otg_tests/ipv4_entry_test/metadata.textproto @@ -11,7 +11,7 @@ platform_exceptions: { } deviations: { ipv4_missing_enabled: true - gribi_mac_override_with_static_arp: true + gribi_mac_override_static_arp_static_route: true } } platform_exceptions: { diff --git a/feature/gribi/otg_tests/mpls_in_udp/README.md b/feature/gribi/otg_tests/mpls_in_udp/README.md index ad88513609d..b2f8fc44704 100644 --- a/feature/gribi/otg_tests/mpls_in_udp/README.md +++ b/feature/gribi/otg_tests/mpls_in_udp/README.md @@ -43,122 +43,72 @@ outer_ip-ttl = "64" #### gRIBI RPC content The gRIBI client should send this proto message to the DUT to create AFT -entries. See [OC AFT Encap PR in progress](https://github.com/openconfig/public/pull/1153) -for the new OC AFT model nodes needed for this. - -TODO: The -[gRIBI v1 protobuf defintions](https://github.com/openconfig/gribi/blob/master/v1/proto/README.md) -will be generated from the afts tree. +entries. ```proto -network_instances: { - network_instance: { - afts { - # - # entries used for "group_A" - ipv6_unicast { - ipv6_entry { - prefix: "inner_ipv6_dst_A" # this is an IPv6 entry for the origin/inner packet. - next_hop_group: 100 - } - } - ipv4_unicast { - ipv4_entry { - prefix: "ipv4_inner_dst_A" # this is an IPv4 entry for the origin/inner packet. - next_hop_group: 100 - } - } - next_hop_groups { - next_hop_group { - id: 100 - next_hops { # reference to a next-hop - next_hop: { - index: 100 - } - } - } - } - next_hops { - next_hop { - index: 100 - network_instance: "group_A" - encap-headers { - encap-header { - index: 1 - pushed_mpls_label_stack: [100,] - } - } - encap-headers { - encap-header { - index: 2 - src_ip: "outer_ipv6_src" - dst_ip: "outer_ipv6_dst_A" - dst_udp_port: "outer_dst_udp_port" - ip_ttl: "outer_ip-ttl" - dscp: "outer_dscp" - } - } - } - } - # - # entries used for "group_B" - ipv6_unicast { - ipv6_entry { - prefix: "inner_ipv6_dst_B" - next_hop_group: 200 - } +# +# aft entries used for network instance "NI_A" +IPv6Entry {2001:DB8:2::2/128 (NI_A)} -> NHG#100 (DEFAULT VRF) +IPv4Entry {203.0.113.2/32 (NI_A)} -> NHG#100 (DEFAULT VRF) -> { + {NH#101, DEFAULT VRF} +} + +# this nexthop specifies a MPLS in UDP encapsulation +NH#101 -> { + encap_-_headers { + encap_header { + index: 1 + mpls { + pushed_mpls_label_stack: [101,] } - ipv4_unicast { - ipv4_entry { - prefix: "ipv4_inner_dst_B" - next_hop_group: 200 - } + } + encap_header { + index: 2 + udp_v6 { + src_ip: "outer_ipv6_src" + dst_ip: "outer_ipv6_dst_A" + dst_udp_port: "outer_dst_udp_port" + ip_ttl: "outer_ip-ttl" + dscp: "outer_dscp" } - next_hop_groups { - next_hop_group { - id: 200 - next_hops { # reference to a next-hop - next_hop: { - index: 200 - } - } - } + } + } + next_hop_group_id: "nhg_A" # new OC path /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/ + network_instance: "DEFAULT" +} + +# +# entries used for network-instance "NI_B" +IPv6Entry {2001:DB8:2::2/128 (NI_B)} -> NHG#200 (DEFAULT VRF) +IPv4Entry {203.0.113.2/32 (NI_B)} -> NHG#200 (DEFAULT VRF) -> { + {NH#201, DEFAULT VRF} +} + +NH#201 -> { + encap_headers { + encap_header { + index: 1 + mpls { + pushed_mpls_label_stack: [201,] } - next_hops { - next_hop { - index: 200 - network_instance: "group_B" - encap-headers { - encap-header { - index: 1 - type : OPENCONFIG_AFT_TYPES:MPLS - mpls { - pushed_mpls_label_stack: [200,] - } - } - } - encap-headers { - encap-header { - index: 2 - type: OPENCONFIG_AFT_TYPES:UDP - udp { - src_ip: "outer_ipv6_src" - dst_ip: "outer_ipv6_dst_B" - dst_udp_port: "outer_dst_udp_port" - ip_ttl: "outer_ip-ttl" - dscp: "outer_dscp" - } - } - } - } + } + encap_header { + index: 2 + udp_v6 { + src_ip: "outer_ipv6_src" + dst_ip: "outer_ipv6_dst_B" + dst_udp_port: "outer_dst_udp_port" + ip_ttl: "outer_ip-ttl" + dscp: "outer_dscp" } } } + next_hop_group_id: "nhg_B" + # network_instance: "DEFAULT" TODO: requires new OC path /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/network-instance } ``` * Send traffic from ATE port 1 to DUT port 1 -* Validate afts next hop counters * Using OTG, validate ATE port 2 receives MPLS-IN-UDP packets * Validate destination IPs are outer_ipv6_dst_A and outer_ipv6_dst_B * Validate MPLS label is set @@ -168,36 +118,66 @@ network_instances: { Canonical OpenConfig for policy forwarding, matching IP prefix with action encapsulate in GRE. -```yaml -openconfig-network-instance: - network-instances: - - network-instance: "group_A" - afts: - policy-forwarding: - policies: - policy: "default encap rule" - config: - policy-id: "default encap rule" - type: PBR_POLICY - rules: - rule: 1 - config: - sequence-id: 1 - ipv6: - config: - destination-address: "inner_ipv6_default" - action: - encapsulate-mpls-in-gre: # TODO: add to OC model/PR in progress - targets: - target: "default_dst_1" - config: - id: "default_dst_1" - network-instance: "DEFAULT" - source-ip: "outer_ipv6_src" - destination-ip: "outer_ipv6_dst_def" - ip-ttl: outer_ip-ttl - dscp: outer_dscp - inner-ttl-min: 2 +```json +{ + "openconfig-network-instance": { + "network-instances": [ + { + "afts": { + "policy-forwarding": { + "policies": [ + { + "config": { + "policy-id": "default encap rule", + "type": "PBR_POLICY" + }, + "policy": "default encap rule", + "rules": [ + { + "action": { + "encapsulate-headers": [ + { + "encapsulate-header": null, + "gre": { + "config": { + "destination-ip": "outer_ipv6_dst_def", + "dscp": "outer_dscp", + "id": "default_dst_1", + "ip-ttl": "outer_ip-ttl", + "source-ip": "outer_ipv6_src" + } + }, + "mpls": { + "mpls-label-stack": [ + 100 + ] + } + } + ], + "config": { + "network-instance": "DEFAULT" + } + }, + "config": { + "sequence-id": 1, + }, + "ipv6": { + "config": { + "destination-address": "inner_ipv6_default" + } + }, + "rule": 1 + } + ] + } + ] + } + }, + "network-instance": "group_A" + } + ] + } +} ``` * Generate the policy forwarding configuration @@ -263,7 +243,7 @@ openconfig-network-instance: config: destination-address: "decap_loopback_ipv6" action: - decapsulate-mpls-in-udp: TRUE + decapsulate-mpls-in-udp: TRUE ``` * Push the gNMI the policy forwarding configuration @@ -273,36 +253,53 @@ openconfig-network-instance: * Generate traffic from ATE port 1 * Validate ATE port 2 receives the innermost IPv4 traffic with correct VLAN and inner_decap_ipv6 -### TE-18.1.5 - Policy forwarding to encap and forward for BGP packets - -TODO: Specify a solution for ensuring BGP packets are matched, encapsulated -and forwarding to a specified destination using OC policy-forwarding terms. - ## OpenConfig Path and RPC Coverage ```yaml paths: # afts state paths set via gRIBI - # TODO: https://github.com/openconfig/public/pull/1153 - - #/network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id: - #/network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/next-hop-group-id: - #/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index: - #/network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/network-instance: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/index: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/type: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/mpls/pushed-mpls-label-stack: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/udp/src-ip: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/udp/dst-ip: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/udp/dst-udp-port: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/udp/ip-ttl: - #/network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/udp/dscp: - -# afts next-hop counters - /network-instances/network-instance/afts/next-hops/next-hop/state/counters/packets-forwarded: - /network-instances/network-instance/afts/next-hops/next-hop/state/counters/octets-forwarded: - + # TODO: need new OC for user defined next-hop-group/state/id, needed for policy-forwarding rules pointing to a NHG + # /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/next-hop-group-id: + + # TODO: new OC path for aft NHG pointing to a different network-instance + # /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/network-instance: + + # Paths added for TE-18.1.1 Match and Encapsulate using gRIBI aft modify + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/index: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/state/type: + + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/mpls/state/mpls-label-stack: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v4/state/src-ip: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v4/state/dst-ip: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v4/state/dst-udp-port: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v4/state/ip-ttl: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v4/state/dscp: + + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v6/state/src-ip: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v6/state/dst-ip: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v6/state/dst-udp-port: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v6/state/ip-ttl: + /network-instances/network-instance/afts/next-hops/next-hop/encap-headers/encap-header/udp-v6/state/dscp: + + # Paths added for TE-18.1.2 Validate prefix match rule for MPLS in GRE encap using default route + /network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/network-instance: + /network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/config/sequence-id: + #/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/encap-headers/encap-header/mpls/config/mpls-label-stack: + #/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/encap-headers/encap-header/gre/config/destination-ip: + #/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/encap-headers/encap-header/gre/config/dscp: + #/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/encap-headers/encap-header/gre/config/id: + #/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/encap-headers/encap-header/gre/config/ip-ttl: + #/network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/encap-headers/encap-header/gre/config/source-ip: + + # Paths added for TE-18.1.3 - MPLS in GRE decapsulation set by gNMI + /network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/config/destination-address: + # TODO: /network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/decapsulate-mpls-in-gre: + + # Paths added for TE-18.1.4 - MPLS in UDP decapsulation set by gNMI + /network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/config/decapsulate-mpls-in-udp: rpcs: gnmi: @@ -313,9 +310,8 @@ rpcs: on_change: true gribi: gRIBI.Modify: - network-instances:network-instance:afts:next-hops:next-hop:encapsulate_header: - network-instances:network-instance:afts:next-hops:next-hop:mpls-in-udp: - network-instances:network-instance:afts:next-hops:next-hop:decapsulate_header: + afts:next-hops:next-hop:encap-headers:encap-header:udp_v6: + afts:next-hops:next-hop:encap-headers:encap-header:mpls: gRIBI.Flush: ``` diff --git a/feature/gribi/otg_tests/mpls_in_udp_scale/README.md b/feature/gribi/otg_tests/mpls_in_udp_scale/README.md new file mode 100644 index 00000000000..e2f42b8c481 --- /dev/null +++ b/feature/gribi/otg_tests/mpls_in_udp_scale/README.md @@ -0,0 +1,145 @@ +# TE-18.3 MPLS in UDP Encapsulation with QoS Scheduler Scale Test + +Building on TE-18.1 and TE-18.2, add scaling parameters + +## Topology + +* 32 ports as the 'input port set' +* 4 ports as "uplink facing" +* VLAN configurations + * input vlans are distributed evenly across the 'input port set' + +## Test setup + +TODO: Complete test environment setup steps + +inner_ipv6_dst_A = "2001:aa:bb::1/128" +inner_ipv6_dst_B = "2001:aa:bb::2/128" +inner_ipv6_default = "::/0" + +ipv4_inner_dst_A = "10.5.1.1/32" +ipv4_inner_dst_B = "10.5.1.2/32" +ipv4_inner_default = "0.0.0.0/0" + +outer_ipv6_src = "2001:f:a:1::0" +outer_ipv6_dst_A = "2001:f:c:e::1" +outer_ipv6_dst_B = "2001:f:c:e::2" +outer_ipv6_dst_def = "2001:1:1:1::0" +outer_dst_udp_port = "5555" +outer_dscp = "26" +outer_ip-ttl = "64" + +## Procedure + +### TE-18.3.1 Scale + +#### Scale targets + +* Flow scale + * 20,000 IPv4/IPv6 destinations + * 1,000 vlans + * Inner IP address space should be reused for each network-instance. + * gRIBI client update rate `flow_r` = 1 update per second + * Each gRIBI update include ip entries in batches of `flow_q` = 200 + * DUT packet forwarding updated within 1 second after adding entries + +* Scheduler (policer) scale + * 1,000 policer rates + * 20,000 policer-policies / token buckets instantiations + * Update policer-policies at 1 per `sched_r` = 60 seconds + * Update policer-policies in a batch of `sched_q` = 1,000 + * Policer-policies changes should take effect within `sched_r` / 2 time + +#### Scale profile A - many vlans + +* 20 ip destinations * 1,000 vlans = 20,000 'flows' +* Each ingress vlan has 20 policer-policies = 10,000 'token buckets' +* The 20 ip destinations are split evenly between the 20 policers +* Each policer is assigned rate limits matching one of 800 different possible limits between 1Gbps to 400Gbps in 0.5Gbps increments + +#### Scale profile B - many destinations, few vlans + +* 200 ip destinations * 100 vlans = 20,000 'flows' +* Each ingress vlan has 4 policer-policies = 4,000 'token buckets' +* The 200 ip destinations are split evenly between the 4 policers +* Each policer is assigned rate limits matching one of 800 different possible limits between 1Gbps to 400Gbps in 0.5Gbps increments + +#### Procedure - Flow Scale + +* For each scale profile, create the following subsets TE-18.1.5.n + * Configure ATE flows to send 100 pps per flow and wait for ARP + * Send traffic for q flows (destination IP prefixes) for 2 seconds + * At traffic start time, gRIBI client to send `flow_q` aft entries and their + related NHG and NH at rate `flow_r` + * Validate RIB_AND_FIB_ACK with FIB_PROGRAMMED is received from DUT within + 1 second + * Measure packet loss. Target packet loss <= 50%. + * Repeat adding 200 flows until 20,000 flows have been added + * Once reaching 20,000 flows, perform 1 iteration of modifying the first + `flow_q` flows to use different NH,NHG + +#### Procedure - Policer + Flow Scale + +* For each scale profile, create the following subsets TE-18.1.6.n + * Program all 20,000 flows + * Every `sched_r` interval use gnmi.Set to replace `sched_q` scheduler policies + * Verify packet loss changes for all flows within `sched_r` / 2 time + +#### OpenConfig Path and RPC Coverage + +```yaml +paths: + # qos scheduler config + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/cir: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/bc: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/queuing-behavior: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/drop: + + # qos classifier config + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/terms/term/config/id: + #/qos/classifiers/classifier/terms/term/conditions/next-hop-group/config/name: # TODO: new OC leaf to be added + + # qos input-policies config - TODO: a new OC subtree (/qos/input-policies) + # /qos/input-policies/input-policy/config/name: + # /qos/input-policies/input-policy/config/classifier: + # /qos/input-policies/input-policy/config/scheduler-policy: + + # qos interface config + #/qos/interfaces/interface/subinterface/input/config/policies: # TODO: new OC leaf-list (/qos/interfaces/interface/input/config/policies) + + # qos interface scheduler counters + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-pkts: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-octets: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-pkts: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-octets: + + # afts next-hop counters + /network-instances/network-instance/afts/next-hops/next-hop/state/counters/packets-forwarded: + /network-instances/network-instance/afts/next-hops/next-hop/state/counters/octets-forwarded: + + # afts state paths set via gRIBI + # TODO: https://github.com/openconfig/public/pull/1153 + #/network-instances/network-instance/afts/next-hops/next-hop/mpls-in-udp/state/src-ip: + #/network-instances/network-instance/afts/next-hops/next-hop/mpls-in-udp/state/dst-ip: + #/network-instances/network-instance/afts/next-hops/next-hop/mpls-in-udp/state/ip-ttl: + #/network-instances/network-instance/afts/next-hops/next-hop/mpls-in-udp/state/dst-udp-port: + #/network-instances/network-instance/afts/next-hops/next-hop/mpls-in-udp/state/dscp: + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true + gribi: + gRIBI.Modify: + gRIBI.Flush: +``` + +## Required DUT platform + +* FFF diff --git a/feature/experimental/gribi/otg_tests/route_addition_during_failover_test/README.md b/feature/gribi/otg_tests/route_addition_during_failover_test/README.md similarity index 100% rename from feature/experimental/gribi/otg_tests/route_addition_during_failover_test/README.md rename to feature/gribi/otg_tests/route_addition_during_failover_test/README.md diff --git a/feature/experimental/gribi/otg_tests/route_addition_during_failover_test/metadata.textproto b/feature/gribi/otg_tests/route_addition_during_failover_test/metadata.textproto similarity index 100% rename from feature/experimental/gribi/otg_tests/route_addition_during_failover_test/metadata.textproto rename to feature/gribi/otg_tests/route_addition_during_failover_test/metadata.textproto diff --git a/feature/experimental/gribi/otg_tests/route_addition_during_failover_test/route_addition_during_failover_test.go b/feature/gribi/otg_tests/route_addition_during_failover_test/route_addition_during_failover_test.go similarity index 100% rename from feature/experimental/gribi/otg_tests/route_addition_during_failover_test/route_addition_during_failover_test.go rename to feature/gribi/otg_tests/route_addition_during_failover_test/route_addition_during_failover_test.go diff --git a/feature/experimental/gribi/otg_tests/route_removal_during_failover_test/README.md b/feature/gribi/otg_tests/route_removal_during_failover_test/README.md similarity index 100% rename from feature/experimental/gribi/otg_tests/route_removal_during_failover_test/README.md rename to feature/gribi/otg_tests/route_removal_during_failover_test/README.md diff --git a/feature/experimental/gribi/otg_tests/route_removal_during_failover_test/metadata.textproto b/feature/gribi/otg_tests/route_removal_during_failover_test/metadata.textproto similarity index 100% rename from feature/experimental/gribi/otg_tests/route_removal_during_failover_test/metadata.textproto rename to feature/gribi/otg_tests/route_removal_during_failover_test/metadata.textproto diff --git a/feature/experimental/gribi/otg_tests/route_removal_during_failover_test/route_removal_during_failover_test.go b/feature/gribi/otg_tests/route_removal_during_failover_test/route_removal_during_failover_test.go similarity index 100% rename from feature/experimental/gribi/otg_tests/route_removal_during_failover_test/route_removal_during_failover_test.go rename to feature/gribi/otg_tests/route_removal_during_failover_test/route_removal_during_failover_test.go diff --git a/feature/gribi/otg_tests/route_removal_non_default_vrf_test/route_removal_non_default_vrf_test.go b/feature/gribi/otg_tests/route_removal_non_default_vrf_test/route_removal_non_default_vrf_test.go index ae25736b1dc..b7f5ab7802c 100644 --- a/feature/gribi/otg_tests/route_removal_non_default_vrf_test/route_removal_non_default_vrf_test.go +++ b/feature/gribi/otg_tests/route_removal_non_default_vrf_test/route_removal_non_default_vrf_test.go @@ -400,7 +400,7 @@ func injectEntries(ctx context.Context, t *testing.T, dut *ondatra.DUTDevice, cl t.Logf("Add an IPv4Entry for %s pointing to ATE port-2 via gRIBI client", ateDstNetCIDR) client.AddNH(t, nhIndex, atePort2.IPv4, deviations.DefaultNetworkInstance(dut), fluent.InstalledInRIB) client.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, deviations.DefaultNetworkInstance(dut), fluent.InstalledInRIB) - client.AddIPv4(t, ateDstNetCIDR, nhgIndex, networkInstanceName, deviations.DefaultNetworkInstance(dut), fluent.InstalledInRIB) + injectIPEntry(ctx, t, dut, client, networkInstanceName, ateDstNetCIDR) } // injectIPEntry adds only IPv4 entry to the specified network instance referencing to the nhgid, to the VRF. diff --git a/feature/gribi/otg_tests/static_lsp_test/static_lsp_test.go b/feature/gribi/otg_tests/static_lsp_test/static_lsp_test.go index 712f8ebed32..46ad3a5a7c1 100644 --- a/feature/gribi/otg_tests/static_lsp_test/static_lsp_test.go +++ b/feature/gribi/otg_tests/static_lsp_test/static_lsp_test.go @@ -142,14 +142,18 @@ func configureOTG(t *testing.T) gosnappi.Config { // configureStaticLSP configures a static MPLS LSP with the provided parameters. func configureStaticLSP(t *testing.T, dut *ondatra.DUTDevice, lspName string, incomingLabel uint32, nextHopIP string) { d := &oc.Root{} - mplsCfg := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)).GetOrCreateMpls() + dni := deviations.DefaultNetworkInstance(dut) + defPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)) + gnmi.Update(t, dut, defPath.Config(), &oc.NetworkInstance{ + Name: ygot.String(deviations.DefaultNetworkInstance(dut)), + Type: oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_DEFAULT_INSTANCE, + }) + mplsCfg := d.GetOrCreateNetworkInstance(dni).GetOrCreateMpls() staticMplsCfg := mplsCfg.GetOrCreateLsps().GetOrCreateStaticLsp(lspName) staticMplsCfg.GetOrCreateEgress().SetIncomingLabel(oc.UnionUint32(incomingLabel)) staticMplsCfg.GetOrCreateEgress().SetNextHop(nextHopIP) staticMplsCfg.GetOrCreateEgress().SetPushLabel(oc.Egress_PushLabel_IMPLICIT_NULL) - gnmi.Update(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Mpls().Config(), mplsCfg) - } func createTrafficFlow(t *testing.T, diff --git a/feature/experimental/gribi/otg_tests/vrf_policy_driven_te/README.md b/feature/gribi/otg_tests/vrf_policy_driven_te/README.md similarity index 100% rename from feature/experimental/gribi/otg_tests/vrf_policy_driven_te/README.md rename to feature/gribi/otg_tests/vrf_policy_driven_te/README.md diff --git a/feature/experimental/gribi/otg_tests/vrf_policy_driven_te/metadata.textproto b/feature/gribi/otg_tests/vrf_policy_driven_te/metadata.textproto similarity index 100% rename from feature/experimental/gribi/otg_tests/vrf_policy_driven_te/metadata.textproto rename to feature/gribi/otg_tests/vrf_policy_driven_te/metadata.textproto diff --git a/feature/experimental/gribi/otg_tests/vrf_policy_driven_te/vrf_policy_driven_te_test.go b/feature/gribi/otg_tests/vrf_policy_driven_te/vrf_policy_driven_te_test.go similarity index 99% rename from feature/experimental/gribi/otg_tests/vrf_policy_driven_te/vrf_policy_driven_te_test.go rename to feature/gribi/otg_tests/vrf_policy_driven_te/vrf_policy_driven_te_test.go index 136cf377d60..e8ed9a01ae0 100644 --- a/feature/experimental/gribi/otg_tests/vrf_policy_driven_te/vrf_policy_driven_te_test.go +++ b/feature/gribi/otg_tests/vrf_policy_driven_te/vrf_policy_driven_te_test.go @@ -666,12 +666,6 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { for idx, a := range []attrs.Attributes{dutPort1, dutPort2, dutPort3, dutPort4, dutPort5, dutPort6, dutPort7, dutPort8} { p := portList[idx] intf := a.NewOCInterface(p.Name(), dut) - if p.PMD() == ondatra.PMD100GBASEFR && dut.Vendor() != ondatra.CISCO { - e := intf.GetOrCreateEthernet() - e.AutoNegotiate = ygot.Bool(false) - e.DuplexMode = oc.Ethernet_DuplexMode_FULL - e.PortSpeed = oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB - } gnmi.Replace(t, dut, d.Interface(p.Name()).Config(), intf) } diff --git a/feature/gribi/vrf_policy_driven_te/README.md b/feature/gribi/vrf_policy_driven_te/README.md deleted file mode 100644 index 41630244a0d..00000000000 --- a/feature/gribi/vrf_policy_driven_te/README.md +++ /dev/null @@ -1,819 +0,0 @@ -# TE-17.1 VRF selection policy driven TE - -## Summary - -Test VRF selection logic involving different decapsulation and encapsulation lookup scenarios via gRIBI. - -## Topology - -ATE port-1 <------> port-1 DUT -DUT port-2 <------> port-2 ATE -DUT port-3 <------> port-3 ATE -DUT port-4 <------> port-4 ATE -DUT port-5 <------> port-5 ATE -DUT port-6 <------> port-6 ATE -DUT port-7 <------> port-7 ATE -DUT port-8 <------> port-8 ATE - -## Variables - -``` -# DSCP value that will be matched to ENCAP_TE_VRF_A -* dscp_encap_a_1 = 10 -* dscp_encap_a_2 = 18 - -# DSCP value that will be matched to ENCAP_TE_VRF_B -* dscp_encap_b_1 = 20 -* dscp_encap_b_2 = 28 - -# DSCP value that will NOT be matched to any VRF for encapsulation. -* dscp_encap_no_match = 30 - -# Magic source IP addresses used in VRF selection policy -* ipv4_outer_src_111 = 198.51.100.111 -* ipv4_outer_src_222 = 198.51.100.222 - -# Magic destination MAC address -* magic_mac = 02:00:00:00:00:01` -``` - -vrf_selection_policy_c -``` -network-instances { - network-instance { - name: DEFAULT - policy-forwarding { - policies { - policy { - policy-id: "vrf_selection_policy_c" - rules { - rule { - sequence-id: 1 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 2 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 3 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 4 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 5 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 6 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 7 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 8 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 9 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 10 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 11 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 12 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 13 - ipv4 { - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - } - action { - network-instance: "ENCAP_TE_VRF_A" - } - } - rule { - sequence-id: 14 - ipv6 { - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - } - action { - network-instance: "ENCAP_TE_VRF_A" - } - } - rule { - sequence-id: 15 - ipv4 { - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - } - action { - network-instance: "ENCAP_TE_VRF_B" - } - } - rule { - sequence-id: 16 - ipv6 { - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - } - action { - network-instance: "ENCAP_TE_VRF_B" - } - } - rule { - sequence-id: 17 - action { - network-instance: "DEFAULT" - } - } - } - } - } - } - } -} -``` - -vrf_selection_policy_w -``` -network-instances { - network-instance { - name: DEFAULT - policy-forwarding { - policies { - policy { - policy-id: "vrf_selection_policy_w" - rules { - rule { - sequence-id: 1 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 2 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 3 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 4 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_a_1, dscp_encap_a_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_A" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 5 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 6 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 7 - ipv4 { - protocol: 4 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 8 - ipv4 { - protocol: 41 - dscp-set: [dscp_encap_b_1, dscp_encap_b_2] - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "ENCAP_TE_VRF_B" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 9 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 10 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_222" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_222" - } - } - rule { - sequence-id: 11 - ipv4 { - protocol: 4 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 12 - ipv4 { - protocol: 41 - source-address: "ipv4_outer_src_111" - } - action { - decap-network-instance: "DECAP_TE_VRF" - post-network-instance: "DEFAULT" - decap-fallback-network-instance: "TE_VRF_111" - } - } - rule { - sequence-id: 13 - action { - network-instance: "DEFAULT" - } - } - } - } - } - } - } -} -``` - -## Baseline - -* Install the following gRIBI AFTs. - -``` -IPv4Entry {138.0.11.0/24 (ENCAP_TE_VRF_A)} -> NHG#101 (DEFAULT VRF) -> { - {NH#101, DEFAULT VRF, weight:1}, - {NH#102, DEFAULT VRF, weight:3}, - backup_next_hop_group: 200 // in case specific vendor implementation or bugs pruned the NHs. -} -IPv4Entry {138.0.11.0/24 (ENCAP_TE_VRF_B)} -> NHG#102 (DEFAULT VRF) -> { - {NH#101, DEFAULT VRF, weight:3}, - {NH#102, DEFAULT VRF, weight:1}, - backup_next_hop_group: 200 // in case specific vendor implementation or bugs pruned the NHs. -} -NH#101 -> { - encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - ip_in_ip { - dst_ip: "203.0.113.1" - src_ip: "ipv4_outer_src_111" - } - network_instance: "TE_VRF_111" -} -NH#102 -> { - encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - ip_in_ip { - dst_ip: "203.10.113.2" - src_ip: "ipv4_outer_src_111" - } - network_instance: "TE_VRF_111" -} - -NHG#200 (Default VRF) { - {NH#200, DEFAULT VRF, weight:1} -} -NH#200 -> { - network_instance: "DEFAULT" -} - -IPv4Entry {203.0.113.1/32 (TE_VRF_111)} -> NHG#1 (DEFAULT VRF) -> { - {NH#1, DEFAULT VRF, weight:1,ip_address=192.0.2.101}, - {NH#2, DEFAULT VRF, weight:3,ip_address=192.0.2.102}, - backup_next_hop_group: 1000 // re-encap to 203.0.113.100 -} -IPv4Entry {192.0.2.101/32 (DEFAULT VRF)} -> NHG#11 (DEFAULT VRF) -> { - {NH#11, DEFAULT VRF, weight:1,mac_address:magic_mac, interface-ref:dut-port-2-interface}, - {NH#12, DEFAULT VRF, weight:3,mac_address:magic_mac, interface-ref:dut-port-3-interface}, -} -IPv4Entry {192.0.2.102/32 (DEFAUlT VRF)} -> NHG#12 (DEFAULT VRF) -> { - {NH#13, DEFAULT VRF, weight:2,mac_address:magic_mac, interface-ref:dut-port-4-interface}, -} - -NHG#1000 (Default VRF) { - {NH#1000, DEFAULT VRF} -} -NH#1000 -> { - decapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - ip_in_ip { - dst_ip: "203.0.113.100" - src_ip: "ipv4_outer_src_222" - } - network_instance: "TE_VRF_222" -} - -IPv4Entry {203.0.113.100/32 (TE_VRF_222)} -> NHG#2 (DEFAULT VRF) -> { - {NH#3, DEFAULT VRF, weight:1,ip_address=192.0.2.103}, - backup_next_hop_group: 1001 // decap to DEFAULT VRF -} -IPv4Entry {192.0.2.103/32 (DEFAULT VRF)} -> NHG#13 (DEFAULT VRF) -> { - {NH#14, DEFAULT VRF, weight:1,mac_address:magic_mac, interface-ref:dut-port-5-interface}, -} -NHG#1001 (Default VRF) { - {NH#2001, DEFAULT VRF, weight:1} -} -NH#1001 -> { - decapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - network_instance: "DEFAULT" -} - -// 203.10.113.2 is the tunnel IP address. Note that the NHG#3 is different than NHG#1. - -IPv4Entry {203.10.113.2/32 (TE_VRF_111)} -> NHG#3 (DEFAULT VRF) -> { - {NH#4, DEFAULT VRF, weight:1,ip_address=192.0.2.104}, - backup_next_hop_group: 1002 // re-encap to 203.10.113.101 -} -IPv4Entry {192.0.2.104/32 (DEFAULT VRF)} -> NHG#14 (DEFAULT VRF) -> { - {NH#15, DEFAULT VRF, weight:1,mac_address:magic_mac, interface-ref:dut-port-6-interface}, -} -NHG#1002 (DEFAULT VRF) { - {NH#1002, DEFAULT VRF} -} -NH#1002 -> { - decapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - encapsulate_header: OPENCONFIGAFTTYPESENCAPSULATIONHEADERTYPE_IPV4 - ip_in_ip { - dst_ip: "203.0.113.101" - src_ip: "ipv4_outer_src_222" - } - network_instance: "TE_VRF_222" -} -IPv4Entry {203.0.113.101/32 (TE_VRF_222)} -> NHG#4 (DEFAULT VRF) -> { - {NH#5, DEFAULT VRF, weight:1,ip_address=192.0.2.103}, - backup_next_hop_group: 1001 // decap to DEFAULT VRF -} -IPv4Entry {192.0.2.103/32 (DEFAULT VRF)} -> NHG#15 (DEFAULT VRF) -> { - {NH#16, DEFAULT VRF, weight:1,mac_address:magic_mac, interface-ref:dut-port-7-interface}, -} - -``` - -* Install a BGP route resolved by ISIS in default VRF to rout traffic out of DUT port-8. - -* Install an 0/0 static route in ENCAP_VRF_A and ENCAP_VRF_B pointing to the DEFAULT VRF. - -## Procedure - -The DUT should be reset to the baseline after each of the following tests. - -#### Test-1, match on source and protocol, no match on DSCP; flow VRF_DECAP hit -> DEFAULT - -1. Using gRIBI to install the following entries in the `DECAP_TE_VRF`: - - ``` - IPv4Entry {192.51.100.1/24 (DECAP_TE_VRF)} -> NHG#1001 (DEFAULT VRF) -> { - {NH#1001, DEFAULT VRF, weight:1} - } - NH#1001 -> { - decapsulate_header: OPENCONFIGAFTTYPESDECAPSULATIONHEADERTYPE_IPV4 - } - ``` - -2. Apply vrf selection policy `vrf_selection_policy_w` to DUT port-1. - -3. Send the following 6in4 and 4in4 flows to DUT port-1: - - ``` - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_no_match` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_no_match` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_no_match` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_no_match` - * proto: `41` - ``` - -4. Verify that the packets have their outer v4 header stripped and are forwarded out of DUT port-8 per the BGP-ISIS routes in the DEFAULT VRF. - -5. Verify that the TTL value is copied from the outer header to the inner header. - -6. Change the subnet mask from /24 and repeat the test for the masks /32, /22, and /28 and verify again that the packets are decapped and forwarded correctly. - -7. Repeat the test with packets with a destination address that does not match the decap entry, and verify that such packets are not decapped. - -#### Test-2, match on source, protocol and DSCP, VRF_DECAP hit -> VRF_ENCAP_A miss -> DEFAULT - -1. Using gRIBI to install the following entries in the `DECAP_TE_VRF`: - - ``` - IPv4Entry {192.51.100.1/24 (DECAP_TE_VRF)} -> NHG#1001 (DEFAULT VRF) -> { - {NH#1001, DEFAULT VRF, weight:1} - } - NH#1001 -> { - decapsulate_header: OPENCONFIGAFTTYPESDECAPSULATIONHEADERTYPE_IPV4 - } - ``` - -2. Apply vrf selection policy `vrf_selection_policy_w` to DUT port-1. - -3. Send the following 6in4 and 4in4 flows to DUT port-1: - - ``` - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_no_match` - * dscp: `dscp_encap_a_1` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_a_1` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_no_match` - * dscp: `dscp_encap_a_1` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_a_1` - * proto: `41` - ``` - -4. Verify that the packets have their outer v4 header stripped and are forwarded out of DUT port-8 per the BGP-ISIS routes in the DEFAULT VRF. - -5. Verify that the TTL value is copied from the outer header to the inner header. - -6. Change the subnet mask from /24 and repeat the test for the masks /32, /22, and /28 and verify again that the packets are decapped and forwarded correctly. - -#### Test-3, Mixed Prefix Decap gRIBI Entries - -Support for decap actions with mixed prefixes installed through gRIBI - -1. Add the following gRIBI entries: - - ``` - IPv4Entry {192.51.129.0/22 (DECAP_TE_VRF)} -> NHG#1001 (DEFAULT VRF) -> { - {NH#1001, DEFAULT VRF, weight:1} - } - IPv4Entry {192.55.200.3/32 (DECAP_TE_VRF)} -> NHG#1001 (DEFAULT VRF) -> { - {NH#1001, DEFAULT VRF, weight:1} - } - - NH#1001 -> { - decapsulate_header: OPENCONFIGAFTTYPESDECAPSULATIONHEADERTYPE_IPV4 - } - ``` - -2. Apply vrf selection policy `vrf_selection_policy_w` to DUT port-1. - -3. Send the following 6in4 and 4in4 flows to DUT port-1: - - ``` - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_no_match` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `192.51.100.64` - * dscp: `dscp_encap_no_match` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_no_match` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `192.55.200.3` - * dscp: `dscp_encap_no_match` - * proto: `41` - - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_no_match` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `192.51.128.5` - * dscp: `dscp_encap_no_match` - * proto: `4` - ``` - -4. Verify that the packets have their outer v4 header stripped, and are forwarded according to the route in the DEFAULT VRF that matches the inner IP address. - -5. Repeat the test with packets with a destination address such as that does not match the decap route, and verify that such packets are not decapped. - -#### Test-4: Tunneled traffic with no decap - -Ensures that tunneled traffic is correctly forwarded when there is no match in the DECAP_VRF. The intent of this test is to ensure that the VRF selection policy correctly sends these packets to either `TE_VRF_111` or `TE_VRF_222`. - -1. Apply vrf selection policy `vrf_selection_policy_c` to DUT port-1. -2. Send 4in4 (IP protocol 4) and 6in4 (IP protocol 41) packets to DUT port-1 where - * The outer v4 header has the destination address 203.0.113.1. - * The outer v4 header has the source address ipv4_outer_src_111. - * The outer v4 header has DSCP value has `dscp_encap_no_match` and `dscp_encap_match` -3. We should expect that all egress packets (100%) are IPinIP encapped with 203.0.113.1 as the outer header, and egress on DUT port-2, port-3, port-4 and port-6 per the hierarchical weight. -4. Send 4in4 (IP protocol 4) and 6in4 (IP protocol 41) packets to DUT port-2 where - * The outer v4 header has the destination address 203.0.113.100. - * The outer v4 header has the source address ipv4_outer_src_222. - * The outer v4 header has DSCP value has `dscp_encap_no_match` and `dscp_encap_match` -We should expect that the egress traffic are 100% encapped with 203.0.113.100 as the outer header, and egress on DUT port-5. - -#### Test-5: match on "default term", send to default VRF - -Tests support for TE disabled IPinIP IPv4 (IP protocol 4) cluster traffic arriving on WAN facing ports. Specifically, this test verifies the tunnel traffic identification using ipv4_outer_src_111 and ipv4_outer_src_222 in the VRF selection policy. - -1. Apply vrf selection policy `vrf_selection_policy_w` to DUT port-1. -2. Send 6in4 and 4in4 packets to DUT port-1, where: - * The outer v4 header has the destination address 138.0.11.8. - * The outer v4 header has the source address that’s not ipv4_outer_src_111 or ipv4_outer_src_222. For example, we can use 198.100.200.123. -3. We should expect that all egress packets: - * 100% are still IPinIP (4in4) with outer v4 destination address as `138.0.11.8`. - * and, egressed out of DUT port-8 per the route in the DEFAULT VRF. -4. Send v4 packet with protocol `17` (not 6in4 or 4in4), where: - * The outer v4 header has the destination address 138.0.11.8. - * 50% of the packets with source address as ipv4_outer_src_111. - * 50% of the packets with source address as ipv4_outer_src_222. -5. We should expect that all egress packets: - * 100% are still of protocl `17` and with outer v4 destination address as `138.0.11.8`. - * and, egressed out of DUT port-8 per the route in the DEFAULT VRF. -6. Remove the matching route (e.g. stop the BGP routes) in the DEFAULT VRF and verify that the traffic are dropped. - -#### Test-6, decap then encap - -1. Apply vrf selection policy `vrf_selection_policy_w` to DUT port-1. - -2. Send the following packets to DUT port-1: - - ``` - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_a_1` - * outter_src: `ipv4_outter_src_222` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_a_1` - * proto: `4` - ``` - - ``` - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_a_1` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_a_1` - * proto: `41` - ``` - -3. We should expect that all egress packets: - - * are IPinIP encapped with outer source IP as `ipv4_outter_src_111` and dscp value `dscp_encap_a_1`. - * 1/4 are with 203.0.113.1 as the outer header destination IP. - * 3/4 are with 203.10.113.2 as the outer header destination IPs. - * egress on DUT port-2, port-3, port-4 and port-6 per the hierarchical weight. - -4. Send the following packets to DUT port -1 - - ``` - * inner_src: `ipv4_inner_src` - * inner_dst: `ipv4_inner_encap_match` - * dscp: `dscp_encap_b_1` - * outter_src: `ipv4_outter_src_111` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_b_1` - * proto: `4` - - * inner_src: `ipv6_inner_src` - * inner_dst: `ipv6_inner_encap_match` - * dscp: `dscp_encap_b_1` - * outter_src: `ipv4_outter_src_222` - * outter_dst: `ipv4_outter_decap_match` - * dscp: `dscp_encap_b_1` - * proto: `41` - ``` - -5. We should expect that all egress packets: - - * are IPinIP encapped with outer source IP as `ipv4_outter_src_111` and dscp value `dscp_encap_b_1`. - * 3/4 are with 203.0.113.1 as the outer header destination IP. - * 1/4 are with 203.10.113.2 as the outer header destination IPs. - * egress on DUT port-2, port-3, port-4 and port-6 per the hierarchical weight. - - -## Config Parameter Coverage - -* network-instances/network-instance/name -* network-instances/network-instance/policy-forwarding/policies/policy/policy-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/post-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-fallback-network-instance - -## Telemetry Parameter Coverage - -* network-instances/network-instance/name -* network-instances/network-instance/policy-forwarding/policies/policy/policy-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/sequence-id -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv4/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/protocol -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/dscp-set -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/ipv6/source-address -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/post-network-instance -* network-instances/network-instance/policy-forwarding/policies/policy/rules/rule/action/decap-fallback-network-instance - -## Protocol/RPC Parameter Coverage - -* gRIBI: - * Modify - * ModifyRequest - -## Required DUT platform - -vRX \ No newline at end of file diff --git a/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/aggregate_all_not_forwarding_viable_test.go b/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/aggregate_all_not_forwarding_viable_test.go index 1128fbf265a..46229d70220 100644 --- a/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/aggregate_all_not_forwarding_viable_test.go +++ b/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/aggregate_all_not_forwarding_viable_test.go @@ -56,30 +56,35 @@ import ( ) const ( - ipv4PLen = 30 - ipv6PLen = 126 - isisInstance = "DEFAULT" - dutAreaAddress = "49.0001" - ateAreaAddress = "49" - dutSysID = "1920.0000.2001" - asn = 64501 - acceptRoutePolicy = "PERMIT-ALL" - trafficPPS = 2500000 - srcTrafficV4 = "100.0.1.1" - srcTrafficV6 = "2002:db8:64:64::1" - dstTrafficV4 = "100.0.2.1" - dstTrafficV6 = "2003:db8:64:64::1" - v4Count = 254 - v6Count = 100000000 - lagTypeLACP = oc.IfAggregate_AggregationType_LACP - ieee8023adLag = oc.IETFInterfaces_InterfaceType_ieee8023adLag - ethernetCsmacd = oc.IETFInterfaces_InterfaceType_ethernetCsmacd - LAG1 = "lag1" - LAG2 = "lag2" - LAG3 = "lag3" - niTeVrf111 = "TE_VRF_111" - niRepairVrf = "REPAIR_VRF" - pfx1AdvV4WithMask = "100.0.1.0/24" + ipv4PLen = 30 + ipv6PLen = 126 + isisInstance = "DEFAULT" + dutAreaAddress = "49.0001" + ateAreaAddress = "49" + dutSysID = "1920.0000.2001" + asn = 64501 + acceptRoutePolicy = "PERMIT-ALL" + trafficPPS = 1000 + srcTrafficV4 = "100.0.1.1" + srcTrafficV6 = "2002:db8:64:64::1" + dstTrafficV4 = "100.0.2.1" + dstTrafficV6 = "2003:db8:64:64::1" + v4Count = 254 + v6Count = 100000000 + lagTypeLACP = oc.IfAggregate_AggregationType_LACP + ieee8023adLag = oc.IETFInterfaces_InterfaceType_ieee8023adLag + ethernetCsmacd = oc.IETFInterfaces_InterfaceType_ethernetCsmacd + LAG1 = "lag1" + LAG2 = "lag2" + LAG3 = "lag3" + niTeVrf111 = "TE_VRF_111" + niRepairVrf = "REPAIR_VRF" + pfx1AdvV4WithMask = "100.0.1.0/24" + niTEVRF222 = "TE_VRF_222" + ipv4OuterSrc111Addr = "198.51.100.111" + gribiIPv4EntryVRF111 = "203.0.113.1" + ipv4OuterSrc222Addr = "198.51.100.222" + gribiIPv4EntryVRF222 = "203.0.113.100" ) type aggPortData struct { @@ -215,12 +220,17 @@ func TestAggregateAllNotForwardingViable(t *testing.T) { }) t.Run("RT-5.7.1.2: Setting Forwarding-Viable to False for Lag2 all ports", func(t *testing.T) { // Ensure ISIS Adjacency is up on LAG_2 - if ok := awaitAdjacency(t, dut, aggIDs[1], oc.Isis_IsisInterfaceAdjState_UP); !ok { + if ok := awaitAdjacency(t, dut, aggIDs[1], []oc.E_Isis_IsisInterfaceAdjState{oc.Isis_IsisInterfaceAdjState_UP}); !ok { t.Fatal("ISIS Adjacency is Down on LAG_2") } - configForwardingViable(t, dut, dutPortList[1:2], false) + configForwardingViable(t, dut, dutPortList[1:agg2.ateLagCount+1], false) // Ensure ISIS Adjacency is Down on LAG_2 + if ok := awaitAdjacency(t, dut, aggIDs[1], []oc.E_Isis_IsisInterfaceAdjState{oc.Isis_IsisInterfaceAdjState_INIT, oc.Isis_IsisInterfaceAdjState_DOWN}); !ok { + if presence := gnmi.LookupAll(t, dut, ocpath.Root().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis().Interface(aggIDs[1]).LevelAny().AdjacencyAny().AdjacencyState().State()); len(presence) > 0 { + t.Fatalf("ISIS Adjacency is Established on LAG_2 ") + } + } startTraffic(t, dut, ate, top) if err := confirmNonViableForwardingTraffic(t, dut, ate, atePortList[1:agg2.ateLagCount+1], dutPortList[1:agg2.ateLagCount+1]); err != nil { t.Fatal(err) @@ -261,7 +271,7 @@ func TestAggregateAllNotForwardingViable(t *testing.T) { t.Run("RT-5.7.1.4: Setting Forwarding-Viable to False and Down some Port on Lag2", func(t *testing.T) { // Ensure ISIS Adjacency is up on LAG_2 - if ok := awaitAdjacency(t, dut, aggIDs[1], oc.Isis_IsisInterfaceAdjState_UP); !ok { + if ok := awaitAdjacency(t, dut, aggIDs[1], []oc.E_Isis_IsisInterfaceAdjState{oc.Isis_IsisInterfaceAdjState_UP}); !ok { t.Fatal("ISIS Adjacency is Down on LAG_2") } configForwardingViable(t, dut, dutPortList[1:agg2.ateLagCount+1], false) @@ -337,10 +347,16 @@ func TestAggregateAllNotForwardingViable(t *testing.T) { t.Run("RT-5.7.2.2: Setting Forwarding-Viable to False for Lag2 all ports", func(t *testing.T) { // Ensure ISIS Adjacency is up on LAG_2 - if ok := awaitAdjacency(t, dut, aggIDs[1], oc.Isis_IsisInterfaceAdjState_UP); !ok { + if ok := awaitAdjacency(t, dut, aggIDs[1], []oc.E_Isis_IsisInterfaceAdjState{oc.Isis_IsisInterfaceAdjState_UP}); !ok { t.Fatal("ISIS Adjacency is Down on LAG_2") } - configForwardingViable(t, dut, dutPortList[1:2], false) + configForwardingViable(t, dut, dutPortList[1:agg2.ateLagCount+1], false) + // Ensure ISIS Adjacency is Down on LAG_2 + if ok := awaitAdjacency(t, dut, aggIDs[1], []oc.E_Isis_IsisInterfaceAdjState{oc.Isis_IsisInterfaceAdjState_INIT, oc.Isis_IsisInterfaceAdjState_DOWN}); !ok { + if presence := gnmi.LookupAll(t, dut, ocpath.Root().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis().Interface(aggIDs[1]).LevelAny().AdjacencyAny().AdjacencyState().State()); len(presence) > 0 { + t.Fatalf("ISIS Adjacency is Established on LAG_2") + } + } startTraffic(t, dut, ate, top) if err := confirmNonViableForwardingTraffic(t, dut, ate, atePortList[1:(agg2.ateLagCount+1)], dutPortList[1:(agg2.ateLagCount+1)]); err != nil { t.Fatal(err) @@ -377,7 +393,7 @@ func TestAggregateAllNotForwardingViable(t *testing.T) { t.Run("RT-5.7.2.4: Setting Forwarding-Viable to False and Down some Port on Lag2", func(t *testing.T) { // Ensure ISIS Adjacency is up on LAG_2 - if ok := awaitAdjacency(t, dut, aggIDs[1], oc.Isis_IsisInterfaceAdjState_UP); !ok { + if ok := awaitAdjacency(t, dut, aggIDs[1], []oc.E_Isis_IsisInterfaceAdjState{oc.Isis_IsisInterfaceAdjState_UP}); !ok { t.Fatal("ISIS Adjacency is Down on LAG_2") } configForwardingViable(t, dut, dutPortList[1:agg2.ateLagCount+1], false) @@ -432,7 +448,7 @@ func setDUTInterfaceWithState(t testing.TB, dut *ondatra.DUTDevice, ports []*ond func configNonDefaultNetworkInstance(t *testing.T, dut *ondatra.DUTDevice) { t.Helper() c := &oc.Root{} - vrfs := []string{niTeVrf111, niRepairVrf} + vrfs := []string{niTeVrf111, niRepairVrf, niTEVRF222} for _, vrf := range vrfs { ni := c.GetOrCreateNetworkInstance(vrf) ni.Type = oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_L3VRF @@ -451,7 +467,9 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) []string { if len(dut.Ports()) > 4 { agg2.ateLagCount = uint32(len(dut.Ports()) - 3) agg3.ateLagCount = 2 - trafficDistributionWeights = []uint64{33, 67} + if dut.Vendor() != ondatra.CISCO { + trafficDistributionWeights = []uint64{33, 67} + } } var aggIDs []string for _, a := range []*aggPortData{agg1, agg2, agg3} { @@ -989,9 +1007,18 @@ func installGRIBIRoutes(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDe WithIndex(uint64(1000)).WithIPAddress(agg3.ateIPv4), fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). WithID(uint64(1000)).AddNextHop(uint64(1000), uint64(1)), + fluent.IPv4Entry().WithNetworkInstance(niTEVRF222).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix(gribiIPv4EntryVRF222+"/32").WithNextHopGroup(1000), - fluent.IPv4Entry().WithNetworkInstance(niRepairVrf).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(pfx4AdvV4.ip+"/24").WithNextHopGroup(1000)) + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(2000).WithDecapsulateHeader(fluent.IPinIP).WithEncapsulateHeader(fluent.IPinIP). + WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF222). + WithNextHopNetworkInstance(niTEVRF222), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(2000).AddNextHop(2000, 1), + + fluent.IPv4Entry().WithNetworkInstance(niRepairVrf).WithNextHopGroup(2000).WithPrefix(gribiIPv4EntryVRF111+"/32"). + WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut))) if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, time.Minute); err != nil { t.Logf("Could not program entries via client, got err, check error codes: %v", err) @@ -999,7 +1026,7 @@ func installGRIBIRoutes(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDe chk.HasResult(t, tcArgs.client.Results(t), fluent.OperationResult(). - WithIPv4Operation(pfx4AdvV4.ip+"/24"). + WithIPv4Operation(gribiIPv4EntryVRF111+"/32"). WithOperationType(constants.Add). WithProgrammingResult(fluent.InstalledInFIB). AsResult(), @@ -1010,7 +1037,7 @@ func installGRIBIRoutes(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDe tcArgs.client.Modify().AddEntry(t, fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). WithIndex(uint64(1)).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP("100.0.1.254", "100.0.4.254"). + WithIPinIP(ipv4OuterSrc111Addr, gribiIPv4EntryVRF111). WithNextHopNetworkInstance(niTeVrf111), fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). WithID(uint64(1)).AddNextHop(uint64(1), uint64(1)), @@ -1032,7 +1059,7 @@ func installGRIBIRoutes(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDe chk.IgnoreOperationID(), ) - // Programming AFT entries for encapped prefixes "100.0.4.254/32" + // Programming AFT entries for encapped prefixes "203.0.113.1/32" tcArgs.client.Modify().AddEntry(t, fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). WithIndex(uint64(101)).WithIPAddress(agg2.ateIPv4), @@ -1040,7 +1067,7 @@ func installGRIBIRoutes(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDe WithID(uint64(101)).AddNextHop(uint64(101), uint64(1)).WithBackupNHG(3000), fluent.IPv4Entry().WithNetworkInstance(niTeVrf111). - WithPrefix("100.0.4.254/32").WithNextHopGroup(101). + WithPrefix(gribiIPv4EntryVRF111+"/32").WithNextHopGroup(101). WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)), ) @@ -1050,7 +1077,7 @@ func installGRIBIRoutes(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDe chk.HasResult(t, tcArgs.client.Results(t), fluent.OperationResult(). - WithIPv4Operation("100.0.4.254/32"). + WithIPv4Operation(gribiIPv4EntryVRF111+"/32"). WithOperationType(constants.Add). WithProgrammingResult(fluent.InstalledInFIB). AsResult(), @@ -1096,6 +1123,7 @@ func verifyTrafficFlow(t *testing.T, ate *ondatra.ATEDevice, flows []gosnappi.Fl rxPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flows[0].Name()).Counters().InPkts().State()) txPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flows[0].Name()).Counters().OutPkts().State()) lostPkt := txPkts - rxPkts + if status { if got := (lostPkt * 100 / txPkts); got >= 51 { return false @@ -1108,6 +1136,7 @@ func verifyTrafficFlow(t *testing.T, ate *ondatra.ATEDevice, flows []gosnappi.Fl rxPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flow.Name()).Counters().InPkts().State()) txPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flow.Name()).Counters().OutPkts().State()) lostPkt := txPkts - rxPkts + if got := (lostPkt * 100 / txPkts); got > 0 { return false } @@ -1117,15 +1146,19 @@ func verifyTrafficFlow(t *testing.T, ate *ondatra.ATEDevice, flows []gosnappi.Fl } // awaitAdjacency wait for adjacency to be up/down -func awaitAdjacency(t *testing.T, dut *ondatra.DUTDevice, intfName string, state oc.E_Isis_IsisInterfaceAdjState) bool { +func awaitAdjacency(t *testing.T, dut *ondatra.DUTDevice, intfName string, state []oc.E_Isis_IsisInterfaceAdjState) bool { isisPath := ocpath.Root().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis() intf := isisPath.Interface(intfName) query := intf.LevelAny().AdjacencyAny().AdjacencyState().State() _, ok := gnmi.WatchAll(t, dut, query, 90*time.Second, func(val *ygnmi.Value[oc.E_Isis_IsisInterfaceAdjState]) bool { v, ok := val.Val() - return v == state && ok + for _, s := range state { + if (v == s) && ok { + return true + } + } + return false }).Await(t) - return ok } diff --git a/feature/interface/aggregate/otg_tests/aggregate_forwarding_viable_test/aggregate_forwarding_viable_test.go b/feature/interface/aggregate/otg_tests/aggregate_forwarding_viable_test/aggregate_forwarding_viable_test.go index afbb72322b5..3e6a376eb05 100644 --- a/feature/interface/aggregate/otg_tests/aggregate_forwarding_viable_test/aggregate_forwarding_viable_test.go +++ b/feature/interface/aggregate/otg_tests/aggregate_forwarding_viable_test/aggregate_forwarding_viable_test.go @@ -552,6 +552,7 @@ func (tc *testArgs) testAggregateForwardingFlow(t *testing.T, forwardingViable b tc.ate.OTG().PushConfig(t, tc.top) tc.ate.OTG().StartProtocols(t) + otgutils.WaitForARP(t, tc.ate.OTG(), tc.top, "IPv4") beforeTrafficCounters := tc.getCounters(t, "before") tc.ate.OTG().StartTraffic(t) diff --git a/feature/interface/aggregate/otg_tests/balancing_test/README.md b/feature/interface/aggregate/otg_tests/balancing_test/README.md index aceda7e25b6..d09453272e8 100644 --- a/feature/interface/aggregate/otg_tests/balancing_test/README.md +++ b/feature/interface/aggregate/otg_tests/balancing_test/README.md @@ -41,3 +41,26 @@ None ## Minimum DUT platform requirement vRX + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths and RPC intended to be covered by this test. + +```yaml +paths: + /interfaces/interface/ethernet/config/aggregate-id: + /interfaces/interface/aggregation/config/lag-type: + /lacp/config/system-priority: + /lacp/interfaces/interface/config/name: + /lacp/interfaces/interface/config/interval: + /lacp/interfaces/interface/config/lacp-mode: + /lacp/interfaces/interface/config/system-id-mac: + /lacp/interfaces/interface/config/system-priority: + +rpcs: + gnmi: + gNMI.Set: + union_replace: false + gNMI.Subscribe: + on_change: false +``` diff --git a/feature/interface/aggregate/otg_tests/balancing_test/balancing_test.go b/feature/interface/aggregate/otg_tests/balancing_test/balancing_test.go index 07b576adf29..3ea546dc932 100644 --- a/feature/interface/aggregate/otg_tests/balancing_test/balancing_test.go +++ b/feature/interface/aggregate/otg_tests/balancing_test/balancing_test.go @@ -76,6 +76,8 @@ const ( opUp = oc.Interface_OperStatus_UP ethernetCsmacd = oc.IETFInterfaces_InterfaceType_ethernetCsmacd ieee8023adLag = oc.IETFInterfaces_InterfaceType_ieee8023adLag + trafficPps = 10000 + totalPackets = 200000 ) var ( @@ -439,7 +441,7 @@ func normalize(xs []uint64) (ys []float64, sum uint64) { return ys, sum } -var approxOpt = cmpopts.EquateApprox(0 /* frac */, 0.01 /* absolute */) +var approxOpt = cmpopts.EquateApprox(0 /* frac */, 0.1 /* absolute */) // portWants converts the nextHop wanted weights to per-port wanted // weights listed in the same order as atePorts. @@ -502,6 +504,8 @@ func (tc *testCase) testFlow(t *testing.T, l3header string) { flow := tc.top.Flows().Add().SetName(l3header) flow.Metrics().SetEnable(true) flow.Size().SetFixed(128) + flow.Rate().SetPps(trafficPps) + flow.Duration().FixedPackets().SetPackets(totalPackets) flow.Packet().Add().Ethernet().Src().SetValue(ateSrc.MAC) ipType := "IPv4" @@ -557,7 +561,7 @@ func (tc *testCase) testFlow(t *testing.T, l3header string) { beforeTrafficCounters := tc.getCounters(t, "before") tc.ate.OTG().StartTraffic(t) - time.Sleep(15 * time.Second) + time.Sleep(20 * time.Second) tc.ate.OTG().StopTraffic(t) otgutils.LogPortMetrics(t, tc.ate.OTG(), tc.top) @@ -569,6 +573,30 @@ func (tc *testCase) testFlow(t *testing.T, l3header string) { if pkts == 0 { t.Errorf("Flow sent packets: got %v, want non zero", pkts) } + + if deviations.InterfaceCountersUpdateDelayed(tc.dut) { + batch := gnmi.OCBatch() + for _, port := range tc.dutPorts[1:] { + batch.AddPaths(gnmi.OC().Interface(port.Name()).Counters()) + } + + _, ok := gnmi.Watch(t, tc.dut, batch.State(), time.Second*60, func(v *ygnmi.Value[*oc.Root]) bool { + got, present := v.Val() + if !present { + return false + } + totalPks := uint64(0) + for _, port := range tc.dutPorts[1:] { + totalPks += got.GetInterface(port.Name()).GetCounters().GetOutPkts() - beforeTrafficCounters[port.Name()].GetOutPkts() + } + return totalPks >= pkts + }).Await(t) + + if !ok { + t.Fatalf("Counters did not update in time") + } + } + afterTrafficCounters := tc.getCounters(t, "after") tc.verifyCounterDiff(t, beforeTrafficCounters, afterTrafficCounters) } diff --git a/feature/interface/aggregate/otg_tests/balancing_test/metadata.textproto b/feature/interface/aggregate/otg_tests/balancing_test/metadata.textproto index 68c8eb17c3a..f29298037aa 100644 --- a/feature/interface/aggregate/otg_tests/balancing_test/metadata.textproto +++ b/feature/interface/aggregate/otg_tests/balancing_test/metadata.textproto @@ -11,6 +11,7 @@ platform_exceptions: { } deviations: { ipv4_missing_enabled: true + interface_counters_update_delayed: true } } platform_exceptions: { diff --git a/feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/README.md b/feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/README.md similarity index 100% rename from feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/README.md rename to feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/README.md diff --git a/feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/interface_loopback_aggregate_test.go b/feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/interface_loopback_aggregate_test.go similarity index 98% rename from feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/interface_loopback_aggregate_test.go rename to feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/interface_loopback_aggregate_test.go index 8e31b1550d0..dcbc768fe6f 100644 --- a/feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/interface_loopback_aggregate_test.go +++ b/feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/interface_loopback_aggregate_test.go @@ -182,7 +182,7 @@ func TestInterfaceLoopbackMode(t *testing.T) { cs := gosnappi.NewControlState() t.Run("Admin down OTG port1", func(t *testing.T) { - cs.Port().Link().SetState(gosnappi.StatePortLinkState.DOWN) + cs.Port().Link().SetPortNames([]string{ate.Port(t, "port1").ID()}).SetState(gosnappi.StatePortLinkState.DOWN) otg.SetControlState(t, cs) }) diff --git a/feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/metadata.textproto b/feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/metadata.textproto similarity index 100% rename from feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/metadata.textproto rename to feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/metadata.textproto diff --git a/feature/interface/ip/ipv6_ND/otg_tests/disable_ipv6_nd_ra_test/metadata.textproto b/feature/interface/ip/ipv6_ND/otg_tests/disable_ipv6_nd_ra_test/metadata.textproto index 7e07c4a34fd..9855f84b507 100644 --- a/feature/interface/ip/ipv6_ND/otg_tests/disable_ipv6_nd_ra_test/metadata.textproto +++ b/feature/interface/ip/ipv6_ND/otg_tests/disable_ipv6_nd_ra_test/metadata.textproto @@ -30,4 +30,12 @@ platform_exceptions: { explicit_interface_in_default_vrf: true interface_enabled: true } +} +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + ipv6_router_advertisement_interval_unsupported: true + } } \ No newline at end of file diff --git a/feature/interface/ip/ipv6_link_local/otg_tests/ipv6_link_local_test/ipv6_link_local_test.go b/feature/interface/ip/ipv6_link_local/otg_tests/ipv6_link_local_test/ipv6_link_local_test.go index cdced10d75a..facd36954b2 100644 --- a/feature/interface/ip/ipv6_link_local/otg_tests/ipv6_link_local_test/ipv6_link_local_test.go +++ b/feature/interface/ip/ipv6_link_local/otg_tests/ipv6_link_local_test/ipv6_link_local_test.go @@ -128,10 +128,9 @@ func TestIPv6LinkLocal(t *testing.T) { t.Run("Disable and Enable Port1", func(t *testing.T) { p1 := dut.Port(t, "port1") gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().Config(), false) - // gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().State(), 30*time.Second, false) - t.Logf("Sleeping for 30 seconds") - time.Sleep(30 * time.Second) + gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().State(), 30*time.Second, false) gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().Config(), true) + gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().State(), 30*time.Second, true) otgutils.WaitForARP(t, ate.OTG(), top, "IPv6") t.Run("Interface Telemetry", func(t *testing.T) { verifyInterfaceTelemetry(t, dut) @@ -210,6 +209,8 @@ func configureDUTLinkLocalInterface(t *testing.T, dut *ondatra.DUTDevice) { fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) } + gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) + gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) } func configureOTGInterface(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config) { @@ -255,9 +256,15 @@ func verifyLinkLocalTraffic(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.A p1 := dut.Port(t, "port1") beforeInPkts := gnmi.Get(t, dut, gnmi.OC().Interface(p1.Name()).Counters().InPkts().State()) ate.OTG().StartTraffic(t) - time.Sleep(15 * time.Second) + _, ok := gnmi.Watch(t, dut, gnmi.OC().Interface(p1.Name()).Counters().InPkts().State(), time.Second*30, func(v *ygnmi.Value[uint64]) bool { + gotPkts, present := v.Val() + return present && (gotPkts-beforeInPkts) >= 100 + }).Await(t) + if !ok { + t.Fatal("did not get expected number of packets after starting traffic. want > 100") + } + ate.OTG().StopTraffic(t) - time.Sleep(15 * time.Second) otgutils.LogFlowMetrics(t, ate.OTG(), top) flowMetrics := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(flowName).Counters().State()) otgTxPkts := flowMetrics.GetOutPkts() diff --git a/feature/experimental/interface/my_station_mac/otg_tests/my_station_mac_test/README.md b/feature/interface/my_station_mac/otg_tests/my_station_mac_test/README.md similarity index 100% rename from feature/experimental/interface/my_station_mac/otg_tests/my_station_mac_test/README.md rename to feature/interface/my_station_mac/otg_tests/my_station_mac_test/README.md diff --git a/feature/experimental/interface/my_station_mac/otg_tests/my_station_mac_test/metadata.textproto b/feature/interface/my_station_mac/otg_tests/my_station_mac_test/metadata.textproto similarity index 100% rename from feature/experimental/interface/my_station_mac/otg_tests/my_station_mac_test/metadata.textproto rename to feature/interface/my_station_mac/otg_tests/my_station_mac_test/metadata.textproto diff --git a/feature/experimental/interface/my_station_mac/otg_tests/my_station_mac_test/my_station_mac_test.go b/feature/interface/my_station_mac/otg_tests/my_station_mac_test/my_station_mac_test.go similarity index 100% rename from feature/experimental/interface/my_station_mac/otg_tests/my_station_mac_test/my_station_mac_test.go rename to feature/interface/my_station_mac/otg_tests/my_station_mac_test/my_station_mac_test.go diff --git a/feature/interface/singleton/otg_tests/singleton_test/README.md b/feature/interface/singleton/otg_tests/singleton_test/README.md index a80de7b2ef8..d8d218db6f9 100644 --- a/feature/interface/singleton/otg_tests/singleton_test/README.md +++ b/feature/interface/singleton/otg_tests/singleton_test/README.md @@ -169,3 +169,56 @@ a new testbed configuration with the desired port types. ## Minimum DUT Platform Requirement vRX + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths and RPC intended to be covered by this test. + +```yaml +paths: + /interfaces/interface/ethernet/state/counters/in-mac-pause-frames: + /interfaces/interface/ethernet/state/counters/out-mac-pause-frames: + /interfaces/interface/ethernet/state/mac-address: + /interfaces/interface/state/counters/in-broadcast-pkts: + /interfaces/interface/state/counters/in-discards: + /interfaces/interface/state/counters/in-errors: + /interfaces/interface/state/counters/in-multicast-pkts: + /interfaces/interface/state/counters/in-octets: + /interfaces/interface/state/counters/in-unicast-pkts: + /interfaces/interface/state/counters/in-unknown-protos: + /interfaces/interface/state/counters/out-broadcast-pkts: + /interfaces/interface/state/counters/out-discards: + /interfaces/interface/state/counters/out-errors: + /interfaces/interface/state/counters/out-multicast-pkts: + /interfaces/interface/state/counters/out-octets: + /interfaces/interface/state/counters/out-pkts: + /interfaces/interface/state/counters/out-unicast-pkts: + /interfaces/interface/subinterfaces/subinterface/ipv4/state/mtu: + /interfaces/interface/subinterfaces/subinterface/ipv6/state/mtu: + /interfaces/interface/state/oper-status: + /interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/ip: + /interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-pkts: + /interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-pkts: + /interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/ip: + /interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-discarded-pkts: + /interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-pkts: + /interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-discarded-pkts: + /interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-pkts: + /interfaces/interface/ethernet/state/aggregate-id: + /interfaces/interface/ethernet/state/port-speed: + /interfaces/interface/state/admin-status: + /interfaces/interface/state/description: + /interfaces/interface/state/type: + /interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-forwarded-pkts: + /interfaces/interface/state/hardware-port: + /interfaces/interface/state/id: + /interfaces/interface/state/counters/in-fcs-errors: + /interfaces/interface/state/counters/carrier-transitions: + +rpcs: + gnmi: + gNMI.Set: + union_replace: false + gNMI.Subscribe: + on_change: false +``` diff --git a/feature/interface/singleton/otg_tests/singleton_test/metadata.textproto b/feature/interface/singleton/otg_tests/singleton_test/metadata.textproto index 76237f19190..926a5a3d560 100644 --- a/feature/interface/singleton/otg_tests/singleton_test/metadata.textproto +++ b/feature/interface/singleton/otg_tests/singleton_test/metadata.textproto @@ -12,6 +12,7 @@ platform_exceptions: { deviations: { ip_neighbor_missing: true ipv4_missing_enabled: true + interface_counters_update_delayed: true } } platform_exceptions: { diff --git a/feature/interface/singleton/otg_tests/singleton_test/singleton_test.go b/feature/interface/singleton/otg_tests/singleton_test/singleton_test.go index 4b38868f6ee..c7f442bd77e 100644 --- a/feature/interface/singleton/otg_tests/singleton_test/singleton_test.go +++ b/feature/interface/singleton/otg_tests/singleton_test/singleton_test.go @@ -30,6 +30,7 @@ import ( "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygnmi/ygnmi" "github.com/openconfig/ygot/ygot" otgtelemetry "github.com/openconfig/ondatra/gnmi/otg" @@ -244,7 +245,7 @@ func (tc *testCase) verifyInterfaceDUT( fptest.LogQuery(t, dp.String(), dip.State(), di) di.PopulateDefaults() - if tc.mtu == 1500 { + if tc.mtu == 1500 || tc.mtu == 5000 || tc.mtu == 9236 { // MTU default values are still not populated. di.GetSubinterface(0).GetIpv4().Mtu = ygot.Uint16(tc.mtu) di.GetSubinterface(0).GetIpv6().Mtu = ygot.Uint32(uint32(tc.mtu)) @@ -430,6 +431,36 @@ func (tc *testCase) testFlow(t *testing.T, packetSize uint16, configIPHeader otg t.Logf("ap1 out-octets %d -> ap2 in-octets %d", aicp1.GetCounters().GetOutOctets(), aicp2.GetCounters().GetInOctets()) } + // Flow counters + otgutils.LogFlowMetrics(t, tc.ate.OTG(), tc.top) + fp := gnmi.Get(t, tc.ate.OTG(), gnmi.OTG().Flow(flow.Name()).State()) + fpc := fp.GetCounters() + + // Pragmatic check on the average in and out packet sizes. IPv4 may + // fragment the packet unless DF bit is set. IPv6 never fragments. + // Under no circumstances should DUT send packets greater than MTU. + + octets := fpc.GetOutOctets() + ateOutPkts := fpc.GetOutPkts() + ateInPkts := fpc.GetInPkts() + + if deviations.InterfaceCountersUpdateDelayed(tc.dut) { + batch := gnmi.OCBatch() + batch.AddPaths( + gnmi.OC().Interface(p1.Name()).Counters(), + gnmi.OC().Interface(p2.Name()).Counters(), + ) + gnmi.Watch(t, tc.dut, batch.State(), time.Second*60, func(v *ygnmi.Value[*oc.Root]) bool { + got, present := v.Val() + if !present { + return false + } + diffP1 := diffCounters(p1InBefore, inCounters(got.GetInterface(p1.Name()).GetCounters())) + diffP2 := diffCounters(p2OutBefore, outCounters(got.GetInterface(p2.Name()).GetCounters())) + return (diffP1.unicast+diffP1.drop >= ateOutPkts) && (diffP2.unicast >= ateInPkts-diffP2.drop) + }).Await(t) + } + // After Traffic Unicast, Multicast, Broadcast Counter p1InAfter := inCounters(gnmi.Get(t, tc.dut, p1Counter.State())) p2OutAfter := outCounters(gnmi.Get(t, tc.dut, p2Counter.State())) @@ -449,18 +480,6 @@ func (tc *testCase) testFlow(t *testing.T, packetSize uint16, configIPHeader otg t.Errorf("Large number of outbound Broadcast packets %d, want <= 100)", p2OutDiff.broadcast) } - // Flow counters - otgutils.LogFlowMetrics(t, tc.ate.OTG(), tc.top) - fp := gnmi.Get(t, tc.ate.OTG(), gnmi.OTG().Flow(flow.Name()).State()) - fpc := fp.GetCounters() - - // Pragmatic check on the average in and out packet sizes. IPv4 may - // fragment the packet unless DF bit is set. IPv6 never fragments. - // Under no circumstances should DUT send packets greater than MTU. - - octets := fpc.GetOutOctets() - ateOutPkts := fpc.GetOutPkts() - ateInPkts := fpc.GetInPkts() if ateOutPkts == 0 { t.Error("Flow did not send any packet") } else if avg := octets / ateOutPkts; avg > uint64(tc.mtu) { diff --git a/feature/experimental/isis/otg_tests/base_adjacencies_test/README.md b/feature/isis/otg_tests/base_adjacencies_test/README.md similarity index 100% rename from feature/experimental/isis/otg_tests/base_adjacencies_test/README.md rename to feature/isis/otg_tests/base_adjacencies_test/README.md diff --git a/feature/experimental/isis/otg_tests/base_adjacencies_test/base_adjacencies_test.go b/feature/isis/otg_tests/base_adjacencies_test/base_adjacencies_test.go similarity index 100% rename from feature/experimental/isis/otg_tests/base_adjacencies_test/base_adjacencies_test.go rename to feature/isis/otg_tests/base_adjacencies_test/base_adjacencies_test.go diff --git a/feature/experimental/isis/otg_tests/base_adjacencies_test/metadata.textproto b/feature/isis/otg_tests/base_adjacencies_test/metadata.textproto similarity index 100% rename from feature/experimental/isis/otg_tests/base_adjacencies_test/metadata.textproto rename to feature/isis/otg_tests/base_adjacencies_test/metadata.textproto diff --git a/feature/isis/otg_tests/graceful_restart_helper/README.md b/feature/isis/otg_tests/graceful_restart_helper/README.md new file mode 100644 index 00000000000..9c822775000 --- /dev/null +++ b/feature/isis/otg_tests/graceful_restart_helper/README.md @@ -0,0 +1,252 @@ +# RT-2.15: IS-IS Graceful Restart Helper + +## Summary + +- test verify isis garceful restarts support in helper role + +## Testbed type + +* https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed + +## Procedure + +#### Initial Setup: + +* Connect: + * DUT port-1 to ATE port-1 + * DUT port-2 to ATE port-2 + +* Configure IPv4 and IPv6 addresses on DUT and ATE ports as shown below + * DUT port-1 IPv4 address ```dp1-v4 = 192.168.1.1/30``` + * ATE port-1 IPv4 address ```ap1-v4 = 192.168.1.2/30``` + + * DUT port-2 IPv4 address ```dp2-v4 = 192.168.1.5/30``` + * ATE port-2 IPv4 address ```ap2-v4 = 192.168.1.6/30``` + + * DUT port-1 IPv6 address ```dp1-v6 = 2001:DB8::1/126``` + * ATE port-1 IPv6 address ```ap1-v6 = 2001:DB8::2/126``` + + * DUT port-2 IPv6 address ```dp2-v6 = 2001:DB8::5/126``` + * ATE port-2 IPv6 address ```ap2-v6 = 2001:DB8::6/126``` + +* Create an "target IPv4" network i.e. ```ipv4-network = 192.168.10.0/24``` attached to ATE port-2 and inject it to ISIS. + +* Create an "target IPv6" network i.e. ```ipv6-network = 2024:db8:128:128::/64``` attached to ATE port-2 and inject it to ISIS. + +* Configure ISIS + * Configure separate ISIS emulated routers, one on each ATE ports-1, port-2 + * Enable IPv4 and IPv6 IS-IS L2 adjacency between ATE port-1 and DUT port-1, DUT port-2 and ATE port-2 in point-to-point mode. + + ```json + { + "network-instances": { + "network-instance": [ + { + "name": "DEFAULT", + "protocols": { + "protocol": [ + { + "identifier": "ISIS", + "name": "DEFAULT", + "config": { + "name": "DEFAULT", + "identifier": "ISIS" + }, + "isis": { + "global": { + "afi-safi": { + "af": [ + { + "afi-name": "IPV4", + "config": { + "afi-name": "IPV4", + "enabled": true, + "safi-name": "UNICAST" + }, + "safi-name": "UNICAST" + }, + { + "afi-name": "IPV6", + "config": { + "afi-name": "IPV6", + "enabled": true, + "safi-name": "UNICAST" + }, + "safi-name": "UNICAST" + } + ] + }, + "config": { + "level-capability": "LEVEL_2", + "net": [ + "" + ] + } + }, + "interfaces": { + "interface": [ + { + "config": { + "passive": true, + "enabled": true, + "interface-id": "Loopback0" + }, + "interface-id": "Loopback0", + "interface-ref": { + "config": { + "interface": "loopback0", + "subinterface": 0 + } + }, + "levels": { + "level": [ + { + "config": { + "level-number": 2, + "enabled": true + }, + "level-number": 2 + } + ] + } + }, + { + "config": { + "circuit-type": "POINT_TO_POINT", + "enabled": true, + "interface-id": "" + }, + "interface-id": "", + "interface-ref": { + "config": { + "interface": "", + "subinterface": 0 + } + }, + "levels": { + "level": [ + { + "afi-safi": { + "af": [ + { + "afi-name": "IPV4", + "config": { + "afi-name": "IPV4", + "metric": 10, + "safi-name": "UNICAST" + }, + "safi-name": "UNICAST" + }, + { + "afi-name": "IPV6", + "config": { + "afi-name": "IPV6", + "metric": 10, + "safi-name": "UNICAST" + }, + "safi-name": "UNICAST" + } + ] + }, + "config": { + "level-number": 2, + "enabled": true + }, + "level-number": 2, + "timers": { + "config": { + "hello-interval": 10, + "hello-multiplier": 6 + } + } + } + ] + } + } + ] + }, + "levels": { + "level": [ + { + "config": { + "level-number": 2, + "metric-style": "WIDE_METRIC", + "enabled": true + }, + "level-number": 2 + } + ] + } + } + } + ] + } + } + ] + } + } + ``` + * Enable IPv4 and IPv6 IS-IS L2 adjacency between ATE port-1 and DUT port-1, DUT port-2 and ATE port-2 in point-to-point mode.\ + * Set ISIS graceful restart helper mode on DUT + + ```json + { + "network-instances": { + "network-instance": [ + { + "name": "DEFAULT", + "protocols": { + "protocol": [ + { + "identifier": "ISIS", + "name": "DEFAULT", + "isis": { + "global": { + "graceful-restart": { + "config": { + "enabled": true, + "helper-only": true, + "restart-time": 30 + } + } + } + } + } + ] + } + } + ] + } + } + ``` + +### RT-2.15.1 [TODO: https://github.com/openconfig/featureprofiles/issues/2494] +#### GR helper + +* Generate traffic form ATE port-1 to "target IPv4" and "target IPv6" networks (ATE port-2) +* Verify traffic is recived on ATE port-2 +* Restart ISIS on ATE port-2 (Alternativly: using set_control_state to "down" for emulated isis router. Wait (restart-time - 10) sec and set it back to "up") +* Verify traffic is recived on ATE port-2 during restart time ( no losses ) +* Disable ISIS on ATE port-2 (set_control_state to "down"). Wait restart-time seconds +* Verify traffic is NOT recived on ATE port-2 (after restart-time expires) + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## Config Paths ## + /network-instances/network-instance/protocols/protocol/isis/global/graceful-restart/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/global/graceful-restart/config/helper-only: + /network-instances/network-instance/protocols/protocol/isis/global/graceful-restart/config/restart-time: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` + +## Required DUT platform + +* FFF \ No newline at end of file diff --git a/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto b/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto new file mode 100644 index 00000000000..4c84b917911 --- /dev/null +++ b/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto @@ -0,0 +1,21 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "4ebdc9b9-8f58-4e33-875b-b5b2a3e0de33" +plan_id: "RT-2.15" +description: "IS-IS Graceful Restart Helper" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + omit_l2_mtu: true + isis_interface_afi_unsupported: true + isis_instance_enabled_required: true + missing_value_for_defaults: true + skip_isis_set_level: true + } +} \ No newline at end of file diff --git a/feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/README.md b/feature/isis/otg_tests/isis_change_lsp_lifetime_test/README.md similarity index 70% rename from feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/README.md rename to feature/isis/otg_tests/isis_change_lsp_lifetime_test/README.md index 02310135271..a7bd7a209cd 100644 --- a/feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/README.md +++ b/feature/isis/otg_tests/isis_change_lsp_lifetime_test/README.md @@ -23,23 +23,18 @@ * Verify that the remaining lifetime of the lsp is remaining lifetime = configured lifetime - time passed since the LSP PDU generation. * Verify that once the new LSP PDU is generated the sequence number and checksum of the new LSP PDU is updated -## Config Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * global/timers/config/lsp-lifetime-interval - -## Telemetry Parameter coverage - -* For prefix: - - * /network-instances/network-instance/protocols/protocol/isis/ - -* Parameters: - - * global/timers/state/lsp-lifetime-interval - * levels/level/link-state-database/lsp/state/remaining-lifetime +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/timers/config/lsp-lifetime-interval: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/timers/state/lsp-lifetime-interval: + /network-instances/network-instance/protocols/protocol/isis/levels/level/link-state-database/lsp/state/remaining-lifetime: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` diff --git a/feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/isis_change_lsp_lifetime_test.go b/feature/isis/otg_tests/isis_change_lsp_lifetime_test/isis_change_lsp_lifetime_test.go similarity index 97% rename from feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/isis_change_lsp_lifetime_test.go rename to feature/isis/otg_tests/isis_change_lsp_lifetime_test/isis_change_lsp_lifetime_test.go index c9da9ae8a7a..8b731d015be 100644 --- a/feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/isis_change_lsp_lifetime_test.go +++ b/feature/isis/otg_tests/isis_change_lsp_lifetime_test/isis_change_lsp_lifetime_test.go @@ -134,6 +134,7 @@ func TestISISChangeLSPLifetime(t *testing.T) { fptest.LogQuery(t, "Protocol ISIS", isissession.ProtocolPath(ts.DUT).Config(), pcl) ts.PushAndStart(t) + time.Sleep(time.Minute * 2) isisPath := isissession.ISISPath(ts.DUT) intfName := ts.DUTPort1.Name() @@ -141,6 +142,7 @@ func TestISISChangeLSPLifetime(t *testing.T) { intfName += ".0" } t.Run("Isis telemetry", func(t *testing.T) { + time.Sleep(time.Minute * 2) // Checking adjacency ateSysID, err := ts.AwaitAdjacency() @@ -189,7 +191,7 @@ func TestISISChangeLSPLifetime(t *testing.T) { t.Errorf("FAIL- Expected v6 route not found in isis, got %v, want %v", got, want) } ipv4Path := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(ts.DUT)).Afts().Ipv4Entry(v4Route) - if got, ok := gnmi.Watch(t, ts.DUT, ipv4Path.State(), time.Second*30, func(val *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv4Entry]) bool { + if got, ok := gnmi.Watch(t, ts.DUT, ipv4Path.State(), time.Minute*2, func(val *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv4Entry]) bool { ipv4Entry, present := val.Val() return present && ipv4Entry.GetPrefix() == v4Route }).Await(t); !ok { @@ -197,7 +199,7 @@ func TestISISChangeLSPLifetime(t *testing.T) { } ipv6Path := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(ts.DUT)).Afts().Ipv6Entry(v6Route) - if got, ok := gnmi.Watch(t, ts.DUT, ipv6Path.State(), time.Second*30, func(val *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv6Entry]) bool { + if got, ok := gnmi.Watch(t, ts.DUT, ipv6Path.State(), time.Minute*2, func(val *ygnmi.Value[*oc.NetworkInstance_Afts_Ipv6Entry]) bool { ipv6Entry, present := val.Val() return present && ipv6Entry.GetPrefix() == v6Route }).Await(t); !ok { diff --git a/feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/metadata.textproto b/feature/isis/otg_tests/isis_change_lsp_lifetime_test/metadata.textproto similarity index 100% rename from feature/experimental/isis/otg_tests/isis_change_lsp_lifetime_test/metadata.textproto rename to feature/isis/otg_tests/isis_change_lsp_lifetime_test/metadata.textproto diff --git a/feature/experimental/isis/otg_tests/isis_drain_test/README.md b/feature/isis/otg_tests/isis_drain_test/README.md similarity index 84% rename from feature/experimental/isis/otg_tests/isis_drain_test/README.md rename to feature/isis/otg_tests/isis_drain_test/README.md index 8c2bf143e5f..67410a03579 100644 --- a/feature/experimental/isis/otg_tests/isis_drain_test/README.md +++ b/feature/isis/otg_tests/isis_drain_test/README.md @@ -12,15 +12,13 @@ Ensure that IS-IS metric change can drain traffic from a DUT trunk interface * Change the ISIS metric of trunk-2 to 1000 value. Validate that 100% of the traffic is going out of only trunk-3 and there is no traffic loss. * Revert back the ISIS metric on trunk-2. Validate that the traffic is going via both trunk-2 and trunk-3, and there is no traffic loss. -## Config Parameter Coverage - -## Telemetry Parameter Coverage - -## Protocol/RPC Parameter Coverage - -* IS-IS - * LSP - * TLV 22 metric field. +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` ## Minimum DUT Platform Requirement diff --git a/feature/experimental/isis/otg_tests/isis_drain_test/isis_drain_test.go b/feature/isis/otg_tests/isis_drain_test/isis_drain_test.go similarity index 100% rename from feature/experimental/isis/otg_tests/isis_drain_test/isis_drain_test.go rename to feature/isis/otg_tests/isis_drain_test/isis_drain_test.go diff --git a/feature/experimental/isis/otg_tests/isis_drain_test/metadata.textproto b/feature/isis/otg_tests/isis_drain_test/metadata.textproto similarity index 100% rename from feature/experimental/isis/otg_tests/isis_drain_test/metadata.textproto rename to feature/isis/otg_tests/isis_drain_test/metadata.textproto diff --git a/feature/isis/otg_tests/isis_extensions_segment_routing_test/README.md b/feature/isis/otg_tests/isis_extensions_segment_routing_test/README.md new file mode 100644 index 00000000000..23fe1fd5e7b --- /dev/null +++ b/feature/isis/otg_tests/isis_extensions_segment_routing_test/README.md @@ -0,0 +1,96 @@ +# RT-2.15 IS-IS Extensions for Segment Routing + +## Summary + +* This test case provides comprehensive coverage of IS-IS extensions for Segment Routing (SR), including: + * Node SID advertisement in IS-IS TLVs. + * SRGB and SRLB configuration and validation. + * Test coverage for Prefix SIDs and Anycast SIDs. + +## Testbed type + +* [`featureprofiles/topologies/atedut_2.testbed`](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed) + +## Procedure + +### Configuration + +1) Create the topology below: + + ``` + ATE1—DUT1–ATE2 + ``` + +2) Enable SR and MPLS: + * Enable Segment Routing for ISIS on the DUT. + * Enable MPLS forwarding on all interfaces. + * Configure appropriate IGP settings to ensure adjacency formation and prefix exchange between the DUT and ATEs. + +### SR-1.2.1: SRGB and SRLB Configuration. + +* Configure a non-default SRGB on the DUT with a specific lower and upper bound (17000-20000). +* Configure an SRLB on the DUT with a specific lower and upper bound (24000-27000). +* Verify that the DUT allocates and advertises labels for prefixes from its configured SRGB range. +* Verify that the DUT allocates and utilizes labels for adjacencies from its configured SRLB range. + +### SR-1.2.2: Node SID Validation. + +* Configure the DUT to advertise its Node SID to ATE1 and ATE2. +* Advertise prefixe (1) from ATE2 to the DUT +* Send labeled traffic transiting through the DUT (using its node-SID) matching prefix (1). +* Verify that the DUT advertises its Node SID in IS-IS TLVs. +* Verify that ATE2 receives traffic with node-SID label popped. +* Verify that traffic arrives to ATE Port 2. +* Verify that corresponding SID forwarding counters are incremented. + +### SR-1.2.3: Prefix SID Validation. + +* Configure the DUT to advertise two loopback prefixes with Prefix SIDs. +* Verify that the DUT advertises the loopback prefixes with the correct Prefix SIDs. +* Send labeled traffic from ATE1 to the loopback prefixes on the DUT +* Verify correct forwarding using Prefix SIDs. +* Verify that corresponding SID forwarding counters are incremented. + +### SR-1.2.4: Anycast SID Validation. + +* Configure the DUT to advertise an Anycast SID representing a service reachable via both loopback interfaces. +* Verify that the DUT advertises the Anycast SID. +* Send traffic from both ATEs towards the Anycast SID. +* Verify that traffic is load-balanced between the DUT's loopback interfaces based on IGP metrics. +* Verify that corresponding SID forwarding counters are incremented. + +## OpenConfig Path and RPC Coverage + +```yaml +paths: + ## Config paths + /network-instances/network-instance/mpls/global/reserved-label-blocks/reserved-label-block/config/local-id: + /network-instances/network-instance/mpls/global/reserved-label-blocks/reserved-label-block/config/lower-bound: + /network-instances/network-instance/mpls/global/reserved-label-blocks/reserved-label-block/config/upper-bound: + /network-instances/network-instance/mpls/global/interface-attributes/interface/config/mpls-enabled: + /network-instances/network-instance/segment-routing/srgbs/srgb/config/local-id: + /network-instances/network-instance/segment-routing/srgbs/srgb/config/mpls-label-blocks: + /network-instances/network-instance/segment-routing/srlbs/srlb/config/mpls-label-block: + /network-instances/network-instance/protocols/protocol/isis/global/segment-routing/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/global/segment-routing/config/srgb: + /network-instances/network-instance/protocols/protocol/isis/global/segment-routing/config/srlb: + + ## Telemetry + /network-instances/network-instance/protocols/protocol/isis/global/segment-routing/state/enabled: + /network-instances/network-instance/mpls/global/reserved-label-blocks/reserved-label-block/state/local-id: + /network-instances/network-instance/mpls/global/reserved-label-blocks/reserved-label-block/state/lower-bound: + /network-instances/network-instance/mpls/global/reserved-label-blocks/reserved-label-block/state/upper-bound: + /network-instances/network-instance/mpls/signaling-protocols/segment-routing/aggregate-sid-counters/aggregate-sid-counter/state/in-pkts: + /network-instances/network-instance/mpls/signaling-protocols/segment-routing/aggregate-sid-counters/aggregate-sid-counter/state/out-pkts: + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true +``` + +## Minimum DUT platform requirement +* FFF - fixed form factor \ No newline at end of file diff --git a/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/README.md b/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/README.md new file mode 100644 index 00000000000..7448bf4d1b8 --- /dev/null +++ b/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/README.md @@ -0,0 +1,92 @@ +# RT-2.6: IS-IS Hello-Padding enabled at interface level + +## Summary + +* Base IS-IS functionality and adjacency establishment. +* Verifies isis adjacency by changing MTU. + +## Procedure + +* Configure IS-IS for ATE port-1 and DUT port-1. +* Configure DUT with global hello-padding enabled. +* Ensure that adjacencies are established with: + * Interface level hello padding is enabled. + * Verify that IPv4 and IPv6 IS-ISIS adjacency comes up fine. + * Verify the output of ST path displaying the status of ISIS hello padding. + * If we change the MTU on either side, then adjacency should not come up. + * Verify that IPv4 and IPv6 prefixes that are advertised by ATE correctly installed into DUTs route and forwarding table. + * TODO-Verify the Hellos are sent with Padding during adjacency turn-up if the padding is enabled adaptively/sometimes. + * Ensure that IPv4 and IPv6 prefixes that are advertised as part of an (emulated) neighboring system are installed into the DUT routing table, and validate that packets are sent and received to them. + +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/config/authentication-check: + /network-instances/network-instance/protocols/protocol/isis/global/config/net: + /network-instances/network-instance/protocols/protocol/isis/global/config/level-capability: + /network-instances/network-instance/protocols/protocol/isis/global/config/hello-padding: + /network-instances/network-instance/protocols/protocol/isis/global/afi-safi/af/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/level-number: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-mode: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-password: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/interface-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/circuit-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/timers/config/csnp-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/timers/config/lsp-pacing-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/config/level-number: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/timers/config/hello-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/timers/config/hello-multiplier: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-mode: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-password: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/afi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/safi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/enabled: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/state/hello-padding: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/state/hello-padding: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/adjacency-state: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv4-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv6-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/system-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/area-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/dis-system-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/local-extended-circuit-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/multi-topology: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-circuit-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-extended-circuit-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-snpa: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/nlpid: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/priority: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-status: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-support: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-suppress: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/afi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/safi-name: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/auth-fails: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/auth-type-fails: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/corrupted-lsps: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/database-overloads: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/exceed-max-seq-nums: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/id-len-mismatch: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/lsp-errors: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/manual-address-drop-from-areas: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/max-area-address-mismatches: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/own-lsp-purges: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/part-changes: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/seq-num-skips: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/spf-runs: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` \ No newline at end of file diff --git a/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/isis_interface_hello_padding_enable_test.go b/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/isis_interface_hello_padding_enable_test.go similarity index 94% rename from feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/isis_interface_hello_padding_enable_test.go rename to feature/isis/otg_tests/isis_interface_hello_padding_enable_test/isis_interface_hello_padding_enable_test.go index 8823ec9e638..7e21ac55d6a 100644 --- a/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/isis_interface_hello_padding_enable_test.go +++ b/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/isis_interface_hello_padding_enable_test.go @@ -74,6 +74,7 @@ func configureISIS(t *testing.T, ts *isissession.TestSession) { // Level configs. level := isis.GetOrCreateLevel(2) level.LevelNumber = ygot.Uint8(2) + level.MetricStyle = oc.Isis_MetricStyle_WIDE_METRIC // Authentication configs. auth := level.GetOrCreateAuthentication() @@ -88,7 +89,6 @@ func configureISIS(t *testing.T, ts *isissession.TestSession) { intfName += ".0" } intf := isis.GetOrCreateInterface(intfName) - intf.HelloPadding = oc.Isis_HelloPaddingType_ADAPTIVE // Interface timers. isisIntfTimers := intf.GetOrCreateTimers() @@ -101,6 +101,8 @@ func configureISIS(t *testing.T, ts *isissession.TestSession) { // Interface level configs. isisIntfLevel := intf.GetOrCreateLevel(2) isisIntfLevel.LevelNumber = ygot.Uint8(2) + isisIntfLevel.SetEnabled(true) + isisIntfLevel.Enabled = ygot.Bool(true) isisIntfLevel.GetOrCreateHelloAuthentication().Enabled = ygot.Bool(true) isisIntfLevel.GetHelloAuthentication().AuthPassword = ygot.String(password) isisIntfLevel.GetHelloAuthentication().AuthType = oc.KeychainTypes_AUTH_TYPE_SIMPLE_KEY @@ -110,12 +112,14 @@ func configureISIS(t *testing.T, ts *isissession.TestSession) { isisIntfLevelTimers.HelloInterval = ygot.Uint32(5) isisIntfLevelTimers.HelloMultiplier = ygot.Uint8(3) - if !deviations.ISISInterfaceAfiUnsupported(ts.DUT) { - isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV4, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) - isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) - } + isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV4, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV4, oc.IsisTypes_SAFI_TYPE_UNICAST).Metric = ygot.Uint32(v4Metric) + isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = ygot.Bool(true) isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST).Metric = ygot.Uint32(v6Metric) + if deviations.MissingIsisInterfaceAfiSafiEnable(ts.DUT) { + isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV4, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = nil + isisIntfLevel.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST).Enabled = nil + } } // configureOTG configures isis and traffic on OTG. @@ -222,7 +226,7 @@ func TestIsisInterfaceHelloPaddingEnable(t *testing.T) { // Adjacency check. _, found := gnmi.Watch(t, ts.DUT, statePath.Interface(intfName).Level(2).Adjacency(ateSysID).AdjacencyState().State(), time.Minute, func(val *ygnmi.Value[oc.E_Isis_IsisInterfaceAdjState]) bool { state, present := val.Val() - return present && state == oc.Isis_IsisInterfaceAdjState_DOWN + return present && (state == oc.Isis_IsisInterfaceAdjState_DOWN || state == oc.Isis_IsisInterfaceAdjState_INIT) }).Await(t) if !found { t.Errorf("Isis adjacency is not down on interface %v when MTU is changed", intfName) @@ -274,8 +278,10 @@ func TestIsisInterfaceHelloPaddingEnable(t *testing.T) { if got := gnmi.Get(t, ts.DUT, adjPath.AreaAddress().State()); !cmp.Equal(got, want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) { t.Errorf("FAIL- Expected area address not found, got %s, want %s", got, want) } - if got := gnmi.Get(t, ts.DUT, adjPath.DisSystemId().State()); got != "0000.0000.0000" { - t.Errorf("FAIL- Expected dis system id not found, got %s, want %s", got, "0000.0000.0000") + if !deviations.IsisDisSysidUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, adjPath.DisSystemId().State()); got != "0000.0000.0000" { + t.Errorf("FAIL- Expected dis system id not found, got %s, want %s", got, "0000.0000.0000") + } } if got := gnmi.Get(t, ts.DUT, adjPath.LocalExtendedCircuitId().State()); got == 0 { t.Errorf("FAIL- Expected local extended circuit id not found,expected non-zero value, got %d", got) @@ -328,8 +334,10 @@ func TestIsisInterfaceHelloPaddingEnable(t *testing.T) { if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().CorruptedLsps().State()); got != 0 { t.Errorf("FAIL- Not expecting any corrupted lsps, got %d, want %d", got, 0) } - if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().DatabaseOverloads().State()); got != 0 { - t.Errorf("FAIL- Not expecting non zero database_overloads, got %d, want %d", got, 0) + if !deviations.IsisDatabaseOverloadsUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().DatabaseOverloads().State()); got != 0 { + t.Errorf("FAIL- Not expecting pre isis config database_overloads value to change, got %d, want %d", got, 0) + } } if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().ExceedMaxSeqNums().State()); got != 0 { t.Errorf("FAIL- Not expecting non zero max_seqnum counter, got %d, want %d", got, 0) diff --git a/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/metadata.textproto b/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/metadata.textproto similarity index 94% rename from feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/metadata.textproto rename to feature/isis/otg_tests/isis_interface_hello_padding_enable_test/metadata.textproto index b534b4ef211..3586116e655 100644 --- a/feature/experimental/isis/otg_tests/isis_interface_hello_padding_enable_test/metadata.textproto +++ b/feature/isis/otg_tests/isis_interface_hello_padding_enable_test/metadata.textproto @@ -25,6 +25,8 @@ platform_exceptions: { deviations: { ipv4_missing_enabled: true isis_interface_level1_disable_required: true + isis_dis_sysid_unsupported: true + isis_database_overloads_unsupported: true } } platform_exceptions: { diff --git a/feature/isis/otg_tests/isis_interface_level_passive_test/README.md b/feature/isis/otg_tests/isis_interface_level_passive_test/README.md new file mode 100644 index 00000000000..b0d7374a153 --- /dev/null +++ b/feature/isis/otg_tests/isis_interface_level_passive_test/README.md @@ -0,0 +1,95 @@ +# RT-2.11: IS-IS Passive is enabled at the area level + +## Summary + +* Verify isis adjacency with passive enabled under level. + +## Topology + +* ATE:port1 <-> port1:DUT:port2 <-> ATE:port2 + +## Procedure + +* Configure IS-IS for ATE port-1 and DUT port-1. +* Configure DUT interface with IS-IS passive configured at area level 2. + * Verify that IS-IS adjacency is not coming up in level-2 area for IPv4 and IPV6 address families. +* Undo the IS-IS passive configuration under level 2 + * Verify that IS-IS adjacency for IPv4 and IPV6 address families are coming up in the level-2 area. + * Verify that IPv4 and IPv6 prefixes that are advertised by ATE are correctly installed into DUTs route and forwarding table. + * Ensure that IPv4 and IPv6 prefixes that are advertised as part of an (emulated) neighboring system are installed into the DUT routing table, and validate that packets are sent and received to them. + * TODO-Verify the output of ST path displaying the interface as passive in ISIS database/adj table + +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/config/authentication-check: + /network-instances/network-instance/protocols/protocol/isis/global/config/net: + /network-instances/network-instance/protocols/protocol/isis/global/config/level-capability: + /network-instances/network-instance/protocols/protocol/isis/global/config/hello-padding: + /network-instances/network-instance/protocols/protocol/isis/global/afi-safi/af/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/level-number: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-mode: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-password: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/interface-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/circuit-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/passive: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/timers/config/csnp-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/timers/config/lsp-pacing-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/config/level-number: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/config/passive: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/timers/config/hello-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/timers/config/hello-multiplier: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-mode: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-password: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/afi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/safi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/enabled: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/state/passive: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/state/passive: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/adjacency-state: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv4-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv6-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/system-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/area-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/dis-system-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/local-extended-circuit-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/multi-topology: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-circuit-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-extended-circuit-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-snpa: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/nlpid: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/priority: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-status: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-support: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-suppress: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/afi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/safi-name: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/auth-fails: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/auth-type-fails: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/corrupted-lsps: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/database-overloads: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/exceed-max-seq-nums: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/id-len-mismatch: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/lsp-errors: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/manual-address-drop-from-areas: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/max-area-address-mismatches: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/own-lsp-purges: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/part-changes: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/seq-num-skips: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/spf-runs: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` \ No newline at end of file diff --git a/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/isis_interface_level_passive_test.go b/feature/isis/otg_tests/isis_interface_level_passive_test/isis_interface_level_passive_test.go similarity index 86% rename from feature/experimental/isis/otg_tests/isis_interface_level_passive_test/isis_interface_level_passive_test.go rename to feature/isis/otg_tests/isis_interface_level_passive_test/isis_interface_level_passive_test.go index 86a695e5ab7..eb0dde965b0 100644 --- a/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/isis_interface_level_passive_test.go +++ b/feature/isis/otg_tests/isis_interface_level_passive_test/isis_interface_level_passive_test.go @@ -15,6 +15,7 @@ package isis_interface_level_passive_test import ( + "fmt" "net" "testing" "time" @@ -23,8 +24,10 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/helpers" "github.com/openconfig/featureprofiles/internal/isissession" "github.com/openconfig/featureprofiles/internal/otgutils" + "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" "github.com/openconfig/ygot/ygot" @@ -99,8 +102,8 @@ func configureISIS(t *testing.T, ts *isissession.TestSession) { // Interface level configs. isisIntfLevel2 := intf.GetOrCreateLevel(2) isisIntfLevel2.LevelNumber = ygot.Uint8(2) + isisIntfLevel2.SetEnabled(true) isisIntfLevel2.Enabled = ygot.Bool(true) - isisIntfLevel2.Passive = ygot.Bool(true) isisIntfLevel2.GetOrCreateHelloAuthentication().Enabled = ygot.Bool(true) isisIntfLevel2.GetHelloAuthentication().AuthPassword = ygot.String(password) @@ -170,7 +173,7 @@ func configureOTG(t *testing.T, ts *isissession.TestSession) { func TestISISLevelPassive(t *testing.T) { ts := isissession.MustNew(t).WithISIS() configureISIS(t, ts) - + dut := ts.DUT configureOTG(t, ts) otg := ts.ATE.OTG() @@ -178,6 +181,7 @@ func TestISISLevelPassive(t *testing.T) { fptest.LogQuery(t, "Protocol ISIS", isissession.ProtocolPath(ts.DUT).Config(), pcl) ts.PushAndStart(t) + time.Sleep(time.Minute * 2) statePath := isissession.ISISPath(ts.DUT) intfName := ts.DUTPort1.Name() @@ -185,11 +189,27 @@ func TestISISLevelPassive(t *testing.T) { intfName += ".0" } t.Run("Isis telemetry", func(t *testing.T) { + time.Sleep(time.Minute * 1) + var isispassiveconfig string t.Run("Passive checks", func(t *testing.T) { - // Passive should be true. - if got := gnmi.Get(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().State()); got != true { - t.Errorf("FAIL- Expected level 2 passive state not found, got %t, want %t", got, true) + if deviations.IsisInterfaceLevelPassiveUnsupported(ts.DUT) { + switch dut.Vendor() { + case ondatra.CISCO: + isispassiveconfig = fmt.Sprintf("router isis DEFAULT\n interface %s\n passive\n", intfName) + default: + t.Fatalf("Unsupported vendor %s for deviation 'IsisInterfaceLevelPassiveUnsupported'", dut.Vendor()) + } + helpers.GnmiCLIConfig(t, dut, isispassiveconfig) + } else { + gnmi.Update(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().Config(), true) + } + if !deviations.IsisInterfaceLevelPassiveUnsupported(ts.DUT) { + // Passive should be true. + if got := gnmi.Get(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().State()); got != true { + t.Errorf("FAIL- Expected level 2 passive state not found, got %t, want %t", got, true) + } } + t.Logf("Adjacency state after passive update is %s", statePath.Interface(intfName).Level(2).AdjacencyAny().AdjacencyState().State()) // Adjacency should be down. for _, val := range gnmi.LookupAll(t, ts.DUT, statePath.Interface(intfName).LevelAny().AdjacencyAny().AdjacencyState().State()) { if v, _ := val.Val(); v == oc.Isis_IsisInterfaceAdjState_UP { @@ -197,12 +217,23 @@ func TestISISLevelPassive(t *testing.T) { } } // Updating passive config to false on dut. - gnmi.Update(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().Config(), false) - time.Sleep(time.Second * 5) - - if got := gnmi.Get(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().State()); got != false { - t.Errorf("FAIL- Expected level 2 passive state not found, got %t, want %t", got, true) + if deviations.IsisInterfaceLevelPassiveUnsupported(ts.DUT) { + switch dut.Vendor() { + case ondatra.CISCO: + isispassiveconfig = fmt.Sprintf("router isis DEFAULT\n interface %s\n no passive\n", intfName) + default: + t.Fatalf("Unsupported vendor %s for deviation 'IsisInterfaceLevelPassiveUnsupported'", dut.Vendor()) + } + helpers.GnmiCLIConfig(t, dut, isispassiveconfig) + } else { + gnmi.Update(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().Config(), false) } + if !deviations.IsisInterfaceLevelPassiveUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, statePath.Interface(intfName).Level(2).Passive().State()); got != false { + t.Errorf("FAIL- Expected level 2 passive state not found, got %t, want %t", got, true) + } + } + t.Logf("Adjacency state after passive update is %s", statePath.Interface(intfName).LevelAny().AdjacencyAny().AdjacencyState().State()) // Level 2 adjacency should be up. _, err := ts.AwaitAdjacency() if err != nil { @@ -244,8 +275,10 @@ func TestISISLevelPassive(t *testing.T) { if got := gnmi.Get(t, ts.DUT, adjPath.AreaAddress().State()); !cmp.Equal(got, want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) { t.Errorf("FAIL- Expected area address not found, got %s, want %s", got, want) } - if got := gnmi.Get(t, ts.DUT, adjPath.DisSystemId().State()); got != "0000.0000.0000" { - t.Errorf("FAIL- Expected dis system id not found, got %s, want %s", got, "0000.0000.0000") + if !deviations.IsisDisSysidUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, adjPath.DisSystemId().State()); got != "0000.0000.0000" { + t.Errorf("FAIL- Expected dis system id not found, got %s, want %s", got, "0000.0000.0000") + } } if got := gnmi.Get(t, ts.DUT, adjPath.LocalExtendedCircuitId().State()); got == 0 { t.Errorf("FAIL- Expected local extended circuit id not found,expected non-zero value, got %d", got) @@ -298,8 +331,10 @@ func TestISISLevelPassive(t *testing.T) { if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().CorruptedLsps().State()); got != 0 { t.Errorf("FAIL- Not expecting any corrupted lsps, got %d, want %d", got, 0) } - if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().DatabaseOverloads().State()); got != 0 { - t.Errorf("FAIL- Not expecting non zero database_overloads, got %d, want %d", got, 0) + if !deviations.IsisDatabaseOverloadsUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().DatabaseOverloads().State()); got != 0 { + t.Errorf("FAIL- Not expecting non zero database_overloads, got %d, want %d", got, 0) + } } if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().ExceedMaxSeqNums().State()); got != 0 { t.Errorf("FAIL- Not expecting non zero max_seqnum counter, got %d, want %d", got, 0) diff --git a/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/metadata.textproto b/feature/isis/otg_tests/isis_interface_level_passive_test/metadata.textproto similarity index 94% rename from feature/experimental/isis/otg_tests/isis_interface_level_passive_test/metadata.textproto rename to feature/isis/otg_tests/isis_interface_level_passive_test/metadata.textproto index 9506ed808ae..d0a0a9cc54f 100644 --- a/feature/experimental/isis/otg_tests/isis_interface_level_passive_test/metadata.textproto +++ b/feature/isis/otg_tests/isis_interface_level_passive_test/metadata.textproto @@ -25,6 +25,8 @@ platform_exceptions: { deviations: { ipv4_missing_enabled: true isis_interface_level1_disable_required: true + isis_dis_sysid_unsupported: true + isis_database_overloads_unsupported: true } } platform_exceptions: { diff --git a/feature/experimental/isis/otg_tests/isis_interface_passive_test/README.md b/feature/isis/otg_tests/isis_interface_passive_test/README.md similarity index 99% rename from feature/experimental/isis/otg_tests/isis_interface_passive_test/README.md rename to feature/isis/otg_tests/isis_interface_passive_test/README.md index cd87a3ba503..bf600ec87b0 100644 --- a/feature/experimental/isis/otg_tests/isis_interface_passive_test/README.md +++ b/feature/isis/otg_tests/isis_interface_passive_test/README.md @@ -76,7 +76,7 @@ paths: /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/exceed-max-seq-nums: /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/id-len-mismatch: /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/lsp-errors: -/network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/manual-address-drop-from-area : +/network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/manual-address-drop-from-areas: /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/max-area-address-mismatches: /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/own-lsp-purges: /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/part-changes : diff --git a/feature/experimental/isis/otg_tests/isis_interface_passive_test/isis_interface_passive_test.go b/feature/isis/otg_tests/isis_interface_passive_test/isis_interface_passive_test.go similarity index 100% rename from feature/experimental/isis/otg_tests/isis_interface_passive_test/isis_interface_passive_test.go rename to feature/isis/otg_tests/isis_interface_passive_test/isis_interface_passive_test.go diff --git a/feature/experimental/isis/otg_tests/isis_interface_passive_test/metadata.textproto b/feature/isis/otg_tests/isis_interface_passive_test/metadata.textproto similarity index 100% rename from feature/experimental/isis/otg_tests/isis_interface_passive_test/metadata.textproto rename to feature/isis/otg_tests/isis_interface_passive_test/metadata.textproto diff --git a/feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/README.md b/feature/isis/otg_tests/isis_metric_style_wide_enabled_test/README.md similarity index 100% rename from feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/README.md rename to feature/isis/otg_tests/isis_metric_style_wide_enabled_test/README.md diff --git a/feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/isis_metric_style_wide_enabled_test.go b/feature/isis/otg_tests/isis_metric_style_wide_enabled_test/isis_metric_style_wide_enabled_test.go similarity index 96% rename from feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/isis_metric_style_wide_enabled_test.go rename to feature/isis/otg_tests/isis_metric_style_wide_enabled_test/isis_metric_style_wide_enabled_test.go index 2ed2ac22d73..29caeafbae6 100644 --- a/feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/isis_metric_style_wide_enabled_test.go +++ b/feature/isis/otg_tests/isis_metric_style_wide_enabled_test/isis_metric_style_wide_enabled_test.go @@ -105,6 +105,8 @@ func configureISIS(t *testing.T, ts *isissession.TestSession) { // Interface level configs. isisIntfLevel := intf.GetOrCreateLevel(2) isisIntfLevel.LevelNumber = ygot.Uint8(2) + isisIntfLevel.SetEnabled(true) + isisIntfLevel.Enabled = ygot.Bool(true) isisIntfLevel.GetOrCreateHelloAuthentication().Enabled = ygot.Bool(true) isisIntfLevel.GetHelloAuthentication().AuthPassword = ygot.String(password) isisIntfLevel.GetHelloAuthentication().AuthType = oc.KeychainTypes_AUTH_TYPE_SIMPLE_KEY @@ -191,6 +193,7 @@ func TestISISWideMetricEnabled(t *testing.T) { fptest.LogQuery(t, "Protocol ISIS", isissession.ProtocolPath(ts.DUT).Config(), pcl) ts.PushAndStart(t) + time.Sleep(time.Minute * 2) statePath := isissession.ISISPath(ts.DUT) intfName := ts.DUTPort1.Name() @@ -198,6 +201,7 @@ func TestISISWideMetricEnabled(t *testing.T) { intfName += ".0" } t.Run("ISIS telemetry", func(t *testing.T) { + time.Sleep(time.Minute * 2) // Checking adjacency ateSysID, err := ts.AwaitAdjacency() @@ -237,8 +241,10 @@ func TestISISWideMetricEnabled(t *testing.T) { if got := gnmi.Get(t, ts.DUT, adjPath.AreaAddress().State()); !cmp.Equal(got, want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) { t.Errorf("FAIL- Expected area address not found, got %s, want %s", got, want) } - if got := gnmi.Get(t, ts.DUT, adjPath.DisSystemId().State()); got != "0000.0000.0000" { - t.Errorf("FAIL- Expected dis system id not found, got %s, want %s", got, "0000.0000.0000") + if !deviations.IsisDisSysidUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, adjPath.DisSystemId().State()); got != "0000.0000.0000" { + t.Errorf("FAIL- Expected dis system id not found, got %s, want %s", got, "0000.0000.0000") + } } if got := gnmi.Get(t, ts.DUT, adjPath.LocalExtendedCircuitId().State()); got == 0 { t.Errorf("FAIL- Expected local extended circuit id not found,expected non-zero value, got %d", got) @@ -291,8 +297,10 @@ func TestISISWideMetricEnabled(t *testing.T) { if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().CorruptedLsps().State()); got != 0 { t.Errorf("FAIL- Not expecting any corrupted lsps, got %d, want %d", got, 0) } - if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().DatabaseOverloads().State()); got != 0 { - t.Errorf("FAIL- Not expecting non zero database_overloads, got %d, want %d", got, 0) + if !deviations.IsisDatabaseOverloadsUnsupported(ts.DUT) { + if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().DatabaseOverloads().State()); got != 0 { + t.Errorf("FAIL- Not expecting pre isis config database_overloads value to change, got %d, want %d", got, 0) + } } if got := gnmi.Get(t, ts.DUT, statePath.Level(2).SystemLevelCounters().ExceedMaxSeqNums().State()); got != 0 { t.Errorf("FAIL- Not expecting non zero max_seqnum counter, got %d, want %d", got, 0) diff --git a/feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/metadata.textproto b/feature/isis/otg_tests/isis_metric_style_wide_enabled_test/metadata.textproto similarity index 94% rename from feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/metadata.textproto rename to feature/isis/otg_tests/isis_metric_style_wide_enabled_test/metadata.textproto index f97decc5a6f..4a83159128d 100644 --- a/feature/experimental/isis/otg_tests/isis_metric_style_wide_enabled_test/metadata.textproto +++ b/feature/isis/otg_tests/isis_metric_style_wide_enabled_test/metadata.textproto @@ -25,6 +25,8 @@ platform_exceptions: { deviations: { ipv4_missing_enabled: true isis_interface_level1_disable_required: true + isis_dis_sysid_unsupported: true + isis_database_overloads_unsupported: true } } platform_exceptions: { diff --git a/feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/README.md b/feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/README.md new file mode 100644 index 00000000000..49fa92ad9b2 --- /dev/null +++ b/feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/README.md @@ -0,0 +1,94 @@ +# RT-2.8: IS-IS metric style wide not enabled + +## Summary + +* Base IS-IS functionality and adjacency establishment. +* Verifies route metric with wide metric disabled on DUT. + +## Procedure + +* TestISISWideMetricNotEnabled + + * Configure IS-IS for ATE port-1 and DUT port-1. + * Do not configure metric style wide under the area level. + * Enable wide metric style on ATE. + * Advertise ISIS prefixes from ATE with wide metrics (value > 63). + * Verify that IS-IS adjacency for IPv4 and IPV6 address family is coming up. + * Verify that IPv4 and IPv6 prefixes that are advertised by ATE correctly installed into DUTs route and forwarding table. + * TODO-Verify that the metrics of the IPv4 and IPv6 prefixes is 63. + * Ensure that IPv4 and IPv6 prefixes that are advertised as part of an (emulated) neighboring system are installed into the DUT routing table, and validate that packets are sent and received to them. + +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/config/authentication-check: + /network-instances/network-instance/protocols/protocol/isis/global/config/net: + /network-instances/network-instance/protocols/protocol/isis/global/config/level-capability: + /network-instances/network-instance/protocols/protocol/isis/global/config/hello-padding: + /network-instances/network-instance/protocols/protocol/isis/global/afi-safi/af/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/level-number: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/config/metric-style: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-mode: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-password: + /network-instances/network-instance/protocols/protocol/isis/levels/level/authentication/config/auth-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/interface-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/circuit-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/config/passive: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/timers/config/csnp-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/timers/config/lsp-pacing-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/config/level-number: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/config/passive: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/timers/config/hello-interval: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/timers/config/hello-multiplier: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-mode: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-password: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/auth-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/hello-authentication/config/enabled: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/afi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/safi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/afi-safi/af/config/enabled: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/levels/level/state/metric-style: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/adjacency-state: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv4-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-ipv6-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/system-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/area-address: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/dis-system-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/local-extended-circuit-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/multi-topology: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-circuit-type: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-extended-circuit-id: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/neighbor-snpa: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/nlpid: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/priority: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-status: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-support: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/adjacencies/adjacency/state/restart-suppress: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/afi-name: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/safi-name: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/auth-fails: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/auth-type-fails: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/corrupted-lsps: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/database-overloads: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/exceed-max-seq-nums: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/id-len-mismatch: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/lsp-errors: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/manual-address-drop-from-areas: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/max-area-address-mismatches: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/own-lsp-purges: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/part-changes: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/seq-num-skips: + /network-instances/network-instance/protocols/protocol/isis/levels/level/system-level-counters/state/spf-runs: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` \ No newline at end of file diff --git a/feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/isis_metric_style_wide_not_enabled_test.go b/feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/isis_metric_style_wide_not_enabled_test.go similarity index 100% rename from feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/isis_metric_style_wide_not_enabled_test.go rename to feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/isis_metric_style_wide_not_enabled_test.go diff --git a/feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/metadata.textproto b/feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/metadata.textproto similarity index 100% rename from feature/experimental/isis/otg_tests/isis_metric_style_wide_not_enabled_test/metadata.textproto rename to feature/isis/otg_tests/isis_metric_style_wide_not_enabled_test/metadata.textproto diff --git a/feature/experimental/isis/otg_tests/lsp_updates_test/README.md b/feature/isis/otg_tests/lsp_updates_test/README.md similarity index 58% rename from feature/experimental/isis/otg_tests/lsp_updates_test/README.md rename to feature/isis/otg_tests/lsp_updates_test/README.md index d207d7c482a..b1f4c16e5bc 100644 --- a/feature/experimental/isis/otg_tests/lsp_updates_test/README.md +++ b/feature/isis/otg_tests/lsp_updates_test/README.md @@ -20,26 +20,21 @@ Ensure that IS-IS updates reflect parameter changes on DUT. port via configuration, update value in configuration, and ensure that ATE and DUT telemetry reflects the change. -## Config Parameter Coverage - -For prefix: /network-instances/network-instance/protocols/protocol/isis/ - -Parameters: - -* global/lsp-bit/overload-bit/config/set-bit - -## Telemetry Parameter Coverage - -* /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric - -* /network-instances/network-instance/protocols/protocol/isis/global/lsp-bit/overload-bit/state/set-bit - -## Protocol/RPC Parameter Coverage - -* IS-IS - * LSP - * Flags - overload bit (5) - * TLV 22 metric field. +## OpenConfig Path and RPC Coverage +```yaml +paths: + ## Config Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/lsp-bit/overload-bit/config/set-bit: + + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/isis/global/lsp-bit/overload-bit/state/set-bit: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric: + +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` ## Minimum DUT Platform Requirement diff --git a/feature/experimental/isis/otg_tests/lsp_updates_test/lsp_updates_test.go b/feature/isis/otg_tests/lsp_updates_test/lsp_updates_test.go similarity index 100% rename from feature/experimental/isis/otg_tests/lsp_updates_test/lsp_updates_test.go rename to feature/isis/otg_tests/lsp_updates_test/lsp_updates_test.go diff --git a/feature/experimental/isis/otg_tests/lsp_updates_test/metadata.textproto b/feature/isis/otg_tests/lsp_updates_test/metadata.textproto similarity index 100% rename from feature/experimental/isis/otg_tests/lsp_updates_test/metadata.textproto rename to feature/isis/otg_tests/lsp_updates_test/metadata.textproto diff --git a/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto b/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto index bbced9e82ee..2e9a824e2c1 100644 --- a/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto +++ b/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto @@ -34,3 +34,15 @@ platform_exceptions: { match_tag_set_condition_unsupported: true } } +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_interface_in_default_vrf: true + interface_enabled: true + static_protocol_name: "static" + skip_prefix_set_mode: true + enable_table_connections: true + } +} diff --git a/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go b/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go index 231b7b19aa5..9bbc947d8d3 100644 --- a/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go +++ b/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go @@ -63,7 +63,8 @@ const ( protoDst = oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS dummyV6 = "2001:db8::192:0:2:d" dummyMAC = "00:1A:11:00:0A:BC" - tagValue = 100 + V4tagValue = 40 + V6tagValue = 60 ) var ( @@ -113,7 +114,7 @@ func getAndVerifyIsisImportPolicy(t *testing.T, if err != nil { t.Fatalf("failed due to %v", err) } - t.Log(getResponse) + t.Log("Received parameters of table connections") t.Log("Verify Get outputs ") for _, notification := range getResponse.Notification { @@ -142,9 +143,9 @@ func getAndVerifyIsisImportPolicy(t *testing.T, t.Fatalf("import-policy is not set to %s as expected", RplName) } } - t.Logf("Table Connection Details:"+ + t.Logf("Table Connection Details:\n"+ "SRC PROTO GOT %v WANT STATIC\n"+ - "DST PRTO GOT %v WANT ISIS\n"+ + "DST PROTO GOT %v WANT ISIS\n"+ "ADDRESS FAMILY GOT %v WANT %v\n"+ "DISABLEMETRICPROPAGATION GOT %v WANT %v\n", config.SrcProtocol, config.DstProtocol, config.AddressFamily, addressFamily, @@ -171,6 +172,10 @@ func isisImportPolicyConfig(t *testing.T, dut *ondatra.DUTDevice, policyName str if !deviations.SkipSettingDisableMetricPropagation(dut) { tableConn.SetDisableMetricPropagation(metricPropagation) } + if deviations.EnableTableConnections(dut) { + state := "enable" + configEnableTbNative(t, dut, state) + } gnmi.BatchReplace(batchSet, gnmi.OC().NetworkInstance(dni).TableConnection(srcProto, dstProto, addfmly).Config(), tableConn) if deviations.SamePolicyAttachedToAllAfis(dut) { @@ -206,7 +211,9 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri v4Prefix := v4Route + "/" + strconv.FormatUint(uint64(v4RoutePrefix), 10) pset := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v4PrefixSet) pset.GetOrCreatePrefix(v4Prefix, prefixMatch) - pset.SetMode(oc.PrefixSet_Mode_IPV4) + if !deviations.SkipPrefixSetMode(dut) { + pset.SetMode(oc.PrefixSet_Mode_IPV4) + } stmt1.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v4PrefixSet) stmt1.GetOrCreateActions().SetPolicyResult(rplType) @@ -217,7 +224,9 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri v6Prefix := v6Route + "/" + strconv.FormatUint(uint64(v6RoutePrefix), 10) pset = rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v6PrefixSet) pset.GetOrCreatePrefix(v6Prefix, prefixMatch) - pset.SetMode(oc.PrefixSet_Mode_IPV6) + if !deviations.SkipPrefixSetMode(dut) { + pset.SetMode(oc.PrefixSet_Mode_IPV6) + } stmt2.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v6PrefixSet) stmt2.GetOrCreateActions().SetPolicyResult(rplType) } else if tagSetCond { @@ -228,7 +237,7 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri } v4tagSet := getTagSetName(dut, rplName, v4Statement, "v4") tagSet1 := rp.GetOrCreateDefinedSets().GetOrCreateTagSet(v4tagSet) - tagSet1.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(tagValue)}) + tagSet1.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(V4tagValue)}) stmt1.GetOrCreateConditions().GetOrCreateMatchTagSet().SetTagSet(v4tagSet) stmt1.GetOrCreateActions().SetPolicyResult(rplType) @@ -238,7 +247,7 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri } v6tagSet := getTagSetName(dut, rplName, v6Statement, "v6") tagSet2 := rp.GetOrCreateDefinedSets().GetOrCreateTagSet(v6tagSet) - tagSet2.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(tagValue)}) + tagSet2.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(V6tagValue)}) stmt2.GetOrCreateConditions().GetOrCreateMatchTagSet().SetTagSet(v6tagSet) stmt2.GetOrCreateActions().SetPolicyResult(rplType) } else { @@ -366,6 +375,46 @@ func getTagSetName(dut *ondatra.DUTDevice, policyName, stmtName, afStr string) s return fmt.Sprintf("tag-set-%s", afStr) } +func configEnableTbNative(t testing.TB, d *ondatra.DUTDevice, state string) { + t.Helper() + switch d.Vendor() { + case ondatra.NOKIA: + adminEnable, err := json.Marshal(state) + if err != nil { + t.Fatalf("Error with json Marshal: %v", err) + } + + gpbSetRequest := &gpb.SetRequest{ + Prefix: &gpb.Path{ + Origin: "native", + }, + Update: []*gpb.Update{ + { + Path: &gpb.Path{ + Elem: []*gpb.PathElem{ + {Name: "network-instance", Key: map[string]string{"name": "DEFAULT"}}, + {Name: "table-connections"}, + {Name: "admin-state"}, + }, + }, + Val: &gpb.TypedValue{ + Value: &gpb.TypedValue_JsonIetfVal{ + JsonIetfVal: adminEnable, + }, + }, + }, + }, + } + + gnmiClient := d.RawAPIs().GNMI(t) + if _, err := gnmiClient.Set(context.Background(), gpbSetRequest); err != nil { + t.Fatalf("Unexpected error updating SRL static-route tag-set: %v", err) + } + default: + t.Fatalf("Unsupported vendor %s for deviation 'EnableTableConnections'", d.Vendor()) + } +} + func TestStaticToISISRedistribution(t *testing.T) { var ts *isissession.TestSession @@ -462,6 +511,7 @@ func TestStaticToISISRedistribution(t *testing.T) { desc: "RT-2.12.8: Redistribute IPv6 static route to IS-IS matching a prefix using a route-policy", protoAf: oc.Types_ADDRESS_FAMILY_IPV6, RplName: v6RoutePolicy, + metricPropogation: true, policyStmtType: oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE, verifyTrafficStats: true, trafficFlows: []string{v6Flow}, @@ -497,8 +547,8 @@ func TestStaticToISISRedistribution(t *testing.T) { if tc.TagSetCondition { t.Run("Verify Configuration for RPL TagSet", func(t *testing.T) { - verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v4Statement, "v4"), oc.UnionUint32(tagValue)) - verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v6Statement, "v6"), oc.UnionUint32(tagValue)) + verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v4Statement, "v4"), oc.UnionUint32(V4tagValue)) + verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v6Statement, "v6"), oc.UnionUint32(V6tagValue)) }) } diff --git a/feature/isis/otg_tests/weighted_ecmp_test/README.md b/feature/isis/otg_tests/weighted_ecmp_test/README.md index dee5ca53f52..8a5bdf8448a 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/README.md +++ b/feature/isis/otg_tests/weighted_ecmp_test/README.md @@ -29,23 +29,25 @@ G[DUT:LAG4] <-- IBGP+IS-IS --> H[LAG3:ATE2]; ## Procedure -In the topology above, - -* Configure 1xLAG interface between ATE1<->DUT and 3xLAG interfaces between - DUT and ATE2. Each LAG interface is expected to be of 2x100Gbps - -* Configure IPv4 and IPv6 L2 adjacencies between DUT and ATE LAG bundles. - Therefore, DUT will have 1xIS-IS adjacency with ATE1 i.e. - DUT:LAG1<->ATE1:LAG1, and 3xIS-IS adjacencies with ATE2 i.e. - DUT:LAG2<->ATE2:LAG1, DUT:LAG3<->ATE2:LAG2 and DUT:LAG4<->ATE2:LAG3 - - * /network-instances/network-instance/protocols/protocol/isis/global/afi-safi - - * /network-instances/network-instance/protocols/protocol/isis/global/config/level-capability, - set to LEVEL_2 - - * /network-instances/network-instance/protocols/protocol/isis/levels/level/config/metric-style - set to WIDE_METRIC +### Test environment setup + +* Configure 1 aggregate interface with 2 100GE ports between DUT and ATE1 +* Configure 3 aggregate interfaces, each with 2 100GE ports between DUT and ATE2. +* Configure IPv4 and IPv6 L2 adjacencies between DUT and ATE aggregate interfaces. + Therefore, DUT will have + * 1xIS-IS adjacency with ATE1 DUT:LAG1<->ATE1:LAG1, + * 3xIS-IS adjacencies between DUT and ATE2 + * DUT:LAG2<->ATE2:LAG1 + * DUT:LAG3<->ATE2:LAG2 + * DUT:LAG4<->ATE2:LAG3 + + * Set ISIS parameters as + * /network-instances/network-instance/protocols/protocol/isis/global/ + * afi-safi/af/config/afi-name: IPV4, IPV6 + * afi-safi/af/config/safi-name: UNICAST + * afi-safi/af/config/enabled: true + * config/level-capability = LEVEL_2 + * /network-instances/network-instance/protocols/protocol/isis/levels/level/config/metric-style = WIDE_METRIC * Configure IPv4 and IPv6 IBGP peering between both ATEs and the DUT using their loopback addresses for both IPv4 and IPv6 address families. @@ -74,7 +76,7 @@ In the topology above, * /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/weighted-ecmp/config/load-balancing-weight set to Auto -## RT-9.1: Equal distribution of traffic +## RT-2.13.1: Equal distribution of traffic * Start 1024 flows from IPv4 addresses in 100.0.2.0/24 to 100.0.1.0/24 @@ -114,7 +116,7 @@ In the topology above, * /interfaces/interface/state/counters/in-pkts -## RT-9.2: Unequal distribution of traffic +## RT-2.13.2: Unequal distribution of traffic * Stop traffic from RT-9.1 and introduce a failure by disabling one of the member interfaces in ATE2:LAG1. @@ -142,17 +144,8 @@ In the topology above, * /interfaces/interface/state/counters/in-pkts -### Config paths - -### Telemetry Parameter Coverage - ## OpenConfig Path and RPC Coverage -The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. - -TODO(OCPATH): Container path originally part of spec that needs to be separated -into leaves: /routing-policy/defined-sets/prefix-sets/prefix-set: - ```yaml paths: ## Config Paths ## diff --git a/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto b/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto index 8057787e787..947afd21cf8 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto +++ b/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto @@ -35,3 +35,11 @@ platform_exceptions: { weighted_ecmp_fixed_packet_verification: true } } +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + isis_level_enabled: true + } +} diff --git a/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go b/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go index 9e434f24e2a..64d778f03a5 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go +++ b/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go @@ -2,14 +2,12 @@ package weighted_ecmp_test import ( "fmt" + "math/rand" "testing" "time" - "math/rand" - "github.com/open-traffic-generator/snappi/gosnappi" "github.com/openconfig/featureprofiles/internal/attrs" - "github.com/openconfig/featureprofiles/internal/cfgplugins" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/helpers" @@ -104,8 +102,8 @@ var ( agg4 = &aggPortData{ dutIPv4: "192.0.2.13", ateIPv4: "192.0.2.14", - dutIPv6: "2001:db8::14", - ateIPv6: "2001:db8::15", + dutIPv6: "2001:db8::15", + ateIPv6: "2001:db8::16", ateAggName: "lag4", ateAggMAC: "02:00:01:01:01:10", atePort1MAC: "02:00:01:01:01:11", @@ -174,12 +172,33 @@ func TestWeightedECMPForISIS(t *testing.T) { ate.OTG().PushConfig(t, top) ate.OTG().StartProtocols(t) VerifyISISTelemetry(t, dut, aggIDs, []*aggPortData{agg1, agg2}) + for _, agg := range []*aggPortData{agg1, agg2} { bgpPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() gnmi.Await(t, dut, bgpPath.Neighbor(agg.ateLoopbackV4).SessionState().State(), 2*time.Minute, oc.Bgp_Neighbor_SessionState_ESTABLISHED) gnmi.Await(t, dut, bgpPath.Neighbor(agg.ateLoopbackV6).SessionState().State(), 2*time.Minute, oc.Bgp_Neighbor_SessionState_ESTABLISHED) } + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + + t.Log("Waiting for BGP v4 prefix to be installed") + got, found := gnmi.Watch(t, dut, statePath.Neighbor(agg2.ateLoopbackV4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Prefixes().Installed().State(), 120*time.Second, func(val *ygnmi.Value[uint32]) bool { + prefixCount, ok := val.Val() + return ok && prefixCount == 1 + }).Await(t) + if !found { + t.Fatalf("Installed prefixes v4 mismatch: got %v, want %v", got, 1) + } + + t.Log("Waiting for BGP v6 prefix to be installed") + got, found = gnmi.Watch(t, dut, statePath.Neighbor(agg2.ateLoopbackV6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Prefixes().Installed().State(), 120*time.Second, func(val *ygnmi.Value[uint32]) bool { + prefixCount, ok := val.Val() + return ok && prefixCount == 1 + }).Await(t) + if !found { + t.Fatalf("Installed prefixes v6 mismatch: got %v, want %v", got, 1) + } + startTraffic(t, ate, top) time.Sleep(time.Minute) t.Run("Equal_Distribution_Of_Traffic", func(t *testing.T) { @@ -427,7 +446,6 @@ func configureOTGBGP(t *testing.T, dev gosnappi.Device, agg *aggPortData, advV4, func configureOTGISIS(t *testing.T, dev gosnappi.Device, agg *aggPortData) { t.Helper() - dut := ondatra.DUT(t, "dut") isis := dev.Isis().SetSystemId(agg.ateISISSysID).SetName(agg.ateAggName + ".ISIS") isis.Basic().SetHostname(isis.Name()) isis.Advanced().SetAreaAddresses([]string{ateAreaAddress}) @@ -437,13 +455,12 @@ func configureOTGISIS(t *testing.T, dev gosnappi.Device, agg *aggPortData) { SetNetworkType(gosnappi.IsisInterfaceNetworkType.POINT_TO_POINT). SetLevelType(gosnappi.IsisInterfaceLevelType.LEVEL_2).SetMetric(10) isisInt.Advanced().SetAutoAdjustMtu(true).SetAutoAdjustArea(true).SetAutoAdjustSupportedProtocols(true) - if deviations.ISISLoopbackRequired(dut) { - // configure ISIS loopback interface and advertise them via ISIS. - isisPort2V4 := dev.Isis().V4Routes().Add().SetName(agg.ateAggName + ".ISISV4").SetLinkMetric(10) - isisPort2V4.Addresses().Add().SetAddress(agg.ateLoopbackV4).SetPrefix(32) - isisPort2V6 := dev.Isis().V6Routes().Add().SetName(agg.ateAggName + ".ISISV6").SetLinkMetric(10) - isisPort2V6.Addresses().Add().SetAddress(agg.ateLoopbackV6).SetPrefix(uint32(128)) - } + + // configure ISIS loopback interface and advertise them via ISIS. + isisPort2V4 := dev.Isis().V4Routes().Add().SetName(agg.ateAggName + ".ISISV4").SetLinkMetric(10) + isisPort2V4.Addresses().Add().SetAddress(agg.ateLoopbackV4).SetPrefix(32) + isisPort2V6 := dev.Isis().V6Routes().Add().SetName(agg.ateAggName + ".ISISV6").SetLinkMetric(10) + isisPort2V6.Addresses().Add().SetAddress(agg.ateLoopbackV6).SetPrefix(uint32(128)) } @@ -514,9 +531,6 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) []string { for _, aggID := range aggIDs { gnmi.Await(t, dut, gnmi.OC().Interface(aggID).AdminStatus().State(), 60*time.Second, oc.Interface_AdminStatus_UP) } - if !deviations.ISISLoopbackRequired(dut) { - configureStaticRouteToATELoopbacks(t, dut) - } configureRoutingPolicy(t, dut) configureDUTISIS(t, dut, aggIDs) configureDUTBGP(t, dut) @@ -563,50 +577,6 @@ func configureDUTLoopback(t *testing.T, dut *ondatra.DUTDevice) { } } -func configureStaticRouteToATELoopbacks(t *testing.T, dut *ondatra.DUTDevice) { - t.Helper() - - sr4ATE1 := &cfgplugins.StaticRouteCfg{ - NetworkInstance: deviations.DefaultNetworkInstance(dut), - Prefix: agg1.ateLoopbackV4 + "/32", - NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ - "0": oc.UnionString(agg1.ateIPv4), - }, - } - sr6ATE1 := &cfgplugins.StaticRouteCfg{ - NetworkInstance: deviations.DefaultNetworkInstance(dut), - Prefix: agg1.ateLoopbackV6 + "/128", - NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ - "0": oc.UnionString(agg1.ateIPv6), - }, - } - sr4ATE2 := &cfgplugins.StaticRouteCfg{ - NetworkInstance: deviations.DefaultNetworkInstance(dut), - Prefix: agg2.ateLoopbackV4 + "/32", - NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ - "0": oc.UnionString(agg2.ateIPv4), - "1": oc.UnionString(agg3.ateIPv4), - "2": oc.UnionString(agg4.ateIPv4), - }, - } - sr6ATE2 := &cfgplugins.StaticRouteCfg{ - NetworkInstance: deviations.DefaultNetworkInstance(dut), - Prefix: agg2.ateLoopbackV6 + "/128", - NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ - "0": oc.UnionString(agg2.ateIPv6), - "1": oc.UnionString(agg3.ateIPv6), - "2": oc.UnionString(agg4.ateIPv6), - }, - } - b := &gnmi.SetBatch{} - for _, cfg := range []*cfgplugins.StaticRouteCfg{sr4ATE1, sr6ATE1, sr4ATE2, sr6ATE2} { - if _, err := cfgplugins.NewStaticRouteCfg(b, cfg, dut); err != nil { - t.Fatalf("Failed to configure static route to ATE Loopback: %v", err) - } - } - b.Set(t, dut) -} - func configureDUTISIS(t *testing.T, dut *ondatra.DUTDevice, aggIDs []string) { t.Helper() @@ -632,6 +602,9 @@ func configureDUTISIS(t *testing.T, dut *ondatra.DUTDevice, aggIDs []string) { isisLevel2 := isis.GetOrCreateLevel(2) isisLevel2.MetricStyle = oc.Isis_MetricStyle_WIDE_METRIC + if deviations.ISISLevelEnabled(dut) { + isisLevel2.Enabled = ygot.Bool(true) + } if deviations.ISISLoopbackRequired(dut) { gnmi.Update(t, dut, gnmi.OC().Config(), d) // add loopback interface to ISIS diff --git a/feature/mpls/otg_tests/static_bgp_nexthop/README.md b/feature/mpls/otg_tests/static_bgp_nexthop/README.md new file mode 100644 index 00000000000..7ed0a06fe99 --- /dev/null +++ b/feature/mpls/otg_tests/static_bgp_nexthop/README.md @@ -0,0 +1,121 @@ +# MPLS-2.2: MPLS forwarding via static LSP to BGP next-hop. + +## Summary + +Validate static LSP functionality with BGP resolved next-hop. This test verifies that the DUT can forward MPLS traffic based on a static LSP that uses a next-hop resolved via BGP. + +## Testbed type + +* [`featureprofiles/topologies/atedut_4.testbed`](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_4.testbed) + +## Procedure + +### Configuration + +1) Create the topology below: + + ``` + | | ---- | ATE Port 2 | ---- [eBGP peer] + [ ATE Port 1 ] ---- | DUT | | | + | | ---- | ATE Port 3 | + ``` + +2) Configure eBGP peer on ATE Port 2 interface and advertise `BGP-NH-V4= 203.0.200.0/24` and `BGP-NH-V6= 2001:db8:128:200::/64` +3) Configure static routes on the DUT to discard traffic destined for BGP-NH-V4 and BGP-NH-V6. These routes should point to a Null0 with an administrative distance of 254 to ensure they are less preferred than the BGP routes. This prevents the DUT from using its IGP to reach the BGP next-hops. +4) Enable MPLS forwarding. +5) Create egress static LSP for IPv4 and IPV6 traffic to pop the label and resolve the next-hop BGP-NH-V4 and BGP-NH-V6 respectivelly + +```yaml +network-instances: + - network-instance: + mpls: + lsps: + static-lsps: + - static-lsp: + config: + name: "lsp-egress-v4" + egress: + next-hop: 203.0.200.1 + incoming-label: 1000004 + - static-lsp: + config: + name: "lsp-egress-v6" + egress: + next-hop: 2001:db8:128:200::1 + incoming-label: 1000006 +``` + * Set resolve NH action for both LSPs. + +**TODO:** OC model does not support resolve next-hop option for LSPs. + +7) Configure static routes i.e. `IPV4-DST = 203.0.113.0/24` and `IPV6-DST = 2001:db8:128:128::/64` to ATE Port 3. +```yaml +network-instances: + - network-instance: + protocols: + - protocol: + static-routes: + - static: + config: + prefix: "203.0.113.0/24" + next-hops: + - next-hop: + config: + index: 1 + next-hop: "ATE PORT 3" + - static: + config: + prefix: "2001:db8:128:128::/64" + next-hops: + - next-hop: + config: + index: 1 + next-hop: "ATE PORT 3" +``` + +### MPLS-2.2.1: Verify IPv4 MPLS forwarding + +* Push the above DUT configuration. +* Start traffic flow with MPLS[lbl-1000004] and IPv4 destined to IPV4-DST. +* Verify that traffic arrives to ATE Port 2. + +### MPLS-2.2.2: Verify IPv6 MPLS forwarding + +* Push the above DUT configuration. +* Start traffic flow with MPLS[lbl-1000006] and IPv4 destined to IPV6-DST. +* Verify that traffic arrives to ATE Port 2. + +### MPLS-2.2.3: Verify IPv4 traffic discard when BGP-NH is not available. + +* Withdraw BGP-NH-V4 advertisement. +* Push the above DUT configuration. +* Start traffic flow with MPLS[lbl-1000004] and IPv4 destination set to IPV4-DST. +* Verify that traffic is discarded. + +### MPLS-2.2.4: Verify IPv6 traffic discard when BGP-NH is not available. + +* Withdraw BGP-NH-V6 advertisement. +* Push the above DUT configuration. +* Start traffic flow with MPLS[lbl-1000006] and IPv6 destination set to IPV6-DST. +* Verify that traffic is discarded. + +## OpenConfig Path and RPC Coverage + +```yaml +paths: + ## Config paths + /network-instances/network-instance/mpls/lsps/static-lsps/static-lsp/egress/config/incoming-label: + /network-instances/network-instance/mpls/lsps/static-lsps/static-lsp/egress/config/next-hop: + /network-instances/network-instance/protocols/protocol/static-routes/static/config/prefix: + /network-instances/network-instance/protocols/protocol/static-routes/static/next-hops/next-hop/config/next-hop: + /network-instances/network-instance/protocols/protocol/static-routes/static/next-hops/next-hop/config/index: + + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true +``` \ No newline at end of file diff --git a/feature/networkinstance/otg_tests/defaults_test/README.md b/feature/networkinstance/otg_tests/defaults_test/README.md index 9e7da08764d..a5ac736175e 100644 --- a/feature/networkinstance/otg_tests/defaults_test/README.md +++ b/feature/networkinstance/otg_tests/defaults_test/README.md @@ -2,12 +2,21 @@ TODO(robshakir): fill in test plan from code already written. +## Description + +This test verifies that the IPv4 and IPv6 address families are enabled within a network instance by default. + +## Test Procedure + +* Configure an ATE with port1 connected to DUT port1, and port2 connected to DUT port2. +* Configure the DUT to have: + * these interfaces within the `DEFAULT` network instance and validate that traffic can be forwarded between ATE port1 and ATE port2. + * these interfaces within a non-default `L3VRF` and validate that traffic can be forwarded between ATE port1 and ATE port2. + ## OpenConfig Path and RPC Coverage The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. -TODO(robshakir): fill in coverage from code already written. - ```yaml paths: rpcs: diff --git a/feature/networkinstance/otg_tests/defaults_test/defaults_test.go b/feature/networkinstance/otg_tests/defaults_test/defaults_test.go index 9c1aa24c511..0e7355e012e 100644 --- a/feature/networkinstance/otg_tests/defaults_test/defaults_test.go +++ b/feature/networkinstance/otg_tests/defaults_test/defaults_test.go @@ -18,6 +18,7 @@ package ni_address_families_test import ( "fmt" + "slices" "testing" "time" @@ -103,6 +104,7 @@ var ( IPv6Len: 64, MAC: "02:00:02:01:01:01", } + kneDeviceModelList = []string{"ncptx", "ceos", "srlinux", "xrd"} ) // TestDefaultAddressFamilies verifies that both IPv4 and IPv6 are enabled by default without a need for additional @@ -181,6 +183,14 @@ func TestDefaultAddressFamilies(t *testing.T) { otgutils.WaitForARP(t, ate.OTG(), top, "IPv4") otgutils.WaitForARP(t, ate.OTG(), top, "IPv6") + // https://github.com/openconfig/featureprofiles/issues/3410 + // Below code will be removed once ixia issue is fixed. + if slices.Contains(kneDeviceModelList, dut.Model()) { + ate.OTG().StartTraffic(t) + time.Sleep(15 * time.Second) + ate.OTG().StopTraffic(t) + } + ate.OTG().StartTraffic(t) time.Sleep(15 * time.Second) ate.OTG().StopTraffic(t) diff --git a/feature/experimental/p4rt/README.md b/feature/p4rt/README.md similarity index 94% rename from feature/experimental/p4rt/README.md rename to feature/p4rt/README.md index a2dc5701736..3acc900e9fc 100644 --- a/feature/experimental/p4rt/README.md +++ b/feature/p4rt/README.md @@ -52,9 +52,9 @@ This document specifies the requirements for p4rt test implementation. `p4rtutils.P4RTNodesByPort()`. ## OpenConfig Path and RPC Coverage - -The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. - ```yaml - +rpcs: + gnmi: + gNMI.Set: + gNMI.Subscribe: ``` diff --git a/feature/experimental/p4rt/otg_tests/base_p4rt/README.md b/feature/p4rt/otg_tests/base_p4rt/README.md similarity index 73% rename from feature/experimental/p4rt/otg_tests/base_p4rt/README.md rename to feature/p4rt/otg_tests/base_p4rt/README.md index e4ca8068fb1..e690e261459 100644 --- a/feature/experimental/p4rt/otg_tests/base_p4rt/README.md +++ b/feature/p4rt/otg_tests/base_p4rt/README.md @@ -24,19 +24,16 @@ Validate that the P4RT server can accept basic configuration and Read/Write RPCs * Repeat the same steps for another FAP and verify the Table entries. - -## Config Parameter Coverage - -* /components/component/integrated-circuit/config/node-id -* /interfaces/interface/config/id - - -## Telemetry Parameter coverage - -No new telemetry covered. - - -## Protocol/RPC Parameter coverage - -No new Protocol/RPC covered. +## OpenConfig Path and RPC Coverage +```yaml +paths: + /components/component/integrated-circuit/config/node-id: + platform_type: ["INTEGRATED_CIRCUIT"] + /interfaces/interface/config/id: +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/experimental/p4rt/otg_tests/base_p4rt/base_p4rt_test.go b/feature/p4rt/otg_tests/base_p4rt/base_p4rt_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/base_p4rt/base_p4rt_test.go rename to feature/p4rt/otg_tests/base_p4rt/base_p4rt_test.go diff --git a/feature/experimental/p4rt/otg_tests/base_p4rt/metadata.textproto b/feature/p4rt/otg_tests/base_p4rt/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/base_p4rt/metadata.textproto rename to feature/p4rt/otg_tests/base_p4rt/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md b/feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md similarity index 86% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md rename to feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md index a5bffb0cdd9..8c5f6f83043 100644 --- a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md +++ b/feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md @@ -14,13 +14,14 @@ Verify that GDP packets are punted with correct metadata. * Verify that the packet has the ingress_singleton_port metadata set and it corresponds to the interface ID of the port that the packet was received on. -## Config Parameter coverage - -No new configuration covered. - -## Telemetry Parameter coverage - -No new telemetry covered. +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/google_discovery_protocol_packetin_test.go b/feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/google_discovery_protocol_packetin_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/google_discovery_protocol_packetin_test.go rename to feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/google_discovery_protocol_packetin_test.go diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/metadata.textproto b/feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/metadata.textproto rename to feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/README.md b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/README.md similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/README.md rename to feature/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/README.md diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/google_discovery_protocol_packetout_lag_test.go b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/google_discovery_protocol_packetout_lag_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/google_discovery_protocol_packetout_lag_test.go rename to feature/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/google_discovery_protocol_packetout_lag_test.go diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/metadata.textproto b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/metadata.textproto rename to feature/p4rt/otg_tests/google_discovery_protocol_packetout_lag_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md similarity index 87% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md rename to feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md index 8d6fd5b5870..d1ba03f1f5b 100644 --- a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md +++ b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md @@ -15,15 +15,14 @@ Verify that GDP packets can be sent by the controller. * Repeat sending the packet in the same way but from the secondary connection. * Verify that the packet is not received on the ATE. - - -## Config Parameter coverage - -No new configuration covered. - -## Telemetry Parameter coverage - -No new telemetry covered. +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/google_discovery_protocol_packetout_test.go b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/google_discovery_protocol_packetout_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/google_discovery_protocol_packetout_test.go rename to feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/google_discovery_protocol_packetout_test.go diff --git a/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/metadata.textproto b/feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/metadata.textproto rename to feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/lldp_packetin_test/README.md b/feature/p4rt/otg_tests/lldp_packetin_test/README.md similarity index 85% rename from feature/experimental/p4rt/otg_tests/lldp_packetin_test/README.md rename to feature/p4rt/otg_tests/lldp_packetin_test/README.md index 4af42c8c091..e3398a89860 100644 --- a/feature/experimental/p4rt/otg_tests/lldp_packetin_test/README.md +++ b/feature/p4rt/otg_tests/lldp_packetin_test/README.md @@ -13,15 +13,14 @@ Verify that LLDP packets are punted with correct metadata. * Send an LLDP packet from the ATE and verify that it is received by the client. * Verify that the packet has the ingress_singleton_port metadata set and it corresponds to the interface ID of the port that the packet was received on. - - -## Config Parameter coverage - -No new configuration covered. - -## Telemetry Parameter coverage - -No new telemetry covered. +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/p4rt/otg_tests/lldp_packetin_test/lldp_packetin_test.go b/feature/p4rt/otg_tests/lldp_packetin_test/lldp_packetin_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/lldp_packetin_test/lldp_packetin_test.go rename to feature/p4rt/otg_tests/lldp_packetin_test/lldp_packetin_test.go diff --git a/feature/experimental/p4rt/otg_tests/lldp_packetin_test/metadata.textproto b/feature/p4rt/otg_tests/lldp_packetin_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/lldp_packetin_test/metadata.textproto rename to feature/p4rt/otg_tests/lldp_packetin_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/lldp_packetout_test/README.md b/feature/p4rt/otg_tests/lldp_packetout_test/README.md similarity index 80% rename from feature/experimental/p4rt/otg_tests/lldp_packetout_test/README.md rename to feature/p4rt/otg_tests/lldp_packetout_test/README.md index ec9b4d9d73a..97616953d12 100644 --- a/feature/experimental/p4rt/otg_tests/lldp_packetout_test/README.md +++ b/feature/p4rt/otg_tests/lldp_packetout_test/README.md @@ -13,17 +13,13 @@ Verify that LLDP packets can be sent by the controller. * Send an LLDP packet from the client with egress_singleton_port set to one of the connected interfaces. * Verify that the LLDP packet is received on the ATE port connected to the indicated interface. - - - -## Config Parameter coverage - -No new configuration covered. - -## Telemetry Parameter coverage - -No new telemetry covered. - -## Minimum DUT platform requirement +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` vRX if the vendor implementation supports FIB-ACK simulation, otherwise FFF. \ No newline at end of file diff --git a/feature/experimental/p4rt/otg_tests/lldp_packetout_test/lldp_packetout_test.go b/feature/p4rt/otg_tests/lldp_packetout_test/lldp_packetout_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/lldp_packetout_test/lldp_packetout_test.go rename to feature/p4rt/otg_tests/lldp_packetout_test/lldp_packetout_test.go diff --git a/feature/experimental/p4rt/otg_tests/lldp_packetout_test/metadata.textproto b/feature/p4rt/otg_tests/lldp_packetout_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/lldp_packetout_test/metadata.textproto rename to feature/p4rt/otg_tests/lldp_packetout_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/performance_test/README.md b/feature/p4rt/otg_tests/performance_test/README.md similarity index 73% rename from feature/experimental/p4rt/otg_tests/performance_test/README.md rename to feature/p4rt/otg_tests/performance_test/README.md index 470f6c467be..fb7d6b31e32 100644 --- a/feature/experimental/p4rt/otg_tests/performance_test/README.md +++ b/feature/p4rt/otg_tests/performance_test/README.md @@ -15,21 +15,18 @@ Verify that both Packetin and Packetout traffic is handled by the P4RT server at * Setup packetout packets for GDP, LLDP and traceroute from the P4RT client. * Start both packetin and packetout traffic at the same rate simultaneously. * Verify no packetloss for both directions of traffic. -* Verify the metadata ID and the value for all three traffic types on the P4RT client for packetin. - - -## Config Parameter coverage - -* /components/component/integrated-circuit/config/node-id -* /interfaces/interface/config/id - - -## Telemetry Parameter coverage - -No new telemetry covered. - - -## Protocol/RPC Parameter coverage - -No new Protocol/RPC covered. +* Verify the metadata ID and the value for all three traffic types on the P4RT client for packetin. + +## OpenConfig Path and RPC Coverage +```yaml +paths: + /components/component/integrated-circuit/config/node-id: + platform_type: ["INTEGRATED_CIRCUIT"] + /interfaces/interface/config/id: +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/experimental/p4rt/otg_tests/performance_test/metadata.textproto b/feature/p4rt/otg_tests/performance_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/performance_test/metadata.textproto rename to feature/p4rt/otg_tests/performance_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/performance_test/performance_test.go b/feature/p4rt/otg_tests/performance_test/performance_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/performance_test/performance_test.go rename to feature/p4rt/otg_tests/performance_test/performance_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_test/README.md b/feature/p4rt/otg_tests/traceroute_packetin_test/README.md similarity index 73% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_test/README.md rename to feature/p4rt/otg_tests/traceroute_packetin_test/README.md index 8a69af7d868..0aee47016e4 100644 --- a/feature/experimental/p4rt/otg_tests/traceroute_packetin_test/README.md +++ b/feature/p4rt/otg_tests/traceroute_packetin_test/README.md @@ -16,19 +16,15 @@ Verify that Traceroute packets are punted with correct metadata. * Send IPv6 packets from the ATE with HopLimit=1 and verify that packets with HopLimit=1 are received by the client. * Verify that the packets have both ingress_singleton_port and egress_singleton_port metadata set. - -## Config Parameter coverage - -* /components/component/integrated-circuit/config/node-id -* /interfaces/interface/config/id - - -## Telemetry Parameter coverage - -No new telemetry covered. - - -## Protocol/RPC Parameter coverage - -No new Protocol/RPC covered. - +## OpenConfig Path and RPC Coverage +```yaml +paths: + /components/component/integrated-circuit/config/node-id: + platform_type: ["INTEGRATED_CIRCUIT"] + /interfaces/interface/config/id: +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_test/metadata.textproto b/feature/p4rt/otg_tests/traceroute_packetin_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_test/metadata.textproto rename to feature/p4rt/otg_tests/traceroute_packetin_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_test/packetin_test.go b/feature/p4rt/otg_tests/traceroute_packetin_test/packetin_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_test/packetin_test.go rename to feature/p4rt/otg_tests/traceroute_packetin_test/packetin_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_test/traceroute_packetin_test.go b/feature/p4rt/otg_tests/traceroute_packetin_test/traceroute_packetin_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_test/traceroute_packetin_test.go rename to feature/p4rt/otg_tests/traceroute_packetin_test/traceroute_packetin_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/README.md b/feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/README.md similarity index 98% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/README.md rename to feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/README.md index d15347dad27..ec980072fd7 100644 --- a/feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/README.md +++ b/feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/README.md @@ -17,7 +17,7 @@ DUT port-8 <------> port-8 ATE ## Baseline setup -* Setup equivalent to [TE-17.1 vrf_policy_driven_te](https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/gribi/otg_tests/vrf_policy_driven_te/README.md), including GRibi programming. +* Setup equivalent to [TE-17.1 vrf_policy_driven_te](https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/vrf_policy_driven_te/README.md), including GRibi programming. * Install a BGP route resolved by ISIS in default VRF to route traffic out of DUT port-8 for 203.0.113.0. diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/metadata.textproto b/feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/metadata.textproto rename to feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/packetin_test.go b/feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/packetin_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/packetin_test.go rename to feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/packetin_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_test.go b/feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_test.go rename to feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_with_vrf_selection_test.go b/feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_with_vrf_selection_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_with_vrf_selection_test.go rename to feature/p4rt/otg_tests/traceroute_packetin_with_vrf_selection_test/traceroute_packetin_with_vrf_selection_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetout_test/README.md b/feature/p4rt/otg_tests/traceroute_packetout_test/README.md similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetout_test/README.md rename to feature/p4rt/otg_tests/traceroute_packetout_test/README.md diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetout_test/metadata.textproto b/feature/p4rt/otg_tests/traceroute_packetout_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetout_test/metadata.textproto rename to feature/p4rt/otg_tests/traceroute_packetout_test/metadata.textproto diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetout_test/packetout_test.go b/feature/p4rt/otg_tests/traceroute_packetout_test/packetout_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetout_test/packetout_test.go rename to feature/p4rt/otg_tests/traceroute_packetout_test/packetout_test.go diff --git a/feature/experimental/p4rt/otg_tests/traceroute_packetout_test/traceroute_packetout_test.go b/feature/p4rt/otg_tests/traceroute_packetout_test/traceroute_packetout_test.go similarity index 100% rename from feature/experimental/p4rt/otg_tests/traceroute_packetout_test/traceroute_packetout_test.go rename to feature/p4rt/otg_tests/traceroute_packetout_test/traceroute_packetout_test.go diff --git a/feature/experimental/p4rt/tests/metadata_validation_test/README.md b/feature/p4rt/tests/metadata_validation_test/README.md similarity index 81% rename from feature/experimental/p4rt/tests/metadata_validation_test/README.md rename to feature/p4rt/tests/metadata_validation_test/README.md index 8ad072ab172..8a311ea7d05 100644 --- a/feature/experimental/p4rt/tests/metadata_validation_test/README.md +++ b/feature/p4rt/tests/metadata_validation_test/README.md @@ -23,3 +23,16 @@ Validate the P4RT server handles Metadata set in Table Entry correctly. ## Notes * [P4RT Proto](https://github.com/p4lang/p4runtime/blob/main/proto/p4/v1/p4runtime.proto) + +## OpenConfig Path and RPC Coverage +```yaml +paths: + /components/component/integrated-circuit/config/node-id: + platform_type: ["INTEGRATED_CIRCUIT"] + /interfaces/interface/config/id: +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/experimental/p4rt/tests/metadata_validation_test/metadata.textproto b/feature/p4rt/tests/metadata_validation_test/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/tests/metadata_validation_test/metadata.textproto rename to feature/p4rt/tests/metadata_validation_test/metadata.textproto diff --git a/feature/experimental/p4rt/tests/metadata_validation_test/metadata_validation_test.go b/feature/p4rt/tests/metadata_validation_test/metadata_validation_test.go similarity index 100% rename from feature/experimental/p4rt/tests/metadata_validation_test/metadata_validation_test.go rename to feature/p4rt/tests/metadata_validation_test/metadata_validation_test.go diff --git a/feature/experimental/p4rt/tests/p4rt_election/README.md b/feature/p4rt/tests/p4rt_election/README.md similarity index 96% rename from feature/experimental/p4rt/tests/p4rt_election/README.md rename to feature/p4rt/tests/p4rt_election/README.md index 5b77cea3ccf..9226182e9e4 100644 --- a/feature/experimental/p4rt/tests/p4rt_election/README.md +++ b/feature/p4rt/tests/p4rt_election/README.md @@ -106,3 +106,16 @@ Validate the P4RT server handles primary election and failover. writes for clients with `election_id=9` & `election_id=10`. * TODO: Enable P4RT on an additional FAP and verify that the same set of scenarios work independently of the first FAP + +## OpenConfig Path and RPC Coverage +```yaml +paths: + /components/component/integrated-circuit/config/node-id: + platform_type: ["INTEGRATED_CIRCUIT"] + /interfaces/interface/config/id: +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/experimental/p4rt/tests/p4rt_election/metadata.textproto b/feature/p4rt/tests/p4rt_election/metadata.textproto similarity index 100% rename from feature/experimental/p4rt/tests/p4rt_election/metadata.textproto rename to feature/p4rt/tests/p4rt_election/metadata.textproto diff --git a/feature/experimental/p4rt/tests/p4rt_election/p4rt_election_test.go b/feature/p4rt/tests/p4rt_election/p4rt_election_test.go similarity index 100% rename from feature/experimental/p4rt/tests/p4rt_election/p4rt_election_test.go rename to feature/p4rt/tests/p4rt_election/p4rt_election_test.go diff --git a/feature/experimental/p4rt/wbb.p4info.pb.txt b/feature/p4rt/wbb.p4info.pb.txt similarity index 100% rename from feature/experimental/p4rt/wbb.p4info.pb.txt rename to feature/p4rt/wbb.p4info.pb.txt diff --git a/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/README.md b/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/README.md index 0f026d1ced4..9b02357681f 100644 --- a/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/README.md +++ b/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/README.md @@ -102,3 +102,24 @@ rpcs: ## Required DUT platform * MFF + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /interfaces/interface/config/enabled: + /interfaces/interface/subinterfaces/subinterface/ipv4/config/enabled: + /interfaces/interface/subinterfaces/subinterface/ipv6/config/enabled: + /components/component/fabric/config/power-admin-state: + + ## State paths: N/A + +rpcs: + gnmi: + gNMI.Set: + Replace: +``` \ No newline at end of file diff --git a/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/metadata.textproto b/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/metadata.textproto index 099686c7f73..6dad9d53b5d 100644 --- a/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/metadata.textproto +++ b/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/metadata.textproto @@ -13,18 +13,6 @@ platform_exceptions: { ipv4_missing_enabled: true } } -platform_exceptions: { - platform: { - vendor: NOKIA - } - deviations: { - interface_enabled: true - explicit_port_speed: true - explicit_interface_in_default_vrf: true - qos_queue_requires_id: true - missing_value_for_defaults: true - } -} platform_exceptions: { platform: { vendor: ARISTA diff --git a/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/sampled_backplane_capacity_counters_test.go b/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/sampled_backplane_capacity_counters_test.go index 651bb61d582..0fe6d2973ad 100644 --- a/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/sampled_backplane_capacity_counters_test.go +++ b/feature/platform/fabric/otg_tests/sampled_backplane_capacity_counters_test/sampled_backplane_capacity_counters_test.go @@ -53,7 +53,7 @@ func TestMain(m *testing.M) { func TestSampledBackplaneCapacityCounters(t *testing.T) { dut := ondatra.DUT(t, "dut") - ics := components.FindComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_INTEGRATED_CIRCUIT) + ics := components.FindActiveComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_INTEGRATED_CIRCUIT) if len(ics) == 0 { t.Fatalf("Get IntegratedCircuit card list for %q: got 0, want > 0", dut.Model()) } @@ -65,7 +65,6 @@ func TestSampledBackplaneCapacityCounters(t *testing.T) { if !isCompNameExpected(t, ic, dut.Vendor()) { continue } - t.Run(fmt.Sprintf("Backplane:%s", ic), func(t *testing.T) { if deviations.BackplaneFacingCapacityUnsupported(dut) { t.Skipf("Skipping check for BackplanceFacingCapacity due to deviation BackplaneFacingCapacityUnsupported") @@ -110,20 +109,16 @@ func gnmiOptsForOnChange(t *testing.T, dut *ondatra.DUTDevice) *gnmi.Opts { func TestOnChangeBackplaneCapacityCounters(t *testing.T) { dut := ondatra.DUT(t, "dut") - ics := components.FindComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_INTEGRATED_CIRCUIT) + ics := components.FindActiveComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_INTEGRATED_CIRCUIT) if len(ics) == 0 { t.Fatalf("Get IntegratedCircuit card list for %q: got 0, want > 0", dut.Model()) } t.Logf("IntegratedCircuit components count: %d", len(ics)) - fabrics := components.FindComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_FABRIC) + fabrics := components.FindActiveComponentsByType(t, dut, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_FABRIC) t.Logf("fabrics are %v", fabrics) removable_fabrics := make([]string, 0) for _, f := range fabrics { - compMtyVal, compMtyPresent := gnmi.Lookup(t, dut, gnmi.OC().Component(f).Empty().State()).Val() - if compMtyPresent && compMtyVal { - continue - } if gnmi.Get(t, dut, gnmi.OC().Component(f).Removable().State()) { removable_fabrics = append(removable_fabrics, f) } @@ -226,7 +221,6 @@ func getBackplaneCapacityCounters(t *testing.T, dut *ondatra.DUTDevice, ics []st if !isCompNameExpected(t, ic, dut.Vendor()) { continue } - t.Run(fmt.Sprintf("Backplane:%s", ic), func(t *testing.T) { if deviations.BackplaneFacingCapacityUnsupported(dut) { t.Skipf("Skipping check for BackplanceFacingCapacity due to deviation BackplaneFacingCapacityUnsupported") diff --git a/feature/platform/tests/breakout_configuration/README.md b/feature/platform/tests/breakout_configuration/README.md new file mode 100644 index 00000000000..1cccdf903c4 --- /dev/null +++ b/feature/platform/tests/breakout_configuration/README.md @@ -0,0 +1,41 @@ +# PLT-1.1: Interface breakout Test + +## Summary + +Validate Interface breakout configuration. + +## Procedure + + +* This test is carried out for different breakout types +* Connect DUT with ATE to all interfaces in the breakout port +* Configure each interface with test IP addressing +* Verify correct interface state and speed reported +* Verify that DUT responds to ARP/ICMP on all tested interfaces + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + /components/component/port/breakout-mode/groups/group/index: + platform_type: [ "PORT" ] + /components/component/port/breakout-mode/groups/group/config/index: + platform_type: [ "PORT" ] + /components/component/port/breakout-mode/groups/group/config/num-breakouts: + platform_type: [ "PORT" ] + /components/component/port/breakout-mode/groups/group/config/breakout-speed: + platform_type: [ "PORT" ] + /components/component/port/breakout-mode/groups/group/config/num-physical-channels: + platform_type: [ "PORT" ] +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` + +## Minimum DUT Platform Requirement + +* Breakout types - 4x100G, 2x100G and 4x10G diff --git a/feature/experimental/platform/tests/optics_thresholds_test/README.md b/feature/platform/tests/optics_thresholds_test/README.md similarity index 52% rename from feature/experimental/platform/tests/optics_thresholds_test/README.md rename to feature/platform/tests/optics_thresholds_test/README.md index 39f318faab4..9126d3eb914 100644 --- a/feature/experimental/platform/tests/optics_thresholds_test/README.md +++ b/feature/platform/tests/optics_thresholds_test/README.md @@ -8,7 +8,7 @@ Validate optics high and low thresholds for input power, output power, temperatu * Connect at least one optical ethernet interface to ATE. * Check all the transceivers with inslalled optcs. -* Validate that the following optics threshold telemetry paths exist for each optics. +* Validate that the optics threshold telemetry paths exist for each optics. * Output power thresholds: * /components/component/Ethernet/properties/property/laser-tx-power-low-alarm-threshold/state/value * /components/component/Ethernet/properties/property/laser-tx-power-high-alarm-threshold/state/value @@ -30,32 +30,17 @@ Validate optics high and low thresholds for input power, output power, temperatu * /components/component/Ethernet/properties/property/laser-bias-current-low-warn-threshold/state/value * /components/component/Ethernet/properties/property/laser-bias-current-high-warn-threshold/state/value - -## Config Parameter coverage +## OpenConfig Path and RPC Coverage -* None +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` -## Telemetry Parameter coverage - * Output power thresholds: - * /components/component/Ethernet/properties/property/laser-tx-power-low-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-tx-power-high-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-tx-power-low-warn-threshold/state/value - * /components/component/Ethernet/properties/property/laser-tx-power-high-warn-threshold/state/value - * Input power threshold: - * /components/component/Ethernet/properties/property/laser-rx-power-low-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-rx-power-high-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-rx-power-low-warn-threshold/state/value - * /components/component/Ethernet/properties/property/laser-rx-power-high-warn-threshold/state/value - * Optics temperature threshold: - * /components/component/Ethernet/properties/property/laser-temperature-low-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-temperature-high-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-temperature-low-warn-threshold/state/value - * /components/component/Ethernet/properties/property/laser-temperature-high-warn-threshold/state/value - * Optics bias-current threshold: - * /components/component/Ethernet/properties/property/laser-bias-current-low-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-bias-current-high-alarm-threshold/state/value - * /components/component/Ethernet/properties/property/laser-bias-current-low-warn-threshold/state/value - * /components/component/Ethernet/properties/property/laser-bias-current-high-warn-threshold/state/value - ## Notes: * The model for optics threshold paths is not finalized. We may need to update those paths after the model is finalized. diff --git a/feature/experimental/platform/tests/optics_thresholds_test/metadata.textproto b/feature/platform/tests/optics_thresholds_test/metadata.textproto similarity index 100% rename from feature/experimental/platform/tests/optics_thresholds_test/metadata.textproto rename to feature/platform/tests/optics_thresholds_test/metadata.textproto diff --git a/feature/experimental/platform/tests/optics_thresholds_test/optics_thresholds_test.go b/feature/platform/tests/optics_thresholds_test/optics_thresholds_test.go similarity index 100% rename from feature/experimental/platform/tests/optics_thresholds_test/optics_thresholds_test.go rename to feature/platform/tests/optics_thresholds_test/optics_thresholds_test.go diff --git a/feature/platform/tests/power_admin_down_up_test/README.md b/feature/platform/tests/power_admin_down_up_test/README.md index 229f9c52ed7..9ecf373081a 100644 --- a/feature/platform/tests/power_admin_down_up_test/README.md +++ b/feature/platform/tests/power_admin_down_up_test/README.md @@ -21,11 +21,27 @@ ControllerCard. to POWER_ENABLED. * Verify /components/component/state/oper-status returns to ACTIVE. -## Config Parameter coverage +## Minumum DUT platform requirement +vRX -* /components/component/{fabric|linecard|controller-card}/config/power-admin-state +## Config Parameter coverage + * /components/component/{fabric|linecard|controller-card}/config/power-admin-state ## Telemetry Parameter coverage + * /components/component/state/oper-status + * /components/component/{fabric|linecard|controller-card}/state/power-admin-state + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths and RPC intended to be covered by this test. + +```yaml +paths: +/components/component/name: +/components/component/state/name: -* /components/component/state/oper-status -* /components/component/{fabric|linecard|controller-card}/state/power-admin-state +rpcs: + gnmi: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/platform/tests/power_admin_down_up_test/metadata.textproto b/feature/platform/tests/power_admin_down_up_test/metadata.textproto index ae49957c730..58ef621af8e 100644 --- a/feature/platform/tests/power_admin_down_up_test/metadata.textproto +++ b/feature/platform/tests/power_admin_down_up_test/metadata.textproto @@ -30,3 +30,12 @@ platform_exceptions: { skip_controller_card_power_admin: true } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + power_disable_enable_leaf_ref_validation: true + } +} + diff --git a/feature/platform/tests/power_admin_down_up_test/power_admin_down_up_test.go b/feature/platform/tests/power_admin_down_up_test/power_admin_down_up_test.go index d536abd7f5c..9a0f3ff5e63 100644 --- a/feature/platform/tests/power_admin_down_up_test/power_admin_down_up_test.go +++ b/feature/platform/tests/power_admin_down_up_test/power_admin_down_up_test.go @@ -14,6 +14,7 @@ import ( "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" ) func TestMain(m *testing.M) { @@ -106,7 +107,7 @@ func TestControllerCardPowerAdmin(t *testing.T) { t.Skipf("ControllerCard Component %s is already INACTIVE, hence skipping", c) } - powerDownUp(t, dut, c, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_CONTROLLER_CARD, 3*time.Minute) + powerDownUp(t, dut, c, oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_CONTROLLER_CARD, 5*time.Minute) }) } if primary != "" { @@ -132,7 +133,11 @@ func powerDownUp(t *testing.T, dut *ondatra.DUTDevice, name string, cType oc.E_P default: t.Fatalf("Unknown component type: %s", cType.String()) } - + if deviations.PowerDisableEnableLeafRefValidation(dut) { + gnmi.Update(t, dut, c.Config(), &oc.Component{ + Name: ygot.String(name), + }) + } start := time.Now() t.Logf("Starting %s POWER_DISABLE", name) gnmi.Replace(t, dut, config, oc.Platform_ComponentPowerType_POWER_DISABLED) diff --git a/feature/platform/tests/telemetry_inventory_test/telemetry_inventory_test.go b/feature/platform/tests/telemetry_inventory_test/telemetry_inventory_test.go index 22212c8ffd7..d29c7c73452 100644 --- a/feature/platform/tests/telemetry_inventory_test/telemetry_inventory_test.go +++ b/feature/platform/tests/telemetry_inventory_test/telemetry_inventory_test.go @@ -1055,7 +1055,7 @@ func TestDefaultPowerAdminState(t *testing.T) { t.Logf("Supervisors: %v", supervisors) if len(fabrics) != 0 { - pas := gnmi.Get(t, dut, gnmi.OC().Component(fabrics[0].GetName()).Fabric().PowerAdminState().Config()) + pas := gnmi.Get(t, dut, gnmi.OC().Component(fabrics[0].GetName()).Fabric().PowerAdminState().State()) t.Logf("Component %s PowerAdminState: %v", fabrics[0].GetName(), pas) if pas == oc.Platform_ComponentPowerType_UNSET { t.Errorf("Component %s PowerAdminState is unset", fabrics[0].GetName()) @@ -1063,7 +1063,7 @@ func TestDefaultPowerAdminState(t *testing.T) { } if len(linecards) != 0 { - pas := gnmi.Get(t, dut, gnmi.OC().Component(linecards[0].GetName()).Linecard().PowerAdminState().Config()) + pas := gnmi.Get(t, dut, gnmi.OC().Component(linecards[0].GetName()).Linecard().PowerAdminState().State()) t.Logf("Component %s PowerAdminState: %v", linecards[0].GetName(), pas) if pas == oc.Platform_ComponentPowerType_UNSET { t.Errorf("Component %s PowerAdminState is unset", linecards[0].GetName()) @@ -1071,7 +1071,7 @@ func TestDefaultPowerAdminState(t *testing.T) { } if !deviations.SkipControllerCardPowerAdmin(dut) { if len(supervisors) != 0 { - pas := gnmi.Get(t, dut, gnmi.OC().Component(supervisors[0].GetName()).ControllerCard().PowerAdminState().Config()) + pas := gnmi.Get(t, dut, gnmi.OC().Component(supervisors[0].GetName()).ControllerCard().PowerAdminState().State()) t.Logf("Component %s PowerAdminState: %v", supervisors[0].GetName(), pas) if pas == oc.Platform_ComponentPowerType_UNSET { t.Errorf("Component %s PowerAdminState is unset", supervisors[0].GetName()) diff --git a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto index 501d2cce28f..f2bd6231241 100644 --- a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto @@ -15,3 +15,13 @@ platform_exceptions: { missing_port_to_optical_channel_component_mapping: true } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + otn_channel_trib_unsupported: true + eth_channel_ingress_parameters_unsupported: true + eth_channel_assignment_cisco_numbering: true + } +} diff --git a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go index 9cb628c6189..8dd5f140adf 100644 --- a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go +++ b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go @@ -83,9 +83,7 @@ func TestZrUncorrectableFrames(t *testing.T) { for _, port := range ports { t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { dp := dut.Port(t, port) - gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) - streamFecOtn := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndexes[dp.Name()]).Otn().FecUncorrectableBlocks().State(), sampleInterval) defer streamFecOtn.Close() validateFecUncorrectableBlocks(t, streamFecOtn) @@ -98,13 +96,13 @@ func TestZrUncorrectableFrames(t *testing.T) { // Disable interface i.Enabled = ygot.Bool(false) gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) - // Wait for the cooling off period + // Wait for the cooling-off period gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) // Enable interface i.Enabled = ygot.Bool(true) gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) - // Wait for the cooling off period + // Wait for the cooling-off period gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) validateFecUncorrectableBlocks(t, streamFecOtn) diff --git a/feature/platform/transceiver/tests/zr_firmware_version_test/zr_firmware_version_test.go b/feature/platform/transceiver/tests/zr_firmware_version_test/zr_firmware_version_test.go index b71efad53db..a5b9f9de78f 100644 --- a/feature/platform/transceiver/tests/zr_firmware_version_test/zr_firmware_version_test.go +++ b/feature/platform/transceiver/tests/zr_firmware_version_test/zr_firmware_version_test.go @@ -19,6 +19,7 @@ import ( "testing" "time" + "github.com/openconfig/featureprofiles/internal/cfgplugins" "github.com/openconfig/featureprofiles/internal/components" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/samplestream" @@ -29,7 +30,6 @@ import ( ) const ( - dp16QAM = 1 targetOutputPower = -10 frequency = 193100000 ) @@ -46,8 +46,13 @@ func configInterface(t *testing.T, dut1 *ondatra.DUTDevice, dp *ondatra.Port, en i.Enabled = ygot.Bool(enable) i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd gnmi.Replace(t, dut1, gnmi.OC().Interface(dp.Name()).Config(), i) - component := components.OpticalChannelComponentFromPort(t, dut1, dp) - gnmi.Replace(t, dut1, gnmi.OC().Component(component).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + componentName := components.OpticalChannelComponentFromPort(t, dut1, dp) + // Set config container leaf for optical channel + component := gnmi.OC().Component(componentName) + gnmi.Replace(t, dut1, component.Config(), &oc.Component{ + Name: ygot.String(componentName), + }) + gnmi.Replace(t, dut1, component.OpticalChannel().Config(), &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(targetOutputPower), Frequency: ygot.Uint64(frequency), }) @@ -74,8 +79,8 @@ func TestZRFirmwareVersionState(t *testing.T) { dp2 := dut1.Port(t, "port2") t.Logf("dut1: %v", dut1) t.Logf("dut1 dp1 name: %v", dp1.Name()) - configInterface(t, dut1, dp1, true) - configInterface(t, dut1, dp2, true) + cfgplugins.InterfaceConfig(t, dut1, dp1) + cfgplugins.InterfaceConfig(t, dut1, dp2) gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), time.Minute*2, oc.Interface_OperStatus_UP) transceiverName := gnmi.Get(t, dut1, gnmi.OC().Interface(dp1.Name()).Transceiver().State()) // Check if TRANSCEIVER is of type 400ZR @@ -97,8 +102,8 @@ func TestZRFirmwareVersionStateInterfaceFlap(t *testing.T) { dp2 := dut1.Port(t, "port2") t.Logf("dut1: %v", dut1) t.Logf("dut1 dp1 name: %v", dp1.Name()) - configInterface(t, dut1, dp1, true) - configInterface(t, dut1, dp2, true) + cfgplugins.InterfaceConfig(t, dut1, dp1) + cfgplugins.InterfaceConfig(t, dut1, dp2) gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) transceiverName := gnmi.Get(t, dut1, gnmi.OC().Interface(dp1.Name()).Transceiver().State()) // Check if TRANSCEIVER is of type 400ZR @@ -111,7 +116,7 @@ func TestZRFirmwareVersionStateInterfaceFlap(t *testing.T) { p1Stream := samplestream.New(t, dut1, component1.FirmwareVersion().State(), 10*time.Second) - // Wait 60 sec cooling off period + // Wait 60 sec cooling-off period gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), 2*time.Minute, oc.Interface_OperStatus_DOWN) verifyFirmwareVersionValue(t, dut1, p1Stream) diff --git a/feature/platform/transceiver/tests/zr_laser_bias_current_test/zr_laser_bias_current_test.go b/feature/platform/transceiver/tests/zr_laser_bias_current_test/zr_laser_bias_current_test.go index 80e67d6649b..bdc31e8f363 100644 --- a/feature/platform/transceiver/tests/zr_laser_bias_current_test/zr_laser_bias_current_test.go +++ b/feature/platform/transceiver/tests/zr_laser_bias_current_test/zr_laser_bias_current_test.go @@ -15,10 +15,10 @@ package zr_laser_bias_current_test import ( - "reflect" "testing" "time" + "github.com/openconfig/featureprofiles/internal/cfgplugins" "github.com/openconfig/featureprofiles/internal/components" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" @@ -29,12 +29,6 @@ import ( "github.com/openconfig/ygot/ygot" ) -const ( - dp16QAM = 1 - targetOutputPower = -10 - frequency = 193500000 -) - func TestMain(m *testing.M) { fptest.RunTests(m) } @@ -43,93 +37,73 @@ func TestMain(m *testing.M) { // dut:port1 <--> port2:dut // -func verifyLaserBiasCurrent(t *testing.T, pStream *samplestream.SampleStream[float64], sensorName string) float64 { - laserBias := pStream.Next() +func verifyLaserBiasValue(t *testing.T, laserBiasValue float64) { + t.Helper() + if laserBiasValue <= 0 && laserBiasValue >= 131 { + t.Errorf("The laser bias value is not between 0 and 131") + } +} + +func verifyLaserBiasCurrentAll(t *testing.T, p1Stream *samplestream.SampleStream[*oc.Component_OpticalChannel_LaserBiasCurrent], dut1 *ondatra.DUTDevice) { + laserBias := p1Stream.Next() if laserBias == nil { - t.Fatalf("laserBias telemetry %q was not streamed in the most recent subscription interval", sensorName) + t.Fatalf("laserBias telemetry was not streamed in the most recent subscription interval") } laserBiasVal, ok := laserBias.Val() if !ok { - t.Fatalf("LaserBias %q telemetry is not present", sensorName) - } - if reflect.TypeOf(laserBiasVal).Kind() != reflect.Float64 { - t.Errorf("Return value is not type float64") - } - if laserBiasVal <= 0 && laserBiasVal >= 131 { - t.Errorf("The laser bias value is not between 0 and 131") + t.Fatalf("LaserBias telemetry is not present") } - t.Logf("laserBias value: %f", laserBiasVal) - return laserBiasVal -} - -func verifyLaserBiasCurrentAll(t *testing.T, pStreamInstant *samplestream.SampleStream[float64], pStreamAvg *samplestream.SampleStream[float64], pStreamMax *samplestream.SampleStream[float64], pStreamMin *samplestream.SampleStream[float64], dut1 *ondatra.DUTDevice) { - laserbiasInstant := verifyLaserBiasCurrent(t, pStreamInstant, "laserbiasInstant") - t.Logf("laserBias Instant value: %f", laserbiasInstant) + laserBiasInstant := laserBiasVal.GetInstant() + t.Logf("laserBias Instant value: %f", laserBiasInstant) if deviations.MissingZROpticalChannelTunableParametersTelemetry(dut1) { t.Log("Skipping Min/Max/Avg Tunable Parameters Telemetry validation. Deviation MissingZROpticalChannelTunableParametersTelemetry enabled.") } else { - laserbiasMin := verifyLaserBiasCurrent(t, pStreamMin, "laserbiasMin") - t.Logf("laserBias Min value: %f", laserbiasMin) - laserbiasMax := verifyLaserBiasCurrent(t, pStreamMax, "laserbiasMax") - t.Logf("laserBias Max value: %f", laserbiasMax) - laserbiasAvg := verifyLaserBiasCurrent(t, pStreamAvg, "laserbiasAvg") - t.Logf("laserBias Avg value: %f", laserbiasAvg) - if laserbiasAvg >= laserbiasMin && laserbiasAvg <= laserbiasMax { - t.Logf("The average is between the maximum and minimum values") + laserBiasMin := laserBiasVal.GetMin() + verifyLaserBiasValue(t, laserBiasMin) + t.Logf("laserBias Min value: %f", laserBiasMin) + laserBiasMax := laserBiasVal.GetMax() + verifyLaserBiasValue(t, laserBiasMax) + t.Logf("laserBias Max value: %f", laserBiasMax) + laserBiasAvg := laserBiasVal.GetAvg() + verifyLaserBiasValue(t, laserBiasAvg) + t.Logf("laserBias Avg value: %f", laserBiasMin) + if laserBiasAvg >= laserBiasMin && laserBiasAvg <= laserBiasMax { + t.Logf("The average %f is between the maximum and minimum values", laserBiasAvg) } else { - t.Fatalf("The average is not between the maximum and minimum values Avg:%f Min:%f Max:%f", laserbiasAvg, laserbiasMin, laserbiasMax) + t.Fatalf("The average is not between the maximum and minimum values Avg:%f Min:%f Max:%f", laserBiasAvg, laserBiasMin, laserBiasMax) } } } -func interfaceConfig(t *testing.T, dut1 *ondatra.DUTDevice, dp *ondatra.Port) { - d := &oc.Root{} - i := d.GetOrCreateInterface(dp.Name()) - i.Enabled = ygot.Bool(true) - i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd - gnmi.Replace(t, dut1, gnmi.OC().Interface(dp.Name()).Config(), i) - OCcomponent := components.OpticalChannelComponentFromPort(t, dut1, dp) - gnmi.Replace(t, dut1, gnmi.OC().Component(OCcomponent).OpticalChannel().Config(), &oc.Component_OpticalChannel{ - TargetOutputPower: ygot.Float64(targetOutputPower), - Frequency: ygot.Uint64(frequency), - }) -} - func TestZRLaserBiasCurrentState(t *testing.T) { dut1 := ondatra.DUT(t, "dut") dp1 := dut1.Port(t, "port1") dp2 := dut1.Port(t, "port2") t.Logf("dut1: %v", dut1) t.Logf("dut1 dp1 name: %v", dp1.Name()) - interfaceConfig(t, dut1, dp1) - interfaceConfig(t, dut1, dp2) + cfgplugins.InterfaceConfig(t, dut1, dp1) + cfgplugins.InterfaceConfig(t, dut1, dp2) intUpdateTime := 2 * time.Minute gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) transceiverState := gnmi.Get(t, dut1, gnmi.OC().Interface(dp1.Name()).Transceiver().State()) if dp1.PMD() != ondatra.PMD400GBASEZR { t.Fatalf("%s Transceiver is not 400ZR its of type: %v", transceiverState, dp1.PMD()) } - OCcomponent := components.OpticalChannelComponentFromPort(t, dut1, dp1) - component1 := gnmi.OC().Component(OCcomponent) - p1StreamInstant := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Instant().State(), 10*time.Second) - p1StreamMin := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Min().State(), 10*time.Second) - p1StreamMax := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Max().State(), 10*time.Second) - p1StreamAvg := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Avg().State(), 10*time.Second) - defer p1StreamAvg.Close() - defer p1StreamMax.Close() - defer p1StreamMin.Close() - defer p1StreamInstant.Close() - verifyLaserBiasCurrentAll(t, p1StreamInstant, p1StreamAvg, p1StreamMax, p1StreamMin, dut1) + componentName := components.OpticalChannelComponentFromPort(t, dut1, dp1) + component := gnmi.OC().Component(componentName) + p1Stream := samplestream.New(t, dut1, component.OpticalChannel().LaserBiasCurrent().State(), 10*time.Second) + defer p1Stream.Close() + verifyLaserBiasCurrentAll(t, p1Stream, dut1) } -func TestZRLaserBiasCurrentStateInterface_Flap(t *testing.T) { +func TestZRLaserBiasCurrentStateInterfaceFlap(t *testing.T) { dut1 := ondatra.DUT(t, "dut") dp1 := dut1.Port(t, "port1") dp2 := dut1.Port(t, "port2") t.Logf("dut1: %v", dut1) t.Logf("dut1 dp1 name: %v", dp1.Name()) - interfaceConfig(t, dut1, dp1) - interfaceConfig(t, dut1, dp2) + cfgplugins.InterfaceConfig(t, dut1, dp1) + cfgplugins.InterfaceConfig(t, dut1, dp2) intUpdateTime := 2 * time.Minute // Check interface is up gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) @@ -144,25 +118,19 @@ func TestZRLaserBiasCurrentStateInterface_Flap(t *testing.T) { i.Enabled = ygot.Bool(false) i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd gnmi.Replace(t, dut1, gnmi.OC().Interface(dp1.Name()).Config(), i) - OCcomponent := components.OpticalChannelComponentFromPort(t, dut1, dp1) - component1 := gnmi.OC().Component(OCcomponent) - p1StreamInstant := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Instant().State(), 10*time.Second) - p1StreamMin := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Min().State(), 10*time.Second) - p1StreamMax := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Max().State(), 10*time.Second) - p1StreamAvg := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Avg().State(), 10*time.Second) - defer p1StreamInstant.Close() - defer p1StreamMin.Close() - defer p1StreamMax.Close() - defer p1StreamAvg.Close() - verifyLaserBiasCurrentAll(t, p1StreamInstant, p1StreamAvg, p1StreamMax, p1StreamMin, dut1) - // Wait 120 sec cooling off period + componentName := components.OpticalChannelComponentFromPort(t, dut1, dp1) + component := gnmi.OC().Component(componentName) + p1Stream := samplestream.New(t, dut1, component.OpticalChannel().LaserBiasCurrent().State(), 10*time.Second) + defer p1Stream.Close() + verifyLaserBiasCurrentAll(t, p1Stream, dut1) + // Wait 120 sec cooling-off period gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) + verifyLaserBiasCurrentAll(t, p1Stream, dut1) // Enable interface - verifyLaserBiasCurrentAll(t, p1StreamInstant, p1StreamAvg, p1StreamMax, p1StreamMin, dut1) i.Enabled = ygot.Bool(true) gnmi.Replace(t, dut1, gnmi.OC().Interface(dp1.Name()).Config(), i) gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) - verifyLaserBiasCurrentAll(t, p1StreamInstant, p1StreamAvg, p1StreamMax, p1StreamMin, dut1) + verifyLaserBiasCurrentAll(t, p1Stream, dut1) } func TestZRLaserBiasCurrentStateTransceiverOnOff(t *testing.T) { @@ -171,8 +139,8 @@ func TestZRLaserBiasCurrentStateTransceiverOnOff(t *testing.T) { dp2 := dut1.Port(t, "port2") t.Logf("dut1: %v", dut1) t.Logf("dut1 dp1 name: %v", dp1.Name()) - interfaceConfig(t, dut1, dp1) - interfaceConfig(t, dut1, dp2) + cfgplugins.InterfaceConfig(t, dut1, dp1) + cfgplugins.InterfaceConfig(t, dut1, dp2) intUpdateTime := 2 * time.Minute gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) transceiverState := gnmi.Get(t, dut1, gnmi.OC().Interface(dp1.Name()).Transceiver().State()) @@ -180,21 +148,17 @@ func TestZRLaserBiasCurrentStateTransceiverOnOff(t *testing.T) { if dp1.PMD() != ondatra.PMD400GBASEZR { t.Fatalf("%s Transceiver is not 400ZR its of type: %v", transceiverState, dp1.PMD()) } - OCcomponent := components.OpticalChannelComponentFromPort(t, dut1, dp1) - component1 := gnmi.OC().Component(OCcomponent) - p1StreamInstant := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Instant().State(), 10*time.Second) - p1StreamMin := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Min().State(), 10*time.Second) - p1StreamMax := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Max().State(), 10*time.Second) - p1StreamAvg := samplestream.New(t, dut1, component1.OpticalChannel().LaserBiasCurrent().Avg().State(), 10*time.Second) - defer p1StreamInstant.Close() - defer p1StreamMin.Close() - defer p1StreamMax.Close() - defer p1StreamAvg.Close() - // Disable interface transceiver power off + componentName := components.OpticalChannelComponentFromPort(t, dut1, dp1) + component := gnmi.OC().Component(componentName) + p1Stream := samplestream.New(t, dut1, component.OpticalChannel().LaserBiasCurrent().State(), 10*time.Second) + defer p1Stream.Close() + verifyLaserBiasCurrentAll(t, p1Stream, dut1) + // power off interface transceiver + gnmi.Update(t, dut1, gnmi.OC().Component(dp1.Name()).Name().Config(), dp1.Name()) gnmi.Update(t, dut1, gnmi.OC().Component(dp1.Name()).Transceiver().Enabled().Config(), false) - verifyLaserBiasCurrentAll(t, p1StreamInstant, p1StreamAvg, p1StreamMax, p1StreamMin, dut1) - // Enable interface transceiver power on + verifyLaserBiasCurrentAll(t, p1Stream, dut1) + // power on interface transceiver gnmi.Update(t, dut1, gnmi.OC().Component(dp1.Name()).Transceiver().Enabled().Config(), true) gnmi.Await(t, dut1, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) - verifyLaserBiasCurrentAll(t, p1StreamInstant, p1StreamAvg, p1StreamMax, p1StreamMin, dut1) + verifyLaserBiasCurrentAll(t, p1Stream, dut1) } diff --git a/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto b/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto index caa9410e80a..fb942581ff5 100644 --- a/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto @@ -14,3 +14,14 @@ platform_exceptions: { missing_port_to_optical_channel_component_mapping: true } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + otn_channel_trib_unsupported: true + eth_channel_ingress_parameters_unsupported: true + eth_channel_assignment_cisco_numbering: true + otn_channel_assignment_cisco_numbering: true + } +} \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go b/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go index 06dca4f91ed..fdf5d9220e8 100644 --- a/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go +++ b/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go @@ -1,6 +1,8 @@ package zr_logical_channels_test import ( + "flag" + "strings" "testing" "time" @@ -8,6 +10,7 @@ import ( "github.com/openconfig/featureprofiles/internal/attrs" "github.com/openconfig/featureprofiles/internal/cfgplugins" "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/samplestream" "github.com/openconfig/ondatra" @@ -18,7 +21,6 @@ import ( const ( targetOutputPower = -9 frequency = 193100000 - dp16QAM = 1 samplingInterval = 10 * time.Second timeout = 10 * time.Minute otnIndex1 = uint32(4001) @@ -33,21 +35,32 @@ var ( IPv4: "192.0.2.1", IPv4Len: 30, } - dutPort2 = attrs.Attributes{ Desc: "dutPort2", IPv4: "192.0.2.5", IPv4Len: 30, } + operationalModeFlag = flag.Int("operational_mode", 1, "vendor-specific operational-mode for the channel") + operationalMode uint16 ) +type testcase struct { + desc string + got any + want any +} + func TestMain(m *testing.M) { fptest.RunTests(m) } func Test400ZRLogicalChannels(t *testing.T) { dut := ondatra.DUT(t, "dut") - + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } p1 := dut.Port(t, "port1") p2 := dut.Port(t, "port2") @@ -61,10 +74,10 @@ func Test400ZRLogicalChannels(t *testing.T) { tr1 := gnmi.Get(t, dut, gnmi.OC().Interface(p1.Name()).Transceiver().State()) tr2 := gnmi.Get(t, dut, gnmi.OC().Interface(p2.Name()).Transceiver().State()) - cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetOutputPower, dp16QAM) + cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetOutputPower, operationalMode) cfgplugins.ConfigOTNChannel(t, dut, oc1, otnIndex1, ethernetIndex1) cfgplugins.ConfigETHChannel(t, dut, p1.Name(), tr1, otnIndex1, ethernetIndex1) - cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetOutputPower, dp16QAM) + cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetOutputPower, operationalMode) cfgplugins.ConfigOTNChannel(t, dut, oc2, otnIndex2, ethernetIndex2) cfgplugins.ConfigETHChannel(t, dut, p2.Name(), tr2, otnIndex2, ethernetIndex2) @@ -80,13 +93,13 @@ func Test400ZRLogicalChannels(t *testing.T) { gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) - validateEthernetChannelTelemetry(t, otnIndex1, ethernetIndex1, ethChan1) - validateEthernetChannelTelemetry(t, otnIndex2, ethernetIndex2, ethChan2) - validateOTNChannelTelemetry(t, otnIndex1, ethernetIndex1, oc1, otnChan1) - validateOTNChannelTelemetry(t, otnIndex2, ethernetIndex2, oc2, otnChan2) + validateEthernetChannelTelemetry(t, dut, otnIndex1, ethernetIndex1, ethChan1) + validateEthernetChannelTelemetry(t, dut, otnIndex2, ethernetIndex2, ethChan2) + validateOTNChannelTelemetry(t, dut, otnIndex1, ethernetIndex1, oc1, otnChan1) + validateOTNChannelTelemetry(t, dut, otnIndex2, ethernetIndex2, oc2, otnChan2) } -func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint32, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { +func validateEthernetChannelTelemetry(t *testing.T, dut *ondatra.DUTDevice, otnChIdx, ethernetChIdx uint32, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { val := stream.Next() // value received in the gnmi subscription within 10 seconds if val == nil { t.Fatalf("Ethernet Channel telemetry stream not received in last 10 seconds") @@ -95,11 +108,7 @@ func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint if !ok { t.Fatalf("Ethernet Channel telemetry stream empty in last 10 seconds") } - tcs := []struct { - desc string - got any - want any - }{ + tcs := []testcase{ { desc: "Index", got: ec.GetIndex(), @@ -120,32 +129,64 @@ func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint got: ec.GetTribProtocol().String(), want: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE.String(), }, - { - desc: "Assignment: Index", - got: ec.GetAssignment(0).GetIndex(), - want: uint32(0), - }, - { - desc: "Assignment: Logical Channel", - got: ec.GetAssignment(0).GetLogicalChannel(), - want: otnChIdx, - }, - { - desc: "Assignment: Description", - got: ec.GetAssignment(0).GetDescription(), - want: "ETH to OTN", - }, - { - desc: "Assignment: Allocation", - got: ec.GetAssignment(0).GetAllocation(), - want: float64(400), - }, - { - desc: "Assignment: Type", - got: ec.GetAssignment(0).GetAssignmentType().String(), - want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), - }, } + var assignmentIndexTestcases []testcase + + if deviations.EthChannelAssignmentCiscoNumbering(dut) { + assignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: ec.GetAssignment(1).GetIndex(), + want: uint32(1)}, + { + desc: "Assignment: Logical Channel", + got: ec.GetAssignment(1).GetLogicalChannel(), + want: otnChIdx, + }, + { + desc: "Assignment: Description", + got: ec.GetAssignment(1).GetDescription(), + want: "ETH to OTN", + }, + { + desc: "Assignment: Allocation", + got: ec.GetAssignment(1).GetAllocation(), + want: float64(400), + }, + { + desc: "Assignment: Type", + got: ec.GetAssignment(1).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), + }} + } else { + assignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: ec.GetAssignment(0).GetIndex(), + want: uint32(0), + }, + { + desc: "Assignment: Logical Channel", + got: ec.GetAssignment(0).GetLogicalChannel(), + want: otnChIdx, + }, + { + desc: "Assignment: Description", + got: ec.GetAssignment(0).GetDescription(), + want: "ETH to OTN", + }, + { + desc: "Assignment: Allocation", + got: ec.GetAssignment(0).GetAllocation(), + want: float64(400), + }, + { + desc: "Assignment: Type", + got: ec.GetAssignment(0).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), + }} + } + tcs = append(tcs, assignmentIndexTestcases...) for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { if diff := cmp.Diff(tc.got, tc.want); diff != "" { @@ -155,7 +196,7 @@ func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint } } -func validateOTNChannelTelemetry(t *testing.T, otnChIdx uint32, ethChIdx uint32, opticalChannel string, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { +func validateOTNChannelTelemetry(t *testing.T, dut *ondatra.DUTDevice, otnChIdx uint32, ethChIdx uint32, opticalChannel string, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { val := stream.Next() // value received in the gnmi subscription within 10 seconds if val == nil { t.Fatalf("OTN Channel telemetry stream not received in last 10 seconds") @@ -164,11 +205,7 @@ func validateOTNChannelTelemetry(t *testing.T, otnChIdx uint32, ethChIdx uint32, if !ok { t.Fatalf("OTN Channel telemetry stream empty in last 10 seconds") } - tcs := []struct { - desc string - got any - want any - }{ + tcs := []testcase{ { desc: "Description", got: cc.GetDescription(), @@ -184,56 +221,97 @@ func validateOTNChannelTelemetry(t *testing.T, otnChIdx uint32, ethChIdx uint32, got: cc.GetLogicalChannelType().String(), want: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN.String(), }, - { - desc: "Optical Channel Assignment: Index", - got: cc.GetAssignment(0).GetIndex(), - want: uint32(0), - }, - { - desc: "Optical Channel Assignment: Optical Channel", - got: cc.GetAssignment(0).GetOpticalChannel(), - want: opticalChannel, - }, - { - desc: "Optical Channel Assignment: Description", - got: cc.GetAssignment(0).GetDescription(), - want: "OTN to Optical Channel", - }, - { - desc: "Optical Channel Assignment: Allocation", - got: cc.GetAssignment(0).GetAllocation(), - want: float64(400), - }, - { - desc: "Optical Channel Assignment: Type", - got: cc.GetAssignment(0).GetAssignmentType().String(), - want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), - }, - { - desc: "Ethernet Assignment: Index", - got: cc.GetAssignment(1).GetIndex(), - want: uint32(1), - }, - { - desc: "Ethernet Assignment: Logical Channel", - got: cc.GetAssignment(1).GetLogicalChannel(), - want: ethChIdx, - }, - { - desc: "Ethernet Assignment: Description", - got: cc.GetAssignment(1).GetDescription(), - want: "OTN to ETH", - }, - { - desc: "Ethernet Assignment: Allocation", - got: cc.GetAssignment(1).GetAllocation(), - want: float64(400), - }, - { - desc: "Ethernet Assignment: Type", - got: cc.GetAssignment(1).GetAssignmentType().String(), - want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), - }, + } + var opticalChannelAssignmentIndexTestcases []testcase + + if deviations.OTNChannelAssignmentCiscoNumbering(dut) { + ciscoOpticalChannelFormat := strings.ReplaceAll(opticalChannel, "/", "_") // Ex: OpticalChannel0_0_0_18 + opticalChannelAssignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: cc.GetAssignment(1).GetIndex(), + want: uint32(1), + }, + { + desc: "Optical Channel Assignment: Optical Channel", + got: cc.GetAssignment(1).GetOpticalChannel(), + want: ciscoOpticalChannelFormat, + }, + { + desc: "Optical Channel Assignment: Description", + got: cc.GetAssignment(1).GetDescription(), + want: "OTN to Optical Channel", + }, + { + desc: "Optical Channel Assignment: Allocation", + got: cc.GetAssignment(1).GetAllocation(), + want: float64(400), + }, + { + desc: "Optical Channel Assignment: Type", + got: cc.GetAssignment(1).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), + }, + } + } else { + opticalChannelAssignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: cc.GetAssignment(0).GetIndex(), + want: uint32(0)}, + { + desc: "Optical Channel Assignment: Optical Channel", + got: cc.GetAssignment(0).GetOpticalChannel(), + want: opticalChannel, + }, + { + desc: "Optical Channel Assignment: Description", + got: cc.GetAssignment(0).GetDescription(), + want: "OTN to Optical Channel", + }, + { + desc: "Optical Channel Assignment: Allocation", + got: cc.GetAssignment(0).GetAllocation(), + want: float64(400), + }, + { + desc: "Optical Channel Assignment: Type", + got: cc.GetAssignment(0).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), + }, + } + } + tcs = append(tcs, opticalChannelAssignmentIndexTestcases...) + + if !deviations.OTNChannelTribUnsupported(dut) { + logicalChannelAssignmentTestcases := []testcase{ + { + desc: "Ethernet Assignment: Index", + got: cc.GetAssignment(1).GetIndex(), + want: uint32(1), + }, + { + desc: "Ethernet Assignment: Logical Channel", + got: cc.GetAssignment(1).GetLogicalChannel(), + want: ethChIdx, + }, + { + desc: "Ethernet Assignment: Description", + got: cc.GetAssignment(1).GetDescription(), + want: "OTN to ETH", + }, + { + desc: "Ethernet Assignment: Allocation", + got: cc.GetAssignment(1).GetAllocation(), + want: float64(400), + }, + { + desc: "Ethernet Assignment: Type", + got: cc.GetAssignment(1).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), + }, + } + tcs = append(tcs, logicalChannelAssignmentTestcases...) } for _, tc := range tcs { diff --git a/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go b/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go index b8bdc687167..c43e72e44a2 100644 --- a/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go +++ b/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/components" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/samplestream" "github.com/openconfig/ondatra" @@ -30,8 +31,7 @@ import ( ) const ( - samplingInterval = 10 * time.Second - intUpdateTime = 2 * time.Minute + intUpdateTime = 2 * time.Minute ) func TestMain(m *testing.M) { @@ -82,7 +82,7 @@ func TestLowPowerMode(t *testing.T) { dut := ondatra.DUT(t, "dut") cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port1")) cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port2")) - + samplingInterval := 10 * time.Second for _, port := range []string{"port1", "port2"} { t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { dp := dut.Port(t, port) @@ -129,35 +129,36 @@ func TestLowPowerMode(t *testing.T) { gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) validateStreamOutput(t, allStream) - - opInst := samplestream.New(t, dut, gnmi.OC().Component(tr).OpticalChannel().OutputPower().Instant().State(), samplingInterval) + opticalChannelName := components.OpticalChannelComponentFromPort(t, dut, dp) + samplingInterval = time.Duration(gnmi.Get(t, dut, gnmi.OC().Component(opticalChannelName).OpticalChannel().OutputPower().Interval().State())) + opInst := samplestream.New(t, dut, gnmi.OC().Component(opticalChannelName).OpticalChannel().OutputPower().Instant().State(), samplingInterval) defer opInst.Close() if opInstN := opInst.Next(); opInstN != nil { - if _, ok := opInstN.Val(); ok { + if val, ok := opInstN.Val(); ok && val != -40 { t.Fatalf("streaming /components/component/optical-channel/state/output-power/instant is not expected to be reported") } } - opAvg := samplestream.New(t, dut, gnmi.OC().Component(tr).OpticalChannel().OutputPower().Avg().State(), samplingInterval) + opAvg := samplestream.New(t, dut, gnmi.OC().Component(opticalChannelName).OpticalChannel().OutputPower().Avg().State(), samplingInterval) defer opAvg.Close() if opAvgN := opAvg.Next(); opAvgN != nil { - if _, ok := opAvgN.Val(); ok { + if val, ok := opAvgN.Val(); ok && val != -40 { t.Fatalf("streaming /components/component/optical-channel/state/output-power/avg is not expected to be reported") } } - opMin := samplestream.New(t, dut, gnmi.OC().Component(tr).OpticalChannel().OutputPower().Min().State(), samplingInterval) + opMin := samplestream.New(t, dut, gnmi.OC().Component(opticalChannelName).OpticalChannel().OutputPower().Min().State(), samplingInterval) defer opMin.Close() if opMinN := opMin.Next(); opMinN != nil { - if _, ok := opMinN.Val(); ok { + if val, ok := opMinN.Val(); ok && val != -40 { t.Fatalf("streaming /components/component/optical-channel/state/output-power/min is not expected to be reported") } } - opMax := samplestream.New(t, dut, gnmi.OC().Component(tr).OpticalChannel().OutputPower().Max().State(), samplingInterval) + opMax := samplestream.New(t, dut, gnmi.OC().Component(opticalChannelName).OpticalChannel().OutputPower().Max().State(), samplingInterval) defer opMax.Close() if opMaxN := opMax.Next(); opMaxN != nil { - if _, ok := opMaxN.Val(); ok { + if val, ok := opMaxN.Val(); ok && val != -40 { t.Fatalf("streaming /components/component/optical-channel/state/output-power/max is not expected to be reported") } } @@ -173,7 +174,6 @@ func TestLowPowerMode(t *testing.T) { "min": opMin, "max": opMax, } - validateOutputPower(t, powerStreamMap) cfgplugins.ValidateInterfaceConfig(t, dut, dp) }) diff --git a/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto b/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto index 91557f86ff6..e7ad71ae9dd 100644 --- a/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto @@ -13,3 +13,14 @@ platform_exceptions: { default_network_instance: "default" } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + otn_channel_trib_unsupported: true + eth_channel_ingress_parameters_unsupported: true + eth_channel_assignment_cisco_numbering: true + cisco_pre_fec_ber_inactive_value: true + } + } \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go b/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go index 455bf38a6cf..4ffd98c8287 100644 --- a/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go +++ b/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go @@ -1,10 +1,12 @@ package zr_pm_test import ( + "flag" "testing" "time" "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/samplestream" "github.com/openconfig/ondatra" @@ -14,7 +16,6 @@ import ( ) const ( - dp16QAM = uint16(1) samplingInterval = 10 * time.Second minAllowedQValue = 7.0 maxAllowedQValue = 14.0 @@ -26,7 +27,6 @@ const ( inactivePreFECBER = 0.0 inactiveESNR = 0.0 timeout = 10 * time.Minute - flapInterval = 30 * time.Second otnIndexBase = uint32(4000) ethernetIndexBase = uint32(40000) ) @@ -34,6 +34,8 @@ const ( var ( frequencies = []uint64{191400000, 196100000} targetOpticalPowers = []float64{-9, -13} + operationalModeFlag = flag.Int("operational_mode", 1, "vendor-specific operational-mode for the channel") + operationalMode uint16 ) func TestMain(m *testing.M) { @@ -42,7 +44,11 @@ func TestMain(m *testing.M) { func TestPM(t *testing.T) { dut := ondatra.DUT(t, "dut") - + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } fptest.ConfigureDefaultNetworkInstance(t, dut) var ( @@ -71,7 +77,7 @@ func TestPM(t *testing.T) { for _, targetOpticalPower := range targetOpticalPowers { // Configure OCH component and OTN and ETH logical channels. for _, p := range dut.Ports() { - cfgplugins.ConfigOpticalChannel(t, dut, ochs[p.Name()], frequency, targetOpticalPower, dp16QAM) + cfgplugins.ConfigOpticalChannel(t, dut, ochs[p.Name()], frequency, targetOpticalPower, operationalMode) cfgplugins.ConfigOTNChannel(t, dut, ochs[p.Name()], otnIndexes[p.Name()], ethIndexes[p.Name()]) cfgplugins.ConfigETHChannel(t, dut, p.Name(), trs[p.Name()], otnIndexes[p.Name()], ethIndexes[p.Name()]) } @@ -135,7 +141,7 @@ func validateAllSamples(t *testing.T, dut *ondatra.DUTDevice, isEnabled bool, in if valIndex >= len(otnStreams[p.Name()].All()) { break } - operStatus := validateSampleStream(t, interfaceStreams[p.Name()].All()[valIndex], otnStreams[p.Name()].All()[valIndex], p.Name()) + operStatus := validateSampleStream(t, dut, interfaceStreams[p.Name()].All()[valIndex], otnStreams[p.Name()].All()[valIndex], p.Name()) switch operStatus { case oc.Interface_OperStatus_UP: if !isEnabled { @@ -151,7 +157,7 @@ func validateAllSamples(t *testing.T, dut *ondatra.DUTDevice, isEnabled bool, in } // validateSampleStream validates the stream data. -func validateSampleStream(t *testing.T, interfaceData *ygnmi.Value[*oc.Interface], terminalDeviceData *ygnmi.Value[*oc.TerminalDevice_Channel], portName string) oc.E_Interface_OperStatus { +func validateSampleStream(t *testing.T, dut *ondatra.DUTDevice, interfaceData *ygnmi.Value[*oc.Interface], terminalDeviceData *ygnmi.Value[*oc.TerminalDevice_Channel], portName string) oc.E_Interface_OperStatus { if interfaceData == nil { t.Errorf("Data not received for port %v.", portName) return oc.Interface_OperStatus_UNSET @@ -179,7 +185,11 @@ func validateSampleStream(t *testing.T, interfaceData *ygnmi.Value[*oc.Interface if b := otn.GetPreFecBer(); b == nil { t.Errorf("PreFECBER data is empty for port %v", portName) } else { - validatePMValue(t, portName, "PreFECBER", b.GetInstant(), b.GetMin(), b.GetMax(), b.GetAvg(), minAllowedPreFECBER, maxAllowedPreFECBER, inactivePreFECBER, operStatus) + if deviations.CiscoPreFECBERInactiveValue(dut) { + validatePMValue(t, portName, "PreFECBER", b.GetInstant(), b.GetMin(), b.GetMax(), b.GetAvg(), minAllowedPreFECBER, maxAllowedPreFECBER, 0.5, operStatus) + } else { + validatePMValue(t, portName, "PreFECBER", b.GetInstant(), b.GetMin(), b.GetMax(), b.GetAvg(), minAllowedPreFECBER, maxAllowedPreFECBER, inactivePreFECBER, operStatus) + } } if e := otn.GetEsnr(); e == nil { t.Errorf("ESNR data is empty for port %v", portName) @@ -203,7 +213,7 @@ func validatePMValue(t *testing.T, portName, pm string, instant, min, max, avg, return } case oc.Interface_OperStatus_DOWN: - if instant != inactiveValue { + if instant > inactiveValue { t.Errorf("Invalid %v sample when %v is DOWN --> min : %v, max : %v, avg : %v, instant : %v", pm, portName, min, max, avg, instant) return } diff --git a/feature/platform/transceiver/tests/zr_tunable_parameters_test/metadata.textproto b/feature/platform/transceiver/tests/zr_tunable_parameters_test/metadata.textproto index 5bd64161c63..731414603ab 100644 --- a/feature/platform/transceiver/tests/zr_tunable_parameters_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_tunable_parameters_test/metadata.textproto @@ -14,3 +14,11 @@ platform_exceptions: { missing_zr_optical_channel_tunable_parameters_telemetry: true } } +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + operational_mode_unsupported:true + } +} \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go b/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go index fe01013e2be..f152d83c96b 100644 --- a/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go +++ b/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go @@ -80,16 +80,21 @@ func Test400ZRTunableFrequency(t *testing.T) { t.Run(tc.description, func(t *testing.T) { for freq := tc.startFreq; freq <= tc.endFreq; freq += tc.freqStep { t.Run(fmt.Sprintf("Freq: %v", freq), func(t *testing.T) { - gnmi.Replace(t, dut, gnmi.OC().Component(oc1).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + opticalChannel1Config := &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(tc.targetOutputPower), Frequency: ygot.Uint64(freq), - OperationalMode: ygot.Uint16(dp16QAM), - }) - gnmi.Replace(t, dut, gnmi.OC().Component(oc2).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + OperationalMode: ygot.Uint16(dp16QAM)} + opticalChannel2Config := &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(tc.targetOutputPower), Frequency: ygot.Uint64(freq), - OperationalMode: ygot.Uint16(dp16QAM), - }) + OperationalMode: ygot.Uint16(dp16QAM)} + + if deviations.OperationalModeUnsupported(dut) { + opticalChannel1Config.OperationalMode = nil + opticalChannel2Config.OperationalMode = nil + } + gnmi.Replace(t, dut, gnmi.OC().Component(oc1).OpticalChannel().Config(), opticalChannel1Config) + gnmi.Replace(t, dut, gnmi.OC().Component(oc2).OpticalChannel().Config(), opticalChannel2Config) gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, freq, tc.targetOutputPower) @@ -132,16 +137,23 @@ func Test400ZRTunableOutputPower(t *testing.T) { for _, tc := range tests { for top := tc.startTargetOutputPower; top <= tc.endTargetOutputPower; top += tc.targetOutputPowerStep { t.Run(fmt.Sprintf("Target Power: %v", top), func(t *testing.T) { - gnmi.Replace(t, dut, gnmi.OC().Component(oc1).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + opticalChannel1Config := &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(top), Frequency: ygot.Uint64(tc.frequency), OperationalMode: ygot.Uint16(dp16QAM), - }) - gnmi.Replace(t, dut, gnmi.OC().Component(oc2).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + } + opticalChannel2Config := &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(top), Frequency: ygot.Uint64(tc.frequency), OperationalMode: ygot.Uint16(dp16QAM), - }) + } + if deviations.OperationalModeUnsupported(dut) { + opticalChannel1Config.OperationalMode = nil + opticalChannel2Config.OperationalMode = nil + } + + gnmi.Replace(t, dut, gnmi.OC().Component(oc1).OpticalChannel().Config(), opticalChannel1Config) + gnmi.Replace(t, dut, gnmi.OC().Component(oc2).OpticalChannel().Config(), opticalChannel2Config) gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, tc.frequency, top) @@ -164,16 +176,25 @@ func Test400ZRInterfaceFlap(t *testing.T) { defer streamOC2.Close() targetPower := float64(-9) frequency := uint64(193100000) - gnmi.Replace(t, dut, gnmi.OC().Component(oc1).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + + opticalChannel1Config := &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(targetPower), Frequency: ygot.Uint64(frequency), OperationalMode: ygot.Uint16(dp16QAM), - }) - gnmi.Replace(t, dut, gnmi.OC().Component(oc2).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + } + opticalChannel2Config := &oc.Component_OpticalChannel{ TargetOutputPower: ygot.Float64(targetPower), Frequency: ygot.Uint64(frequency), OperationalMode: ygot.Uint16(dp16QAM), - }) + } + + if deviations.OperationalModeUnsupported(dut) { + opticalChannel1Config.OperationalMode = nil + opticalChannel2Config.OperationalMode = nil + } + + gnmi.Replace(t, dut, gnmi.OC().Component(oc1).OpticalChannel().Config(), opticalChannel1Config) + gnmi.Replace(t, dut, gnmi.OC().Component(oc2).OpticalChannel().Config(), opticalChannel2Config) gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), time.Minute, oc.Interface_OperStatus_UP) t.Run("Telemetry before flap", func(t *testing.T) { @@ -222,7 +243,7 @@ func validateOpticsTelemetry(t *testing.T, streams []*samplestream.SampleStream[ avg := oc.GetCarrierFrequencyOffset().GetAvg() min := oc.GetCarrierFrequencyOffset().GetMin() max := oc.GetCarrierFrequencyOffset().GetMax() - if got, want := opm, uint16(dp16QAM); got != want { + if got, want := opm, uint16(dp16QAM); got != want && !deviations.OperationalModeUnsupported(dut) { t.Errorf("Optical-Channel: operational-mode: got %v, want %v", got, want) } // Laser frequency offset should not be more than +/- 1.8 GHz max from the diff --git a/feature/experimental/policy/otg_tests/prefix_set_test/README.md b/feature/policy_forwarding/otg_tests/prefix_set_test/README.md similarity index 100% rename from feature/experimental/policy/otg_tests/prefix_set_test/README.md rename to feature/policy_forwarding/otg_tests/prefix_set_test/README.md diff --git a/feature/experimental/policy/otg_tests/prefix_set_test/metadata.textproto b/feature/policy_forwarding/otg_tests/prefix_set_test/metadata.textproto similarity index 100% rename from feature/experimental/policy/otg_tests/prefix_set_test/metadata.textproto rename to feature/policy_forwarding/otg_tests/prefix_set_test/metadata.textproto diff --git a/feature/experimental/policy/otg_tests/prefix_set_test/prefix_set_test.go b/feature/policy_forwarding/otg_tests/prefix_set_test/prefix_set_test.go similarity index 100% rename from feature/experimental/policy/otg_tests/prefix_set_test/prefix_set_test.go rename to feature/policy_forwarding/otg_tests/prefix_set_test/prefix_set_test.go diff --git a/feature/experimental/policy/policy_vrf_selection/otg_tests/base_vrf_selection/README.md b/feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/README.md similarity index 100% rename from feature/experimental/policy/policy_vrf_selection/otg_tests/base_vrf_selection/README.md rename to feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/README.md diff --git a/feature/experimental/policy/policy_vrf_selection/otg_tests/base_vrf_selection/base_vrf_selection_test.go b/feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/base_vrf_selection_test.go similarity index 100% rename from feature/experimental/policy/policy_vrf_selection/otg_tests/base_vrf_selection/base_vrf_selection_test.go rename to feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/base_vrf_selection_test.go diff --git a/feature/experimental/policy/policy_vrf_selection/otg_tests/base_vrf_selection/metadata.textproto b/feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/metadata.textproto similarity index 100% rename from feature/experimental/policy/policy_vrf_selection/otg_tests/base_vrf_selection/metadata.textproto rename to feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/metadata.textproto diff --git a/feature/experimental/policy/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/README.md b/feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/README.md similarity index 100% rename from feature/experimental/policy/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/README.md rename to feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/README.md diff --git a/feature/experimental/policy/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/metadata.textproto b/feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/metadata.textproto similarity index 100% rename from feature/experimental/policy/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/metadata.textproto rename to feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/metadata.textproto diff --git a/feature/experimental/policy/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/protocol_dscp_rules_for_vrf_selection_test.go b/feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/protocol_dscp_rules_for_vrf_selection_test.go similarity index 100% rename from feature/experimental/policy/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/protocol_dscp_rules_for_vrf_selection_test.go rename to feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/protocol_dscp_rules_for_vrf_selection_test.go diff --git a/feature/qos/otg_tests/bursty_traffic_test/bursty_traffic_test.go b/feature/qos/otg_tests/bursty_traffic_test/bursty_traffic_test.go index 2e8e158c370..f0504b744a8 100644 --- a/feature/qos/otg_tests/bursty_traffic_test/bursty_traffic_test.go +++ b/feature/qos/otg_tests/bursty_traffic_test/bursty_traffic_test.go @@ -371,22 +371,12 @@ func TestBurstyTraffic(t *testing.T) { var counterNames []string counters := make(map[string]map[string]uint64) - if !deviations.QOSDroppedOctets(dut) { - counterNames = []string{ - - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", - "dutQosDroppedOctetsAfterTraffic", - } - } else { - counterNames = []string{ - - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedPktsAfterTraffic", - } + counterNames = []string{ + "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", + "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", + "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", + "dutQosDroppedOctetsAfterTraffic", } for _, name := range counterNames { @@ -420,13 +410,12 @@ func TestBurstyTraffic(t *testing.T) { } counters["dutQosDroppedPktsBeforeTraffic"][data.queue], _ = count.Val() - if !deviations.QOSDroppedOctets(dut) { - count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) - if !ok { - t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp3.Name(), data.queue, timeout) - } - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) + if !ok { + t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp3.Name(), data.queue, timeout) } + counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + } t.Logf("Running traffic 1 on DUT interfaces: %s => %s ", dp1.Name(), dp3.Name()) @@ -448,9 +437,8 @@ func TestBurstyTraffic(t *testing.T) { counters["dutQosPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).TransmitPkts().State()) counters["dutQosOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).TransmitOctets().State()) counters["dutQosDroppedPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedPkts().State()) - if !deviations.QOSDroppedOctets(dut) { - counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State()) - } + counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State()) + t.Logf("ateInPkts: %v, txPkts %v, Queue: %v", counters["ateInPkts"][data.queue], counters["dutQosPktsAfterTraffic"][data.queue], data.queue) if ateTxPkts == 0 { t.Fatalf("TxPkts == 0, want >0.") @@ -490,13 +478,11 @@ func TestBurstyTraffic(t *testing.T) { } } - if !deviations.QOSDroppedOctets(dut) { - ateDropOctetCounterDiff := (counters["ateOutPkts"][data.queue] - counters["ateInPkts"][data.queue]) * uint64(data.frameSize) - dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] - t.Logf("Queue %q: ateDropOctetCounterDiff: %v dutDropOctetCounterDiff: %v", data.queue, ateDropOctetCounterDiff, dutDropOctetCounterDiff) - if dutDropOctetCounterDiff < ateDropOctetCounterDiff { - t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want >= %v", data.queue, dutDropOctetCounterDiff, ateDropOctetCounterDiff) - } + ateDropOctetCounterDiff := (counters["ateOutPkts"][data.queue] - counters["ateInPkts"][data.queue]) * uint64(data.frameSize) + dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] + t.Logf("Queue %q: ateDropOctetCounterDiff: %v dutDropOctetCounterDiff: %v", data.queue, ateDropOctetCounterDiff, dutDropOctetCounterDiff) + if dutDropOctetCounterDiff < ateDropOctetCounterDiff { + t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want >= %v", data.queue, dutDropOctetCounterDiff, ateDropOctetCounterDiff) } } diff --git a/feature/qos/otg_tests/bursty_traffic_test/metadata.textproto b/feature/qos/otg_tests/bursty_traffic_test/metadata.textproto index 0f9af70b1d7..7ee4ccb49c0 100644 --- a/feature/qos/otg_tests/bursty_traffic_test/metadata.textproto +++ b/feature/qos/otg_tests/bursty_traffic_test/metadata.textproto @@ -17,10 +17,6 @@ platform_exceptions: { platform: { vendor: JUNIPER } - deviations: { - explicit_interface_ref_definition: true - qos_dropped_octets: true - } } platform_exceptions: { platform: { diff --git a/feature/qos/otg_tests/ingress_police_default/README.md b/feature/qos/otg_tests/ingress_police_default/README.md new file mode 100644 index 00000000000..df47044e638 --- /dev/null +++ b/feature/qos/otg_tests/ingress_police_default/README.md @@ -0,0 +1,195 @@ +# DP-2.4 Police traffic on input matching all packets using 1 rate, 2 color marker + +## Summary + +Use the gRIBI applied ip entries from TE-18.1 gRIBI. +Configure an ingress scheduler to police traffic using a 1 rate, 2 color policer and attach the scheduler to the interface without a classifier. +Lack of match conditions will cause all packets to be matched. +Send traffic to validate the policer. + +## Topology + +* [`featureprofiles/topologies/atedut_2.testbed`](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed) + +## Test setup + +Use TE-18.1 test environment setup. + +## Procedure + +### DP-2.4.1 Generate and push configuration + +* Generate config for 2 scheduler polices with an input rate limit. +* Apply scheduler to DUT subinterface with vlan. +* Use gnmi.Replace to push the config to the DUT. + +```json +{ + "openconfig-qos": { + "scheduler-policies": [ + { + "scheduler-policy": null, + "config": { + "name": "limit_1Gb" + }, + "schedulers": [ + { + "scheduler": null, + "config": { + "sequence": 1, + "type": "ONE_RATE_TWO_COLOR" + }, + "inputs": [ + { + "input": "my input policer 1Gb", + "config": { + "id": "my input policer 1Gb", + "input-type": "QUEUE", + "queue": "dummy_input_queue_A" + } + } + ], + "one-rate-two-color": { + "config": { + "cir": 1000000000, + "bc": 100000, + "queuing-behavior": "POLICE" + }, + "exceed-action": { + "config": { + "drop": true + } + } + } + } + ] + }, + { + "scheduler-policy": null, + "config": { + "name": "limit_2Gb" + }, + "schedulers": [ + { + "scheduler": null, + "config": { + "sequence": 1, + "type": "ONE_RATE_TWO_COLOR" + }, + "inputs": [ + { + "input": "my input policer 2Gb", + "config": { + "id": "my input policer 2Gb", + "input-type": "QUEUE", + "queue": "dummy_input_queue_B" + } + } + ], + "one-rate-two-color": { + "config": { + "cir": 2000000000, + "bc": 100000, + "queuing-behavior": "POLICE" + }, + "exceed-action": { + "config": { + "drop": true + } + } + } + } + ] + } + ], + # + # Interfaces input are mapped to the desired scheduler. + "interfaces": [ + { + "interface": null, + "config": { + "interface-id": "PortChannel1.100" + }, + "input": { + "scheduler-policy": { + "config": { + "name": "limit_group_A_1Gb" + } + } + } + }, + { + "interface": null, + "config": { + "interface-id": "PortChannel1.200" + }, + "input": { + "scheduler-policy": { + "config": { + "name": "limit_group_B_1Gb" + } + } + } + } + ] + } +} +``` + +### DP-2.4.2 Test traffic + +* Send traffic + * Send flow A traffic from ATE port 1 to DUT for dest_A at 0.7Gbps (note cir is 1Gbps). + * Send flow B traffic from ATE port 1 to DUT for to dest_B at 1.5Gbps (note cir is 2Gbps). + * Validate qos counters per DUT. + * Validate qos counters by ATE port. + * Validate packets are received by ATE port 2. + * Validate DUT qos interface scheduler counters count packets as conforming-pkts and conforming-octets + * Validate at OTG that 0 packets are lost on flow A and flow B + * When the outer packet is IPv6, the flow-label should be inspected on the ATE. + * If the inner packet is IPv4, the outer IPv6 flow label should be computed based on the IPv4 5 tuple src,dst address and ports, plus protocol. + * If the inner packet is IPv6, the inner flow label should be copied to the outer packet. + * To validate the flow label, use the ATE to verify that the packets for + * flow A all have the same flow label + * flow B have the same flow label + * flow A and B labels do not match + * Increase traffic on flow to dest_B to 2Gbps + * Validate that flow dest_B experiences ~50% packet loss (+/- 1%) + + +#### OpenConfig Path and RPC Coverage + +```yaml +paths: + # qos scheduler config + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/cir: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/bc: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/queuing-behavior: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/drop: + + # qos interfaces config + /qos/interfaces/interface/config/interface-id: + /qos/interfaces/interface/input/scheduler-policy/config/name: + + # qos interface scheduler counters + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-pkts: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-octets: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-pkts: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-octets: + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true +``` + +## Required DUT platform + +* FFF + + diff --git a/feature/qos/otg_tests/ingress_police_nhg/README.md b/feature/qos/otg_tests/ingress_police_nhg/README.md new file mode 100644 index 00000000000..cb694f05ac4 --- /dev/null +++ b/feature/qos/otg_tests/ingress_police_nhg/README.md @@ -0,0 +1,433 @@ +# DP-2.2 QoS scheduler with 1 rate 2 color policer, classifying on next-hop group + +## Summary + +Use the gRIBI applied IP entries from DP-2.1 gRIBI. Configure an ingress scheduler +to police traffic using a 1 rate, 2 color policer. Configure a classifier to match +traffic on a next-hop-group. Apply the configuration to a VLAN on an aggregate +interface. Send traffic to validate the policer. + +## Topology + +* [`featureprofiles/topologies/atedut_2.testbed`](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed) + +## Test setup + +Use DP-2.1 test environment setup. + +## Procedure + +### DP-2.2.1 Generate and push policer configuration + +* Generate config for 2 classifiers which match on next-hop-group. +* Generate config for 2 forwarding-groups mapped to "dummy" input queues + * Note that the DUT is not required to have an input queue, the dummy queue + satisfies the OC schema which requires defining nodes mapping + classfier->forwarding-group->queue->scheduler +* Generate config for 2 scheduler-policies to police traffic +* Generate config to apply classifer and scheduler to DUT subinterface. +* Use gnmi.Replace to push the config to the DUT. + +```json +{ + # + # A classifer is created to match packets belonging to certain + # next-hop-groups and map them either forwarding-group input_dest_A or + # input_dest_B + "openconfig-qos": { + "classifers": [ + { + "classifer": "“dest_A”", + "config": { + "name": "“dest_A”" + }, + "terms": [ + { + "term": null, + "config": { + "id": "match_1_dest_A1" + }, + "conditions": { + "next-hop-group": { + "config": { + # TODO: new OC path needed, string related to /afts/next-hop-groups/next-hop-group/state/next-hop-group-id + "name": "nhg_A1" + } + } + }, + "actions": { + "config": { + "target-group": "input_dest_A" + } + } + }, + { + "term": null, + "config": { + "id": "match_1_dest_A2" + }, + "conditions": { + "next-hop-group": { + "config": { + "name": "nhg_A2" + } + } + }, + "actions": { + "config": { + "target-group": "input_dest_A" + } + } + } + ] + }, + { + "classifer": "“dest_B”", + "config": { + "name": "“dest_B”" + }, + "terms": [ + { + "term": null, + "config": { + "id": "match_1_dest_B1" + }, + "conditions": { + "next-hop-group": { + "config": { + "name": "nhg_B1" + } + } + }, + "actions": { + "config": { + "target-group": "input_dest_B" + } + } + }, + { + "term": null, + "config": { + "id": "match_1_dest_B2" + }, + "conditions": { + "next-hop-group": { + "config": { + "name": "nhg_B2" + } + } + }, + "actions": { + "config": { + "target-group": "input_dest_B" + } + } + } + ] + } + ], + # + # Forwarding groups are created named input_dest_A and input_dest_B. + # These are mapped to 'fake' queues + "forwarding-groups": [ + { + "forwarding-group": "input_dest_A", + "config": { + "name": "input_dest_A", + "output-queue": "dummy_input_queue_A" + } + }, + { + "forwarding-group": "input_dest_B", + "config": { + "name": "input_dest_B", + "output-queue": "dummy_input_queue_B" + } + } + ], + "queues": [ + { + "queue": null, + "config": { + "name": "dummy_input_queue_A" + } + }, + { + "queue": null, + "config": { + "name": "dummy_input_queue_B" + } + } + ], + # + # Two scheduler policies are created, limit_1Gb and limit_2Gb + # and are associated with the dummy queue they are servicing. + "scheduler-policies": [ + { + "scheduler-policy": null, + "config": { + "name": "limit_1Gb" + }, + "schedulers": [ + { + "scheduler": null, + "config": { + "sequence": 1, + "type": "ONE_RATE_TWO_COLOR" + }, + "inputs": [ + { + "input": "my input policer 1Gb", + "config": { + "id": "my input policer 1Gb", + "input-type": "QUEUE", + "queue": "dummy_input_queue_A" + } + } + ], + "one-rate-two-color": { + "config": { + "cir": 1000000000, + "bc": 100000, + "queuing-behavior": "POLICE" + }, + "exceed-action": { + "config": { + "drop": true + } + } + } + } + ] + }, + { + "scheduler-policy": null, + "config": { + "name": "limit_2Gb" + }, + "schedulers": [ + { + "scheduler": null, + "config": { + "sequence": 1, + "type": "ONE_RATE_TWO_COLOR" + }, + "inputs": [ + { + "input": "my input policer 2Gb", + "config": { + "id": "my input policer 2Gb", + "input-type": "QUEUE", + "queue": "dummy_input_queue_B" + } + } + ], + "one-rate-two-color": { + "config": { + "cir": 2000000000, + "bc": 100000, + "queuing-behavior": "POLICE" + }, + "exceed-action": { + "config": { + "drop": true + } + } + } + } + ] + } + ], + # + # Interfaces input are mapped to the desired classifier and scheduler. + "interfaces": [ + { + "interface": null, + "config": { + "interface-id": "PortChannel1.100" + }, + "input": { + "classifiers": [ + { + "classifier": null, + "config": { + "name": "dest_A", + "type": "IPV4" + } + } + ], + "scheduler-policy": { + "config": { + "name": "limit_group_A_1Gb" + } + } + } + }, + { + "interface": null, + "config": { + "interface-id": "PortChannel1.200" + }, + "input": { + "classifiers": [ + { + "classifier": null, + "config": { + "name": "dest_B", + "type": "IPV4" + } + } + ], + "scheduler-policy": { + "config": { + "name": "limit_group_B_1Gb" + } + } + } + } + ] + } +} +``` + +### DP-2.2.2 push gRIBI AFT encapsulation rules with next-hop-group-id + +Create a gRIBI client and send this proto message to the DUT to create AFT +entries. Note the next-hop-groups here include a `next_hop_group_id` field +which matches the +`/qos/classifiers/classifier/condition/next-hop-group/config/name` leaf. + +```proto +# +# aft entries used for network instance "NI_A" +IPv6Entry {2001:DB8:2::2/128 (NI_A)} -> NHG#100 (DEFAULT VRF) +IPv4Entry {203.0.113.2/32 (NI_A)} -> NHG#100 (DEFAULT VRF) -> { + {NH#101, DEFAULT VRF} +} + +# this nexthop specifies a MPLS in UDP encapsulation +NH#101 -> { + encap-headers { + encap-header { + index: 1 + mpls { + pushed_mpls_label_stack: [101,] + } + } + encap-header { + index: 2 + udpv6 { + src_ip: "outer_ipv6_src" + dst_ip: "outer_ipv6_dst_A" + dst_udp_port: "outer_dst_udp_port" + ip_ttl: "outer_ip-ttl" + dscp: "outer_dscp" + } + } + } + next_hop_group_id: "nhg_A" # TODO: new OC path /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/next-hop-group-id + network_instance: "DEFAULT" +} + +# +# entries used for network-instance "NI_B" +IPv6Entry {2001:DB8:2::2/128 (NI_B)} -> NHG#200 (DEFAULT VRF) +IPv4Entry {203.0.113.2/32 (NI_B)} -> NHG#200 (DEFAULT VRF) -> { + {NH#201, DEFAULT VRF} +} + +NH#201 -> { + encap-headers { + encap-header { + index: 1 + mpls { + pushed_mpls_label_stack: [201,] + } + } + encap-header { + index: 2 + udpv6 { + src_ip: "outer_ipv6_src" + dst_ip: "outer_ipv6_dst_B" + dst_udp_port: "outer_dst_udp_port" + ip_ttl: "outer_ip-ttl" + dscp: "outer_dscp" + } + } + } + next_hop_group_id: "nhg_B" # TODO: new OC path /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/next-hop-group-id + network_instance: "DEFAULT" +} +``` + +### DP-2.2.3 Test flow policing + +* Send traffic + * Send flow A traffic from ATE port 1 to DUT for dest_A at 0.7Gbps (note cir is 1Gbps). + * Send flow B traffic from ATE port 1 to DUT for to dest_B at 1.5Gbps (note cir is 2Gbps). + * Validate packets are received by ATE port 2. + * Validate DUT qos interface scheduler counters count packets as conforming-pkts and conforming-octets + * Validate at OTG that 0 packets are lost on flow A and flow B + * Increase traffic on flow to dest_A to 2Gbps + * Validate that flow dest_A experiences ~50% packet loss (+/- 1%) + * Stop traffic + +### DP-2.2.3 IPv6 flow label validiation + + * Send 100 packets for flow A and flow B. (Use an OTG fixed packet count flow) + * When the outer packet is IPv6, the flow-label should be inspected on the ATE. + * If the inner packet is IPv4, the outer IPv6 flow label should be computed based on the IPv4 5 tuple src,dst address and ports, plus protocol. + * If the inner packet is IPv6, the inner flow label should be copied to the outer packet. + * To validate the flow label, use the ATE to verify that the packets for + * flow A all have the same flow label + * flow B have the same flow label + * flow A and B labels do not match + +#### OpenConfig Path and RPC Coverage + +```yaml +paths: + # qos scheduler config + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/cir: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/bc: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/queuing-behavior: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/drop: + + # qos classifier config + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/terms/term/config/id: + #/qos/classifiers/classifier/terms/term/conditions/next-hop-group/config/name: # TODO: new OC leaf to be added + + # qos forwarding-groups config + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + + # qos queue config + /qos/queues/queue/config/name: + + # qos interfaces config + /qos/interfaces/interface/config/interface-id: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/type: + /qos/interfaces/interface/input/scheduler-policy/config/name: + + # qos interface scheduler counters + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-pkts: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-octets: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-pkts: + /qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-octets: + +rpcs: + gnmi: + gNMI.Set: + union_replace: true + replace: true + gNMI.Subscribe: + on_change: true +``` + +## Required DUT platform + +* FFF diff --git a/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/README.md b/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/README.md index 09c58f2d08b..adbb4e22acf 100644 --- a/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/README.md +++ b/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/README.md @@ -150,3 +150,59 @@ forwards AF3, AF2, AF1, BE1 and BE0 based on weight. * /qos/interfaces/interface/output/queues/queue/state/transmit-octets * /qos/interfaces/interface/output/queues/queue/state/dropped-pkts * /qos/interfaces/interface/output/queues/queue/state/dropped-octets + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/metadata.textproto b/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/metadata.textproto index cf011351b89..34786e74bae 100644 --- a/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/metadata.textproto +++ b/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/metadata.textproto @@ -18,8 +18,6 @@ platform_exceptions: { vendor: JUNIPER } deviations: { - explicit_interface_ref_definition: true - qos_dropped_octets: true scheduler_input_weight_limit: true } } diff --git a/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/mixed_sp_wrr_traffic_test.go b/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/mixed_sp_wrr_traffic_test.go index 4016f751681..1ef4e4f42d5 100644 --- a/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/mixed_sp_wrr_traffic_test.go +++ b/feature/qos/otg_tests/mixed_sp_wrr_traffic_test/mixed_sp_wrr_traffic_test.go @@ -530,19 +530,11 @@ func TestMixedSPWrrTraffic(t *testing.T) { var counterNames []string counters := make(map[string]map[string]uint64) - if !deviations.QOSDroppedOctets(dut) { - counterNames = []string{ - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", - "dutQosDroppedOctetsAfterTraffic", - } - } else { - counterNames = []string{ - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedPktsAfterTraffic", - } + counterNames = []string{ + "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", + "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", + "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", + "dutQosDroppedOctetsAfterTraffic", } for _, name := range counterNames { @@ -576,13 +568,11 @@ func TestMixedSPWrrTraffic(t *testing.T) { } counters["dutQosDroppedPktsBeforeTraffic"][data.queue], _ = count.Val() - if !deviations.QOSDroppedOctets(dut) { - count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) - if !ok { - t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp3.Name(), data.queue, timeout) - } - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) + if !ok { + t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp3.Name(), data.queue, timeout) } + counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() } t.Logf("Running traffic 1 on DUT interfaces: %s => %s ", dp1.Name(), dp3.Name()) @@ -601,9 +591,7 @@ func TestMixedSPWrrTraffic(t *testing.T) { counters["dutQosPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).TransmitPkts().State()) counters["dutQosOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).TransmitOctets().State()) counters["dutQosDroppedPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedPkts().State()) - if !deviations.QOSDroppedOctets(dut) { - counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State()) - } + counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State()) t.Logf("ateInPkts: %v, txPkts %v, Queue: %v", counters["ateInPkts"][data.queue], counters["dutQosPktsAfterTraffic"][data.queue], data.queue) // Calculate aggregated throughput: @@ -666,14 +654,12 @@ func TestMixedSPWrrTraffic(t *testing.T) { } } - if !deviations.QOSDroppedOctets(dut) { - ateDropOctetCounterDiff := (counters["ateOutPkts"][data.queue] - counters["ateInPkts"][data.queue]) * uint64(data.frameSize) - dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] - t.Logf("Queue %q: ateDropOctetCounterDiff: %v dutDropOctetCounterDiff: %v", data.queue, ateDropOctetCounterDiff, dutDropOctetCounterDiff) - if dutDropOctetCounterDiff < ateDropOctetCounterDiff { - if !deviations.DequeueDeleteNotCountedAsDrops(dut) { - t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want >= %v", data.queue, dutDropOctetCounterDiff, ateDropOctetCounterDiff) - } + ateDropOctetCounterDiff := (counters["ateOutPkts"][data.queue] - counters["ateInPkts"][data.queue]) * uint64(data.frameSize) + dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] + t.Logf("Queue %q: ateDropOctetCounterDiff: %v dutDropOctetCounterDiff: %v", data.queue, ateDropOctetCounterDiff, dutDropOctetCounterDiff) + if dutDropOctetCounterDiff < ateDropOctetCounterDiff { + if !deviations.DequeueDeleteNotCountedAsDrops(dut) { + t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want >= %v", data.queue, dutDropOctetCounterDiff, ateDropOctetCounterDiff) } } diff --git a/feature/qos/otg_tests/one_sp_queue_traffic_test/README.md b/feature/qos/otg_tests/one_sp_queue_traffic_test/README.md index d2cd200b781..2c357ec3166 100644 --- a/feature/qos/otg_tests/one_sp_queue_traffic_test/README.md +++ b/feature/qos/otg_tests/one_sp_queue_traffic_test/README.md @@ -136,3 +136,59 @@ Verify that DUT drops AF4, AF3, AF2, AF1, BE1 and BE0 before NC1. * /qos/interfaces/interface/output/queues/queue/state/transmit-octets * /qos/interfaces/interface/output/queues/queue/state/dropped-pkts * /qos/interfaces/interface/output/queues/queue/state/dropped-octets + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/otg_tests/one_sp_queue_traffic_test/metadata.textproto b/feature/qos/otg_tests/one_sp_queue_traffic_test/metadata.textproto index 5ad022dedf8..24e2c3193d3 100644 --- a/feature/qos/otg_tests/one_sp_queue_traffic_test/metadata.textproto +++ b/feature/qos/otg_tests/one_sp_queue_traffic_test/metadata.textproto @@ -17,9 +17,6 @@ platform_exceptions: { platform: { vendor: JUNIPER } - deviations: { - explicit_interface_ref_definition: true - } } platform_exceptions: { platform: { diff --git a/feature/qos/otg_tests/qos_basic_test/README.md b/feature/qos/otg_tests/qos_basic_test/README.md index 27c82a5bd18..e836aa0fc66 100644 --- a/feature/qos/otg_tests/qos_basic_test/README.md +++ b/feature/qos/otg_tests/qos_basic_test/README.md @@ -164,3 +164,59 @@ Verify that DUT supports QoS config and forward QoS traffic correctly. ## Required DUT platform * FFF + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/otg_tests/qos_basic_test/metadata.textproto b/feature/qos/otg_tests/qos_basic_test/metadata.textproto index e85163ec382..36abf3c642b 100644 --- a/feature/qos/otg_tests/qos_basic_test/metadata.textproto +++ b/feature/qos/otg_tests/qos_basic_test/metadata.textproto @@ -19,8 +19,7 @@ platform_exceptions: { } deviations: { ecn_profile_required_definition: true - explicit_interface_ref_definition: true - qos_dropped_octets: true + no_zero_suppression: true } } platform_exceptions: { diff --git a/feature/qos/otg_tests/qos_basic_test/qos_basic_test.go b/feature/qos/otg_tests/qos_basic_test/qos_basic_test.go index b4ae086cc22..a136165b316 100644 --- a/feature/qos/otg_tests/qos_basic_test/qos_basic_test.go +++ b/feature/qos/otg_tests/qos_basic_test/qos_basic_test.go @@ -15,6 +15,7 @@ package qos_basic_test import ( + "context" "testing" "time" @@ -114,6 +115,10 @@ func TestBasicConfigWithTraffic(t *testing.T) { ConfigureQoS(t, dut) } + if deviations.NoZeroSuppression(dut) { + configureNoZeroSuppression(t, dut) + } + // Configure ATE interfaces. ate := ondatra.ATE(t, "ate") ap1 := ate.Port(t, "port1") @@ -399,24 +404,13 @@ func TestBasicConfigWithTraffic(t *testing.T) { ate.OTG().StartProtocols(t) counters := make(map[string]map[string]uint64) - var counterNames []string - - if !deviations.QOSDroppedOctets(dut) { - counterNames = []string{ - - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", - "dutQosDroppedOctetsAfterTraffic", - } - } else { - counterNames = []string{ - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedPktsAfterTraffic", - } + var counterNames = []string{ + "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", + "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", + "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", + "dutQosDroppedOctetsAfterTraffic", } for _, name := range counterNames { @@ -450,13 +444,12 @@ func TestBasicConfigWithTraffic(t *testing.T) { } counters["dutQosDroppedPktsBeforeTraffic"][data.queue], _ = count.Val() - if !deviations.QOSDroppedOctets(dut) { - count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) - if !ok { - t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp3.Name(), data.queue, timeout) - } - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) + if !ok { + t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp3.Name(), data.queue, timeout) } + counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + } t.Logf("Running traffic 1 on DUT interfaces: %s => %s ", dp1.Name(), dp3.Name()) @@ -476,9 +469,8 @@ func TestBasicConfigWithTraffic(t *testing.T) { counters["dutQosPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).TransmitPkts().State()) counters["dutQosOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).TransmitOctets().State()) counters["dutQosDroppedPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedPkts().State()) - if !deviations.QOSDroppedOctets(dut) { - counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State()) - } + counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State()) + t.Logf("ateInPkts: %v, txPkts %v, Queue: %v", counters["ateInPkts"][data.queue], counters["dutQosPktsAfterTraffic"][data.queue], data.queue) if ateTxPkts == 0 { @@ -519,13 +511,12 @@ func TestBasicConfigWithTraffic(t *testing.T) { } } - if !deviations.QOSDroppedOctets(dut) { - dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] - t.Logf("Queue %q: dutDropOctetCounterDiff: %v", data.queue, dutDropOctetCounterDiff) - if dutDropOctetCounterDiff != 0 { - t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want 0", data.queue, dutDropOctetCounterDiff) - } + dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] + t.Logf("Queue %q: dutDropOctetCounterDiff: %v", data.queue, dutDropOctetCounterDiff) + if dutDropOctetCounterDiff != 0 { + t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want 0", data.queue, dutDropOctetCounterDiff) } + } // gnmi subscribe sample mode(10 and 15 seconds sample interval) for queue counters @@ -545,12 +536,11 @@ func TestBasicConfigWithTraffic(t *testing.T) { if len(droppedPkts) < minWant { t.Errorf("DroppedPkts: got %d, want >= %d", len(droppedPkts), minWant) } - if !deviations.QOSDroppedOctets(dut) { - droppedOctets := gnmi.Collect(t, gnmiOpts(t, dut, sampleInterval), gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), subscribeTimeout).Await(t) - if len(droppedOctets) < minWant { - t.Errorf("DroppedOctets: got %d, want >= %d", len(droppedOctets), minWant) - } + droppedOctets := gnmi.Collect(t, gnmiOpts(t, dut, sampleInterval), gnmi.OC().Qos().Interface(dp3.Name()).Output().Queue(data.queue).DroppedOctets().State(), subscribeTimeout).Await(t) + if len(droppedOctets) < minWant { + t.Errorf("DroppedOctets: got %d, want >= %d", len(droppedOctets), minWant) } + } } }) @@ -1759,3 +1749,52 @@ func gnmiOpts(t *testing.T, dut *ondatra.DUTDevice, interval time.Duration) *gnm ygnmi.WithSampleInterval(interval), ) } +func configureNoZeroSuppression(t *testing.T, dut *ondatra.DUTDevice) { + // Disable Zero suppression + t.Logf("Disable zero suppression:\n%s", dut.Vendor()) + var config string + switch dut.Vendor() { + case ondatra.JUNIPER: + config = disableZeroSuppression() + t.Logf("Push the CLI config:\n%s", config) + + default: + t.Errorf("Invalid configuration") + } + gnmiClient := dut.RawAPIs().GNMI(t) + gpbSetRequest := buildCliConfigRequest(config) + + t.Log("gnmiClient Set CLI config") + if _, err := gnmiClient.Set(context.Background(), gpbSetRequest); err != nil { + t.Fatalf("gnmiClient.Set() with unexpected error: %v", err) + } +} + +func buildCliConfigRequest(config string) *gpb.SetRequest { + // Build config with Origin set to cli and Ascii encoded config. + gpbSetRequest := &gpb.SetRequest{ + Update: []*gpb.Update{{ + Path: &gpb.Path{ + Origin: "cli", + Elem: []*gpb.PathElem{}, + }, + Val: &gpb.TypedValue{ + Value: &gpb.TypedValue_AsciiVal{ + AsciiVal: config, + }, + }, + }}, + } + return gpbSetRequest +} + +func disableZeroSuppression() string { + return (` + services { + analytics { + zero-suppression { + no-zero-suppression; + } + } + }`) +} diff --git a/feature/qos/otg_tests/qos_output_queue_counters_test/README.md b/feature/qos/otg_tests/qos_output_queue_counters_test/README.md index eb8bb04af09..9fab7d0d7e8 100644 --- a/feature/qos/otg_tests/qos_output_queue_counters_test/README.md +++ b/feature/qos/otg_tests/qos_output_queue_counters_test/README.md @@ -13,7 +13,7 @@ Validate QoS interface output queue counters. * /qos/interfaces/interface/output/queues/queue/state/transmit-octets * /qos/interfaces/interface/output/queues/queue/state/dropped-pkts * /qos/interfaces/interface/output/queues/queue/state/dropped-octets - + ## Config Parameter coverage * /interfaces/interface/config/enabled @@ -26,3 +26,59 @@ Validate QoS interface output queue counters. * /qos/interfaces/interface/output/queues/queue/state/transmit-octets * /qos/interfaces/interface/output/queues/queue/state/dropped-pkts * /qos/interfaces/interface/output/queues/queue/state/dropped-octets + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/otg_tests/qos_output_queue_counters_test/metadata.textproto b/feature/qos/otg_tests/qos_output_queue_counters_test/metadata.textproto index f6a3bbf0e12..75b7900893e 100644 --- a/feature/qos/otg_tests/qos_output_queue_counters_test/metadata.textproto +++ b/feature/qos/otg_tests/qos_output_queue_counters_test/metadata.textproto @@ -19,8 +19,6 @@ platform_exceptions: { } deviations: { scheduler_input_weight_limit: true - explicit_interface_ref_definition: true - qos_dropped_octets: true } } platform_exceptions: { diff --git a/feature/qos/otg_tests/qos_output_queue_counters_test/qos_output_queue_counters_test.go b/feature/qos/otg_tests/qos_output_queue_counters_test/qos_output_queue_counters_test.go index 3ba558b3091..82353b5eef1 100644 --- a/feature/qos/otg_tests/qos_output_queue_counters_test/qos_output_queue_counters_test.go +++ b/feature/qos/otg_tests/qos_output_queue_counters_test/qos_output_queue_counters_test.go @@ -178,22 +178,12 @@ func TestQoSCounters(t *testing.T) { var counterNames []string counters := make(map[string]map[string]uint64) - if !deviations.QOSDroppedOctets(dut) { - counterNames = []string{ - - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", - "dutQosDroppedOctetsAfterTraffic", - } - } else { - counterNames = []string{ - - "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", - "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", - "dutQosDroppedPktsAfterTraffic", - } + counterNames = []string{ + "ateOutPkts", "ateInPkts", "dutQosPktsBeforeTraffic", "dutQosOctetsBeforeTraffic", + "dutQosPktsAfterTraffic", "dutQosOctetsAfterTraffic", "dutQosDroppedPktsBeforeTraffic", + "dutQosDroppedOctetsBeforeTraffic", "dutQosDroppedPktsAfterTraffic", + "dutQosDroppedOctetsAfterTraffic", } for _, name := range counterNames { @@ -226,13 +216,12 @@ func TestQoSCounters(t *testing.T) { } counters["dutQosDroppedPktsBeforeTraffic"][data.queue], _ = count.Val() - if !deviations.QOSDroppedOctets(dut) { - count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) - if !ok { - t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp2.Name(), data.queue, timeout) - } - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + count, ok = gnmi.Watch(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).DroppedOctets().State(), timeout, isPresent).Await(t) + if !ok { + t.Errorf("DroppedOctets count for queue %q on interface %q not available within %v", dp2.Name(), data.queue, timeout) } + counters["dutQosDroppedOctetsBeforeTraffic"][data.queue], _ = count.Val() + } ate.OTG().PushConfig(t, top) @@ -254,9 +243,8 @@ func TestQoSCounters(t *testing.T) { counters["dutQosPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).TransmitPkts().State()) counters["dutQosOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).TransmitOctets().State()) counters["dutQosDroppedPktsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).DroppedPkts().State()) - if !deviations.QOSDroppedOctets(dut) { - counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).DroppedOctets().State()) - } + counters["dutQosDroppedOctetsAfterTraffic"][data.queue] = gnmi.Get(t, dut, gnmi.OC().Qos().Interface(dp2.Name()).Output().Queue(data.queue).DroppedOctets().State()) + t.Logf("ateInPkts: %v, txPkts %v, Queue: %v", counters["ateInPkts"][data.queue], counters["dutQosPktsAfterTraffic"][data.queue], data.queue) ateTxPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(trafficID).Counters().OutPkts().State()) @@ -296,12 +284,10 @@ func TestQoSCounters(t *testing.T) { } } - if !deviations.QOSDroppedOctets(dut) { - dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] - t.Logf("Queue %q: dutDropOctetCounterDiff: %v", data.queue, dutDropOctetCounterDiff) - if dutDropOctetCounterDiff != 0 { - t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want 0", data.queue, dutDropOctetCounterDiff) - } + dutDropOctetCounterDiff := counters["dutQosDroppedOctetsAfterTraffic"][data.queue] - counters["dutQosDroppedOctetsBeforeTraffic"][data.queue] + t.Logf("Queue %q: dutDropOctetCounterDiff: %v", data.queue, dutDropOctetCounterDiff) + if dutDropOctetCounterDiff != 0 { + t.Errorf("Get dutDropOctetCounterDiff for queue %q: got %v, want 0", data.queue, dutDropOctetCounterDiff) } } diff --git a/feature/qos/otg_tests/two_sp_queue_traffic_test/README.md b/feature/qos/otg_tests/two_sp_queue_traffic_test/README.md index 69c06f27d9b..4fdc68784a5 100644 --- a/feature/qos/otg_tests/two_sp_queue_traffic_test/README.md +++ b/feature/qos/otg_tests/two_sp_queue_traffic_test/README.md @@ -160,3 +160,59 @@ Verify that DUT drops AF3, AF2, AF1, BE1 and BE0 before AF4 before NC1. * /qos/interfaces/interface/output/queues/queue/state/transmit-octets * /qos/interfaces/interface/output/queues/queue/state/dropped-pkts * /qos/interfaces/interface/output/queues/queue/state/dropped-octets + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/otg_tests/two_sp_queue_traffic_test/metadata.textproto b/feature/qos/otg_tests/two_sp_queue_traffic_test/metadata.textproto index bc1316ff266..a439925272e 100644 --- a/feature/qos/otg_tests/two_sp_queue_traffic_test/metadata.textproto +++ b/feature/qos/otg_tests/two_sp_queue_traffic_test/metadata.textproto @@ -18,7 +18,6 @@ platform_exceptions: { vendor: JUNIPER } deviations: { - explicit_interface_ref_definition: true scheduler_input_weight_limit: true } } diff --git a/feature/qos/otg_tests/wrr_traffic_test/README.md b/feature/qos/otg_tests/wrr_traffic_test/README.md index 1a981ac4d5e..c9361579b70 100644 --- a/feature/qos/otg_tests/wrr_traffic_test/README.md +++ b/feature/qos/otg_tests/wrr_traffic_test/README.md @@ -145,3 +145,59 @@ Verify that DUT forwards AF3, AF2, AF1, BE0 and BE1 traffic based on WRR weight. * /qos/interfaces/interface/output/queues/queue/state/transmit-octets * /qos/interfaces/interface/output/queues/queue/state/dropped-pkts * /qos/interfaces/interface/output/queues/queue/state/dropped-octets + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/otg_tests/wrr_traffic_test/metadata.textproto b/feature/qos/otg_tests/wrr_traffic_test/metadata.textproto index d50a81212bb..f81dfe8c4b3 100644 --- a/feature/qos/otg_tests/wrr_traffic_test/metadata.textproto +++ b/feature/qos/otg_tests/wrr_traffic_test/metadata.textproto @@ -18,7 +18,6 @@ platform_exceptions: { vendor: JUNIPER } deviations: { - explicit_interface_ref_definition: true scheduler_input_weight_limit: true } } diff --git a/feature/qos/tests/qos_policy_config_test/README.md b/feature/qos/tests/qos_policy_config_test/README.md index 2a556389500..949e9c4d835 100644 --- a/feature/qos/tests/qos_policy_config_test/README.md +++ b/feature/qos/tests/qos_policy_config_test/README.md @@ -172,3 +172,59 @@ Verify QoS policy feature configuration. * /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type * /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue * /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config paths: + /qos/forwarding-groups/forwarding-group/config/name: + /qos/forwarding-groups/forwarding-group/config/output-queue: + /qos/queues/queue/config/name: + /qos/classifiers/classifier/config/name: + /qos/classifiers/classifier/config/type: + /qos/classifiers/classifier/terms/term/actions/config/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp-set: + /qos/classifiers/classifier/terms/term/config/id: + /qos/interfaces/interface/output/queues/queue/config/name: + /qos/interfaces/interface/input/classifiers/classifier/config/name: + /qos/interfaces/interface/output/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/config/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight: + + ## State paths: + /qos/forwarding-groups/forwarding-group/state/name: + /qos/forwarding-groups/forwarding-group/state/output-queue: + /qos/queues/queue/state/name: + /qos/classifiers/classifier/state/name: + /qos/classifiers/classifier/state/type: + /qos/classifiers/classifier/terms/term/actions/state/target-group: + /qos/classifiers/classifier/terms/term/conditions/ipv4/state/dscp-set: + /qos/classifiers/classifier/terms/term/conditions/ipv6/state/dscp-set: + /qos/classifiers/classifier/terms/term/state/id: + /qos/interfaces/interface/output/queues/queue/state/name: + /qos/interfaces/interface/input/classifiers/classifier/state/name: + /qos/interfaces/interface/output/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/state/name: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/priority: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/sequence: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/state/type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/id: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/input-type: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/queue: + /qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/state/weight: + +rpcs: + gnmi: + gNMI.Set: + Replace: \ No newline at end of file diff --git a/feature/qos/tests/qos_policy_config_test/metadata.textproto b/feature/qos/tests/qos_policy_config_test/metadata.textproto index 2933884e6da..bb92f5f7756 100644 --- a/feature/qos/tests/qos_policy_config_test/metadata.textproto +++ b/feature/qos/tests/qos_policy_config_test/metadata.textproto @@ -9,9 +9,4 @@ platform_exceptions: { platform: { vendor: JUNIPER } - deviations: { - state_path_unsupported: true - drop_weight_leaves_unsupported: true - explicit_interface_ref_definition: true - } } diff --git a/feature/qos/tests/qos_policy_config_test/qos_policy_config_test.go b/feature/qos/tests/qos_policy_config_test/qos_policy_config_test.go index e035af3e562..267cb0bddee 100644 --- a/feature/qos/tests/qos_policy_config_test/qos_policy_config_test.go +++ b/feature/qos/tests/qos_policy_config_test/qos_policy_config_test.go @@ -20,7 +20,6 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/qoscfg" "github.com/openconfig/ondatra" @@ -1437,13 +1436,11 @@ func testJuniperClassifierConfig(t *testing.T) { if got, want := gnmi.Get(t, dut, classifier.Type().State()), tc.classType; got != want { t.Errorf("classifier.Type().State(): got %v, want %v", got, want) } - if !deviations.StatePathsUnsupported(dut) { - if got, want := gnmi.Get(t, dut, term.Id().State()), tc.termID; got != want { - t.Errorf("term.Id().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, action.TargetGroup().State()), tc.targetGroup; got != want { - t.Errorf("action.TargetGroup().State(): got %v, want %v", got, want) - } + if got, want := gnmi.Get(t, dut, term.Id().State()), tc.termID; got != want { + t.Errorf("term.Id().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, action.TargetGroup().State()), tc.targetGroup; got != want { + t.Errorf("action.TargetGroup().State(): got %v, want %v", got, want) // This Transformer sorts a []uint8. trans := cmp.Transformer("Sort", func(in []uint8) []uint8 { @@ -1483,28 +1480,27 @@ func testJuniperClassifierConfig(t *testing.T) { targetGroup: "target-group-BE1", queueName: "0", }} - if !deviations.StatePathsUnsupported(dut) { - cases = append(cases, - struct { - desc string - inputClassifierType oc.E_Input_Classifier_Type - classifier string - classType oc.E_Qos_Classifier_Type - termID string - dscpSet []uint8 - targetGroup string - queueName string - }{ - desc: "Input Classifier Type IPV6", - inputClassifierType: oc.Input_Classifier_Type_IPV6, - classifier: "dscp_based_classifier_ipv6", - classType: oc.Qos_Classifier_Type_IPV6, - termID: "0", - targetGroup: "target-group-BE1", - dscpSet: []uint8{0, 1, 2, 3}, - queueName: "0", - }) - } + cases = append(cases, + struct { + desc string + inputClassifierType oc.E_Input_Classifier_Type + classifier string + classType oc.E_Qos_Classifier_Type + termID string + dscpSet []uint8 + targetGroup string + queueName string + }{ + desc: "Input Classifier Type IPV6", + inputClassifierType: oc.Input_Classifier_Type_IPV6, + classifier: "dscp_based_classifier_ipv6", + classType: oc.Qos_Classifier_Type_IPV6, + termID: "0", + targetGroup: "target-group-BE1", + dscpSet: []uint8{0, 1, 2, 3}, + queueName: "0", + }) + dp := dut.Port(t, "port1") ip := &oc.Interface{Name: ygot.String(dp.Name())} ip.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd @@ -1634,22 +1630,22 @@ func testJuniperSchedulerPoliciesConfig(t *testing.T) { scheduler := gnmi.OC().Qos().SchedulerPolicy("scheduler").Scheduler(tc.sequence) input := scheduler.Input(tc.inputID) - if !deviations.StatePathsUnsupported(dut) { - if got, want := gnmi.Get(t, dut, input.Id().State()), tc.inputID; got != want { - t.Errorf("input.Id().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, input.InputType().State()), oc.Input_InputType_QUEUE; got != want { - t.Errorf("input.InputType().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, input.Weight().State()), tc.weight; got != want { - t.Errorf("input.Weight().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, input.Queue().State()), tc.queueName; got != want { - t.Errorf("input.Queue().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, scheduler.Sequence().State()), tc.sequence; got != want { - t.Errorf("scheduler.Sequence().State(): got %v, want %v", got, want) - } + if got, want := gnmi.Get(t, dut, input.Id().State()), tc.inputID; got != want { + t.Errorf("input.Id().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, input.InputType().State()), oc.Input_InputType_QUEUE; got != want { + t.Errorf("input.InputType().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, input.Weight().State()), tc.weight; got != want { + t.Errorf("input.Weight().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, input.Queue().State()), tc.queueName; got != want { + t.Errorf("input.Queue().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, scheduler.Sequence().State()), tc.sequence; got != want { + t.Errorf("scheduler.Sequence().State(): got %v, want %v", got, want) + } + if tc.priority == oc.Scheduler_Priority_STRICT { if got, want := gnmi.Get(t, dut, scheduler.Priority().State()), tc.priority; got != want { t.Errorf("scheduler.Priority().State(): got %v, want %v", got, want) } @@ -1690,25 +1686,21 @@ func testJuniperSchedulerPoliciesConfig(t *testing.T) { if got, want := gnmi.Get(t, dut, wredUniform.MaxDropProbabilityPercent().State()), ecnConfig.maxDropProbabilityPercent; got != want { t.Errorf("wredUniform.MaxDropProbabilityPercent().State(): got %v, want %v", got, want) } - if !deviations.StatePathsUnsupported(dut) { - if got, want := gnmi.Get(t, dut, wredUniform.MinThreshold().State()), ecnConfig.minThreshold; got != want { - t.Errorf("wredUniform.MinThreshold().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, wredUniform.MaxThreshold().State()), ecnConfig.maxThreshold; got != want { - t.Errorf("wredUniform.MaxThreshold().State(): got %v, want %v", got, want) - } + if got, want := gnmi.Get(t, dut, wredUniform.MinThreshold().State()), ecnConfig.minThreshold; got != want { + t.Errorf("wredUniform.MinThreshold().State(): got %v, want %v", got, want) } - if !deviations.DropWeightLeavesUnsupported(dut) { - uniform.SetDrop(ecnConfig.dropEnabled) - uniform.SetWeight(ecnConfig.weight) - gnmi.Replace(t, dut, gnmi.OC().Qos().Config(), q) + if got, want := gnmi.Get(t, dut, wredUniform.MaxThreshold().State()), ecnConfig.maxThreshold; got != want { + t.Errorf("wredUniform.MaxThreshold().State(): got %v, want %v", got, want) + } + uniform.SetDrop(ecnConfig.dropEnabled) + uniform.SetWeight(ecnConfig.weight) + gnmi.Replace(t, dut, gnmi.OC().Qos().Config(), q) - if got, want := gnmi.Get(t, dut, wredUniform.Drop().State()), ecnConfig.dropEnabled; got != want { - t.Errorf("wredUniform.Drop().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, wredUniform.Weight().State()), ecnConfig.weight; got != want { - t.Errorf("wredUniform.Weight().State(): got %v, want %v", got, want) - } + if got, want := gnmi.Get(t, dut, wredUniform.Drop().State()), ecnConfig.dropEnabled; got != want { + t.Errorf("wredUniform.Drop().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, wredUniform.Weight().State()), ecnConfig.weight; got != want { + t.Errorf("wredUniform.Weight().State(): got %v, want %v", got, want) } cases := []struct { @@ -1752,16 +1744,14 @@ func testJuniperSchedulerPoliciesConfig(t *testing.T) { // Verify the policy is applied by checking the telemetry path state values. policy := gnmi.OC().Qos().Interface(dp.Name()).Output().SchedulerPolicy() outQueue := gnmi.OC().Qos().Interface(dp.Name()).Output().Queue(tc.targetGroup) - if !deviations.StatePathsUnsupported(dut) { - if got, want := gnmi.Get(t, dut, policy.Name().State()), "scheduler"; got != want { - t.Errorf("policy.Name().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, outQueue.Name().State()), tc.targetGroup; got != want { - t.Errorf("outQueue.Name().State(): got %v, want %v", got, want) - } - if got, want := gnmi.Get(t, dut, outQueue.QueueManagementProfile().State()), "DropProfile"; got != want { - t.Errorf("outQueue.QueueManagementProfile().State(): got %v, want %v", got, want) - } + if got, want := gnmi.Get(t, dut, policy.Name().State()), "scheduler"; got != want { + t.Errorf("policy.Name().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, outQueue.Name().State()), tc.targetGroup; got != want { + t.Errorf("outQueue.Name().State(): got %v, want %v", got, want) + } + if got, want := gnmi.Get(t, dut, outQueue.QueueManagementProfile().State()), "DropProfile"; got != want { + t.Errorf("outQueue.QueueManagementProfile().State(): got %v, want %v", got, want) } if got, want := gnmi.Get(t, dut, wredUniform.EnableEcn().State()), ecnConfig.ecnEnabled; got != want { t.Errorf("wredUniform.EnableEcn().State(): got %v, want %v", got, want) diff --git a/feature/experimental/replay/tests/diff_command_trees/README.md b/feature/replay/tests/diff_command_trees/README.md similarity index 62% rename from feature/experimental/replay/tests/diff_command_trees/README.md rename to feature/replay/tests/diff_command_trees/README.md index 91720b7d422..61ddc439b53 100644 --- a/feature/experimental/replay/tests/diff_command_trees/README.md +++ b/feature/replay/tests/diff_command_trees/README.md @@ -7,3 +7,17 @@ diff the command trees" error when applying certain gNMI config on Arista devices. At this time, no vendor is expected to run this test. + +## OpenConfig Path and RPC Coverage + +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` diff --git a/feature/experimental/replay/tests/diff_command_trees/diff_command_trees_test.go b/feature/replay/tests/diff_command_trees/diff_command_trees_test.go similarity index 100% rename from feature/experimental/replay/tests/diff_command_trees/diff_command_trees_test.go rename to feature/replay/tests/diff_command_trees/diff_command_trees_test.go diff --git a/feature/experimental/replay/tests/diff_command_trees/metadata.textproto b/feature/replay/tests/diff_command_trees/metadata.textproto similarity index 100% rename from feature/experimental/replay/tests/diff_command_trees/metadata.textproto rename to feature/replay/tests/diff_command_trees/metadata.textproto diff --git a/feature/experimental/replay/tests/p4rt_replay/README.md b/feature/replay/tests/p4rt_replay/README.md similarity index 54% rename from feature/experimental/replay/tests/p4rt_replay/README.md rename to feature/replay/tests/p4rt_replay/README.md index 6861b35f9cb..f23fe835e7e 100644 --- a/feature/experimental/replay/tests/p4rt_replay/README.md +++ b/feature/replay/tests/p4rt_replay/README.md @@ -6,3 +6,17 @@ This is an example record/replay test. It is meant to reproduce an error when replaying P4RT messages. At this time, no vendor is expected to run this test. + +## OpenConfig Path and RPC Coverage + +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` diff --git a/feature/experimental/replay/tests/p4rt_replay/metadata.textproto b/feature/replay/tests/p4rt_replay/metadata.textproto similarity index 100% rename from feature/experimental/replay/tests/p4rt_replay/metadata.textproto rename to feature/replay/tests/p4rt_replay/metadata.textproto diff --git a/feature/experimental/replay/tests/p4rt_replay/p4rt_replay_test.go b/feature/replay/tests/p4rt_replay/p4rt_replay_test.go similarity index 100% rename from feature/experimental/replay/tests/p4rt_replay/p4rt_replay_test.go rename to feature/replay/tests/p4rt_replay/p4rt_replay_test.go diff --git a/feature/replay/tests/presession_test/README.md b/feature/replay/tests/presession_test/README.md new file mode 100644 index 00000000000..f1528f687b0 --- /dev/null +++ b/feature/replay/tests/presession_test/README.md @@ -0,0 +1,20 @@ +# Replay-1.0: Record/replay presession test + +## Summary + +This is an example record/replay test. +At this time, no vendor is expected to run this test. + +## OpenConfig Path and RPC Coverage + +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` diff --git a/feature/experimental/replay/tests/presession_test/metadata.textproto b/feature/replay/tests/presession_test/metadata.textproto similarity index 100% rename from feature/experimental/replay/tests/presession_test/metadata.textproto rename to feature/replay/tests/presession_test/metadata.textproto diff --git a/feature/experimental/replay/tests/presession_test/presession_test.go b/feature/replay/tests/presession_test/presession_test.go similarity index 100% rename from feature/experimental/replay/tests/presession_test/presession_test.go rename to feature/replay/tests/presession_test/presession_test.go diff --git a/feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md b/feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md similarity index 91% rename from feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md rename to feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md index 4515b12bb87..f1e22c2734e 100644 --- a/feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md +++ b/feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md @@ -25,17 +25,13 @@ and gRPC connections. * Ensure gNMI set/get requests are denied with incorrect login or incorrect password. -## Config Parameter coverage - -N/A - -## Telemetry Parameter coverage - -N/A - -## Protocol/RPC Parameter coverage - -N/A +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Set: + gNMI.Subscribe: +``` ## Minimum DUT platform requirement diff --git a/feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/metadata.textproto b/feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/metadata.textproto similarity index 100% rename from feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/metadata.textproto rename to feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/metadata.textproto diff --git a/feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/tls_authentication_over_grpc_test.go b/feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/tls_authentication_over_grpc_test.go similarity index 100% rename from feature/experimental/security/aaa/kne_tests/tls_authentication_over_grpc_test/tls_authentication_over_grpc_test.go rename to feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/tls_authentication_over_grpc_test.go diff --git a/feature/security/gnsi/acctz/README.md b/feature/security/gnsi/acctz/README.md index 3232624cf89..4286a891888 100644 --- a/feature/security/gnsi/acctz/README.md +++ b/feature/security/gnsi/acctz/README.md @@ -33,11 +33,11 @@ Create a library of device configuration to be used for all of the gNSI.acctz.v1 - A User permitted to run some commands in each of the service classes of gnsi.acctz.v1.CommandService.CmdServiceType & gnsi.acctz.v1.GrpcService.GrpcServiceType, but not all ## gNSI Accounting (acctz) Tests: -- [ACCTZ-1.1 Record Subscribe Full](RecordSubscribeFull) -- [ACCTZ-2.1 Record Subscribe Partial](RecordSubscribePartial) -- [ACCTZ-3.1 Record Subscribe Non-gRPC](RecordSubscribeNongrpc) -- [ACCTZ-4.1 Record History Truncation](RecordHistoryTruncation/) -- [ACCTZ-4.2 Record Payload Truncation](RecordPayloadTruncation/) +- [ACCTZ-1.1 Record Subscribe Full](tests/record_subscribe_full) +- [ACCTZ-2.1 Record Subscribe Partial](tests/record_subscribe_partial) +- [ACCTZ-3.1 Record Subscribe Non-gRPC](tests/record_subscribe_non_grpc) +- [ACCTZ-4.1 Record History Truncation](tests/record_history_truncation) +- [ACCTZ-4.2 Record Payload Truncation](tests/record_payload_truncation) - [ACCTZ-5.1 Record Subscribe Idle Timeout](RecordSubscribeIdleTimeout/) - [ACCTZ-6.1 Record Subscribe Idle Timeout DoA](RecordSubscribeIdleTimeoutDoA/) - [ACCTZ-7.1 Accounting Authentication Failure - Multi-transaction](AccountingAuthenFailMulti/) diff --git a/feature/security/gnsi/acctz/RecordHistoryTruncation/README.md b/feature/security/gnsi/acctz/tests/record_history_truncation/README.md similarity index 93% rename from feature/security/gnsi/acctz/RecordHistoryTruncation/README.md rename to feature/security/gnsi/acctz/tests/record_history_truncation/README.md index a8d705b31bd..1f4436d776c 100644 --- a/feature/security/gnsi/acctz/RecordHistoryTruncation/README.md +++ b/feature/security/gnsi/acctz/tests/record_history_truncation/README.md @@ -1,4 +1,4 @@ -# ACCTZ-4.1 - gNSI.acctz.v1 (Accounting) Test Record History Truncation +# ACCTZ-4.1: Record History Truncation ## Summary Test Record Response Truncation boolean is set diff --git a/feature/security/gnsi/acctz/tests/record_history_truncation/metadata.textproto b/feature/security/gnsi/acctz/tests/record_history_truncation/metadata.textproto new file mode 100644 index 00000000000..d50184e352c --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_history_truncation/metadata.textproto @@ -0,0 +1,8 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "3ac6b788-687a-41c7-9324-0afb8d789e15" +plan_id: "ACCTZ-4.1" +description: "Record History Truncation" +testbed: TESTBED_DUT +platform_exceptions: {} diff --git a/feature/security/gnsi/acctz/tests/record_history_truncation/record_history_truncation_test.go b/feature/security/gnsi/acctz/tests/record_history_truncation/record_history_truncation_test.go new file mode 100644 index 00000000000..1c14c9ef1ab --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_history_truncation/record_history_truncation_test.go @@ -0,0 +1,65 @@ +// Copyright 2024 Google LLC +// +// 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. + +package record_history_truncation_test + +import ( + "context" + "testing" + "time" + + "github.com/openconfig/featureprofiles/internal/fptest" + acctzpb "github.com/openconfig/gnsi/acctz" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestAccountzRecordHistoryTruncation(t *testing.T) { + dut := ondatra.DUT(t, "dut") + + systemState := gnmi.Get(t, dut, gnmi.OC().System().State()) + + bootTime := systemState.GetBootTime() + + // Try to get records from 1 day prior to device's boot time. + recordStartTime := time.Unix(0, int64(bootTime)).Add(-24 * time.Hour) + + acctzClient := dut.RawAPIs().GNSI(t).Acctz() + + acctzSubClient, err := acctzClient.RecordSubscribe(context.Background()) + if err != nil { + t.Fatalf("Failed getting accountz record subscribe client, error: %s", err) + } + + err = acctzSubClient.Send(&acctzpb.RecordRequest{ + Timestamp: timestamppb.New(recordStartTime), + }) + if err != nil { + t.Fatalf("Failed sending record request, error: %s", err) + } + + record, err := acctzSubClient.Recv() + if err != nil { + t.Fatalf("Failed receiving from accountz record subscribe client, error: %s", err) + } + + if record.GetHistoryIstruncated() != true { + t.Fatal("History is not truncated but should be.") + } +} diff --git a/feature/security/gnsi/acctz/RecordPayloadTruncation/README.md b/feature/security/gnsi/acctz/tests/record_payload_truncation/README.md similarity index 94% rename from feature/security/gnsi/acctz/RecordPayloadTruncation/README.md rename to feature/security/gnsi/acctz/tests/record_payload_truncation/README.md index 8bf0782019c..fe10d942750 100644 --- a/feature/security/gnsi/acctz/RecordPayloadTruncation/README.md +++ b/feature/security/gnsi/acctz/tests/record_payload_truncation/README.md @@ -1,4 +1,4 @@ -# ACCTZ-4.2 - gNSI.acctz.v1 (Accounting) Test Record Payload Truncation +# ACCTZ-4.2: Record Payload Truncation ## Summary diff --git a/feature/security/gnsi/acctz/tests/record_payload_truncation/metadata.textproto b/feature/security/gnsi/acctz/tests/record_payload_truncation/metadata.textproto new file mode 100644 index 00000000000..714851304ee --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_payload_truncation/metadata.textproto @@ -0,0 +1,8 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "ae09edfd-f64e-4095-b56d-021ce29b659b" +plan_id: "ACCTZ-4.2" +description: "Record Payload Truncation" +testbed: TESTBED_DUT +platform_exceptions: {} diff --git a/feature/security/gnsi/acctz/tests/record_payload_truncation/record_payload_truncation_test.go b/feature/security/gnsi/acctz/tests/record_payload_truncation/record_payload_truncation_test.go new file mode 100644 index 00000000000..ae532753f6b --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_payload_truncation/record_payload_truncation_test.go @@ -0,0 +1,122 @@ +// Copyright 2024 Google LLC +// +// 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. + +package record_payload_truncation_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/openconfig/featureprofiles/internal/fptest" + acctzpb "github.com/openconfig/gnsi/acctz" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +type recordRequestResult struct { + record *acctzpb.RecordResponse + err error +} + +func sendOversizedPayload(t *testing.T, dut *ondatra.DUTDevice) { + // Perhaps other vendors will need a different payload/size/etc., for now we'll just send a + // giant set of network instances + static routes which should hopefully work for everyone. + ocRoot := &oc.Root{} + + for i := 0; i < 50; i++ { + ni := ocRoot.GetOrCreateNetworkInstance(fmt.Sprintf("acctz-test-ni-%d", i)) + ni.SetDescription("This is a pointlessly long description in order to make the payload bigger.") + ni.SetType(oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_L3VRF) + staticProtocol := ni.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_STATIC, "static") + for j := 0; j < 254; j++ { + staticProtocol.GetOrCreateStatic(fmt.Sprintf("10.%d.0.0/24", j)) + } + } + + gnmi.Update(t, dut, gnmi.OC().Config(), ocRoot) +} + +func TestAccountzRecordPayloadTruncation(t *testing.T) { + dut := ondatra.DUT(t, "dut") + startTime := time.Now() + sendOversizedPayload(t, dut) + acctzClient := dut.RawAPIs().GNSI(t).Acctz() + + acctzSubClient, err := acctzClient.RecordSubscribe(context.Background()) + if err != nil { + t.Fatalf("Failed getting accountz record subscribe client, error: %s", err) + } + + err = acctzSubClient.Send(&acctzpb.RecordRequest{ + Timestamp: timestamppb.New(startTime), + }) + if err != nil { + t.Fatalf("Failed sending record request, error: %s", err) + } + + for { + r := make(chan recordRequestResult) + + go func(r chan recordRequestResult) { + var response *acctzpb.RecordResponse + response, err = acctzSubClient.Recv() + r <- recordRequestResult{ + record: response, + err: err, + } + }(r) + + var done bool + var resp recordRequestResult + + select { + case rr := <-r: + resp = rr + case <-time.After(10 * time.Second): + done = true + } + + if done { + t.Fatal("Done receiving records and did not find our record...") + } + + if resp.err != nil { + t.Fatalf("Failed receiving record response, error: %s", resp.err) + } + + grpcServiceRecord := resp.record.GetGrpcService() + + if grpcServiceRecord.GetServiceType() != acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNMI { + // Not our gnmi set, nothing to see here. + continue + } + + if grpcServiceRecord.RpcName != "/gnmi.gNMI/Set" { + continue + } + + if grpcServiceRecord.GetPayloadIstruncated() { + t.Log("Found truncated payload of gnmi.Set after start timestamp, success!") + break + } + } +} diff --git a/feature/security/gnsi/acctz/RecordSubscribeFull/README.md b/feature/security/gnsi/acctz/tests/record_subscribe_full/README.md similarity index 98% rename from feature/security/gnsi/acctz/RecordSubscribeFull/README.md rename to feature/security/gnsi/acctz/tests/record_subscribe_full/README.md index 31e90a3d563..56ead2cf8de 100644 --- a/feature/security/gnsi/acctz/RecordSubscribeFull/README.md +++ b/feature/security/gnsi/acctz/tests/record_subscribe_full/README.md @@ -1,4 +1,4 @@ -# ACCTZ-1.1 - gNSI.acctz.v1 (Accounting) Test Record Subscribe Full +# ACCTZ-1.1: Record Subscribe Full ## Summary Test RecordSubscribe for all (since epoch) records diff --git a/feature/security/gnsi/acctz/tests/record_subscribe_full/metadata.textproto b/feature/security/gnsi/acctz/tests/record_subscribe_full/metadata.textproto new file mode 100644 index 00000000000..9d42fb16744 --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_subscribe_full/metadata.textproto @@ -0,0 +1,7 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "c1352e24-e45c-4f6d-9b16-d28cc1a5093a" +plan_id: "ACCTZ-1.1" +description: "Record Subscribe Full" +testbed: TESTBED_DUT \ No newline at end of file diff --git a/feature/security/gnsi/acctz/tests/record_subscribe_full/record_subscribe_full_test.go b/feature/security/gnsi/acctz/tests/record_subscribe_full/record_subscribe_full_test.go new file mode 100644 index 00000000000..4c6e329f8d2 --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_subscribe_full/record_subscribe_full_test.go @@ -0,0 +1,181 @@ +// Copyright 2024 Google LLC +// +// 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. + +package recordsubscribefull_test + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" + + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/security/acctz" + acctzpb "github.com/openconfig/gnsi/acctz" + "github.com/openconfig/ondatra" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type recordRequestResult struct { + record *acctzpb.RecordResponse + err error +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func prettyPrint(i any) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +func TestAccountzRecordSubscribeFull(t *testing.T) { + dut := ondatra.DUT(t, "dut") + acctz.SetupUsers(t, dut, false) + var records []*acctzpb.RecordResponse + + // Put enough time between the test starting and any prior events so we can easily know where + // our records start. + time.Sleep(5 * time.Second) + + startTime := time.Now() + newRecords := acctz.SendGnmiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendGnoiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendGnsiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendGribiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendP4rtRPCs(t, dut) + records = append(records, newRecords...) + + // Quick sleep to ensure all the records have been processed/ready for us. + time.Sleep(5 * time.Second) + + // Get gNSI record subscribe client. + requestTimestamp := ×tamppb.Timestamp{ + Seconds: 0, + Nanos: 0, + } + acctzClient := dut.RawAPIs().GNSI(t).AcctzStream() + acctzSubClient, err := acctzClient.RecordSubscribe(context.Background(), &acctzpb.RecordRequest{Timestamp: requestTimestamp}) + if err != nil { + t.Fatalf("Failed sending accountz record request, error: %s", err) + } + defer acctzSubClient.CloseSend() + + var recordIdx int + var lastTimestampUnixMillis int64 + r := make(chan recordRequestResult) + + // Ignore proto fields which are set internally by the DUT (cannot be matched exactly) + // and compare them manually later. + popts := []cmp.Option{ + protocmp.Transform(), + protocmp.IgnoreFields(&acctzpb.RecordResponse{}, "timestamp", "task_ids"), + protocmp.IgnoreFields(&acctzpb.AuthzDetail{}, "detail"), + protocmp.IgnoreFields(&acctzpb.SessionInfo{}, "channel_id"), + } + + for { + if recordIdx >= len(records) { + t.Log("Out of records to process...") + break + } + + // Read single acctz record from stream into channel. + go func(r chan recordRequestResult) { + var response *acctzpb.RecordResponse + response, err = acctzSubClient.Recv() + r <- recordRequestResult{ + record: response, + err: err, + } + }(r) + + var done bool + var resp recordRequestResult + + // Read acctz record from channel for evaluation. + // Timeout and exit if no records received on the channel for some time. + select { + case rr := <-r: + resp = rr + case <-time.After(10 * time.Second): + done = true + } + + if done { + t.Log("Done receiving records...") + break + } + + if resp.err != nil { + t.Fatalf("Failed receiving record response, error: %s", resp.err) + } + + if resp.record.GetHistoryIstruncated() { + t.Errorf("History is truncated but it shouldn't be, Record Details: %s", prettyPrint(resp.record)) + } + + if !resp.record.Timestamp.AsTime().After(startTime) { + // Skipping record if it happened before test start time. + continue + } + + timestamp := resp.record.Timestamp.AsTime() + if timestamp.UnixMilli() == lastTimestampUnixMillis { + // This ensures that timestamps are actually changing for each record. + t.Errorf("Timestamp is the same as the previous timestamp, this shouldn't be possible!, Record Details: %s", prettyPrint(resp.record)) + } + lastTimestampUnixMillis = timestamp.UnixMilli() + + // Verify acctz proto bits. + if diff := cmp.Diff(resp.record, records[recordIdx], popts...); diff != "" { + t.Errorf("Got diff in got/want: %s", diff) + } + + // Verify record timestamp is after request timestamp. + if !timestamp.After(requestTimestamp.AsTime()) { + t.Errorf("Record timestamp is before record request timestamp %v, Record Details: %v", requestTimestamp.AsTime(), prettyPrint(resp.record)) + } + + // This channel check maybe should just go away entirely -- see: + // https://github.com/openconfig/gnsi/issues/98 + // In case of Nokia this is being set to the aaa session id just to have some hopefully + // useful info in this field to identify a "session" (even if it isn't necessarily ssh/grpc + // directly). + if resp.record.GetSessionInfo().GetChannelId() == "" { + t.Errorf("Channel Id is not populated for record: %v", prettyPrint(resp.record)) + } + + // Verify authz detail is populated for denied rpcs. + authzInfo := resp.record.GetGrpcService().GetAuthz() + if authzInfo.Status == acctzpb.AuthzDetail_AUTHZ_STATUS_DENY && authzInfo.GetDetail() == "" { + t.Errorf("Authorization detail is not populated for record: %v", prettyPrint(resp.record)) + } + + t.Logf("Processed Record: %s", prettyPrint(resp.record)) + recordIdx++ + } + + if recordIdx != len(records) { + t.Fatal("Did not process all records.") + } +} diff --git a/feature/security/gnsi/acctz/RecordSubscribeNongrpc/README.md b/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/README.md similarity index 98% rename from feature/security/gnsi/acctz/RecordSubscribeNongrpc/README.md rename to feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/README.md index 74a7e7aaad7..6ca2e7f8fc1 100644 --- a/feature/security/gnsi/acctz/RecordSubscribeNongrpc/README.md +++ b/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/README.md @@ -1,4 +1,4 @@ -# ACCTZ-3.1 - gNSI.acctz.v1 (Accounting) Test Record Subscribe Non-gRPC +# ACCTZ-3.1: Record Subscribe Non-gRPC ## Summary Test Accounting for non-gRPC records diff --git a/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/metadata.textproto b/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/metadata.textproto new file mode 100644 index 00000000000..a9a183ff323 --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/metadata.textproto @@ -0,0 +1,7 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "036d3d49-00dd-46ff-abe6-afc20768db6f" +plan_id: "ACCTZ-3.1" +description: "Record Subscribe Non-gRPC" +testbed: TESTBED_DUT \ No newline at end of file diff --git a/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/record_subscribe_non_grpc_test.go b/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/record_subscribe_non_grpc_test.go new file mode 100644 index 00000000000..97812587dc9 --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_subscribe_non_grpc/record_subscribe_non_grpc_test.go @@ -0,0 +1,186 @@ +// Copyright 2024 Google LLC +// +// 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. + +package recordsubscribenongrpc_test + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/security/acctz" + acctzpb "github.com/openconfig/gnsi/acctz" + "github.com/openconfig/ondatra" +) + +type recordRequestResult struct { + record *acctzpb.RecordResponse + err error +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func prettyPrint(i any) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +func TestAccountzRecordSubscribeNonGRPC(t *testing.T) { + dut := ondatra.DUT(t, "dut") + acctz.SetupUsers(t, dut, true) + var records []*acctzpb.RecordResponse + + // Put enough time between the test starting and any prior events so we can easily know where + // our records start. + time.Sleep(5 * time.Second) + + startTime := time.Now() + newRecords := acctz.SendSuccessCliCommand(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendFailCliCommand(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendShellCommand(t, dut) + records = append(records, newRecords...) + + // Quick sleep to ensure all the records have been processed/ready for us. + time.Sleep(5 * time.Second) + + // Get gNSI record subscribe client. + requestTimestamp := ×tamppb.Timestamp{ + Seconds: 0, + Nanos: 0, + } + acctzClient := dut.RawAPIs().GNSI(t).AcctzStream() + acctzSubClient, err := acctzClient.RecordSubscribe(context.Background(), &acctzpb.RecordRequest{Timestamp: requestTimestamp}) + if err != nil { + t.Fatalf("Failed sending accountz record request, error: %s", err) + } + defer acctzSubClient.CloseSend() + + var recordIdx int + var lastTimestampUnixMillis int64 + var lastTaskID string + r := make(chan recordRequestResult) + + // Ignore proto fields which are set internally by the DUT (cannot be matched exactly) + // and compare them manually later. + popts := []cmp.Option{protocmp.Transform(), + protocmp.IgnoreFields(&acctzpb.RecordResponse{}, "timestamp", "task_ids"), + protocmp.IgnoreFields(&acctzpb.AuthzDetail{}, "detail"), + protocmp.IgnoreFields(&acctzpb.SessionInfo{}, "channel_id", "tty"), + } + + for { + if recordIdx >= len(records) { + t.Log("Out of records to process...") + break + } + + // Read single acctz record from stream into channel. + go func(r chan recordRequestResult) { + var response *acctzpb.RecordResponse + response, err = acctzSubClient.Recv() + r <- recordRequestResult{ + record: response, + err: err, + } + }(r) + + var done bool + var resp recordRequestResult + + // Read acctz record from channel for evaluation. + // Timeout and exit if no records received on the channel for some time. + select { + case rr := <-r: + resp = rr + case <-time.After(10 * time.Second): + done = true + } + + if done { + t.Log("Done receiving records...") + break + } + + if resp.err != nil { + t.Fatalf("Failed receiving record response, error: %s", resp.err) + } + + if !resp.record.Timestamp.AsTime().After(startTime) { + // Skipping record if it happened before test start time. + continue + } + + // Some task ids may be tracked multiple times (for start/stop accounting). If we see two in + // a row that are the same task, we can skip this record and continue. + currentTaskID := resp.record.TaskIds[0] + if currentTaskID == lastTaskID { + continue + } + lastTaskID = currentTaskID + + timestamp := resp.record.Timestamp.AsTime() + if timestamp.UnixMilli() == lastTimestampUnixMillis { + // This ensures that timestamps are actually changing for each record. + t.Errorf("Timestamp is the same as the previous timestamp, this shouldn't be possible!, Record Details: %s", prettyPrint(resp.record)) + } + lastTimestampUnixMillis = timestamp.UnixMilli() + + // Verify acctz proto bits. + if diff := cmp.Diff(resp.record, records[recordIdx], popts...); diff != "" { + t.Errorf("got diff in got/want: %s", diff) + } + + // Verify record timestamp is after request timestamp. + if !timestamp.After(requestTimestamp.AsTime()) { + t.Errorf("Record timestamp is before record request timestamp %v, Record Details: %v", requestTimestamp.AsTime(), prettyPrint(resp.record)) + } + + // This channel check maybe should just go away entirely -- see: + // https://github.com/openconfig/gnsi/issues/98 + // In case of Nokia this is being set to the aaa session id just to have some hopefully + // useful info in this field to identify a "session" (even if it isn't necessarily ssh/grpc + // directly). + if resp.record.GetSessionInfo().GetChannelId() == "" { + t.Errorf("Channel Id is not populated for record: %v", prettyPrint(resp.record)) + } + + // Tty only set for ssh records. + if resp.record.GetSessionInfo().GetTty() == "" { + t.Errorf("Should have tty allocated but not set, Record Details: %s", prettyPrint(resp.record)) + } + + // Verify authz detail is populated for denied cmds. + authzInfo := resp.record.GetCmdService().GetAuthz() + if authzInfo.Status == acctzpb.AuthzDetail_AUTHZ_STATUS_DENY && authzInfo.GetDetail() == "" { + t.Errorf("Authorization detail is not populated for record: %v", prettyPrint(resp.record)) + } + + t.Logf("Processed Record: %s", prettyPrint(resp.record)) + recordIdx++ + } + + if recordIdx != len(records) { + t.Fatal("Did not process all records.") + } +} diff --git a/feature/security/gnsi/acctz/RecordSubscribePartial/README.md b/feature/security/gnsi/acctz/tests/record_subscribe_partial/README.md similarity index 96% rename from feature/security/gnsi/acctz/RecordSubscribePartial/README.md rename to feature/security/gnsi/acctz/tests/record_subscribe_partial/README.md index 69e685d4b76..f7b38bf2cb2 100644 --- a/feature/security/gnsi/acctz/RecordSubscribePartial/README.md +++ b/feature/security/gnsi/acctz/tests/record_subscribe_partial/README.md @@ -1,4 +1,4 @@ -# ACCTZ-2.1 - gNSI.acctz.v1 (Accounting) Test Record Subscribe Partial +# ACCTZ-2.1: Record Subscribe Partial ## Summary Test RecordSubscribe for records since a non-zero timestamp diff --git a/feature/security/gnsi/acctz/tests/record_subscribe_partial/metadata.textproto b/feature/security/gnsi/acctz/tests/record_subscribe_partial/metadata.textproto new file mode 100644 index 00000000000..bb04d5949b7 --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_subscribe_partial/metadata.textproto @@ -0,0 +1,7 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "31dbda6b-5034-4a95-880c-25e4ce0676c4" +plan_id: "ACCTZ-2.1" +description: "Record Subscribe Partial" +testbed: TESTBED_DUT \ No newline at end of file diff --git a/feature/security/gnsi/acctz/tests/record_subscribe_partial/record_subscribe_partial_test.go b/feature/security/gnsi/acctz/tests/record_subscribe_partial/record_subscribe_partial_test.go new file mode 100644 index 00000000000..136f2d3d7ad --- /dev/null +++ b/feature/security/gnsi/acctz/tests/record_subscribe_partial/record_subscribe_partial_test.go @@ -0,0 +1,201 @@ +// Copyright 2024 Google LLC +// +// 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. + +package recordsubscribepartial_test + +import ( + "context" + "encoding/json" + "reflect" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" + + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/security/acctz" + acctzpb "github.com/openconfig/gnsi/acctz" + "github.com/openconfig/ondatra" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type recordRequestResult struct { + record *acctzpb.RecordResponse + err error +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func prettyPrint(i any) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +func TestAccountzRecordSubscribePartial(t *testing.T) { + dut := ondatra.DUT(t, "dut") + acctz.SetupUsers(t, dut, false) + var records []*acctzpb.RecordResponse + + // Put enough time between the test starting and any prior events so we can easily know where + // our records start. + time.Sleep(5 * time.Second) + + startTime := time.Now() + newRecords := acctz.SendGnmiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendGnoiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendGnsiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendGribiRPCs(t, dut) + records = append(records, newRecords...) + newRecords = acctz.SendP4rtRPCs(t, dut) + records = append(records, newRecords...) + + // Quick sleep to ensure all the records have been processed/ready for us. + time.Sleep(5 * time.Second) + + // Get gNSI record subscribe client. + acctzClient := dut.RawAPIs().GNSI(t).AcctzStream() + acctzSubClient, err := acctzClient.RecordSubscribe(context.Background(), &acctzpb.RecordRequest{ + Timestamp: ×tamppb.Timestamp{ + Seconds: 0, + Nanos: 0, + }, + }) + if err != nil { + t.Fatalf("Failed sending first accountz record request, error: %s", err) + } + + firstResponse, err := acctzSubClient.Recv() + if err != nil { + t.Fatalf("Failed receiving first record response, error: %s", err) + } + + // Fetch fresh client. + acctzClient = dut.RawAPIs().GNSI(t).AcctzStream() + acctzSubClient, err = acctzClient.RecordSubscribe(context.Background(), &acctzpb.RecordRequest{ + Timestamp: firstResponse.Timestamp, + }) + if err != nil { + t.Fatalf("Failed sending second accountz record request, error: %s", err) + } + defer acctzSubClient.CloseSend() + + secondResponse, err := acctzSubClient.Recv() + if err != nil { + t.Fatalf("Failed receiving second record response, error: %s", err) + } + + if reflect.DeepEqual(firstResponse, secondResponse) { + t.Fatalf("Accountz server responded with same event on subsequent record request.") + } + + var recordIdx int + var lastTimestampUnixMillis int64 + r := make(chan recordRequestResult) + + // Ignore proto fields which are set internally by the DUT (cannot be matched exactly) + // and compare them manually later. + popts := []cmp.Option{protocmp.Transform(), + protocmp.IgnoreFields(&acctzpb.RecordResponse{}, "timestamp", "task_ids"), + protocmp.IgnoreFields(&acctzpb.AuthzDetail{}, "detail"), + protocmp.IgnoreFields(&acctzpb.SessionInfo{}, "channel_id"), + } + + for { + if recordIdx >= len(records) { + t.Log("Out of records to process...") + break + } + + // Read single acctz record from stream into channel. + go func(r chan recordRequestResult) { + var response *acctzpb.RecordResponse + response, err = acctzSubClient.Recv() + r <- recordRequestResult{ + record: response, + err: err, + } + }(r) + + var done bool + var resp recordRequestResult + + // Read acctz record from channel for evaluation. + // Timeout and exit if no records received on the channel for some time. + select { + case rr := <-r: + resp = rr + case <-time.After(10 * time.Second): + done = true + } + + if done { + t.Log("Done receiving records...") + break + } + + if resp.err != nil { + t.Fatalf("Failed receiving record response, error: %s", resp.err) + } + + if !resp.record.Timestamp.AsTime().After(startTime) { + // Skipping record, was before test start time. + continue + } + + timestamp := resp.record.Timestamp.AsTime() + if timestamp.UnixMilli() == lastTimestampUnixMillis { + // This ensures that timestamps are actually changing for each record. + t.Errorf("Timestamp is the same as the previous timestamp, this shouldn't be possible!, Record Details: %s", prettyPrint(resp.record)) + } + lastTimestampUnixMillis = timestamp.UnixMilli() + + // Verify acctz proto bits. + if diff := cmp.Diff(resp.record, records[recordIdx], popts...); diff != "" { + t.Errorf("got diff in got/want: %s", diff) + } + + // Verify record timestamp is after request timestamp. + if !timestamp.After(firstResponse.Timestamp.AsTime()) { + t.Errorf("Record timestamp is before record request timestamp %v, Record Details: %v", firstResponse.Timestamp.AsTime(), prettyPrint(resp.record)) + } + + // This channel check maybe should just go away entirely -- see: + // https://github.com/openconfig/gnsi/issues/98 + // In case of Nokia this is being set to the aaa session id just to have some hopefully + // useful info in this field to identify a "session" (even if it isn't necessarily ssh/grpc + // directly). + if resp.record.GetSessionInfo().GetChannelId() == "" { + t.Errorf("Channel Id is not populated for record: %v", prettyPrint(resp.record)) + } + + // Verify authz detail is populated for denied rpcs. + authzInfo := resp.record.GetGrpcService().GetAuthz() + if authzInfo.Status == acctzpb.AuthzDetail_AUTHZ_STATUS_DENY && authzInfo.GetDetail() == "" { + t.Errorf("Authorization detail is not populated for record: %v", prettyPrint(resp.record)) + } + + t.Logf("Processed Record: %s", prettyPrint(resp.record)) + recordIdx++ + } + + if recordIdx != len(records) { + t.Fatal("Did not process all records.") + } +} diff --git a/feature/security/gnsi/certz/client_certificates/README.md b/feature/security/gnsi/certz/client_certificates/README.md index f34513e3eac..0efdc4f8f6c 100644 --- a/feature/security/gnsi/certz/client_certificates/README.md +++ b/feature/security/gnsi/certz/client_certificates/README.md @@ -8,6 +8,20 @@ identification information. The client certificate should have a SPIFFE Idenitifier embedded in it to be used as the identifier of the client to the server. +* SPIFFEE ID format + +``` +spiffe://.../role/ +``` + +* Example: + +``` +URI:spiffe://ca-issuer.sdn.wan.example.com/role/controller-role +``` + + + ## Baseline Setup ### Input Args @@ -42,8 +56,8 @@ gRPC service. Perform this for both RSA and ECDSA signed CA bundles and certificates. -Perform this for the permutations of 1, 2, 10, 1000 CA -trust_bundle configurations: (## indicates the 1, 2, 10, 1000 CA testdata) +Perform this for the permutations of 1, 2, 10, 1000, 20000 CA +trust_bundle configurations: (## indicates the 1, 2, 10, 1000, 20000 CA testdata) 1) Load the correct key-type trust bundle onto the device and client system: ca-##/trust_bundle_##_rsa.pem diff --git a/feature/security/gnsi/certz/test_data/README.md b/feature/security/gnsi/certz/test_data/README.md index 736b7cd9486..3ccc3362143 100644 --- a/feature/security/gnsi/certz/test_data/README.md +++ b/feature/security/gnsi/certz/test_data/README.md @@ -10,6 +10,7 @@ Creation of test data for use in TLS tests. * ca-02 - a set of two CAs where signatures are RSA or ECDSA. * ca-10 - a set of ten CAs where signatures are RSA or ECDSA. * ca-1000 - a set of one thousand CAs where signatures are RSA or ECDSA. + * ca-20000 - a set of twenty thousand CAs where signatures are RSA or ECDSA. * server_cert.cnf/server_cert_ext.cnf - server openssl profile configuration * client_cert.cnf/client_cert_ext.cnf - client openssl profile configuration diff --git a/feature/security/gnsi/certz/test_data/cleanup.sh b/feature/security/gnsi/certz/test_data/cleanup.sh index a8afee9db65..95b7cbaf6da 100755 --- a/feature/security/gnsi/certz/test_data/cleanup.sh +++ b/feature/security/gnsi/certz/test_data/cleanup.sh @@ -1,4 +1,5 @@ #!/bin/sh -for d in 01 02 10 1000; do - rm -f ca-${d}/* +for d in 01 02 10 1000 20000; do + find ca-${d}/ -type f -exec /usr/bin/rm -f {} \; + /usr/bin/rm -rf ca-${d}/ done diff --git a/feature/security/gnsi/certz/test_data/mk_cas.sh b/feature/security/gnsi/certz/test_data/mk_cas.sh index 50dda0cdfdd..06febedb804 100755 --- a/feature/security/gnsi/certz/test_data/mk_cas.sh +++ b/feature/security/gnsi/certz/test_data/mk_cas.sh @@ -5,7 +5,7 @@ # # The list of directories of CA contents, also the count of CAs built # in each directory. -DIRS=(01 02 10 1000) +DIRS=(01 02 10 1000 20000) # The types of signatures to support for the CA Certs. TYPES=(rsa ecdsa) @@ -20,14 +20,14 @@ RSAKEYLEN=2048 LIFETIME=3650 # Create RSA and ECDSA CA keys, and associated certificates. -for d in ${DIRS[@]} ; do +for d in ${DIRS[@]} ; do if [ ! -d ca-${d} ] ; then mkdir ca-${d} fi # Create a CA key and certificate for each of the DIRS count of # keys / certs. Do this for each of the TYPES key types. for k in $(seq 1 ${d}); do - OFFSET=$(printf "%04i" ${k}) + OFFSET=$(printf "%05i" ${k}) for t in ${TYPES[@]}; do # Generate the appropriate key type keys. case ${t} in @@ -53,6 +53,11 @@ done for d in ${DIRS[@]}; do for t in ${TYPES[@]}; do cat ca-${d}/ca-*-${t}-cert.pem > ca-${d}/trust_bundle_${d}_${t}.pem + CERTS="" + for cf in ca-${d}/ca-*-${t}-cert.pem; do + CERTS="${CERTS} -certfile ${cf}" + done + openssl crl2pkcs7 -nocrl ${CERTS} -out ca-${d}/trust_bundle_${d}_${t}.p7b done done @@ -67,7 +72,7 @@ for d in ${DIRS[@]}; do mkdir ca-${d} fi for t in ${TYPES[@]}; do - OFFSET=$(printf "%04i" ${d}) + OFFSET=$(printf "%05i" ${d}) # Create both client and server cert keys for each type. # use a/b here to signal the required 2 client or server certs/keys. for g in a b; do diff --git a/feature/security/gnsi/certz/trust_bundle/README.md b/feature/security/gnsi/certz/trust_bundle/README.md index eda1bf030de..fbbee7d1e6d 100644 --- a/feature/security/gnsi/certz/trust_bundle/README.md +++ b/feature/security/gnsi/certz/trust_bundle/README.md @@ -62,6 +62,7 @@ Load the server certificate and key from each of the following CA sets: * ca-02 * ca-10 * ca-1000 + * ca-20000 Each service must be configured to use the appropriate certificate and validate that certificate using the included trust_bundle. diff --git a/feature/security/gnsi/credentialz/tests/README.md b/feature/security/gnsi/credentialz/tests/README.md index 08442078f8d..a6cd29841d9 100644 --- a/feature/security/gnsi/credentialz/tests/README.md +++ b/feature/security/gnsi/credentialz/tests/README.md @@ -169,7 +169,7 @@ and * Provide incorrect password, but correct username. * Authentication must fail. -### Credentialz-2, SSH pasword login disallowed +### Credentialz-2, SSH password login disallowed #### Setup * Set a username of `testuser` diff --git a/feature/security/gnsi/credentialz/tests/hiba_authentication/README.md b/feature/security/gnsi/credentialz/tests/hiba_authentication/README.md new file mode 100644 index 00000000000..89f3fc884c4 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/hiba_authentication/README.md @@ -0,0 +1,55 @@ +# Credentialz-5: Hiba Authentication + +## Summary + +Test that Credentialz properly configures (hiba) certificate authentication. + + +## Procedure + +* Follow the instructions for setting up a [HIBA CA](https://github.com/google/hiba/blob/main/CA.md) +* Set DUT allowed authentication types to only public key using gnsi.Credentialz +* Create a user `testuser` (with no certificate at this point) +* Set the AuthorizedPrincipalsCommand by setting the tool to `TOOL_HIBA_DEFAULT` + +* Perform the following tests and assert the expected result: + * Case 1: Failure + * Authenticate with the `testuser` username and the previously created public key via SSH + * Assert that authentication has failed (because the DUT doesn't have the Hiba host certificate at this point) + * Ensure that access rejects telemetry counter is incremented `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-rejects` + * Case 2: Success + * Configure the dut with the Hiba host certificate. + * Authenticate with the `testuser` username the previously created public key via SSH + * Assert that authentication has been successful + * Ensure telemetry values for version and created-on match the values set by + RotateHostParameters for + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:active-host-certificate-version` + and + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:active-host-certificate-created-on` + * Ensure that access accept telemetry counters are incremented after successful login + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-accepts` + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:last-access-accept` + + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## State Paths ## + /system/ssh-server/state/active-host-certificate-version: + /system/ssh-server/state/active-host-certificate-created-on: + /system/ssh-server/state/counters/access-accepts: + /system/ssh-server/state/counters/last-access-accept: + /system/ssh-server/state/counters/access-rejects: + +rpcs: + gnsi: + credentialz.v1.Credentialz.RotateHostParameters: +``` + + +## Minimum DUT platform requirement + +N/A \ No newline at end of file diff --git a/feature/security/gnsi/credentialz/tests/hiba_authentication/hiba_authentication_test.go b/feature/security/gnsi/credentialz/tests/hiba_authentication/hiba_authentication_test.go new file mode 100644 index 00000000000..d63699abff9 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/hiba_authentication/hiba_authentication_test.go @@ -0,0 +1,163 @@ +// Copyright 2024 Google LLC +// +// 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. + +package hibaauthentication_test + +import ( + "fmt" + "os" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/openconfig/featureprofiles/internal/security/credz" + "github.com/openconfig/ondatra/gnmi" + + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + cpb "github.com/openconfig/gnsi/credentialz" + "github.com/openconfig/ondatra" +) + +const ( + username = "testuser" + hostCertificateVersion = "v1.0" +) + +var ( + hostCertificateCreatedOn = time.Now().Unix() +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestCredentialz(t *testing.T) { + dut := ondatra.DUT(t, "dut") + target := credz.GetDutTarget(t, dut) + + // Create temporary directory for storing ssh keys/certificates. + dir, err := os.MkdirTemp("", "") + if err != nil { + t.Fatalf("creating temp dir, err: %s", err) + } + defer func(dir string) { + err = os.RemoveAll(dir) + if err != nil { + t.Logf("error removing temp directory, error: %s", err) + } + }(dir) + + credz.CreateHibaKeys(t, dir) + credz.SetupUser(t, dut, username) + + // Set only public key authentication for our test. + credz.RotateAuthenticationTypes(t, dut, []cpb.AuthenticationType{ + cpb.AuthenticationType_AUTHENTICATION_TYPE_PUBKEY, + }) + + // Setup hiba for authorized principals command. + credz.RotateAuthorizedPrincipalCheck(t, dut, cpb.AuthorizedPrincipalCheckRequest_TOOL_HIBA_DEFAULT) + + t.Run("auth should fail hiba host certificate not present", func(t *testing.T) { + var startingRejectCounter uint64 + if !deviations.SSHServerCountersUnsupported(dut) { + startingRejectCounter, _ = credz.GetRejectTelemetry(t, dut) + } + + // Verify ssh with hiba fails as expected. + _, err := credz.SSHWithCertificate(t, target, username, fmt.Sprintf("%s/users", dir)) + if err == nil { + t.Fatalf("Dialing ssh succeeded, but we expected to fail") + } + + if !deviations.SSHServerCountersUnsupported(dut) { + endingRejectCounter, _ := credz.GetRejectTelemetry(t, dut) + if endingRejectCounter <= startingRejectCounter { + t.Fatalf("SSH server reject counter did not increment after unsuccessful login. startCounter: %v, endCounter: %v", startingRejectCounter, endingRejectCounter) + } + } + }) + + t.Run("auth should succeed ssh public key authorized for user with hiba granted certificate", func(t *testing.T) { + // Push host key/certificate to the dut. + credz.RotateAuthenticationArtifacts(t, + dut, + fmt.Sprintf("%s/hosts", dir), + fmt.Sprintf("%s/hosts", dir), + hostCertificateVersion, + uint64(hostCertificateCreatedOn), + ) + + // Setup trusted user ca on the dut. + credz.RotateTrustedUserCA(t, dut, dir) + + var startingAcceptCounter, startingLastAcceptTime uint64 + if !deviations.SSHServerCountersUnsupported(dut) { + startingAcceptCounter, startingLastAcceptTime = credz.GetAcceptTelemetry(t, dut) + } + + _, err := credz.SSHWithCertificate(t, target, username, fmt.Sprintf("%s/users", dir)) + if err != nil { + t.Fatalf("Dialing ssh failed, but we expected to succeed, errror: %s", err) + } + + // Verify ssh counters. + if !deviations.SSHServerCountersUnsupported(dut) { + endingAcceptCounter, endingLastAcceptTime := credz.GetAcceptTelemetry(t, dut) + if endingAcceptCounter <= startingAcceptCounter { + t.Fatalf("SSH server accept counter did not increment after successful login. startCounter: %v, endCounter: %v", startingAcceptCounter, endingAcceptCounter) + } + if startingLastAcceptTime == endingLastAcceptTime { + t.Fatalf("SSH server accept last timestamp did not update after successful login. Timestamp: %v", endingLastAcceptTime) + } + } + + // Verify host certificate telemetry. + sshServer := gnmi.Get(t, dut, gnmi.OC().System().SshServer().State()) + gotHostCertificateVersion := sshServer.GetActiveHostCertificateVersion() + if !cmp.Equal(gotHostCertificateVersion, hostCertificateVersion) { + t.Fatalf( + "Telemetry reports host certificate version is not correct\n\tgot: %s\n\twant: %s", + gotHostCertificateVersion, hostCertificateVersion, + ) + } + gotHostCertificateCreatedOn := sshServer.GetActiveHostCertificateCreatedOn() + if !cmp.Equal(time.Unix(0, int64(gotHostCertificateCreatedOn)), time.Unix(hostCertificateCreatedOn, 0)) { + t.Fatalf( + "Telemetry reports host certificate created on is not correct\n\tgot: %d\n\twant: %d", + gotHostCertificateCreatedOn, hostCertificateCreatedOn, + ) + } + }) + + t.Cleanup(func() { + // Cleanup to remove previous policy which only allowed key auth to make sure we don't leave dut in a + // state where we can't reset config for further tests. + credz.RotateAuthenticationTypes(t, dut, []cpb.AuthenticationType{ + cpb.AuthenticationType_AUTHENTICATION_TYPE_PASSWORD, + cpb.AuthenticationType_AUTHENTICATION_TYPE_PUBKEY, + cpb.AuthenticationType_AUTHENTICATION_TYPE_KBDINTERACTIVE, + }) + + // Remove user ca so subsequent fail cases work. + credz.RotateTrustedUserCA(t, dut, "") + + // Clear hiba for authorized principals command. + credz.RotateAuthorizedPrincipalCheck(t, dut, cpb.AuthorizedPrincipalCheckRequest_TOOL_UNSPECIFIED) + + // Remove host artifacts from the dut. + credz.RotateAuthenticationArtifacts(t, dut, "", "", "", 0) + }) +} diff --git a/feature/security/gnsi/credentialz/tests/hiba_authentication/metadata.textproto b/feature/security/gnsi/credentialz/tests/hiba_authentication/metadata.textproto new file mode 100644 index 00000000000..d27061b81a2 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/hiba_authentication/metadata.textproto @@ -0,0 +1,15 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "4083a01e-9b52-44c0-aa5c-994e78be66fe" +plan_id: "Credentialz-5" +description: "Hiba Authentication" +testbed: TESTBED_DUT +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + ssh_server_counters_unsupported: true + } +} diff --git a/feature/security/gnsi/credentialz/tests/host_certificates/README.md b/feature/security/gnsi/credentialz/tests/host_certificates/README.md new file mode 100644 index 00000000000..de9e92bb424 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/host_certificates/README.md @@ -0,0 +1,45 @@ +# Credentialz-3: Host Certificates + +## Summary + +Test that Credentialz can properly fetch and push SSH host certificates, and that the DUT sends +this certificate during SSH authentication. + + +## Procedure + +* Fetch the DUT's public key using gnsi.Credentialz + * If DUT doesnt have one, generate and set the private key using gnsi.Credentialz. +* Sign the DUT's public key with the ca key to create a host certificate. +* Add the newly created certificate to the DUT using gnsi.Credentialz +* Perform the following tests and assert the expected result: + * Case 1: Success + * SSH to the device and assert that the host key returned is the host key that was + pushed in the test set up + * Ensure telemetry values for version and created-on match the values set by + RotateHostParameters for + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:active-host-certificate-version` + and + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:active-host-certificate-created-on` + + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## State Paths ## + /system/ssh-server/state/active-host-certificate-version: + /system/ssh-server/state/active-host-certificate-created-on: + +rpcs: + gnsi: + credentialz.v1.Credentialz.GetPublicKeys: + credentialz.v1.Credentialz.RotateHostParameters: +``` + + +## Minimum DUT platform requirement + +N/A \ No newline at end of file diff --git a/feature/security/gnsi/credentialz/tests/host_certificates/host_certificates_test.go b/feature/security/gnsi/credentialz/tests/host_certificates/host_certificates_test.go new file mode 100644 index 00000000000..f728ae0f531 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/host_certificates/host_certificates_test.go @@ -0,0 +1,116 @@ +// Copyright 2024 Google LLC +// +// 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. + +package hostcertificates_test + +import ( + "fmt" + "net" + "os" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/openconfig/ondatra/gnmi" + + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/security/credz" + "github.com/openconfig/ondatra" + "golang.org/x/crypto/ssh" +) + +const ( + hostCertificateVersion = "v1.0" +) + +var ( + hostCertificateCreatedOn = time.Now().Unix() +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestCredentialz(t *testing.T) { + dut := ondatra.DUT(t, "dut") + target := credz.GetDutTarget(t, dut) + + // Create temporary directory for storing ssh keys/certificates. + dir, err := os.MkdirTemp("", "") + if err != nil { + t.Fatalf("Creating temp dir, err: %s", err) + } + defer func(dir string) { + err = os.RemoveAll(dir) + if err != nil { + t.Logf("Error removing temp directory, error: %s", err) + } + }(dir) + + // Create ssh keys/certificates for CA & host. + credz.CreateSSHKeyPair(t, dir, "ca") + credz.CreateSSHKeyPair(t, dir, "dut") + + credz.RotateAuthenticationArtifacts(t, dut, dir, "", hostCertificateVersion, uint64(hostCertificateCreatedOn)) + dutKey := credz.GetDutPublicKey(t, dut) + credz.CreateHostCertificate(t, dir, dutKey) + credz.RotateAuthenticationArtifacts(t, dut, "", dir, hostCertificateVersion, uint64(hostCertificateCreatedOn)) + + t.Run("dut should return signed host certificate", func(t *testing.T) { + certificateContents, err := os.ReadFile(fmt.Sprintf("%s/dut-cert.pub", dir)) + if err != nil { + t.Fatalf("Failed reading host signed certificate, error: %s", err) + } + wantHostKey, _, _, _, err := ssh.ParseAuthorizedKey(certificateContents) + if err != nil { + t.Fatalf("Failed parsing host certificate authorized (cert)key: %s", err) + } + + // Verify correct host certificate is returned by the dut. + _, err = ssh.Dial( + "tcp", + target, + &ssh.ClientConfig{ + User: "admin", + Auth: []ssh.AuthMethod{}, + HostKeyCallback: func(hostname string, remote net.Addr, gotHostKey ssh.PublicKey) error { + if !cmp.Equal(gotHostKey, wantHostKey) { + t.Fatalf("Host presented key (cert) that does not match expected host certificate. got: %v, want: %v", gotHostKey, wantHostKey) + } + return nil + }, + }, + ) + if err == nil { + t.Fatal("Dial ssh succeeded, but we expected failure.") + } + + // Verify host certificate telemetry values. + sshServer := gnmi.Get(t, dut, gnmi.OC().System().SshServer().State()) + gotHostCertificateVersion := sshServer.GetActiveHostCertificateVersion() + if !cmp.Equal(gotHostCertificateVersion, hostCertificateVersion) { + t.Fatalf( + "Telemetry reports host certificate version is not correct\n\tgot: %s\n\twant: %s", + gotHostCertificateVersion, hostCertificateVersion, + ) + } + gotHostCertificateCreatedOn := sshServer.GetActiveHostCertificateCreatedOn() + if !cmp.Equal(time.Unix(0, int64(gotHostCertificateCreatedOn)), time.Unix(hostCertificateCreatedOn, 0)) { + t.Fatalf( + "Telemetry reports host certificate created on is not correct\n\tgot: %d\n\twant: %d", + gotHostCertificateCreatedOn, hostCertificateCreatedOn, + ) + } + }) +} diff --git a/feature/security/gnsi/credentialz/tests/host_certificates/metadata.textproto b/feature/security/gnsi/credentialz/tests/host_certificates/metadata.textproto new file mode 100644 index 00000000000..b0cbb9220fc --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/host_certificates/metadata.textproto @@ -0,0 +1,7 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "91120b0a-91ea-493c-8046-f52176ec2029" +plan_id: "Credentialz-3" +description: "Host Certificates" +testbed: TESTBED_DUT diff --git a/feature/security/gnsi/credentialz/tests/password_console_login/README.md b/feature/security/gnsi/credentialz/tests/password_console_login/README.md new file mode 100644 index 00000000000..312968bb057 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/password_console_login/README.md @@ -0,0 +1,40 @@ +# Credentialz-1: Password console login + +## Summary + +Test that Credentialz properly creates users and the associated password and that the DUT handles +authentication of those users properly. + + +## Procedure + +* Set a username of `testuser` with a password having following restrictions: + * Must be 24-32 characters long. + * Must use 4 of the 5 character classes ([a-z], [A-Z], [0-9], [!@#$%^&*(){}[]\|:;'"], [ ]). +* Perform the following tests and assert the expected result: + * Case 1: Success + * Authenticate with the `testuser` username and password created in the first step above. + * Authentication must result in success with a prompt. + * Case 2: Failure + * Authenticate with the `testuser` username and an *incorrect* password of `password` + * Assert that authentication has failed + * Case 3: Failure + * Authenticate with the invalid username `username` and a valid (for a different username) + password created in the first step above. + * Assert that authentication has failed + + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +rpcs: + gnsi: + credentialz.v1.Credentialz.RotateAccountCredentials: +``` + + +## Minimum DUT platform requirement + +N/A diff --git a/feature/security/gnsi/credentialz/tests/password_console_login/metadata.textproto b/feature/security/gnsi/credentialz/tests/password_console_login/metadata.textproto new file mode 100644 index 00000000000..790ee493aec --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/password_console_login/metadata.textproto @@ -0,0 +1,7 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "902e381c-8196-436e-8f5b-f945e57ff855" +plan_id: "Credentialz-1" +description: "Password console login" +testbed: TESTBED_DUT diff --git a/feature/security/gnsi/credentialz/tests/password_console_login/password_console_login_test.go b/feature/security/gnsi/credentialz/tests/password_console_login/password_console_login_test.go new file mode 100644 index 00000000000..97ac39b3c94 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/password_console_login/password_console_login_test.go @@ -0,0 +1,110 @@ +// Copyright 2024 Google LLC +// +// 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. + +package passwordconsolelogin_test + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/openconfig/ondatra/gnmi" + + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/security/credz" + "github.com/openconfig/ondatra" +) + +const ( + username = "testuser" + passwordVersion = "v1.0" +) + +var ( + passwordCreatedOn = time.Now().Unix() +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestCredentialz(t *testing.T) { + dut := ondatra.DUT(t, "dut") + target := credz.GetDutTarget(t, dut) + + // Setup test user and password. + credz.SetupUser(t, dut, username) + password := credz.GeneratePassword() + credz.RotateUserPassword(t, dut, username, password, passwordVersion, uint64(passwordCreatedOn)) + + testCases := []struct { + name string + loginUser string + loginPassword string + expectFail bool + }{ + { + name: "auth should succeed", + loginUser: username, + loginPassword: password, + expectFail: false, + }, + { + name: "auth should fail bad username", + loginUser: "notadmin", + loginPassword: password, + expectFail: true, + }, + { + name: "auth should fail bad password", + loginUser: username, + loginPassword: "notthepassword", + expectFail: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Verify ssh succeeds/fails based on expected result. + client, err := credz.SSHWithPassword(target, tc.loginUser, tc.loginPassword) + if tc.expectFail { + if err == nil { + t.Fatalf("Dialing ssh succeeded, but we expected to fail.") + } + return + } + if err != nil { + t.Fatalf("Failed dialing ssh, error: %s", err) + } + defer client.Close() + + // Verify password telemetry. + userState := gnmi.Get(t, dut, gnmi.OC().System().Aaa().Authentication().User(username).State()) + gotPasswordVersion := userState.GetPasswordVersion() + if !cmp.Equal(gotPasswordVersion, passwordVersion) { + t.Fatalf( + "Telemetry reports password version is not correctn\tgot: %s\n\twant: %s", + gotPasswordVersion, passwordVersion, + ) + } + gotPasswordCreatedOn := userState.GetPasswordCreatedOn() + if !cmp.Equal(time.Unix(0, int64(gotPasswordCreatedOn)), time.Unix(passwordCreatedOn, 0)) { + t.Fatalf( + "Telemetry reports password created on is not correct\n\tgot: %d\n\twant: %d", + gotPasswordCreatedOn, passwordCreatedOn, + ) + } + }) + } +} diff --git a/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/README.md b/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/README.md new file mode 100644 index 00000000000..b594291d517 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/README.md @@ -0,0 +1,71 @@ +# Credentialz-2: SSH Password Login Disallowed + +## Summary + +Test that Credentialz properly disallows password based SSH authentication when configured to do +so, furthermore, ensure that certificate based SSH authentication is allowed, and properly +accounted for. + + +## Procedure + +* Create a ssh CA keypair with `ssh-keygen -f /tmp/ca` +* Create a user keypair with `ssh-keygen -t ed25519` +* Sign the user public key into a certificate using the CA using `ssh-keygen -s + /tmp/ca -I testuser -n principal_name -V +52w user.pub`. You will + find your certificate ending in `-cert.pub` +* Set DUT TrustedUserCAKeys using gnsi.Credentialz with the CA public key +* Set a username of `testuser` with a password having following restrictions: + * Must be 24-32 characters long. + * Must use 4 of the 5 character classes ([a-z], [A-Z], [0-9], [!@#$%^&*(){}[]\|:;'"], [ ]). +* Set DUT authentication types to permit only public key (PUBKEY) using gnsi.Credentialz +* Set DUT authorized_users for `testuser` with a principal of `my_principal` (configured above + when signing public key) +* Perform the following tests and assert the expected result: + * Case 1: Failure + * Authenticate with the `testuser` username and password created above + via SSH + * Assert that authentication has failed + * Ensure that access failure telemetry counters are incremented + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-rejects` + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:last-access-reject` + * Case 2: Success + * Authenticate with the `testuser` username and password created above + via console + * Assert that authentication has been successful (password authentication was only + disallowed for SSH) + * Ensure that access accept telemetry counters are incremented + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-accepts` + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:last-access-accept` + * Case 3: Success + * Authenticate with the `testuser` and certificate created above + * Assert that authentication has been successful + * Assert that gnsi accounting recorded the principal (`my_principal`) from the + certificate rather than the SSH username (`testuser`) + * Ensure that access accept telemetry counters are incremented + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-accepts` + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:last-access-accept` + + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## State Paths ## + /system/ssh-server/state/counters/access-rejects: + /system/ssh-server/state/counters/last-access-reject: + /system/ssh-server/state/counters/access-accepts: + /system/ssh-server/state/counters/last-access-accept: + +rpcs: + gnsi: + credentialz.v1.Credentialz.RotateAccountCredentials: + credentialz.v1.Credentialz.RotateHostParameters: +``` + + +## Minimum DUT platform requirement + +N/A \ No newline at end of file diff --git a/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/metadata.textproto b/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/metadata.textproto new file mode 100644 index 00000000000..afd3a143542 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/metadata.textproto @@ -0,0 +1,16 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "4632f134-71e6-46a2-ac2a-b1ff6a3444e6" +plan_id: "Credentialz-2" +description: "SSH Password Login Disallowed" +testbed: TESTBED_DUT + +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + ssh_server_counters_unsupported: true + } +} \ No newline at end of file diff --git a/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/ssh_password_login_disallowed_test.go b/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/ssh_password_login_disallowed_test.go new file mode 100644 index 00000000000..f2cd77e93e3 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/ssh_password_login_disallowed/ssh_password_login_disallowed_test.go @@ -0,0 +1,188 @@ +// Copyright 2024 Google LLC +// +// 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. + +package sshpasswordlogindisallowed_test + +import ( + "context" + "os" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "testing" + "time" + + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/security/credz" + acctzpb "github.com/openconfig/gnsi/acctz" + cpb "github.com/openconfig/gnsi/credentialz" + "github.com/openconfig/ondatra" +) + +const ( + username = "testuser" + userPrincipal = "my_principal" + command = "show version" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestCredentialz(t *testing.T) { + dut := ondatra.DUT(t, "dut") + target := credz.GetDutTarget(t, dut) + recordStartTime := timestamppb.New(time.Now()) + + // Create temporary directory for storing ssh keys/certificates. + dir, err := os.MkdirTemp("", "") + if err != nil { + t.Fatalf("Creating temp dir, err: %s", err) + } + defer func(dir string) { + err = os.RemoveAll(dir) + if err != nil { + t.Logf("Error removing temp directory, error: %s", err) + } + }(dir) + + // Create ssh keys/certificates for CA & testuser. + credz.CreateSSHKeyPair(t, dir, "ca") + credz.CreateSSHKeyPair(t, dir, username) + credz.CreateUserCertificate(t, dir, userPrincipal) + + // Setup user and password. + credz.SetupUser(t, dut, username) + password := credz.GeneratePassword() + credz.RotateUserPassword(t, dut, username, password, "v1.0", uint64(time.Now().Unix())) + + credz.RotateTrustedUserCA(t, dut, dir) + credz.RotateAuthenticationTypes(t, dut, []cpb.AuthenticationType{ + cpb.AuthenticationType_AUTHENTICATION_TYPE_PUBKEY, + }) + credz.RotateAuthorizedPrincipal(t, dut, username, userPrincipal) + + t.Run("auth should fail ssh password authentication disallowed", func(t *testing.T) { + var startingRejectCounter, startingLastRejectTime uint64 + if !deviations.SSHServerCountersUnsupported(dut) { + startingRejectCounter, startingLastRejectTime = credz.GetRejectTelemetry(t, dut) + } + + // Verify ssh with password fails as expected. + _, err := credz.SSHWithPassword(target, username, password) + if err == nil { + t.Fatalf("Dialing ssh succeeded, but we expected to fail.") + } + + // Verify ssh counters. + if !deviations.SSHServerCountersUnsupported(dut) { + endingRejectCounter, endingLastRejectTime := credz.GetRejectTelemetry(t, dut) + if endingRejectCounter <= startingRejectCounter { + t.Fatalf("SSH server reject counter did not increment after unsuccessful login. startCounter: %v, endCounter: %v", startingRejectCounter, endingRejectCounter) + } + if startingLastRejectTime == endingLastRejectTime { + t.Fatalf("SSH server reject last timestamp did not update after unsuccessful login. Timestamp: %v", endingLastRejectTime) + } + } + }) + + t.Run("auth should succeed ssh certificate authentication allowed", func(t *testing.T) { + var startingAcceptCounter, startingLastAcceptTime uint64 + if !deviations.SSHServerCountersUnsupported(dut) { + startingAcceptCounter, startingLastAcceptTime = credz.GetAcceptTelemetry(t, dut) + } + + // Verify ssh with certificate succeeds. + conn, err := credz.SSHWithCertificate(t, target, username, dir) + if err != nil { + t.Fatalf("Dialing ssh failed, but we expected to succeed, error: %s", err) + } + defer conn.Close() + + // Send command for accounting. + sess, err := conn.NewSession() + if err != nil { + t.Fatalf("Failed creating ssh session, error: %s", err) + } + defer sess.Close() + sess.Run(command) + + // Verify ssh counters. + if !deviations.SSHServerCountersUnsupported(dut) { + endingAcceptCounter, endingLastAcceptTime := credz.GetAcceptTelemetry(t, dut) + if endingAcceptCounter <= startingAcceptCounter { + t.Fatalf("SSH server accept counter did not increment after successful login. startCounter: %v, endCounter: %v", startingAcceptCounter, endingAcceptCounter) + } + if startingLastAcceptTime == endingLastAcceptTime { + t.Fatalf("SSH server accept last timestamp did not update after successful login. Timestamp: %v", endingLastAcceptTime) + } + } + + // Verify accounting record. + acctzClient := dut.RawAPIs().GNSI(t).AcctzStream() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + acctzSubClient, err := acctzClient.RecordSubscribe(ctx, &acctzpb.RecordRequest{Timestamp: recordStartTime}) + if err != nil { + t.Fatalf("Failed sending accountz record request, error: %s", err) + } + defer acctzSubClient.CloseSend() + + var foundRecord bool + for { + acctzResponse, err := acctzSubClient.Recv() + if err != nil { + if status.Code(err) == codes.DeadlineExceeded { + t.Log("Done receiving records...") + break + } + t.Fatalf( + "Failed receiving from accountz record subscribe client, "+ + "this could mean we didn't find the user identity and eventually timed "+ + "out with no more records to review, or another server error. Error: %s", + err, + ) + } + + // Skip non-ssh records. + if acctzResponse.GetCmdService() == nil { + continue + } + + reportedIdentity := acctzResponse.GetSessionInfo().GetUser().GetIdentity() + if reportedIdentity == username { + t.Logf("Found Record: %s", credz.PrettyPrint(acctzResponse)) + foundRecord = true + break + } + } + if !foundRecord { + t.Fatalf("Did not find accounting record for %s", username) + } + }) + + t.Cleanup(func() { + // Cleanup to remove previous policy which only allowed key auth to make sure we don't + // leave dut in a state where we can't reset config for further tests. + credz.RotateAuthenticationTypes(t, dut, []cpb.AuthenticationType{ + cpb.AuthenticationType_AUTHENTICATION_TYPE_PASSWORD, + cpb.AuthenticationType_AUTHENTICATION_TYPE_PUBKEY, + cpb.AuthenticationType_AUTHENTICATION_TYPE_KBDINTERACTIVE, + }) + }) +} diff --git a/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/README.md b/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/README.md new file mode 100644 index 00000000000..fe13bbdb82f --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/README.md @@ -0,0 +1,52 @@ +# Credentialz-4: SSH Public Key Authentication + +## Summary + +Test that Credentialz properly configures authorized SSH public keys for a given user, and that +the DUT properly allows or disallows authentication based on the configured settings. + + +## Procedure + +* Create a user ssh keypair with `ssh-keygen` +* Set a username of `testuser` +* Perform the following tests and assert the expected result: + * Case 1: Failure + * Attempt to ssh into the server with the `testuser` username, presenting the ssh key. + * Assert that authentication has failed (because the key is not authorized) + * Case 2: Success + * Configure the previously created ssh public key as an authorized key for the + `testuser` using gnsi.Credentialz/AuthorizedKeysRequest + * Authenticate with the `testuser` username and the previously created public key via SSH + * Assert that authentication has been successful + * Ensure telemetry values for version and created-on match the values set by + RotateHostParameters for + `/oc-sys:system/oc-sys:aaa/oc-sys:authentication/oc-sys:users/oc-sys:user/oc-sys:state:authorized-keys-list-version` + and + `/oc-sys:system/oc-sys:aaa/oc-sys:authentication/oc-sys:users/oc-sys:user/oc-sys:state:authorized-keys-list-created-on` + * Ensure that access accept telemetry counters are incremented + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-accepts` + `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:last-access-accept` + + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## State Paths ## + /system/aaa/authentication/users/user/state/authorized-keys-list-version: + /system/aaa/authentication/users/user/state/authorized-keys-list-created-on: + /system/ssh-server/state/counters/access-accepts: + /system/ssh-server/state/counters/last-access-accept: + +rpcs: + gnsi: + credentialz.v1.Credentialz.RotateAccountCredentials: +``` + + +## Minimum DUT platform requirement + +N/A \ No newline at end of file diff --git a/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/metadata.textproto b/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/metadata.textproto new file mode 100644 index 00000000000..3281da1a9d9 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/metadata.textproto @@ -0,0 +1,16 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "3e6294aa-8f9d-4c8d-9041-4a2f4cd84c36" +plan_id: "Credentialz-4" +description: "SSH Public Key Authentication" +testbed: TESTBED_DUT + +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + ssh_server_counters_unsupported: true + } +} \ No newline at end of file diff --git a/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/ssh_public_key_authentication_test.go b/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/ssh_public_key_authentication_test.go new file mode 100644 index 00000000000..de5530d7b20 --- /dev/null +++ b/feature/security/gnsi/credentialz/tests/ssh_public_key_authentication/ssh_public_key_authentication_test.go @@ -0,0 +1,123 @@ +// Copyright 2024 Google LLC +// +// 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. + +package sshpublickeyauthentication_test + +import ( + "os" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/openconfig/featureprofiles/internal/security/credz" + + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" +) + +const ( + username = "testuser" + authorizedKeysListVersion = "v1.0" +) + +var ( + authorizedKeysListCreatedOn = time.Now().Unix() +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestCredentialz(t *testing.T) { + dut := ondatra.DUT(t, "dut") + target := credz.GetDutTarget(t, dut) + + // Create temporary directory for storing ssh keys/certificates. + dir, err := os.MkdirTemp("", "") + if err != nil { + t.Fatalf("Creating temp dir, err: %s", err) + } + defer func(dir string) { + err = os.RemoveAll(dir) + if err != nil { + t.Logf("Error removing temp directory, error: %s", err) + } + }(dir) + + credz.CreateSSHKeyPair(t, dir, username) + credz.SetupUser(t, dut, username) + + t.Run("auth should fail ssh public key not authorized for user", func(t *testing.T) { + _, err := credz.SSHWithKey(t, target, username, dir) + if err == nil { + t.Fatalf("Dialing ssh succeeded, but we expected to fail.") + } + }) + + t.Run("auth should succeed ssh public key authorized for user", func(t *testing.T) { + // Push authorized key to the dut. + credz.RotateAuthorizedKey(t, + dut, + dir, + username, + authorizedKeysListVersion, + uint64(authorizedKeysListCreatedOn)) + + var startingAcceptCounter, startingLastAcceptTime uint64 + if !deviations.SSHServerCountersUnsupported(dut) { + startingAcceptCounter, startingLastAcceptTime = credz.GetAcceptTelemetry(t, dut) + } + + // Verify ssh with key succeeds. + _, err := credz.SSHWithKey(t, target, username, dir) + if err != nil { + t.Fatalf("Dialing ssh failed, but we expected to succeed. error: %v", err) + } + + // Verify ssh counters. + if !deviations.SSHServerCountersUnsupported(dut) { + endingAcceptCounter, endingLastAcceptTime := credz.GetAcceptTelemetry(t, dut) + if endingAcceptCounter <= startingAcceptCounter { + t.Fatalf("SSH server accept counter did not increment after successful login. startCounter: %v, endCounter: %v", startingAcceptCounter, endingAcceptCounter) + } + if startingLastAcceptTime == endingLastAcceptTime { + t.Fatalf("SSH server accept last timestamp did not update after successful login. Timestamp: %v", endingLastAcceptTime) + } + } + + // Verify authorized keys telemetry. + userState := gnmi.Get(t, dut, gnmi.OC().System().Aaa().Authentication().User(username).State()) + gotAuthorizedKeysListVersion := userState.GetAuthorizedKeysListVersion() + if !cmp.Equal(gotAuthorizedKeysListVersion, authorizedKeysListVersion) { + t.Fatalf( + "Telemetry reports authorized keys list version is not correct\n\tgot: %s\n\twant: %s", + gotAuthorizedKeysListVersion, authorizedKeysListVersion, + ) + } + gotAuthorizedKeysListCreatedOn := userState.GetAuthorizedKeysListCreatedOn() + if !cmp.Equal(time.Unix(0, int64(gotAuthorizedKeysListCreatedOn)), time.Unix(authorizedKeysListCreatedOn, 0)) { + t.Fatalf( + "Telemetry reports authorized keys list version on is not correct\n\tgot: %d\n\twant: %d", + gotAuthorizedKeysListCreatedOn, authorizedKeysListCreatedOn, + ) + } + }) + + t.Cleanup(func() { + // Cleanup user authorized key after test. + credz.RotateAuthorizedKey(t, dut, "", username, "", 0) + }) +} diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/README.md b/feature/staticroute/otg_tests/basic_static_route_support_test/README.md index a50aa04c701..1127cffe981 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/README.md +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/README.md @@ -16,8 +16,8 @@ #### Initial Setup: -* Connect DUT port-1, port-2 and port-3 to ATE port-1, port-2 and port-3 - respectively +* Connect DUT port-1, port-2, port-3 and port-4 to ATE port-1, port-2, port-3 + and port-4 respectively * Configure IPv4/IPv6 addresses on DUT and ATE the interfaces * Configure one IPv4 destination i.e. `ipv4-network = 203.0.113.0/24` connected to ATE port 1 and 2 @@ -177,9 +177,24 @@ 203.0.113.0/24` and `ipv6-network 2001:db8:128:128::/64` * Validate that traffic is NOT received from DUT +### RT-1.26.9 + +#### Test to validate add and remove to next-hops in a static route + +* Configure one IPv4 static route i.e. ipv4-route with the next hop set to the + IPv4 address of ATE port-2(0 index) and port-3(1 index). +* Validate next-hops of `ipv4-route` static route and indexes. +* Update IPv4 static route i.e. ipv4-route with the next hop set to the IPv4 + address of ATE port-1(0 index), port-2(1 index), port-3(2 index) and + port-4(3 index). +* Validate next-hops of `ipv4-route` static route and indexes. +* Remove two next hops at index 0 and 3 added in previous step. +* Validate next-hops of `ipv4-route` static route and indexes. + ## OpenConfig Path and RPC Coverage -The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. ```yaml paths: diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go b/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go index fbfd8da98ef..f5defe9452d 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go @@ -44,8 +44,8 @@ const ( trafficDuration = 2 * time.Minute lossTolerance = float64(1) ecmpTolerance = uint64(2) - port1Tag = "0x101" - port2Tag = "0x102" + port1Tag = "0x01" + port2Tag = "0x02" dummyV6 = "2001:db8::192:0:2:d" dummyMAC = "00:1A:11:00:0A:BC" explicitMetricTolerance = float64(2) @@ -102,6 +102,23 @@ var ( IPv6: "2001:db8::192:0:2:a", IPv6Len: ipv6PrefixLen, } + + dutPort4 = attrs.Attributes{ + Desc: "dutPort4", + IPv4: "192.0.2.13", + IPv4Len: ipv4PrefixLen, + IPv6: "2001:db8::192:0:2:d", + IPv6Len: ipv6PrefixLen, + } + + atePort4 = attrs.Attributes{ + Name: "atePort4", + MAC: "02:00:01:01:01:04", + IPv4: "192.0.2.14", + IPv4Len: ipv4PrefixLen, + IPv6: "2001:db8::192:0:2:e", + IPv6Len: ipv6PrefixLen, + } ) func TestMain(m *testing.M) { @@ -209,6 +226,92 @@ func TestBasicStaticRouteSupport(t *testing.T) { } } +func TestStaticRouteAddRemove(t *testing.T) { + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + + ate := ondatra.ATE(t, "ate") + top := gosnappi.NewConfig() + configureOTG(t, ate, top) + + ate.OTG().PushConfig(t, top) + ate.OTG().StartProtocols(t) + defer ate.OTG().StopProtocols(t) + otgutils.WaitForARP(t, ate.OTG(), top, "IPv4") + + prefix := ipAddr{address: v4Route, prefix: v4RoutePrefix} + b := &gnmi.SetBatch{} + sV4 := &cfgplugins.StaticRouteCfg{ + NetworkInstance: deviations.DefaultNetworkInstance(dut), + Prefix: prefix.cidr(t), + NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ + "0": oc.UnionString(atePort2.IPv4), + "1": oc.UnionString(atePort3.IPv4), + }, + } + if _, err := cfgplugins.NewStaticRouteCfg(b, sV4, dut); err != nil { + t.Fatalf("Failed to configure IPv4 static route: %v", err) + } + b.Set(t, dut) + validateStaticRoute(t, dut, prefix.cidr(t), sV4) + + // add 2 new nextHops, one at 0 index and another at 3 index + b = &gnmi.SetBatch{} + sV4 = &cfgplugins.StaticRouteCfg{ + NetworkInstance: deviations.DefaultNetworkInstance(dut), + Prefix: prefix.cidr(t), + NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ + "0": oc.UnionString(atePort1.IPv4), + "1": oc.UnionString(atePort2.IPv4), + "2": oc.UnionString(atePort3.IPv4), + "3": oc.UnionString(atePort4.IPv4), + }, + } + if _, err := cfgplugins.NewStaticRouteCfg(b, sV4, dut); err != nil { + t.Fatalf("Failed to configure IPv4 static route: %v", err) + } + b.Set(t, dut) + validateStaticRoute(t, dut, prefix.cidr(t), sV4) + + // remove previously added indexes + b = &gnmi.SetBatch{} + sV4 = &cfgplugins.StaticRouteCfg{ + NetworkInstance: deviations.DefaultNetworkInstance(dut), + Prefix: prefix.cidr(t), + NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ + "0": oc.UnionString(atePort2.IPv4), + "1": oc.UnionString(atePort3.IPv4), + }, + } + if _, err := cfgplugins.NewStaticRouteCfg(b, sV4, dut); err != nil { + t.Fatalf("Failed to configure IPv4 static route: %v", err) + } + b.Set(t, dut) + validateStaticRoute(t, dut, prefix.cidr(t), sV4) +} + +func validateStaticRoute(t *testing.T, dut *ondatra.DUTDevice, prefix string, sV4 *cfgplugins.StaticRouteCfg) { + sp := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_STATIC, deviations.StaticProtocolName(dut)) + gnmi.Await(t, dut, sp.Static(prefix).Prefix().State(), 120*time.Second, prefix) + + if deviations.SkipStaticNexthopCheck(dut) { + nexthops := gnmi.LookupAll(t, dut, sp.Static(prefix).NextHopAny().NextHop().State()) + if got, want := len(nexthops), len(sV4.NextHops); got != want { + t.Errorf("Static route next hop count - %s: got: %v, want: %v", prefix, got, want) + } + } else { + // Validate both the routes i.e. ipv4-route-[a|b] are configured and reported + // correctly + gotStatic := gnmi.Get(t, dut, sp.Static(prefix).State()) + t.Logf("Static route %s: got: %v, want: %v", prefix, len(gotStatic.NextHop), len(sV4.NextHops)) + for index, nextHop := range gotStatic.NextHop { + if got, want := nextHop.GetNextHop(), sV4.NextHops[index]; got != want { + t.Errorf("Static route %s: got: %v, want: %v", prefix, got, want) + } + } + } +} + func TestDisableRecursiveNextHopResolution(t *testing.T) { dut := ondatra.DUT(t, "dut") if deviations.UnsupportedStaticRouteNextHopRecurse(dut) { @@ -1162,7 +1265,7 @@ func (td *testData) configureOTGFlows(t *testing.T) { eth := v4F.EgressPacket().Add().Ethernet() ethTag := eth.Dst().MetricTags().Add() - ethTag.SetName("MACTrackingv4").SetOffset(36).SetLength(12) + ethTag.SetName("MACTrackingv4").SetOffset(40).SetLength(8) v6F := td.top.Flows().Add() v6F.SetName(v6Flow).Metrics().SetEnable(true) @@ -1181,7 +1284,7 @@ func (td *testData) configureOTGFlows(t *testing.T) { eth = v6F.EgressPacket().Add().Ethernet() ethTag = eth.Dst().MetricTags().Add() - ethTag.SetName("MACTrackingv6").SetOffset(36).SetLength(12) + ethTag.SetName("MACTrackingv6").SetOffset(40).SetLength(8) } func (td *testData) awaitISISAdjacency(t *testing.T, p *ondatra.Port, isisName string) error { @@ -1208,23 +1311,29 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { p1 := dut.Port(t, "port1") p2 := dut.Port(t, "port2") p3 := dut.Port(t, "port3") + p4 := dut.Port(t, "port4") b := &gnmi.SetBatch{} i1 := dutPort1.NewOCInterface(p1.Name(), dut) i2 := dutPort2.NewOCInterface(p2.Name(), dut) i3 := dutPort3.NewOCInterface(p3.Name(), dut) + i4 := dutPort4.NewOCInterface(p4.Name(), dut) if deviations.IPv6StaticRouteWithIPv4NextHopRequiresStaticARP(dut) { i1.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) i2.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) + i3.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) + i4.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) } gnmi.BatchReplace(b, gnmi.OC().Interface(p1.Name()).Config(), i1) gnmi.BatchReplace(b, gnmi.OC().Interface(p2.Name()).Config(), i2) gnmi.BatchReplace(b, gnmi.OC().Interface(p3.Name()).Config(), i3) + gnmi.BatchReplace(b, gnmi.OC().Interface(p4.Name()).Config(), i4) b.Set(t, dut) if deviations.ExplicitPortSpeed(dut) { fptest.SetPortSpeed(t, p1) fptest.SetPortSpeed(t, p2) fptest.SetPortSpeed(t, p3) + fptest.SetPortSpeed(t, p4) } fptest.ConfigureDefaultNetworkInstance(t, dut) @@ -1233,6 +1342,7 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) fptest.AssignToNetworkInstance(t, dut, p3.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p4.Name(), deviations.DefaultNetworkInstance(dut), 0) } } @@ -1241,11 +1351,13 @@ func configureOTG(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config) []g p1 := ate.Port(t, "port1") p2 := ate.Port(t, "port2") p3 := ate.Port(t, "port3") + p4 := ate.Port(t, "port4") d1 := atePort1.AddToOTG(top, p1, &dutPort1) d2 := atePort2.AddToOTG(top, p2, &dutPort2) d3 := atePort3.AddToOTG(top, p3, &dutPort3) - return []gosnappi.Device{d1, d2, d3} + d4 := atePort4.AddToOTG(top, p4, &dutPort4) + return []gosnappi.Device{d1, d2, d3, d4} } func (td *testData) advertiseRoutesWithISIS(t *testing.T) { diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto b/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto index 34fb8af4eaf..af7f010bc52 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto @@ -36,7 +36,6 @@ platform_exceptions: { unsupported_static_route_next_hop_recurse: true static_route_with_explicit_metric: true interface_ref_config_unsupported: true - } } platform_exceptions: { diff --git a/feature/experimental/system/gnmi/benchmarking/internal/setup/setup.go b/feature/system/gnmi/benchmarking/internal/setup/setup.go similarity index 100% rename from feature/experimental/system/gnmi/benchmarking/internal/setup/setup.go rename to feature/system/gnmi/benchmarking/internal/setup/setup.go diff --git a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/README.md b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/README.md similarity index 59% rename from feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/README.md rename to feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/README.md index 80b76298f1e..43312a43c90 100644 --- a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/README.md +++ b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/README.md @@ -35,21 +35,24 @@ defined in the case): * Measure time between t=0 and all BGP received routes on ATE to report changed metric. -## Config Parameter coverage - - * BGP - * /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-med - * /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/repeat-n - * /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/as-number - - * ISIS - * /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric - * /network-instances/network-instance/protocols/protocol/isis/global/lsp-bit/overload-bit/state/set-bit - -## Telemetry Parameter coverage - - * ISIS - * /interfaces/interfaces/levels/level/adjacencies/adjacency/state/adjacency-state - * BGP - * /afi-safis/afi-safi/state/prefixes/sent - * /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + ## Config Parameter coverage + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-med: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/repeat-n: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-as-path-prepend/config/asn: + /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/levels/level/afi-safi/af/state/metric: + /network-instances/network-instance/protocols/protocol/isis/global/lsp-bit/overload-bit/state/set-bit: + + ## Telemetry Parameter coverage + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/state/prefixes/sent: +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` diff --git a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_bgp_test.go b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_bgp_test.go similarity index 99% rename from feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_bgp_test.go rename to feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_bgp_test.go index 3b12bc1d5e5..53bdf999d3f 100644 --- a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_bgp_test.go +++ b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_bgp_test.go @@ -21,7 +21,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/openconfig/featureprofiles/feature/experimental/system/gnmi/benchmarking/internal/setup" + "github.com/openconfig/featureprofiles/feature/system/gnmi/benchmarking/internal/setup" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/ondatra" diff --git a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_isis_test.go b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_isis_test.go similarity index 98% rename from feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_isis_test.go rename to feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_isis_test.go index e8bf2d5cfd2..fbdbba61792 100644 --- a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_isis_test.go +++ b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/drained_configuration_convergence_time_isis_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - "github.com/openconfig/featureprofiles/feature/experimental/system/gnmi/benchmarking/internal/setup" + "github.com/openconfig/featureprofiles/feature/system/gnmi/benchmarking/internal/setup" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" diff --git a/feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto similarity index 100% rename from feature/experimental/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto rename to feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto diff --git a/feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/README.md b/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/README.md similarity index 100% rename from feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/README.md rename to feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/README.md diff --git a/feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/full_configuration_replace_test.go b/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/full_configuration_replace_test.go similarity index 97% rename from feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/full_configuration_replace_test.go rename to feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/full_configuration_replace_test.go index e07d56bb4aa..03d8878c59e 100644 --- a/feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/full_configuration_replace_test.go +++ b/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/full_configuration_replace_test.go @@ -19,7 +19,7 @@ import ( "testing" "time" - "github.com/openconfig/featureprofiles/feature/experimental/system/gnmi/benchmarking/internal/setup" + "github.com/openconfig/featureprofiles/feature/system/gnmi/benchmarking/internal/setup" "github.com/openconfig/featureprofiles/internal/args" "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" diff --git a/feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto b/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto similarity index 100% rename from feature/experimental/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto rename to feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto diff --git a/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md b/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md index 51ac7dab893..e0b5b2ba32b 100644 --- a/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md +++ b/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md @@ -40,3 +40,13 @@ dut.testbed ## Minimum DUT platform FFF + +## OpenConfig Path and RPC Coverage + +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Subscribe: + +``` \ No newline at end of file diff --git a/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go b/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go index 84b7e7af943..5dbc85b2572 100644 --- a/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go +++ b/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go @@ -49,57 +49,6 @@ func TestMain(m *testing.M) { fptest.RunTests(m) } -// getDeviceConfig gets a full config from a device but refurbishes it enough so it can be -// pushed out again -func getDeviceConfig(t testing.TB, dev gnmi.DeviceOrOpts) *oc.Root { - config := gnmi.Get[*oc.Root](t, dev, gnmi.OC().Config()) - fptest.WriteQuery(t, "Untouched", gnmi.OC().Config(), config) - - for cname, component := range config.Component { - // Keep the port components in order to preserve the breakout-mode config. - if component.GetPort() == nil { - delete(config.Component, cname) - continue - } - // Need to prune subcomponents that may have a leafref to a component that was - // pruned. - component.Subcomponent = nil - } - - for iname, iface := range config.Interface { - if iface.GetEthernet() == nil { - continue - } - // Ethernet config may not contain meaningful values if it wasn't explicitly - // configured, so use its current state for the config, but prune non-config leaves. - intf := gnmi.Get(t, dev, gnmi.OC().Interface(iname).State()) - breakout := config.GetComponent(intf.GetHardwarePort()).GetPort().GetBreakoutMode() - e := intf.GetEthernet() - // Set port speed to unknown for non breakout interfaces - if breakout.GetGroup(1) == nil && e != nil { - e.SetPortSpeed(oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN) - } - ygot.PruneConfigFalse(oc.SchemaTree["Interface_Ethernet"], e) - if e.PortSpeed != 0 && e.PortSpeed != oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN { - iface.Ethernet = e - } - } - - if config.Lldp != nil { - config.Lldp.ChassisId = nil - config.Lldp.ChassisIdType = oc.Lldp_ChassisIdType_UNSET - } - - config.Qos = nil - - for _, ni := range config.NetworkInstance { - ni.Fdb = nil - } - - fptest.WriteQuery(t, "Touched", gnmi.OC().Config(), config) - return config -} - // setEthernetFromBase merges the ethernet config from the interfaces in base config into // the destination config. func setEthernetFromBase(t testing.TB, config *oc.Root) { @@ -244,8 +193,7 @@ func checkMetadata1(t *testing.T, gnmiClient gpb.GNMIClient, dut *ondatra.DUTDev t.Helper() got, getRespTimeStamp := extractMetadataAnnotation(t, gnmiClient, dut) want := metadata1 - t.Logf("getResp: %v ", getRespTimeStamp) - if got != want && done.Load() == 0 { + if got != want && getRespTimeStamp < done.Load() { t.Errorf("extractMetadataAnnotation: got %v, want %v", got, want) } } @@ -268,13 +216,15 @@ func TestLargeSetConsistency(t *testing.T) { p1 := dut.Port(t, "port1") p2 := dut.Port(t, "port2") + fptest.ConfigureDefaultNetworkInstance(t, dut) + // Configuring basic interface and network instance as some devices only populate OC after configuration. gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) gnmi.Replace(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Type().Config(), oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_DEFAULT_INSTANCE) - baselineConfig := getDeviceConfig(t, dut) + baselineConfig := fptest.GetDeviceConfig(t, dut) setEthernetFromBase(t, baselineConfig) gnmiClient := dut.RawAPIs().GNMI(t) diff --git a/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto b/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto index cae8c3c1a46..c346a8d5da2 100644 --- a/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto +++ b/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto @@ -13,4 +13,12 @@ platform_exceptions: { default_network_instance: "default" } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + skip_macaddress_check: true + } +} diff --git a/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go b/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go index 8152a803887..d169ecec2f9 100644 --- a/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go +++ b/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go @@ -45,22 +45,8 @@ var ( skipContainerOp = flag.Bool("skip_container_op", false, "Skip ContainerOp test cases.") skipItemOp = flag.Bool("skip_item_op", false, "Skip ItemOp test cases.") - // The following experimental flags fine-tune the RootOp and ContainerOp behavior. Some - // devices require the config to be pruned for these to work. We are still undecided - // whether they should be deviations; pending OpenConfig clarifications. - pruneComponents = flag.Bool("prune_components", true, "Prune components that are not ports. Use this to preserve the breakout-mode settings.") - pruneLLDP = flag.Bool("prune_lldp", true, "Prune LLDP config.") - setEthernetFromState = flag.Bool("set_ethernet_from_state", true, "Set interface/ethernet config from state, mostly to get the port-speed settings correct.") - - // This has no known effect except to reduce logspam while debugging. - pruneQoS = flag.Bool("prune_qos", true, "Prune QoS config.") - // Experimental flags that will likely become a deviation. - cannotDeleteVRF = flag.Bool("cannot_delete_vrf", true, "Device cannot delete VRF.") // See "Note about cannotDeleteVRF" below. - cannotConfigurePortSpeed = flag.Bool("cannot_config_port_speed", false, "Some devices depending on the type of line card may not allow changing port speed, while still supporting the port speed leaf.") - - // Flags to ensure test passes without any dependency to the device config - baseOCConfigIsPresent = flag.Bool("base_oc_config_is_present", false, "No OC config is loaded on router, so Get config on the root returns no data.") + cannotDeleteVRF = flag.Bool("cannot_delete_vrf", true, "Device cannot delete VRF.") // See "Note about cannotDeleteVRF" below. ) var ( @@ -236,10 +222,6 @@ func TestReuseIP(t *testing.T) { forEachPushOp(t, dut, func(t *testing.T, op pushOp, config *oc.Root) { t.Log("Initialize") - if deviations.SkipMacaddressCheck(dut) { - *setEthernetFromState = false - } - config.DeleteInterface(p1.Name()) config.DeleteInterface(agg1) configMember(config.GetOrCreateInterface(p1.Name()), agg1, dut) @@ -840,7 +822,7 @@ func forEachPushOp( f func(t *testing.T, op pushOp, config *oc.Root), ) { baselineConfigOnce.Do(func() { - baselineConfig = getDeviceConfig(t, dut) + baselineConfig = fptest.GetDeviceConfig(t, dut) }) for _, op := range []pushOp{ @@ -850,154 +832,12 @@ func forEachPushOp( if op.shouldSkip() { t.Skip() } - o, err := ygot.DeepCopy(baselineConfig) - if err != nil { - t.Fatalf("Cannot copy baseConfig: %v", err) - } - config := o.(*oc.Root) + config := fptest.CopyDeviceConfig(t, dut, baselineConfig) f(t, op, config) }) } } -// getDeviceConfig gets a full config from a device but refurbishes it enough so it can be -// pushed out again. Ideally, we should be able to push the config we get from the same -// device without modification, but this is not explicitly defined in OpenConfig. -func getDeviceConfig(t testing.TB, dev gnmi.DeviceOrOpts) *oc.Root { - t.Helper() - - // Gets all the config (read-write) paths from root, not the state (read-only) paths. - config := gnmi.Get[*oc.Root](t, dev, gnmi.OC().Config()) - fptest.WriteQuery(t, "Untouched", gnmi.OC().Config(), config) - - // load the base oc config from the device state when no oc config is loaded - if !*baseOCConfigIsPresent { - if ondatra.DUT(t, "dut").Vendor() == ondatra.CISCO { - intfsState := gnmi.GetAll(t, dev, gnmi.OC().InterfaceAny().State()) - for _, intf := range intfsState { - ygot.PruneConfigFalse(oc.SchemaTree["Interface"], intf) - config.DeleteInterface(intf.GetName()) - if intf.GetName() == "Loopback0" || intf.GetName() == "PTP0/RP1/CPU0/0" || intf.GetName() == "Null0" || intf.GetName() == "PTP0/RP0/CPU0/0" { - continue - } - intf.ForwardingViable = nil - intf.Mtu = nil - intf.HoldTime = nil - if intf.Subinterface != nil { - if intf.Subinterface[0].Ipv6 != nil { - intf.Subinterface[0].Ipv6.Autoconf = nil - } - } - config.AppendInterface(intf) - } - vrfsStates := gnmi.GetAll(t, dev, gnmi.OC().NetworkInstanceAny().State()) - for _, vrf := range vrfsStates { - // only needed for containerOp - if vrf.GetName() == "**iid" { - continue - } - if vrf.GetName() == "DEFAULT" { - config.NetworkInstance = nil - vrf.Interface = nil - for _, ni := range config.NetworkInstance { - ni.Mpls = nil - } - } - ygot.PruneConfigFalse(oc.SchemaTree["NetworkInstance"], vrf) - vrf.Table = nil - vrf.RouteLimit = nil - vrf.Mpls = nil - for _, intf := range vrf.Interface { - intf.AssociatedAddressFamilies = nil - } - for _, protocol := range vrf.Protocol { - for _, routes := range protocol.Static { - routes.Description = nil - } - } - config.AppendNetworkInstance(vrf) - } - } - } - - if *pruneComponents { - for cname, component := range config.Component { - // Keep the port components in order to preserve the breakout-mode config. - if component.GetPort() == nil { - delete(config.Component, cname) - continue - } - // Need to prune subcomponents that may have a leafref to a component that was - // pruned. - component.Subcomponent = nil - } - } - - if *setEthernetFromState { - for iname, iface := range config.Interface { - if iface.GetEthernet() == nil { - continue - } - // Ethernet config may not contain meaningful values if it wasn't explicitly - // configured, so use its current state for the config, but prune non-config leaves. - intf := gnmi.Get(t, dev, gnmi.OC().Interface(iname).State()) - e := intf.GetEthernet() - if len(intf.GetHardwarePort()) != 0 { - breakout := config.GetComponent(intf.GetHardwarePort()).GetPort().GetBreakoutMode() - e := intf.GetEthernet() - // Set port speed to unknown for non breakout interfaces - if breakout.GetGroup(1) == nil && e != nil { - e.SetPortSpeed(oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN) - } - } - ygot.PruneConfigFalse(oc.SchemaTree["Interface_Ethernet"], e) - if e.PortSpeed != 0 && e.PortSpeed != oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN { - iface.Ethernet = e - } - // need to set mac address for mgmt interface to nil - if intf.GetName() == "MgmtEth0/RP0/CPU0/0" || intf.GetName() == "MgmtEth0/RP1/CPU0/0" && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { - e.MacAddress = nil - } - // need to set mac address for bundle interface to nil - if iface.Ethernet.AggregateId != nil && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { - iface.Ethernet.MacAddress = nil - continue - } - } - } - - if !*cannotConfigurePortSpeed { - for _, iface := range config.Interface { - if iface.GetEthernet() == nil { - continue - } - iface.GetEthernet().PortSpeed = oc.IfEthernet_ETHERNET_SPEED_UNSET - iface.GetEthernet().DuplexMode = oc.Ethernet_DuplexMode_UNSET - iface.GetEthernet().EnableFlowControl = nil - } - } - - if *pruneLLDP && config.Lldp != nil { - config.Lldp.ChassisId = nil - config.Lldp.ChassisIdType = oc.Lldp_ChassisIdType_UNSET - } - - if *pruneQoS { - config.Qos = nil - } - - pruneUnsupportedPaths(config) - - fptest.WriteQuery(t, "Touched", gnmi.OC().Config(), config) - return config -} - -func pruneUnsupportedPaths(config *oc.Root) { - for _, ni := range config.NetworkInstance { - ni.Fdb = nil - } -} - // pushScope describe the config scope that the test case wants to modify. This is for // itemOp only; rootOp and containerOp ignore this. type pushScope struct { @@ -1012,23 +852,6 @@ type pushOp interface { push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, scope *pushScope) } -// setEthernetFromBase merges the ethernet config from the interfaces in base config into -// the destination config. -func setEthernetFromBase(t testing.TB, base *oc.Root, config *oc.Root) { - t.Helper() - - for iname, iface := range config.Interface { - eb := base.GetInterface(iname).GetEthernet() - ec := iface.GetOrCreateEthernet() - if eb == nil || ec == nil { - continue - } - if err := ygot.MergeStructInto(ec, eb); err != nil { - t.Errorf("Cannot merge %s ethernet: %v", iname, err) - } - } -} - // rootOp pushes config using replace at root. type rootOp struct{ base *oc.Root } @@ -1037,9 +860,6 @@ func (rootOp) shouldSkip() bool { return *skipRootOp } func (op rootOp) push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, _ *pushScope) { t.Helper() - if *setEthernetFromState { - setEthernetFromBase(t, op.base, config) - } fptest.WriteQuery(t, "RootOp", gnmi.OC().Config(), config) dut := ondatra.DUT(t, "dut") if deviations.AddMissingBaseConfigViaCli(dut) { @@ -1060,9 +880,6 @@ func (containerOp) shouldSkip() bool { return *skipContainerOp } func (op containerOp) push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, _ *pushScope) { t.Helper() - if *setEthernetFromState { - setEthernetFromBase(t, op.base, config) - } fptest.WriteQuery(t, "ContainerOp", gnmi.OC().Config(), config) batch := &gnmi.SetBatch{} @@ -1095,9 +912,6 @@ func (itemOp) shouldSkip() bool { return *skipItemOp } func (op itemOp) push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, scope *pushScope) { t.Helper() - if *setEthernetFromState { - setEthernetFromBase(t, op.base, config) - } fptest.WriteQuery(t, "ItemOp", gnmi.OC().Config(), config) batch := &gnmi.SetBatch{} diff --git a/feature/experimental/system/health/tests/system_generic_health_check/README.md b/feature/system/health/tests/system_generic_health_check/README.md similarity index 100% rename from feature/experimental/system/health/tests/system_generic_health_check/README.md rename to feature/system/health/tests/system_generic_health_check/README.md diff --git a/feature/experimental/system/health/tests/system_generic_health_check/metadata.textproto b/feature/system/health/tests/system_generic_health_check/metadata.textproto similarity index 100% rename from feature/experimental/system/health/tests/system_generic_health_check/metadata.textproto rename to feature/system/health/tests/system_generic_health_check/metadata.textproto diff --git a/feature/experimental/system/health/tests/system_generic_health_check/system_generic_health_check_test.go b/feature/system/health/tests/system_generic_health_check/system_generic_health_check_test.go similarity index 100% rename from feature/experimental/system/health/tests/system_generic_health_check/system_generic_health_check_test.go rename to feature/system/health/tests/system_generic_health_check/system_generic_health_check_test.go diff --git a/feature/system/management/otg_tests/management_ha_test/management_ha_test.go b/feature/system/management/otg_tests/management_ha_test/management_ha_test.go index 9a92d63f2ce..7b5c3334703 100644 --- a/feature/system/management/otg_tests/management_ha_test/management_ha_test.go +++ b/feature/system/management/otg_tests/management_ha_test/management_ha_test.go @@ -183,9 +183,9 @@ func TestManagementHA1(t *testing.T) { }) t.Run("traffic received by port1", func(t *testing.T) { - createFlowV6(t, bs) gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().Config(), true) gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).AdminStatus().State(), 30*time.Second, oc.Interface_AdminStatus_UP) + createFlowV6(t, bs) time.Sleep(30 * time.Second) bs.ATE.OTG().StartTraffic(t) time.Sleep(30 * time.Second) diff --git a/feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/README.md b/feature/tunnel/otg_tests/tunnel_acl_based_test/README.md similarity index 66% rename from feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/README.md rename to feature/tunnel/otg_tests/tunnel_acl_based_test/README.md index 073bc96cac8..f7f4769287a 100644 --- a/feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/README.md +++ b/feature/tunnel/otg_tests/tunnel_acl_based_test/README.md @@ -14,10 +14,20 @@ Verify the DSCP value of original packet header after GRE acl based tunnel encap * verify dscp value of original packet after encapsulation. * verify that no traffic drops in all flows. -## Config Parameter coverage - -* /acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/config/set-name -* /acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/config/set-type +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. + +```yaml +paths: + /acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/config/set-name: + /acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/config/type: +rpcs: + gnmi: + gNMI.Subscribe: + gNMI.Set: +``` ## Validation coverage diff --git a/feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/metadata.textproto b/feature/tunnel/otg_tests/tunnel_acl_based_test/metadata.textproto similarity index 100% rename from feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/metadata.textproto rename to feature/tunnel/otg_tests/tunnel_acl_based_test/metadata.textproto diff --git a/feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/tun_acl_dscp_test.go b/feature/tunnel/otg_tests/tunnel_acl_based_test/tun_acl_dscp_test.go similarity index 100% rename from feature/experimental/tunnel/otg_tests/tunnel_acl_based_test/tun_acl_dscp_test.go rename to feature/tunnel/otg_tests/tunnel_acl_based_test/tun_acl_dscp_test.go diff --git a/feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/README.md b/feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/README.md similarity index 94% rename from feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/README.md rename to feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/README.md index 0bfc7dbe99f..076b0069e74 100644 --- a/feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/README.md +++ b/feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/README.md @@ -71,4 +71,13 @@ Validate Interface based Ipv6 GRE Tunnel Config. - state/counters/out-forwarded-pkts - state/counters/out-forwarded-octets - state/counters/out-discarded-pkt - - Fragmentation and assembly counters Filter counters Output to display the traffic is spread across the different tunnel subnet ranges/NH groups/Interfaces \ No newline at end of file + - Fragmentation and assembly counters Filter counters Output to display the traffic is spread across the different tunnel subnet ranges/NH groups/Interfaces + +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/metadata.textproto b/feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/metadata.textproto similarity index 100% rename from feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/metadata.textproto rename to feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/metadata.textproto diff --git a/feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/tunnel_interface_based_ipv6_gre_encapsulation_test.go b/feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/tunnel_interface_based_ipv6_gre_encapsulation_test.go similarity index 100% rename from feature/experimental/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/tunnel_interface_based_ipv6_gre_encapsulation_test.go rename to feature/tunnel/otg_tests/tunnel_interface_based_ipv6_gre_encapsulation_test/tunnel_interface_based_ipv6_gre_encapsulation_test.go diff --git a/feature/experimental/tunnel/otg_tests/tunnel_interface_based_resize_test/README.md b/feature/tunnel/otg_tests/tunnel_interface_based_resize_test/README.md similarity index 98% rename from feature/experimental/tunnel/otg_tests/tunnel_interface_based_resize_test/README.md rename to feature/tunnel/otg_tests/tunnel_interface_based_resize_test/README.md index 1bdd0384ace..24925300655 100644 --- a/feature/experimental/tunnel/otg_tests/tunnel_interface_based_resize_test/README.md +++ b/feature/tunnel/otg_tests/tunnel_interface_based_resize_test/README.md @@ -101,3 +101,12 @@ TODO: OpenConfig definition required for Tunnel protocol under interfaces/interf * state/counters/out-forwarded-pkts * state/counters/out-forwarded-octets * state/counters/out-discarded-pkts + +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` diff --git a/go.mod b/go.mod index c93984c9271..9965d7ca82f 100644 --- a/go.mod +++ b/go.mod @@ -41,9 +41,9 @@ require ( github.com/spf13/viper v1.19.0 github.com/yoheimuta/go-protoparser/v4 v4.9.0 github.com/yuin/goldmark v1.4.13 - golang.org/x/crypto v0.27.0 + golang.org/x/crypto v0.31.0 golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 - golang.org/x/text v0.18.0 + golang.org/x/text v0.21.0 google.golang.org/api v0.171.0 google.golang.org/grpc v1.66.2 google.golang.org/protobuf v1.34.2 @@ -154,9 +154,9 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.22.0 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect diff --git a/go.sum b/go.sum index 454fb06c5bc..f5b7340ff7c 100644 --- a/go.sum +++ b/go.sum @@ -1920,8 +1920,8 @@ golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72 golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2117,8 +2117,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2213,8 +2213,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2233,8 +2233,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2256,8 +2256,8 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/cfgplugins/bgp.go b/internal/cfgplugins/bgp.go index b1b69e1b003..4b57c046f82 100644 --- a/internal/cfgplugins/bgp.go +++ b/internal/cfgplugins/bgp.go @@ -227,14 +227,14 @@ func (bs *BGPSession) WithEBGP(t *testing.T, afiTypes []oc.E_BgpTypes_AFI_SAFI_T ipv4 := devices[i].Ethernets().Items()[0].Ipv4Addresses().Items()[0] bgp4Peer := bgp.Ipv4Interfaces().Add().SetIpv4Name(ipv4.Name()).Peers().Add().SetName(devices[i].Name() + ".BGP4.peer") bgp4Peer.SetPeerAddress(ipv4.Gateway()) - bgp4Peer.SetAsNumber(uint32(asNumbers[i])) + bgp4Peer.SetAsNumber(asNumbers[i]) bgp4Peer.SetAsType(gosnappi.BgpV4PeerAsType.EBGP) bgp4Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true) case oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST: ipv6 := devices[i].Ethernets().Items()[0].Ipv6Addresses().Items()[0] bgp6Peer := bgp.Ipv6Interfaces().Add().SetIpv6Name(ipv6.Name()).Peers().Add().SetName(devices[i].Name() + ".BGP6.peer") bgp6Peer.SetPeerAddress(ipv6.Gateway()) - bgp6Peer.SetAsNumber(uint32(asNumbers[i])) + bgp6Peer.SetAsNumber(asNumbers[i]) bgp6Peer.SetAsType(gosnappi.BgpV6PeerAsType.EBGP) bgp6Peer.LearnedInformationFilter().SetUnicastIpv6Prefix(true) } @@ -354,6 +354,15 @@ type NeighborConfig struct { AS uint32 } +// BgpNeighbor holds BGP Peer information. +type BgpNeighbor struct { + LocalAS uint32 + PeerAS uint32 + Neighborip string + IsV4 bool + PeerGrp string +} + // buildNeigborConfig builds neighbor config based on given flags func (bs *BGPSession) buildNeigborConfig(isSamePG, isSameAS bool, bgpPorts []string) []*NeighborConfig { nc1 := &NeighborConfig{ @@ -386,7 +395,7 @@ func (bs *BGPSession) buildNeigborConfig(isSamePG, isSameAS bool, bgpPorts []str } ncAll := []*NeighborConfig{nc1, nc2, nc3, nc4} - validNC := []*NeighborConfig{} + var validNC []*NeighborConfig for _, nc := range ncAll[:len(bs.DUTPorts)] { if containsValue(bgpPorts, nc.Name) { validNC = append(validNC, nc) @@ -492,3 +501,56 @@ func containsValue[T comparable](slice []T, value T) bool { } return false } + +// BGPClearConfig removes all BGP configuration from the DUT. +func BGPClearConfig(t *testing.T, dut *ondatra.DUTDevice) { + resetBatch := &gnmi.SetBatch{} + gnmi.BatchDelete(resetBatch, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Config()) + + if deviations.NetworkInstanceTableDeletionRequired(dut) { + tablePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).TableAny() + for _, table := range gnmi.LookupAll[*oc.NetworkInstance_Table](t, dut, tablePath.Config()) { + if val, ok := table.Val(); ok { + if val.GetProtocol() == oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP { + gnmi.BatchDelete(resetBatch, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Table(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, val.GetAddressFamily()).Config()) + } + } + } + } + resetBatch.Set(t, dut) +} + +// VerifyBGPCapabilities function is used to Verify BGP capabilities like route refresh as32 and mpbgp. +func VerifyBGPCapabilities(t *testing.T, dut *ondatra.DUTDevice, nbrs []*BgpNeighbor) { + t.Log("Verifying BGP capabilities") + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + + for _, nbr := range nbrs { + nbrPath := statePath.Neighbor(nbr.Neighborip) + + capabilities := map[oc.E_BgpTypes_BGP_CAPABILITY]bool{ + oc.BgpTypes_BGP_CAPABILITY_ROUTE_REFRESH: false, + oc.BgpTypes_BGP_CAPABILITY_ASN32: false, + oc.BgpTypes_BGP_CAPABILITY_MPBGP: false, + } + for _, c := range gnmi.Get(t, dut, nbrPath.SupportedCapabilities().State()) { + capabilities[c] = true + } + for c, present := range capabilities { + if !present { + t.Errorf("Capability not reported: %v", c) + } + } + } +} + +// VerifyPortsUp asserts that each port on the device is operating. +func VerifyPortsUp(t *testing.T, dev *ondatra.Device) { + t.Helper() + for _, p := range dev.Ports() { + status := gnmi.Get(t, dev, gnmi.OC().Interface(p.Name()).OperStatus().State()) + if want := oc.Interface_OperStatus_UP; status != want { + t.Errorf("%s Status: got %v, want %v", p, status, want) + } + } +} diff --git a/internal/cfgplugins/interface.go b/internal/cfgplugins/interface.go index e8e2c0330c2..fdef68680b5 100644 --- a/internal/cfgplugins/interface.go +++ b/internal/cfgplugins/interface.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" @@ -77,6 +78,7 @@ func ToggleInterface(t *testing.T, dut *ondatra.DUTDevice, intf string, isEnable // ConfigOpticalChannel configures the optical channel. func ConfigOpticalChannel(t *testing.T, dut *ondatra.DUTDevice, och string, frequency uint64, targetOpticalPower float64, operationalMode uint16) { + gnmi.Update(t, dut, gnmi.OC().Component(och).Name().Config(), och) gnmi.Replace(t, dut, gnmi.OC().Component(och).OpticalChannel().Config(), &oc.Component_OpticalChannel{ OperationalMode: ygot.Uint16(operationalMode), Frequency: ygot.Uint64(frequency), @@ -87,43 +89,70 @@ func ConfigOpticalChannel(t *testing.T, dut *ondatra.DUTDevice, och string, freq // ConfigOTNChannel configures the OTN channel. func ConfigOTNChannel(t *testing.T, dut *ondatra.DUTDevice, och string, otnIndex, ethIndex uint32) { t.Helper() - gnmi.Replace(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex).Config(), &oc.TerminalDevice_Channel{ - Description: ygot.String("OTN Logical Channel"), - Index: ygot.Uint32(otnIndex), - LogicalChannelType: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN, - TribProtocol: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE, - Assignment: map[uint32]*oc.TerminalDevice_Channel_Assignment{ - 0: { - Index: ygot.Uint32(0), - OpticalChannel: ygot.String(och), - Description: ygot.String("OTN to Optical Channel"), - Allocation: ygot.Float64(400), - AssignmentType: oc.Assignment_AssignmentType_OPTICAL_CHANNEL, + if deviations.OTNChannelTribUnsupported(dut) { + gnmi.Replace(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex).Config(), &oc.TerminalDevice_Channel{ + Description: ygot.String("OTN Logical Channel"), + Index: ygot.Uint32(otnIndex), + LogicalChannelType: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN, + Assignment: map[uint32]*oc.TerminalDevice_Channel_Assignment{ + 0: { + Index: ygot.Uint32(1), + OpticalChannel: ygot.String(och), + Description: ygot.String("OTN to Optical Channel"), + Allocation: ygot.Float64(400), + AssignmentType: oc.Assignment_AssignmentType_OPTICAL_CHANNEL, + }, }, - 1: { - Index: ygot.Uint32(1), - LogicalChannel: ygot.Uint32(ethIndex), - Description: ygot.String("OTN to ETH"), - Allocation: ygot.Float64(400), - AssignmentType: oc.Assignment_AssignmentType_LOGICAL_CHANNEL, + }) + } else { + gnmi.Replace(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex).Config(), &oc.TerminalDevice_Channel{ + Description: ygot.String("OTN Logical Channel"), + Index: ygot.Uint32(otnIndex), + LogicalChannelType: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN, + TribProtocol: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE, + Assignment: map[uint32]*oc.TerminalDevice_Channel_Assignment{ + 0: { + Index: ygot.Uint32(0), + OpticalChannel: ygot.String(och), + Description: ygot.String("OTN to Optical Channel"), + Allocation: ygot.Float64(400), + AssignmentType: oc.Assignment_AssignmentType_OPTICAL_CHANNEL, + }, + 1: { + Index: ygot.Uint32(1), + LogicalChannel: ygot.Uint32(ethIndex), + Description: ygot.String("OTN to ETH"), + Allocation: ygot.Float64(400), + AssignmentType: oc.Assignment_AssignmentType_LOGICAL_CHANNEL, + }, }, - }, - }) + }) + } } // ConfigETHChannel configures the ETH channel. func ConfigETHChannel(t *testing.T, dut *ondatra.DUTDevice, interfaceName, transceiverName string, otnIndex, ethIndex uint32) { t.Helper() - gnmi.Replace(t, dut, gnmi.OC().TerminalDevice().Channel(ethIndex).Config(), &oc.TerminalDevice_Channel{ - Description: ygot.String("ETH Logical Channel"), - Index: ygot.Uint32(ethIndex), - LogicalChannelType: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_ETHERNET, - TribProtocol: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE, - Ingress: &oc.TerminalDevice_Channel_Ingress{ + var ingress = &oc.TerminalDevice_Channel_Ingress{} + if !deviations.EthChannelIngressParametersUnsupported(dut) { + ingress = &oc.TerminalDevice_Channel_Ingress{ Interface: ygot.String(interfaceName), Transceiver: ygot.String(transceiverName), - }, - Assignment: map[uint32]*oc.TerminalDevice_Channel_Assignment{ + } + } + var assignment = map[uint32]*oc.TerminalDevice_Channel_Assignment{} + if deviations.EthChannelAssignmentCiscoNumbering(dut) { + assignment = map[uint32]*oc.TerminalDevice_Channel_Assignment{ + 0: { + Index: ygot.Uint32(1), + LogicalChannel: ygot.Uint32(otnIndex), + Description: ygot.String("ETH to OTN"), + Allocation: ygot.Float64(400), + AssignmentType: oc.Assignment_AssignmentType_LOGICAL_CHANNEL, + }, + } + } else { + assignment = map[uint32]*oc.TerminalDevice_Channel_Assignment{ 0: { Index: ygot.Uint32(0), LogicalChannel: ygot.Uint32(otnIndex), @@ -131,6 +160,16 @@ func ConfigETHChannel(t *testing.T, dut *ondatra.DUTDevice, interfaceName, trans Allocation: ygot.Float64(400), AssignmentType: oc.Assignment_AssignmentType_LOGICAL_CHANNEL, }, - }, - }) + } + } + channel := &oc.TerminalDevice_Channel{ + Description: ygot.String("ETH Logical Channel"), + Index: ygot.Uint32(ethIndex), + LogicalChannelType: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_ETHERNET, + TribProtocol: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE, + RateClass: oc.TransportTypes_TRIBUTARY_RATE_CLASS_TYPE_TRIB_RATE_400G, + Ingress: ingress, + Assignment: assignment, + } + gnmi.Replace(t, dut, gnmi.OC().TerminalDevice().Channel(ethIndex).Config(), channel) } diff --git a/internal/cfgplugins/sflow.go b/internal/cfgplugins/sflow.go index bf0086daba0..99229eac17a 100644 --- a/internal/cfgplugins/sflow.go +++ b/internal/cfgplugins/sflow.go @@ -57,7 +57,7 @@ func NewSFlowGlobalCfg(t *testing.T, batch *gnmi.SetBatch, newcfg *oc.Sampling_S // NewSFlowCollector creates a collector to be appended to SFlowConfig. // If sfc is nil, default values are provided. func NewSFlowCollector(t *testing.T, batch *gnmi.SetBatch, newcfg *oc.Sampling_Sflow_Collector, d *ondatra.DUTDevice, ni, intfName string, srcAddrV4 string, srcAddrV6 string) []*oc.Sampling_Sflow_Collector { - coll := []*oc.Sampling_Sflow_Collector{} + var coll []*oc.Sampling_Sflow_Collector if newcfg == nil { intf := gnmi.Get[*oc.Interface](t, d, gnmi.OC().Interface(intfName).State()) diff --git a/internal/components/components.go b/internal/components/components.go index c2e6a8b2896..e13fd064046 100644 --- a/internal/components/components.go +++ b/internal/components/components.go @@ -171,9 +171,9 @@ func (y Y) FindByType(ctx context.Context, want oc.Component_Type_Union) ([]stri return names, nil } -// FindStandbyRP gets a list of two components and finds out the active and standby rp. -func FindStandbyRP(t *testing.T, dut *ondatra.DUTDevice, supervisors []string) (string, string) { - var activeRP, standbyRP string +// FindStandbyControllerCard gets a list of two components and finds out the active and standby controller_cards. +func FindStandbyControllerCard(t *testing.T, dut *ondatra.DUTDevice, supervisors []string) (string, string) { + var activeCC, standbyCC string for _, supervisor := range supervisors { watch := gnmi.Watch(t, dut, gnmi.OC().Component(supervisor).RedundantRole().State(), 10*time.Minute, func(val *ygnmi.Value[oc.E_Platform_ComponentRedundantRole]) bool { return val.IsPresent() @@ -184,19 +184,19 @@ func FindStandbyRP(t *testing.T, dut *ondatra.DUTDevice, supervisors []string) ( role := gnmi.Get(t, dut, gnmi.OC().Component(supervisor).RedundantRole().State()) t.Logf("Component(supervisor).RedundantRole().Get(t): %v, Role: %v", supervisor, role) if role == standbyController { - standbyRP = supervisor + standbyCC = supervisor } else if role == activeController { - activeRP = supervisor + activeCC = supervisor } else { t.Fatalf("Expected controller %s to be active or standby, got %v", supervisor, role) } } - if standbyRP == "" || activeRP == "" { - t.Fatalf("Expected non-empty activeRP and standbyRP, got activeRP: %v, standbyRP: %v", activeRP, standbyRP) + if standbyCC == "" || activeCC == "" { + t.Fatalf("Expected non-empty activeCC and standbyCC, got activeCC: %v, standbyCC: %v", activeCC, standbyCC) } - t.Logf("Detected activeRP: %v, standbyRP: %v", activeRP, standbyRP) + t.Logf("Detected activeCC: %v, standbyCC: %v", activeCC, standbyCC) - return standbyRP, activeRP + return standbyCC, activeCC } // OpticalChannelComponentFromPort finds the optical channel component for a port. diff --git a/internal/deviations/README.md b/internal/deviations/README.md index 670bdbe9226..a42d37cfd59 100644 --- a/internal/deviations/README.md +++ b/internal/deviations/README.md @@ -1,21 +1,57 @@ -## Guidelines to add deviations to FNT tests +# Guidelines to add deviations to FNT tests -### Adding Deviations +## When to use deviations -* Add the deviation to the `Deviations` message in the [proto/metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) file. +1. Deviations may be created to use alternate OC or use CLI instead of OC to + achieve the operational intent described in the README. +2. Deviations should not be created which change the operational intent. See + below for guidance on changing operational intent. +3. Deviations may be created to change which OC path is used for telemetry or + use an implementation's native yang path.  Deviations for telemetry + should not introduce a depedency on CLI output. +4. As with any pull request (PR), the CODEOWNERs must review and approve (or + delegate if appropriate). +5. The CODEOWNERs must ensure the README and code reflects the agreed to + operational support goal.  This may be done via offline discussions or + directly via approvals in the github PR. - ``` +See [Deviation Examples](#deviation-examples) for more information. + +## When not to use a deviation + +Deviations should not be used to skip configuration or skip validations. If the +feature is not supported and there is no workaround to achieve +the functionality, then the test should fail for that platform. + +If the README is in error, the README can be updated and code can be changed +(without introducing deviation) with approval from the CODEOWNERs. + +If the intent of the README needs to be changed (not due to an error, but a +change in the feature request), the CODEOWNER must ensure all parties are +notified. The CODEOWNER must determine if the change is late or early in the +development cycle. If late (development is underway and/or nearly complete), it +is recommended to create a new test which represents the change. If early in +the feature request (development has not started or is very early stage), then +the existing README and code may be updated. + +## Adding Deviations + +* Add the deviation to the `Deviations` message in the + [proto/metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) + file. + +```go message Deviations { ... // Device does not support fragmentation bit for traceroute. bool traceroute_fragmentation = 2; ... } - ``` +``` * Run `make proto/metadata_go_proto/metadata.pb.go` from your featureprofiles root directory to generate the Go code for the added proto fields. - ``` +```shell $ make proto/metadata_go_proto/metadata.pb.go mkdir -p proto/metadata_go_proto # Set directory to hold symlink @@ -30,36 +66,57 @@ go list -f '{{ .Dir }} protobuf-import/{{ .Path }}' -m github.com/openconfig/ondatra | xargs -L1 -- ln -s protoc -I='protobuf-import' --proto_path=proto --go_out=./ --go_opt=Mmetadata.proto=proto/metadata_go_proto metadata.proto goimports -w proto/metadata_go_proto/metadata.pb.go - ``` - -* Add the accessor function for this deviation to the [internal/deviations/deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) file. This function will need to accept a parameter `dut` of type `*ondatra.DUTDevice` to lookup the deviation value for a specific dut. This accessor function must call `lookupDUTDeviations` and return the deviation value. Test code will use this function to access deviations. - * If the default value of the deviation is the same as the default value for the proto field, the accessor method can directly call the `Get*()` function for the deviation field. For example, the boolean `traceroute_fragmentation` deviation, which has a default value of `false`, will have an accessor method with the single line `return lookupDUTDeviations(dut).GetTracerouteFragmentation()`. - - ``` - // TraceRouteFragmentation returns if the device does not support fragmentation bit for traceroute. - // Default value is false. - func TraceRouteFragmentation(dut *ondatra.DUTDevice) bool { - return lookupDUTDeviations(dut).GetTracerouteFragmentation() - } - ``` - - * If the default value of deviation is not the same as the default value of the proto field, the accessor method can add a check and return the required default value. For example, the accessor method for the float `hierarchical_weight_resolution_tolerance` deviation, which has a default value of `0`, will call the `GetHierarchicalWeightResolutionTolerance()` to check the value set in `metadata.textproto` and return the default value `0.2` if applicable. - - ``` - // HierarchicalWeightResolutionTolerance returns the allowed tolerance for BGP traffic flow while comparing for pass or fail conditions. - // Default minimum value is 0.2. Anything less than 0.2 will be set to 0.2. - func HierarchicalWeightResolutionTolerance(dut *ondatra.DUTDevice) float64 { - hwrt := lookupDUTDeviations(dut).GetHierarchicalWeightResolutionTolerance() - if minHWRT := 0.2; hwrt < minHWRT { +``` + +* Add the accessor function for this deviation to the + [internal/deviations/deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) + file. This function will need to accept a parameter `dut` of type + `*ondatra.DUTDevice` to lookup the deviation value for a specific dut. This + accessor function must call `lookupDUTDeviations` and return the deviation + value. Test code will use this function to access deviations. + * If the default value of the deviation is the same as the default value for + the proto field, the accessor method can directly call the `Get*()` function + for the deviation field. For example, the boolean `traceroute_fragmentation` + deviation, which has a default value of `false`, will have an accessor + method with the single line `return + lookupDUTDeviations(dut).GetTracerouteFragmentation()`. + + ```go + // TraceRouteFragmentation returns if the device does not support fragmentation bit for traceroute. + // Default value is false. + func TraceRouteFragmentation(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetTracerouteFragmentation() + } + ``` + + * If the default value of deviation is not the same as the default value of + the proto field, the accessor method can add a check and return the required + default value. For example, the accessor method for the float + `hierarchical_weight_resolution_tolerance` deviation, which has a default + value of `0`, will call the `GetHierarchicalWeightResolutionTolerance()` to + check the value set in `metadata.textproto` and return the default value + `0.2` if applicable. + + ```go + // HierarchicalWeightResolutionTolerance returns the allowed tolerance for BGP traffic flow while comparing for pass or fail conditions. + // Default minimum value is 0.2. Anything less than 0.2 will be set to 0.2. + func HierarchicalWeightResolutionTolerance(dut *ondatra.DUTDevice) float64 { + hwrt := lookupDUTDeviations(dut).GetHierarchicalWeightResolutionTolerance() + if minHWRT := 0.2; hwrt < minHWRT { return minHWRT - } - return hwrt - } - ``` - -* Set the deviation value in the `metadata.textproto` file in the same folder as the test. For example, the deviations used in the test `feature/gnoi/system/tests/traceroute_test/traceroute_test.go` will be set in the file `feature/gnoi/system/tests/traceroute_test/metadata.textproto`. List all the vendor and optionally also hardware model regex that this deviation is applicable for. - - ``` + } + return hwrt + } + ``` + +* Set the deviation value in the `metadata.textproto` file in the same folder as + the test. For example, the deviations used in the test + `feature/gnoi/system/tests/traceroute_test/traceroute_test.go` will be set in + the file `feature/gnoi/system/tests/traceroute_test/metadata.textproto`. List + all the vendor and optionally also hardware model regex that this deviation is + applicable for. + + ```go ... platform_exceptions: { platform: { @@ -73,30 +130,69 @@ ... ``` -* To access the deviation from the test call the accessor function for the deviation. Pass the dut to this accessor. +* To access the deviation from the test call the accessor function for the + deviation. Pass the dut to this accessor. - ``` + ```go if deviations.TraceRouteFragmentation(dut) { ... } ``` -* Example PRs - https://github.com/openconfig/featureprofiles/pull/1649 and - https://github.com/openconfig/featureprofiles/pull/1668 +* Example PRs - and + + +## Removing Deviations -### Removing Deviations +* Once a deviation is no longer required and removed from all tests, delete the + deviation by removing them from the following files: -* Once a deviation is no longer required and removed from all tests, delete the deviation by removing them from the following files: + * metadata.textproto - Remove the deviation field from all metadata.textproto + in all tests. - * metadata.textproto - Remove the deviation field from all metadata.textproto in all tests. + * Remove the accessor method from + [deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) - * [deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) - Remove the accessor method for this deviation. + * Remove the field number from + [metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) + by adding the `reserved n` to the `Deviations` message. Ref: + - * [metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) - Remove the deviation field from the `Deviations` message and reserve the deleted field number by adding the `reserved n` to the `Deviations` message. -Ref: https://protobuf.dev/programming-guides/proto3/#deleting +* Run `make proto/metadata_go_proto/metadata.pb.go` from your featureprofiles + root directory to update the Go code for the removed proto fields. -* Run `make proto/metadata_go_proto/metadata.pb.go` from your featureprofiles root directory to update the Go code for the removed proto fields. +## Deviation examples + +```go +conf := configureDUT(dut) // returns *oc.Root + +if deviations.AlternateOCEnabled(t, dut) { + switch dut.Vendor() { + case ondatra.VENDOR_X: + conf.SetAlternateOC(val) + } +} else { + conf.SetRequiredOC(val) +} +``` + +```go +conf := configureDUT(dut) // returns *oc.Root + +if deviations.RequiredOCNotSupported(t, dut) { + switch dut.Vendor() { + case ondatra.VENDOR_X: + configureDeviceUsingCli(t, dut, vendorXConfig) + } +} +``` ## Notes -* If you run into issues with the `make proto/metadata_go_proto/metadata.pb.go` you may need to check if the `protoc` module is installed in your environment. Also depending on your Go version you may need to update your PATH and GOPATH. -* After running the `make proto/metadata_go_proto/metadata.pb.go` script, a `protobuf-import/` folder will be added in your current directory. Keep an eye out for this in case you use `git add .` to add modified files since this folder should not be part of your PR. + +* If you run into issues with the `make proto/metadata_go_proto/metadata.pb.go` + you may need to check if the `protoc` module is installed in your environment. + Also depending on your Go version you may need to update your PATH and GOPATH. +* After running the `make proto/metadata_go_proto/metadata.pb.go` script, a + `protobuf-import/` folder will be added in your current directory. Keep an eye + out for this in case you use `git add .` to add modified files since this + folder should not be part of your PR. diff --git a/internal/deviations/deviations.go b/internal/deviations/deviations.go index 43895c6ef5e..2d34420d438 100644 --- a/internal/deviations/deviations.go +++ b/internal/deviations/deviations.go @@ -31,8 +31,8 @@ // Requirements for deviations: // // - Deviations may only use OpenConfig compliant behavior. -// - Deviations should be small in scope, typically affecting one sub-test, one -// OpenConfig path or small OpenConfig sub-tree. +// - Deviations should be small in scope, typically affecting one subtest, one +// OpenConfig path or small OpenConfig subtree. // // If a device could not pass without deviation, that is considered non-compliant // behavior. Ideally, a device should pass both with and without a deviation which means @@ -49,6 +49,7 @@ import ( log "github.com/golang/glog" "github.com/openconfig/featureprofiles/internal/metadata" + mpb "github.com/openconfig/featureprofiles/proto/metadata_go_proto" "github.com/openconfig/ondatra" ) @@ -56,12 +57,12 @@ import ( func lookupDeviations(dvc *ondatra.Device) (*mpb.Metadata_PlatformExceptions, error) { var matchedPlatformException *mpb.Metadata_PlatformExceptions - for _, platformExceptions := range metadata.Get().PlatformExceptions { - if platformExceptions.GetPlatform().Vendor.String() == "" { + for _, platformExceptions := range metadata.Get().GetPlatformExceptions() { + if platformExceptions.GetPlatform().GetVendor().String() == "" { return nil, fmt.Errorf("vendor should be specified in textproto %v", platformExceptions) } - if dvc.Vendor().String() != platformExceptions.GetPlatform().Vendor.String() { + if dvc.Vendor().String() != platformExceptions.GetPlatform().GetVendor().String() { continue } @@ -131,7 +132,7 @@ func GRIBIMACOverrideStaticARPStaticRoute(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetGribiMacOverrideStaticArpStaticRoute() } -// AggregateAtomicUpdate returns if device requires that aggregate Port-Channel and its members be defined in a single gNMI Update transaction at /interfaces. +// AggregateAtomicUpdate returns if device requires that aggregate Port-Channel and its members be defined in a single gNMI Update transaction at /interfaces, // Otherwise lag-type will be dropped, and no member can be added to the aggregate. // Full OpenConfig compliant devices should pass both with and without this deviation. func AggregateAtomicUpdate(dut *ondatra.DUTDevice) bool { @@ -184,7 +185,7 @@ func SwitchChipIDUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetSwitchChipIdUnsupported() } -// BackplaneFacingCapacityUnsupported returns whether the device supports backplane-facing-capacity leaves for some of the components. +// BackplaneFacingCapacityUnsupported returns whether the device supports backplane-facing-capacity leaves for some components. func BackplaneFacingCapacityUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetBackplaneFacingCapacityUnsupported() } @@ -343,7 +344,7 @@ func InstallOSForStandbyRP(dut *ondatra.DUTDevice) bool { } // GNOIStatusWithEmptySubcomponent returns if the response of gNOI reboot status is a single value (not a list), -// the device requires explict component path to account for a situation when there is more than one active reboot requests. +// the device requires explicit component path to account for a situation when there is more than one active reboot requests. func GNOIStatusWithEmptySubcomponent(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetGnoiStatusEmptySubcomponent() } @@ -432,7 +433,7 @@ func GNOIFabricComponentRebootUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetGnoiFabricComponentRebootUnsupported() } -// NtpNonDefaultVrfUnsupported returns true if the device does not support ntp nondefault vrf. +// NtpNonDefaultVrfUnsupported returns true if the device does not support ntp non-default vrf. // Default value is false. func NtpNonDefaultVrfUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetNtpNonDefaultVrfUnsupported() @@ -490,7 +491,7 @@ func SetNativeUser(dut *ondatra.DUTDevice) bool { } // P4RTGdpRequiresDot1QSubinterface returns true for devices that require configuring -// subinterface with tagged vlan for p4rt packet in. +// subinterface with tagged vlan for P4RT packet in. func P4RTGdpRequiresDot1QSubinterface(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetP4RtGdpRequiresDot1QSubinterface() } @@ -593,7 +594,7 @@ func QOSQueueRequiresID(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetQosQueueRequiresId() } -// BgpLlgrOcUndefined returns true if device should does not support OC path to disable BGP LLGR. +// BgpLlgrOcUndefined returns true if device does not support OC path to disable BGP LLGR. func BgpLlgrOcUndefined(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetBgpLlgrOcUndefined() } @@ -604,7 +605,7 @@ func QOSBufferAllocationConfigRequired(dut *ondatra.DUTDevice) bool { } // BGPGlobalExtendedNextHopEncodingUnsupported returns true for devices that do not support configuring -// BGP ExtendedNextHopEncoding at thee global level. +// BGP ExtendedNextHopEncoding at the global level. func BGPGlobalExtendedNextHopEncodingUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetBgpGlobalExtendedNextHopEncodingUnsupported() } @@ -715,7 +716,7 @@ func StaticRouteNextHopInterfaceRefUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetStaticRouteNextHopInterfaceRefUnsupported() } -// SkipStaticNexthopCheck returns if device needs index starting from non zero +// SkipStaticNexthopCheck returns if device needs index starting from non-zero func SkipStaticNexthopCheck(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetSkipStaticNexthopCheck() } @@ -776,7 +777,7 @@ func BGPConditionsMatchCommunitySetUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetBgpConditionsMatchCommunitySetUnsupported() } -// PfRequireMatchDefaultRule returns true for device which requires match condition for ethertype v4 and v6 for default rule with network-instance default-vrf in policy-forwarding. +// PfRequireMatchDefaultRule returns true for device which requires match condition for ether type v4 and v6 for default rule with network-instance default-vrf in policy-forwarding. func PfRequireMatchDefaultRule(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetPfRequireMatchDefaultRule() } @@ -871,12 +872,12 @@ func PLQReflectorStatsUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetPlqReflectorStatsUnsupported() } -// PLQGeneratorCapabilitiesMaxMTU returns supported max_mtu for devices that does not support packet link qualification(PLQ) Generator max_mtu to be atleast >= 8184. +// PLQGeneratorCapabilitiesMaxMTU returns supported max_mtu for devices that does not support packet link qualification(PLQ) Generator max_mtu to be at least >= 8184. func PLQGeneratorCapabilitiesMaxMTU(dut *ondatra.DUTDevice) uint32 { return lookupDUTDeviations(dut).GetPlqGeneratorCapabilitiesMaxMtu() } -// PLQGeneratorCapabilitiesMaxPPS returns supported max_pps for devices that does not support packet link qualification(PLQ) Generator max_pps to be atleast >= 100000000. +// PLQGeneratorCapabilitiesMaxPPS returns supported max_pps for devices that does not support packet link qualification(PLQ) Generator max_pps to be at least >= 100000000. func PLQGeneratorCapabilitiesMaxPPS(dut *ondatra.DUTDevice) uint64 { return lookupDUTDeviations(dut).GetPlqGeneratorCapabilitiesMaxPps() } @@ -927,17 +928,17 @@ func IPv4StaticRouteWithIPv6NextHopUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetIpv4StaticRouteWithIpv6NhUnsupported() } -// IPv6StaticRouteWithIPv4NextHopUnsupported unsported ipv6 with ipv4 nexthop +// IPv6StaticRouteWithIPv4NextHopUnsupported unsupported ipv6 with ipv4 nexthop func IPv6StaticRouteWithIPv4NextHopUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetIpv6StaticRouteWithIpv4NhUnsupported() } -// StaticRouteWithDropNhUnsupported unsuported drop nexthop +// StaticRouteWithDropNhUnsupported unsupported drop nexthop func StaticRouteWithDropNhUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetStaticRouteWithDropNh() } -// StaticRouteWithExplicitMetric set explict metric +// StaticRouteWithExplicitMetric set explicit metric func StaticRouteWithExplicitMetric(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetStaticRouteWithExplicitMetric() } @@ -947,7 +948,7 @@ func BgpDefaultPolicyUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetBgpDefaultPolicyUnsupported() } -// ExplicitEnableBGPOnDefaultVRF return true if BGP needs to be explicity enabled on default VRF +// ExplicitEnableBGPOnDefaultVRF return true if BGP needs to be explicitly enabled on default VRF func ExplicitEnableBGPOnDefaultVRF(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetExplicitEnableBgpOnDefaultVrf() } @@ -1027,7 +1028,7 @@ func InstallPositionAndInstallComponentUnsupported(dut *ondatra.DUTDevice) bool return lookupDUTDeviations(dut).GetInstallPositionAndInstallComponentUnsupported() } -// EncapTunnelShutBackupNhgZeroTraffic returns true when encap tunnel is shut then zero traffic flows to backup NHG +// EncapTunnelShutBackupNhgZeroTraffic returns true when encap tunnel is shut then zero traffic flows to back-up NHG func EncapTunnelShutBackupNhgZeroTraffic(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetEncapTunnelShutBackupNhgZeroTraffic() } @@ -1150,3 +1151,116 @@ func UseParentComponentForTemperatureTelemetry(dut *ondatra.DUTDevice) bool { func ComponentMfgDateUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetComponentMfgDateUnsupported() } + +// InterfaceCountersUpdateDelayed returns true if telemetry for interface counters +// does not return the latest counter values. +func InterfaceCountersUpdateDelayed(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetInterfaceCountersUpdateDelayed() +} + +// OTNChannelTribUnsupported returns true if TRIB parameter is unsupported under OTN channel configuration +func OTNChannelTribUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetOtnChannelTribUnsupported() +} + +// EthChannelIngressParametersUnsupported returns true if ingress parameters are unsupported under ETH channel configuration +func EthChannelIngressParametersUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetEthChannelIngressParametersUnsupported() +} + +// EthChannelAssignmentCiscoNumbering returns true if eth channel assignment index starts from 1 instead of 0 +func EthChannelAssignmentCiscoNumbering(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetEthChannelAssignmentCiscoNumbering() +} + +// ChassisGetRPCUnsupported returns true if a Healthz Get RPC against the Chassis component is unsupported +func ChassisGetRPCUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetChassisGetRpcUnsupported() +} + +// PowerDisableEnableLeafRefValidation returns true if definition of leaf-ref is not supported. +func PowerDisableEnableLeafRefValidation(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetPowerDisableEnableLeafRefValidation() +} + +// SSHServerCountersUnsupported is to skip checking ssh server counters. +func SSHServerCountersUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetSshServerCountersUnsupported() +} + +// OperationalModeUnsupported returns true if operational-mode leaf is unsupported +func OperationalModeUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetOperationalModeUnsupported() +} + +// BgpSessionStateIdleInPassiveMode returns true if BGP session state idle is not supported instead of active in passive mode. +func BgpSessionStateIdleInPassiveMode(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpSessionStateIdleInPassiveMode() +} + +// EnableMultipathUnderAfiSafi returns true for devices that do not support multipath under /global path and instead support under global/afi/safi path. +func EnableMultipathUnderAfiSafi(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetEnableMultipathUnderAfiSafi() +} + +// BgpAllowownasDiffDefaultValue permits a device to have a different default value for allow own as. +func BgpAllowownasDiffDefaultValue(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpAllowownasDiffDefaultValue() +} + +// OTNChannelAssignmentCiscoNumbering returns true if OTN channel assignment index starts from 1 instead of 0 +func OTNChannelAssignmentCiscoNumbering(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetOtnChannelAssignmentCiscoNumbering() +} + +// CiscoPreFECBERInactiveValue returns true if a non-zero pre-fec-ber value is to be used for Cisco +func CiscoPreFECBERInactiveValue(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetCiscoPreFecBerInactiveValue() +} + +// BgpExtendedNextHopEncodingLeafUnsupported return true if bgp extended next hop encoding leaf is unsupported +// Cisco supports the extended nexthop encoding set to true by default that is exercised in the Script where the extended-nexthop-encoding +// a bool value is set to true. +func BgpExtendedNextHopEncodingLeafUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpExtendedNextHopEncodingLeafUnsupported() +} + +// BgpAfiSafiWildcardNotSupported return true if bgp afi/safi wildcard query is not supported. +// For example, this yang path query includes the wildcard key `afi-safi-name=`: +// `/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=192.0.2.2]/afi-safis/afi-safi[afi-safi-name=]`. +// Use of this deviation is permitted if a query using an explicit key is supported (such as +// `oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST`). +func BgpAfiSafiWildcardNotSupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpAfiSafiWildcardNotSupported() +} + +// NoZeroSuppression returns true if device wants to remove zero suppression +func NoZeroSuppression(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetNoZeroSuppression() +} + +// IsisInterfaceLevelPassiveUnsupported returns true for devices that do not support passive leaf +func IsisInterfaceLevelPassiveUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetIsisInterfaceLevelPassiveUnsupported() +} + +// IsisDisSysidUnsupported returns true for devices that do not support dis-system-id leaf +func IsisDisSysidUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetIsisDisSysidUnsupported() +} + +// IsisDatabaseOverloadsUnsupported returns true for devices that do not support database-overloads leaf +func IsisDatabaseOverloadsUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetIsisDatabaseOverloadsUnsupported() +} + +// BgpSetMedV7Unsupported returns true if devices which are not +// supporting bgp set med union type in OC. +func BgpSetMedV7Unsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpSetMedV7Unsupported() +} + +// EnableTableConnections returns true if admin state of tableconnections needs to be enabled in SRL native model +func EnableTableConnections(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetEnableTableConnections() +} diff --git a/internal/fptest/config.go b/internal/fptest/config.go new file mode 100644 index 00000000000..bb976eea456 --- /dev/null +++ b/internal/fptest/config.go @@ -0,0 +1,205 @@ +package fptest + +import ( + "flag" + "testing" + + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygot/ygot" +) + +var ( + // Some devices require the config to be pruned for these to work. We are still undecided + // whether they should be deviations; pending OpenConfig clarifications. + pruneComponents = flag.Bool("prune_components", true, "Prune components that are not ports. Use this to preserve the breakout-mode settings.") + pruneLLDP = flag.Bool("prune_lldp", true, "Prune LLDP config.") + setEthernetFromState = flag.Bool("set_ethernet_from_state", true, "Set interface/ethernet config from state, mostly to get the port-speed settings correct.") + + // This has no known effect except to reduce logspam while debugging. + pruneQoS = flag.Bool("prune_qos", true, "Prune QoS config.") + + // Experimental flags that will likely become a deviation. + cannotConfigurePortSpeed = flag.Bool("cannot_config_port_speed", false, "Some devices depending on the type of line card may not allow changing port speed, while still supporting the port speed leaf.") + + // Flags to ensure test passes without any dependency to the device config + baseOCConfigIsPresent = flag.Bool("base_oc_config_is_present", false, "No OC config is loaded on router, so Get config on the root returns no data.") +) + +// GetDeviceConfig gets a full config from a device but refurbishes it enough so it can be +// pushed out again. Ideally, we should be able to push the config we get from the same +// device without modification, but this is not explicitly defined in OpenConfig. +func GetDeviceConfig(t testing.TB, dev gnmi.DeviceOrOpts) *oc.Root { + t.Helper() + + // Gets all the config (read-write) paths from root, not the state (read-only) paths. + config := gnmi.Get[*oc.Root](t, dev, gnmi.OC().Config()) + WriteQuery(t, "Untouched", gnmi.OC().Config(), config) + + // load the base oc config from the device state when no oc config is loaded + if !*baseOCConfigIsPresent { + if ondatra.DUT(t, "dut").Vendor() == ondatra.CISCO { + intfsState := gnmi.GetAll(t, dev, gnmi.OC().InterfaceAny().State()) + for _, intf := range intfsState { + ygot.PruneConfigFalse(oc.SchemaTree["Interface"], intf) + config.DeleteInterface(intf.GetName()) + if intf.GetName() == "Loopback0" || intf.GetName() == "PTP0/RP1/CPU0/0" || intf.GetName() == "Null0" || intf.GetName() == "PTP0/RP0/CPU0/0" { + continue + } + intf.ForwardingViable = nil + intf.Mtu = nil + intf.HoldTime = nil + if intf.Subinterface != nil { + if intf.Subinterface[0].Ipv6 != nil { + intf.Subinterface[0].Ipv6.Autoconf = nil + } + } + config.AppendInterface(intf) + } + vrfsStates := gnmi.GetAll(t, dev, gnmi.OC().NetworkInstanceAny().State()) + for _, vrf := range vrfsStates { + // only needed for containerOp + if vrf.GetName() == "**iid" { + continue + } + if vrf.GetName() == "DEFAULT" { + config.NetworkInstance = nil + vrf.Interface = nil + for _, ni := range config.NetworkInstance { + ni.Mpls = nil + } + } + ygot.PruneConfigFalse(oc.SchemaTree["NetworkInstance"], vrf) + vrf.Table = nil + vrf.RouteLimit = nil + vrf.Mpls = nil + for _, intf := range vrf.Interface { + intf.AssociatedAddressFamilies = nil + } + for _, protocol := range vrf.Protocol { + for _, routes := range protocol.Static { + routes.Description = nil + } + } + config.AppendNetworkInstance(vrf) + } + } + } + + if *pruneComponents { + for cname, component := range config.Component { + // Keep the port components in order to preserve the breakout-mode config. + if component.GetPort() == nil { + delete(config.Component, cname) + continue + } + // Need to prune subcomponents that may have a leafref to a component that was + // pruned. + component.Subcomponent = nil + } + } + + if *setEthernetFromState { + for iname, iface := range config.Interface { + if iface.GetEthernet() == nil { + continue + } + // Ethernet config may not contain meaningful values if it wasn't explicitly + // configured, so use its current state for the config, but prune non-config leaves. + intf := gnmi.Get(t, dev, gnmi.OC().Interface(iname).State()) + e := intf.GetEthernet() + if len(intf.GetHardwarePort()) != 0 { + breakout := config.GetComponent(intf.GetHardwarePort()).GetPort().GetBreakoutMode() + e := intf.GetEthernet() + // Set port speed to unknown for non breakout interfaces + if breakout.GetGroup(1) == nil && e != nil { + e.SetPortSpeed(oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN) + } + } + ygot.PruneConfigFalse(oc.SchemaTree["Interface_Ethernet"], e) + if e.PortSpeed != 0 && e.PortSpeed != oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN { + iface.Ethernet = e + } + // need to set mac address for mgmt interface to nil + if intf.GetName() == "MgmtEth0/RP0/CPU0/0" || intf.GetName() == "MgmtEth0/RP1/CPU0/0" && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { + e.MacAddress = nil + } + // need to set mac address for bundle interface to nil + if iface.Ethernet.AggregateId != nil && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { + iface.Ethernet.MacAddress = nil + continue + } + } + } + + if !*cannotConfigurePortSpeed { + for _, iface := range config.Interface { + if iface.GetEthernet() == nil { + continue + } + iface.GetEthernet().PortSpeed = oc.IfEthernet_ETHERNET_SPEED_UNSET + iface.GetEthernet().DuplexMode = oc.Ethernet_DuplexMode_UNSET + iface.GetEthernet().EnableFlowControl = nil + } + } + + if *pruneLLDP && config.Lldp != nil { + config.Lldp.ChassisId = nil + config.Lldp.ChassisIdType = oc.Lldp_ChassisIdType_UNSET + } + + if *pruneQoS { + config.Qos = nil + } + + pruneUnsupportedPaths(config) + + WriteQuery(t, "Touched", gnmi.OC().Config(), config) + return config +} + +// CopyDeviceConfig returns a deep copy of a device config but refurbishes it enough so it can be +// pushed out again +func CopyDeviceConfig(t testing.TB, dut *ondatra.DUTDevice, config *oc.Root) *oc.Root { + if deviations.SkipMacaddressCheck(dut) { + *setEthernetFromState = false + } + + o, err := ygot.DeepCopy(config) + if err != nil { + t.Fatalf("Cannot copy baseConfig: %v", err) + } + + copy := o.(*oc.Root) + + if *setEthernetFromState { + setEthernetFromBase(t, config, copy) + } + + return copy +} + +func pruneUnsupportedPaths(config *oc.Root) { + for _, ni := range config.NetworkInstance { + ni.Fdb = nil + } +} + +// setEthernetFromBase merges the ethernet config from the interfaces in base config into +// the destination config. +func setEthernetFromBase(t testing.TB, base *oc.Root, config *oc.Root) { + t.Helper() + + for iname, iface := range config.Interface { + eb := base.GetInterface(iname).GetEthernet() + ec := iface.GetOrCreateEthernet() + if eb == nil || ec == nil { + continue + } + if err := ygot.MergeStructInto(ec, eb); err != nil { + t.Errorf("Cannot merge %s ethernet: %v", iname, err) + } + } +} diff --git a/internal/fptest/log.go b/internal/fptest/log.go index 520bc6d4224..498380f3911 100644 --- a/internal/fptest/log.go +++ b/internal/fptest/log.go @@ -15,6 +15,7 @@ package fptest import ( + "flag" "fmt" "log" "os" @@ -24,8 +25,6 @@ import ( "time" "unicode" - "flag" - "github.com/openconfig/featureprofiles/internal/check" "github.com/openconfig/ondatra" "github.com/openconfig/ygnmi/ygnmi" @@ -106,7 +105,7 @@ func LogQuery(t testing.TB, what string, query LoggableQuery, obj ygot.GoStruct) logQuery(t, what, query, obj, true) } -// WriteQuery is like LogQuery but only writes to test outputs dir so it +// WriteQuery is like LogQuery but only writes to test output dir, so it // does not pollute the test log. func WriteQuery(t testing.TB, what string, query LoggableQuery, obj ygot.GoStruct) { t.Helper() diff --git a/internal/fptest/tableconnection.go b/internal/fptest/tableconnection.go new file mode 100644 index 00000000000..258f48a5acc --- /dev/null +++ b/internal/fptest/tableconnection.go @@ -0,0 +1,66 @@ +// Copyright 2022 Google LLC +// +// 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. + +package fptest + +import ( + "context" + "encoding/json" + "testing" + + gpb "github.com/openconfig/gnmi/proto/gnmi" + "github.com/openconfig/ondatra" +) + +// ConfigEnableTbNative enables admin-state of table-connections in native mode. +func ConfigEnableTbNative(t testing.TB, d *ondatra.DUTDevice) { + t.Helper() + state := "enable" + switch d.Vendor() { + case ondatra.NOKIA: + adminEnable, err := json.Marshal(state) + if err != nil { + t.Fatalf("Error with json Marshal: %v", err) + } + + gpbSetRequest := &gpb.SetRequest{ + Prefix: &gpb.Path{ + Origin: "native", + }, + Update: []*gpb.Update{ + { + Path: &gpb.Path{ + Elem: []*gpb.PathElem{ + {Name: "network-instance", Key: map[string]string{"name": "DEFAULT"}}, + {Name: "table-connections"}, + {Name: "admin-state"}, + }, + }, + Val: &gpb.TypedValue{ + Value: &gpb.TypedValue_JsonIetfVal{ + JsonIetfVal: adminEnable, + }, + }, + }, + }, + } + + gnmiClient := d.RawAPIs().GNMI(t) + if _, err := gnmiClient.Set(context.Background(), gpbSetRequest); err != nil { + t.Fatalf("Unexpected error updating SRL static-route tag-set: %v", err) + } + default: + t.Fatalf("Unsupported vendor %s for deviation 'EnableTableConnections'", d.Vendor()) + } +} diff --git a/internal/gnoi/gnoi.go b/internal/gnoi/gnoi.go index 48eec464b83..cf7892ecea6 100644 --- a/internal/gnoi/gnoi.go +++ b/internal/gnoi/gnoi.go @@ -40,6 +40,7 @@ var ( }, ondatra.CISCO: { GRIBI: "emsd", + OCAGENT: "emsd", P4RT: "emsd", ROUTING: "emsd", }, diff --git a/internal/helpers/helpers.go b/internal/helpers/helpers.go index 0667886c46e..a0a13183ca1 100644 --- a/internal/helpers/helpers.go +++ b/internal/helpers/helpers.go @@ -36,7 +36,7 @@ import ( // When CheckInterfacesInBinding is set to true, all interfaces that are not defined in binding file are excluded. func FetchOperStatusUPIntfs(t *testing.T, dut *ondatra.DUTDevice, checkInterfacesInBinding bool) []string { t.Helper() - intfsOperStatusUP := []string{} + var intfsOperStatusUP []string intfs := gnmi.GetAll(t, dut, gnmi.OC().InterfaceAny().Name().State()) bindedIntf := make(map[string]bool) for _, port := range dut.Ports() { diff --git a/internal/otg_helpers/otg_config_helpers/otgconfighelpers.go b/internal/otg_helpers/otg_config_helpers/otgconfighelpers.go new file mode 100644 index 00000000000..862d5381fa6 --- /dev/null +++ b/internal/otg_helpers/otg_config_helpers/otgconfighelpers.go @@ -0,0 +1,115 @@ +// Package otgconfighelpers provides helper functions to setup Protocol configurations on traffic generators. +package otgconfighelpers + +import ( + "testing" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/ondatra" +) + +/* +Port is a struct to hold aggregate/physical port data. + +Usage for Aggregate port: + + agg1 = &otgconfighelpers.Port{ + Name: "Port-Channel1", + AggMAC: "02:00:01:01:01:07", + Interfaces: []*otgconfighelpers.InterfaceProperties{interface1, interface2, interface3, interface4, interface5, interface6}, + MemberPorts: []string{"port1", "port2"}, + LagID: 1, + Islag: true, + } + +Usage for Physical port: + + phy1 = &otgconfighelpers.Port{ + Name: "port1", + Interfaces: []*otgconfighelpers.InterfaceProperties{interface1, interface2, interface3, interface4, interface5, interface6}, + } + +Interface properties has attributes required for creating interfaces/subinterfaces on the port.. + + interface1 = &otgconfighelpers.InterfaceProperties{ + IPv4: "169.254.0.12", + IPv4Gateway: "169.254.0.11", + Name: "Port-Channel1.20", + Vlan: 20, + IPv4Len: 29, + Mac: "02:00:01:01:01:08", + } +*/ +type Port struct { + Name string + AggMAC string + Interfaces []*InterfaceProperties + MemberPorts []string + LagID uint32 + Islag bool +} + +// InterfaceProperties is a struct to hold interface data. +type InterfaceProperties struct { + IPv4 string + IPv4Gateway string + IPv6 string + IPv6Gateway string + Name string + Vlan uint32 + IPv4Len uint32 + IPv6Len uint32 + Mac string +} + +// ConfigureOtgNetworkInterface configures the network interface. +func ConfigureOtgNetworkInterface(t *testing.T, top gosnappi.Config, ate *ondatra.ATEDevice, a *Port) { + if a.Islag { + ConfigureOtgLag(t, top, ate, a) + } else { + top.Ports().Add().SetName(a.Name) + } + for _, intf := range a.Interfaces { + ConfigureOtgInterface(t, top, intf, a) + } +} + +// ConfigureOtgLag configures the aggregate port. +func ConfigureOtgLag(t *testing.T, top gosnappi.Config, ate *ondatra.ATEDevice, a *Port) { + agg := top.Lags().Add().SetName(a.Name) + agg.Protocol().Lacp().SetActorKey(1).SetActorSystemPriority(1).SetActorSystemId(a.AggMAC) + for index, portName := range a.MemberPorts { + p := ate.Port(t, portName) + top.Ports().Add().SetName(p.ID()) + ConfigureOtgLagMemberPort(agg, p.ID(), a, index) + } +} + +// ConfigureOtgLagMemberPort configures the member port in the LAG. +func ConfigureOtgLagMemberPort(agg gosnappi.Lag, portID string, a *Port, index int) { + lagPort := agg.Ports().Add().SetPortName(portID) + lagPort.Ethernet().SetMac(a.AggMAC).SetName(a.Name + "-" + portID) + lagPort.Lacp().SetActorActivity("active").SetActorPortNumber(uint32(index) + 1).SetActorPortPriority(1).SetLacpduTimeout(0) +} + +// ConfigureOtgInterface configures the Ethernet for the LAG or subinterface. +func ConfigureOtgInterface(t *testing.T, top gosnappi.Config, intf *InterfaceProperties, a *Port) { + dev := top.Devices().Add().SetName(intf.Name + ".Dev") + eth := dev.Ethernets().Add().SetName(intf.Name + ".Eth").SetMac(intf.Mac) + if a.Islag { + eth.Connection().SetLagName(a.Name) + } else { + eth.Connection().SetPortName(a.Name) + } + // VLAN configuration + if intf.Vlan != 0 { + eth.Vlans().Add().SetName(intf.Name + ".vlan").SetId(intf.Vlan) + } + // IP address configuration + if intf.IPv4 != "" { + eth.Ipv4Addresses().Add().SetName(intf.Name + ".IPv4").SetAddress(intf.IPv4).SetGateway(intf.IPv4Gateway).SetPrefix(intf.IPv4Len) + } + if intf.IPv6 != "" { + eth.Ipv6Addresses().Add().SetName(intf.Name + ".IPv6").SetAddress(intf.IPv6).SetGateway(intf.IPv6Gateway).SetPrefix(intf.IPv6Len) + } +} diff --git a/internal/otg_helpers/otg_config_helpers/otgflowhelpers.go b/internal/otg_helpers/otg_config_helpers/otgflowhelpers.go new file mode 100644 index 00000000000..23ffc578c2d --- /dev/null +++ b/internal/otg_helpers/otg_config_helpers/otgflowhelpers.go @@ -0,0 +1,215 @@ +package otgconfighelpers + +import ( + "github.com/open-traffic-generator/snappi/gosnappi" +) + +// Iana Ethertype is the IANA Ethertype for MPLS, IPv4 and IPv6. +const ( + IanaMPLSEthertype = 34887 + IanaIPv4Ethertype = 2048 + IanaIPv6Ethertype = 34525 +) + +/* +Flow is a struct to hold Flow parameters. +TxNames and RxNames should be set to a valid OTG endpoint name. +Creating basic IPv4 Flow. + +top = gosnappi.NewConfig() + + FlowIPv4 = &Flow{ + TxNames: []string{"interface1"}, + RxNames: []string{"interface2"}, + FrameSize: 1500, + FlowName: "IPv4Flow", + EthFlow: &EthFlowParams{SrcMAC: "00:11:22:33:44:55", DstMAC: "00:11:22:33:44:66"}, + IPv4Flow: &IPv4FlowParams{IPv4Src: "192.0.2.1", IPv4Dst: "192.0.2.129", IPv4DstCount: 10}, + } + +FlowIPv4.CreateFlow(top) +FlowIPv4.AddEthHeader() +FlowIPv4.AddIPv4Header() +*/ +type Flow struct { + TxNames []string + RxNames []string + FrameSize uint32 + FlowName string + VLANFlow *VLANFlowParams + GREFlow *GREFlowParams + EthFlow *EthFlowParams + IPv4Flow *IPv4FlowParams + IPv6Flow *IPv6FlowParams + TCPFlow *TCPFlowParams + UDPFlow *UDPFlowParams + MPLSFlow *MPLSFlowParams + flow gosnappi.Flow +} + +// GREFlowParams is a struct to hold Ethernet traffic parameters. +type GREFlowParams struct { + Protocol uint32 +} + +// VLANFlowParams is a struct to hold VLAN traffic parameters. +type VLANFlowParams struct { + VLANId uint32 +} + +// EthFlowParams is a struct to hold Ethernet traffic parameters. +type EthFlowParams struct { + SrcMAC string + DstMAC string + SrcMACCount uint32 +} + +// IPv4FlowParams is a struct to hold IPv4 traffic parameters. +type IPv4FlowParams struct { + IPv4Src string + IPv4Dst string + IPv4SrcCount uint32 + IPv4DstCount uint32 + TTL uint32 +} + +// IPv6FlowParams is a struct to hold IPv6 traffic parameters. +type IPv6FlowParams struct { + IPv6Src string + IPv6Dst string + IPv6SrcCount uint32 + IPv6DstCount uint32 + HopLimit uint32 +} + +// TCPFlowParams is a struct to hold TCP traffic parameters. +type TCPFlowParams struct { + TCPSrcPort uint32 + TCPDstPort uint32 + TCPSrcCount uint32 + TCPDstCount uint32 +} + +// UDPFlowParams is a struct to hold UDP traffic parameters. +type UDPFlowParams struct { + UDPSrcPort uint32 + UDPDstPort uint32 + UDPSrcCount uint32 + UDPDstCount uint32 +} + +// MPLSFlowParams is a struct to hold MPLS traffic parameters. +type MPLSFlowParams struct { + MPLSLabel uint32 + MPLSExp uint32 +} + +// CreateFlow defines Tx and Rx end points for traffic flow. +func (f *Flow) CreateFlow(top gosnappi.Config) { + f.flow = top.Flows().Add().SetName(f.FlowName) + f.flow.Metrics().SetEnable(true) + f.flow.TxRx().Device(). + SetTxNames(f.TxNames). + SetRxNames(f.RxNames) + f.flow.Size().SetFixed(f.FrameSize) +} + +// AddEthHeader adds an Ethernet header to the flow. +func (f *Flow) AddEthHeader() { + eth := f.flow.Packet().Add().Ethernet() + eth.Src().SetValue(f.EthFlow.SrcMAC) + eth.Dst().SetValue(f.EthFlow.DstMAC) +} + +// AddGREHeader adds a GRE header to the flow. +func (f *Flow) AddGREHeader() { + greHdr := f.flow.Packet().Add().Gre() + switch f.GREFlow.Protocol { + case IanaMPLSEthertype: + greHdr.Protocol().SetValue(IanaMPLSEthertype) + case IanaIPv4Ethertype: + greHdr.Protocol().SetValue(IanaIPv4Ethertype) + case IanaIPv6Ethertype: + greHdr.Protocol().SetValue(IanaIPv6Ethertype) + default: + greHdr.Protocol().SetValue(IanaIPv4Ethertype) + } +} + +// AddVlanHeader adds a VLAN header to the flow. +func (f *Flow) AddVlanHeader() { + f.flow.Packet().Add().Vlan().Id().SetValue(f.VLANFlow.VLANId) +} + +// AddMPLSHeader adds an MPLS header to the flow. +func (f *Flow) AddMPLSHeader() { + mplsHdr := f.flow.Packet().Add().Mpls() + mplsHdr.Label().SetValue(f.MPLSFlow.MPLSLabel) + mplsHdr.TrafficClass().SetValue(f.MPLSFlow.MPLSExp) +} + +// AddIPv4Header adds an IPv4 header to the flow. +func (f *Flow) AddIPv4Header() { + ipv4Hdr := f.flow.Packet().Add().Ipv4() + if f.IPv4Flow.IPv4SrcCount != 0 { + ipv4Hdr.Src().Increment().SetStart(f.IPv4Flow.IPv4Src).SetCount(f.IPv4Flow.IPv4SrcCount) + } else { + ipv4Hdr.Src().SetValue(f.IPv4Flow.IPv4Src) + } + if f.IPv4Flow.IPv4DstCount != 0 { + ipv4Hdr.Dst().Increment().SetStart(f.IPv4Flow.IPv4Dst).SetCount(f.IPv4Flow.IPv4DstCount) + } else { + ipv4Hdr.Dst().SetValue(f.IPv4Flow.IPv4Dst) + } + if f.IPv4Flow.TTL != 0 { + ipv4Hdr.TimeToLive().SetValue(f.IPv4Flow.TTL) + } +} + +// AddIPv6Header adds an IPv6 header to the flow. +func (f *Flow) AddIPv6Header() { + ipv6Hdr := f.flow.Packet().Add().Ipv6() + if f.IPv6Flow.IPv6SrcCount != 0 { + ipv6Hdr.Src().Increment().SetStart(f.IPv6Flow.IPv6Src).SetCount(f.IPv6Flow.IPv6SrcCount) + } else { + ipv6Hdr.Src().SetValue(f.IPv6Flow.IPv6Src) + } + if f.IPv6Flow.IPv6DstCount != 0 { + ipv6Hdr.Dst().Increment().SetStart(f.IPv6Flow.IPv6Dst).SetCount(f.IPv6Flow.IPv6DstCount) + } else { + ipv6Hdr.Dst().SetValue(f.IPv6Flow.IPv6Dst) + } + if f.IPv6Flow.HopLimit != 0 { + ipv6Hdr.HopLimit().SetValue(f.IPv6Flow.HopLimit) + } +} + +// AddTCPHeader adds a TCP header to the flow. +func (f *Flow) AddTCPHeader() { + tcpHdr := f.flow.Packet().Add().Tcp() + if f.TCPFlow.TCPSrcCount != 0 { + tcpHdr.SrcPort().Increment().SetStart(f.TCPFlow.TCPSrcPort).SetCount(f.TCPFlow.TCPSrcCount) + } else { + tcpHdr.SrcPort().SetValue(f.TCPFlow.TCPSrcPort) + } + if f.TCPFlow.TCPDstCount != 0 { + tcpHdr.DstPort().Increment().SetStart(f.TCPFlow.TCPDstPort).SetCount(f.TCPFlow.TCPDstCount) + } else { + tcpHdr.DstPort().SetValue(f.TCPFlow.TCPDstPort) + } +} + +// AddUDPHeader adds a UDP header to the flow. +func (f *Flow) AddUDPHeader() { + udpHdr := f.flow.Packet().Add().Udp() + if f.UDPFlow.UDPSrcCount != 0 { + udpHdr.SrcPort().Increment().SetStart(f.UDPFlow.UDPSrcPort).SetCount(f.UDPFlow.UDPSrcCount) + } else { + udpHdr.SrcPort().SetValue(f.UDPFlow.UDPSrcPort) + } + if f.UDPFlow.UDPDstCount != 0 { + udpHdr.DstPort().Increment().SetStart(f.UDPFlow.UDPDstPort).SetCount(f.UDPFlow.UDPDstCount) + } else { + udpHdr.DstPort().SetValue(f.UDPFlow.UDPDstPort) + } +} diff --git a/internal/otg_helpers/otg_validation_helpers/otgvalidationhelpers.go b/internal/otg_helpers/otg_validation_helpers/otgvalidationhelpers.go new file mode 100644 index 00000000000..bbac0d33fe8 --- /dev/null +++ b/internal/otg_helpers/otg_validation_helpers/otgvalidationhelpers.go @@ -0,0 +1,102 @@ +// Package otgvalidationhelpers provides helper functions to validate OTG attributes for OTG tests. +package otgvalidationhelpers + +import ( + "fmt" + "testing" + "time" + + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/otg" + "github.com/openconfig/ygnmi/ygnmi" +) + +/* +OTGValidation is a struct to hold OTG validation parameters. + + params := &OTGValidation{ + Interface: &InterfaceParams{Names: []string{"Interface1", "Interface2"}, Ports: []string{"Port1", "Port2"}}, + Flow: &FlowParams{Name: "flow1", TolerancePct: 0.5}, + } + + if err := params.ValidatePortIsActive(t, ate); err != nil { + t.Errorf("ValidatePortIsActive(): got err: %q, want nil", err) + } + if err := params.IsIPv4Interfaceresolved(t, ate); err != nil { + t.Errorf("IsIPv4Interfaceresolved(): got err: %q, want nil", err) + } + if err := params.ValidateLossOnFlows(t, ate); err != nil { + t.Errorf("ValidateLossOnFlows(): got err: %q, want nil", err) + } +*/ +type OTGValidation struct { + Interface *InterfaceParams + Flow *FlowParams +} + +// InterfaceParams is a struct to hold OTG interface parameters. +type InterfaceParams struct { + Names []string + Ports []string +} + +// FlowParams is a struct to hold OTG flow parameters. +type FlowParams struct { + Name string + TolerancePct float32 +} + +// IsIPv4Interfaceresolved validates that the IPv4 interface is resolved based on the interface configured using otgconfighelpers. +func (v *OTGValidation) IsIPv4Interfaceresolved(t *testing.T, ate *ondatra.ATEDevice) error { + for _, intf := range v.Interface.Names { + val1, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().Interface(intf+".Eth").Ipv4NeighborAny().LinkLayerAddress().State(), time.Minute, func(val *ygnmi.Value[string]) bool { + return val.IsPresent() + }).Await(t) + if !ok { + return fmt.Errorf(`IPv4 %s gateway not resolved`, intf) + } + t.Logf(`IPv4 %s gateway resolved to: %s`, intf, val1) + } + return nil +} + +// IsIPv6Interfaceresolved validates that the IPv6 interface is resolved based on the interface configured using otgconfighelpers. +func (v *OTGValidation) IsIPv6Interfaceresolved(t *testing.T, ate *ondatra.ATEDevice) error { + for _, intf := range v.Interface.Names { + val1, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().Interface(intf+".Eth").Ipv6NeighborAny().LinkLayerAddress().State(), time.Minute, func(val *ygnmi.Value[string]) bool { + return val.IsPresent() + }).Await(t) + if !ok { + return fmt.Errorf(`IPv6 %s gateway not resolved`, intf) + } + t.Logf(`IPv6 %s gateway resolved to: %s`, intf, val1) + } + return nil +} + +// ValidateLossOnFlows validates the percentage of traffic loss on the flows. +func (v *OTGValidation) ValidateLossOnFlows(t *testing.T, ate *ondatra.ATEDevice) error { + outPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(v.Flow.Name).Counters().OutPkts().State()) + if outPkts == 0 { + t.Fatalf("Get(out packets for flow %q): got %v, want nonzero", v.Flow.Name, outPkts) + } + inPkts := gnmi.Get(t, ate.OTG(), gnmi.OTG().Flow(v.Flow.Name).Counters().InPkts().State()) + lossPct := 100 * float32(outPkts-inPkts) / float32(outPkts) + if lossPct > v.Flow.TolerancePct { + return fmt.Errorf("Get(traffic loss for flow %q): got %v percent, want < %v percent", v.Flow.Name, lossPct, v.Flow.TolerancePct) + } + t.Logf("Flow %q, inPkts %d, outPkts %d, lossPct %v", v.Flow.Name, inPkts, outPkts, lossPct) + return nil +} + +// ValidatePortIsActive validates the OTG port status. +func (v *OTGValidation) ValidatePortIsActive(t *testing.T, ate *ondatra.ATEDevice) error { + for _, port := range v.Interface.Ports { + PortStatus := gnmi.Get(t, ate.OTG(), gnmi.OTG().Port(port).Link().State()) + if want := otg.Port_Link_UP; PortStatus != want { + return fmt.Errorf("Get(OTG port status): got %v, want %v", PortStatus, want) + } + } + return nil +} diff --git a/internal/p4rtutils/p4rtutils.go b/internal/p4rtutils/p4rtutils.go index 34611fb2384..2972aeaef95 100644 --- a/internal/p4rtutils/p4rtutils.go +++ b/internal/p4rtutils/p4rtutils.go @@ -28,7 +28,7 @@ import ( "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" - p4_v1 "github.com/p4lang/p4runtime/go/p4/v1" + p4V1 "github.com/p4lang/p4runtime/go/p4/v1" ) // Some hardcoding to simplify things @@ -51,7 +51,7 @@ var ( // ACLWbbIngressTableEntryInfo defines struct for wbb acl table type ACLWbbIngressTableEntryInfo struct { - Type p4_v1.Update_Type + Type p4V1.Update_Type IsIpv4 uint8 IsIpv6 uint8 EtherType uint16 @@ -65,40 +65,40 @@ type ACLWbbIngressTableEntryInfo struct { } // Filling up P4RT Structs is a bit cumbersome, wrap things to simplify -func aclWbbIngressTableEntryGet(info *ACLWbbIngressTableEntryInfo) *p4_v1.Update { +func aclWbbIngressTableEntryGet(info *ACLWbbIngressTableEntryInfo) *p4V1.Update { if info == nil { glog.Fatal("Nil info") } - matchFields := []*p4_v1.FieldMatch{} + var matchFields []*p4V1.FieldMatch if info.IsIpv4 > 0 { - matchFields = append(matchFields, &p4_v1.FieldMatch{ + matchFields = append(matchFields, &p4V1.FieldMatch{ FieldId: WbbMatchMap["is_ipv4"], - FieldMatchType: &p4_v1.FieldMatch_Optional_{ - Optional: &p4_v1.FieldMatch_Optional{ - Value: []byte{byte(info.IsIpv4)}, + FieldMatchType: &p4V1.FieldMatch_Optional_{ + Optional: &p4V1.FieldMatch_Optional{ + Value: []byte{info.IsIpv4}, }, }, }) } if info.IsIpv6 > 0 { - matchFields = append(matchFields, &p4_v1.FieldMatch{ + matchFields = append(matchFields, &p4V1.FieldMatch{ FieldId: WbbMatchMap["is_ipv6"], - FieldMatchType: &p4_v1.FieldMatch_Optional_{ - Optional: &p4_v1.FieldMatch_Optional{ - Value: []byte{byte(info.IsIpv6)}, + FieldMatchType: &p4V1.FieldMatch_Optional_{ + Optional: &p4V1.FieldMatch_Optional{ + Value: []byte{info.IsIpv6}, }, }, }) } if info.EtherTypeMask > 0 { - matchFields = append(matchFields, &p4_v1.FieldMatch{ + matchFields = append(matchFields, &p4V1.FieldMatch{ FieldId: WbbMatchMap["ether_type"], - FieldMatchType: &p4_v1.FieldMatch_Ternary_{ - Ternary: &p4_v1.FieldMatch_Ternary{ + FieldMatchType: &p4V1.FieldMatch_Ternary_{ + Ternary: &p4V1.FieldMatch_Ternary{ Value: []byte{ byte(info.EtherType >> 8), byte(info.EtherType & 0xFF), @@ -113,22 +113,22 @@ func aclWbbIngressTableEntryGet(info *ACLWbbIngressTableEntryInfo) *p4_v1.Update } if info.TTLMask > 0 { - matchFields = append(matchFields, &p4_v1.FieldMatch{ + matchFields = append(matchFields, &p4V1.FieldMatch{ FieldId: WbbMatchMap["ttl"], - FieldMatchType: &p4_v1.FieldMatch_Ternary_{ - Ternary: &p4_v1.FieldMatch_Ternary{ - Value: []byte{byte(info.TTL)}, - Mask: []byte{byte(info.TTLMask)}, + FieldMatchType: &p4V1.FieldMatch_Ternary_{ + Ternary: &p4V1.FieldMatch_Ternary{ + Value: []byte{info.TTL}, + Mask: []byte{info.TTLMask}, }, }, }) } if info.OuterVlanIDMask > 0 { - matchFields = append(matchFields, &p4_v1.FieldMatch{ + matchFields = append(matchFields, &p4V1.FieldMatch{ FieldId: WbbMatchMap["outer_vlan_id"], - FieldMatchType: &p4_v1.FieldMatch_Ternary_{ - Ternary: &p4_v1.FieldMatch_Ternary{ + FieldMatchType: &p4V1.FieldMatch_Ternary_{ + Ternary: &p4V1.FieldMatch_Ternary{ Value: []byte{ byte((info.OuterVlanID >> 8) & 0xF), byte(info.OuterVlanID & 0xFF), @@ -142,16 +142,16 @@ func aclWbbIngressTableEntryGet(info *ACLWbbIngressTableEntryInfo) *p4_v1.Update }) } - update := &p4_v1.Update{ + update := &p4V1.Update{ Type: info.Type, - Entity: &p4_v1.Entity{ - Entity: &p4_v1.Entity_TableEntry{ - TableEntry: &p4_v1.TableEntry{ + Entity: &p4V1.Entity{ + Entity: &p4V1.Entity_TableEntry{ + TableEntry: &p4V1.TableEntry{ TableId: WbbTableMap["acl_wbb_ingress_table"], Match: matchFields, - Action: &p4_v1.TableAction{ - Type: &p4_v1.TableAction_Action{ - Action: &p4_v1.Action{ + Action: &p4V1.TableAction{ + Type: &p4V1.TableAction_Action{ + Action: &p4V1.Action{ ActionId: WbbActionsMap["acl_wbb_ingress_trap"], }, }, @@ -172,8 +172,8 @@ func aclWbbIngressTableEntryGet(info *ACLWbbIngressTableEntryInfo) *p4_v1.Update } // ACLWbbIngressTableEntryGet returns acl table updates -func ACLWbbIngressTableEntryGet(infoList []*ACLWbbIngressTableEntryInfo) []*p4_v1.Update { - var updates []*p4_v1.Update +func ACLWbbIngressTableEntryGet(infoList []*ACLWbbIngressTableEntryInfo) []*p4V1.Update { + var updates []*p4V1.Update for _, info := range infoList { updates = append(updates, aclWbbIngressTableEntryGet(info)) diff --git a/internal/rundata/local.go b/internal/rundata/local.go index 1e22bcb90b1..52ad488dd94 100644 --- a/internal/rundata/local.go +++ b/internal/rundata/local.go @@ -16,6 +16,7 @@ package rundata import ( "errors" + "flag" "fmt" "os" "path/filepath" @@ -24,9 +25,7 @@ import ( "strings" "time" - "flag" - - gitv5 "github.com/go-git/go-git/v5" + gitV5 "github.com/go-git/go-git/v5" "github.com/golang/glog" ) @@ -49,7 +48,7 @@ func buildInfo(m map[string]string) { } // gitOrigin returns the fetch URL of the "origin" remote. -func gitOrigin(repo *gitv5.Repository) (string, error) { +func gitOrigin(repo *gitV5.Repository) (string, error) { origin, err := repo.Remote("origin") if err != nil { return "", err @@ -62,7 +61,7 @@ func gitOrigin(repo *gitv5.Repository) (string, error) { } // gitHead returns the commit hash and the commit timestamp at HEAD. -func gitHead(repo *gitv5.Repository) (string, time.Time, error) { +func gitHead(repo *gitV5.Repository) (string, time.Time, error) { var zero time.Time head, err := repo.Head() if err != nil { @@ -77,7 +76,7 @@ func gitHead(repo *gitv5.Repository) (string, time.Time, error) { // gitInfoWithRepo populates the git properties from a given git repo // and returns the path to the working directory. -func gitInfoWithRepo(m map[string]string, repo *gitv5.Repository) string { +func gitInfoWithRepo(m map[string]string, repo *gitV5.Repository) string { wt, err := repo.Worktree() if err != nil { return "" @@ -117,7 +116,7 @@ func gitInfo(m map[string]string) string { if err != nil { return "" } - repo, err := gitv5.PlainOpenWithOptions(cwd, &gitv5.PlainOpenOptions{ + repo, err := gitV5.PlainOpenWithOptions(cwd, &gitV5.PlainOpenOptions{ DetectDotGit: true, }) if err != nil { @@ -128,18 +127,18 @@ func gitInfo(m map[string]string) string { // fpPath returns the package path of a test file path under the // featureprofiles repo. -func fpPath(testpath string) string { +func fpPath(testPath string) string { const part = "/featureprofiles/" - i := strings.LastIndex(testpath, part) + i := strings.LastIndex(testPath, part) if i < 0 { return "" } i += len(part) - j := strings.LastIndexByte(testpath, '/') + j := strings.LastIndexByte(testPath, '/') if j < 0 || j < i { return "" } - return testpath[i:j] + return testPath[i:j] } // testPath detects the relative path of the test to the base of the diff --git a/internal/rundata/local_test.go b/internal/rundata/local_test.go index 87a1a0e3f13..4670fedcb43 100644 --- a/internal/rundata/local_test.go +++ b/internal/rundata/local_test.go @@ -15,6 +15,7 @@ package rundata import ( + "flag" "fmt" "os/exec" "runtime/debug" @@ -22,10 +23,8 @@ import ( "testing" "time" - "flag" - "github.com/go-git/go-billy/v5/memfs" - gitv5 "github.com/go-git/go-git/v5" + gitV5 "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" @@ -55,10 +54,10 @@ func TestBuildInfo(t *testing.T) { } } -func newGitRepo() (*gitv5.Repository, error) { +func newGitRepo() (*gitV5.Repository, error) { // Use repo.Storer to get the object storer, and // repo.Worktree().Filesystem to get the worktree. - return gitv5.Init( + return gitV5.Init( memory.NewStorage(), memfs.New(), ) @@ -80,7 +79,7 @@ var commitSignature = &object.Signature{ When: time.Now().Round(time.Second), // Git only keeps time in seconds. } -func addCommit(repo *gitv5.Repository) (plumbing.Hash, error) { +func addCommit(repo *gitV5.Repository) (plumbing.Hash, error) { var emptyHash plumbing.Hash wt, err := repo.Worktree() @@ -97,7 +96,7 @@ func addCommit(repo *gitv5.Repository) (plumbing.Hash, error) { f.Close() wt.Add("foo") - return wt.Commit("commit message", &gitv5.CommitOptions{ + return wt.Commit("commit message", &gitV5.CommitOptions{ Author: commitSignature, }) } @@ -317,7 +316,7 @@ func TestGitInfo(t *testing.T) { got := make(map[string]string) gotWd := gitInfo(got) - if gotWd != string(wantWd) { + if gotWd != wantWd { t.Errorf("gitInfo got %q, want %q", gotWd, wantWd) } t.Log(got) diff --git a/internal/rundata/rundata.go b/internal/rundata/rundata.go index c41853a414b..21aa7333ea5 100644 --- a/internal/rundata/rundata.go +++ b/internal/rundata/rundata.go @@ -51,13 +51,12 @@ package rundata import ( "context" + "flag" "fmt" "sort" "strings" "time" - "flag" - "github.com/openconfig/featureprofiles/internal/metadata" "github.com/openconfig/ondatra/binding" ) diff --git a/internal/security/acctz/acctz.go b/internal/security/acctz/acctz.go new file mode 100644 index 00000000000..6f475e14e1e --- /dev/null +++ b/internal/security/acctz/acctz.go @@ -0,0 +1,1021 @@ +// Copyright 2024 Google LLC +// +// 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. + +// Package acctz provides helper APIs to simplify writing acctz test cases. +package acctz + +import ( + "context" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "strconv" + "testing" + "time" + + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + systempb "github.com/openconfig/gnoi/system" + acctzpb "github.com/openconfig/gnsi/acctz" + authzpb "github.com/openconfig/gnsi/authz" + cpb "github.com/openconfig/gnsi/credentialz" + gribi "github.com/openconfig/gribi/v1/proto/service" + tpb "github.com/openconfig/kne/proto/topo" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/binding" + "github.com/openconfig/ondatra/binding/introspect" + ondatragnmi "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" + "golang.org/x/crypto/ssh" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/types/known/anypb" +) + +const ( + successUsername = "acctztestuser" + successPassword = "verysecurepassword" + failUsername = "bilbo" + failPassword = "baggins" + failRoleName = "acctz-fp-test-fail" + successCliCommand = "show version" + failCliCommand = "show version" + shellCommand = "uname -a" + gnmiCapabilitiesPath = "/gnmi.gNMI/Capabilities" + gnoiPingPath = "/gnoi.system.System/Ping" + gnsiGetPath = "/gnsi.authz.v1.Authz/Get" + gribiGetPath = "/gribi.gRIBI/Get" + p4rtCapabilitiesPath = "/p4.v1.P4Runtime/Capabilities" + defaultSSHPort = 22 + ipProto = 6 +) + +var gRPCClientAddr net.Addr + +func setupUserPassword(t *testing.T, dut *ondatra.DUTDevice, username, password string) { + request := &cpb.RotateAccountCredentialsRequest{ + Request: &cpb.RotateAccountCredentialsRequest_Password{ + Password: &cpb.PasswordRequest{ + Accounts: []*cpb.PasswordRequest_Account{ + { + Account: username, + Password: &cpb.PasswordRequest_Password{ + Value: &cpb.PasswordRequest_Password_Plaintext{ + Plaintext: password, + }, + }, + Version: "v1.0", + CreatedOn: uint64(time.Now().Unix()), + }, + }, + }, + }, + } + + credzClient := dut.RawAPIs().GNSI(t).Credentialz() + credzRotateClient, err := credzClient.RotateAccountCredentials(context.Background()) + if err != nil { + t.Fatalf("Failed fetching credentialz rotate account credentials client, error: %s", err) + } + err = credzRotateClient.Send(request) + if err != nil { + t.Fatalf("Failed sending credentialz rotate account credentials request, error: %s", err) + } + _, err = credzRotateClient.Recv() + if err != nil { + t.Fatalf("Failed receiving credentialz rotate account credentials response, error: %s", err) + } + err = credzRotateClient.Send(&cpb.RotateAccountCredentialsRequest{ + Request: &cpb.RotateAccountCredentialsRequest_Finalize{ + Finalize: request.GetFinalize(), + }, + }) + if err != nil { + t.Fatalf("Failed sending credentialz rotate account credentials finalize request, error: %s", err) + } + + // Brief sleep for finalize to get processed. + time.Sleep(time.Second) +} + +func nokiaFailCliRole(t *testing.T) *gnmipb.SetRequest { + failRoleData, err := json.Marshal([]any{ + map[string]any{ + "services": []string{"cli"}, + "cli": map[string][]string{ + "deny-command-list": {failCliCommand}, + }, + }, + }) + if err != nil { + t.Fatalf("Error with json marshal: %v", err) + } + + return &gnmipb.SetRequest{ + Prefix: &gnmipb.Path{ + Origin: "native", + }, + Replace: []*gnmipb.Update{ + { + Path: &gnmipb.Path{ + Elem: []*gnmipb.PathElem{ + {Name: "system"}, + {Name: "aaa"}, + {Name: "authorization"}, + {Name: "role", Key: map[string]string{"rolename": failRoleName}}, + }, + }, + Val: &gnmipb.TypedValue{ + Value: &gnmipb.TypedValue_JsonIetfVal{ + JsonIetfVal: failRoleData, + }, + }, + }, + }, + } +} + +// SetupUsers Setup users for acctz tests and optionally configure cli role for denied commands. +func SetupUsers(t *testing.T, dut *ondatra.DUTDevice, configureFailCliRole bool) { + auth := &oc.System_Aaa_Authentication{} + successUser := auth.GetOrCreateUser(successUsername) + successUser.SetRole(oc.AaaTypes_SYSTEM_DEFINED_ROLES_SYSTEM_ROLE_ADMIN) + failUser := auth.GetOrCreateUser(failUsername) + if configureFailCliRole { + var SetRequest *gnmipb.SetRequest + + // Create failure cli role in native. + switch dut.Vendor() { + case ondatra.NOKIA: + SetRequest = nokiaFailCliRole(t) + } + + gnmiClient := dut.RawAPIs().GNMI(t) + if _, err := gnmiClient.Set(context.Background(), SetRequest); err != nil { + t.Fatalf("Unexpected error configuring role: %v", err) + } + + failUser.SetRole(oc.UnionString(failRoleName)) + } + ondatragnmi.Update(t, dut, ondatragnmi.OC().System().Aaa().Authentication().Config(), auth) + setupUserPassword(t, dut, successUsername, successPassword) + setupUserPassword(t, dut, failUsername, failPassword) +} + +func getGrpcTarget(t *testing.T, dut *ondatra.DUTDevice, service introspect.Service) string { + dialTarget := introspect.DUTDialer(t, dut, service).DialTarget + resolvedTarget, err := net.ResolveTCPAddr("tcp", dialTarget) + if err != nil { + t.Fatalf("Failed resolving %s target %s", service, dialTarget) + } + t.Logf("Target for %s service: %s", service, resolvedTarget) + return resolvedTarget.String() +} + +func getSSHTarget(t *testing.T, dut *ondatra.DUTDevice) string { + var serviceDUT interface { + Service(string) (*tpb.Service, error) + } + + var target string + err := binding.DUTAs(dut.RawAPIs().BindingDUT(), &serviceDUT) + if err != nil { + t.Log("DUT does not support `Service` function, will attempt to resolve dut name field.") + + // Suppose ssh could be not 22 in some cases but don't think this is exposed by introspect. + dialTarget := fmt.Sprintf("%s:%d", dut.Name(), defaultSSHPort) + resolvedTarget, err := net.ResolveTCPAddr("tcp", dialTarget) + if err != nil { + t.Fatalf("Failed resolving ssh target %s", dialTarget) + } + target = resolvedTarget.String() + } else { + dutSSHService, err := serviceDUT.Service("ssh") + if err != nil { + t.Fatal(err) + } + target = fmt.Sprintf("%s:%d", dutSSHService.GetOutsideIp(), dutSSHService.GetOutside()) + } + + t.Logf("Target for ssh service: %s", target) + return target +} + +func dialGrpc(t *testing.T, target string) *grpc.ClientConn { + conn, err := grpc.NewClient( + target, + grpc.WithTransportCredentials( + credentials.NewTLS( + &tls.Config{ + InsecureSkipVerify: true, + }, + ), + ), + grpc.WithContextDialer(func(ctx context.Context, a string) (net.Conn, error) { + dst, err := net.ResolveTCPAddr("tcp", a) + if err != nil { + return nil, err + } + c, err := net.DialTCP("tcp", nil, dst) + if err != nil { + return nil, err + } + gRPCClientAddr = c.LocalAddr() + return c, err + })) + if err != nil { + t.Fatalf("Got unexpected error dialing gRPC target %q, error: %v", target, err) + } + + return conn +} + +func dialSSH(t *testing.T, username, password, target string) (*ssh.Client, io.WriteCloser) { + conn, err := ssh.Dial( + "tcp", + target, + &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.Password(password), + ssh.KeyboardInteractive( + func(user, instruction string, questions []string, echos []bool) ([]string, error) { + answers := make([]string, len(questions)) + for i := range answers { + answers[i] = password + } + return answers, nil + }, + ), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + }) + if err != nil { + t.Fatalf("Got unexpected error dialing ssh target %s, error: %v", target, err) + } + + sess, err := conn.NewSession() + if err != nil { + t.Fatalf("Failed creating ssh session, error: %s", err) + } + + w, err := sess.StdinPipe() + if err != nil { + t.Fatal(err) + } + + term := ssh.TerminalModes{ + ssh.ECHO: 0, + ssh.TTY_OP_ISPEED: 14400, + ssh.TTY_OP_OSPEED: 14400, + } + + err = sess.RequestPty( + "xterm", + 40, + 80, + term, + ) + if err != nil { + t.Fatal(err) + } + + err = sess.Shell() + if err != nil { + t.Fatal(err) + } + + return conn, w +} + +func getHostPortInfo(t *testing.T, address string) (string, uint32) { + ip, port, err := net.SplitHostPort(address) + if err != nil { + t.Fatal(err) + } + portNumber, err := strconv.Atoi(port) + if err != nil { + t.Fatal(err) + } + return ip, uint32(portNumber) +} + +// SendGnmiRPCs Setup gNMI test RPCs (successful and failed) to be used in the acctz client tests. +func SendGnmiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we just use introspection + // but that won't get us v4 and v6, it will just get us whatever is configured in binding, + // so while the test asks for v4 and v6 we'll just be doing it for whatever we get. + target := getGrpcTarget(t, dut, introspect.GNMI) + + var records []*acctzpb.RecordResponse + grpcConn := dialGrpc(t, target) + gnmiClient := gnmipb.NewGNMIClient(grpcConn) + ctx := context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) + + // Send an unsuccessful gNMI capabilities request (bad creds in context). + _, err := gnmiClient.Capabilities(ctx, &gnmipb.CapabilityRequest{}) + if err != nil { + t.Logf("Got expected error fetching capabilities with bad creds, error: %s", err) + } else { + t.Fatal("Did not get expected error fetching capabilities with bad creds.") + } + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNMI, + RpcName: gnmiCapabilitiesPath, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_DENY, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_UNSPECIFIED, + }, + User: &acctzpb.UserDetail{ + Identity: failUsername, + }, + }, + }) + + // Send a successful gNMI capabilities request. + ctx = context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) + req := &gnmipb.CapabilityRequest{} + payload, err := anypb.New(req) + if err != nil { + t.Fatal("Failed creating anypb payload.") + } + _, err = gnmiClient.Capabilities(ctx, req) + if err != nil { + t.Fatalf("Error fetching capabilities, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, gRPCClientAddr.String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNMI, + RpcName: gnmiCapabilitiesPath, + Payload: &acctzpb.GrpcService_ProtoVal{ + ProtoVal: payload, + }, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: successUsername, + }, + }, + }) + + return records +} + +// SendGnoiRPCs Setup gNOI test RPCs (successful and failed) to be used in the acctz client tests. +func SendGnoiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we just use introspection + // but that won't get us v4 and v6, it will just get us whatever is configured in binding, + // so while the test asks for v4 and v6 we'll just be doing it for whatever we get. + target := getGrpcTarget(t, dut, introspect.GNOI) + + var records []*acctzpb.RecordResponse + grpcConn := dialGrpc(t, target) + gnoiSystemClient := systempb.NewSystemClient(grpcConn) + ctx := context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) + + // Send an unsuccessful gNOI system time request (bad creds in context), we don't + // care about receiving on it, just want to make the request. + gnoiSystemPingClient, err := gnoiSystemClient.Ping(ctx, &systempb.PingRequest{ + Destination: "127.0.0.1", + Count: 1, + }) + if err != nil { + t.Fatalf("Got unexpected error getting gnoi system time client, error: %s", err) + } + + _, err = gnoiSystemPingClient.Recv() + if err != nil { + t.Logf("Got expected error getting gnoi system time with bad creds, error: %s", err) + } + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNOI, + RpcName: gnoiPingPath, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_DENY, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_UNSPECIFIED, + }, + User: &acctzpb.UserDetail{ + Identity: failUsername, + }, + }, + }) + + // Send a successful gNOI ping request. + ctx = context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) + req := &systempb.PingRequest{ + Destination: "127.0.0.1", + Count: 1, + } + payload, err := anypb.New(req) + if err != nil { + t.Fatal("Failed creating anypb payload.") + } + gnoiSystemPingClient, err = gnoiSystemClient.Ping(ctx, req) + if err != nil { + t.Fatalf("Error fetching gnoi system time, error: %s", err) + } + _, err = gnoiSystemPingClient.Recv() + if err != nil { + t.Fatalf("Got unexpected error getting gnoi system time, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, gRPCClientAddr.String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNOI, + RpcName: gnoiPingPath, + Payload: &acctzpb.GrpcService_ProtoVal{ + ProtoVal: payload, + }, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: successUsername, + }, + }, + }) + + return records +} + +// SendGnsiRPCs Setup gNSI test RPCs (successful and failed) to be used in the acctz client tests. +func SendGnsiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we just use introspection + // but that won't get us v4 and v6, it will just get us whatever is configured in binding, + // so while the test asks for v4 and v6 we'll just be doing it for whatever we get. + target := getGrpcTarget(t, dut, introspect.GNSI) + + var records []*acctzpb.RecordResponse + grpcConn := dialGrpc(t, target) + authzClient := authzpb.NewAuthzClient(grpcConn) + ctx := context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) + + // Send an unsuccessful gNSI authz get request (bad creds in context), we don't + // care about receiving on it, just want to make the request. + _, err := authzClient.Get(ctx, &authzpb.GetRequest{}) + if err != nil { + t.Logf("Got expected error fetching authz policy with bad creds, error: %s", err) + } else { + t.Fatal("Did not get expected error fetching authz policy with bad creds.") + } + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNSI, + RpcName: gnsiGetPath, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_DENY, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_UNSPECIFIED, + }, + User: &acctzpb.UserDetail{ + Identity: failUsername, + }, + }, + }) + + // Send a successful gNSI authz get request. + ctx = context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) + req := &authzpb.GetRequest{} + payload, err := anypb.New(req) + if err != nil { + t.Fatal("Failed creating anypb payload.") + } + _, err = authzClient.Get(ctx, &authzpb.GetRequest{}) + if err != nil { + t.Fatalf("Error fetching authz policy, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, gRPCClientAddr.String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GNSI, + RpcName: gnsiGetPath, + Payload: &acctzpb.GrpcService_ProtoVal{ + ProtoVal: payload, + }, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: successUsername, + }, + }, + }) + + return records +} + +// SendGribiRPCs Setup gRIBI test RPCs (successful and failed) to be used in the acctz client tests. +func SendGribiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we just use introspection + // but that won't get us v4 and v6, it will just get us whatever is configured in binding, + // so while the test asks for v4 and v6 we'll just be doing it for whatever we get. + target := getGrpcTarget(t, dut, introspect.GRIBI) + + var records []*acctzpb.RecordResponse + grpcConn := dialGrpc(t, target) + gribiClient := gribi.NewGRIBIClient(grpcConn) + ctx := context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) + + // Send an unsuccessful gRIBI get request (bad creds in context), we don't + // care about receiving on it, just want to make the request. + gribiGetClient, err := gribiClient.Get( + ctx, + &gribi.GetRequest{ + NetworkInstance: &gribi.GetRequest_All{}, + Aft: gribi.AFTType_IPV4, + }, + ) + if err != nil { + t.Fatalf("Got unexpected error during gribi get request, error: %s", err) + } + _, err = gribiGetClient.Recv() + if err != nil { + t.Logf("Got expected error during gribi recv request, error: %s", err) + } + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GRIBI, + RpcName: gribiGetPath, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_DENY, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_UNSPECIFIED, + }, + User: &acctzpb.UserDetail{ + Identity: failUsername, + }, + }, + }) + + // Send a successful gRIBI get request. + ctx = context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) + req := &gribi.GetRequest{ + NetworkInstance: &gribi.GetRequest_All{}, + Aft: gribi.AFTType_IPV4, + } + payload, err := anypb.New(req) + if err != nil { + t.Fatal("Failed creating anypb payload.") + } + gribiGetClient, err = gribiClient.Get(ctx, req) + if err != nil { + t.Fatalf("Got unexpected error during gribi get request, error: %s", err) + } + _, err = gribiGetClient.Recv() + if err != nil { + // Having no messages, we get an EOF so this is not a failure. + if !errors.Is(err, io.EOF) { + t.Fatalf("Got unexpected error during gribi recv request, error: %s", err) + } + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, gRPCClientAddr.String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_GRIBI, + RpcName: gribiGetPath, + Payload: &acctzpb.GrpcService_ProtoVal{ + ProtoVal: payload, + }, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: successUsername, + }, + }, + }) + + return records +} + +// SendP4rtRPCs Setup P4RT test RPCs (successful and failed) to be used in the acctz client tests. +func SendP4rtRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we just use introspection + // but that won't get us v4 and v6, it will just get us whatever is configured in binding, + // so while the test asks for v4 and v6 we'll just be doing it for whatever we get. + target := getGrpcTarget(t, dut, introspect.P4RT) + + var records []*acctzpb.RecordResponse + grpcConn := dialGrpc(t, target) + ctx := context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) + p4rtclient := p4pb.NewP4RuntimeClient(grpcConn) + _, err := p4rtclient.Capabilities(ctx, &p4pb.CapabilitiesRequest{}) + if err != nil { + t.Logf("Got expected error getting p4rt capabilities with no creds, error: %s", err) + } else { + t.Fatal("Did not get expected error fetching pr4t capabilities with no creds.") + } + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_P4RT, + RpcName: p4rtCapabilitiesPath, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_DENY, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_UNSPECIFIED, + }, + User: &acctzpb.UserDetail{ + Identity: failUsername, + }, + }, + }) + + ctx = context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) + ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) + req := &p4pb.CapabilitiesRequest{} + payload, err := anypb.New(req) + if err != nil { + t.Fatal("Failed creating anypb payload.") + } + _, err = p4rtclient.Capabilities(ctx, req) + if err != nil { + t.Fatalf("Error fetching p4rt capabilities, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, gRPCClientAddr.String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_GrpcService{ + GrpcService: &acctzpb.GrpcService{ + ServiceType: acctzpb.GrpcService_GRPC_SERVICE_TYPE_P4RT, + RpcName: p4rtCapabilitiesPath, + Payload: &acctzpb.GrpcService_ProtoVal{ + ProtoVal: payload, + }, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_ONCE, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: successUsername, + }, + }, + }) + + return records +} + +// SendSuccessCliCommand Setup test CLI command (successful) to be used in the acctz client tests. +func SendSuccessCliCommand(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we use this workaround + // because ssh isn't exposed in introspection. + target := getSSHTarget(t, dut) + + var records []*acctzpb.RecordResponse + + sshConn, w := dialSSH(t, successUsername, successPassword, target) + defer func() { + // Give things a second to percolate then close the connection. + time.Sleep(3 * time.Second) + err := sshConn.Close() + if err != nil { + t.Logf("Error closing tcp(ssh) connection, will ignore, error: %s", err) + } + }() + + _, err := w.Write([]byte(fmt.Sprintf("%s\n", successCliCommand))) + if err != nil { + t.Fatalf("Failed sending cli command, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, sshConn.LocalAddr().String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_CmdService{ + CmdService: &acctzpb.CommandService{ + ServiceType: acctzpb.CommandService_CMD_SERVICE_TYPE_CLI, + Cmd: successCliCommand, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_OPERATION, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: successUsername, + }, + }, + }) + + return records +} + +// SendFailCliCommand Setup test CLI command (failed) to be used in the acctz client tests. +func SendFailCliCommand(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we use this workaround + // because ssh isn't exposed in introspection. + target := getSSHTarget(t, dut) + + var records []*acctzpb.RecordResponse + sshConn, w := dialSSH(t, failUsername, failPassword, target) + + defer func() { + // Give things a second to percolate then close the connection. + time.Sleep(3 * time.Second) + err := sshConn.Close() + if err != nil { + t.Logf("Error closing tcp(ssh) connection, will ignore, error: %s", err) + } + }() + + _, err := w.Write([]byte(fmt.Sprintf("%s\n", failCliCommand))) + if err != nil { + t.Fatalf("Failed sending cli command, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, sshConn.LocalAddr().String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_CmdService{ + CmdService: &acctzpb.CommandService{ + ServiceType: acctzpb.CommandService_CMD_SERVICE_TYPE_CLI, + Cmd: failCliCommand, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_DENY, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_OPERATION, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_SUCCESS, + Cause: "authentication_method: local", + }, + User: &acctzpb.UserDetail{ + Identity: failUsername, + Role: failRoleName, + }, + }, + }) + + return records +} + +// SendShellCommand Setup test shell command (successful) to be used in the acctz client tests. +func SendShellCommand(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordResponse { + // Per https://github.com/openconfig/featureprofiles/issues/2637, waiting to see what the + // "best"/"preferred" way is to get the v4/v6 of the dut. For now, we use this workaround + // because ssh isn't exposed in introspection. + target := getSSHTarget(t, dut) + + var records []*acctzpb.RecordResponse + shellUsername := successUsername + shellPassword := successPassword + + switch dut.Vendor() { + case ondatra.NOKIA: + // Assuming linuxadmin is present and ssh'ing directly via this user gets us to shell + // straight away so this is easy button to trigger a shell record. + shellUsername = "linuxadmin" + shellPassword = "NokiaSrl1!" + } + + sshConn, w := dialSSH(t, shellUsername, shellPassword, target) + defer func() { + // Give things a second to percolate then close the connection. + time.Sleep(3 * time.Second) + err := sshConn.Close() + if err != nil { + t.Logf("Error closing tcp(ssh) connection, will ignore, error: %s", err) + } + }() + + // This might not work for other vendors, so probably we can have a switch here and pass + // the writer to func per vendor if needed. + _, err := w.Write([]byte(fmt.Sprintf("%s\n", shellCommand))) + if err != nil { + t.Fatalf("Failed sending cli command, error: %s", err) + } + + // Remote from the perspective of the router. + remoteIP, remotePort := getHostPortInfo(t, sshConn.LocalAddr().String()) + localIP, localPort := getHostPortInfo(t, target) + + records = append(records, &acctzpb.RecordResponse{ + ServiceRequest: &acctzpb.RecordResponse_CmdService{ + CmdService: &acctzpb.CommandService{ + ServiceType: acctzpb.CommandService_CMD_SERVICE_TYPE_SHELL, + Cmd: shellCommand, + Authz: &acctzpb.AuthzDetail{ + Status: acctzpb.AuthzDetail_AUTHZ_STATUS_PERMIT, + }, + }, + }, + SessionInfo: &acctzpb.SessionInfo{ + Status: acctzpb.SessionInfo_SESSION_STATUS_OPERATION, + LocalAddress: localIP, + LocalPort: localPort, + RemoteAddress: remoteIP, + RemotePort: remotePort, + IpProto: ipProto, + Authn: &acctzpb.AuthnDetail{ + Type: acctzpb.AuthnDetail_AUTHN_TYPE_UNSPECIFIED, + Status: acctzpb.AuthnDetail_AUTHN_STATUS_UNSPECIFIED, + }, + User: &acctzpb.UserDetail{ + Identity: shellUsername, + }, + }, + }) + + return records +} diff --git a/internal/security/credz/credz.go b/internal/security/credz/credz.go new file mode 100644 index 00000000000..4625c51afb0 --- /dev/null +++ b/internal/security/credz/credz.go @@ -0,0 +1,663 @@ +// Copyright 2024 Google LLC +// +// 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. + +// Package credz provides helper APIs to simplify writing credentialz test cases. +package credz + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + "os" + "os/exec" + "strings" + "testing" + "time" + + cpb "github.com/openconfig/gnsi/credentialz" + tpb "github.com/openconfig/kne/proto/topo" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/binding" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "golang.org/x/crypto/ssh" +) + +const ( + lowercase = "abcdefghijklmnopqrstuvwxyz" + uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + digits = "0123456789" + symbols = "!@#$%^&*(){}[]\\|:;\"'" + space = " " + userKey = "testuser" + dutKey = "dut" + caKey = "ca" + minPasswordLength = 24 + maxPasswordLength = 32 + defaultSSHPort = 22 +) + +var ( + charClasses = []string{lowercase, uppercase, digits, symbols, space} +) + +// PrettyPrint prints rpc requests/responses in a pretty format. +func PrettyPrint(i interface{}) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +// SetupUser setup user for credentialz tests. +func SetupUser(t *testing.T, dut *ondatra.DUTDevice, username string) { + auth := &oc.System_Aaa_Authentication{} + user := auth.GetOrCreateUser(username) + user.SetRole(oc.AaaTypes_SYSTEM_DEFINED_ROLES_SYSTEM_ROLE_ADMIN) + gnmi.Update(t, dut, gnmi.OC().System().Aaa().Authentication().Config(), auth) +} + +// GeneratePassword creates a password with following restrictions: +// - Must be 24-32 characters long. +// - Must use 4 of the 5 character classes ([a-z], [A-Z], [0-9], [!@#$%^&*(){}[]\|:;'"], [ ]). +func GeneratePassword() string { + // Create random length between 24-32 characters long. + length := minPasswordLength + rand.Intn(maxPasswordLength-minPasswordLength+1) + + // Randomly select 4 out of 5 character classes by shuffling the list. + rand.Shuffle(len(charClasses), func(i, j int) { + charClasses[i], charClasses[j] = charClasses[j], charClasses[i] + }) + selectedClasses := charClasses[:4] + + var password strings.Builder + + // Add one random character from each selected class. + for _, class := range selectedClasses { + password.WriteByte(class[rand.Intn(len(class))]) + } + + // Fill remaining characters for the password. + for password.Len() < length { + classIndex := rand.Intn(len(charClasses)) + class := charClasses[classIndex] + password.WriteByte(class[rand.Intn(len(class))]) + } + + return password.String() +} + +func sendHostParametersRequest(t *testing.T, dut *ondatra.DUTDevice, request *cpb.RotateHostParametersRequest) { + credzClient := dut.RawAPIs().GNSI(t).Credentialz() + credzRotateClient, err := credzClient.RotateHostParameters(context.Background()) + if err != nil { + t.Fatalf("Failed fetching credentialz rotate host parameters client, error: %s", err) + } + t.Logf("Sending credentialz rotate host request: %s", PrettyPrint(request)) + err = credzRotateClient.Send(request) + if err != nil { + t.Fatalf("Failed sending credentialz rotate host parameters request, error: %s", err) + } + _, err = credzRotateClient.Recv() + if err != nil { + t.Fatalf("Failed receiving credentialz rotate host parameters response, error: %s", err) + } + err = credzRotateClient.Send(&cpb.RotateHostParametersRequest{ + Request: &cpb.RotateHostParametersRequest_Finalize{ + Finalize: request.GetFinalize(), + }, + }) + if err != nil { + t.Fatalf("Failed sending credentialz rotate host parameters finalize request, error: %s", err) + } + // Brief sleep for finalize to get processed. + time.Sleep(time.Second) +} + +func sendAccountCredentialsRequest(t *testing.T, dut *ondatra.DUTDevice, request *cpb.RotateAccountCredentialsRequest) { + credzClient := dut.RawAPIs().GNSI(t).Credentialz() + credzRotateClient, err := credzClient.RotateAccountCredentials(context.Background()) + if err != nil { + t.Fatalf("Failed fetching credentialz rotate account credentials client, error: %s", err) + } + t.Logf("Sending credentialz rotate account request: %s", PrettyPrint(request)) + err = credzRotateClient.Send(request) + if err != nil { + t.Fatalf("Failed sending credentialz rotate account credentials request, error: %s", err) + } + _, err = credzRotateClient.Recv() + if err != nil { + t.Fatalf("Failed receiving credentialz rotate account credentials response, error: %s", err) + } + err = credzRotateClient.Send(&cpb.RotateAccountCredentialsRequest{ + Request: &cpb.RotateAccountCredentialsRequest_Finalize{ + Finalize: request.GetFinalize(), + }, + }) + if err != nil { + t.Fatalf("Failed sending credentialz rotate account credentials finalize request, error: %s", err) + } + // Brief sleep for finalize to get processed. + time.Sleep(time.Second) +} + +// RotateUserPassword apply password for the specified username on the dut. +func RotateUserPassword(t *testing.T, dut *ondatra.DUTDevice, username, password, version string, createdOn uint64) { + request := &cpb.RotateAccountCredentialsRequest{ + Request: &cpb.RotateAccountCredentialsRequest_Password{ + Password: &cpb.PasswordRequest{ + Accounts: []*cpb.PasswordRequest_Account{ + { + Account: username, + Password: &cpb.PasswordRequest_Password{ + Value: &cpb.PasswordRequest_Password_Plaintext{ + Plaintext: password, + }, + }, + Version: version, + CreatedOn: createdOn, + }, + }, + }, + }, + } + + sendAccountCredentialsRequest(t, dut, request) +} + +// RotateAuthorizedPrincipal apply authorized principal for the specified username on the dut. +func RotateAuthorizedPrincipal(t *testing.T, dut *ondatra.DUTDevice, username, userPrincipal string) { + request := &cpb.RotateAccountCredentialsRequest{ + Request: &cpb.RotateAccountCredentialsRequest_User{ + User: &cpb.AuthorizedUsersRequest{ + Policies: []*cpb.UserPolicy{ + { + Account: username, + AuthorizedPrincipals: &cpb.UserPolicy_SshAuthorizedPrincipals{ + AuthorizedPrincipals: []*cpb.UserPolicy_SshAuthorizedPrincipal{ + { + AuthorizedUser: userPrincipal, + }, + }, + }, + Version: "v1.0", + CreatedOn: uint64(time.Now().Unix()), + }, + }, + }, + }, + } + + sendAccountCredentialsRequest(t, dut, request) +} + +// RotateAuthorizedKey read user key contents from the specified directory & apply it as authorized key on the dut. +func RotateAuthorizedKey(t *testing.T, dut *ondatra.DUTDevice, dir, username, version string, createdOn uint64) { + var keyContents []*cpb.AccountCredentials_AuthorizedKey + + if dir != "" { + data, err := os.ReadFile(fmt.Sprintf("%s/%s.pub", dir, userKey)) + if err != nil { + t.Fatalf("Failed reading private key contents, error: %s", err) + } + keyContents = append(keyContents, &cpb.AccountCredentials_AuthorizedKey{ + AuthorizedKey: data, + KeyType: cpb.KeyType_KEY_TYPE_ED25519, + }) + } + request := &cpb.RotateAccountCredentialsRequest{ + Request: &cpb.RotateAccountCredentialsRequest_Credential{ + Credential: &cpb.AuthorizedKeysRequest{ + Credentials: []*cpb.AccountCredentials{ + { + Account: username, + AuthorizedKeys: keyContents, + Version: version, + CreatedOn: createdOn, + }, + }, + }, + }, + } + + sendAccountCredentialsRequest(t, dut, request) +} + +// RotateTrustedUserCA read CA key contents from the specified directory & apply it on the dut. +func RotateTrustedUserCA(t *testing.T, dut *ondatra.DUTDevice, dir string) { + var keyContents []*cpb.PublicKey + + if dir != "" { + data, err := os.ReadFile(fmt.Sprintf("%s/%s.pub", dir, caKey)) + if err != nil { + t.Fatalf("Failed reading ca public key contents, error: %s", err) + } + keyContents = append(keyContents, &cpb.PublicKey{ + PublicKey: data, + KeyType: cpb.KeyType_KEY_TYPE_ED25519, + }) + } + request := &cpb.RotateHostParametersRequest{ + Request: &cpb.RotateHostParametersRequest_SshCaPublicKey{ + SshCaPublicKey: &cpb.CaPublicKeyRequest{ + SshCaPublicKeys: keyContents, + Version: "v1.0", + CreatedOn: uint64(time.Now().Unix()), + }, + }, + } + + sendHostParametersRequest(t, dut, request) +} + +// RotateAuthenticationTypes apply specified host authentication types on the dut. +func RotateAuthenticationTypes(t *testing.T, dut *ondatra.DUTDevice, authTypes []cpb.AuthenticationType) { + request := &cpb.RotateHostParametersRequest{ + Request: &cpb.RotateHostParametersRequest_AuthenticationAllowed{ + AuthenticationAllowed: &cpb.AllowedAuthenticationRequest{ + AuthenticationTypes: authTypes, + }, + }, + } + + sendHostParametersRequest(t, dut, request) +} + +// RotateAuthenticationArtifacts read dut key/certificate contents from the specified directory & apply it as host authentication artifacts on the dut. +func RotateAuthenticationArtifacts(t *testing.T, dut *ondatra.DUTDevice, keyDir, certDir, version string, createdOn uint64) { + var artifactContents []*cpb.ServerKeysRequest_AuthenticationArtifacts + + if keyDir != "" { + data, err := os.ReadFile(fmt.Sprintf("%s/%s", keyDir, dutKey)) + if err != nil { + t.Fatalf("Failed reading host private key, error: %s", err) + } + artifactContents = append(artifactContents, &cpb.ServerKeysRequest_AuthenticationArtifacts{ + PrivateKey: data, + }) + } + + if certDir != "" { + data, err := os.ReadFile(fmt.Sprintf("%s/%s-cert.pub", certDir, dutKey)) + if err != nil { + t.Fatalf("Failed reading host signed certificate, error: %s", err) + } + artifactContents = append(artifactContents, &cpb.ServerKeysRequest_AuthenticationArtifacts{ + Certificate: data, + }) + } + + request := &cpb.RotateHostParametersRequest{ + Request: &cpb.RotateHostParametersRequest_ServerKeys{ + ServerKeys: &cpb.ServerKeysRequest{ + AuthArtifacts: artifactContents, + Version: version, + CreatedOn: createdOn, + }, + }, + } + + sendHostParametersRequest(t, dut, request) +} + +// RotateAuthorizedPrincipalCheck apply specified authorized principal tool on the dut. +func RotateAuthorizedPrincipalCheck(t *testing.T, dut *ondatra.DUTDevice, tool cpb.AuthorizedPrincipalCheckRequest_Tool) { + request := &cpb.RotateHostParametersRequest{ + Request: &cpb.RotateHostParametersRequest_AuthorizedPrincipalCheck{ + AuthorizedPrincipalCheck: &cpb.AuthorizedPrincipalCheckRequest{ + Tool: tool, + }, + }, + } + + sendHostParametersRequest(t, dut, request) +} + +// GetRejectTelemetry retrieve ssh reject telemetry counters from the dut. +func GetRejectTelemetry(t *testing.T, dut *ondatra.DUTDevice) (uint64, uint64) { + sshCounters := gnmi.Get(t, dut, gnmi.OC().System().SshServer().Counters().State()) + return sshCounters.GetAccessRejects(), sshCounters.GetLastAccessReject() +} + +// GetAcceptTelemetry retrieve ssh accept telemetry counters from the dut. +func GetAcceptTelemetry(t *testing.T, dut *ondatra.DUTDevice) (uint64, uint64) { + sshCounters := gnmi.Get(t, dut, gnmi.OC().System().SshServer().Counters().State()) + return sshCounters.GetAccessAccepts(), sshCounters.GetLastAccessAccept() +} + +// GetDutTarget returns ssh target for the dut to be used in credentialz tests. +func GetDutTarget(t *testing.T, dut *ondatra.DUTDevice) string { + var serviceDUT interface { + Service(string) (*tpb.Service, error) + } + err := binding.DUTAs(dut.RawAPIs().BindingDUT(), &serviceDUT) + if err != nil { + t.Log("DUT does not support `Service` function, will attempt to use dut name field") + return fmt.Sprintf("%s:%d", dut.Name(), defaultSSHPort) + } + dutSSHService, err := serviceDUT.Service("ssh") + if err != nil { + t.Fatal(err) + } + return fmt.Sprintf("%s:%d", dutSSHService.GetOutsideIp(), dutSSHService.GetOutside()) +} + +// GetDutPublicKey retrieve single host public key from the dut. +func GetDutPublicKey(t *testing.T, dut *ondatra.DUTDevice) []byte { + credzClient := dut.RawAPIs().GNSI(t).Credentialz() + req := &cpb.GetPublicKeysRequest{} + response, err := credzClient.GetPublicKeys(context.Background(), req) + if err != nil { + t.Fatalf("Failed fetching fetching credentialz public keys, error: %s", err) + } + if len(response.PublicKeys) < 1 { + return nil + } + return response.PublicKeys[0].PublicKey +} + +// CreateSSHKeyPair creates ssh keypair with a filename of keyName in the specified directory. +// Keypairs can be created for ca/dut/testuser as per individual credentialz test requirements. +func CreateSSHKeyPair(t *testing.T, dir, keyName string) { + sshCmd := exec.Command( + "ssh-keygen", + "-t", "ed25519", + "-f", keyName, + "-C", keyName, + "-q", "-N", "", + ) + sshCmd.Dir = dir + err := sshCmd.Run() + if err != nil { + t.Fatalf("Failed generating %s key pair, error: %s", keyName, err) + } +} + +// CreateUserCertificate creates ssh user certificate in the specified directory. +func CreateUserCertificate(t *testing.T, dir, userPrincipal string) { + userCertCmd := exec.Command( + "ssh-keygen", + "-s", caKey, + "-I", userKey, + "-n", userPrincipal, + "-V", "+52w", + fmt.Sprintf("%s.pub", userKey), + ) + userCertCmd.Dir = dir + err := userCertCmd.Run() + if err != nil { + t.Fatalf("Failed generating user cert, error: %s", err) + } +} + +// CreateHostCertificate takes in dut key contents & creates ssh host certificate in the specified directory. +func CreateHostCertificate(t *testing.T, dir string, dutKeyContents []byte) { + err := os.WriteFile(fmt.Sprintf("%s/%s.pub", dir, dutKey), dutKeyContents, 0o777) + if err != nil { + t.Fatalf("Failed writing dut public key to temp dir, error: %s", err) + } + cmd := exec.Command( + "ssh-keygen", + "-s", caKey, // sign using this ca key + "-I", dutKey, // key identity + "-h", // create host (not user) certificate + "-n", "dut.test.com", // principal(s) + "-V", "+52w", // validity + fmt.Sprintf("%s.pub", dutKey), + ) + cmd.Dir = dir + err = cmd.Run() + if err != nil { + t.Fatalf("Failed generating dut cert, error: %s", err) + } +} + +func createHibaKeysCopy(t *testing.T, dir string) { + keyFiles := []string{ + "ca", + "ca.pub", + "hosts/dut", + "hosts/dut.pub", + "hosts/dut-cert.pub", + "users/testuser", + "users/testuser.pub", + "users/testuser-cert.pub", + } + err := os.Mkdir(fmt.Sprintf("%s/hosts", dir), 0o700) + if err != nil { + t.Fatalf("Failed ensuring hosts dir in temp dir, error: %s", err) + } + err = os.Mkdir(fmt.Sprintf("%s/users", dir), 0o700) + if err != nil { + t.Fatalf("Failed ensuring users dir in temp dir, error: %s", err) + } + + for _, keyFile := range keyFiles { + var input []byte + input, err = os.ReadFile(keyFile) + if err != nil { + t.Errorf("Error reading file %v, error: %s", keyFile, err) + return + } + err = os.WriteFile(fmt.Sprintf("%s/%s", dir, keyFile), input, 0o600) + if err != nil { + t.Fatalf("Failed copying key file %s to temp test dir, error: %s", keyFile, err) + } + } +} + +func createHibaKeysGen(t *testing.T, dir string) { + caCmd := exec.Command( + "hiba-ca.sh", + "-c", + "-d", dir, // output to the temp dir + "--", // pass the rest to ssh-keygen + "-q", "-N", "", // quiet, empty passphrase + + ) + caCmd.Dir = dir + err := caCmd.Run() + if err != nil { + t.Fatalf("Failed generating ca key pair, error: %s", err) + } + + userKeyCmd := exec.Command( + "hiba-ca.sh", + "-c", + "-d", dir, + "-u", "-I", userKey, + "--", + "-q", "-N", "", + ) + userKeyCmd.Dir = dir + err = userKeyCmd.Run() + if err != nil { + t.Fatalf("Failed generating user key pair, error: %s", err) + } + + dutKeyCmd := exec.Command( + "hiba-ca.sh", + "-c", + "-d", dir, + "-h", "-I", dutKey, + "--", + "-q", "-N", "", + ) + dutKeyCmd.Dir = dir + err = dutKeyCmd.Run() + if err != nil { + t.Fatalf("Failed generating dut key pair, error: %s", err) + } + + prodIdentityCmd := exec.Command( + "hiba-gen", + "-i", + "-f", fmt.Sprintf("%s/policy/identities/prod", dir), + "domain", "example.com", + ) + prodIdentityCmd.Dir = dir + err = prodIdentityCmd.Run() + if err != nil { + t.Fatalf("Failed creating prod identity, error: %s", err) + } + + shellGrantCmd := exec.Command( + "hiba-gen", + "-f", fmt.Sprintf("%s/policy/grants/shell", dir), + "domain", "example.com", + ) + shellGrantCmd.Dir = dir + err = shellGrantCmd.Run() + if err != nil { + t.Fatalf("Failed creating shell grant, error: %s", err) + } + + grantShellToUserCmd := exec.Command( + "hiba-ca.sh", + "-d", dir, + "-p", + "-I", userKey, + "-H", "shell", + ) + grantShellToUserCmd.Dir = dir + err = grantShellToUserCmd.Run() + if err != nil { + t.Fatalf("Failed granting shell grant to testuser, error: %s", err) + } + + createHostCertCmd := exec.Command( + "hiba-ca.sh", + "-d", dir, + "-s", + "-h", + "-I", dutKey, + "-H", "prod", + "-V", "+52w", + ) + createHostCertCmd.Dir = dir + err = createHostCertCmd.Run() + if err != nil { + t.Fatalf("Failed creating host certificate, error: %s", err) + } + + createUserCertCmd := exec.Command( + "hiba-ca.sh", + "-d", dir, + "-s", + "-u", + "-I", userKey, + "-H", "shell", + ) + createUserCertCmd.Dir = dir + err = createUserCertCmd.Run() + if err != nil { + t.Fatalf("Failed creating user certificate, error: %s", err) + } +} + +// CreateHibaKeys creates/copies hiba granted keys/certificates in the specified directory. +// If hiba tool is not installed on the testbed, ensure following files (generated after executing steps +// from https://github.com/google/hiba/blob/main/CA.md) are present in the test directory : +// feature/security/gnsi/credentialz/tests/hiba_authentication/ca, +// feature/security/gnsi/credentialz/tests/hiba_authentication/ca.pub, +// feature/security/gnsi/credentialz/tests/hiba_authentication/hosts/dut, +// feature/security/gnsi/credentialz/tests/hiba_authentication/hosts/dut.pub, +// feature/security/gnsi/credentialz/tests/hiba_authentication/hosts/dut-cert.pub, +// feature/security/gnsi/credentialz/tests/hiba_authentication/users/testuser, +// feature/security/gnsi/credentialz/tests/hiba_authentication/users/testuser.pub, +// feature/security/gnsi/credentialz/tests/hiba_authentication/users/testuser-cert.pub, +func CreateHibaKeys(t *testing.T, dir string) { + hibaCa, _ := exec.LookPath("hiba-ca.sh") + hibaGen, _ := exec.LookPath("hiba-gen") + if hibaCa == "" || hibaGen == "" { + t.Log("hiba-ca and/or hiba-gen not found on path, will try to use certs in local test dir if present.") + createHibaKeysCopy(t, dir) + } else { + createHibaKeysGen(t, dir) + } +} + +// SSHWithPassword dials ssh with password based authentication to be used in credentialz tests. +func SSHWithPassword(target, username, password string) (*ssh.Client, error) { + return ssh.Dial( + "tcp", + target, + &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.Password(password), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + }, + ) +} + +// SSHWithCertificate dials ssh with user certificate to be used in credentialz tests. +func SSHWithCertificate(t *testing.T, target, username, dir string) (*ssh.Client, error) { + privateKeyContents, err := os.ReadFile(fmt.Sprintf("%s/%s", dir, userKey)) + if err != nil { + t.Fatalf("Failed reading private key contents, error: %s", err) + } + signer, err := ssh.ParsePrivateKey(privateKeyContents) + if err != nil { + t.Fatalf("Failed parsing private key, error: %s", err) + } + certificateContents, err := os.ReadFile(fmt.Sprintf("%s/%s-cert.pub", dir, userKey)) + if err != nil { + t.Fatalf("Failed reading certificate contents, error: %s", err) + } + certificate, _, _, _, err := ssh.ParseAuthorizedKey(certificateContents) + if err != nil { + t.Fatalf("Failed parsing certificate contents, error: %s", err) + } + certificateSigner, err := ssh.NewCertSigner(certificate.(*ssh.Certificate), signer) + if err != nil { + t.Fatalf("Failed creating certificate signer, error: %s", err) + } + + return ssh.Dial( + "tcp", + target, + &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.PublicKeys(certificateSigner), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + }, + ) +} + +// SSHWithKey dials ssh with key based authentication to be used in credentialz tests. +func SSHWithKey(t *testing.T, target, username, dir string) (*ssh.Client, error) { + privateKeyContents, err := os.ReadFile(fmt.Sprintf("%s/%s", dir, userKey)) + if err != nil { + t.Fatalf("Failed reading private key contents, error: %s", err) + } + signer, err := ssh.ParsePrivateKey(privateKeyContents) + if err != nil { + t.Fatalf("Failed parsing private key, error: %s", err) + } + + return ssh.Dial( + "tcp", + target, + &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.PublicKeys(signer), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + }, + ) +} diff --git a/internal/vrfpolicy/vrfpolicy.go b/internal/vrfpolicy/vrfpolicy.go index 09d687b26a3..1946093987c 100644 --- a/internal/vrfpolicy/vrfpolicy.go +++ b/internal/vrfpolicy/vrfpolicy.go @@ -356,7 +356,7 @@ func buildVRFSelectionPolicy(niName string, policyName string, pfRules []*policy pfRProtoIP.DscpSet = pfRule.ipv4.dscpSet } if pfRule.ipv4.protocol != 0 { - pfRProtoIP.Protocol = oc.UnionUint8(pfRule.ipv4.protocol) + pfRProtoIP.Protocol = pfRule.ipv4.protocol } if pfRule.ipv4.sourceAddr != "" { pfRProtoIP.SourceAddress = ygot.String(pfRule.ipv4.sourceAddr) @@ -395,6 +395,6 @@ func DeletePolicyForwarding(t *testing.T, dut *ondatra.DUTDevice, portID string) if deviations.InterfaceRefInterfaceIDFormat(dut) { interfaceID = ingressPort + ".0" } - pfpath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).PolicyForwarding().Interface(interfaceID) - gnmi.Delete(t, dut, pfpath.Config()) + pfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).PolicyForwarding().Interface(interfaceID) + gnmi.Delete(t, dut, pfPath.Config()) } diff --git a/proto/metadata.proto b/proto/metadata.proto index 25ea4d71cc6..7b6318bc66b 100644 --- a/proto/metadata.proto +++ b/proto/metadata.proto @@ -558,7 +558,7 @@ message Metadata { // equal to the canonical hardware model name of its device. bool model_name_unsupported = 194; // community_match_with_redistribution_unsupported is set to true for devices that do not support matching community at the redistribution attach point. - bool community_match_with_redistribution_unsupported = 195; + bool community_match_with_redistribution_unsupported = 195; // Devices that do not support components/component/state/install-component // and components/component/state/install-position. bool install_position_and_install_component_unsupported = 196; @@ -575,7 +575,7 @@ message Metadata { // weighted ecmp feature verification using fixed packet bool weighted_ecmp_fixed_packet_verification = 202; // Override default NextHop scale while enabling encap/decap scale - // CISCO: + // CISCO: bool override_default_nh_scale = 203; // Devices that donot support setting bgp extended community set bool bgp_extended_community_set_unsupported = 204; @@ -615,6 +615,59 @@ message Metadata { bool use_parent_component_for_temperature_telemetry = 219; // component manufactured date is unsupported bool component_mfg_date_unsupported = 220; + // trib protocol field under otn channel config unsupported + bool otn_channel_trib_unsupported = 221; + // ingress parameters under eth channel config unsupported + bool eth_channel_ingress_parameters_unsupported = 222; + // Cisco numbering for eth channel assignment starts from 1 instead of 0 + bool eth_channel_assignment_cisco_numbering = 223; + // Devices needs time to update interface counters. + bool interface_counters_update_delayed = 224; + // device does not support a Healthz GET RPC against Chassis level component like "CHASSIS" or "Rack 0" + bool chassis_get_rpc_unsupported = 225; + // Leaf-ref validation for list keys which is enforced for Cisco and hence deviation + // b/373581140 + bool power_disable_enable_leaf_ref_validation = 226; + // Device does not support ssh server counters. + bool ssh_server_counters_unsupported = 227; + // True when the optical-channel operational-mode is unsupported. + // Juniper: b/355456031 + bool operational_mode_unsupported = 228; + // BGP session state idle is supported in passive mode instead of active + // Cisco: b/376021545 + bool bgp_session_state_idle_in_passive_mode = 229; + // EnableMultipathUnderAfiSafi returns true for devices that do not support multipath under /global path and instead support under global/afi/safi path + // CISCO: b/376241033 + // CISCO: b/340859662 + bool enable_multipath_under_afi_safi = 230; + // Device have different default value for allow own as. + // Juniper : b/373559004 + bool bgp_allowownas_diff_default_value = 231; + // Cisco numbering for OTN channel assignment starts from 1 instead of 0 + bool otn_channel_assignment_cisco_numbering = 232; + // Cisco pre-fec-ber inactive value for CISCO-ACACIA vendors + bool cisco_pre_fec_ber_inactive_value = 233; + // Device does not support bgp extended next hop encoding leaf. + // Cisco: b/377433951 + bool bgp_extended_next_hop_encoding_leaf_unsupported = 234; + // Device does not support bgp afi safi wildcard. + // Cisco: b/379863985 + bool bgp_afi_safi_wildcard_not_supported = 235; + // Nokia; b/304493065 comment#7 SRL native admin_enable for table-connections + bool enable_table_connections = 236; + // Device has default zero suppression. + // Juniper : b/378646018 + bool no_zero_suppression = 237; + // Cisco: b/378801305 + bool isis_interface_level_passive_unsupported = 238; + // Cisco: b/378616912 + bool isis_dis_sysid_unsupported = 239; + // Cisco: b/378616912 + bool isis_database_overloads_unsupported = 240; + // Juniper: b/358534837 + // Devices that do not support setting med value using union type in OC. + bool bgp_set_med_v7_unsupported = 241; + // Reserved field numbers and identifiers. reserved 84, 9, 28, 20, 90, 97, 55, 89, 19, 36, 35, 40, 173; } @@ -644,4 +697,3 @@ message Metadata { // checks. bool path_presence_test = 7; } - diff --git a/proto/metadata_go_proto/metadata.pb.go b/proto/metadata_go_proto/metadata.pb.go index 74bd44e8e0b..64a87d81f78 100644 --- a/proto/metadata_go_proto/metadata.pb.go +++ b/proto/metadata_go_proto/metadata.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.28.0 +// protoc v3.6.1 // source: metadata.proto package metadata_go_proto @@ -897,6 +897,58 @@ type Metadata_Deviations struct { UseParentComponentForTemperatureTelemetry bool `protobuf:"varint,219,opt,name=use_parent_component_for_temperature_telemetry,json=useParentComponentForTemperatureTelemetry,proto3" json:"use_parent_component_for_temperature_telemetry,omitempty"` // component manufactured date is unsupported ComponentMfgDateUnsupported bool `protobuf:"varint,220,opt,name=component_mfg_date_unsupported,json=componentMfgDateUnsupported,proto3" json:"component_mfg_date_unsupported,omitempty"` + // trib protocol field under otn channel config unsupported + OtnChannelTribUnsupported bool `protobuf:"varint,221,opt,name=otn_channel_trib_unsupported,json=otnChannelTribUnsupported,proto3" json:"otn_channel_trib_unsupported,omitempty"` + // ingress parameters under eth channel config unsupported + EthChannelIngressParametersUnsupported bool `protobuf:"varint,222,opt,name=eth_channel_ingress_parameters_unsupported,json=ethChannelIngressParametersUnsupported,proto3" json:"eth_channel_ingress_parameters_unsupported,omitempty"` + // Cisco numbering for eth channel assignment starts from 1 instead of 0 + EthChannelAssignmentCiscoNumbering bool `protobuf:"varint,223,opt,name=eth_channel_assignment_cisco_numbering,json=ethChannelAssignmentCiscoNumbering,proto3" json:"eth_channel_assignment_cisco_numbering,omitempty"` + // Devices needs time to update interface counters. + InterfaceCountersUpdateDelayed bool `protobuf:"varint,224,opt,name=interface_counters_update_delayed,json=interfaceCountersUpdateDelayed,proto3" json:"interface_counters_update_delayed,omitempty"` + // device does not support a Healthz GET RPC against Chassis level component like "CHASSIS" or "Rack 0" + ChassisGetRpcUnsupported bool `protobuf:"varint,225,opt,name=chassis_get_rpc_unsupported,json=chassisGetRpcUnsupported,proto3" json:"chassis_get_rpc_unsupported,omitempty"` + // Leaf-ref validation for list keys which is enforced for Cisco and hence deviation + // b/373581140 + PowerDisableEnableLeafRefValidation bool `protobuf:"varint,226,opt,name=power_disable_enable_leaf_ref_validation,json=powerDisableEnableLeafRefValidation,proto3" json:"power_disable_enable_leaf_ref_validation,omitempty"` + // Device does not support ssh server counters. + SshServerCountersUnsupported bool `protobuf:"varint,227,opt,name=ssh_server_counters_unsupported,json=sshServerCountersUnsupported,proto3" json:"ssh_server_counters_unsupported,omitempty"` + // True when the optical-channel operational-mode is unsupported. + // Juniper: b/355456031 + OperationalModeUnsupported bool `protobuf:"varint,228,opt,name=operational_mode_unsupported,json=operationalModeUnsupported,proto3" json:"operational_mode_unsupported,omitempty"` + // BGP session state idle is supported in passive mode instead of active + // Cisco: b/376021545 + BgpSessionStateIdleInPassiveMode bool `protobuf:"varint,229,opt,name=bgp_session_state_idle_in_passive_mode,json=bgpSessionStateIdleInPassiveMode,proto3" json:"bgp_session_state_idle_in_passive_mode,omitempty"` + // EnableMultipathUnderAfiSafi returns true for devices that do not support multipath under /global path and instead support under global/afi/safi path + // CISCO: b/376241033 + // CISCO: b/340859662 + EnableMultipathUnderAfiSafi bool `protobuf:"varint,230,opt,name=enable_multipath_under_afi_safi,json=enableMultipathUnderAfiSafi,proto3" json:"enable_multipath_under_afi_safi,omitempty"` + // Device have different default value for allow own as. + // Juniper : b/373559004 + BgpAllowownasDiffDefaultValue bool `protobuf:"varint,231,opt,name=bgp_allowownas_diff_default_value,json=bgpAllowownasDiffDefaultValue,proto3" json:"bgp_allowownas_diff_default_value,omitempty"` + // Cisco numbering for OTN channel assignment starts from 1 instead of 0 + OtnChannelAssignmentCiscoNumbering bool `protobuf:"varint,232,opt,name=otn_channel_assignment_cisco_numbering,json=otnChannelAssignmentCiscoNumbering,proto3" json:"otn_channel_assignment_cisco_numbering,omitempty"` + // Cisco pre-fec-ber inactive value for CISCO-ACACIA vendors + CiscoPreFecBerInactiveValue bool `protobuf:"varint,233,opt,name=cisco_pre_fec_ber_inactive_value,json=ciscoPreFecBerInactiveValue,proto3" json:"cisco_pre_fec_ber_inactive_value,omitempty"` + // Device does not support bgp extended next hop encoding leaf. + // Cisco: b/377433951 + BgpExtendedNextHopEncodingLeafUnsupported bool `protobuf:"varint,234,opt,name=bgp_extended_next_hop_encoding_leaf_unsupported,json=bgpExtendedNextHopEncodingLeafUnsupported,proto3" json:"bgp_extended_next_hop_encoding_leaf_unsupported,omitempty"` + // Device does not support bgp afi safi wildcard. + // Cisco: b/379863985 + BgpAfiSafiWildcardNotSupported bool `protobuf:"varint,235,opt,name=bgp_afi_safi_wildcard_not_supported,json=bgpAfiSafiWildcardNotSupported,proto3" json:"bgp_afi_safi_wildcard_not_supported,omitempty"` + // Nokia; b/304493065 comment#7 SRL native admin_enable for table-connections + EnableTableConnections bool `protobuf:"varint,236,opt,name=enable_table_connections,json=enableTableConnections,proto3" json:"enable_table_connections,omitempty"` + // Device has default zero suppression. + // Juniper : b/378646018 + NoZeroSuppression bool `protobuf:"varint,237,opt,name=no_zero_suppression,json=noZeroSuppression,proto3" json:"no_zero_suppression,omitempty"` + // Cisco: b/378801305 + IsisInterfaceLevelPassiveUnsupported bool `protobuf:"varint,238,opt,name=isis_interface_level_passive_unsupported,json=isisInterfaceLevelPassiveUnsupported,proto3" json:"isis_interface_level_passive_unsupported,omitempty"` + // Cisco: b/378616912 + IsisDisSysidUnsupported bool `protobuf:"varint,239,opt,name=isis_dis_sysid_unsupported,json=isisDisSysidUnsupported,proto3" json:"isis_dis_sysid_unsupported,omitempty"` + // Cisco: b/378616912 + IsisDatabaseOverloadsUnsupported bool `protobuf:"varint,240,opt,name=isis_database_overloads_unsupported,json=isisDatabaseOverloadsUnsupported,proto3" json:"isis_database_overloads_unsupported,omitempty"` + // Juniper: b/358534837 + // Devices that do not support setting med value using union type in OC. + BgpSetMedV7Unsupported bool `protobuf:"varint,241,opt,name=bgp_set_med_v7_unsupported,json=bgpSetMedV7Unsupported,proto3" json:"bgp_set_med_v7_unsupported,omitempty"` } func (x *Metadata_Deviations) Reset() { @@ -2324,6 +2376,153 @@ func (x *Metadata_Deviations) GetComponentMfgDateUnsupported() bool { return false } +func (x *Metadata_Deviations) GetOtnChannelTribUnsupported() bool { + if x != nil { + return x.OtnChannelTribUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetEthChannelIngressParametersUnsupported() bool { + if x != nil { + return x.EthChannelIngressParametersUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetEthChannelAssignmentCiscoNumbering() bool { + if x != nil { + return x.EthChannelAssignmentCiscoNumbering + } + return false +} + +func (x *Metadata_Deviations) GetInterfaceCountersUpdateDelayed() bool { + if x != nil { + return x.InterfaceCountersUpdateDelayed + } + return false +} + +func (x *Metadata_Deviations) GetChassisGetRpcUnsupported() bool { + if x != nil { + return x.ChassisGetRpcUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetPowerDisableEnableLeafRefValidation() bool { + if x != nil { + return x.PowerDisableEnableLeafRefValidation + } + return false +} + +func (x *Metadata_Deviations) GetSshServerCountersUnsupported() bool { + if x != nil { + return x.SshServerCountersUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetOperationalModeUnsupported() bool { + if x != nil { + return x.OperationalModeUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetBgpSessionStateIdleInPassiveMode() bool { + if x != nil { + return x.BgpSessionStateIdleInPassiveMode + } + return false +} + +func (x *Metadata_Deviations) GetEnableMultipathUnderAfiSafi() bool { + if x != nil { + return x.EnableMultipathUnderAfiSafi + } + return false +} + +func (x *Metadata_Deviations) GetBgpAllowownasDiffDefaultValue() bool { + if x != nil { + return x.BgpAllowownasDiffDefaultValue + } + return false +} + +func (x *Metadata_Deviations) GetOtnChannelAssignmentCiscoNumbering() bool { + if x != nil { + return x.OtnChannelAssignmentCiscoNumbering + } + return false +} + +func (x *Metadata_Deviations) GetCiscoPreFecBerInactiveValue() bool { + if x != nil { + return x.CiscoPreFecBerInactiveValue + } + return false +} + +func (x *Metadata_Deviations) GetBgpExtendedNextHopEncodingLeafUnsupported() bool { + if x != nil { + return x.BgpExtendedNextHopEncodingLeafUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetBgpAfiSafiWildcardNotSupported() bool { + if x != nil { + return x.BgpAfiSafiWildcardNotSupported + } + return false +} + +func (x *Metadata_Deviations) GetEnableTableConnections() bool { + if x != nil { + return x.EnableTableConnections + } + return false +} + +func (x *Metadata_Deviations) GetNoZeroSuppression() bool { + if x != nil { + return x.NoZeroSuppression + } + return false +} + +func (x *Metadata_Deviations) GetIsisInterfaceLevelPassiveUnsupported() bool { + if x != nil { + return x.IsisInterfaceLevelPassiveUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetIsisDisSysidUnsupported() bool { + if x != nil { + return x.IsisDisSysidUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetIsisDatabaseOverloadsUnsupported() bool { + if x != nil { + return x.IsisDatabaseOverloadsUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetBgpSetMedV7Unsupported() bool { + if x != nil { + return x.BgpSetMedV7Unsupported + } + return false +} + type Metadata_PlatformExceptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2387,999 +2586,1097 @@ var file_metadata_proto_rawDesc = []byte{ 0x74, 0x69, 0x6e, 0x67, 0x1a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x72, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x62, 0x65, - 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf2, 0x7b, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x61, 0x6e, 0x49, - 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x88, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6c, 0x61, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x61, 0x6e, + 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, 0x52, 0x07, 0x74, 0x65, 0x73, + 0x74, 0x62, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x13, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x12, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, 0x52, 0x07, 0x74, 0x65, 0x73, 0x74, - 0x62, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x13, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, - 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, - 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x12, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x12, - 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x65, - 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x70, 0x61, 0x74, 0x68, 0x50, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x54, 0x65, 0x73, 0x74, 0x1a, 0xb8, 0x01, 0x0a, 0x08, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2e, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x72, - 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x52, - 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, - 0x61, 0x72, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4d, - 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x6f, 0x66, - 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, - 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x6f, 0x66, 0x74, 0x77, - 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x4a, - 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0e, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, - 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xc5, 0x73, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x12, 0x69, 0x70, 0x76, 0x34, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x45, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x18, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x3b, 0x0a, 0x1a, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, - 0x6c, 0x34, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x75, 0x64, 0x70, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x75, 0x74, - 0x65, 0x4c, 0x34, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x55, 0x64, 0x70, 0x12, 0x3a, - 0x0a, 0x19, 0x70, 0x72, 0x65, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x72, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x17, 0x70, 0x72, 0x65, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x28, 0x68, 0x69, - 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6c, - 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x25, 0x68, 0x69, - 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x69, 0x63, 0x61, 0x6c, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x1f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, - 0x69, 0x5f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x69, 0x73, - 0x69, 0x73, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, - 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x52, 0x0a, 0x26, 0x69, 0x73, - 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x31, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x69, 0x73, 0x69, 0x73, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x31, 0x44, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x41, - 0x0a, 0x1d, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x5f, 0x74, 0x6f, - 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x69, 0x73, 0x69, 0x73, 0x53, 0x69, 0x6e, 0x67, 0x6c, - 0x65, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, - 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x69, 0x73, 0x69, 0x73, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x26, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, - 0x67, 0x5f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x49, - 0x73, 0x69, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x41, 0x66, 0x69, 0x53, - 0x61, 0x66, 0x69, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x54, 0x0a, 0x27, 0x69, 0x73, 0x69, - 0x73, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x69, 0x73, 0x69, 0x73, - 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, - 0x58, 0x0a, 0x29, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, - 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x25, 0x69, 0x73, 0x69, 0x73, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x21, 0x69, 0x73, 0x69, - 0x73, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x69, 0x73, 0x69, 0x73, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x53, 0x75, 0x70, 0x70, 0x72, 0x65, 0x73, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x70, 0x5f, 0x6e, 0x65, 0x69, 0x67, 0x68, - 0x62, 0x6f, 0x72, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x11, 0x69, 0x70, 0x4e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x4d, 0x69, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x73, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x5f, 0x6e, 0x6f, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x12, 0x6f, 0x73, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x72, - 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x73, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x5f, 0x72, - 0x70, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x6f, 0x73, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x52, 0x70, 0x12, 0x50, - 0x0a, 0x25, 0x6c, 0x6c, 0x64, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, - 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x6c, - 0x6c, 0x64, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x12, 0x55, 0x0a, 0x28, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x67, 0x70, 0x5f, - 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x15, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x23, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x42, 0x67, 0x70, 0x4c, 0x61, - 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x47, 0x0a, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, - 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x12, 0x34, 0x0a, 0x16, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, - 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x14, 0x73, 0x74, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3f, 0x0a, 0x1d, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, - 0x6e, 0x68, 0x5f, 0x64, 0x6d, 0x61, 0x63, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x69, - 0x70, 0x76, 0x36, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x47, 0x72, 0x69, 0x62, - 0x69, 0x4e, 0x68, 0x44, 0x6d, 0x61, 0x63, 0x12, 0x45, 0x0a, 0x1f, 0x65, 0x63, 0x6e, 0x5f, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, - 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1c, 0x65, 0x63, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, - 0x0a, 0x1f, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, - 0x5f, 0x70, 0x6b, 0x74, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x69, 0x70, 0x76, 0x36, 0x44, 0x69, 0x73, - 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x50, 0x6b, 0x74, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x77, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x64, - 0x72, 0x6f, 0x70, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x55, - 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1c, 0x63, 0x6c, - 0x69, 0x5f, 0x74, 0x61, 0x6b, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, - 0x63, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6f, 0x63, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x18, 0x63, 0x6c, 0x69, 0x54, 0x61, 0x6b, 0x65, 0x73, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, - 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x4f, 0x63, 0x12, 0x3f, 0x0a, 0x1c, 0x73, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x77, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x19, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x1a, 0x73, - 0x77, 0x69, 0x74, 0x63, 0x68, 0x5f, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x69, 0x64, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x17, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x43, 0x68, 0x69, 0x70, 0x49, 0x64, 0x55, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x25, 0x62, 0x61, 0x63, 0x6b, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x66, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x61, 0x70, - 0x61, 0x63, 0x69, 0x74, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x62, 0x61, 0x63, 0x6b, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x46, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, - 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x21, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, - 0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x18, 0x21, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x5a, 0x0a, 0x2b, 0x6e, 0x6f, 0x5f, 0x6d, 0x69, 0x78, - 0x5f, 0x6f, 0x66, 0x5f, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x5f, 0x61, 0x6e, 0x64, 0x5f, 0x75, - 0x6e, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x6e, 0x6f, 0x4d, - 0x69, 0x78, 0x4f, 0x66, 0x54, 0x61, 0x67, 0x67, 0x65, 0x64, 0x41, 0x6e, 0x64, 0x55, 0x6e, 0x74, - 0x61, 0x67, 0x67, 0x65, 0x64, 0x53, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x25, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x14, 0x73, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x21, 0x65, 0x78, 0x70, 0x6c, - 0x69, 0x63, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, - 0x65, 0x66, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x26, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x1e, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x18, 0x27, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x73, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x78, 0x70, 0x6c, 0x69, - 0x63, 0x69, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x29, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x50, 0x6f, - 0x72, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x65, 0x78, 0x70, 0x6c, 0x69, - 0x63, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x6e, - 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x72, 0x66, 0x18, 0x2a, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x1d, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x66, 0x61, 0x63, 0x65, 0x49, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x72, - 0x66, 0x12, 0x2c, 0x0a, 0x12, 0x71, 0x6f, 0x73, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, - 0x5f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x73, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x71, - 0x6f, 0x73, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x4f, 0x63, 0x74, 0x65, 0x74, 0x73, 0x12, - 0x4f, 0x0a, 0x24, 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, - 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x73, - 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x65, - 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, - 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x74, 0x72, - 0x79, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x49, 0x0a, 0x22, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, 0x6d, - 0x61, 0x63, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, - 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, 0x72, 0x70, 0x18, 0x2e, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1d, 0x67, 0x72, 0x69, 0x62, 0x69, 0x4d, 0x61, 0x63, 0x4f, 0x76, 0x65, 0x72, 0x72, - 0x69, 0x64, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x72, 0x70, - 0x12, 0x4a, 0x0a, 0x22, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x72, 0x6f, - 0x75, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x66, - 0x69, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x56, 0x0a, 0x28, - 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x5f, 0x63, 0x6f, 0x6d, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x75, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x30, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, - 0x67, 0x6e, 0x6f, 0x69, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x6e, 0x74, 0x70, 0x5f, 0x6e, 0x6f, 0x6e, 0x5f, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x72, 0x66, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x6e, - 0x74, 0x70, 0x4e, 0x6f, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x72, 0x66, 0x55, - 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x6f, 0x6d, - 0x69, 0x74, 0x5f, 0x6c, 0x32, 0x5f, 0x6d, 0x74, 0x75, 0x18, 0x32, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x6f, 0x6d, 0x69, 0x74, 0x4c, 0x32, 0x4d, 0x74, 0x75, 0x12, 0x46, 0x0a, 0x20, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x63, 0x61, - 0x72, 0x64, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x33, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x61, 0x72, 0x64, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x41, 0x64, 0x6d, - 0x69, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x61, - 0x6e, 0x6e, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x0a, - 0x13, 0x62, 0x67, 0x70, 0x5f, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x62, 0x67, 0x70, 0x54, - 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4d, 0x0a, - 0x24, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x71, 0x75, 0x61, 0x6c, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x5f, - 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x6c, 0x69, 0x6e, - 0x6b, 0x51, 0x75, 0x61, 0x6c, 0x57, 0x61, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, - 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x65, 0x6d, 0x70, 0x74, - 0x79, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x3f, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x12, 0x56, 0x0a, 0x28, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x40, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x24, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x16, 0x62, 0x67, 0x70, - 0x5f, 0x6d, 0x64, 0x35, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, - 0x73, 0x65, 0x74, 0x18, 0x41, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x62, 0x67, 0x70, 0x4d, 0x64, - 0x35, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, 0x4b, - 0x0a, 0x23, 0x64, 0x65, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x73, 0x5f, - 0x64, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x42, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x64, 0x65, 0x71, - 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x65, 0x64, 0x41, 0x73, 0x44, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x67, - 0x72, 0x69, 0x62, 0x69, 0x5f, 0x72, 0x69, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, - 0x18, 0x43, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x67, 0x72, 0x69, 0x62, 0x69, 0x52, 0x69, 0x62, - 0x61, 0x63, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x18, 0x44, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, - 0x3b, 0x0a, 0x1a, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x45, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x17, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x46, 0x6f, 0x72, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, - 0x0a, 0x16, 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x47, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, - 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x4c, 0x0a, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x72, 0x66, 0x5f, 0x62, 0x65, 0x66, - 0x6f, 0x72, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x48, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x56, 0x72, 0x66, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x76, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x49, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, - 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x56, 0x6c, 0x61, 0x6e, 0x49, 0x64, - 0x12, 0x58, 0x0a, 0x2a, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x6f, 0x76, - 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, 0x72, - 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x4a, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x67, 0x72, 0x69, 0x62, 0x69, 0x4d, 0x61, 0x63, 0x4f, 0x76, - 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x72, 0x70, 0x53, - 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, - 0x4b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x6f, 0x73, 0x5f, 0x6f, - 0x63, 0x74, 0x65, 0x74, 0x73, 0x18, 0x4c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x71, 0x6f, 0x73, - 0x4f, 0x63, 0x74, 0x65, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x70, 0x75, 0x5f, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x18, 0x4d, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x70, 0x75, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, - 0x41, 0x6e, 0x63, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x12, 0x41, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x30, 0x18, 0x4e, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1a, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x64, 0x53, 0x75, - 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x30, 0x12, 0x5f, 0x0a, 0x2d, 0x67, - 0x6e, 0x6f, 0x69, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x72, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x18, 0x4f, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x28, 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x6f, 0x76, - 0x65, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x24, 0x70, 0x34, 0x72, 0x74, 0x5f, 0x75, - 0x6e, 0x73, 0x65, 0x74, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x5f, 0x70, - 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x51, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x70, 0x34, 0x72, 0x74, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, - 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x62, 0x6b, 0x75, 0x70, 0x5f, - 0x61, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, - 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x52, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x62, 0x6b, 0x75, - 0x70, 0x41, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x43, 0x6f, 0x64, 0x65, 0x12, 0x49, 0x0a, 0x22, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6e, - 0x68, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x76, 0x72, 0x66, 0x5f, - 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x65, 0x63, 0x61, 0x70, 0x18, 0x53, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1d, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4e, 0x68, 0x67, 0x52, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x73, 0x56, 0x72, 0x66, 0x57, 0x69, 0x74, 0x68, 0x44, 0x65, 0x63, 0x61, 0x70, 0x12, - 0x43, 0x0a, 0x1e, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x18, 0x55, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x69, 0x73, 0x69, 0x73, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x41, 0x66, 0x69, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x23, 0x70, 0x34, 0x72, 0x74, 0x5f, 0x6d, 0x6f, 0x64, - 0x69, 0x66, 0x79, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, - 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x56, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1f, 0x70, 0x34, 0x72, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x5e, 0x0a, 0x2d, 0x6f, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x70, - 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x63, - 0x61, 0x72, 0x64, 0x18, 0x57, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x6f, 0x73, 0x43, 0x6f, 0x6d, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x73, 0x53, 0x75, - 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x4f, 0x72, 0x4c, 0x69, 0x6e, 0x65, 0x63, 0x61, - 0x72, 0x64, 0x12, 0x42, 0x0a, 0x1e, 0x6f, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x63, 0x68, 0x61, - 0x73, 0x73, 0x69, 0x73, 0x18, 0x58, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x6f, 0x73, 0x43, 0x6f, - 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x73, 0x43, - 0x68, 0x61, 0x73, 0x73, 0x69, 0x73, 0x12, 0x57, 0x0a, 0x2a, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x72, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6c, 0x31, 0x5f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6c, 0x32, 0x5f, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x69, 0x73, 0x69, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x53, 0x61, 0x6d, 0x65, 0x4c, 0x31, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x57, 0x69, 0x74, 0x68, 0x4c, 0x32, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, - 0x57, 0x0a, 0x2a, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x64, 0x5f, 0x72, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x5f, 0x6f, 0x73, - 0x70, 0x66, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x5c, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x23, 0x62, 0x67, 0x70, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x4f, 0x73, 0x70, 0x66, 0x53, - 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x4e, 0x0a, 0x24, 0x70, 0x34, 0x72, 0x74, - 0x5f, 0x67, 0x64, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x64, 0x6f, - 0x74, 0x31, 0x71, 0x5f, 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x18, 0x5d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x70, 0x34, 0x72, 0x74, 0x47, 0x64, 0x70, 0x52, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x44, 0x6f, 0x74, 0x31, 0x71, 0x53, 0x75, 0x62, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x2a, 0x61, 0x74, 0x65, 0x5f, - 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, - 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x5e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x61, 0x74, - 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, - 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x5f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x65, - 0x74, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x73, 0x0a, 0x38, 0x69, - 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x73, 0x70, 0x5f, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, - 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x6c, 0x73, 0x70, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x60, 0x20, 0x01, 0x28, 0x08, 0x52, 0x31, 0x69, - 0x73, 0x69, 0x73, 0x4c, 0x73, 0x70, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x4c, 0x73, - 0x70, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x12, 0x4f, 0x0a, 0x24, 0x6c, 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x70, 0x75, - 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x62, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, - 0x6c, 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x43, 0x70, 0x75, 0x55, 0x74, 0x69, 0x6c, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x12, 0x53, 0x0a, 0x26, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x5f, - 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5f, - 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x63, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x23, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x2b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x70, 0x75, 0x5f, 0x75, 0x74, - 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x61, 0x72, 0x64, 0x43, 0x70, 0x75, 0x55, 0x74, - 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x5f, 0x64, - 0x72, 0x6f, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x66, - 0x61, 0x62, 0x72, 0x69, 0x63, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, - 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x27, 0x6c, - 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, - 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x66, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x6c, 0x69, - 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x74, 0x69, 0x6c, + 0x74, 0x61, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x2c, 0x0a, + 0x12, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x70, 0x61, 0x74, 0x68, 0x50, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x54, 0x65, 0x73, 0x74, 0x1a, 0xb8, 0x01, 0x0a, 0x08, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2e, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6f, 0x6e, 0x64, 0x61, 0x74, + 0x72, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, + 0x77, 0x61, 0x72, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, + 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x6f, + 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, + 0x65, 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x6f, 0x66, 0x74, + 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x65, 0x78, + 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0e, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xed, 0x7f, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x70, 0x76, 0x34, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x18, 0x74, 0x72, 0x61, 0x63, 0x65, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x74, 0x72, 0x61, 0x63, 0x65, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x1a, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x5f, 0x6c, 0x34, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x75, 0x64, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x4c, 0x34, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x55, 0x64, 0x70, 0x12, + 0x3a, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x72, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x17, 0x70, 0x72, 0x65, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x28, 0x68, + 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, + 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x25, 0x68, + 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x69, 0x63, 0x61, 0x6c, 0x57, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6c, 0x65, 0x72, + 0x61, 0x6e, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x1f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x5f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x69, + 0x73, 0x69, 0x73, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, + 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x52, 0x0a, 0x26, 0x69, + 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x31, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x69, 0x73, 0x69, + 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x31, + 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, + 0x41, 0x0a, 0x1d, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x5f, 0x74, + 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x69, 0x73, 0x69, 0x73, 0x53, 0x69, 0x6e, 0x67, + 0x6c, 0x65, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x69, 0x73, 0x69, 0x73, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x26, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6e, 0x67, 0x5f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, + 0x49, 0x73, 0x69, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x41, 0x66, 0x69, + 0x53, 0x61, 0x66, 0x69, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x54, 0x0a, 0x27, 0x69, 0x73, + 0x69, 0x73, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x69, 0x73, 0x69, + 0x73, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, + 0x12, 0x58, 0x0a, 0x29, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, + 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x25, 0x69, 0x73, 0x69, 0x73, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, + 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x21, 0x69, 0x73, + 0x69, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x69, 0x73, 0x69, 0x73, 0x52, 0x65, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x53, 0x75, 0x70, 0x70, 0x72, 0x65, 0x73, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x70, 0x5f, 0x6e, 0x65, 0x69, 0x67, + 0x68, 0x62, 0x6f, 0x72, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x11, 0x69, 0x70, 0x4e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x4d, 0x69, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x73, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x6f, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x18, 0x10, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x12, 0x6f, 0x73, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4e, 0x6f, + 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x73, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x5f, + 0x72, 0x70, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x6f, 0x73, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x52, 0x70, 0x12, + 0x50, 0x0a, 0x25, 0x6c, 0x6c, 0x64, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, + 0x65, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, + 0x6c, 0x6c, 0x64, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x12, 0x55, 0x0a, 0x28, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x67, 0x70, + 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x23, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x42, 0x67, 0x70, 0x4c, + 0x61, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x47, 0x0a, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, + 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x73, 0x74, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3f, 0x0a, 0x1d, 0x69, 0x70, 0x76, 0x36, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x67, 0x72, 0x69, 0x62, 0x69, + 0x5f, 0x6e, 0x68, 0x5f, 0x64, 0x6d, 0x61, 0x63, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, + 0x69, 0x70, 0x76, 0x36, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x47, 0x72, 0x69, + 0x62, 0x69, 0x4e, 0x68, 0x44, 0x6d, 0x61, 0x63, 0x12, 0x45, 0x0a, 0x1f, 0x65, 0x63, 0x6e, 0x5f, + 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, + 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1c, 0x65, 0x63, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x45, 0x0a, 0x1f, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, + 0x64, 0x5f, 0x70, 0x6b, 0x74, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x69, 0x70, 0x76, 0x36, 0x44, 0x69, + 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x50, 0x6b, 0x74, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x77, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, + 0x64, 0x72, 0x6f, 0x70, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, + 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1c, 0x63, + 0x6c, 0x69, 0x5f, 0x74, 0x61, 0x6b, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6f, 0x63, 0x18, 0x1d, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x18, 0x63, 0x6c, 0x69, 0x54, 0x61, 0x6b, 0x65, 0x73, 0x50, 0x72, 0x65, 0x63, 0x65, + 0x64, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x4f, 0x63, 0x12, 0x3f, 0x0a, 0x1c, 0x73, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x77, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x19, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x1a, + 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5f, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x69, 0x64, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x17, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x43, 0x68, 0x69, 0x70, 0x49, 0x64, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x25, 0x62, 0x61, 0x63, + 0x6b, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x66, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x61, + 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x62, 0x61, 0x63, 0x6b, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x46, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, + 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x21, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x18, 0x21, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x5a, 0x0a, 0x2b, 0x6e, 0x6f, 0x5f, 0x6d, 0x69, + 0x78, 0x5f, 0x6f, 0x66, 0x5f, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x5f, 0x61, 0x6e, 0x64, 0x5f, + 0x75, 0x6e, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x6e, 0x6f, + 0x4d, 0x69, 0x78, 0x4f, 0x66, 0x54, 0x61, 0x67, 0x67, 0x65, 0x64, 0x41, 0x6e, 0x64, 0x55, 0x6e, + 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x53, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x25, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x14, 0x73, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x21, 0x65, 0x78, 0x70, + 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, + 0x72, 0x65, 0x66, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x26, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x27, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x78, 0x70, 0x6c, + 0x69, 0x63, 0x69, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, + 0x29, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x50, + 0x6f, 0x72, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x65, 0x78, 0x70, 0x6c, + 0x69, 0x63, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x69, + 0x6e, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x72, 0x66, 0x18, 0x2a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x1d, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x49, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, + 0x72, 0x66, 0x12, 0x2c, 0x0a, 0x12, 0x71, 0x6f, 0x73, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, + 0x64, 0x5f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x73, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, + 0x71, 0x6f, 0x73, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x4f, 0x63, 0x74, 0x65, 0x74, 0x73, + 0x12, 0x4f, 0x0a, 0x24, 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, + 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, + 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x50, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x74, + 0x72, 0x79, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x49, 0x0a, 0x22, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, + 0x6d, 0x61, 0x63, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x77, 0x69, 0x74, + 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, 0x72, 0x70, 0x18, 0x2e, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1d, 0x67, 0x72, 0x69, 0x62, 0x69, 0x4d, 0x61, 0x63, 0x4f, 0x76, 0x65, 0x72, + 0x72, 0x69, 0x64, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x72, + 0x70, 0x12, 0x4a, 0x0a, 0x22, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x72, + 0x6f, 0x75, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x41, + 0x66, 0x69, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x56, 0x0a, + 0x28, 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x5f, 0x63, 0x6f, 0x6d, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x30, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x24, 0x67, 0x6e, 0x6f, 0x69, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x6e, 0x74, 0x70, 0x5f, 0x6e, 0x6f, 0x6e, + 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x72, 0x66, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, + 0x6e, 0x74, 0x70, 0x4e, 0x6f, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x72, 0x66, + 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x6f, + 0x6d, 0x69, 0x74, 0x5f, 0x6c, 0x32, 0x5f, 0x6d, 0x74, 0x75, 0x18, 0x32, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x6f, 0x6d, 0x69, 0x74, 0x4c, 0x32, 0x4d, 0x74, 0x75, 0x12, 0x46, 0x0a, 0x20, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x63, + 0x61, 0x72, 0x64, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, + 0x33, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x61, 0x72, 0x64, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x64, 0x65, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, + 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x12, 0x2e, + 0x0a, 0x13, 0x62, 0x67, 0x70, 0x5f, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x62, 0x67, 0x70, + 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4d, + 0x0a, 0x24, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x71, 0x75, 0x61, 0x6c, 0x5f, 0x77, 0x61, 0x69, 0x74, + 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x6c, 0x69, + 0x6e, 0x6b, 0x51, 0x75, 0x61, 0x6c, 0x57, 0x61, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x43, 0x0a, + 0x1e, 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x65, 0x6d, 0x70, + 0x74, 0x79, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, + 0x3f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x12, 0x56, 0x0a, 0x28, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x40, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x16, 0x62, 0x67, + 0x70, 0x5f, 0x6d, 0x64, 0x35, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, + 0x65, 0x73, 0x65, 0x74, 0x18, 0x41, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x62, 0x67, 0x70, 0x4d, + 0x64, 0x35, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, + 0x4b, 0x0a, 0x23, 0x64, 0x65, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x73, + 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x42, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x64, 0x65, + 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x64, 0x41, 0x73, 0x44, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x2a, 0x0a, 0x11, + 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, 0x72, 0x69, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, + 0x79, 0x18, 0x43, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x67, 0x72, 0x69, 0x62, 0x69, 0x52, 0x69, + 0x62, 0x61, 0x63, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x44, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x12, 0x3b, 0x0a, 0x1a, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x45, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x46, 0x6f, 0x72, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x30, 0x0a, + 0x14, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x34, 0x0a, 0x16, 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x47, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x14, 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x4c, 0x0a, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x72, 0x66, 0x5f, 0x62, 0x65, + 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x48, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x56, 0x72, 0x66, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x76, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x49, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x10, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x56, 0x6c, 0x61, 0x6e, 0x49, + 0x64, 0x12, 0x58, 0x0a, 0x2a, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x6f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, + 0x72, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x18, + 0x4a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x67, 0x72, 0x69, 0x62, 0x69, 0x4d, 0x61, 0x63, 0x4f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x72, 0x70, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x4b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x6f, 0x73, 0x5f, + 0x6f, 0x63, 0x74, 0x65, 0x74, 0x73, 0x18, 0x4c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x71, 0x6f, + 0x73, 0x4f, 0x63, 0x74, 0x65, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x70, 0x75, 0x5f, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x18, + 0x4d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x70, 0x75, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x41, 0x6e, 0x63, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x12, 0x41, 0x0a, 0x1d, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x30, 0x18, 0x4e, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1a, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x64, 0x53, + 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x30, 0x12, 0x5f, 0x0a, 0x2d, + 0x67, 0x6e, 0x6f, 0x69, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x5f, + 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x18, 0x4f, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x28, 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x6f, + 0x76, 0x65, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, + 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x16, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x24, 0x70, 0x34, 0x72, 0x74, 0x5f, + 0x75, 0x6e, 0x73, 0x65, 0x74, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x5f, + 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, + 0x51, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x70, 0x34, 0x72, 0x74, 0x55, 0x6e, 0x73, 0x65, 0x74, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, + 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x62, 0x6b, 0x75, 0x70, + 0x5f, 0x61, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, + 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x52, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x62, 0x6b, + 0x75, 0x70, 0x41, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x49, 0x0a, 0x22, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, + 0x6e, 0x68, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x76, 0x72, 0x66, + 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x65, 0x63, 0x61, 0x70, 0x18, 0x53, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1d, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4e, 0x68, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x73, 0x56, 0x72, 0x66, 0x57, 0x69, 0x74, 0x68, 0x44, 0x65, 0x63, 0x61, 0x70, + 0x12, 0x43, 0x0a, 0x1e, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x18, 0x55, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x69, 0x73, 0x69, 0x73, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x41, 0x66, 0x69, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x23, 0x70, 0x34, 0x72, 0x74, 0x5f, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x56, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1f, 0x70, 0x34, 0x72, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, 0x61, + 0x62, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x12, 0x5e, 0x0a, 0x2d, 0x6f, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, 0x69, 0x6e, 0x65, + 0x63, 0x61, 0x72, 0x64, 0x18, 0x57, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x6f, 0x73, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x73, 0x53, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x4f, 0x72, 0x4c, 0x69, 0x6e, 0x65, 0x63, + 0x61, 0x72, 0x64, 0x12, 0x42, 0x0a, 0x1e, 0x6f, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x63, 0x68, + 0x61, 0x73, 0x73, 0x69, 0x73, 0x18, 0x58, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x6f, 0x73, 0x43, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x73, + 0x43, 0x68, 0x61, 0x73, 0x73, 0x69, 0x73, 0x12, 0x57, 0x0a, 0x2a, 0x69, 0x73, 0x69, 0x73, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6c, 0x31, 0x5f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6c, 0x32, 0x5f, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x69, 0x73, 0x69, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x53, 0x61, 0x6d, 0x65, 0x4c, 0x31, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x57, 0x69, 0x74, 0x68, 0x4c, 0x32, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x12, 0x57, 0x0a, 0x2a, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x64, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x5f, 0x6f, + 0x73, 0x70, 0x66, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x5c, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x62, 0x67, 0x70, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6c, 0x4f, 0x73, 0x70, 0x66, + 0x53, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x4e, 0x0a, 0x24, 0x70, 0x34, 0x72, + 0x74, 0x5f, 0x67, 0x64, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x64, + 0x6f, 0x74, 0x31, 0x71, 0x5f, 0x73, 0x75, 0x62, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x18, 0x5d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x70, 0x34, 0x72, 0x74, 0x47, 0x64, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x44, 0x6f, 0x74, 0x31, 0x71, 0x53, 0x75, 0x62, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x2a, 0x61, 0x74, 0x65, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x5e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x61, + 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x5f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, + 0x65, 0x74, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x73, 0x0a, 0x38, + 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x73, 0x70, 0x5f, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x73, 0x5f, 0x6c, 0x73, 0x70, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x60, 0x20, 0x01, 0x28, 0x08, 0x52, 0x31, + 0x69, 0x73, 0x69, 0x73, 0x4c, 0x73, 0x70, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x4c, + 0x73, 0x70, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x12, 0x4f, 0x0a, 0x24, 0x6c, 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x70, + 0x75, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x62, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x21, 0x6c, 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x43, 0x70, 0x75, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x71, 0x6f, 0x73, 0x5f, 0x76, 0x6f, 0x71, 0x5f, 0x64, 0x72, - 0x6f, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x67, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x71, 0x6f, - 0x73, 0x56, 0x6f, 0x71, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x55, - 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x61, 0x74, - 0x65, 0x5f, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x68, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x1b, 0x61, 0x74, 0x65, 0x49, 0x70, 0x76, 0x36, 0x46, 0x6c, 0x6f, 0x77, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x12, 0x50, 0x0a, 0x25, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x73, 0x5f, - 0x63, 0x73, 0x6e, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x69, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x21, 0x69, 0x73, 0x69, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x73, 0x43, 0x73, 0x6e, 0x70, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x71, 0x0a, 0x37, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x65, 0x72, 0x5f, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x72, 0x65, 0x61, - 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6a, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x30, 0x69, 0x73, 0x69, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, - 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x44, 0x72, 0x6f, - 0x70, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x72, 0x65, 0x61, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x50, 0x0a, 0x25, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6b, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x69, 0x73, 0x69, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, - 0x72, 0x50, 0x61, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x55, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, - 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6c, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, - 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x6d, 0x6f, 0x64, 0x65, - 0x5f, 0x72, 0x61, 0x77, 0x5f, 0x67, 0x6e, 0x6d, 0x69, 0x18, 0x6d, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, - 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x61, 0x77, 0x47, 0x6e, 0x6d, 0x69, 0x12, 0x40, 0x0a, - 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x73, 0x73, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x6e, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x6b, 0x69, 0x70, 0x54, 0x63, 0x70, 0x4e, 0x65, 0x67, - 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, - 0x4c, 0x0a, 0x23, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x73, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x61, 0x66, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x69, 0x73, - 0x69, 0x73, 0x4c, 0x73, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x61, - 0x66, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, - 0x15, 0x71, 0x6f, 0x73, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x70, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x71, 0x6f, - 0x73, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x49, 0x64, - 0x12, 0x55, 0x0a, 0x28, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x69, 0x62, 0x5f, 0x66, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x66, 0x6f, 0x72, 0x77, - 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x71, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x23, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x69, 0x62, 0x46, 0x61, 0x69, 0x6c, 0x65, - 0x64, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, - 0x6e, 0x67, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x25, 0x71, 0x6f, 0x73, 0x5f, 0x62, - 0x75, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, - 0x18, 0x72, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x71, 0x6f, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65, - 0x72, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x66, 0x0a, 0x31, 0x62, 0x67, 0x70, - 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, - 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x73, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x2b, 0x62, 0x67, 0x70, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x45, - 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x45, 0x6e, - 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x12, 0x31, 0x0a, 0x15, 0x62, 0x67, 0x70, 0x5f, 0x6c, 0x6c, 0x67, 0x72, 0x5f, 0x6f, 0x63, - 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x74, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x12, 0x62, 0x67, 0x70, 0x4c, 0x6c, 0x67, 0x72, 0x4f, 0x63, 0x55, 0x6e, 0x64, 0x65, 0x66, - 0x69, 0x6e, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x1d, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x75, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x74, 0x75, 0x6e, - 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x74, 0x75, 0x6e, 0x6e, 0x65, - 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x76, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1b, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, 0x74, - 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x26, - 0x65, 0x63, 0x6e, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x6d, 0x61, 0x78, - 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x77, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x65, 0x63, - 0x6e, 0x53, 0x61, 0x6d, 0x65, 0x4d, 0x69, 0x6e, 0x4d, 0x61, 0x78, 0x54, 0x68, 0x72, 0x65, 0x73, - 0x68, 0x6f, 0x6c, 0x64, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x41, 0x0a, 0x1d, 0x71, 0x6f, 0x73, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, - 0x18, 0x78, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x71, 0x6f, 0x73, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x71, 0x6f, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x77, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x79, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x71, - 0x6f, 0x73, 0x53, 0x65, 0x74, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x42, 0x0a, 0x1e, - 0x71, 0x6f, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x7a, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x71, 0x6f, 0x73, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x7b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, - 0x69, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, - 0x0a, 0x21, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x5f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x18, 0x7c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x49, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x47, 0x0a, 0x20, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, - 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x7d, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x1d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4c, 0x69, 0x6e, 0x6b, 0x4c, 0x6f, - 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x12, 0x4d, 0x0a, 0x24, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x6c, 0x71, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x7e, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1f, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x6c, 0x71, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x4f, 0x70, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x12, 0x4a, 0x0a, 0x22, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, - 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x72, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x18, 0x7f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x62, 0x67, - 0x70, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x12, 0x58, 0x0a, 0x29, - 0x62, 0x67, 0x70, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x63, 0x5f, 0x6d, - 0x61, 0x78, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x24, 0x62, 0x67, 0x70, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4f, 0x63, 0x4d, 0x61, - 0x78, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x26, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, - 0x67, 0x70, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, - 0x5f, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x5f, 0x61, 0x66, 0x69, 0x73, 0x61, 0x66, 0x69, - 0x18, 0x81, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x67, 0x70, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x57, 0x69, 0x74, 0x68, - 0x6f, 0x75, 0x74, 0x41, 0x66, 0x69, 0x73, 0x61, 0x66, 0x69, 0x12, 0x62, 0x0a, 0x2e, 0x6d, 0x69, - 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, - 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, - 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x82, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x29, 0x6d, 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x48, - 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x68, - 0x0a, 0x31, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, - 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x83, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2c, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6e, 0x67, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x42, 0x65, 0x66, 0x6f, - 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5d, 0x0a, 0x2b, 0x67, 0x6e, 0x6f, 0x69, - 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, - 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x84, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, - 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x73, 0x6b, 0x69, 0x70, 0x5f, - 0x6e, 0x6f, 0x6e, 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x85, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x6f, 0x6e, 0x42, 0x67, 0x70, 0x52, 0x6f, 0x75, - 0x74, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x55, 0x0a, - 0x27, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x79, - 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x75, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x86, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x23, 0x69, 0x73, 0x69, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x53, 0x74, 0x79, 0x6c, 0x65, - 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x87, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x48, - 0x6f, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x55, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x6b, 0x69, - 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, - 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x88, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, - 0x6b, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x4e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x5f, 0x0a, 0x2c, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x72, 0x6f, - 0x75, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8a, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x28, 0x69, 0x70, - 0x76, 0x36, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x41, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x5d, 0x0a, 0x2b, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x5f, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8b, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, - 0x64, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6d, 0x75, 0x6c, 0x74, - 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x61, 0x73, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, - 0x73, 0x6b, 0x69, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, - 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x41, 0x73, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x70, 0x62, 0x66, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x65, 0x63, 0x61, - 0x70, 0x5f, 0x65, 0x6e, 0x63, 0x61, 0x70, 0x5f, 0x76, 0x72, 0x66, 0x18, 0x8d, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x62, 0x66, 0x57, 0x69, 0x74, 0x68, 0x44, - 0x65, 0x63, 0x61, 0x70, 0x45, 0x6e, 0x63, 0x61, 0x70, 0x56, 0x72, 0x66, 0x12, 0x31, 0x0a, 0x14, - 0x74, 0x74, 0x6c, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x18, 0x8e, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x74, 0x74, 0x6c, - 0x43, 0x6f, 0x70, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x4b, 0x0a, 0x22, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, 0x64, 0x65, 0x63, 0x61, 0x70, 0x5f, 0x6d, - 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x6c, 0x65, 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8f, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x67, 0x72, - 0x69, 0x62, 0x69, 0x44, 0x65, 0x63, 0x61, 0x70, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x50, 0x6c, 0x65, - 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, - 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6c, 0x65, - 0x76, 0x65, 0x6c, 0x18, 0x90, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x73, 0x6b, 0x69, 0x70, - 0x49, 0x73, 0x69, 0x73, 0x53, 0x65, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x44, 0x0a, 0x1f, - 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x91, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x49, 0x73, 0x69, 0x73, - 0x53, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, - 0x70, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70, - 0x53, 0x65, 0x74, 0x52, 0x70, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x27, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x93, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x73, 0x6b, 0x69, 0x70, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x62, 0x0a, 0x2e, 0x62, - 0x67, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6d, 0x61, - 0x74, 0x63, 0x68, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, - 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x94, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x62, 0x67, 0x70, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, - 0x79, 0x53, 0x65, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x41, 0x0a, 0x1d, 0x70, 0x66, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, 0x6d, 0x61, - 0x74, 0x63, 0x68, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, 0x75, 0x6c, 0x65, - 0x18, 0x95, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x70, 0x66, 0x52, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x75, - 0x6c, 0x65, 0x12, 0x67, 0x0a, 0x31, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, - 0x72, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, - 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x96, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2b, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x72, 0x74, 0x54, 0x6f, 0x4f, 0x70, 0x74, - 0x69, 0x63, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x73, - 0x6b, 0x69, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6f, 0x70, - 0x18, 0x97, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4f, 0x70, 0x12, 0x51, 0x0a, 0x25, 0x72, 0x65, 0x6f, 0x72, - 0x64, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x76, 0x65, - 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x74, - 0x79, 0x18, 0x98, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x72, 0x65, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x46, 0x6f, 0x72, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x43, - 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x1f, 0x61, - 0x64, 0x64, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x69, 0x61, 0x5f, 0x63, 0x6c, 0x69, 0x18, 0x99, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x61, 0x64, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, - 0x67, 0x42, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x69, 0x61, 0x43, 0x6c, - 0x69, 0x12, 0x33, 0x0a, 0x15, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x9a, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x13, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x3d, 0x0a, 0x1b, 0x62, 0x67, 0x70, 0x5f, 0x72, 0x69, - 0x62, 0x5f, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x9b, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x62, 0x67, - 0x70, 0x52, 0x69, 0x62, 0x4f, 0x63, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x9c, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x53, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x73, 0x65, 0x74, 0x5f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x18, 0x9d, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x73, 0x65, 0x74, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x41, 0x73, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x12, 0x72, 0x0a, 0x38, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x70, 0x76, 0x34, - 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, 0x72, 0x70, 0x18, 0x9e, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x2f, 0x69, 0x70, 0x76, 0x36, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x70, 0x76, 0x34, 0x4e, 0x65, 0x78, - 0x74, 0x48, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x53, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x41, 0x72, 0x70, 0x12, 0x50, 0x0a, 0x25, 0x70, 0x66, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6f, - 0x72, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x62, 0x72, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x9f, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x70, 0x66, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, - 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x50, - 0x62, 0x72, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x2e, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, - 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0xa0, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x28, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x58, 0x0a, 0x29, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, - 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x65, 0x18, 0xa1, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, - 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x69, - 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x52, 0x65, 0x63, - 0x75, 0x72, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x2c, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x64, 0x72, 0x6f, - 0x70, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x18, 0xa2, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x26, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x44, - 0x72, 0x6f, 0x70, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x74, 0x72, 0x79, 0x12, 0x73, 0x0a, 0x37, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x7a, - 0x72, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x5f, 0x74, 0x75, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x73, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0xa3, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x31, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5a, 0x72, - 0x4f, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x75, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x54, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x1f, 0x70, 0x6c, 0x71, 0x5f, - 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, - 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xa4, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x1c, 0x70, 0x6c, 0x71, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x53, 0x74, 0x61, 0x74, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x12, 0x4b, 0x0a, 0x22, 0x70, 0x6c, 0x71, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x6d, - 0x61, 0x78, 0x5f, 0x6d, 0x74, 0x75, 0x18, 0xa5, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1e, 0x70, - 0x6c, 0x71, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x4d, 0x61, 0x78, 0x4d, 0x74, 0x75, 0x12, 0x4b, 0x0a, - 0x22, 0x70, 0x6c, 0x71, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x63, - 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x5f, - 0x70, 0x70, 0x73, 0x18, 0xa6, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x70, 0x6c, 0x71, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x69, 0x65, 0x73, 0x4d, 0x61, 0x78, 0x50, 0x70, 0x73, 0x12, 0x57, 0x0a, 0x28, 0x62, 0x67, + 0x65, 0x64, 0x12, 0x53, 0x0a, 0x26, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x63, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x23, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x55, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x2b, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x70, 0x75, 0x5f, 0x75, + 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x61, 0x72, 0x64, 0x43, 0x70, 0x75, 0x55, + 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x5f, + 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, + 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x27, + 0x6c, 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, + 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x66, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x6c, + 0x69, 0x6e, 0x65, 0x63, 0x61, 0x72, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x74, 0x69, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x71, 0x6f, 0x73, 0x5f, 0x76, 0x6f, 0x71, 0x5f, 0x64, + 0x72, 0x6f, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x67, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x71, + 0x6f, 0x73, 0x56, 0x6f, 0x71, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x61, + 0x74, 0x65, 0x5f, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x68, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x61, 0x74, 0x65, 0x49, 0x70, 0x76, 0x36, 0x46, 0x6c, 0x6f, + 0x77, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x50, 0x0a, 0x25, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x73, + 0x5f, 0x63, 0x73, 0x6e, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x69, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x21, 0x69, 0x73, 0x69, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x73, 0x43, 0x73, 0x6e, 0x70, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x12, 0x71, 0x0a, 0x37, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x65, 0x72, 0x5f, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x72, 0x65, + 0x61, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6a, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x30, 0x69, 0x73, 0x69, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x44, 0x72, + 0x6f, 0x70, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x72, 0x65, 0x61, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x50, 0x0a, 0x25, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0x6b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x69, 0x73, 0x69, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x50, 0x61, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x55, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x22, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, + 0x64, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6c, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x72, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, + 0x61, 0x63, 0x65, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x6d, 0x6f, 0x64, + 0x65, 0x5f, 0x72, 0x61, 0x77, 0x5f, 0x67, 0x6e, 0x6d, 0x69, 0x18, 0x6d, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x62, + 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x61, 0x77, 0x47, 0x6e, 0x6d, 0x69, 0x12, 0x40, + 0x0a, 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x6e, 0x65, 0x67, 0x6f, 0x74, + 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x73, 0x73, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, + 0x6e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x6b, 0x69, 0x70, 0x54, 0x63, 0x70, 0x4e, 0x65, + 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x12, 0x4c, 0x0a, 0x23, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x73, 0x70, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x61, 0x66, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x69, + 0x73, 0x69, 0x73, 0x4c, 0x73, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, + 0x61, 0x66, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x31, + 0x0a, 0x15, 0x71, 0x6f, 0x73, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x70, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x71, + 0x6f, 0x73, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x49, + 0x64, 0x12, 0x55, 0x0a, 0x28, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x69, 0x62, 0x5f, 0x66, 0x61, + 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x66, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x71, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x23, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x69, 0x62, 0x46, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x25, 0x71, 0x6f, 0x73, 0x5f, + 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x18, 0x72, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x71, 0x6f, 0x73, 0x42, 0x75, 0x66, 0x66, + 0x65, 0x72, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x66, 0x0a, 0x31, 0x62, 0x67, + 0x70, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, + 0x64, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, + 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0x73, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2b, 0x62, 0x67, 0x70, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x62, 0x67, 0x70, 0x5f, 0x6c, 0x6c, 0x67, 0x72, 0x5f, 0x6f, + 0x63, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x74, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x12, 0x62, 0x67, 0x70, 0x4c, 0x6c, 0x67, 0x72, 0x4f, 0x63, 0x55, 0x6e, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x1d, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x75, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x74, 0x75, + 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x74, 0x75, 0x6e, 0x6e, + 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x76, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1b, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, + 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x51, 0x0a, + 0x26, 0x65, 0x63, 0x6e, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x6d, 0x61, + 0x78, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x77, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x65, + 0x63, 0x6e, 0x53, 0x61, 0x6d, 0x65, 0x4d, 0x69, 0x6e, 0x4d, 0x61, 0x78, 0x54, 0x68, 0x72, 0x65, + 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x41, 0x0a, 0x1d, 0x71, 0x6f, 0x73, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x18, 0x78, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x71, 0x6f, 0x73, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x71, 0x6f, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x77, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x79, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, + 0x71, 0x6f, 0x73, 0x53, 0x65, 0x74, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x42, 0x0a, + 0x1e, 0x71, 0x6f, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0x7a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x71, 0x6f, 0x73, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x7b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, + 0x73, 0x69, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, + 0x48, 0x0a, 0x21, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, + 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x18, 0x7c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x47, 0x0a, 0x20, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, + 0x6b, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x7d, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x1d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4c, 0x69, 0x6e, 0x6b, 0x4c, + 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x12, 0x4d, 0x0a, 0x24, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x6c, 0x71, 0x5f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x7e, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1f, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x6c, 0x71, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x12, 0x4a, 0x0a, 0x22, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, + 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x18, 0x7f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x62, + 0x67, 0x70, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x12, 0x58, 0x0a, + 0x29, 0x62, 0x67, 0x70, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x63, 0x5f, + 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x24, 0x62, 0x67, 0x70, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4f, 0x63, 0x4d, + 0x61, 0x78, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x26, 0x73, 0x6b, 0x69, 0x70, 0x5f, + 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x5f, 0x61, 0x66, 0x69, 0x73, 0x61, 0x66, + 0x69, 0x18, 0x81, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x67, + 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x57, 0x69, 0x74, + 0x68, 0x6f, 0x75, 0x74, 0x41, 0x66, 0x69, 0x73, 0x61, 0x66, 0x69, 0x12, 0x62, 0x0a, 0x2e, 0x6d, + 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, + 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x82, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x6d, 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, + 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, + 0x68, 0x0a, 0x31, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x61, 0x72, 0x64, 0x77, + 0x61, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x83, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2c, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6e, 0x67, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x42, 0x65, 0x66, + 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5d, 0x0a, 0x2b, 0x67, 0x6e, 0x6f, + 0x69, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x72, + 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x84, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x27, 0x67, 0x6e, 0x6f, 0x69, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x73, 0x6b, 0x69, 0x70, + 0x5f, 0x6e, 0x6f, 0x6e, 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x65, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x85, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x6f, 0x6e, 0x42, 0x67, 0x70, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x55, + 0x0a, 0x27, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x86, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x23, 0x69, 0x73, 0x69, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x53, 0x74, 0x79, 0x6c, + 0x65, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x87, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x29, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x65, 0x78, 0x74, + 0x48, 0x6f, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x65, 0x66, 0x55, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x6b, + 0x69, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, + 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x88, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, + 0x73, 0x6b, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x4e, 0x65, 0x78, 0x74, 0x68, 0x6f, + 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x5f, 0x0a, 0x2c, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x72, + 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8a, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x28, 0x69, + 0x70, 0x76, 0x36, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x41, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, + 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x55, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x5d, 0x0a, 0x2b, 0x70, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, + 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8b, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x70, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, + 0x65, 0x64, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x61, 0x73, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x41, 0x73, 0x12, 0x40, 0x0a, 0x1d, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x62, 0x66, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x65, 0x63, + 0x61, 0x70, 0x5f, 0x65, 0x6e, 0x63, 0x61, 0x70, 0x5f, 0x76, 0x72, 0x66, 0x18, 0x8d, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x62, 0x66, 0x57, 0x69, 0x74, 0x68, + 0x44, 0x65, 0x63, 0x61, 0x70, 0x45, 0x6e, 0x63, 0x61, 0x70, 0x56, 0x72, 0x66, 0x12, 0x31, 0x0a, + 0x14, 0x74, 0x74, 0x6c, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8e, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x74, 0x74, + 0x6c, 0x43, 0x6f, 0x70, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x4b, 0x0a, 0x22, 0x67, 0x72, 0x69, 0x62, 0x69, 0x5f, 0x64, 0x65, 0x63, 0x61, 0x70, 0x5f, + 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x6c, 0x65, 0x6e, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x8f, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x67, + 0x72, 0x69, 0x62, 0x69, 0x44, 0x65, 0x63, 0x61, 0x70, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x50, 0x6c, + 0x65, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, + 0x13, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x18, 0x90, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x73, 0x6b, 0x69, + 0x70, 0x49, 0x73, 0x69, 0x73, 0x53, 0x65, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x44, 0x0a, + 0x1f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x91, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x49, 0x73, 0x69, + 0x73, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x5f, + 0x72, 0x70, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x92, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, + 0x70, 0x53, 0x65, 0x74, 0x52, 0x70, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x53, 0x65, 0x74, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x27, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x93, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x73, 0x6b, 0x69, 0x70, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x62, 0x0a, 0x2e, + 0x62, 0x67, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, + 0x65, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x94, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x62, 0x67, 0x70, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x74, 0x79, 0x53, 0x65, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x41, 0x0a, 0x1d, 0x70, 0x66, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, 0x75, 0x6c, + 0x65, 0x18, 0x95, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x70, 0x66, 0x52, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, + 0x75, 0x6c, 0x65, 0x12, 0x67, 0x0a, 0x31, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x96, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x2b, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x72, 0x74, 0x54, 0x6f, 0x4f, 0x70, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6d, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x11, + 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6f, + 0x70, 0x18, 0x97, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4f, 0x70, 0x12, 0x51, 0x0a, 0x25, 0x72, 0x65, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x76, + 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, + 0x74, 0x79, 0x18, 0x98, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x72, 0x65, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x46, 0x6f, 0x72, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x1f, + 0x61, 0x64, 0x64, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x73, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x69, 0x61, 0x5f, 0x63, 0x6c, 0x69, 0x18, + 0x99, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x61, 0x64, 0x64, 0x4d, 0x69, 0x73, 0x73, 0x69, + 0x6e, 0x67, 0x42, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x69, 0x61, 0x43, + 0x6c, 0x69, 0x12, 0x33, 0x0a, 0x15, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x9a, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x13, 0x73, 0x6b, 0x69, 0x70, 0x4d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x3d, 0x0a, 0x1b, 0x62, 0x67, 0x70, 0x5f, 0x72, + 0x69, 0x62, 0x5f, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x9b, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x62, + 0x67, 0x70, 0x52, 0x69, 0x62, 0x4f, 0x63, 0x50, 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x9c, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x53, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x73, 0x65, 0x74, 0x5f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x9d, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x73, 0x65, 0x74, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x41, 0x73, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x12, 0x72, 0x0a, 0x38, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x70, 0x76, + 0x34, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, 0x72, 0x70, 0x18, 0x9e, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2f, 0x69, 0x70, 0x76, 0x36, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x70, 0x76, 0x34, 0x4e, 0x65, + 0x78, 0x74, 0x48, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x63, 0x41, 0x72, 0x70, 0x12, 0x50, 0x0a, 0x25, 0x70, 0x66, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x62, 0x72, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, + 0x9f, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x70, 0x66, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x50, 0x62, 0x72, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x2e, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0xa0, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x28, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x58, 0x0a, 0x29, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, + 0x5f, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x65, 0x18, 0xa1, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x24, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x52, 0x65, + 0x63, 0x75, 0x72, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x2c, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x64, 0x72, + 0x6f, 0x70, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x74, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0xa2, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x26, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x44, 0x72, 0x6f, 0x70, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, 0x70, 0x54, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x74, 0x72, 0x79, 0x12, 0x73, 0x0a, 0x37, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, + 0x7a, 0x72, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x5f, 0x74, 0x75, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, + 0xa3, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x31, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5a, + 0x72, 0x4f, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, + 0x75, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x1f, 0x70, 0x6c, 0x71, + 0x5f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, + 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xa4, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x1c, 0x70, 0x6c, 0x71, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x4b, 0x0a, 0x22, 0x70, 0x6c, 0x71, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x5f, + 0x6d, 0x61, 0x78, 0x5f, 0x6d, 0x74, 0x75, 0x18, 0xa5, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1e, + 0x70, 0x6c, 0x71, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x4d, 0x61, 0x78, 0x4d, 0x74, 0x75, 0x12, 0x4b, + 0x0a, 0x22, 0x70, 0x6c, 0x71, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, + 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x6d, 0x61, 0x78, + 0x5f, 0x70, 0x70, 0x73, 0x18, 0xa6, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x70, 0x6c, 0x71, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x69, 0x65, 0x73, 0x4d, 0x61, 0x78, 0x50, 0x70, 0x73, 0x12, 0x57, 0x0a, 0x28, 0x62, + 0x67, 0x70, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xa7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, + 0x62, 0x67, 0x70, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x75, + 0x6e, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x22, 0x62, 0x67, 0x70, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xa8, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1e, 0x62, 0x67, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x53, + 0x65, 0x74, 0x52, 0x65, 0x66, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x69, 0x62, 0x5f, 0x77, 0x65, 0x63, 0x6d, 0x70, 0x18, 0xa9, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x69, 0x62, 0x57, 0x65, 0x63, 0x6d, 0x70, 0x12, + 0x43, 0x0a, 0x1d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x18, 0xaa, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x75, 0x73, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x5f, 0x73, 0x65, + 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0xab, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x1b, 0x75, 0x73, 0x65, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x54, 0x61, 0x67, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x1c, + 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x63, 0x6f, + 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0xac, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x67, 0x70, 0x53, 0x65, 0x6e, 0x64, + 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x5e, 0x0a, + 0x2c, 0x62, 0x67, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x73, 0x65, 0x74, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xae, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x62, 0x67, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2a, 0x0a, + 0x11, 0x73, 0x65, 0x74, 0x5f, 0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x18, 0xaf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x65, 0x74, 0x4e, 0x6f, + 0x50, 0x65, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x46, 0x0a, 0x20, 0x62, 0x67, 0x70, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x5f, 0x69, 0x73, 0x5f, 0x61, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0xb0, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x62, 0x67, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x74, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x73, 0x41, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x12, 0x59, 0x0a, 0x2a, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x70, 0x76, 0x36, + 0x5f, 0x6e, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0xb1, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x69, 0x70, 0x76, 0x34, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x70, 0x76, 0x36, 0x4e, + 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x59, 0x0a, 0x2a, + 0x69, 0x70, 0x76, 0x36, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x6e, 0x68, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xb2, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x24, 0x69, 0x70, 0x76, 0x36, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x70, 0x76, 0x34, 0x4e, 0x68, 0x55, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x19, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x72, 0x6f, + 0x70, 0x5f, 0x6e, 0x68, 0x18, 0xb3, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x44, 0x72, 0x6f, 0x70, + 0x4e, 0x68, 0x12, 0x49, 0x0a, 0x21, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, + 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0xb4, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x45, + 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x44, 0x0a, + 0x1e, 0x62, 0x67, 0x70, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0xb5, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x62, 0x67, 0x70, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x12, 0x4a, 0x0a, 0x22, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x6f, 0x6e, 0x5f, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x72, 0x66, 0x18, 0xb6, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1d, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x42, 0x67, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x72, 0x66, 0x12, + 0x45, 0x0a, 0x1f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x5f, 0x74, 0x61, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, + 0x65, 0x64, 0x18, 0xb7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x72, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x67, 0x53, 0x65, 0x74, 0x45, 0x6d, + 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x50, 0x0a, 0x26, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, + 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x6f, 0x72, + 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x61, 0x73, + 0x18, 0xb8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x66, 0x69, + 0x53, 0x61, 0x66, 0x69, 0x50, 0x61, 0x74, 0x68, 0x46, 0x6f, 0x72, 0x42, 0x67, 0x70, 0x4d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x41, 0x73, 0x12, 0x4c, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x6d, + 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, + 0x65, 0x78, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xb9, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x67, 0x65, 0x78, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x74, + 0x6f, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x66, 0x69, 0x73, 0x18, 0xba, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1b, 0x73, 0x61, 0x6d, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x41, 0x74, 0x74, + 0x61, 0x63, 0x68, 0x65, 0x64, 0x54, 0x6f, 0x41, 0x6c, 0x6c, 0x41, 0x66, 0x69, 0x73, 0x12, 0x49, + 0x0a, 0x21, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x18, 0xbb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x6b, 0x69, 0x70, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x46, 0x6f, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x6b, 0x69, + 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0xbc, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x41, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x55, 0x0a, + 0x27, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, + 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0xbd, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x23, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x57, 0x69, + 0x74, 0x68, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x48, 0x0a, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xbe, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x1d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x35, + 0x0a, 0x16, 0x73, 0x6c, 0x61, 0x61, 0x63, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x31, 0x32, 0x38, 0x18, 0xbf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x14, 0x73, 0x6c, 0x61, 0x61, 0x63, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x4c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x31, 0x32, 0x38, 0x12, 0x4d, 0x0a, 0x23, 0x62, 0x67, 0x70, 0x5f, 0x6d, 0x61, 0x78, + 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, + 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc0, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x1f, 0x62, 0x67, 0x70, 0x4d, 0x61, 0x78, 0x4d, 0x75, 0x6c, 0x74, 0x69, + 0x70, 0x61, 0x74, 0x68, 0x50, 0x61, 0x74, 0x68, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x12, 0x59, 0x0a, 0x29, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x74, + 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x6e, 0x65, + 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x5f, 0x6f, 0x72, 0x5f, 0x61, 0x66, 0x69, 0x73, 0x61, 0x66, + 0x69, 0x18, 0xc1, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x61, 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x4e, 0x65, + 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x4f, 0x72, 0x41, 0x66, 0x69, 0x73, 0x61, 0x66, 0x69, 0x12, + 0x35, 0x0a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc2, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x14, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, + 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x72, + 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc3, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x2b, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x57, 0x69, 0x74, 0x68, 0x52, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x6a, 0x0a, + 0x32, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x18, 0xc4, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2d, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6e, 0x64, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x29, 0x65, 0x6e, 0x63, + 0x61, 0x70, 0x5f, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x68, 0x75, 0x74, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6e, 0x68, 0x67, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x74, + 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x18, 0xc5, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x65, + 0x6e, 0x63, 0x61, 0x70, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x68, 0x75, 0x74, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x4e, 0x68, 0x67, 0x5a, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x63, 0x6d, 0x70, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x73, 0x18, 0xc6, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x78, + 0x45, 0x63, 0x6d, 0x70, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x35, 0x0a, 0x16, 0x77, 0x65, 0x63, + 0x6d, 0x70, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x18, 0xc7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x77, 0x65, 0x63, 0x6d, + 0x70, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x4e, 0x0a, 0x23, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, + 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x35, 0x0a, 0x16, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, + 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x69, 0x73, 0x69, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x27, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x65, 0x64, 0x5f, 0x65, 0x63, 0x6d, 0x70, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x65, 0x64, 0x45, 0x63, 0x6d, 0x70, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, + 0x0a, 0x19, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x6e, 0x68, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x18, 0xcb, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x16, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x4e, 0x68, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x53, 0x0a, 0x26, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, - 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xa7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x62, - 0x67, 0x70, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, - 0x69, 0x74, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x22, 0x62, 0x67, 0x70, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, - 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xa8, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1e, 0x62, 0x67, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x53, 0x65, - 0x74, 0x52, 0x65, 0x66, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x69, 0x62, 0x5f, 0x77, 0x65, 0x63, 0x6d, 0x70, 0x18, 0xa9, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x69, 0x62, 0x57, 0x65, 0x63, 0x6d, 0x70, 0x12, 0x43, - 0x0a, 0x1d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, - 0xaa, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x75, 0x73, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x5f, 0x73, 0x65, 0x74, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0xab, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, - 0x75, 0x73, 0x65, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x54, - 0x61, 0x67, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x1c, 0x73, - 0x6b, 0x69, 0x70, 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6d, - 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0xac, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x67, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x43, - 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x5e, 0x0a, 0x2c, - 0x62, 0x67, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x5f, - 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xae, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x27, 0x62, 0x67, 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, - 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x11, - 0x73, 0x65, 0x74, 0x5f, 0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x18, 0xaf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x65, 0x74, 0x4e, 0x6f, 0x50, - 0x65, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x46, 0x0a, 0x20, 0x62, 0x67, 0x70, 0x5f, - 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x5f, 0x69, 0x73, 0x5f, 0x61, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0xb0, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x1b, 0x62, 0x67, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, - 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x73, 0x41, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x12, 0x59, 0x0a, 0x2a, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x70, 0x76, 0x36, 0x5f, - 0x6e, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xb1, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x69, 0x70, 0x76, 0x34, 0x53, 0x74, 0x61, 0x74, 0x69, - 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x70, 0x76, 0x36, 0x4e, 0x68, - 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x59, 0x0a, 0x2a, 0x69, - 0x70, 0x76, 0x36, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, - 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x6e, 0x68, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xb2, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x24, 0x69, 0x70, 0x76, 0x36, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x57, 0x69, 0x74, 0x68, 0x49, 0x70, 0x76, 0x34, 0x4e, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x19, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x72, 0x6f, 0x70, - 0x5f, 0x6e, 0x68, 0x18, 0xb3, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x44, 0x72, 0x6f, 0x70, 0x4e, - 0x68, 0x12, 0x49, 0x0a, 0x21, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, - 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0xb4, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x45, 0x78, - 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x44, 0x0a, 0x1e, - 0x62, 0x67, 0x70, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xb5, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x62, 0x67, 0x70, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x4a, 0x0a, 0x22, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x67, 0x70, 0x5f, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x72, 0x66, 0x18, 0xb6, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1d, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x42, - 0x67, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x72, 0x66, 0x12, 0x45, - 0x0a, 0x1f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x5f, 0x74, 0x61, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x18, 0xb7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, - 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x61, 0x67, 0x53, 0x65, 0x74, 0x45, 0x6d, 0x62, - 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x50, 0x0a, 0x26, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x66, - 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x6f, 0x72, 0x5f, - 0x62, 0x67, 0x70, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x61, 0x73, 0x18, - 0xb8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x66, 0x69, 0x53, - 0x61, 0x66, 0x69, 0x50, 0x61, 0x74, 0x68, 0x46, 0x6f, 0x72, 0x42, 0x67, 0x70, 0x4d, 0x75, 0x6c, - 0x74, 0x69, 0x70, 0x6c, 0x65, 0x41, 0x73, 0x12, 0x4c, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x6d, 0x75, - 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x65, - 0x78, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xb9, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x67, 0x65, 0x78, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x74, 0x6f, - 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x66, 0x69, 0x73, 0x18, 0xba, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1b, 0x73, 0x61, 0x6d, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x41, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x65, 0x64, 0x54, 0x6f, 0x41, 0x6c, 0x6c, 0x41, 0x66, 0x69, 0x73, 0x12, 0x49, 0x0a, - 0x21, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x18, 0xbb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x46, - 0x6f, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x6b, 0x69, 0x70, - 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0xbc, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x55, 0x0a, 0x27, - 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x77, - 0x69, 0x74, 0x68, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0xbd, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, - 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x57, 0x69, 0x74, - 0x68, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x48, 0x0a, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xbe, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x35, 0x0a, - 0x16, 0x73, 0x6c, 0x61, 0x61, 0x63, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x6c, 0x65, - 0x6e, 0x67, 0x74, 0x68, 0x31, 0x32, 0x38, 0x18, 0xbf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, - 0x73, 0x6c, 0x61, 0x61, 0x63, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x31, 0x32, 0x38, 0x12, 0x4d, 0x0a, 0x23, 0x62, 0x67, 0x70, 0x5f, 0x6d, 0x61, 0x78, 0x5f, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x5f, - 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc0, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x1f, 0x62, 0x67, 0x70, 0x4d, 0x61, 0x78, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, - 0x61, 0x74, 0x68, 0x50, 0x61, 0x74, 0x68, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x59, 0x0a, 0x29, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x74, 0x68, - 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x6e, 0x65, 0x69, - 0x67, 0x68, 0x62, 0x6f, 0x72, 0x5f, 0x6f, 0x72, 0x5f, 0x61, 0x66, 0x69, 0x73, 0x61, 0x66, 0x69, - 0x18, 0xc1, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, - 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x4e, 0x65, 0x69, - 0x67, 0x68, 0x62, 0x6f, 0x72, 0x4f, 0x72, 0x41, 0x66, 0x69, 0x73, 0x61, 0x66, 0x69, 0x12, 0x35, - 0x0a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc2, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x14, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, - 0x74, 0x79, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x72, 0x65, - 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc3, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x2b, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x57, - 0x69, 0x74, 0x68, 0x52, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x6a, 0x0a, 0x32, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x18, 0xc4, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6e, 0x64, 0x49, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x29, 0x65, 0x6e, 0x63, 0x61, - 0x70, 0x5f, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x68, 0x75, 0x74, 0x5f, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x6e, 0x68, 0x67, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x74, 0x72, - 0x61, 0x66, 0x66, 0x69, 0x63, 0x18, 0xc5, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x65, 0x6e, - 0x63, 0x61, 0x70, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x68, 0x75, 0x74, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x4e, 0x68, 0x67, 0x5a, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, - 0x63, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x63, 0x6d, 0x70, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x73, 0x18, 0xc6, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x45, - 0x63, 0x6d, 0x70, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x35, 0x0a, 0x16, 0x77, 0x65, 0x63, 0x6d, - 0x70, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x18, 0xc7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x77, 0x65, 0x63, 0x6d, 0x70, - 0x41, 0x75, 0x74, 0x6f, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x4e, 0x0a, 0x23, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x72, - 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x35, 0x0a, 0x16, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, - 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x14, 0x69, 0x73, 0x69, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x27, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x65, 0x64, 0x5f, 0x65, 0x63, 0x6d, 0x70, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x61, - 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x65, 0x64, 0x45, 0x63, 0x6d, 0x70, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x65, - 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, - 0x19, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x5f, 0x6e, 0x68, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x18, 0xcb, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x16, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x4e, 0x68, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x53, 0x0a, 0x26, 0x62, 0x67, 0x70, - 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, - 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x18, 0xcc, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x62, 0x67, 0x70, 0x45, - 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, - 0x53, 0x65, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x59, - 0x0a, 0x2a, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x63, 0x6f, - 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x66, 0x73, - 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xcd, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x24, 0x62, 0x67, 0x70, 0x53, 0x65, 0x74, 0x45, 0x78, 0x74, 0x43, 0x6f, - 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x53, 0x65, 0x74, 0x52, 0x65, 0x66, 0x73, 0x55, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x25, 0x62, 0x67, 0x70, - 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x62, 0x61, 0x6e, - 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x18, 0xce, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x62, 0x67, 0x70, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, - 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4f, 0x0a, 0x24, - 0x71, 0x6f, 0x73, 0x5f, 0x69, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x64, 0x72, 0x6f, 0x70, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x18, 0xcf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x71, 0x6f, 0x73, - 0x49, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x53, 0x0a, - 0x26, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x65, 0x78, - 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, - 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0xd0, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, - 0x62, 0x67, 0x70, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, - 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x12, 0x4d, 0x0a, 0x23, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x61, 0x67, 0x5f, - 0x73, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd1, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x61, 0x67, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x12, 0x4c, 0x0a, 0x23, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, - 0x64, 0x65, 0x66, 0x5f, 0x65, 0x62, 0x67, 0x70, 0x5f, 0x76, 0x72, 0x66, 0x5f, 0x75, 0x6e, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd2, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1e, 0x70, 0x65, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x66, 0x45, 0x62, 0x67, - 0x70, 0x56, 0x72, 0x66, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x5a, 0x0a, 0x2a, 0x72, 0x65, 0x64, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x65, 0x62, 0x67, 0x70, 0x5f, 0x76, 0x72, - 0x66, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd3, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x72, 0x65, 0x64, 0x69, 0x73, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x45, 0x62, 0x67, 0x70, 0x56, 0x72, 0x66, - 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x2a, 0x62, - 0x67, 0x70, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x69, 0x6e, 0x5f, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6e, 0x69, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, - 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x69, 0x18, 0xd4, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x22, 0x62, 0x67, 0x70, 0x41, 0x66, 0x69, 0x53, 0x61, 0x66, 0x69, 0x49, 0x6e, 0x44, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x69, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x4f, 0x74, 0x68, - 0x65, 0x72, 0x4e, 0x69, 0x12, 0x57, 0x0a, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x18, 0xd5, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x63, 0x0a, - 0x2e, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x76, - 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, - 0xd6, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2a, 0x69, 0x70, 0x76, 0x36, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x72, 0x41, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x24, 0x64, 0x65, 0x63, 0x61, 0x70, 0x5f, 0x6e, 0x68, 0x5f, 0x77, - 0x69, 0x74, 0x68, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, 0x5f, 0x6e, 0x69, 0x5f, 0x75, - 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd7, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1f, 0x64, 0x65, 0x63, 0x61, 0x70, 0x4e, 0x68, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x65, - 0x78, 0x74, 0x68, 0x6f, 0x70, 0x4e, 0x69, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x48, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, - 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x6e, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x63, - 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x41, 0x6e, - 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x27, - 0x73, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd9, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, - 0x73, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x18, 0xda, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x10, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x61, 0x73, 0x6b, - 0x4c, 0x65, 0x6e, 0x12, 0x62, 0x0a, 0x2e, 0x75, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x5f, - 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0xdb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x75, 0x73, - 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x46, 0x6f, 0x72, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x44, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x66, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x6e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xdc, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x1b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4d, 0x66, 0x67, 0x44, 0x61, - 0x74, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x4a, 0x04, 0x08, - 0x54, 0x10, 0x55, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, - 0x04, 0x08, 0x14, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x5a, 0x10, 0x5b, 0x4a, 0x04, 0x08, 0x61, 0x10, - 0x62, 0x4a, 0x04, 0x08, 0x37, 0x10, 0x38, 0x4a, 0x04, 0x08, 0x59, 0x10, 0x5a, 0x4a, 0x04, 0x08, - 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x24, 0x10, 0x25, 0x4a, 0x04, 0x08, 0x23, 0x10, 0x24, 0x4a, - 0x04, 0x08, 0x28, 0x10, 0x29, 0x4a, 0x06, 0x08, 0xad, 0x01, 0x10, 0xae, 0x01, 0x1a, 0xa0, 0x01, - 0x0a, 0x12, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x47, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x22, 0xfa, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x13, - 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, - 0x5f, 0x44, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, - 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x34, 0x4c, 0x49, 0x4e, 0x4b, 0x53, - 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, - 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x32, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x03, 0x12, 0x1a, - 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, - 0x45, 0x5f, 0x34, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x04, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x45, - 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x39, 0x4c, - 0x49, 0x4e, 0x4b, 0x53, 0x5f, 0x4c, 0x41, 0x47, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x45, - 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, - 0x45, 0x5f, 0x32, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x06, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, - 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x38, 0x4c, - 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, - 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x34, 0x30, 0x30, 0x5a, 0x52, 0x10, 0x08, 0x22, 0x6d, 0x0a, - 0x04, 0x54, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x54, - 0x41, 0x47, 0x53, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, - 0x01, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x43, 0x45, - 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x45, 0x44, 0x47, 0x45, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, - 0x41, 0x47, 0x53, 0x5f, 0x45, 0x44, 0x47, 0x45, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x41, - 0x47, 0x53, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x49, 0x54, 0x10, 0x04, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x18, 0xcc, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x62, 0x67, 0x70, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, + 0x79, 0x53, 0x65, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, + 0x59, 0x0a, 0x2a, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x66, + 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xcd, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x62, 0x67, 0x70, 0x53, 0x65, 0x74, 0x45, 0x78, 0x74, 0x43, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x53, 0x65, 0x74, 0x52, 0x65, 0x66, 0x73, 0x55, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x25, 0x62, 0x67, + 0x70, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x62, 0x61, + 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x18, 0xce, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x21, 0x62, 0x67, 0x70, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4f, 0x0a, + 0x24, 0x71, 0x6f, 0x73, 0x5f, 0x69, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x64, 0x72, 0x6f, + 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xcf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x71, 0x6f, + 0x73, 0x49, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x53, + 0x0a, 0x26, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, + 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0xd0, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x22, 0x62, 0x67, 0x70, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x12, 0x4d, 0x0a, 0x23, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x61, 0x67, + 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd1, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x61, 0x67, 0x53, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x23, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x5f, 0x64, 0x65, 0x66, 0x5f, 0x65, 0x62, 0x67, 0x70, 0x5f, 0x76, 0x72, 0x66, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd2, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1e, 0x70, 0x65, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x66, 0x45, 0x62, + 0x67, 0x70, 0x56, 0x72, 0x66, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x5a, 0x0a, 0x2a, 0x72, 0x65, 0x64, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x65, 0x62, 0x67, 0x70, 0x5f, 0x76, + 0x72, 0x66, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd3, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x72, 0x65, 0x64, 0x69, 0x73, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x45, 0x62, 0x67, 0x70, 0x56, 0x72, + 0x66, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x2a, + 0x62, 0x67, 0x70, 0x5f, 0x61, 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x69, 0x6e, 0x5f, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6e, 0x69, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, + 0x65, 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x69, 0x18, 0xd4, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x22, 0x62, 0x67, 0x70, 0x41, 0x66, 0x69, 0x53, 0x61, 0x66, 0x69, 0x49, 0x6e, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x69, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x4f, 0x74, + 0x68, 0x65, 0x72, 0x4e, 0x69, 0x12, 0x57, 0x0a, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x18, 0xd5, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x63, + 0x0a, 0x2e, 0x69, 0x70, 0x76, 0x36, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, + 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x18, 0xd6, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x2a, 0x69, 0x70, 0x76, 0x36, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x72, 0x41, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x24, 0x64, 0x65, 0x63, 0x61, 0x70, 0x5f, 0x6e, 0x68, 0x5f, + 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, 0x5f, 0x6e, 0x69, 0x5f, + 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd7, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1f, 0x64, 0x65, 0x63, 0x61, 0x70, 0x4e, 0x68, 0x57, 0x69, 0x74, 0x68, 0x4e, + 0x65, 0x78, 0x74, 0x68, 0x6f, 0x70, 0x4e, 0x69, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, + 0x5f, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x6e, 0x79, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, + 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x41, + 0x6e, 0x79, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x55, 0x0a, + 0x27, 0x73, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xd9, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x23, 0x73, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x18, 0xda, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x61, 0x73, + 0x6b, 0x4c, 0x65, 0x6e, 0x12, 0x62, 0x0a, 0x2e, 0x75, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x6f, 0x72, + 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x18, 0xdb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x75, + 0x73, 0x65, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x46, 0x6f, 0x72, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x44, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x66, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xdc, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4d, 0x66, 0x67, 0x44, + 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x40, + 0x0a, 0x1c, 0x6f, 0x74, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x74, 0x72, + 0x69, 0x62, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xdd, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x6f, 0x74, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x54, 0x72, 0x69, 0x62, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x12, 0x5b, 0x0a, 0x2a, 0x65, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, + 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xde, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x26, 0x65, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x53, 0x0a, + 0x26, 0x65, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x73, + 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x5f, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0xdf, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, + 0x65, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x21, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x18, 0xe0, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x12, 0x3e, + 0x0a, 0x1b, 0x63, 0x68, 0x61, 0x73, 0x73, 0x69, 0x73, 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x70, + 0x63, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xe1, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x63, 0x68, 0x61, 0x73, 0x73, 0x69, 0x73, 0x47, 0x65, 0x74, + 0x52, 0x70, 0x63, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x56, + 0x0a, 0x28, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x72, 0x65, 0x66, 0x5f, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe2, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x23, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x65, 0x61, 0x66, 0x52, 0x65, 0x66, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x1f, 0x73, 0x73, 0x68, 0x5f, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xe3, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1c, 0x73, 0x73, 0x68, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x73, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x41, + 0x0a, 0x1c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x6f, + 0x64, 0x65, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xe4, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x65, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x51, 0x0a, 0x26, 0x62, 0x67, 0x70, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x5f, 0x70, + 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0xe5, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x20, 0x62, 0x67, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x49, 0x64, 0x6c, 0x65, 0x49, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x45, 0x0a, 0x1f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, + 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, + 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x18, 0xe6, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x74, 0x68, 0x55, + 0x6e, 0x64, 0x65, 0x72, 0x41, 0x66, 0x69, 0x53, 0x61, 0x66, 0x69, 0x12, 0x49, 0x0a, 0x21, 0x62, + 0x67, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x77, 0x6e, 0x61, 0x73, 0x5f, 0x64, 0x69, + 0x66, 0x66, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0xe7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x62, 0x67, 0x70, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x6f, 0x77, 0x6e, 0x61, 0x73, 0x44, 0x69, 0x66, 0x66, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x53, 0x0a, 0x26, 0x6f, 0x74, 0x6e, 0x5f, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x18, 0xe8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x6f, 0x74, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x69, 0x73, + 0x63, 0x6f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x46, 0x0a, 0x20, 0x63, + 0x69, 0x73, 0x63, 0x6f, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x63, 0x5f, 0x62, 0x65, 0x72, + 0x5f, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0xe9, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x50, 0x72, 0x65, + 0x46, 0x65, 0x63, 0x42, 0x65, 0x72, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x63, 0x0a, 0x2f, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xea, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x62, + 0x67, 0x70, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, + 0x70, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, 0x66, 0x55, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x23, 0x62, 0x67, 0x70, 0x5f, + 0x61, 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, + 0x64, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0xeb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x62, 0x67, 0x70, 0x41, 0x66, 0x69, 0x53, 0x61, + 0x66, 0x69, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x4e, 0x6f, 0x74, 0x53, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0xec, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x6e, 0x6f, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x73, 0x75, 0x70, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xed, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x11, 0x6e, 0x6f, 0x5a, 0x65, 0x72, 0x6f, 0x53, 0x75, 0x70, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x57, 0x0a, 0x28, 0x69, 0x73, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x69, + 0x76, 0x65, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xee, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x69, 0x73, 0x69, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, + 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3c, 0x0a, 0x1a, 0x69, + 0x73, 0x69, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x5f, 0x73, 0x79, 0x73, 0x69, 0x64, 0x5f, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xef, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x17, 0x69, 0x73, 0x69, 0x73, 0x44, 0x69, 0x73, 0x53, 0x79, 0x73, 0x69, 0x64, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x23, 0x69, 0x73, 0x69, + 0x73, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x6c, + 0x6f, 0x61, 0x64, 0x73, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x18, 0xf0, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x69, 0x73, 0x69, 0x73, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x62, 0x67, 0x70, + 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x64, 0x5f, 0x76, 0x37, 0x5f, 0x75, 0x6e, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xf1, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, + 0x62, 0x67, 0x70, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x64, 0x56, 0x37, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x54, 0x10, 0x55, 0x4a, 0x04, 0x08, 0x09, + 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x14, 0x10, 0x15, 0x4a, 0x04, + 0x08, 0x5a, 0x10, 0x5b, 0x4a, 0x04, 0x08, 0x61, 0x10, 0x62, 0x4a, 0x04, 0x08, 0x37, 0x10, 0x38, + 0x4a, 0x04, 0x08, 0x59, 0x10, 0x5a, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x24, + 0x10, 0x25, 0x4a, 0x04, 0x08, 0x23, 0x10, 0x24, 0x4a, 0x04, 0x08, 0x28, 0x10, 0x29, 0x4a, 0x06, + 0x08, 0xad, 0x01, 0x10, 0xae, 0x01, 0x1a, 0xa0, 0x01, 0x0a, 0x12, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x41, 0x0a, + 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x47, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0a, 0x64, + 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x07, 0x54, 0x65, + 0x73, 0x74, 0x62, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, + 0x0a, 0x0b, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x10, 0x01, 0x12, + 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x44, + 0x55, 0x54, 0x5f, 0x34, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x54, + 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x32, + 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, + 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x34, 0x4c, 0x49, 0x4e, 0x4b, + 0x53, 0x10, 0x04, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, + 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x39, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x5f, 0x4c, 0x41, + 0x47, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, + 0x55, 0x54, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x32, 0x4c, 0x49, 0x4e, 0x4b, + 0x53, 0x10, 0x06, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, + 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x38, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x07, 0x12, + 0x15, 0x0a, 0x11, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x34, + 0x30, 0x30, 0x5a, 0x52, 0x10, 0x08, 0x22, 0x6d, 0x0a, 0x04, 0x54, 0x61, 0x67, 0x73, 0x12, 0x14, + 0x0a, 0x10, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x41, 0x47, 0x47, + 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x41, + 0x47, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x45, 0x44, + 0x47, 0x45, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x45, 0x44, 0x47, + 0x45, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x54, 0x52, 0x41, 0x4e, + 0x53, 0x49, 0x54, 0x10, 0x04, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/ocpaths.proto b/proto/ocpaths.proto index 46f3bd41717..ea7d21e6d57 100644 --- a/proto/ocpaths.proto +++ b/proto/ocpaths.proto @@ -58,6 +58,10 @@ message OCPath { // A set of opaque tags that are used for this path. These tags can be used // to group paths according to use-case specific criteria. repeated string tags = 4; + + // GNMIRpc describes expected (or supported) behavior for a particular + // Openconfig path. + GNMIRpc gnmi_rpc = 5; } // OCPathConstraint enumerates platform_types that are required to be supported @@ -76,3 +80,39 @@ message OCPathConstraint { string platform_type = 1; } } + +// GNMIRpc describes expected (or supported) behavior for a particular +// Openconfig path. +message GNMIRpc { + bool get = 1; + bool set = 2; + bool subscribe = 3; + + // SubscribeMode, describes how updates are triggered for the request. + enum SubscribeMode { + UNSPECIFIED_SUBSCRIBE_MODE = 0; + NO_READ_SUPPORT = 1; // No requirement / support for path. + STREAM = 2; // Values streamed by the target (Sec. 3.5.1.5.2). + ONCE = 3; // Values sent once-off by the target (Sec. 3.5.1.5.1). + POLL = 4; // Values sent in response to a poll request (Sec. 3.5.1.5.3). + } + repeated SubscribeMode sub_mode = 4; + + // StreamMode is the mode of a streamed subscription, specifying how the + // target must return values for that subscription. + // Reference: gNMI Specification Section 3.5.1.3 + enum StreamMode { + UNSPECIFIED_STREAM_MODE = 0; + NO_STREAMING_SUPPORT = 1; // No requirement / support for streaming path. + TARGET_DEFINED = 2; // The target selects for each element. + ON_CHANGE = 3; // The target sends an update on element value change. + SAMPLE = 4; // The target samples values according to the interval. + } + repeated StreamMode stream_mode = 5; + + // If listed as part of a requirement, sample_interval_nanoseconds is the + // maximum allowable interval between updates. + // If listed as part of the description of level of support, it should be the + // smallest, recommended value. + uint64 sample_interval_nanoseconds = 6; +} diff --git a/testregistry.textproto b/testregistry.textproto index 533758476f2..a70dfc099b8 100644 --- a/testregistry.textproto +++ b/testregistry.textproto @@ -167,6 +167,12 @@ test: { id: "Certz-5" readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/ssecurity/gnsi/certz/trust_bundle_rotation/README.md" } +test: { + id: "CPT-1.1" + description: "Ingress Interface ARP Policer" + readme: "" + exec: " " +} test: { id: "Credentialz-1" readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/security/gnsi/credentialz/tests/README.md" @@ -229,6 +235,12 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/qos/otg_tests/ingress_traffic_classification_and_rewrite_test/README.md" exec: " " } +test: { + id: "DP-1.18" + description: "Flow matching using ACL and to Port Mirror/Redirect" + readme: "" + exec: " " +} test: { id: "DP-1.2" description: "QoS policy feature config" @@ -269,6 +281,14 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/qos/ate_tests/wrr_traffic_test/README.md" exec: " " } +test: { + id: "DP-2.2" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/qos/otg_tests/ingress_police_nhg/README.md" +} +test: { + id: "DP-2.4" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/qos/otg_tests/ingress_police_default/README.md" +} test: { id: "FP-1.1" description: "Power admin DOWN/UP Test" @@ -277,7 +297,7 @@ test: { test: { id: "Health-1.1" description: "Generic Health Check" - readme: "https://github.com/openconfig/featureprofiles/blob/d26ac7fac5406af29c9a582b8d8ee73d56953e3b/feature/experimental/system/health/tests/system_generic_health_check/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/system/health/tests/system_generic_health_check/README.md" exec: " " } test: { @@ -336,7 +356,7 @@ test: { } test: { id: "P4RT-1.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/base_p4rt/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/base_p4rt/README.md" } test: { id: "P4RT-1.2" @@ -344,39 +364,39 @@ test: { } test: { id: "P4RT-2.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/tests/p4rt_election/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/tests/p4rt_election/README.md" } test: { id: "P4RT-2.2" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/tests/metadata_validation_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/tests/metadata_validation_test/README.md" } test: { id: "P4RT-3.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/google_discovery_protocol_packetin_test/README.md" } test: { id: "P4RT-3.2" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/google_discovery_protocol_packetout_test/README.md" } test: { id: "P4RT-5.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/traceroute_packetin_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/traceroute_packetin_test/README.md" } test: { id: "P4RT-5.2" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/traceroute_packetout_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/traceroute_packetout_test/README.md" } test: { id: "P4RT-6.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/performance_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/performance_test/README.md" } test: { id: "P4RT-7.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/lldp_packetin_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/lldp_packetin_test/README.md" } test: { id: "P4RT-7.2" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/p4rt/otg_tests/lldp_packetout_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/p4rt/otg_tests/lldp_packetout_test/README.md" } test: { id: "PF-1.1" @@ -408,10 +428,16 @@ test: { readme: " " exec: " " } +test: { + id: "PF-1.6" + description: "IPv4 & IPV6 based traffic steering from Non-default VRF to Default VRF using Policy based VRF selection" + readme: "" + exec: " " +} test: { id: "PLT-1.1" description: "Interface breakout Test" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/platform/tests/breakout_configuration/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/platform/tests/breakout_configuration/README.md" exec: " " } test: { @@ -466,13 +492,13 @@ test: { test: { id: "RT-1.11" description: "RT-1.11: BGP remove private AS" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/bgp/ate_tests/bgp_remove_private_as/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/otg_tests/bgp_remove_private_as/README.md" exec: " " } test: { id: "RT-1.12" description: "RT-1.12: BGP always compare MED" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/bgp/ate_tests/bgp_always_compare_med/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/otg_tests/bgp_always_compare_med/README.md" exec: " " } test: { @@ -513,8 +539,14 @@ test: { } test: { id: "RT-1.19" - description: "BGP 2-Byte and 4-Byte ASN support" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn/README.md" + description: "RT-1.19: BGP 2-Byte and 4-Byte ASN support" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/otg_tests/bgp_2byte_4byte_asn/README.md" + exec: " " +} +test: { + id: "RT-1.2" + description: "BGP Policy & Route Installation" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/policybase/otg_tests/route_installation_test/README.md" exec: " " } test: { @@ -538,7 +570,7 @@ test: { test: { id: "RT-1.24" description: "BGP 2-byte and 4-byte ASN support with policy" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/README.md" exec: " " } test: { @@ -620,7 +652,7 @@ test: { test: { id: "RT-1.53" description: "Prefix-set test" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/policy/prefix_set/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/policy_forwarding/otg_tests/prefix_set_test/README.md" exec: " " } test: { @@ -671,6 +703,12 @@ test: { readme: " " exec: " " } +test: { + id: "RT-1.63" + description: "BGP Multihop" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/multihop/README.md" + exec: " " +} test: { id: "RT-2.10" description: "IS-IS change LSP lifetime" @@ -697,13 +735,25 @@ test: { test: { id: "RT-2.14" description: "ISIS Drain Test" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/isis/otg_tests/isis_drain_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/isis/otg_tests/isis_drain_test/README.md" + exec: " " +} +test: { + id: "RT-2.15" + description: "IS-IS Extensions for Segment Routing" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/isis/otg_tests/isis_extensions_segment_routing_test/README.md" + exec: " " +} +test: { + id: "RT-2.15" + description: "IS-IS Graceful Restart Helper" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/isis/otg_tests/graceful_restart_helper/README.md" exec: " " } test: { id: "RT-2.2" description: "IS-IS LSP Updates" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/isis/otg_tests/lsp_updates_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/isis/otg_tests/lsp_updates_test/README.md" } test: { id: "RT-2.6" @@ -732,13 +782,31 @@ test: { test: { id: "RT-3.1" description: "Policy based VRF selection base" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/policy/policy_vrf_selection/ate_tests/base_vrf_selection/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/policy_forwarding/policy_vrf_selection/otg_tests/base_vrf_selection/README.md" exec: " " } test: { id: "RT-3.2" description: "Policy based VRF selection with multiple protocol and DSCP values" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/policy/policy_vrf_selection/ate_tests/protocol_dscp_rules_for_vrf_selection_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/policy_forwarding/policy_vrf_selection/otg_tests/protocol_dscp_rules_for_vrf_selection_test/README.md" + exec: " " +} +test: { + id: "RT-3.3" + description: "Multiple VRFs and GUE DECAP in Default VRF" + readme: "" + exec: " " +} +test: { + id: "RT-3.31" + description: "DSCP based traffic steering from default VRF to non-Default VRF using Policy based VRF selection plus GUE DECAP" + readme: "" + exec: " " +} +test: { + id: "RT-3.32" + description: "DSCP based traffic steering from Non-default VRF to Default VRF using Policy based VRF selection plus GUE DECAP and ENCAP" + readme: "" exec: " " } test: { @@ -747,6 +815,13 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_summary/otg_tests/route_summary_counters_test/README.md" exec: " " } +test: { + id: "RT-4.11" + description: " Scale AFTs Route Summary" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_summary/otg_tests/scale_aft_summary/README.md" + exec: " " +} + test: { id: "RT-5.1" description: "Singleton Interface" @@ -804,7 +879,7 @@ test: { test: { id: "RT-5.6" description: "Interface Loopback mode" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/interface/interface_loopback_aggregate/otg_tests/interface_loopback_aggregate/README.md" } test: { id: "RT-5.7" @@ -867,7 +942,7 @@ test: { test: { id: "RT-7.5" description: "BGP Policy - Set Link Bandwidth Community" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/otg_tests/link_bandwidth_test/README.md" } test: { id: "RT-7.6" @@ -918,7 +993,7 @@ test: { } test: { id: "Replay-1.2" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/replay/tests/p4rt_replay/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/replay/tests/p4rt_replay/README.md" } test: { id: "SFLOW-1" @@ -985,22 +1060,32 @@ test: { } test: { id: "TE-16.1" + description: "gRIBI Traffic Engineering - Basic encapsulation tests" readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/basic_encap_test/README.md" } test: { id: "TE-16.2" - description: "gRIBI encapsulation FRR scenarios" + description: "gRIBI Traffic Engineering encapsulation FRR scenarios" readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/encap_frr/README.md" } +test: { + id: "TE-16.3" + description: "gRIBI Traffic Engineering Encapsulation with Re-encap NI FRR scenarios" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/encap_frr_with_reencap_vrf_test/README.md" +} test: { id: "TE-17.1" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/gribi/otg_tests/vrf_policy_driven_te/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/vrf_policy_driven_te/README.md" } test { id: "TE-18.1" description: "MPLS in UDP Encapsulation with QoS scheduler" readme: "" } +test: { + id: "TE-18.3" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/mpls_in_udp_scale/README.md" +} test: { id: "TE-2.1" description: "gRIBI IPv4 Entry" @@ -1153,8 +1238,13 @@ test: { } test: { id: "TE-9.1" - description: "Base gRIBI MPLS Compliance" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/static_lsp/README.md" + description: "Push MPLS Labels to MPLS payload" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/mpls_compliance/README.md" +} +test: { + id: "TE-9.3" + description: "gRIBI FIB Failure due to hardware resource exhaust" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md" } test: { id: "TE-9.2" @@ -1383,6 +1473,11 @@ test: { readme: "" exec: " " } +test: { + id: "SEC-3.1" + description: "TLS Authentication over gRPC" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/security/aaa/kne_tests/tls_authentication_over_grpc_test/README.md" +} test: { id: "bootz-1.1" description: "Missing configuration - Device fails with status invalid parameter" @@ -1544,7 +1639,7 @@ test: { test: { id: "gNMI-1.20" description: "Telemetry: Optics Thresholds" - readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/experimental/platform/tests/optics_thresholds_test/README.md" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/platform/tests/optics_thresholds_test/README.md" exec: " " } test: { @@ -1717,3 +1812,15 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/container/networking/tests/container_connectivity/README.md" exec: " " } +test: { + id: "AFT-1.1" + description: "AFT Streaming" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_base/otg_tests/aft_base/README.md" + exec: " " +} +test: { + id: "AFT-2.1" + description: "AFT Streaming" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_base/otg_tests/aft_prefixcounters/README.md" + exec: " " +} \ No newline at end of file diff --git a/tools/nosimage/validate/validate.go b/tools/nosimage/validate/validate.go index a43203d4e4d..76115528626 100644 --- a/tools/nosimage/validate/validate.go +++ b/tools/nosimage/validate/validate.go @@ -91,7 +91,12 @@ func main() { if err := os.MkdirAll(config.DownloadPath, 0750); err != nil { fmt.Println(fmt.Errorf("cannot create download path directory: %v", config.DownloadPath)) } - publicPath, err := ocpaths.ClonePublicRepo(config.DownloadPath, "v"+profile.Ocpaths.GetVersion()) + + ocReleaseTag := "" + if profile.Ocpaths.GetVersion() != "" { + ocReleaseTag = "v" + profile.Ocpaths.GetVersion() + } + publicPath, err := ocpaths.ClonePublicRepo(config.DownloadPath, ocReleaseTag) if err != nil { fmt.Println(err) os.Exit(1)