diff --git a/.azure-pipelines/docker-sonic-slave.yml b/.azure-pipelines/docker-sonic-slave.yml index 9d8b30210a..6b4da92c69 100644 --- a/.azure-pipelines/docker-sonic-slave.yml +++ b/.azure-pipelines/docker-sonic-slave.yml @@ -48,7 +48,6 @@ parameters: - bullseye - buster - stretch - - jessie - name: registry_url type: string default: sonicdev-microsoft.azurecr.io @@ -61,14 +60,11 @@ stages: jobs: - ${{ each dist in parameters.dists }}: - ${{ if endswith(variables['Build.DefinitionName'], dist) }}: - - ${{ each arch in parameters.arches }}: - - template: .azure-pipelines/docker-sonic-slave-template.yml@buildimage - parameters: - pool: sonicbld-1es - arch: ${{ arch }} - dist: ${{ dist }} - ${{ if ne(arch, 'amd64') }}: - march: _march_${{ arch }} + - template: .azure-pipelines/docker-sonic-slave-template.yml@buildimage + parameters: + pool: sonicbld-1es + arch: amd64 + dist: ${{ dist }} - stage: Build_native_arm dependsOn: [] jobs: diff --git a/.azure-pipelines/official-build-vs-with-test.yml b/.azure-pipelines/official-build-vs-with-test.yml new file mode 100644 index 0000000000..235c5931fb --- /dev/null +++ b/.azure-pipelines/official-build-vs-with-test.yml @@ -0,0 +1,151 @@ +# This pipeline generates daily, successful virtual SONiC images, primarily for PR testing in non-build repositories. + +name: $(Build.DefinitionName)_$(SourceBranchName)_$(Date:yyyyMMdd) + +schedules: + - cron: "0 */8 * * *" # At 0 minutes past the hour, every 8 hours, every day UTC + displayName: "Daily Build and Test SONiC virtual images" + branches: + include: + - master + - 202305 + - 202311 + - 202405 + - 202411 + +trigger: none +pr: none + +resources: + repositories: + - repository: sonic-mgmt + type: github + name: sonic-net/sonic-mgmt + ref: master + endpoint: sonic-net + - repository: buildimage + type: github + name: sonic-net/sonic-buildimage + endpoint: sonic-net + ref: master + +variables: + - template: .azure-pipelines/template-variables.yml@buildimage + - name: BUILD_BRANCH + value: $(Build.SourceBranchName) + +stages: + - stage: BuildVS + pool: sonicbld-1es + jobs: + - template: azure-pipelines-build.yml + parameters: + buildOptions: 'USERNAME=admin SONIC_BUILD_JOBS=$(nproc) BUILD_MULTIASIC_KVM=y INCLUDE_DHCP_SERVER=y ${{ variables.VERSION_CONTROL_OPTIONS }}' + jobGroups: + - name: vs + + - stage: Test + dependsOn: BuildVS + condition: and(succeeded(), in(dependencies.BuildVS.result, 'Succeeded', 'SucceededWithIssues')) + variables: + - group: SONiC-Elastictest + + jobs: + - job: t0_elastictest + pool: sonic-ubuntu-1c + displayName: "kvmtest-t0 by Elastictest" + timeoutInMinutes: 240 + continueOnError: false + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: t0 + MIN_WORKER: $(T0_INSTANCE_NUM) + MAX_WORKER: $(T0_INSTANCE_NUM) + MGMT_BRANCH: $(BUILD_BRANCH) + + - job: t0_2vlans_elastictest + pool: sonic-ubuntu-1c + displayName: "kvmtest-t0-2vlans by Elastictest" + timeoutInMinutes: 240 + continueOnError: false + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: t0 + TEST_SET: t0-2vlans + MIN_WORKER: $(T0_2VLANS_INSTANCE_NUM) + MAX_WORKER: $(T0_2VLANS_INSTANCE_NUM) + MGMT_BRANCH: $(BUILD_BRANCH) + DEPLOY_MG_EXTRA_PARAMS: "-e vlan_config=two_vlan_a" + + - job: t1_lag_elastictest + pool: sonic-ubuntu-1c + displayName: "kvmtest-t1-lag by Elastictest" + timeoutInMinutes: 240 + continueOnError: false + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: t1-lag + MIN_WORKER: $(T1_LAG_INSTANCE_NUM) + MAX_WORKER: $(T1_LAG_INSTANCE_NUM) + MGMT_BRANCH: $(BUILD_BRANCH) + + - job: multi_asic_elastictest + displayName: "kvmtest-multi-asic-t1-lag by Elastictest" + pool: sonic-ubuntu-1c + timeoutInMinutes: 240 + continueOnError: false + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: t1-8-lag + TEST_SET: multi-asic-t1-lag + MIN_WORKER: $(MULTI_ASIC_INSTANCE_NUM) + MAX_WORKER: $(MULTI_ASIC_INSTANCE_NUM) + NUM_ASIC: 4 + MGMT_BRANCH: $(BUILD_BRANCH) + + - job: dualtor_elastictest + pool: sonic-ubuntu-1c + displayName: "kvmtest-dualtor-t0 by Elastictest" + timeoutInMinutes: 240 + continueOnError: false + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: dualtor + MIN_WORKER: $(T0_DUALTOR_INSTANCE_NUM) + MAX_WORKER: $(T0_DUALTOR_INSTANCE_NUM) + MGMT_BRANCH: $(BUILD_BRANCH) + COMMON_EXTRA_PARAMS: "--disable_loganalyzer " + + - job: sonic_t0_elastictest + displayName: "kvmtest-t0-sonic by Elastictest" + pool: sonic-ubuntu-1c + timeoutInMinutes: 240 + continueOnError: false + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: t0-64-32 + MIN_WORKER: $(T0_SONIC_INSTANCE_NUM) + MAX_WORKER: $(T0_SONIC_INSTANCE_NUM) + TEST_SET: t0-sonic + MGMT_BRANCH: $(BUILD_BRANCH) + COMMON_EXTRA_PARAMS: "--neighbor_type=sonic " + VM_TYPE: vsonic + + - job: dpu_elastictest + displayName: "kvmtest-dpu by Elastictest" + timeoutInMinutes: 240 + continueOnError: false + pool: sonic-ubuntu-1c + steps: + - template: .azure-pipelines/run-test-elastictest-template.yml@sonic-mgmt + parameters: + TOPOLOGY: dpu + MIN_WORKER: $(T0_SONIC_INSTANCE_NUM) + MAX_WORKER: $(T0_SONIC_INSTANCE_NUM) + MGMT_BRANCH: $(BUILD_BRANCH) diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers.json.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers.json.j2 new file mode 120000 index 0000000000..91bf6407d9 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers.json.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers.json.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_objects.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_objects.j2 new file mode 120000 index 0000000000..b799f8c7e0 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_objects.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers_defaults_objects.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_t0.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_t0.j2 new file mode 120000 index 0000000000..da6bfd24f4 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_t0.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers_defaults_t0.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_t1.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..0c0886d2b1 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_defaults_t1.j2 @@ -0,0 +1,44 @@ +{# + Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. + Apache-2.0 + + 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. +#} +{% set default_cable = '300m' %} +{%-set ports2cable = { + 'spinerouter_leafrouter' : '2000m', + 'leafrouter_torrouter' : '300m' + } +-%} +{% set ingress_lossless_pool_size = '50667520' %} +{% set ingress_lossless_pool_xoff = '3854336' %} +{% set egress_lossless_pool_size = '60817392' %} +{% set egress_lossy_pool_size = '50667520' %} + +{% import 'buffers_defaults_objects.j2' as defs with context %} + +{%- macro generate_buffer_pool_and_profiles_with_inactive_ports(port_names_inactive) %} +{{ defs.generate_buffer_pool_and_profiles_with_inactive_ports(port_names_inactive) }} +{%- endmacro %} + +{%- macro generate_profile_lists_with_inactive_ports(port_names_active, port_names_inactive) %} +{{ defs.generate_profile_lists(port_names_active, port_names_inactive) }} +{%- endmacro %} + +{%- macro generate_queue_buffers_with_inactive_ports(port_names_active, port_names_inactive) %} +{{ defs.generate_queue_buffers(port_names_active, port_names_inactive) }} +{%- endmacro %} + +{%- macro generate_pg_profiles_with_inactive_ports(port_names_active, port_names_inactive) %} +{{ defs.generate_pg_profiles(port_names_active, port_names_inactive) }} +{%- endmacro %} + diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_dynamic.json.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_dynamic.json.j2 new file mode 120000 index 0000000000..4de460cb27 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/buffers_dynamic.json.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers_dynamic.json.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/hwsku.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/hwsku.json new file mode 100644 index 0000000000..0a2a8fb2d6 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/hwsku.json @@ -0,0 +1,264 @@ +{ + "interfaces": { + "Ethernet0": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet4": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet8": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet12": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet16": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet20": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet24": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet28": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet32": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet36": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet40": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet44": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet48": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet52": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet56": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet60": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet64": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet68": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet72": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet76": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet80": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet84": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet88": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet92": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet96": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet104": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet112": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet120": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet128": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet136": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet144": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet152": { + "default_brkout_mode": "1x100G[400G,200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet160": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet164": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet168": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet172": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet176": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet180": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet184": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet188": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet192": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet196": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet200": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet204": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet208": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet212": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet216": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet220": { + "default_brkout_mode": "2x100G[200G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet224": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + }, + "Ethernet232": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + }, + "Ethernet240": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + }, + "Ethernet248": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + } + } +} diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/media_settings.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/media_settings.json new file mode 120000 index 0000000000..becbe5ec68 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/media_settings.json @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/media_settings.json \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/optics_si_settings.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/optics_si_settings.json new file mode 120000 index 0000000000..a30588ab62 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/optics_si_settings.json @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/optics_si_settings.json \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/pg_profile_lookup.ini b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/pg_profile_lookup.ini new file mode 100644 index 0000000000..6b40ed3f60 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/pg_profile_lookup.ini @@ -0,0 +1,60 @@ +## +## Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. +## Apache-2.0 +## +## 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. +## +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 19456 19456 16384 0 + 25000 5m 19456 19456 17408 0 + 40000 5m 19456 19456 19456 0 + 50000 5m 19456 19456 21504 0 + 100000 5m 19456 19456 37888 0 + 200000 5m 19456 19456 43008 0 + 400000 5m 38912 38912 73728 0 + 10000 30m 19456 19456 16384 0 + 25000 30m 19456 19456 18432 0 + 40000 30m 19456 19456 21504 0 + 50000 30m 19456 19456 23552 0 + 100000 30m 19456 19456 43008 0 + 200000 30m 19456 19456 51200 0 + 400000 30m 38912 38912 91136 0 + 10000 40m 19456 19456 16384 0 + 25000 40m 19456 19456 18432 0 + 40000 40m 19456 19456 21504 0 + 50000 40m 19456 19456 23552 0 + 100000 40m 19456 19456 43008 0 + 200000 40m 19456 19456 51200 0 + 400000 40m 38912 38912 91136 0 + 10000 300m 19456 19456 19456 0 + 25000 300m 19456 19456 26624 0 + 40000 300m 19456 19456 34816 0 + 50000 300m 19456 19456 40960 0 + 100000 300m 19456 19456 75776 0 + 200000 300m 19456 19456 118784 0 + 400000 300m 38912 38912 225280 0 + 10000 1500m 19456 19456 35840 0 + 25000 1500m 19456 19456 65536 0 + 40000 1500m 19456 19456 96256 0 + 50000 1500m 19456 19456 117760 0 + 100000 1500m 19456 19456 230400 0 + 200000 1500m 19456 19456 427008 0 + 400000 1500m 38912 38912 427008 0 + 10000 2000m 19456 19456 41984 0 + 25000 2000m 19456 19456 80896 0 + 40000 2000m 19456 19456 121856 0 + 50000 2000m 19456 19456 149504 0 + 100000 2000m 19456 19456 293888 0 + 200000 2000m 19456 19456 555008 0 + 400000 2000m 38912 38912 555008 0 diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/pmon_daemon_control.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/pmon_daemon_control.json new file mode 120000 index 0000000000..fc7fbfe33e --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/pmon_daemon_control.json @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/pmon_daemon_control.json \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/port_config.ini b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/port_config.ini new file mode 100644 index 0000000000..0998d2313c --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/port_config.ini @@ -0,0 +1,70 @@ +## +## Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. +## Apache-2.0 +## +## 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. +## + +# name lanes alias index speed +Ethernet0 0,1,2,3 etp1a 1 100000 +Ethernet4 4,5,6,7 etp1b 1 100000 +Ethernet8 8,9,10,11 etp2a 2 100000 +Ethernet12 12,13,14,15 etp2b 2 100000 +Ethernet16 16,17,18,19 etp3a 3 100000 +Ethernet20 20,21,22,23 etp3b 3 100000 +Ethernet24 24,25,26,27 etp4a 4 100000 +Ethernet28 28,29,30,31 etp4b 4 100000 +Ethernet32 32,33,34,35 etp5a 5 100000 +Ethernet36 36,37,38,39 etp5b 5 100000 +Ethernet40 40,41,42,43 etp6a 6 100000 +Ethernet44 44,45,46,47 etp6b 6 100000 +Ethernet48 48,49,50,51 etp7a 7 100000 +Ethernet52 52,53,54,55 etp7b 7 100000 +Ethernet56 56,57,58,59 etp8a 8 100000 +Ethernet60 60,61,62,63 etp8b 8 100000 +Ethernet64 64,65,66,67 etp9a 9 100000 +Ethernet68 68,69,70,71 etp9b 9 100000 +Ethernet72 72,73,74,75 etp10a 10 100000 +Ethernet76 76,77,78,79 etp10b 10 100000 +Ethernet80 80,81,82,83 etp11a 11 100000 +Ethernet84 84,85,86,87 etp11b 11 100000 +Ethernet88 88,89,90,91 etp12a 12 100000 +Ethernet92 92,93,94,95 etp12b 12 100000 +Ethernet96 96,97,98,99,100,101,102,103 etp13 13 100000 +Ethernet104 104,105,106,107,108,109,110,111 etp14 14 100000 +Ethernet112 112,113,114,115,116,117,118,119 etp15 15 100000 +Ethernet120 120,121,122,123,124,125,126,127 etp16 16 100000 +Ethernet128 128,129,130,131,132,133,134,135 etp17 17 100000 +Ethernet136 136,137,138,139,140,141,142,143 etp18 18 100000 +Ethernet144 144,145,146,147,148,149,150,151 etp19 19 100000 +Ethernet152 152,153,154,155,156,157,158,159 etp20 20 100000 +Ethernet160 160,161,162,163 etp21a 21 100000 +Ethernet164 164,165,166,167 etp21b 21 100000 +Ethernet168 168,169,170,171 etp22a 22 100000 +Ethernet172 172,173,174,175 etp22b 22 100000 +Ethernet176 176,177,178,179 etp23a 23 100000 +Ethernet180 180,181,182,183 etp23b 23 100000 +Ethernet184 184,185,186,187 etp24a 24 100000 +Ethernet188 188,189,190,191 etp24b 24 100000 +Ethernet192 192,193,194,195 etp25a 25 100000 +Ethernet196 196,197,198,199 etp25b 25 100000 +Ethernet200 200,201,202,203 etp26a 26 100000 +Ethernet204 204,205,206,207 etp26b 26 100000 +Ethernet208 208,209,210,211 etp27a 27 100000 +Ethernet212 212,213,214,215 etp27b 27 100000 +Ethernet216 216,217,218,219 etp28a 28 100000 +Ethernet220 220,221,222,223 etp28b 28 100000 +Ethernet224 224,225,226,227,228,229,230,231 etp29 29 400000 +Ethernet232 232,233,234,235,236,237,238,239 etp30 30 400000 +Ethernet240 240,241,242,243,244,245,246,247 etp31 31 400000 +Ethernet248 248,249,250,251,252,253,254,255 etp32 32 400000 diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/qos.json.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/qos.json.j2 new file mode 120000 index 0000000000..176ba14827 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/qos.json.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/qos.json.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/sai.profile b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/sai.profile new file mode 120000 index 0000000000..ee409a1510 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/sai.profile @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/sai.profile \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/sai_4280.xml b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/sai_4280.xml new file mode 120000 index 0000000000..563ede5a0a --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-C48/sai_4280.xml @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/sai_4280.xml \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers.json.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers.json.j2 new file mode 120000 index 0000000000..91bf6407d9 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers.json.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers.json.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_objects.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_objects.j2 new file mode 120000 index 0000000000..b799f8c7e0 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_objects.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers_defaults_objects.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_t0.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_t0.j2 new file mode 120000 index 0000000000..da6bfd24f4 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_t0.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers_defaults_t0.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_t1.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..c0792d5651 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_defaults_t1.j2 @@ -0,0 +1,38 @@ +{# + Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. + Apache-2.0 + + 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. +#} +{% set default_cable = '300m' %} +{% set ingress_lossless_pool_size = '48013312' %} +{% set ingress_lossless_pool_xoff = '6508544' %} +{% set egress_lossless_pool_size = '60817392' %} +{% set egress_lossy_pool_size = '48013312' %} + +{% import 'buffers_defaults_objects.j2' as defs with context %} + +{%- macro generate_buffer_pool_and_profiles_with_inactive_ports(port_names_inactive) %} +{{ defs.generate_buffer_pool_and_profiles_with_inactive_ports(port_names_inactive) }} +{%- endmacro %} + +{%- macro generate_profile_lists_with_inactive_ports(port_names_active, port_names_inactive) %} +{{ defs.generate_profile_lists(port_names_active, port_names_inactive) }} +{%- endmacro %} + +{%- macro generate_queue_buffers_with_inactive_ports(port_names_active, port_names_inactive) %} +{{ defs.generate_queue_buffers(port_names_active, port_names_inactive) }} +{%- endmacro %} + +{%- macro generate_pg_profiles_with_inactive_ports(port_names_active, port_names_inactive) %} +{{ defs.generate_pg_profiles(port_names_active, port_names_inactive) }} +{%- endmacro %} diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_dynamic.json.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_dynamic.json.j2 new file mode 120000 index 0000000000..4de460cb27 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/buffers_dynamic.json.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/buffers_dynamic.json.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/hwsku.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/hwsku.json new file mode 100644 index 0000000000..7a7d0d6c65 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/hwsku.json @@ -0,0 +1,264 @@ +{ + "interfaces": { + "Ethernet0": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet4": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet8": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet12": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet16": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet20": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet24": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet28": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet32": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet36": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet40": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet44": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet48": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet52": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet56": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet60": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet64": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet68": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet72": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet76": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet80": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet84": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet88": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet92": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet96": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet104": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet112": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet120": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet128": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet136": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet144": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet152": { + "default_brkout_mode": "1x400G[200G,100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet160": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet164": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet168": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet172": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet176": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet180": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet184": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet188": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet192": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet196": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet200": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet204": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet208": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet212": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet216": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "1", + "autoneg": "off" + }, + "Ethernet220": { + "default_brkout_mode": "2x200G[100G,50G,40G,25G,10G,1G]", + "subport": "2", + "autoneg": "off" + }, + "Ethernet224": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + }, + "Ethernet232": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + }, + "Ethernet240": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + }, + "Ethernet248": { + "default_brkout_mode": "1x400G", + "subport": "1", + "autoneg": "off" + } + } +} diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/media_settings.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/media_settings.json new file mode 120000 index 0000000000..becbe5ec68 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/media_settings.json @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/media_settings.json \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/optics_si_settings.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/optics_si_settings.json new file mode 120000 index 0000000000..a30588ab62 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/optics_si_settings.json @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/optics_si_settings.json \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/pg_profile_lookup.ini b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/pg_profile_lookup.ini new file mode 100644 index 0000000000..6b40ed3f60 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/pg_profile_lookup.ini @@ -0,0 +1,60 @@ +## +## Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. +## Apache-2.0 +## +## 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. +## +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 19456 19456 16384 0 + 25000 5m 19456 19456 17408 0 + 40000 5m 19456 19456 19456 0 + 50000 5m 19456 19456 21504 0 + 100000 5m 19456 19456 37888 0 + 200000 5m 19456 19456 43008 0 + 400000 5m 38912 38912 73728 0 + 10000 30m 19456 19456 16384 0 + 25000 30m 19456 19456 18432 0 + 40000 30m 19456 19456 21504 0 + 50000 30m 19456 19456 23552 0 + 100000 30m 19456 19456 43008 0 + 200000 30m 19456 19456 51200 0 + 400000 30m 38912 38912 91136 0 + 10000 40m 19456 19456 16384 0 + 25000 40m 19456 19456 18432 0 + 40000 40m 19456 19456 21504 0 + 50000 40m 19456 19456 23552 0 + 100000 40m 19456 19456 43008 0 + 200000 40m 19456 19456 51200 0 + 400000 40m 38912 38912 91136 0 + 10000 300m 19456 19456 19456 0 + 25000 300m 19456 19456 26624 0 + 40000 300m 19456 19456 34816 0 + 50000 300m 19456 19456 40960 0 + 100000 300m 19456 19456 75776 0 + 200000 300m 19456 19456 118784 0 + 400000 300m 38912 38912 225280 0 + 10000 1500m 19456 19456 35840 0 + 25000 1500m 19456 19456 65536 0 + 40000 1500m 19456 19456 96256 0 + 50000 1500m 19456 19456 117760 0 + 100000 1500m 19456 19456 230400 0 + 200000 1500m 19456 19456 427008 0 + 400000 1500m 38912 38912 427008 0 + 10000 2000m 19456 19456 41984 0 + 25000 2000m 19456 19456 80896 0 + 40000 2000m 19456 19456 121856 0 + 50000 2000m 19456 19456 149504 0 + 100000 2000m 19456 19456 293888 0 + 200000 2000m 19456 19456 555008 0 + 400000 2000m 38912 38912 555008 0 diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/pmon_daemon_control.json b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/pmon_daemon_control.json new file mode 120000 index 0000000000..fc7fbfe33e --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/pmon_daemon_control.json @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/pmon_daemon_control.json \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/port_config.ini b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/port_config.ini new file mode 100644 index 0000000000..f22f59516b --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/port_config.ini @@ -0,0 +1,70 @@ +## +## Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. +## Apache-2.0 +## +## 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. +## + +# name lanes alias index speed +Ethernet0 0,1,2,3 etp1a 1 200000 +Ethernet4 4,5,6,7 etp1b 1 200000 +Ethernet8 8,9,10,11 etp2a 2 200000 +Ethernet12 12,13,14,15 etp2b 2 200000 +Ethernet16 16,17,18,19 etp3a 3 200000 +Ethernet20 20,21,22,23 etp3b 3 200000 +Ethernet24 24,25,26,27 etp4a 4 200000 +Ethernet28 28,29,30,31 etp4b 4 200000 +Ethernet32 32,33,34,35 etp5a 5 200000 +Ethernet36 36,37,38,39 etp5b 5 200000 +Ethernet40 40,41,42,43 etp6a 6 200000 +Ethernet44 44,45,46,47 etp6b 6 200000 +Ethernet48 48,49,50,51 etp7a 7 200000 +Ethernet52 52,53,54,55 etp7b 7 200000 +Ethernet56 56,57,58,59 etp8a 8 200000 +Ethernet60 60,61,62,63 etp8b 8 200000 +Ethernet64 64,65,66,67 etp9a 9 200000 +Ethernet68 68,69,70,71 etp9b 9 200000 +Ethernet72 72,73,74,75 etp10a 10 200000 +Ethernet76 76,77,78,79 etp10b 10 200000 +Ethernet80 80,81,82,83 etp11a 11 200000 +Ethernet84 84,85,86,87 etp11b 11 200000 +Ethernet88 88,89,90,91 etp12a 12 200000 +Ethernet92 92,93,94,95 etp12b 12 200000 +Ethernet96 96,97,98,99,100,101,102,103 etp13 13 400000 +Ethernet104 104,105,106,107,108,109,110,111 etp14 14 400000 +Ethernet112 112,113,114,115,116,117,118,119 etp15 15 400000 +Ethernet120 120,121,122,123,124,125,126,127 etp16 16 400000 +Ethernet128 128,129,130,131,132,133,134,135 etp17 17 400000 +Ethernet136 136,137,138,139,140,141,142,143 etp18 18 400000 +Ethernet144 144,145,146,147,148,149,150,151 etp19 19 400000 +Ethernet152 152,153,154,155,156,157,158,159 etp20 20 400000 +Ethernet160 160,161,162,163 etp21a 21 200000 +Ethernet164 164,165,166,167 etp21b 21 200000 +Ethernet168 168,169,170,171 etp22a 22 200000 +Ethernet172 172,173,174,175 etp22b 22 200000 +Ethernet176 176,177,178,179 etp23a 23 200000 +Ethernet180 180,181,182,183 etp23b 23 200000 +Ethernet184 184,185,186,187 etp24a 24 200000 +Ethernet188 188,189,190,191 etp24b 24 200000 +Ethernet192 192,193,194,195 etp25a 25 200000 +Ethernet196 196,197,198,199 etp25b 25 200000 +Ethernet200 200,201,202,203 etp26a 26 200000 +Ethernet204 204,205,206,207 etp26b 26 200000 +Ethernet208 208,209,210,211 etp27a 27 200000 +Ethernet212 212,213,214,215 etp27b 27 200000 +Ethernet216 216,217,218,219 etp28a 28 200000 +Ethernet220 220,221,222,223 etp28b 28 200000 +Ethernet224 224,225,226,227,228,229,230,231 etp29 29 400000 +Ethernet232 232,233,234,235,236,237,238,239 etp30 30 400000 +Ethernet240 240,241,242,243,244,245,246,247 etp31 31 400000 +Ethernet248 248,249,250,251,252,253,254,255 etp32 32 400000 diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/qos.json.j2 b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/qos.json.j2 new file mode 120000 index 0000000000..176ba14827 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/qos.json.j2 @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/qos.json.j2 \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/sai.profile b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/sai.profile new file mode 120000 index 0000000000..ee409a1510 --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/sai.profile @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/sai.profile \ No newline at end of file diff --git a/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/sai_4280.xml b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/sai_4280.xml new file mode 120000 index 0000000000..563ede5a0a --- /dev/null +++ b/device/mellanox/x86_64-nvidia_sn4280-r0/Mellanox-SN4280-O8V40/sai_4280.xml @@ -0,0 +1 @@ +../Mellanox-SN4280-O28/sai_4280.xml \ No newline at end of file diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.main.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.main.conf.j2 index db11d662a3..0f848195af 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.main.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.main.conf.j2 @@ -88,8 +88,10 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp graceful-restart select-defer-time {{ constants.bgp.graceful_restart.select_defer_time | default(45) }} {% endif %} ! -{# set bmp info #} -{% if (FEATURE is defined) and ('bmp' in FEATURE) and ('state' in FEATURE['bmp']) and (FEATURE['bmp']['state'] == 'enabled') %} +{# set frr_bmp info #} +{% if (FEATURE is defined) and + (('frr_bmp' in FEATURE and 'state' in FEATURE['frr_bmp'] and FEATURE['frr_bmp']['state'] == 'enabled') or + ('bmp' in FEATURE and 'state' in FEATURE['bmp'] and FEATURE['bmp']['state'] == 'enabled')) %} ! bmp mirror buffer-limit 4294967214 ! @@ -97,7 +99,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bmp stats interval 1000 bmp monitor ipv4 unicast pre-policy bmp monitor ipv6 unicast pre-policy - bmp connect 127.0.0.1 port 5000 min-retry 1000 max-retry 2000 + bmp connect 127.0.0.1 port 5000 min-retry 10000 max-retry 15000 ! ! {% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/templates/internal/policies.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/templates/internal/policies.conf.j2 index e6eccc75fa..c0e49cc904 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/templates/internal/policies.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/templates/internal/policies.conf.j2 @@ -39,8 +39,9 @@ route-map FROM_BGP_INTERNAL_PEER_V4 permit 2 on-match next ! {% if CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'DownstreamLC' %} -route-map FROM_BGP_INTERNAL_PEER_V4 deny 3 +route-map FROM_BGP_INTERNAL_PEER_V4 permit 3 match community DEVICE_INTERNAL_FALLBACK_COMMUNITY + set comm-list DEVICE_INTERNAL_FALLBACK_COMMUNITY delete {% else %} route-map FROM_BGP_INTERNAL_PEER_V4 permit 3 match community DEVICE_INTERNAL_FALLBACK_COMMUNITY @@ -63,8 +64,9 @@ route-map FROM_BGP_INTERNAL_PEER_V6 permit 3 on-match next ! {% if CONFIG_DB__DEVICE_METADATA['localhost']['subtype'] == 'DownstreamLC' %} -route-map FROM_BGP_INTERNAL_PEER_V6 deny 4 +route-map FROM_BGP_INTERNAL_PEER_V6 permit 4 match community DEVICE_INTERNAL_FALLBACK_COMMUNITY + set comm-list DEVICE_INTERNAL_FALLBACK_COMMUNITY delete {% else %} route-map FROM_BGP_INTERNAL_PEER_V6 permit 4 match community DEVICE_INTERNAL_FALLBACK_COMMUNITY diff --git a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 index 113289af3b..9c726e564e 100644 --- a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 +++ b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 @@ -88,7 +88,9 @@ dependent_startup_wait_for=zebra:running {% endif %} [program:bgpd] -{% if FEATURE is defined and FEATURE.bmp is defined and FEATURE.bmp.state is defined and FEATURE.bmp.state == "enabled" %} +{% if FEATURE is defined and + (FEATURE.frr_bmp is defined and FEATURE.frr_bmp.state is defined and FEATURE.frr_bmp.state == "enabled") or + (FEATURE.bmp is defined and FEATURE.bmp.state is defined and FEATURE.bmp.state == "enabled") %} command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp -M bmp {% else %} command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp diff --git a/dockers/docker-orchagent/orchagent.sh b/dockers/docker-orchagent/orchagent.sh index 45f4999b61..07e20d3532 100755 --- a/dockers/docker-orchagent/orchagent.sh +++ b/dockers/docker-orchagent/orchagent.sh @@ -110,4 +110,7 @@ if [[ x"${MGMT_VRF_ENABLED}" == x"true" ]]; then ORCHAGENT_ARGS+=" -v mgmt" fi +# Mask SIGHUP signal to avoid orchagent termination by logrotate before orchagent registers its handler. +trap '' SIGHUP + exec /usr/bin/orchagent ${ORCHAGENT_ARGS} diff --git a/dockers/docker-ptf/Dockerfile.j2 b/dockers/docker-ptf/Dockerfile.j2 index 5148dd1125..30242a3382 100644 --- a/dockers/docker-ptf/Dockerfile.j2 +++ b/dockers/docker-ptf/Dockerfile.j2 @@ -88,7 +88,9 @@ RUN apt-get update \ gdb \ automake \ iproute2 \ - wireshark-common + wireshark-common \ + freeradius \ + quilt {% if PTF_ENV_PY_VER == "py3" %} RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1 \ @@ -157,6 +159,7 @@ RUN rm -rf /debs \ && pip install pysubnettree \ && pip install paramiko \ && pip install flask \ + && pip install tornado \ && pip install exabgp==3.4.17\ && pip install pyaml \ && pip install pybrctl pyro4 rpyc yabgp \ @@ -194,10 +197,11 @@ RUN pip3 install setuptools \ && pip3 install ipaddress \ && pip3 install pysubnettree \ && pip3 install paramiko \ + && pip3 install tornado \ && pip3 install Flask \ && pip3 install exabgp \ && pip3 install pyaml \ - && pip3 install pybrctl pyro4 rpyc \ + && pip3 install pyro4 rpyc \ && pip3 install unittest-xml-reporting \ && pip3 install pyrasite \ && pip3 install python-libpcap \ @@ -245,9 +249,14 @@ RUN ln -s /usr/bin/tcpdump /usr/sbin/tcpdump RUN mkdir -p /var/log/supervisor # Install Python-based GNMI client -RUN git clone https://github.com/lguohan/gnxi.git \ +RUN git clone https://github.com/google/gnxi.git \ && cd gnxi \ - && git checkout 3adf8b9 \ + && git checkout 208acfa85f5b5b8717e14896e9d6ee93cfda9d5f + +COPY gnxi-patches/ gnxi/patches/ + +RUN cd gnxi \ + && quilt push -a \ && cd gnmi_cli_py \ {% if PTF_ENV_PY_VER == "mixed" %} && pip install -r requirements.txt diff --git a/dockers/docker-ptf/gnxi-patches/0001-add-xpath_target-option.patch b/dockers/docker-ptf/gnxi-patches/0001-add-xpath_target-option.patch new file mode 100644 index 0000000000..8d1f86e3b5 --- /dev/null +++ b/dockers/docker-ptf/gnxi-patches/0001-add-xpath_target-option.patch @@ -0,0 +1,76 @@ +From d01b36e471f387007680e0f07d8bfe32db8e0269 Mon Sep 17 00:00:00 2001 +From: Guohan Lu +Date: Fri, 3 Jul 2020 09:17:32 +0000 +Subject: [PATCH 1/5] add xpath_target option + +Signed-off-by: Guohan Lu +--- + gnmi_cli_py/py_gnmicli.py | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py +index 7c9e92b..062dee7 100644 +--- a/gnmi_cli_py/py_gnmicli.py ++++ b/gnmi_cli_py/py_gnmicli.py +@@ -126,6 +126,9 @@ def _create_parser(): + required=False, action='store_true') + parser.add_argument('-x', '--xpath', type=str, help='The gNMI path utilized' + 'in the GetRequest or Subscirbe', required=True) ++ parser.add_argument('-xt', '--xpath_target', type=str, help='The gNMI prefix' ++ 'target in the GetRequest or Subscirbe', default=None, ++ required=False) + parser.add_argument('-o', '--host_override', type=str, help='Use this as ' + 'Targets hostname/peername when checking it\'s' + 'certificate CN. You can check the cert with:\nopenssl ' +@@ -258,7 +261,7 @@ def _get_val(json_value): + return val + + +-def _get(stub, paths, username, password): ++def _get(stub, paths, username, password, prefix): + """Create a gNMI GetRequest. + + Args: +@@ -266,16 +269,17 @@ def _get(stub, paths, username, password): + paths: gNMI Path + username: (str) Username used when building the channel. + password: (str) Password used when building the channel. ++ prefix: gNMI Path + + Returns: + a gnmi_pb2.GetResponse object representing a gNMI GetResponse. + """ ++ kwargs = {} + if username: # User/pass supplied for Authentication. +- return stub.Get( +- gnmi_pb2.GetRequest(path=[paths], encoding='JSON_IETF'), +- metadata=[('username', username), ('password', password)]) +- return stub.Get(gnmi_pb2.GetRequest(path=[paths], encoding='JSON_IETF')) +- ++ kwargs = {'metadata': [('username', username), ('password', password)]} ++ return stub.Get( ++ gnmi_pb2.GetRequest(prefix=prefix, path=[paths], encoding='JSON_IETF'), ++ **kwargs) + + def _set(stub, paths, set_type, username, password, json_value): + """Create a gNMI SetRequest. +@@ -368,6 +372,7 @@ def main(): + json_value = args['value'] + private_key = args['private_key'] + xpath = args['xpath'] ++ prefix = gnmi_pb2.Path(target=args['xpath_target']) + host_override = args['host_override'] + user = args['username'] + password = args['password'] +@@ -381,7 +386,7 @@ def main(): + if mode == 'get': + print('Performing GetRequest, encoding=JSON_IETF', 'to', target, + ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _get(stub, paths, user, password) ++ response = _get(stub, paths, user, password, prefix) + print('The GetResponse is below\n' + '-'*25 + '\n') + if form == 'protobuff': + print(response) +-- +2.48.1.windows.1 + diff --git a/dockers/docker-ptf/gnxi-patches/0002-Adding-support-for-subscribe-mode-1.patch b/dockers/docker-ptf/gnxi-patches/0002-Adding-support-for-subscribe-mode-1.patch new file mode 100644 index 0000000000..eca4176d39 --- /dev/null +++ b/dockers/docker-ptf/gnxi-patches/0002-Adding-support-for-subscribe-mode-1.patch @@ -0,0 +1,166 @@ +From 53901aba9ead82be21f1408a601b6266dcf1e3e4 Mon Sep 17 00:00:00 2001 +From: macikgozwa <74217992+macikgozwa@users.noreply.github.com> +Date: Mon, 9 Nov 2020 16:19:24 -0800 +Subject: [PATCH 2/5] Adding support for subscribe mode (#1) + +- Adding support for subscribe mode. The code is mostly based on this patch: https://github.com/google/gnxi/pull/65 +- Adding a new parameter to limit the number of updates, e.g. after a number of streaming updates the client would stop listening. It is convenient for testing purposes. +- Changing the sample interval unit to millisecond. This is also required for testing cases. + +Co-authored-by: Murat Acikgoz +--- + gnmi_cli_py/py_gnmicli.py | 102 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 95 insertions(+), 7 deletions(-) + +diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py +index 062dee7..7152f13 100644 +--- a/gnmi_cli_py/py_gnmicli.py ++++ b/gnmi_cli_py/py_gnmicli.py +@@ -24,9 +24,7 @@ Current supported gNMI features: + - Auto-loads Target cert from Target if not specified + - User/password based authentication + - Certifificate based authentication +- +-Current unsupported gNMI features: +-- Subscribe ++- Subscribe request + """ + + from __future__ import absolute_import +@@ -40,14 +38,16 @@ import re + import ssl + import sys + import six ++import datetime + try: + import gnmi_pb2 + except ImportError: + print('ERROR: Ensure you\'ve installed dependencies from requirements.txt\n' + 'eg, pip install -r requirements.txt') + import gnmi_pb2_grpc ++import grpc + +-__version__ = '0.4' ++__version__ = '0.5' + + _RE_PATH_COMPONENT = re.compile(r''' + ^ +@@ -143,6 +143,21 @@ def _create_parser(): + required=False, action='store_true') + parser.add_argument('-n', '--notls', help='gRPC insecure mode', + required=False, action='store_true') ++ parser.add_argument('--interval', default=10000, type=int, ++ help='sample interval in millisecond (default: 10000ms)') ++ parser.add_argument('--timeout', type=int, help='subscription' ++ 'duration in seconds (default: none)') ++ parser.add_argument('--heartbeat', default=0, type=int, help='heartbeat interval (default: None)') ++ parser.add_argument('--aggregate', action='store_true', help='allow aggregation') ++ parser.add_argument('--suppress', action='store_true', help='suppress redundant') ++ parser.add_argument('--submode', default=2, type=int, ++ help='subscription mode [0=TARGET_DEFINED, 1=ON_CHANGE, 2=SAMPLE]') ++ parser.add_argument('--update_count', default=0, type=int, help='Max number of streaming updates to receive. 0 means no limit.') ++ parser.add_argument('--subscribe_mode', default=0, type=int, help='[0=STREAM, 1=ONCE, 2=POLL]') ++ parser.add_argument('--encoding', default=0, type=int, help='[0=JSON, 1=BYTES, 2=PROTO, 3=ASCII, 4=JSON_IETF]') ++ parser.add_argument('--qos', default=0, type=int, help='') ++ parser.add_argument('--use_alias', action='store_true', help='use alias') ++ parser.add_argument('--prefix', default='', help='gRPC path prefix (default: none)') + return parser + + +@@ -353,6 +368,79 @@ def _open_certs(**kwargs): + return kwargs + + ++def gen_request(paths, opt, prefix): ++ """Create subscribe request for passed xpath. ++ Args: ++ paths: (str) gNMI path. ++ opt: (dict) Command line argument passed for subscribe reqeust. ++ Returns: ++ gNMI SubscribeRequest object. ++ """ ++ mysubs = [] ++ mysub = gnmi_pb2.Subscription(path=paths, mode=opt["submode"], ++ sample_interval=opt["interval"]*1000000, ++ heartbeat_interval=opt['heartbeat']*1000000, ++ suppress_redundant=opt['suppress']) ++ mysubs.append(mysub) ++ ++ if prefix: ++ myprefix = prefix ++ elif opt["prefix"]: ++ myprefix = _parse_path(_path_names(opt["prefix"])) ++ else: ++ myprefix = None ++ ++ if opt["qos"]: ++ myqos = gnmi_pb2.QOSMarking(marking=opt["qos"]) ++ else: ++ myqos = None ++ mysblist = gnmi_pb2.SubscriptionList(prefix=myprefix, mode=opt['subscribe_mode'], ++ allow_aggregation=opt['aggregate'], encoding=opt['encoding'], ++ subscription=mysubs, use_aliases=opt['use_alias'], qos=myqos) ++ mysubreq = gnmi_pb2.SubscribeRequest(subscribe=mysblist) ++ ++ print('Sending SubscribeRequest\n'+str(mysubreq)) ++ yield mysubreq ++ ++ ++def subscribe_start(stub, options, req_iterator): ++ """ RPC Start for Subscribe reqeust ++ Args: ++ stub: (class) gNMI Stub used to build the secure channel. ++ options: (dict) Command line argument passed for subscribe reqeust. ++ req_iterator: gNMI Subscribe Request from gen_request. ++ Returns: ++ Start Subscribe and printing response of gNMI Subscribe Response. ++ """ ++ metadata = [('username', options['username']), ('password', options['password'])] ++ max_update_count = options["update_count"] ++ try: ++ responses = stub.Subscribe(req_iterator, options['timeout'], metadata=metadata) ++ update_count = 0 ++ for response in responses: ++ print('{0} response received: '.format(datetime.datetime.now())) ++ if response.HasField('sync_response'): ++ print(str(response)) ++ elif response.HasField('error'): ++ print('gNMI Error '+str(response.error.code)+\ ++ ' received\n'+str(response.error.message) + str(response.error)) ++ elif response.HasField('update'): ++ print(response) ++ update_count = update_count+1 ++ else: ++ print('Unknown response received:\n'+str(response)) ++ ++ if max_update_count != 0 and update_count == max_update_count: ++ print("Max update count reached {0}".format(update_count)) ++ break ++ except KeyboardInterrupt: ++ print("Subscribe Session stopped by user.") ++ except grpc.RpcError as x: ++ print("grpc.RpcError received:\n%s" %x) ++ except Exception as err: ++ print(err) ++ ++ + def main(): + argparser = _create_parser() + args = vars(argparser.parse_args()) +@@ -414,9 +502,9 @@ def main(): + response = _set(stub, paths, 'delete', user, password, json_value) + print('The SetRequest response is below\n' + '-'*25 + '\n', response) + elif mode == 'subscribe': +- print('This mode not available in this version') +- sys.exit() ++ request_iterator = gen_request(paths, args, prefix) ++ subscribe_start(stub, args, request_iterator) + + + if __name__ == '__main__': +- main() ++ main() +\ No newline at end of file +-- +2.48.1.windows.1 + diff --git a/dockers/docker-ptf/gnxi-patches/0003-gNMI_client-Add-an-option-to-trigger-memory-spike-on.patch b/dockers/docker-ptf/gnxi-patches/0003-gNMI_client-Add-an-option-to-trigger-memory-spike-on.patch new file mode 100644 index 0000000000..42d893b619 --- /dev/null +++ b/dockers/docker-ptf/gnxi-patches/0003-gNMI_client-Add-an-option-to-trigger-memory-spike-on.patch @@ -0,0 +1,167 @@ +From f2b11e45b16ab13485ae14933f30c18ee6336499 Mon Sep 17 00:00:00 2001 +From: yozhao101 <56170650+yozhao101@users.noreply.github.com> +Date: Thu, 14 Jul 2022 15:02:01 -0700 +Subject: [PATCH 3/5] [gNMI_client] Add an option to trigger memory spike on + gNMI server. (#2) + +What is the motivation of this PR? +This PR aims to trigger memory spike on gNMI server side without explicitly closing the channels (TCP connections) from gNMI client side. + +How did you do it? +I added an option --trigger_mem_spike in this python client script such that the user can specify this option to trigger memory spike. + +How did you test/verify it? +I verify this on the ptf docker container binding to the lab device str-s6000-acs-11. The command line I used is as following: +python /gnxi/gnmi_cli_py/py_gnmicli.py -g -t *.*.*.* -p 50051 -m subscribe -x DOCKER_STATS,TEST_STATS -xt STATE_DB -o "ndastreamingservertest" --trigger_mem_spike + +Signed-off-by: Yong Zhao +--- + gnmi_cli_py/py_gnmicli.py | 105 ++++++++++++++++++++++++-------------- + 1 file changed, 67 insertions(+), 38 deletions(-) + +diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py +index 7152f13..62d4ec8 100644 +--- a/gnmi_cli_py/py_gnmicli.py ++++ b/gnmi_cli_py/py_gnmicli.py +@@ -57,7 +57,8 @@ _RE_PATH_COMPONENT = re.compile(r''' + (?P.*) # gNMI path value + \])?$ + ''', re.VERBOSE) +- ++INVALID_GNMI_CLIENT_CONNECTION_NUMBER = 1 ++GNMI_SERVER_UNAVAILABLE = 2 + + class Error(Exception): + """Module-level Exception class.""" +@@ -157,6 +158,10 @@ def _create_parser(): + parser.add_argument('--encoding', default=0, type=int, help='[0=JSON, 1=BYTES, 2=PROTO, 3=ASCII, 4=JSON_IETF]') + parser.add_argument('--qos', default=0, type=int, help='') + parser.add_argument('--use_alias', action='store_true', help='use alias') ++ parser.add_argument('--create_connections', type=int, nargs='?', const=1, default=1, ++ help='Creates specific number of TCP connections with gNMI server side. ' ++ 'Default number of TCP connections is 1 and use -1 to create ' ++ 'infinite TCP connections.') + parser.add_argument('--prefix', default='', help='gRPC path prefix (default: none)') + return parser + +@@ -435,8 +440,9 @@ def subscribe_start(stub, options, req_iterator): + break + except KeyboardInterrupt: + print("Subscribe Session stopped by user.") +- except grpc.RpcError as x: +- print("grpc.RpcError received:\n%s" %x) ++ except grpc.RpcError as err: ++ print("Received an exception from server side and error message is: '{}'.".format(err)) ++ raise + except Exception as err: + print(err) + +@@ -465,46 +471,69 @@ def main(): + user = args['username'] + password = args['password'] + form = args['format'] ++ create_connections = args['create_connections'] + paths = _parse_path(_path_names(xpath)) + kwargs = {'root_cert': root_cert, 'cert_chain': cert_chain, + 'private_key': private_key} + certs = _open_certs(**kwargs) + creds = _build_creds(target, port, get_cert, certs, notls) +- stub = _create_stub(creds, target, port, host_override) +- if mode == 'get': +- print('Performing GetRequest, encoding=JSON_IETF', 'to', target, +- ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _get(stub, paths, user, password, prefix) +- print('The GetResponse is below\n' + '-'*25 + '\n') +- if form == 'protobuff': +- print(response) +- elif response.notification[0].update[0].val.json_ietf_val: +- print(json.dumps(json.loads(response.notification[0].update[0].val. +- json_ietf_val), indent=2)) +- elif response.notification[0].update[0].val.string_val: +- print(response.notification[0].update[0].val.string_val) +- else: +- print('JSON Format specified, but gNMI Response was not json_ietf_val') +- print(response) +- elif mode == 'set-update': +- print('Performing SetRequest Update, encoding=JSON_IETF', ' to ', target, +- ' with the following gNMI Path\n', '-'*25, '\n', paths, json_value) +- response = _set(stub, paths, 'update', user, password, json_value) +- print('The SetRequest response is below\n' + '-'*25 + '\n', response) +- elif mode == 'set-replace': +- print('Performing SetRequest Replace, encoding=JSON_IETF', ' to ', target, +- ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _set(stub, paths, 'replace', user, password, json_value) +- print('The SetRequest response is below\n' + '-'*25 + '\n', response) +- elif mode == 'set-delete': +- print('Performing SetRequest Delete, encoding=JSON_IETF', ' to ', target, +- ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _set(stub, paths, 'delete', user, password, json_value) +- print('The SetRequest response is below\n' + '-'*25 + '\n', response) +- elif mode == 'subscribe': +- request_iterator = gen_request(paths, args, prefix) +- subscribe_start(stub, args, request_iterator) ++ ++ if create_connections < -1: ++ print(''' ++ Default number of TCP connections with gNMI server is 1. ++ Please use the '--create_connections ' to ++ create TCP connections or use '--create_connections -1' to ++ create infinite TCP connections. ++ ''', file=sys.stderr) ++ sys.exit(INVALID_GNMI_CLIENT_CONNECTION_NUMBER) ++ ++ while True: ++ if create_connections > 0: ++ create_connections -= 1 ++ elif create_connections == 0: ++ break ++ ++ try: ++ stub = _create_stub(creds, target, port, host_override) ++ if mode == 'get': ++ print('Performing GetRequest, encoding=JSON_IETF', 'to', target, ++ ' with the following gNMI Path\n', '-'*25, '\n', paths) ++ response = _get(stub, paths, user, password, prefix) ++ print('The GetResponse is below\n' + '-'*25 + '\n') ++ if form == 'protobuff': ++ print(response) ++ elif response.notification[0].update[0].val.json_ietf_val: ++ print(json.dumps(json.loads(response.notification[0].update[0].val. ++ json_ietf_val), indent=2)) ++ elif response.notification[0].update[0].val.string_val: ++ print(response.notification[0].update[0].val.string_val) ++ else: ++ print('JSON Format specified, but gNMI Response was not json_ietf_val') ++ print(response) ++ elif mode == 'set-update': ++ print('Performing SetRequest Update, encoding=JSON_IETF', ' to ', target, ++ ' with the following gNMI Path\n', '-'*25, '\n', paths, json_value) ++ response = _set(stub, paths, 'update', user, password, json_value) ++ print('The SetRequest response is below\n' + '-'*25 + '\n', response) ++ elif mode == 'set-replace': ++ print('Performing SetRequest Replace, encoding=JSON_IETF', ' to ', target, ++ ' with the following gNMI Path\n', '-'*25, '\n', paths) ++ response = _set(stub, paths, 'replace', user, password, json_value) ++ print('The SetRequest response is below\n' + '-'*25 + '\n', response) ++ elif mode == 'set-delete': ++ print('Performing SetRequest Delete, encoding=JSON_IETF', ' to ', target, ++ ' with the following gNMI Path\n', '-'*25, '\n', paths) ++ response = _set(stub, paths, 'delete', user, password, json_value) ++ print('The SetRequest response is below\n' + '-'*25 + '\n', response) ++ elif mode == 'subscribe': ++ request_iterator = gen_request(paths, args, prefix) ++ subscribe_start(stub, args, request_iterator) ++ except grpc.RpcError as err: ++ if err.code() == grpc.StatusCode.UNAVAILABLE: ++ print("Client receives an exception '{}' indicating gNMI server is shut down and Exiting ..." ++ .format(err.details())) ++ sys.exit(GNMI_SERVER_UNAVAILABLE) + + + if __name__ == '__main__': +- main() +\ No newline at end of file ++ main() +-- +2.48.1.windows.1 + diff --git a/dockers/docker-ptf/gnxi-patches/0004-Add-support-for-streaming-structured-events-in-night.patch b/dockers/docker-ptf/gnxi-patches/0004-Add-support-for-streaming-structured-events-in-night.patch new file mode 100644 index 0000000000..8d82b86492 --- /dev/null +++ b/dockers/docker-ptf/gnxi-patches/0004-Add-support-for-streaming-structured-events-in-night.patch @@ -0,0 +1,88 @@ +From b85e4ab565df4472fdcfcded2a53e6bf57aa493f Mon Sep 17 00:00:00 2001 +From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> +Date: Tue, 20 Jun 2023 13:58:42 -0700 +Subject: [PATCH 4/5] Add support for streaming structured events in nightly + test (#3) + +What is the motivation of this PR? + +This PR adds support for testing structured events as part of nightly test, by adding params: filter_event and event_op_file +When subscribing to EVENTS/all we will check for filter_event as part of response and then we will add response that contains filter to op_file. Test will then fetch this output file then do parsing logic for yang validation. + +How did you do it? + +I added options filter_event and event_op_file for supporting nightly tests for event + +How did you test/verify it? + +I verify this on the ptf docker container binding to the lab device str-s6000-on-6. The command line I used is as following: +python /gnxi/gnmi_cli_py/py_gnmicli.py -g -t ... -p 50051 -m subscribe -x all -xt EVENTS -o "ndastreamingservertest" --filter_event_regex sonic-events-bgp:bgp-state +--- + gnmi_cli_py/py_gnmicli.py | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py +index 62d4ec8..c46592a 100644 +--- a/gnmi_cli_py/py_gnmicli.py ++++ b/gnmi_cli_py/py_gnmicli.py +@@ -37,6 +37,7 @@ import os + import re + import ssl + import sys ++import string + import six + import datetime + try: +@@ -162,6 +163,7 @@ def _create_parser(): + help='Creates specific number of TCP connections with gNMI server side. ' + 'Default number of TCP connections is 1 and use -1 to create ' + 'infinite TCP connections.') ++ parser.add_argument('--filter_event_regex', help='Regex to filter event when querying events path') + parser.add_argument('--prefix', default='', help='gRPC path prefix (default: none)') + return parser + +@@ -408,6 +410,12 @@ def gen_request(paths, opt, prefix): + yield mysubreq + + ++def check_event_response(response, filter_event_regex): ++ resp = str(response) ++ match = re.findall(filter_event_regex, resp) ++ return match ++ ++ + def subscribe_start(stub, options, req_iterator): + """ RPC Start for Subscribe reqeust + Args: +@@ -419,6 +427,8 @@ def subscribe_start(stub, options, req_iterator): + """ + metadata = [('username', options['username']), ('password', options['password'])] + max_update_count = options["update_count"] ++ filter_event_regex = options["filter_event_regex"] ++ + try: + responses = stub.Subscribe(req_iterator, options['timeout'], metadata=metadata) + update_count = 0 +@@ -430,8 +440,17 @@ def subscribe_start(stub, options, req_iterator): + print('gNMI Error '+str(response.error.code)+\ + ' received\n'+str(response.error.message) + str(response.error)) + elif response.HasField('update'): +- print(response) +- update_count = update_count+1 ++ if filter_event_regex is not None: ++ if filter_event_regex is not "": ++ match = check_event_response(response, filter_event_regex) ++ if len(match) is not 0: ++ print(response) ++ update_count = update_count + 1 ++ else: ++ raise Exception("Filter event regex should not be empty") ++ else: ++ print(response) ++ update_count = update_count+1 + else: + print('Unknown response received:\n'+str(response)) + +-- +2.48.1.windows.1 + diff --git a/dockers/docker-ptf/gnxi-patches/0005-Enhance-gnmi_cli_py-4.patch b/dockers/docker-ptf/gnxi-patches/0005-Enhance-gnmi_cli_py-4.patch new file mode 100644 index 0000000000..f9fc30d96e --- /dev/null +++ b/dockers/docker-ptf/gnxi-patches/0005-Enhance-gnmi_cli_py-4.patch @@ -0,0 +1,323 @@ +From 3adf8b97755b49947e465b5a14645f11e79fa0cd Mon Sep 17 00:00:00 2001 +From: ganglv <88995770+ganglyu@users.noreply.github.com> +Date: Fri, 8 Sep 2023 13:15:29 +0800 +Subject: [PATCH 5/5] Enhance gnmi_cli_py (#4) + +1. Upgrade grpcio and grpcio-tools +2. Support origin in gnmi prefix +3. Print grpc error code +4. Support PROTO encoding for gnmi get +5. Ignore / in [] +6. Support proto_bytes for gnmi set +7. Support multiple path and value for gnmi set, get and subscribe +--- + gnmi_cli_py/py_gnmicli.py | 161 ++++++++++++++++++++++++++--------- + gnmi_cli_py/requirements.txt | 4 +- + 2 files changed, 125 insertions(+), 40 deletions(-) + +diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py +index c46592a..0ea6f3d 100644 +--- a/gnmi_cli_py/py_gnmicli.py ++++ b/gnmi_cli_py/py_gnmicli.py +@@ -111,8 +111,11 @@ def _create_parser(): + 'file (prepend filename with "@")', default='get') + parser.add_argument('-val', '--value', type=str, help='Value for SetRequest.' + '\nCan be Leaf value or JSON file. If JSON file, prepend' +- ' with "@"; eg "@interfaces.json".', +- required=False) ++ ' with "@"; eg "@interfaces.json".' ++ '\n If empty value for delete operation, use "".', ++ nargs="+", required=False) ++ parser.add_argument('--proto', type=str, help='Output files for proto bytes', ++ nargs="*", required=False) + parser.add_argument('-pkey', '--private_key', type=str, help='Fully' + 'quallified path to Private key to use when establishing' + 'a gNMI Channel to the Target', required=False) +@@ -127,10 +130,13 @@ def _create_parser(): + 'Target when establishing secure gRPC channel.', + required=False, action='store_true') + parser.add_argument('-x', '--xpath', type=str, help='The gNMI path utilized' +- 'in the GetRequest or Subscirbe', required=True) ++ 'in the GetRequest or Subscirbe', nargs="+", required=True) + parser.add_argument('-xt', '--xpath_target', type=str, help='The gNMI prefix' + 'target in the GetRequest or Subscirbe', default=None, + required=False) ++ parser.add_argument('-xo', '--xpath_origin', type=str, help='The gNMI prefix' ++ 'origin in the GetRequest, SetRequest or Subscirbe', default=None, ++ required=False) + parser.add_argument('-o', '--host_override', type=str, help='Use this as ' + 'Targets hostname/peername when checking it\'s' + 'certificate CN. You can check the cert with:\nopenssl ' +@@ -181,7 +187,53 @@ def _path_names(xpath): + """ + if not xpath or xpath == '/': # A blank xpath was provided at CLI. + return [] +- return xpath.strip().strip('/').split('/') # Remove leading and trailing '/'. ++ xpath = xpath.strip().strip('/') ++ path = [] ++ xpath = xpath + '/' ++ # insideBrackets is true when at least one '[' has been found and no ++ # ']' has been found. It is false when a closing ']' has been found. ++ insideBrackets = False ++ # begin marks the beginning of a path element, which is separated by ++ # '/' unclosed between '[' and ']'. ++ begin = 0 ++ # end marks the end of a path element, which is separated by '/' ++ # unclosed between '[' and ']'. ++ end = 0 ++ ++ # Split the given string using unescaped '/'. ++ while end < len(xpath): ++ if xpath[end] == '/': ++ if not insideBrackets: ++ # Current '/' is a valid path element ++ # separator. ++ if end > begin: ++ path.append(xpath[begin:end]) ++ end += 1 ++ begin = end ++ else: ++ # Current '/' must be part of a List key value ++ # string. ++ end += 1 ++ elif xpath[end] == '[': ++ if (end == 0 or xpath[end-1] != '\\') and not insideBrackets: ++ # Current '[' is unescacped, and is the ++ # beginning of List key-value pair(s) string. ++ insideBrackets = True ++ end += 1 ++ elif xpath[end] == ']': ++ if (end == 0 or xpath[end-1] != '\\') and insideBrackets: ++ # Current ']' is unescacped, and is the end of ++ # List key-value pair(s) string. ++ insideBrackets = False ++ end += 1 ++ else: ++ end += 1 ++ ++ if insideBrackets: ++ print("missing ] in path string: %s" % xpath) ++ return [] ++ ++ return path + + + def _parse_path(p_names): +@@ -275,6 +327,16 @@ def _get_val(json_value): + raise JsonReadError('Error while loading JSON: %s' % str(e)) + val.json_ietf_val = json.dumps(set_json).encode() + return val ++ elif '$' in json_value: ++ try: ++ proto_bytes = six.moves.builtins.open(json_value.strip('$'), 'rb').read() ++ except (IOError, ValueError) as e: ++ raise ValueError('Error while loading %s: %s' % (json_value.strip('$'), str(e))) ++ val.proto_bytes = proto_bytes ++ return val ++ elif json_value == '': ++ # GNMI client should use delete operation for empty string ++ return None + coerced_val = _format_type(json_value) + type_to_value = {bool: 'bool_val', int: 'int_val', float: 'float_val', + str: 'string_val'} +@@ -283,16 +345,16 @@ def _get_val(json_value): + return val + + +-def _get(stub, paths, username, password, prefix): ++def _get(stub, paths, username, password, prefix, encoding): + """Create a gNMI GetRequest. + + Args: + stub: (class) gNMI Stub used to build the secure channel. +- paths: gNMI Path ++ paths: (list) gNMI Path + username: (str) Username used when building the channel. + password: (str) Password used when building the channel. + prefix: gNMI Path +- ++ encoding: (int) Encoding + Returns: + a gnmi_pb2.GetResponse object representing a gNMI GetResponse. + """ +@@ -300,35 +362,36 @@ def _get(stub, paths, username, password, prefix): + if username: # User/pass supplied for Authentication. + kwargs = {'metadata': [('username', username), ('password', password)]} + return stub.Get( +- gnmi_pb2.GetRequest(prefix=prefix, path=[paths], encoding='JSON_IETF'), ++ gnmi_pb2.GetRequest(prefix=prefix, path=paths, encoding=encoding), + **kwargs) + +-def _set(stub, paths, set_type, username, password, json_value): ++def _set(stub, prefix, paths, set_type, username, password, value_list): + """Create a gNMI SetRequest. + + Args: + stub: (class) gNMI Stub used to build the secure channel. +- paths: gNMI Path ++ paths: (list) gNMI Path + set_type: (str) Type of gNMI SetRequest. + username: (str) Username used when building the channel. + password: (str) Password used when building the channel. +- json_value: (str) JSON_IETF or file. ++ value_list: (list) JSON_IETF or file. + + Returns: + a gnmi_pb2.SetResponse object representing a gNMI SetResponse. + """ +- if json_value: # Specifying ONLY a path is possible (eg delete). +- val = _get_val(json_value) +- path_val = gnmi_pb2.Update(path=paths, val=val,) +- ++ delete_list = [] ++ update_list = [] ++ for path, value in zip(paths, value_list): ++ val = _get_val(value) ++ if val is None: ++ delete_list.append(path) ++ else: ++ path_val = gnmi_pb2.Update(path=path, val=val,) ++ update_list.append(path_val) + kwargs = {} + if username: + kwargs = {'metadata': [('username', username), ('password', password)]} +- if set_type == 'delete': +- return stub.Set(gnmi_pb2.SetRequest(delete=[paths]), **kwargs) +- elif set_type == 'update': +- return stub.Set(gnmi_pb2.SetRequest(update=[path_val]), **kwargs) +- return stub.Set(gnmi_pb2.SetRequest(replace=[path_val]), **kwargs) ++ return stub.Set(gnmi_pb2.SetRequest(prefix=prefix, delete=delete_list, update=update_list), **kwargs) + + + def _build_creds(target, port, get_cert, certs, notls): +@@ -378,17 +441,18 @@ def _open_certs(**kwargs): + def gen_request(paths, opt, prefix): + """Create subscribe request for passed xpath. + Args: +- paths: (str) gNMI path. ++ paths: (list) gNMI path. + opt: (dict) Command line argument passed for subscribe reqeust. + Returns: + gNMI SubscribeRequest object. + """ + mysubs = [] +- mysub = gnmi_pb2.Subscription(path=paths, mode=opt["submode"], +- sample_interval=opt["interval"]*1000000, +- heartbeat_interval=opt['heartbeat']*1000000, +- suppress_redundant=opt['suppress']) +- mysubs.append(mysub) ++ for path in paths: ++ mysub = gnmi_pb2.Subscription(path=path, mode=opt["submode"], ++ sample_interval=opt["interval"]*1000000, ++ heartbeat_interval=opt['heartbeat']*1000000, ++ suppress_redundant=opt['suppress']) ++ mysubs.append(mysub) + + if prefix: + myprefix = prefix +@@ -482,16 +546,22 @@ def main(): + get_cert = args['get_cert'] + root_cert = args['root_cert'] + cert_chain = args['cert_chain'] +- json_value = args['value'] ++ value_list = args['value'] + private_key = args['private_key'] +- xpath = args['xpath'] +- prefix = gnmi_pb2.Path(target=args['xpath_target']) ++ xpath_list = args['xpath'] ++ proto_list = args['proto'] ++ # In the case that a prefix is specified, it MUST specify any required origin ++ prefix = gnmi_pb2.Path(origin=args['xpath_origin'], target=args['xpath_target']) + host_override = args['host_override'] + user = args['username'] + password = args['password'] + form = args['format'] + create_connections = args['create_connections'] +- paths = _parse_path(_path_names(xpath)) ++ encoding = args['encoding'] ++ paths = [] ++ if xpath_list: ++ for xpath in xpath_list: ++ paths.append(_parse_path(_path_names(xpath))) + kwargs = {'root_cert': root_cert, 'cert_chain': cert_chain, + 'private_key': private_key} + certs = _open_certs(**kwargs) +@@ -517,13 +587,25 @@ def main(): + if mode == 'get': + print('Performing GetRequest, encoding=JSON_IETF', 'to', target, + ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _get(stub, paths, user, password, prefix) ++ response = _get(stub, paths, user, password, prefix, encoding) + print('The GetResponse is below\n' + '-'*25 + '\n') +- if form == 'protobuff': ++ if encoding == 2: ++ i = 0 ++ for notification in response.notification: ++ for update in notification.update: ++ if i >= len(proto_list): ++ print("Not enough files: %s" % str(proto_list)) ++ sys.exit(1) ++ with open(proto_list[i], 'wb') as fp: ++ fp.write(update.val.proto_bytes) ++ i += 1 ++ elif form == 'protobuff': + print(response) + elif response.notification[0].update[0].val.json_ietf_val: +- print(json.dumps(json.loads(response.notification[0].update[0].val. +- json_ietf_val), indent=2)) ++ for notification in response.notification: ++ for update in notification.update: ++ print(json.dumps(json.loads(update.val.json_ietf_val), indent=2)) ++ print('-'*25 + '\n') + elif response.notification[0].update[0].val.string_val: + print(response.notification[0].update[0].val.string_val) + else: +@@ -531,18 +613,18 @@ def main(): + print(response) + elif mode == 'set-update': + print('Performing SetRequest Update, encoding=JSON_IETF', ' to ', target, +- ' with the following gNMI Path\n', '-'*25, '\n', paths, json_value) +- response = _set(stub, paths, 'update', user, password, json_value) ++ ' with the following gNMI Path\n', '-'*25, '\n', paths, value_list) ++ response = _set(stub, prefix, paths, 'update', user, password, value_list) + print('The SetRequest response is below\n' + '-'*25 + '\n', response) + elif mode == 'set-replace': + print('Performing SetRequest Replace, encoding=JSON_IETF', ' to ', target, + ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _set(stub, paths, 'replace', user, password, json_value) ++ response = _set(stub, prefix, paths, 'replace', user, password, value_list) + print('The SetRequest response is below\n' + '-'*25 + '\n', response) + elif mode == 'set-delete': + print('Performing SetRequest Delete, encoding=JSON_IETF', ' to ', target, + ' with the following gNMI Path\n', '-'*25, '\n', paths) +- response = _set(stub, paths, 'delete', user, password, json_value) ++ response = _set(stub, prefix, paths, 'delete', user, password, value_list) + print('The SetRequest response is below\n' + '-'*25 + '\n', response) + elif mode == 'subscribe': + request_iterator = gen_request(paths, args, prefix) +@@ -552,6 +634,9 @@ def main(): + print("Client receives an exception '{}' indicating gNMI server is shut down and Exiting ..." + .format(err.details())) + sys.exit(GNMI_SERVER_UNAVAILABLE) ++ else: ++ print("GRPC error\n {}".format(err.details())) ++ sys.exit(1) + + + if __name__ == '__main__': +diff --git a/gnmi_cli_py/requirements.txt b/gnmi_cli_py/requirements.txt +index dab2db6..e32b3ff 100644 +--- a/gnmi_cli_py/requirements.txt ++++ b/gnmi_cli_py/requirements.txt +@@ -1,6 +1,6 @@ + enum34==1.1.6 + futures==3.2.0 +-grpcio==1.18.0 +-grpcio-tools==1.15.0 ++grpcio==1.41.1 ++grpcio-tools==1.41.1 + protobuf==3.6.1 --no-binary=protobuf + six==1.12.0 +-- +2.48.1.windows.1 + diff --git a/dockers/docker-ptf/gnxi-patches/series b/dockers/docker-ptf/gnxi-patches/series new file mode 100644 index 0000000000..d3c400ab92 --- /dev/null +++ b/dockers/docker-ptf/gnxi-patches/series @@ -0,0 +1,5 @@ +0001-add-xpath_target-option.patch +0002-Adding-support-for-subscribe-mode-1.patch +0003-gNMI_client-Add-an-option-to-trigger-memory-spike-on.patch +0004-Add-support-for-streaming-structured-events-in-night.patch +0005-Enhance-gnmi_cli_py-4.patch \ No newline at end of file diff --git a/platform/checkout/cisco-8000.ini b/platform/checkout/cisco-8000.ini index ff34aeded4..ee06785941 100644 --- a/platform/checkout/cisco-8000.ini +++ b/platform/checkout/cisco-8000.ini @@ -1,3 +1,3 @@ [module] repo=git@github.com:Cisco-8000-sonic/platform-cisco-8000.git -ref=202411.1.0.4 +ref=202411.1.0.6 diff --git a/src/libnl3/patch/series b/src/libnl3/patch/series index 92317908c4..93799c6d16 100644 --- a/src/libnl3/patch/series +++ b/src/libnl3/patch/series @@ -2,3 +2,4 @@ switch-to-debhelper.patch keep-symbol-versions-in-libraries.patch update-changelog.patch +skip-tests-when-having-no-private-netns.patch diff --git a/src/libnl3/patch/skip-tests-when-having-no-private-netns.patch b/src/libnl3/patch/skip-tests-when-having-no-private-netns.patch new file mode 100644 index 0000000000..671a03486b --- /dev/null +++ b/src/libnl3/patch/skip-tests-when-having-no-private-netns.patch @@ -0,0 +1,163 @@ +From b3822aa3b605b2dc5f01f9aee8ee224fc23e23a0 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Sun, 12 Jan 2025 10:54:59 +0100 +Subject: [PATCH] test: skip tests when having no private netns + +In github CI we seem now unable to create the netns. This worked +previously, now it no longer does. + +Handle that by skipping the tests that require a netns. +--- + tests/cksuite-all-netns.c | 13 +++++++++- + tests/nl-test-util.c | 50 +++++++++++++++++++++++++++++++++++++-- + tests/nl-test-util.h | 3 +++ + 3 files changed, 63 insertions(+), 3 deletions(-) + +diff --git a/tests/cksuite-all-netns.c b/tests/cksuite-all-netns.c +index 1948c3e8..04e0f6df 100644 +--- a/tests/cksuite-all-netns.c ++++ b/tests/cksuite-all-netns.c +@@ -73,6 +73,9 @@ START_TEST(cache_and_clone) + int i; + int r; + ++ if (_nltst_skip_no_netns()) ++ return; ++ + for (i = 0; i < _NL_N_ELEMENTS(links); i++) { + if (links[i].add) + _nltst_add_link(NULL, links[i].ifname, links[i].kind, +@@ -132,11 +135,16 @@ START_TEST(test_create_iface) + _nl_auto_rtnl_link struct rtnl_link *link2 = NULL; + _nl_auto_rtnl_link struct rtnl_link *peer = NULL; + _nltst_auto_delete_link const char *IFNAME_DUMMY = NULL; +- _nltst_auto_delete_link const char *IFNAME = "ifname"; ++ _nltst_auto_delete_link const char *IFNAME = NULL; + int ifindex_dummy; + uint32_t u32; + int r; + ++ if (_nltst_skip_no_netns()) ++ return; ++ ++ IFNAME = "ifname"; ++ + switch (TEST_IDX) { + case 0: + link = _nltst_assert(rtnl_link_bridge_alloc()); +diff --git a/tests/nl-test-util.c b/tests/nl-test-util.c +index dc8dc5ad..d1a8f3f1 100644 +--- a/tests/nl-test-util.c ++++ b/tests/nl-test-util.c +@@ -84,6 +84,7 @@ uint32_t _nltst_rand_u32(void) + + struct nltst_netns { + int canary; ++ bool is_unshared; + }; + + /*****************************************************************************/ +@@ -114,6 +115,23 @@ void nltst_netns_fixture_teardown(void) + _nl_clear_pointer(&_netns_fixture_global.nsdata, nltst_netns_leave); + } + ++bool nltst_netns_fixture_is_unshared(void) ++{ ++ _assert_nltst_netns(_netns_fixture_global.nsdata); ++ return _netns_fixture_global.nsdata->is_unshared; ++} ++ ++/*****************************************************************************/ ++ ++bool _nltst_skip_no_netns(void) ++{ ++ if (nltst_netns_fixture_is_unshared()) ++ return false; ++ ++ printf("skip test due to having no private netns\n"); ++ return true; ++} ++ + /*****************************************************************************/ + + static void unshare_user(void) +@@ -125,6 +143,10 @@ static void unshare_user(void) + + /* Become a root in new user NS. */ + r = unshare(CLONE_NEWUSER); ++ if (r != 0 && errno == EPERM) { ++ /* No permissions? Ignore. Will be handled later. */ ++ return; ++ } + _nltst_assert_errno(r == 0); + + /* Since Linux 3.19 we have to disable setgroups() in order to map users. +@@ -149,14 +171,28 @@ static void unshare_user(void) + } + r = fprintf(f, "0 %d 1", uid); + _nltst_assert_errno(r > 0); +- _nltst_fclose(f); ++ r = fclose(f); ++ if (r != 0 && errno == EPERM) { ++ /* Oddly, it seems close() can fail at this point. Ignore it, ++ * but we probably will be unable to unshare (which we handle ++ * later). ++ */ ++ } else ++ _nltst_assert_errno(r == 0); + + /* Map current GID to root in NS to be created. */ + f = fopen("/proc/self/gid_map", "we"); + _nltst_assert_errno(f); + r = fprintf(f, "0 %d 1", gid); + _nltst_assert_errno(r > 0); +- _nltst_fclose(f); ++ r = fclose(f); ++ if (r != 0 && errno == EPERM) { ++ /* Oddly, it seems close() can fail at this point. Ignore it, but ++ * we probably will be unable to unshare (which we handle ++ * later). ++ */ ++ } else ++ _nltst_assert_errno(r == 0); + } + + struct nltst_netns *nltst_netns_enter(void) +@@ -172,6 +208,15 @@ struct nltst_netns *nltst_netns_enter(void) + unshare_user(); + + r = unshare(CLONE_NEWNET | CLONE_NEWNS); ++ if (r != 0 && errno == EPERM) { ++ /* The system is probably sandboxed somehow and we are unable ++ * to create a private netns. That seems questionable, because ++ * a point of a private netns is to sandbox an application. ++ * Not having permissions to sandbox sounds bad. ++ * ++ * Anyway. We accept this and will later skip some tests. */ ++ return nsdata; ++ } + _nltst_assert_errno(r == 0); + + /* We need a read-only /sys so that the platform knows there's no udev. */ +@@ -179,6 +224,7 @@ struct nltst_netns *nltst_netns_enter(void) + r = mount("sys", "/sys", "sysfs", MS_RDONLY, NULL); + _nltst_assert_errno(r == 0); + ++ nsdata->is_unshared = true; + return nsdata; + } + +diff --git a/tests/nl-test-util.h b/tests/nl-test-util.h +index 981228b4..d840a4ab 100644 +--- a/tests/nl-test-util.h ++++ b/tests/nl-test-util.h +@@ -429,6 +429,9 @@ char **_nltst_strtokv(const char *str); + + void nltst_netns_fixture_setup(void); + void nltst_netns_fixture_teardown(void); ++bool nltst_netns_fixture_is_unshared(void); ++ ++bool _nltst_skip_no_netns(void); + + struct nltst_netns; + diff --git a/src/sonic-bgpcfgd/tests/data/internal/policies.conf/result_chasiss_packet.conf b/src/sonic-bgpcfgd/tests/data/internal/policies.conf/result_chasiss_packet.conf index 5569f3a5d3..d67849a86f 100644 --- a/src/sonic-bgpcfgd/tests/data/internal/policies.conf/result_chasiss_packet.conf +++ b/src/sonic-bgpcfgd/tests/data/internal/policies.conf/result_chasiss_packet.conf @@ -15,8 +15,9 @@ route-map FROM_BGP_INTERNAL_PEER_V4 permit 2 set local-preference 80 on-match next ! -route-map FROM_BGP_INTERNAL_PEER_V4 deny 3 +route-map FROM_BGP_INTERNAL_PEER_V4 permit 3 match community DEVICE_INTERNAL_FALLBACK_COMMUNITY + set comm-list DEVICE_INTERNAL_FALLBACK_COMMUNITY delete ! route-map FROM_BGP_INTERNAL_PEER_V6 permit 1 set ipv6 next-hop prefer-global @@ -32,8 +33,9 @@ route-map FROM_BGP_INTERNAL_PEER_V6 permit 3 set local-preference 80 on-match next ! -route-map FROM_BGP_INTERNAL_PEER_V6 deny 4 +route-map FROM_BGP_INTERNAL_PEER_V6 permit 4 match community DEVICE_INTERNAL_FALLBACK_COMMUNITY + set comm-list DEVICE_INTERNAL_FALLBACK_COMMUNITY delete ! route-map TO_BGP_INTERNAL_PEER_V4 permit 1 match ip address prefix-list PL_LoopbackV4 diff --git a/src/sonic-config-engine/tests/sample_output/py2/bgpd_frr_bmp.conf b/src/sonic-config-engine/tests/sample_output/py2/bgpd_frr_bmp.conf index c7d9c560aa..85c26e0eed 100644 --- a/src/sonic-config-engine/tests/sample_output/py2/bgpd_frr_bmp.conf +++ b/src/sonic-config-engine/tests/sample_output/py2/bgpd_frr_bmp.conf @@ -56,7 +56,7 @@ router bgp 65100 bmp stats interval 1000 bmp monitor ipv4 unicast pre-policy bmp monitor ipv6 unicast pre-policy - bmp connect 127.0.0.1 port 5000 min-retry 1000 max-retry 2000 + bmp connect 127.0.0.1 port 5000 min-retry 10000 max-retry 15000 ! ! bgp router-id 10.1.0.32 diff --git a/src/sonic-config-engine/tests/sample_output/py3/bgpd_frr_bmp.conf b/src/sonic-config-engine/tests/sample_output/py3/bgpd_frr_bmp.conf index c7d9c560aa..85c26e0eed 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/bgpd_frr_bmp.conf +++ b/src/sonic-config-engine/tests/sample_output/py3/bgpd_frr_bmp.conf @@ -56,7 +56,7 @@ router bgp 65100 bmp stats interval 1000 bmp monitor ipv4 unicast pre-policy bmp monitor ipv6 unicast pre-policy - bmp connect 127.0.0.1 port 5000 min-retry 1000 max-retry 2000 + bmp connect 127.0.0.1 port 5000 min-retry 10000 max-retry 15000 ! ! bgp router-id 10.1.0.32 diff --git a/src/sonic-config-engine/tests/test_frr.py b/src/sonic-config-engine/tests/test_frr.py index 5a7ca109b3..c8453c91a2 100644 --- a/src/sonic-config-engine/tests/test_frr.py +++ b/src/sonic-config-engine/tests/test_frr.py @@ -80,5 +80,5 @@ def test_zebra_frr_dualtor(self): self.assertTrue(*self.run_case('zebra/zebra.conf.j2', 'zebra_frr_dualtor.conf', extra_data=extra_data)) def test_bgpd_frr_bmp(self): - extra_data = {"FEATURE": {"bmp": {"state": "enabled"}}} + extra_data = {"FEATURE": {"frr_bmp": {"state": "enabled"}}} self.assertTrue(*self.run_case('bgpd/bgpd.conf.j2', 'bgpd_frr_bmp.conf', extra_data=extra_data)) \ No newline at end of file diff --git a/src/sonic-frr/patch/0063-lib-Return-duplicate-prefix-list-entry-test.patch b/src/sonic-frr/patch/0063-lib-Return-duplicate-prefix-list-entry-test.patch new file mode 100644 index 0000000000..59e3b6e4ca --- /dev/null +++ b/src/sonic-frr/patch/0063-lib-Return-duplicate-prefix-list-entry-test.patch @@ -0,0 +1,61 @@ +From 8384d41144496019725c1e250abd0ceea854341f Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Tue, 25 Mar 2025 13:54:24 +0200 +Subject: [PATCH] lib: Return duplicate prefix-list entry test If we do e.g.: + +ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32 +ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32 +ip prefix-list PL_LoopbackV4 permit 10.1.0.32/32 + +We end up, having duplicate records with a different sequence number only. +Also ported the same changes for ipv6 also. +--- + lib/filter_cli.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/lib/filter_cli.c b/lib/filter_cli.c +index c40c2a75f..2012fa987 100644 +--- a/lib/filter_cli.c ++++ b/lib/filter_cli.c +@@ -1206,10 +1206,14 @@ DEFPY_YANG( + snprintf(xpath, sizeof(xpath), + "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name); + if (seq_str == NULL) { +- /* Use XPath to find the next sequence number. */ +- sseq = acl_get_seq(vty, xpath, false); +- if (sseq < 0) +- return CMD_WARNING_CONFIG_FAILED; ++ if (plist_is_dup(vty->candidate_config->dnode, &pda)) ++ sseq = pda.pda_seq; ++ else { ++ /* Use XPath to find the next sequence number. */ ++ sseq = acl_get_seq(vty, xpath, false); ++ if (sseq < 0) ++ return CMD_WARNING_CONFIG_FAILED; ++ } + + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); +@@ -1396,11 +1400,14 @@ DEFPY_YANG( + snprintf(xpath, sizeof(xpath), + "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name); + if (seq_str == NULL) { +- /* Use XPath to find the next sequence number. */ +- sseq = acl_get_seq(vty, xpath, false); +- if (sseq < 0) +- return CMD_WARNING_CONFIG_FAILED; +- ++ if (plist_is_dup(vty->candidate_config->dnode, &pda)) ++ sseq = pda.pda_seq; ++ else { ++ /* Use XPath to find the next sequence number. */ ++ sseq = acl_get_seq(vty, xpath, false); ++ if (sseq < 0) ++ return CMD_WARNING_CONFIG_FAILED; ++ } + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + } else +-- +2.39.4 + diff --git a/src/sonic-frr/patch/0064-mgmtd-clean-session-config-only-when-it-is-needed.patch b/src/sonic-frr/patch/0064-mgmtd-clean-session-config-only-when-it-is-needed.patch new file mode 100644 index 0000000000..517d72e4ca --- /dev/null +++ b/src/sonic-frr/patch/0064-mgmtd-clean-session-config-only-when-it-is-needed.patch @@ -0,0 +1,167 @@ +From 210a082dea671accfc10a8dcce1431329f0153ae Mon Sep 17 00:00:00 2001 +From: Ying Xie +Date: Sat, 29 Mar 2025 15:30:37 +0000 +Subject: [PATCH 63/63] [mgmtd] clean session config only when it is needed + +mgmtd configuration management has an issue where any session +can clean up outstanding configuration upon destruction. + +When a long-lived session is taking configuration changes, and +another short-lived session which never took any configuration +closes, the outstanding configuration would be lost because +the configuration clearing doesn't have protection during session +closing. + +This change keeps track if a session has received any configuration, +and if the configuration has been applied or cleared. + +The outstanding configuration should be applied or cleared before +session closure (assertion). + +When clearing the outstanding session structure, only attempt to +clear configuration when the closing session has outstanding +configurations. + +Signed-off-by: Ying Xie +--- + mgmtd/mgmt_fe_adapter.c | 57 +++++++++++++++++++++++++++++------------ + 1 file changed, 41 insertions(+), 16 deletions(-) + +diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c +index ec8e77335..27171dfa2 100644 +--- a/mgmtd/mgmt_fe_adapter.c ++++ b/mgmtd/mgmt_fe_adapter.c +@@ -45,6 +45,8 @@ struct mgmt_fe_session_ctx { + uint8_t ds_locked[MGMTD_DS_MAX_ID]; + struct event *proc_cfg_txn_clnp; + struct event *proc_show_txn_clnp; ++ uint32_t config_count; ++ uint32_t committed_count; + + struct mgmt_fe_sessions_item list_linkage; + }; +@@ -118,7 +120,10 @@ mgmt_fe_session_cfg_txn_cleanup(struct mgmt_fe_session_ctx *session) + * Ensure any uncommitted changes in Candidate DS + * is discarded. + */ +- mgmt_ds_copy_dss(mm->running_ds, mm->candidate_ds, false); ++ if (session->config_count > 0) { ++ mgmt_ds_copy_dss(mm->running_ds, mm->candidate_ds, false); ++ session->config_count = 0; ++ } + + /* + * Destroy the actual transaction created earlier. +@@ -278,6 +283,8 @@ mgmt_fe_create_session(struct mgmt_fe_client_adapter *adapter, + session->adapter = adapter; + session->txn_id = MGMTD_TXN_ID_NONE; + session->cfg_txn_id = MGMTD_TXN_ID_NONE; ++ session->config_count = 0; ++ session->committed_count = 0; + mgmt_fe_adapter_lock(adapter); + mgmt_fe_sessions_add_tail(&adapter->fe_sessions, session); + if (!mgmt_fe_next_session_id) +@@ -373,9 +380,11 @@ static int fe_adapter_send_set_cfg_reply(struct mgmt_fe_session_ctx *session, + + assert(session->adapter); + +- if (implicit_commit && session->cfg_txn_id) ++ if (implicit_commit && session->cfg_txn_id) { ++ session->committed_count += session->config_count; + mgmt_fe_session_register_event( + session, MGMTD_FE_SESSION_CFG_TXN_CLNUP); ++ } + + mgmtd__fe_set_config_reply__init(&setcfg_reply); + setcfg_reply.session_id = session->session_id; +@@ -443,9 +452,11 @@ static int fe_adapter_send_commit_cfg_reply( + */ + if (session->cfg_txn_id + && ((result == MGMTD_SUCCESS && !validate_only) +- || (result == MGMTD_NO_CFG_CHANGES))) ++ || (result == MGMTD_NO_CFG_CHANGES))) { ++ session->committed_count += session->config_count; + mgmt_fe_session_register_event( + session, MGMTD_FE_SESSION_CFG_TXN_CLNUP); ++ } + + if (mm->perf_stats_en) + gettimeofday(&session->adapter->cmt_stats.last_end, NULL); +@@ -919,6 +930,7 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, + Mgmtd__FeMessage *fe_msg) + { + struct mgmt_fe_session_ctx *session; ++ static int session_cnt = 0; + + /* + * protobuf-c adds a max size enum with an internal, and changing by +@@ -941,27 +953,37 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, + && fe_msg->session_req->id_case + == MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID) { + __dbg("Got SESSION_REQ (create) for client-id %" PRIu64 +- " from '%s'", +- fe_msg->session_req->client_conn_id, +- adapter->name); ++ " from '%s' session_cnt %d", ++ fe_msg->session_req->client_conn_id, ++ adapter->name, session_cnt); + + session = mgmt_fe_create_session( + adapter, fe_msg->session_req->client_conn_id); ++ if (session) { ++ session_cnt++; ++ } + fe_adapter_send_session_reply(adapter, session, true, + session ? true : false); + } else if ( + !fe_msg->session_req->create + && fe_msg->session_req->id_case + == MGMTD__FE_SESSION_REQ__ID_SESSION_ID) { +- __dbg("Got SESSION_REQ (destroy) for session-id %" PRIu64 +- "from '%s'", +- fe_msg->session_req->session_id, adapter->name); +- + session = mgmt_session_id2ctx( + fe_msg->session_req->session_id); +- fe_adapter_send_session_reply(adapter, session, false, +- true); +- mgmt_fe_cleanup_session(&session); ++ ++ __dbg("Got SESSION_REQ (destroy) for session-id %" PRIu64 ++ " from '%s' session_cnt %d session %p config_count %u committed_count %u", ++ fe_msg->session_req->session_id, adapter->name, ++ session_cnt, session, session ? session->config_count : -1, ++ session ? session->committed_count : -1); ++ ++ if (session) { ++ assert(session->config_count == 0); ++ fe_adapter_send_session_reply(adapter, session, false, ++ true); ++ mgmt_fe_cleanup_session(&session); ++ session_cnt--; ++ } + } + break; + case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ: +@@ -979,12 +1001,15 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, + session = mgmt_session_id2ctx( + fe_msg->setcfg_req->session_id); + session->adapter->setcfg_stats.set_cfg_count++; ++ session->config_count++; + __dbg("Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64 +- " from '%s'", +- (int)fe_msg->setcfg_req->n_data, ++ " from '%s' session %p config_count %u committed_count %u", ++ (int)fe_msg->setcfg_req->n_data, + fe_msg->setcfg_req->implicit_commit ? 'T' : 'F', + mgmt_ds_id2name(fe_msg->setcfg_req->ds_id), +- fe_msg->setcfg_req->session_id, adapter->name); ++ fe_msg->setcfg_req->session_id, adapter->name, ++ session, session->config_count, ++ session->committed_count); + + mgmt_fe_session_handle_setcfg_req_msg( + session, fe_msg->setcfg_req); +-- +2.25.1 + diff --git a/src/sonic-gnmi b/src/sonic-gnmi index 369059641e..18657b9aba 160000 --- a/src/sonic-gnmi +++ b/src/sonic-gnmi @@ -1 +1 @@ -Subproject commit 369059641e7af8cab156177731cf3cd1d7f35cdd +Subproject commit 18657b9aba3c0c08564a062883e88a606a12594b