From b4cf3c54dcbc0d8208c537429d9118e334a247a5 Mon Sep 17 00:00:00 2001 From: jimmy Date: Fri, 14 Feb 2025 17:13:19 -0800 Subject: [PATCH 1/2] Support OTN change to github path for submodules Modify config to disable some features not used on ot platform Fix EOL mirror issues for Buster and Bullseye by updating MIRROR_URLS The Bullseye release is now end-of-life, and the `bullseye-backports` entry is no longer available on the standard Debian mirrors, causing Docker image builds to fail. Due to the way `files/apt/sources.list.j2` is templated, the backports URL is generated using the shared `MIRROR_URLS` variable, which also affects the main and updates entries. Rather than restructuring the template to special- case `bullseye-backports`, this commit updates `DEFAULT_MIRROR_URLS` entirely for Bullseye to point to archive-capable mirrors that support all required repositories. In the case of Buster, `DEFAULT_MIRROR_SECURITY_URLS` was also updated to resolve similar build failures. - For Bullseye: uses `archive.debian.org` for main, updates, and backports, and `debian-archive.trafficmanager.net` specifically for security. - For Buster: uses `archive.debian.org` for main, updates backports and security. This approach keeps the templating logic simple and ensures stable builds for EOL releases using fully supported mirror endpoints. Fixes #23430 and #23336 Signed-off-by: Alberto Martin Support otn-kvm platform for OTN devices Signed-off-by: oplklum merge event and alarm management related to official #22617 extend event function for platform event function changed libsai version to 1.1.0 use hal server version 1.1.0 supervisord does not spawn hal and HalApiServer anymore Fix submodule pointer for sonic-platform-daemons Update submodule sonic-swss-common to 202411_otn Update submodule sonic-sairedis to 202411_otn Update submodule sonic-swss 202411_otn Update submodule sonic-utilities 202411_otn --- .../x86_64-otn-kvm_x86_64-r0/OLS-V/hwsku.json | 4 + .../OLS-V/otn_config.json | 317 +++++++++ .../OLS-V/port_config.ini | 2 + .../OLS-V/sai.profile | 1 + .../x86_64-otn-kvm_x86_64-r0/default_sku | 1 + .../x86_64-otn-kvm_x86_64-r0/installer.conf | 1 + .../linecard_extra_map.json | 4 + .../otn_attenuator_pluggin.lua | 98 +++ .../otn_metadata.json | 8 + .../otn_oa_pluggin.lua | 147 ++++ .../otn_ocm_pluggin.lua | 73 ++ .../otn_osc_pluggin.lua | 86 +++ .../x86_64-otn-kvm_x86_64-r0/platform.json | 172 +++++ .../x86_64-otn-kvm_x86_64-r0/platform_asic | 1 + .../pmon_daemon_control.json | 7 + .../docker-database/database_config.json.j2 | 6 + dockers/docker-eventd/Dockerfile.j2 | 1 + dockers/docker-eventd/eventdb_wrapper.sh | 18 + dockers/docker-eventd/supervisord.conf | 12 + .../docker-orchagent/critical_processes.j2 | 7 + dockers/docker-orchagent/supervisord.conf.j2 | 19 + .../docker-pmon.supervisord.conf.j2 | 17 + files/build_templates/docker_image_ctl.j2 | 19 +- .../build_templates/sonic_debian_extension.j2 | 7 + files/image_config/otn/otn-config.service | 15 + files/image_config/otn/otn-config.sh | 6 + platform/otn-kvm/README.md | 250 +++++++ platform/otn-kvm/docker-syncd-otn-kvm.dep | 11 + platform/otn-kvm/docker-syncd-otn-kvm.mk | 21 + .../docker-syncd-otn-kvm/Dockerfile.j2 | 52 ++ .../docker-syncd-otn-kvm/critical_processes | 1 + .../docker-syncd-otn-kvm/event/cpu_regex.json | 12 + .../docker-syncd-otn-kvm/event/default.json | 36 + .../event/eventdb_wrapper.sh | 18 + .../docker-syncd-otn-kvm/event/fan_regex.json | 12 + .../event/platform_events_info.json | 13 + .../otn-kvm/docker-syncd-otn-kvm/start.sh | 14 + .../docker-syncd-otn-kvm/supervisord.conf | 63 ++ platform/otn-kvm/hal-client.dep | 2 + platform/otn-kvm/hal-client.mk | 8 + platform/otn-kvm/hal-server.dep | 2 + platform/otn-kvm/hal-server.mk | 8 + platform/otn-kvm/kvm-image.dep | 2 + platform/otn-kvm/kvm-image.mk | 15 + platform/otn-kvm/one-image.dep | 2 + platform/otn-kvm/one-image.mk | 17 + platform/otn-kvm/onie.dep | 2 + platform/otn-kvm/onie.mk | 4 + platform/otn-kvm/platform-modules-otn-kvm.dep | 8 + platform/otn-kvm/platform-modules-otn-kvm.mk | 11 + platform/otn-kvm/platform.conf | 0 platform/otn-kvm/raw-image.dep | 2 + platform/otn-kvm/raw-image.mk | 9 + platform/otn-kvm/rules.dep | 13 + platform/otn-kvm/rules.mk | 19 + platform/otn-kvm/sai.dep | 2 + platform/otn-kvm/sai.mk | 5 + .../sonic-platform-modules-otn-kvm/LICENSE | 339 +++++++++ .../sonic-platform-modules-otn-kvm/README.md | 4 + .../debian/changelog | 4 + .../debian/compat | 1 + .../debian/control | 10 + .../debian/rules | 37 + .../sonic-platform-otn-kvm-ols-v.install | 1 + .../ols-v/setup.py | 29 + .../ols-v/sonic_platform/__init__.py | 2 + .../ols-v/sonic_platform/chassis.py | 342 +++++++++ .../ols-v/sonic_platform/component.py | 136 ++++ .../ols-v/sonic_platform/fan.py | 170 +++++ .../ols-v/sonic_platform/fan_drawer.py | 73 ++ .../ols-v/sonic_platform/module.py | 146 ++++ .../ols-v/sonic_platform/platform.py | 25 + .../ols-v/sonic_platform/psu.py | 257 +++++++ .../ols-v/sonic_platform/sfp.py | 365 ++++++++++ .../ols-v/sonic_platform/thermal.py | 173 +++++ .../ols-v/sonic_platform/watchdog.py | 71 ++ platform/otn-kvm/sonic-version.dep | 2 + platform/otn-kvm/sonic-version.mk | 13 + platform/otn-kvm/sonic-version/Makefile | 10 + .../sonic-version/build_sonic_version.sh | 8 + .../sonic-version/sonic_version.yml.j2 | 1 + platform/otn-kvm/thrift.dep | 2 + platform/otn-kvm/thrift.mk | 15 + rules/config | 22 +- rules/docker-platform-monitor.mk | 1 + rules/sonic-linecardsyncd.dep | 10 + rules/sonic-linecardsyncd.mk | 8 + scripts/build_mirror_config.sh | 7 +- src/sonic-eventd/Makefile | 28 +- src/sonic-eventd/debian/sonic-eventd.install | 3 + src/sonic-eventd/etc/eventd.json | 5 + src/sonic-eventd/src/eventconsume.cpp | 669 ++++++++++++++++++ src/sonic-eventd/src/eventconsume.h | 56 ++ src/sonic-eventd/src/eventdb.cpp | 29 + src/sonic-eventd/src/eventutils.cpp | 103 +++ src/sonic-eventd/src/eventutils.h | 42 ++ src/sonic-eventd/src/loghandler.cpp | 49 ++ src/sonic-eventd/src/loghandler.h | 8 + src/sonic-eventd/src/subdir.mk | 5 +- src/sonic-eventd/tests/default.json | 24 + src/sonic-eventd/tests/eventd.json | 6 + .../tests/eventdb_database_config.json | 108 +++ .../tests/eventdb_database_config_global.json | 9 + src/sonic-eventd/tests/eventdb_ut.cpp | 435 ++++++++++++ src/sonic-eventd/tests/subdir.mk | 4 +- src/sonic-eventd/var/evprofile/default.json | 12 + src/sonic-mgmt-common | 2 +- src/sonic-mgmt-framework | 2 +- src/sonic-platform-daemons | 2 +- src/sonic-sairedis | 2 +- src/sonic-swss | 2 +- src/sonic-swss-common | 2 +- src/sonic-utilities | 2 +- .../yang-models/sonic-alarm.yang | 144 ++++ .../yang-models/sonic-device_metadata.yang | 4 +- .../yang-models/sonic-event.yang | 136 ++++ .../yang-models/sonic-events-common.yang | 42 ++ 117 files changed, 5873 insertions(+), 29 deletions(-) create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/hwsku.json create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/otn_config.json create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/port_config.ini create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/sai.profile create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/default_sku create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/installer.conf create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/linecard_extra_map.json create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/otn_attenuator_pluggin.lua create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/otn_metadata.json create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/otn_oa_pluggin.lua create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/otn_ocm_pluggin.lua create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/otn_osc_pluggin.lua create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/platform.json create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/platform_asic create mode 100644 device/molex/x86_64-otn-kvm_x86_64-r0/pmon_daemon_control.json create mode 100644 dockers/docker-eventd/eventdb_wrapper.sh create mode 100644 files/image_config/otn/otn-config.service create mode 100755 files/image_config/otn/otn-config.sh create mode 100644 platform/otn-kvm/README.md create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm.dep create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm.mk create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/Dockerfile.j2 create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/critical_processes create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/event/cpu_regex.json create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/event/default.json create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/event/eventdb_wrapper.sh create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/event/fan_regex.json create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/event/platform_events_info.json create mode 100755 platform/otn-kvm/docker-syncd-otn-kvm/start.sh create mode 100644 platform/otn-kvm/docker-syncd-otn-kvm/supervisord.conf create mode 100644 platform/otn-kvm/hal-client.dep create mode 100644 platform/otn-kvm/hal-client.mk create mode 100644 platform/otn-kvm/hal-server.dep create mode 100644 platform/otn-kvm/hal-server.mk create mode 100644 platform/otn-kvm/kvm-image.dep create mode 100644 platform/otn-kvm/kvm-image.mk create mode 100644 platform/otn-kvm/one-image.dep create mode 100644 platform/otn-kvm/one-image.mk create mode 100644 platform/otn-kvm/onie.dep create mode 100644 platform/otn-kvm/onie.mk create mode 100644 platform/otn-kvm/platform-modules-otn-kvm.dep create mode 100644 platform/otn-kvm/platform-modules-otn-kvm.mk create mode 100644 platform/otn-kvm/platform.conf create mode 100644 platform/otn-kvm/raw-image.dep create mode 100644 platform/otn-kvm/raw-image.mk create mode 100644 platform/otn-kvm/rules.dep create mode 100644 platform/otn-kvm/rules.mk create mode 100644 platform/otn-kvm/sai.dep create mode 100644 platform/otn-kvm/sai.mk create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/LICENSE create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/README.md create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/changelog create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/compat create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/control create mode 100755 platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/rules create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/sonic-platform-otn-kvm-ols-v.install create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/setup.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/__init__.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/chassis.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/component.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan_drawer.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/module.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/platform.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/psu.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/sfp.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/thermal.py create mode 100644 platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/watchdog.py create mode 100644 platform/otn-kvm/sonic-version.dep create mode 100644 platform/otn-kvm/sonic-version.mk create mode 100644 platform/otn-kvm/sonic-version/Makefile create mode 100644 platform/otn-kvm/sonic-version/build_sonic_version.sh create mode 120000 platform/otn-kvm/sonic-version/sonic_version.yml.j2 create mode 100644 platform/otn-kvm/thrift.dep create mode 100644 platform/otn-kvm/thrift.mk create mode 100644 rules/sonic-linecardsyncd.dep create mode 100644 rules/sonic-linecardsyncd.mk create mode 100644 src/sonic-eventd/etc/eventd.json create mode 100644 src/sonic-eventd/src/eventconsume.cpp create mode 100644 src/sonic-eventd/src/eventconsume.h create mode 100644 src/sonic-eventd/src/eventdb.cpp create mode 100644 src/sonic-eventd/src/eventutils.cpp create mode 100644 src/sonic-eventd/src/eventutils.h create mode 100644 src/sonic-eventd/src/loghandler.cpp create mode 100644 src/sonic-eventd/src/loghandler.h create mode 100644 src/sonic-eventd/tests/default.json create mode 100644 src/sonic-eventd/tests/eventd.json create mode 100644 src/sonic-eventd/tests/eventdb_database_config.json create mode 100644 src/sonic-eventd/tests/eventdb_database_config_global.json create mode 100644 src/sonic-eventd/tests/eventdb_ut.cpp create mode 100644 src/sonic-eventd/var/evprofile/default.json create mode 100644 src/sonic-yang-models/yang-models/sonic-alarm.yang create mode 100644 src/sonic-yang-models/yang-models/sonic-event.yang diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/hwsku.json b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/hwsku.json new file mode 100644 index 00000000000..15b56762dcd --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/hwsku.json @@ -0,0 +1,4 @@ +{ + "interfaces": { + } +} diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/otn_config.json b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/otn_config.json new file mode 100644 index 00000000000..a004af393de --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/otn_config.json @@ -0,0 +1,317 @@ +{ + "OTN_ATTENUATOR": { + "VOA0-0": { + "attenuation": "4.2", + "attenuation-mode": "CONSTANT_ATTENUATION", + "enabled": "true" + }, + "VOA0-1": { + "attenuation": "3.2", + "attenuation-mode": "CONSTANT_ATTENUATION", + "enabled": "true" + } + }, + "OTN_OA": { + "OA0-0": { + "target-gain": "4.2", + "target-gain-tilt": "0.4", + "gain-range": "FIXED_GAIN_RANGE", + "amp-mode": "CONSTANT_GAIN", + "enabled": "true", + "type": "EDFA" + }, + "OA0-1": { + "target-gain": "5.2", + "target-gain-tilt": "0.5", + "gain-range": "FIXED_GAIN_RANGE", + "amp-mode": "CONSTANT_GAIN", + "enabled": "true", + "type": "EDFA" + } + }, + "OTN_OSC": { + "OSC0-0": { + }, + "OSC0-1": { + } + }, + "OTN_OCM": { + "OCM0-0|0": { + "monitor-port": "LineIn" + }, + "OCM0-0|1": { + "monitor-port": "LineOut" + }, + "OCM0-0|2": { + "monitor-port": "ClientIn" + }, + "OCM0-0|3": { + "monitor-port": "ClientOut" + }, + "OCM0-0|4": { + "monitor-port": "OcmIn" + } + }, + "OTN_OCM_CHANNEL": { + "OCM0-0|0|191262500": { + "lower_frequency": 191262500, + "upper_frequency": 191337500 + }, + "OCM0-0|0|191337500": { + "lower_frequency": 191337500, + "upper_frequency": 191412500 + }, + "OCM0-0|0|191412500": { + "lower_frequency": 191412500, + "upper_frequency": 191487500 + }, + "OCM0-0|0|191487500": { + "lower_frequency": 191487500, + "upper_frequency": 191562500 + }, + "OCM0-0|0|191562500": { + "lower_frequency": 191562500, + "upper_frequency": 191637500 + }, + "OCM0-0|0|191637500": { + "lower_frequency": 191637500, + "upper_frequency": 191712500 + }, + "OCM0-0|0|191712500": { + "lower_frequency": 191712500, + "upper_frequency": 191787500 + }, + "OCM0-0|0|191787500": { + "lower_frequency": 191787500, + "upper_frequency": 191862500 + }, + "OCM0-0|0|191862500": { + "lower_frequency": 191862500, + "upper_frequency": 191937500 + }, + "OCM0-0|0|191937500": { + "lower_frequency": 191937500, + "upper_frequency": 192012500 + }, + "OCM0-0|0|192012500": { + "lower_frequency": 192012500, + "upper_frequency": 192087500 + }, + "OCM0-0|0|192087500": { + "lower_frequency": 192087500, + "upper_frequency": 192162500 + }, + "OCM0-0|0|192162500": { + "lower_frequency": 192162500, + "upper_frequency": 192237500 + }, + "OCM0-0|0|192237500": { + "lower_frequency": 192237500, + "upper_frequency": 192312500 + }, + "OCM0-0|0|192312500": { + "lower_frequency": 192312500, + "upper_frequency": 192387500 + }, + "OCM0-0|0|192387500": { + "lower_frequency": 192387500, + "upper_frequency": 192462500 + }, + "OCM0-0|0|192462500": { + "lower_frequency": 192462500, + "upper_frequency": 192537500 + }, + "OCM0-0|0|192537500": { + "lower_frequency": 192537500, + "upper_frequency": 192612500 + }, + "OCM0-0|0|192612500": { + "lower_frequency": 192612500, + "upper_frequency": 192687500 + }, + "OCM0-0|0|192687500": { + "lower_frequency": 192687500, + "upper_frequency": 192762500 + }, + "OCM0-0|0|192762500": { + "lower_frequency": 192762500, + "upper_frequency": 192837500 + }, + "OCM0-0|0|192837500": { + "lower_frequency": 192837500, + "upper_frequency": 192912500 + }, + "OCM0-0|0|192912500": { + "lower_frequency": 192912500, + "upper_frequency": 192987500 + }, + "OCM0-0|0|192987500": { + "lower_frequency": 192987500, + "upper_frequency": 193062500 + }, + "OCM0-0|0|193062500": { + "lower_frequency": 193062500, + "upper_frequency": 193137500 + }, + "OCM0-0|0|193137500": { + "lower_frequency": 193137500, + "upper_frequency": 193212500 + }, + "OCM0-0|0|193212500": { + "lower_frequency": 193212500, + "upper_frequency": 193287500 + }, + "OCM0-0|0|193287500": { + "lower_frequency": 193287500, + "upper_frequency": 193362500 + }, + "OCM0-0|0|193362500": { + "lower_frequency": 193362500, + "upper_frequency": 193437500 + }, + "OCM0-0|0|193437500": { + "lower_frequency": 193437500, + "upper_frequency": 193512500 + }, + "OCM0-0|0|193512500": { + "lower_frequency": 193512500, + "upper_frequency": 193587500 + }, + "OCM0-0|0|193587500": { + "lower_frequency": 193587500, + "upper_frequency": 193662500 + }, + "OCM0-0|0|193662500": { + "lower_frequency": 193662500, + "upper_frequency": 193737500 + }, + "OCM0-0|0|193737500": { + "lower_frequency": 193737500, + "upper_frequency": 193812500 + }, + "OCM0-0|0|193812500": { + "lower_frequency": 193812500, + "upper_frequency": 193887500 + }, + "OCM0-0|0|193887500": { + "lower_frequency": 193887500, + "upper_frequency": 193962500 + }, + "OCM0-0|0|193962500": { + "lower_frequency": 193962500, + "upper_frequency": 194037500 + }, + "OCM0-0|0|194037500": { + "lower_frequency": 194037500, + "upper_frequency": 194112500 + }, + "OCM0-0|0|194112500": { + "lower_frequency": 194112500, + "upper_frequency": 194187500 + }, + "OCM0-0|0|194187500": { + "lower_frequency": 194187500, + "upper_frequency": 194262500 + }, + "OCM0-0|0|194262500": { + "lower_frequency": 194262500, + "upper_frequency": 194337500 + }, + "OCM0-0|0|194337500": { + "lower_frequency": 194337500, + "upper_frequency": 194412500 + }, + "OCM0-0|0|194412500": { + "lower_frequency": 194412500, + "upper_frequency": 194487500 + }, + "OCM0-0|0|194487500": { + "lower_frequency": 194487500, + "upper_frequency": 194562500 + }, + "OCM0-0|0|194562500": { + "lower_frequency": 194562500, + "upper_frequency": 194637500 + }, + "OCM0-0|0|194637500": { + "lower_frequency": 194637500, + "upper_frequency": 194712500 + }, + "OCM0-0|0|194712500": { + "lower_frequency": 194712500, + "upper_frequency": 194787500 + }, + "OCM0-0|0|194787500": { + "lower_frequency": 194787500, + "upper_frequency": 194862500 + }, + "OCM0-0|0|194862500": { + "lower_frequency": 194862500, + "upper_frequency": 194937500 + }, + "OCM0-0|0|194937500": { + "lower_frequency": 194937500, + "upper_frequency": 195012500 + }, + "OCM0-0|0|195012500": { + "lower_frequency": 195012500, + "upper_frequency": 195087500 + }, + "OCM0-0|0|195087500": { + "lower_frequency": 195087500, + "upper_frequency": 195162500 + }, + "OCM0-0|0|195162500": { + "lower_frequency": 195162500, + "upper_frequency": 195237500 + }, + "OCM0-0|0|195237500": { + "lower_frequency": 195237500, + "upper_frequency": 195312500 + }, + "OCM0-0|0|195312500": { + "lower_frequency": 195312500, + "upper_frequency": 195387500 + }, + "OCM0-0|0|195387500": { + "lower_frequency": 195387500, + "upper_frequency": 195462500 + }, + "OCM0-0|0|195462500": { + "lower_frequency": 195462500, + "upper_frequency": 195537500 + }, + "OCM0-0|0|195537500": { + "lower_frequency": 195537500, + "upper_frequency": 195612500 + }, + "OCM0-0|0|195612500": { + "lower_frequency": 195612500, + "upper_frequency": 195687500 + }, + "OCM0-0|0|195687500": { + "lower_frequency": 195687500, + "upper_frequency": 195762500 + }, + "OCM0-0|0|195762500": { + "lower_frequency": 195762500, + "upper_frequency": 195837500 + }, + "OCM0-0|0|195837500": { + "lower_frequency": 195837500, + "upper_frequency": 195912500 + }, + "OCM0-0|0|195912500": { + "lower_frequency": 195912500, + "upper_frequency": 195987500 + }, + "OCM0-0|0|195987500": { + "lower_frequency": 195987500, + "upper_frequency": 196062500 + }, + "OCM0-0|0|196062500": { + "lower_frequency": 196062500, + "upper_frequency": 196137500 + } + } +} diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/port_config.ini b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/port_config.ini new file mode 100644 index 00000000000..9c3469f1130 --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/port_config.ini @@ -0,0 +1,2 @@ +# name lanes alias index speed +# TODO, add OCS/DCN/... ports for framework management diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/sai.profile b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/sai.profile new file mode 100644 index 00000000000..aebb752d06f --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/OLS-V/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/etc/RegisterFile diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/default_sku b/device/molex/x86_64-otn-kvm_x86_64-r0/default_sku new file mode 100644 index 00000000000..ccf1824137c --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/default_sku @@ -0,0 +1 @@ +OLS-V t1 diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/installer.conf b/device/molex/x86_64-otn-kvm_x86_64-r0/installer.conf new file mode 100644 index 00000000000..d8d47e67389 --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/installer.conf @@ -0,0 +1 @@ +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="swiotlb=65536" \ No newline at end of file diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/linecard_extra_map.json b/device/molex/x86_64-otn-kvm_x86_64-r0/linecard_extra_map.json new file mode 100644 index 00000000000..ae726ab4678 --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/linecard_extra_map.json @@ -0,0 +1,4 @@ +{ + "OA0-0" : ["VOA0-0", "OSC0-0"], + "OA0-1" : ["VOA0-1", "OSC0-1"] +} diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/otn_attenuator_pluggin.lua b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_attenuator_pluggin.lua new file mode 100644 index 00000000000..9c1ba01f69a --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_attenuator_pluggin.lua @@ -0,0 +1,98 @@ +-- KEYS - rif IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local function convertToSigned(unsigned) + local INT32_MAX = 2^31 - 1 + if unsigned <= INT32_MAX then + return unsigned + else + return unsigned - 2^32 + end +end + +local function strValuePro(str, div) + local v = tonumber(str) + v = convertToSigned(v) + return tostring(v / div) +end + +local function hex_decode(str) + return (str:gsub("\\x(%x%x)", function(hex) + return string.char(tonumber(hex, 16)) + end)) +end + +local logtable = {} + +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local state_db = "6" +local vid_table_name = "COUNTERS_OTN_ATTENUATOR_NAME_MAP" +local state_table_name = "OTN_ATTENUATOR_TABLE" + +-- Phase 1: read counters +redis.call('SELECT', counters_db) +for i = 1, #KEYS do + local vid = KEYS[i] + local obj_name = redis.call('HGET', vid_table_name, vid) + if obj_name then + local div = 100 + -- Get new COUNTERS values + local counter_key = counters_table_name .. ':' .. vid + + local ingress_port = "" + local val = redis.call('HGET', counter_key, 'SAI_OTN_ATTENUATOR_ATTR_INGRESS_PORT') + if val then + ingress_port = hex_decode(val) + end + + local egress_port = "" + val = redis.call('HGET', counter_key, 'SAI_OTN_ATTENUATOR_ATTR_EGRESS_PORT') + if val then + egress_port = hex_decode(val) + end + + local actual_att = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_ATTENUATOR_ATTR_ACTUAL_ATTENUATION') + if val then + actual_att = strValuePro(val, div) + end + + local output_power = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_ATTENUATOR_ATTR_OUTPUT_POWER_TOTAL') + if val then + output_power = strValuePro(val, div) + end + + local return_loss = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_ATTENUATOR_ATTR_OPTICAL_RETURN_LOSS') + if val then + return_loss = strValuePro(val, div) + end + + -- switch to state DB and update + redis.call('SELECT', state_db) + redis.call('HMSET', state_table_name .. '|' .. obj_name, + 'ingress-port', ingress_port, + 'egress-port', egress_port, + 'actual-attenuation', actual_att, + 'output-power-total', output_power, + 'optical-return-loss', return_loss) + + -- switch back for next iteration + redis.call('SELECT', counters_db) + + logit("Updated " .. obj_name) + else + logit("No mapping for vid=" .. vid) + end +end + +return logtable diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/otn_metadata.json b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_metadata.json new file mode 100644 index 00000000000..96d13a9fd1f --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_metadata.json @@ -0,0 +1,8 @@ +{ + "DEVICE_METADATA": { + "localhost": { + "type": "SonicOtn", + "switch_type": "otn" + } + } +} diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/otn_oa_pluggin.lua b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_oa_pluggin.lua new file mode 100644 index 00000000000..9434c751751 --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_oa_pluggin.lua @@ -0,0 +1,147 @@ +-- KEYS - rif IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local function convertToSigned(unsigned) + local INT32_MAX = 2^31 - 1 + if unsigned <= INT32_MAX then + return unsigned + else + return unsigned - 2^32 + end +end + +local function strValuePro(str, div) + local v = tonumber(str) + v = convertToSigned(v) + return tostring(v / div) +end + +local function hex_decode(str) + return (str:gsub("\\x(%x%x)", function(hex) + return string.char(tonumber(hex, 16)) + end)) +end + +local logtable = {} + +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local state_db = "6" +local vid_table_name = "COUNTERS_OTN_OA_NAME_MAP" +local state_table_name = "OTN_OA_TABLE" + +-- Phase 1: read counters +redis.call('SELECT', counters_db) +for i = 1, #KEYS do + local vid = KEYS[i] + local obj_name = redis.call('HGET', vid_table_name, vid) + if obj_name then + local div = 100 + -- Get new COUNTERS values + local counter_key = counters_table_name .. ':' .. vid + + local ingress_port = "" + local val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_INGRESS_PORT') + if val then + ingress_port = hex_decode(val) + end + + local egress_port = "" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_EGRESS_PORT') + if val then + egress_port = hex_decode(val) + end + + local actual_gain = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_ACTUAL_GAIN') + if val then + actual_gain = strValuePro(val, div) + end + + local actual_tilt = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_ACTUAL_GAIN_TILT') + if val then + actual_tilt = strValuePro(val, div) + end + + local input_power_total = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_INPUT_POWER_TOTAL') + if val then + input_power_total = strValuePro(val, div) + end + + local input_power_c = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_INPUT_POWER_C_BAND') + if val then + input_power_total = strValuePro(val, div) + end + + local input_power_l = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_INPUT_POWER_L_BAND') + if val then + input_power_l = strValuePro(val, div) + end + + local output_power_total = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_OUTPUT_POWER_TOTAL') + if val then + output_power_total = strValuePro(val, div) + end + + local output_power_c = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_OUTPUT_POWER_C_BAND') + if val then + output_power_c = strValuePro(val, div) + end + + local output_power_l = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_OUTPUT_POWER_L_BAND') + if val then + output_power_l = strValuePro(val, div) + end + + local laser_current = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_LASER_BIAS_CURRENT') + if val then + laser_current = strValuePro(val, div) + end + + local return_loss = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OA_ATTR_OPTICAL_RETURN_LOSS') + if val then + return_loss = strValuePro(val, div) + end + + -- switch to state DB and update + redis.call('SELECT', state_db) + redis.call('HMSET', state_table_name .. '|' .. obj_name, + 'ingress-port', ingress_port, + 'egress-port', egress_port, + 'actual-gain', actual_gain, + 'actual-gain-tilt', actual_tilt, + 'input-power-total', input_power_total, + 'input-power-c-band', input_power_c, + 'input-power-l-band', input_power_l, + 'output-power-total', output_power_total, + 'output-power-c-band', output_power_c, + 'output-power-l-band', output_power_l, + 'laser-bias-current', laser_current, + 'optical-return-loss', return_loss) + + -- switch back for next iteration + redis.call('SELECT', counters_db) + + logit("Updated " .. obj_name) + else + logit("No mapping for vid=" .. vid) + end +end + +return logtable diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/otn_ocm_pluggin.lua b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_ocm_pluggin.lua new file mode 100644 index 00000000000..0c8c6744595 --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_ocm_pluggin.lua @@ -0,0 +1,73 @@ +-- KEYS - rif IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local function convertToSigned(unsigned) + local INT32_MAX = 2^31 - 1 + if unsigned <= INT32_MAX then + return unsigned + else + return unsigned - 2^32 + end +end + +local function strValuePro(str, div) + local v = tonumber(str) + if not v then return "0" end + v = convertToSigned(v) + return tostring(v / div) +end + +local logtable = {} +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local state_db = "6" +local vid_table_name = "COUNTERS_OTN_OCM_CHANNEL_NAME_MAP" +local state_table_name = "OTN_OCM_CHANNEL_TABLE" + +-- Phase 1: read counters +redis.call('SELECT', counters_db) + +for i = 1, #KEYS do + local vid = KEYS[i] + local obj_name = redis.call('HGET', vid_table_name, vid) + + if obj_name then + local div = 100 + -- Get new COUNTERS values + local counter_key = counters_table_name .. ':' .. vid + + local ch_power = "-60" + local val = redis.call('HGET', counter_key, 'SAI_OTN_OCM_CHANNEL_ATTR_POWER') + if val then + ch_power = strValuePro(val, div) + end + + local target_power = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OCM_CHANNEL_ATTR_TARGET_POWER') + if val then + target_power = strValuePro(val, div) + end + + -- switch to state DB and update + redis.call('SELECT', state_db) + redis.call('HMSET', state_table_name .. '|' .. obj_name, + 'power', ch_power, + 'target-power', target_power) + + -- switch back for next iteration + redis.call('SELECT', counters_db) + + logit("Updated " .. obj_name) + else + logit("No mapping for vid=" .. vid) + end +end + +return logtable diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/otn_osc_pluggin.lua b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_osc_pluggin.lua new file mode 100644 index 00000000000..09d1da4b3ad --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/otn_osc_pluggin.lua @@ -0,0 +1,86 @@ +-- KEYS - rif IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local function convertToSigned(unsigned) + local INT32_MAX = 2^31 - 1 + if unsigned <= INT32_MAX then + return unsigned + else + return unsigned - 2^32 + end +end + +local function strValuePro(str, div) + local v = tonumber(str) + v = convertToSigned(v) + return tostring(v / div) +end + +local logtable = {} + +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local state_db = "6" +local vid_table_name = "COUNTERS_OTN_OSC_NAME_MAP" +local state_table_name = "OTN_OSC_TABLE" + + +-- Phase 1: read counters +redis.call('SELECT', counters_db) +for i = 1, #KEYS do + local vid = KEYS[i] + local obj_name = redis.call('HGET', vid_table_name, vid) + if obj_name then + local div = 100 + -- Get new COUNTERS values + local counter_key = counters_table_name .. ':' .. vid + + local input_power = "-60" + local val = redis.call('HGET', counter_key, 'SAI_OTN_OSC_ATTR_INPUT_POWER') + if val then + input_power = strValuePro(val, div) + end + + local output_power = "-60" + val = redis.call('HGET', counter_key, 'SAI_OTN_OSC_ATTR_OUTPUT_POWER') + if val then + output_power = strValuePro(val, div) + end + + local laser_current = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OSC_ATTR_LASER_BIAS_CURRENT') + if val then + laser_current = strValuePro(val, div) + end + + local output_frequency = "0" + val = redis.call('HGET', counter_key, 'SAI_OTN_OSC_ATTR_OUTPUT_FREQUENCY') + if val then + output_frequency = val + end + + -- switch to state DB and update + redis.call('SELECT', state_db) + redis.call('HMSET', state_table_name .. '|' .. obj_name, + 'input-power', input_power, + 'output-power', output_power, + 'laser-bias-current', laser_current, + 'output-frequency', output_frequency) + + -- switch back for next iteration + redis.call('SELECT', counters_db) + + logit("Updated " .. obj_name) + else + logit("No mapping for vid=" .. vid) + end +end + +return logtable diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/platform.json b/device/molex/x86_64-otn-kvm_x86_64-r0/platform.json new file mode 100644 index 00000000000..343b8a76c8c --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/platform.json @@ -0,0 +1,172 @@ +{ + "chassis": { + "components": [], + "fan_drawers": { + "fans": [ + { + "name": "FanTray0-Fan0", + "speed": { + "controllable": true + }, + "status_led": { + "status_led": true + } + }, + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": true + }, + "status_led": { + "status_led": true + } + }, + { + "name": "FanTray2-Fan2", + "speed": { + "controllable": true + }, + "status_led": { + "status_led": true + } + }, + { + "name": "FanTray3-Fan3", + "speed": { + "controllable": true + }, + "status_led": { + "status_led": true + } + } + ], + "name": "FanTray0", + "status_led": { + "controllable": true + } + }, + "modules": [ + { + "components": [ + { + "description": "Optical amplifier (west)", + "name": "OA0-0" + }, + { + "description": "Optical amplifier (east)", + "name": "OA0-1" + }, + { + "description": "Optical supervisory channel (west)", + "name": "OSC0-0" + }, + { + "description": "Optical supervisory channel (east)", + "name": "OSC0-1" + }, + { + "description": "Optical channel monitor", + "name": "OCM0-0" + }, + { + "description": "Optical time domain reflectometer", + "name": "OTDR0-0" + } + ], + "description": "Working optical card", + "name": "LINE-CARD0" + }, + { + "components": [ + { + "description": "Performs initialization of hardware components during booting", + "name": "BIOS" + }, + { + "description": "Platform managment controller for on-board components", + "name": "FPGA" + }, + { + "description": "Used for managing IO modules", + "name": "CPLD" + }, + { + "description": "Open network install environment", + "name": "ONIE" + } + ], + "description": "Supervisor module", + "name": "SUPERVISOR0" + } + ], + "name": "OLA", + "psus": [ + { + "fans": [ + { + "name": "PSU0-Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ], + "name": "PSU0", + "status_led": { + "status_led": false + } + }, + { + "fans": [ + { + "name": "PSU1-Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ], + "name": "PSU1", + "status_led": { + "status_led": false + } + } + ], + "status_led": { + "colors": [ + "off", + "red", + "green", + "amber", + "red blink", + "green blink", + "amber blink" + ], + "controllable": true + }, + "thermal_manager": false, + "thermals": [ + { + "controllable": false, + "high-crit-threshold": false, + "low-crit-threshold": false, + "maximum-recorded": false, + "minimum-recorded": false, + "name": "System Exhaust" + }, + { + "controllable": false, + "high-crit-threshold": false, + "low-crit-threshold": false, + "maximum-recorded": false, + "minimum-recorded": false, + "name": "System Board" + } + ] + }, + "interfaces": {} +} diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/platform_asic b/device/molex/x86_64-otn-kvm_x86_64-r0/platform_asic new file mode 100644 index 00000000000..a9304aa2262 --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/platform_asic @@ -0,0 +1 @@ +otn-kvm diff --git a/device/molex/x86_64-otn-kvm_x86_64-r0/pmon_daemon_control.json b/device/molex/x86_64-otn-kvm_x86_64-r0/pmon_daemon_control.json new file mode 100644 index 00000000000..a860e3781cc --- /dev/null +++ b/device/molex/x86_64-otn-kvm_x86_64-r0/pmon_daemon_control.json @@ -0,0 +1,7 @@ +{ + "skip_ledd": true, + "skip_pcied": true, + "skip_syseepromd": true, + "skip_xcvrd": true, + "skip_ycabled": true +} diff --git a/dockers/docker-database/database_config.json.j2 b/dockers/docker-database/database_config.json.j2 index b97589d3733..19289a2d97a 100644 --- a/dockers/docker-database/database_config.json.j2 +++ b/dockers/docker-database/database_config.json.j2 @@ -140,6 +140,12 @@ "instance" : {% if include_remote_db %} "remote_redis" {% else %} "redis" {% endif %} } {% else %} + , + "EVENT_DB" : { + "id" : 19, + "separator": "|", + "instance" : "redis" + } , "BMP_STATE_DB" : { "id" : 20, diff --git a/dockers/docker-eventd/Dockerfile.j2 b/dockers/docker-eventd/Dockerfile.j2 index 8e2f905f786..dc5eea381ae 100644 --- a/dockers/docker-eventd/Dockerfile.j2 +++ b/dockers/docker-eventd/Dockerfile.j2 @@ -36,6 +36,7 @@ COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] COPY ["critical_processes", "/etc/supervisor"] COPY ["*.json", "/etc/rsyslog.d/rsyslog_plugin_conf/"] COPY ["files/rsyslog_plugin.conf.j2", "/etc/rsyslog.d/rsyslog_plugin_conf/"] +COPY ["eventdb_wrapper.sh", "/usr/bin"] RUN j2 -f json /etc/rsyslog.d/rsyslog_plugin_conf/rsyslog_plugin.conf.j2 /etc/rsyslog.d/rsyslog_plugin_conf/host_events_info.json > /etc/rsyslog.d/rsyslog_plugin_conf/host_events.conf RUN j2 -f json /etc/rsyslog.d/rsyslog_plugin_conf/rsyslog_plugin.conf.j2 /etc/rsyslog.d/rsyslog_plugin_conf/bgp_events_info.json > /etc/rsyslog.d/rsyslog_plugin_conf/bgp_events.conf diff --git a/dockers/docker-eventd/eventdb_wrapper.sh b/dockers/docker-eventd/eventdb_wrapper.sh new file mode 100644 index 00000000000..061d715a25b --- /dev/null +++ b/dockers/docker-eventd/eventdb_wrapper.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +JSON_FILE="/etc/evprofile/default.json" + +# Check if file exists and is not empty +if [ -s "$JSON_FILE" ]; then + # Check if "events" is defined and has at least one entry + if jq -e '.events and (.events | length > 0)' "$JSON_FILE" > /dev/null; then + echo "Valid events found. Starting eventdb." + exec /usr/bin/eventdb + else + echo "'events' list is missing or empty. Skipping eventdb start." + exit 0 + fi +else + echo "JSON file missing or empty. Skipping eventdb start." + exit 0 +fi \ No newline at end of file diff --git a/dockers/docker-eventd/supervisord.conf b/dockers/docker-eventd/supervisord.conf index be51f922c12..bd57f978c02 100644 --- a/dockers/docker-eventd/supervisord.conf +++ b/dockers/docker-eventd/supervisord.conf @@ -50,3 +50,15 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=start:exited +[program:eventdb] +command=/usr/bin/eventdb_wrapper.sh +priority=3 +autostart=false +autorestart=false +startsecs=0 +startretries=0 +exitcodes=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=start:exited \ No newline at end of file diff --git a/dockers/docker-orchagent/critical_processes.j2 b/dockers/docker-orchagent/critical_processes.j2 index b9bad74089b..49250982e9e 100644 --- a/dockers/docker-orchagent/critical_processes.j2 +++ b/dockers/docker-orchagent/critical_processes.j2 @@ -1,8 +1,12 @@ {% set is_fabric_asic = 0 %} +{% set is_otn_asic = 0 %} {% if DEVICE_METADATA.localhost.switch_type %} {% if DEVICE_METADATA.localhost.switch_type == "fabric" %} {% set is_fabric_asic = 1 %} {% endif %} +{% if DEVICE_METADATA.localhost.switch_type == "otn" %} +{% set is_otn_asic = 1 %} +{% endif %} {% endif %} program:orchagent {% if is_fabric_asic == 0 %} @@ -20,3 +24,6 @@ program:vxlanmgrd program:coppmgrd program:tunnelmgrd {%- endif %} +{% if is_otn_asic == 1 %} +program:otnmgrd +{%- endif %} diff --git a/dockers/docker-orchagent/supervisord.conf.j2 b/dockers/docker-orchagent/supervisord.conf.j2 index 026958197fb..f29566a1416 100644 --- a/dockers/docker-orchagent/supervisord.conf.j2 +++ b/dockers/docker-orchagent/supervisord.conf.j2 @@ -29,12 +29,16 @@ stderr_logfile=syslog dependent_startup=true {% set is_fabric_asic = 0 %} +{% set is_otn_asic = 0 %} {% set orchagent_dependent_startup_wait_for = "portsyncd:running" %} {% if DEVICE_METADATA.localhost.switch_type %} {% if DEVICE_METADATA.localhost.switch_type == "fabric" %} {% set is_fabric_asic = 1 %} {% set orchagent_dependent_startup_wait_for = "rsyslogd:running" %} {%- endif %} +{% if DEVICE_METADATA.localhost.switch_type == "otn" %} +{% set is_otn_asic = 1 %} +{%- endif %} {%- endif %} {% set asan_extra_options = ':print_suppressions=0' %} @@ -302,3 +306,18 @@ dependent_startup_wait_for=swssconfig:exited environment=ASAN_OPTIONS="log_path=/var/log/asan/fdbsyncd-asan.log{{ asan_extra_options }}" {% endif %} {%- endif %} + +{% if is_otn_asic == 1 %} +[program:otnmgrd] +command=/usr/bin/otnmgrd +priority=18 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=swssconfig:exited +{% if ENABLE_ASAN == "y" %} +environment=ASAN_OPTIONS="log_path=/var/log/asan/otnmgrd-asan.log{{ asan_extra_options }}" +{% endif %} +{%- endif %} diff --git a/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 b/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 index fd2d0729637..137715ee938 100644 --- a/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 +++ b/dockers/docker-platform-monitor/docker-pmon.supervisord.conf.j2 @@ -229,3 +229,20 @@ startsecs=10 dependent_startup=true dependent_startup_wait_for=rsyslogd:running {% endif %} + +{% set is_otn_asic = 0 %} +{% if DEVICE_METADATA.localhost.switch_type == "otn" %} +{% set is_otn_asic = 1 %} +{%- endif %} +{% if is_otn_asic == 1 and not skip_linecardsyncd %} +[program:linecardsyncd] +command={% if API_VERSION == 3 and 'linecardsyncd' not in python2_daemons %}python3 {% else %} python2 {% endif %}/usr/local/bin/linecardsyncd +priority=8 +autostart=false +autorestart=unexpected +stdout_logfile=syslog +stderr_logfile=syslog +startsecs=10 +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running {% if delay_non_critical_daemon %}delay:exited{% endif %} +{% endif %} diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index dabf4958afa..1992a27f021 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -94,10 +94,17 @@ function preStartAction() # Load redis content from /host/warmboot/dump.rdb docker cp $WARM_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb else - # Create an emtpy file and overwrite any RDB if already there - echo -n > /tmp/dump.rdb - docker cp /tmp/dump.rdb database$DEV:/var/lib/redis/ - docker cp /tmp/dump.rdb database$DEV:/var/lib/redis_bmp/ + COLD_DIR=/host/coldboot + #In case of cold reboot, load redis content from /host/coldboot/dump.rdb + if [[ -f $COLD_DIR/dump.rdb ]]; then + #Load redis content from /host/coldboot/dump.rdb + docker cp $COLD_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb + else + # Create an emtpy file and overwrite any RDB if already there + echo -n > /tmp/dump.rdb + docker cp /tmp/dump.rdb database$DEV:/var/lib/redis/ + docker cp /tmp/dump.rdb database$DEV:/var/lib/redis_bmp/ + fi fi fi {%- elif docker_container_name == "pde" %} @@ -356,6 +363,10 @@ function postStartAction() systemctl reset-failed rsyslog systemctl restart rsyslog fi +{%- elif docker_container_name == "syncd" %} + for f in $(docker exec -i syncd ls /etc/rsyslog.d/rsyslog_plugin_conf); do docker cp syncd:/etc/rsyslog.d/rsyslog_plugin_conf/$f /etc/rsyslog.d/; done + systemctl reset-failed rsyslog + systemctl restart rsyslog {%- else %} : # nothing {%- endif %} diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 729ab4ec2b3..47faa11ec49 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -1193,3 +1193,10 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-mark unho {% if ENABLE_MULTIDB == "y" %} sudo touch $FILESYSTEM_ROOT_ETC_SONIC/enable_multidb {% endif %} + +## Load OTN configuration files +{% if sonic_asic_platform in ["otn-kvm", "otn"] %} +sudo cp $IMAGE_CONFIGS/otn/otn-config.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM +sudo cp $IMAGE_CONFIGS/otn/otn-config.sh $FILESYSTEM_ROOT/usr/bin/ +echo "otn-config.service" | sudo tee -a $GENERATED_SERVICE_FILE +{% endif %} diff --git a/files/image_config/otn/otn-config.service b/files/image_config/otn/otn-config.service new file mode 100644 index 00000000000..e1ff7bdc20f --- /dev/null +++ b/files/image_config/otn/otn-config.service @@ -0,0 +1,15 @@ +[Unit] +Description=Update optical configuration +Requires=database.service +After=database.service +Requires=config-setup.service +After=config-setup.service +BindsTo=sonic.target +After=sonic.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/otn-config.sh + +[Install] +WantedBy=sonic.target diff --git a/files/image_config/otn/otn-config.sh b/files/image_config/otn/otn-config.sh new file mode 100755 index 00000000000..bfd17700b66 --- /dev/null +++ b/files/image_config/otn/otn-config.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +PLATFORM=${PLATFORM:-`sonic-cfggen -d -v DEVICE_METADATA.localhost.platform`} +sonic-cfggen -j /usr/share/sonic/device/$PLATFORM/otn_metadata.json --write-to-db +HWSKU=${HWSKU:-`sonic-cfggen -d -v DEVICE_METADATA.localhost.hwsku`} +sonic-cfggen -j /usr/share/sonic/device/$PLATFORM/$HWSKU/otn_config.json --write-to-db diff --git a/platform/otn-kvm/README.md b/platform/otn-kvm/README.md new file mode 100644 index 00000000000..0fb4e8140cb --- /dev/null +++ b/platform/otn-kvm/README.md @@ -0,0 +1,250 @@ +# SONIC otn-kvm Demo Instructions + +This doc contains the procedure to compile, run and test the SONiC-OTN KVM image, the prototype the team currently has. +For SONiC compilation environment setup, please refer to [sonic-buildimage](https://github.com/sonic-net/sonic-buildimage) and [README.md](https://github.com/sonic-net/sonic-buildimage/blob/master/README.md) + +# HOWTO Build otn-kvm image + +``` bash +make init +make configure PLATFORM=otn-kvm +make target/sonic-otn-kvm.img.gz +``` + +# HOWTO setup KVM environment +1. Install Ubuntu KVM tools + +```bash +sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils -y +``` + +2. Check CPU virtualization support + +```bash +kvm-ok +INFO: /dev/kvm exists +KVM acceleration can be used +``` + +3. Copy the SONiC image to host + - sonic-otn-kvm.img.gz --- compressed SONiC image + +4. Decompress the image +```bash +gunzip sonic-otn-kvm.img.gz +``` + +## Running SONiC OTN KVM +```bash +sudo qemu-system-x86_64 \ + -hda sonic-otn-kvm.img \ + -enable-kvm -m 4096 -smp 4 \ + -nographic \ + -netdev user,id=net0,hostfwd=tcp::2222-:22 \ + -device e1000,netdev=net0 + + + GNU GRUB version 2.02 + + +----------------------------------------------------------------------------+ + |*SONiC-OS-otn.0-dirty-202528.102930 | + | ONIE | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------------------------------------------------------------------+ + + Use the ^ and v keys to select which entry is highlighted. + Press enter to boot the selected OS, `e' to edit the commands + before booting or `c' for a command-line. + + GNU GRUB version 2.02 +``` +If want to quit qemu, please hold Ctrl and press A, then release both keys, and press X. + +# HOWTO use otn-kvm image +## Login directly in CLI +Input user and password to login, which are configured in config file, admin/YourPaSsWoRd for default. +``` +sonic login: admin +Password: +Linux sonic 6.1.0-29-2-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64 +You are on + ____ ___ _ _ _ ____ + / ___| / _ \| \ | (_)/ ___| + \___ \| | | | \| | | | + ___) | |_| | |\ | | |___ + |____/ \___/|_| \_|_|\____| + +-- Software for Open Networking in the Cloud -- + +Unauthorized access and/or use are prohibited. +All access and/or use are subject to monitoring. + +Help: https://sonic-net.github.io/SONiC/ + +Last login: Wed Jul 23 02:54:51 UTC 2025 on ttyS0 +admin@sonic:~$ +``` + +## Login via SSH +Use ssh port 2222 to locally login to SONiC. +``` +ssh -p 2222 admin@localhost + +The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established. +RSA key fingerprint is SHA256:+pZRW181kQeX5mhEoVaK9VTm1b/nFsyxdkfNYNaQwWY. +This key is not known by any other names. +Are you sure you want to continue connecting (yes/no/[fingerprint])? yes +Warning: Permanently added '[localhost]:2222' (RSA) to the list of known hosts. +Debian GNU/Linux 12 \n \l + +admin@localhost's password: +Linux sonic 6.1.0-29-2-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64 +You are on + ____ ___ _ _ _ ____ + / ___| / _ \| \ | (_)/ ___| + \___ \| | | | \| | | | + ___) | |_| | |\ | | |___ + |____/ \___/|_| \_|_|\____| + +-- Software for Open Networking in the Cloud -- + +Unauthorized access and/or use are prohibited. +All access and/or use are subject to monitoring. + +Help: https://sonic-net.github.io/SONiC/ + +Last login: Mon Aug 25 23:35:30 2025 +admin@sonic:~$ +``` + +## Show PMON platform information +### Show summary information +```bash +admin@sonic:~$ show platform summary +Platform: x86_64-otn-kvm_x86_64-r0 +HwSKU: OLS-V +ASIC: otn-kvm +ASIC Count: 1 +Serial Number: D9401XXX +Model Number: 1835260XXX +Hardware Revision: 1.01 +Switch Type: otn +admin@sonic:~$ +``` + +### Show PSU information +```bash +admin@sonic:~$ show platform psu +PSU Model Serial HW Rev Voltage (V) Current (A) Power (W) Status LED +----- ------- ------------------- -------- ------------- ------------- ----------- -------- ----- +PSU 1 VM-PSU G1251551NJ220600XXX R00 11.96 1.97 23.62 OK green +PSU 2 VM-PSU G1251551NJ220600XXX R00 11.98 2.01 23.95 OK green +admin@sonic:~$ +``` + +### Show fan information +```bash +admin@sonic:~$ show platform fan + Drawer LED FAN Speed Direction Presence Status Timestamp +-------- ----- ------------- ------- --------------------- ---------- -------- ----------------- +FanTray0 green FanTray0-Fan0 51% FAN_DIRECTION_EXHAUST Present OK 20250723 03:31:23 +FanTray0 green FanTray0-Fan1 53% FAN_DIRECTION_EXHAUST Present OK 20250723 03:31:23 +FanTray0 green FanTray0-Fan2 55% FAN_DIRECTION_EXHAUST Present OK 20250723 03:31:23 +FanTray0 green FanTray0-Fan3 57% FAN_DIRECTION_EXHAUST Present OK 20250723 03:31:23 + N/A green PSU0-Fan 100% FAN_DIRECTION_INTAKE Present OK 20250723 03:31:23 + N/A green PSU1-Fan 100% FAN_DIRECTION_INTAKE Present OK 20250723 03:31:23 +admin@sonic:~$ +``` + +### Show thermal information +```bash +admin@sonic:~$ show platform temperature + Sensor Temperature High TH Low TH Crit High TH Crit Low TH Warning Timestamp +-------------- ------------- --------- -------- -------------- ------------- --------- ----------------- + System Board 0 75 -5 70 0 False 20250723 03:32:23 +System Exhaust 0 75 -5 70 0 False 20250723 03:32:23 +admin@sonic:~$ +``` + +### Show firmware information +```bash +admin@sonic:~$ show platform firmware status +Chassis Module Component Version Description +--------- ----------- ----------- --------- ------------------------------------------------------------- +OLA LINE-CARD0 OA0-0 1.00.0002 Optical amplifier (west) + OA0-1 1.00.0002 Optical amplifier (east) + OSC0-0 1.02.0003 Optical supervisory channel (west) + OSC0-1 N/A Optical supervisory channel (east) + OCM0-0 1.00.0003 Optical channel monitor + OTDR0-0 1.00.0004 Optical time domain reflectometer + SUPERVISOR0 BIOS 5.6.5 Performs initialization of hardware components during booting + FPGA 1.01.0004 Platform managment controller for on-board components + CPLD 1.01.0005 Used for managing IO modules + ONIE 2022.08 Open network install environment +admin@sonic:~$ +``` + +## Redis +We have added the following tables to support data of OCS. +- For CONFIG_DB (DB 4) + - OTN_ATTENUATOR + - OTN_OA + - OTN_OCM + - OTN_OCM_CHANNEL + - OTN_OSC +- For STATE_DB (DB 6) + - OTN_ATTENUATOR_TABLE + - OTN_OA_TABLE + - OTN_OCM_CHANNEL_TABLE + - OTN_OSC_TABLE + +## CLI Support for OTN +We use SONiC CLI Auto-generation tool to support SONiC OTN CLI by ocs yang model. For more detail please refer to [SONiC CLI Auto-generation tool](https://github.com/sonic-net/SONiC/blob/master/doc/cli_auto_generation/cli_auto_generation.md) + +### Generate OTN CLI command +```bash +sudo -i + +``` + +### Features +- show xxxxx +- config xxxxx + +### Show OTN xxxxx configuration +```bash +root@sonic:~# show xxxxx + +root@sonic:~# +``` + +### Show OTN xxxxx state +```bash +root@sonic:~# show xxxxx + +root@sonic:~# +``` + +## REST API Support for OTN +REST API follows RESTCONF protocol + +In ```sonic-mgmt-common```, REST APIs are generated from ```sonic-xxxxx.yang``` yang model. + +### Show OTN xxxxx configuration +```bash +admin@sonic:~$ +``` + +### Show OTN xxxxx state +```bash +admin@sonic:~$ +``` diff --git a/platform/otn-kvm/docker-syncd-otn-kvm.dep b/platform/otn-kvm/docker-syncd-otn-kvm.dep new file mode 100644 index 00000000000..df2f0061cbe --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm.dep @@ -0,0 +1,11 @@ +#DPKG FRK +DPATH := $($(DOCKER_SYNCD_BASE)_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) $(PLATFORM_PATH)/docker-syncd-otn-kvm.mk $(PLATFORM_PATH)/docker-syncd-otn-kvm.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(DPATH)) + +$(DOCKER_SYNCD_BASE)_CACHE_MODE := GIT_CONTENT_SHA +$(DOCKER_SYNCD_BASE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(DOCKER_SYNCD_BASE)_DEP_FILES := $(DEP_FILES) + +$(eval $(call add_dbg_docker,$(DOCKER_SYNCD_BASE),$(DOCKER_SYNCD_BASE_DBG))) diff --git a/platform/otn-kvm/docker-syncd-otn-kvm.mk b/platform/otn-kvm/docker-syncd-otn-kvm.mk new file mode 100644 index 00000000000..4bc7bba7957 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm.mk @@ -0,0 +1,21 @@ +# docker image for otn-kvm syncd + +DOCKER_SYNCD_PLATFORM_CODE = otn-kvm +include $(PLATFORM_PATH)/../template/docker-syncd-bullseye.mk + +$(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) \ + $(OTN_KVM_THRIFT_LIB_DEB) \ + $(OTN_KVM_THRIFT_LIB_DEV_DEB) \ + $(OTN_KVM_LIBSAI_DEB) \ + $(OTN_KVM_HALSERVER_DEB) \ + $(SONIC_EVENTD) + +$(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ + $(LIBSWSSCOMMON_DBG) \ + $(LIBSAIMETADATA_DBG) \ + $(LIBSAIREDIS_DBG) + +$(DOCKER_SYNCD_BASE)_VERSION = 1.0.0 +$(DOCKER_SYNCD_BASE)_PACKAGE_NAME = syncd + +$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/Dockerfile.j2 b/platform/otn-kvm/docker-syncd-otn-kvm/Dockerfile.j2 new file mode 100644 index 00000000000..28bccbe5952 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/Dockerfile.j2 @@ -0,0 +1,52 @@ +{% from "dockers/dockerfile-macros.j2" import install_debian_packages %} +FROM docker-config-engine-bullseye-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} + +ARG docker_container_name + +RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf + +## Make apt-get non-interactive +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update + +COPY \ +{% for deb in docker_syncd_otn_kvm_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +# Install locally-built Debian packages and implicitly install their dependencies +{{ install_debian_packages(docker_syncd_otn_kvm_debs.split(' ')) }} + +## TODO: add kmod into Depends +RUN apt-get install -yf kmod + +## BRCM uses ethtool to set host interface speed +RUN apt-get install -y ethtool + +COPY ["start.sh", "/usr/bin/"] + +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] + +RUN mkdir -p /etc/rsyslog.d/rsyslog_plugin_conf + +## add eventd into Depends +COPY ["./event/*.json", "/etc/rsyslog.d/rsyslog_plugin_conf/"] +COPY ["files/rsyslog_plugin.conf.j2", "/etc/rsyslog.d/rsyslog_plugin_conf/"] +COPY ["./event/eventdb_wrapper.sh", "/usr/bin"] +COPY ["./event/default.json", "/etc/evprofile/"] +RUN chmod +x /usr/bin/eventdb_wrapper.sh + +RUN j2 -f json /etc/rsyslog.d/rsyslog_plugin_conf/rsyslog_plugin.conf.j2 /etc/rsyslog.d/rsyslog_plugin_conf/platform_events_info.json > /etc/rsyslog.d/rsyslog_plugin_conf/platform_events.conf + +RUN rm -f /etc/rsyslog.d/rsyslog_plugin_conf/platform_events_info.json + + +## Clean up +RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y +RUN rm -rf /debs + +ENTRYPOINT ["/usr/local/bin/supervisord"] diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/critical_processes b/platform/otn-kvm/docker-syncd-otn-kvm/critical_processes new file mode 100644 index 00000000000..bdd6903c569 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/critical_processes @@ -0,0 +1 @@ +program:syncd diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/event/cpu_regex.json b/platform/otn-kvm/docker-syncd-otn-kvm/event/cpu_regex.json new file mode 100644 index 00000000000..df252e30c15 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/event/cpu_regex.json @@ -0,0 +1,12 @@ +[ + { + "tag": "Cpu", + "regex": ".*(Cpu) high .*(RAISE|CLEAR) (.*)", + "params": [ "type-id","action","text" ] + }, + { + "tag": "Cpu", + "regex": ".*(Cpu) supervisor (started|stopped)", + "params": [ "type-id","text" ] + } +] \ No newline at end of file diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/event/default.json b/platform/otn-kvm/docker-syncd-otn-kvm/event/default.json new file mode 100644 index 00000000000..88ef8af94b6 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/event/default.json @@ -0,0 +1,36 @@ +{ + "__README__" : "This is default map of events that eventd uses. Developer can modify this file and send SIGINT to eventd to make it read and use the updated file. Alternatively developer can test the new event by adding it to a custom event profile and use 'event profile ' command to apply that profile without having to send SIGINT to eventd. Developer need to commit default.json file with the new event after testing it out. Supported severities are: CRITICAL, MAJOR, MINOR, WARNING and INFORMATIONAL. Supported enable flag values are: true and false.", + "events":[ + { + "name": "SYSTEM_STATE", + "severity": "INFORMATIONAL", + "enable": "true", + "message" : "" + }, + { + "name": "SENSOR_TEMP_HIGH", + "severity": "WARNING", + "enable": "true", + "message" : "" + }, + { + "name": "USER_LOGIN", + "severity": "INFORMATIONAL", + "enable": "true", + "message" : "" + }, + { + "name": "Fan", + "severity": "INFORMATIONAL", + "enable": "true", + "message" : "FAN_EVENT" + }, + { + "name": "Cpu", + "severity": "WARNING", + "enable": "true", + "message" : "CPU_EVENT" + } + ] +} + diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/event/eventdb_wrapper.sh b/platform/otn-kvm/docker-syncd-otn-kvm/event/eventdb_wrapper.sh new file mode 100644 index 00000000000..061d715a25b --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/event/eventdb_wrapper.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +JSON_FILE="/etc/evprofile/default.json" + +# Check if file exists and is not empty +if [ -s "$JSON_FILE" ]; then + # Check if "events" is defined and has at least one entry + if jq -e '.events and (.events | length > 0)' "$JSON_FILE" > /dev/null; then + echo "Valid events found. Starting eventdb." + exec /usr/bin/eventdb + else + echo "'events' list is missing or empty. Skipping eventdb start." + exit 0 + fi +else + echo "JSON file missing or empty. Skipping eventdb start." + exit 0 +fi \ No newline at end of file diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/event/fan_regex.json b/platform/otn-kvm/docker-syncd-otn-kvm/event/fan_regex.json new file mode 100644 index 00000000000..ecb6d9c66c0 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/event/fan_regex.json @@ -0,0 +1,12 @@ +[ + { + "tag": "Fan", + "regex": ".*(Fan) failure .*(RAISE|CLEAR) (.*)", + "params": [ "type-id","action","text" ] + }, + { + "tag": "Fan", + "regex": ".*(Fan) failure monitor (started|stopped)", + "params": [ "type-id","text" ] + } +] diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/event/platform_events_info.json b/platform/otn-kvm/docker-syncd-otn-kvm/event/platform_events_info.json new file mode 100644 index 00000000000..82be0db1344 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/event/platform_events_info.json @@ -0,0 +1,13 @@ +{ + "yang_module": "sonic-events-platform", + "proclist": [ + { + "name": "fan", + "parse_json": "fan_regex.json" + }, + { + "name": "cpu", + "parse_json": "cpu_regex.json" + } + ] +} \ No newline at end of file diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/start.sh b/platform/otn-kvm/docker-syncd-otn-kvm/start.sh new file mode 100755 index 00000000000..40178f13e00 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/start.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +HWSKU_DIR=/usr/share/sonic/hwsku + +mkdir -p /etc/sai.d/ + +# Create/Copy the sai.profile to /etc/sai.d/sai.profile +if [ -f $HWSKU_DIR/sai.profile.j2 ]; then + sonic-cfggen -d -t $HWSKU_DIR/sai.profile.j2 > /etc/sai.d/sai.profile +else + if [ -f $HWSKU_DIR/sai.profile ]; then + cp $HWSKU_DIR/sai.profile /etc/sai.d/sai.profile + fi +fi diff --git a/platform/otn-kvm/docker-syncd-otn-kvm/supervisord.conf b/platform/otn-kvm/docker-syncd-otn-kvm/supervisord.conf new file mode 100644 index 00000000000..2fdef926c03 --- /dev/null +++ b/platform/otn-kvm/docker-syncd-otn-kvm/supervisord.conf @@ -0,0 +1,63 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[eventlistener:dependent-startup] +command=python3 -m supervisord_dependent_startup +autostart=true +autorestart=unexpected +startretries=0 +exitcodes=0,3 +events=PROCESS_STATE +buffer_size=1024 + +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener --container-name syncd +events=PROCESS_STATE_EXITED,PROCESS_STATE_RUNNING +autostart=true +autorestart=unexpected +buffer_size=1024 + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n -iNONE +priority=1 +autostart=false +autorestart=unexpected +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true + +[program:start] +command=/usr/bin/start.sh +priority=2 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + + +[program:syncd] +command=/usr/bin/syncd_start.sh +priority=4 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[program:HalPlatformApiServer] +command=/usr/local/bin/HalPlatformApiServer +priority=5 +autostart=false +autorestart=true +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + + diff --git a/platform/otn-kvm/hal-client.dep b/platform/otn-kvm/hal-client.dep new file mode 100644 index 00000000000..97b6a719a56 --- /dev/null +++ b/platform/otn-kvm/hal-client.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(OTN_KVM_HALCLIENT_DEB)_CACHE_MODE := none diff --git a/platform/otn-kvm/hal-client.mk b/platform/otn-kvm/hal-client.mk new file mode 100644 index 00000000000..d2afac101e2 --- /dev/null +++ b/platform/otn-kvm/hal-client.mk @@ -0,0 +1,8 @@ +HALCLIENT_VERSION = 1.0.0 +OTN_KVM_HALCLIENT_DEB = libhalplatformclient-mlx-$(HALCLIENT_VERSION)-amd64.deb +$(OTN_KVM_HALCLIENT_DEB)_URL = "https://raw.githubusercontent.com/sonic-molex/sonic-libmlx/refs/heads/otn/$(OTN_KVM_HALCLIENT_DEB)" + +$(OTN_KVM_HALCLIENT_DEB)_DEPENDS += $(OTN_KVM_THRIFT_PYTHON3_DEB) $(OTN_KVM_PYTHON3_SIX_DEB) +$(OTN_KVM_HALCLIENT_DEB)_RDEPENDS += $(OTN_KVM_THRIFT_PYTHON3_DEB) $(OTN_KVM_PYTHON3_SIX_DEB) + +SONIC_ONLINE_DEBS += $(OTN_KVM_HALCLIENT_DEB) diff --git a/platform/otn-kvm/hal-server.dep b/platform/otn-kvm/hal-server.dep new file mode 100644 index 00000000000..ef13b0af173 --- /dev/null +++ b/platform/otn-kvm/hal-server.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(OTN_KVM_HALSERVER_DEB)_CACHE_MODE := none diff --git a/platform/otn-kvm/hal-server.mk b/platform/otn-kvm/hal-server.mk new file mode 100644 index 00000000000..0110d6c6a68 --- /dev/null +++ b/platform/otn-kvm/hal-server.mk @@ -0,0 +1,8 @@ +HALSERVER_VERSION = 1.1.0 +OTN_KVM_HALSERVER_DEB = libhal-mlx-otn-kvm-$(HALSERVER_VERSION)-amd64.deb +$(OTN_KVM_HALSERVER_DEB)_URL = "https://raw.githubusercontent.com/sonic-molex/sonic-libmlx/refs/heads/otn/$(OTN_KVM_HALSERVER_DEB)" + +$(OTN_KVM_HALSERVER_DEB)_DEPENDS += $(OTN_KVM_THRIFT_LIB_DEB) $(OTN_KVM_THRIFT_LIB_DEV_DEB) +$(OTN_KVM_HALSERVER_DEB)_RDEPENDS += $(OTN_KVM_THRIFT_LIB_DEB) + +SONIC_ONLINE_DEBS += $(OTN_KVM_HALSERVER_DEB) diff --git a/platform/otn-kvm/kvm-image.dep b/platform/otn-kvm/kvm-image.dep new file mode 100644 index 00000000000..05c083a5159 --- /dev/null +++ b/platform/otn-kvm/kvm-image.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(SONIC_KVM_IMAGE)_CACHE_MODE := none diff --git a/platform/otn-kvm/kvm-image.mk b/platform/otn-kvm/kvm-image.mk new file mode 100644 index 00000000000..273620677b1 --- /dev/null +++ b/platform/otn-kvm/kvm-image.mk @@ -0,0 +1,15 @@ +# sonic otn-kvm image + +SONIC_KVM_IMAGE = sonic-otn-kvm.img.gz +$(SONIC_KVM_IMAGE)_INSTALLS += $($(SONIC_ONE_IMAGE)_INSTALLS) +$(SONIC_KVM_IMAGE)_LAZY_INSTALLS += $($(SONIC_ONE_IMAGE)_LAZY_INSTALLS) +$(SONIC_KVM_IMAGE)_MACHINE = otn-kvm +$(SONIC_KVM_IMAGE)_IMAGE_TYPE = kvm +ifeq ($(INSTALL_DEBUG_TOOLS),y) +$(SONIC_KVM_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) +$(SONIC_KVM_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES)) +else +$(SONIC_KVM_IMAGE)_DOCKERS = $(SONIC_INSTALL_DOCKER_IMAGES) +endif +$(SONIC_KVM_IMAGE)_FILES = $(ONIE_RECOVERY_IMAGE) $(ONIE_RECOVERY_KVM_4ASIC_IMAGE) $(ONIE_RECOVERY_KVM_6ASIC_IMAGE) +SONIC_INSTALLERS += $(SONIC_KVM_IMAGE) diff --git a/platform/otn-kvm/one-image.dep b/platform/otn-kvm/one-image.dep new file mode 100644 index 00000000000..c5399d80817 --- /dev/null +++ b/platform/otn-kvm/one-image.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(SONIC_ONE_IMAGE)_CACHE_MODE := none diff --git a/platform/otn-kvm/one-image.mk b/platform/otn-kvm/one-image.mk new file mode 100644 index 00000000000..d740e934519 --- /dev/null +++ b/platform/otn-kvm/one-image.mk @@ -0,0 +1,17 @@ +# sonic otn-kvm one image installer + +SONIC_ONE_IMAGE = sonic-otn-kvm.bin +$(SONIC_ONE_IMAGE)_MACHINE = otn-kvm +$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie +$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) \ + $(OTN_KVM_PYTHON3_SIX_DEB) \ + $(OTN_KVM_THRIFT_PYTHON3_DEB) \ + $(OTN_KVM_HALCLIENT_DEB) +$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(OTN_KVM_OLSV_PLATFORM_MODULE) +ifeq ($(INSTALL_DEBUG_TOOLS),y) +$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) +$(SONIC_ONE_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES)) +else +$(SONIC_ONE_IMAGE)_DOCKERS = $(SONIC_INSTALL_DOCKER_IMAGES) +endif +SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/otn-kvm/onie.dep b/platform/otn-kvm/onie.dep new file mode 100644 index 00000000000..36de83ce8ea --- /dev/null +++ b/platform/otn-kvm/onie.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(ONIE_RECOVERY_IMAGE)_CACHE_MODE := none diff --git a/platform/otn-kvm/onie.mk b/platform/otn-kvm/onie.mk new file mode 100644 index 00000000000..7e955651c02 --- /dev/null +++ b/platform/otn-kvm/onie.mk @@ -0,0 +1,4 @@ +ONIE_RECOVERY_IMAGE = onie-recovery-x86_64-otn-kvm_x86_64-r0.iso +$(ONIE_RECOVERY_IMAGE)_URL = "https://raw.githubusercontent.com/sonic-molex/ot_kvm_onie/refs/heads/otn/$(ONIE_RECOVERY_IMAGE)" + +SONIC_ONLINE_FILES += $(ONIE_RECOVERY_IMAGE) diff --git a/platform/otn-kvm/platform-modules-otn-kvm.dep b/platform/otn-kvm/platform-modules-otn-kvm.dep new file mode 100644 index 00000000000..1b413e13919 --- /dev/null +++ b/platform/otn-kvm/platform-modules-otn-kvm.dep @@ -0,0 +1,8 @@ +MPATH := $($(OTN_KVM_OLSV_PLATFORM_MODULE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) $(PLATFORM_PATH)/platform-modules-otn-kvm.mk $(PLATFORM_PATH)/platform-modules-otn-kvm.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(MPATH)) + +$(OTN_KVM_OLSV_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA +$(OTN_KVM_OLSV_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(OTN_KVM_OLSV_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) diff --git a/platform/otn-kvm/platform-modules-otn-kvm.mk b/platform/otn-kvm/platform-modules-otn-kvm.mk new file mode 100644 index 00000000000..4117d109a43 --- /dev/null +++ b/platform/otn-kvm/platform-modules-otn-kvm.mk @@ -0,0 +1,11 @@ +# OTN-KVM Platform modules + +OTN_KVM_OLSV_PLATFORM_MODULE_VERSION = 1.0 +export OTN_KVM_OLSV_PLATFORM_MODULE_VERSION + +OTN_KVM_OLSV_PLATFORM_MODULE = sonic-platform-otn-kvm-ols-v_$(OTN_KVM_OLSV_PLATFORM_MODULE_VERSION)_amd64.deb +$(OTN_KVM_OLSV_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-otn-kvm +$(OTN_KVM_OLSV_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(OTN_KVM_HALCLIENT_DEB) +$(OTN_KVM_OLSV_PLATFORM_MODULE)_PLATFORM = x86_64-otn-kvm_x86_64-r0 + +SONIC_DPKG_DEBS += $(OTN_KVM_OLSV_PLATFORM_MODULE) diff --git a/platform/otn-kvm/platform.conf b/platform/otn-kvm/platform.conf new file mode 100644 index 00000000000..e69de29bb2d diff --git a/platform/otn-kvm/raw-image.dep b/platform/otn-kvm/raw-image.dep new file mode 100644 index 00000000000..500ba2a70fe --- /dev/null +++ b/platform/otn-kvm/raw-image.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(SONIC_RAW_IMAGE)_CACHE_MODE := none diff --git a/platform/otn-kvm/raw-image.mk b/platform/otn-kvm/raw-image.mk new file mode 100644 index 00000000000..30d581fa402 --- /dev/null +++ b/platform/otn-kvm/raw-image.mk @@ -0,0 +1,9 @@ +# sonic otn-kvm raw image installer + +SONIC_RAW_IMAGE = sonic-otn-kvm.raw +$(SONIC_RAW_IMAGE)_MACHINE = otn-kvm +$(SONIC_RAW_IMAGE)_IMAGE_TYPE = raw +$(SONIC_RAW_IMAGE)_INSTALLS += $($(SONIC_ONE_IMAGE)_INSTALLS) +$(SONIC_RAW_IMAGE)_LAZY_INSTALLS += $($(SONIC_ONE_IMAGE)_LAZY_INSTALLS) +$(SONIC_RAW_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) +SONIC_INSTALLERS += $(SONIC_RAW_IMAGE) diff --git a/platform/otn-kvm/rules.dep b/platform/otn-kvm/rules.dep new file mode 100644 index 00000000000..e3d86a4b3e2 --- /dev/null +++ b/platform/otn-kvm/rules.dep @@ -0,0 +1,13 @@ +#DPKG FRK +include $(PLATFORM_PATH)/thrift.dep +include $(PLATFORM_PATH)/hal-server.dep +include $(PLATFORM_PATH)/hal-client.dep +include $(PLATFORM_PATH)/sai.dep +include $(PLATFORM_PATH)/docker-syncd-otn-kvm.dep +include $(PLATFORM_PATH)/platform-modules-otn-kvm.dep +include $(PLATFORM_PATH)/sonic-version.dep +include $(PLATFORM_PATH)/one-image.dep +include $(PLATFORM_PATH)/onie.dep +include $(PLATFORM_PATH)/kvm-image.dep +include $(PLATFORM_PATH)/raw-image.dep + diff --git a/platform/otn-kvm/rules.mk b/platform/otn-kvm/rules.mk new file mode 100644 index 00000000000..3f84c76a7f8 --- /dev/null +++ b/platform/otn-kvm/rules.mk @@ -0,0 +1,19 @@ +include $(PLATFORM_PATH)/thrift.mk +include $(PLATFORM_PATH)/hal-server.mk +include $(PLATFORM_PATH)/hal-client.mk +include $(PLATFORM_PATH)/sai.mk +include $(PLATFORM_PATH)/docker-syncd-otn-kvm.mk +include $(PLATFORM_PATH)/platform-modules-otn-kvm.mk +include $(PLATFORM_PATH)/sonic-version.mk +include $(PLATFORM_PATH)/one-image.mk +include $(PLATFORM_PATH)/onie.mk +include $(PLATFORM_PATH)/kvm-image.mk +include $(PLATFORM_PATH)/raw-image.mk + +SONIC_ALL += $(SONIC_ONE_IMAGE) $(SONIC_KVM_IMAGE) $(SONIC_RAW_IMAGE) + +# Inject otn-kvm sai into syncd +$(SYNCD)_DEPENDS += $(OTN_KVM_LIBSAI_DEB) $(LIBSAIMETADATA_DEV) + +# Inject otn-kvm hal dependency library into pmon +$(DOCKER_PLATFORM_MONITOR)_DEPENDS += $(OTN_KVM_THRIFT_PYTHON3_DEB) $(OTN_KVM_HALCLIENT_DEB) diff --git a/platform/otn-kvm/sai.dep b/platform/otn-kvm/sai.dep new file mode 100644 index 00000000000..c7a38fdcfde --- /dev/null +++ b/platform/otn-kvm/sai.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(OTN_KVM_LIBSAI_DEB)_CACHE_MODE := none diff --git a/platform/otn-kvm/sai.mk b/platform/otn-kvm/sai.mk new file mode 100644 index 00000000000..95ccf291c26 --- /dev/null +++ b/platform/otn-kvm/sai.mk @@ -0,0 +1,5 @@ +LIBSAI_VERSION = 1.1.0 +OTN_KVM_LIBSAI_DEB = libsai-mlx-$(LIBSAI_VERSION)-amd64.deb +$(OTN_KVM_LIBSAI_DEB)_URL = "https://raw.githubusercontent.com/sonic-molex/sonic-libmlx/refs/heads/otn/$(OTN_KVM_LIBSAI_DEB)" + +SONIC_ONLINE_DEBS += $(OTN_KVM_LIBSAI_DEB) diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/LICENSE b/platform/otn-kvm/sonic-platform-modules-otn-kvm/LICENSE new file mode 100644 index 00000000000..d159169d105 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/README.md b/platform/otn-kvm/sonic-platform-modules-otn-kvm/README.md new file mode 100644 index 00000000000..4510743f0d8 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/README.md @@ -0,0 +1,4 @@ +OTN-KVM Platform Support for SONiC +================================ + +SONiC platform monitoring implementation for OTN-KVM virtual hardware. diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/changelog b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/changelog new file mode 100644 index 00000000000..54ef9d88c62 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/changelog @@ -0,0 +1,4 @@ +sonic-otn-kvm-platform-modules (1.0) unstable; urgency=low + * Initial release: Support SONiC platform API for OTN-KVM. + + -- Molex Fri, 10 Feb 2023 16:00:00 +0800 diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/compat b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/compat new file mode 100644 index 00000000000..f599e28b8ab --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/compat @@ -0,0 +1 @@ +10 diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/control b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/control new file mode 100644 index 00000000000..9e47a78c2a8 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/control @@ -0,0 +1,10 @@ +Source: sonic-otn-kvm-platform-modules +Section: main +Priority: extra +Maintainer: Molex +Build-Depends: debhelper (>= 9), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-otn-kvm-ols-v +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/rules b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/rules new file mode 100755 index 00000000000..500e095d36c --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/rules @@ -0,0 +1,37 @@ +#!/usr/bin/make -f + +export INSTALL_MOD_DIR:=extra + +PACKAGE_PRE_NAME := sonic-platform-otn-kvm +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +MODULE_DIRS:= ols-v + +%: + dh $@ --with python3 + +override_dh_auto_build: + (for mod in $(MODULE_DIRS); do \ + cd $(MOD_SRC_DIR)/$${mod}; \ + if [ -f setup.py ]; then \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ + echo "Finished making whl package for $$mod"; \ + fi; \ + cd $(MOD_SRC_DIR); \ + done) + +override_dh_auto_install: + (for mod in $(MODULE_DIRS); do \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python3 setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + cd $(MOD_SRC_DIR); \ + done) + +override_dh_usrlocal: + +override_dh_pysupport: + +override_dh_clean: + dh_clean + diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/sonic-platform-otn-kvm-ols-v.install b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/sonic-platform-otn-kvm-ols-v.install new file mode 100644 index 00000000000..d3d8fba15bc --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/debian/sonic-platform-otn-kvm-ols-v.install @@ -0,0 +1 @@ +ols-v/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-otn-kvm_x86_64-r0 diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/setup.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/setup.py new file mode 100644 index 00000000000..df7f02fd74f --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup + +setup( + name='sonic_platform', + version='1.0', + description='SONiC platform API implementation on OTN-KVM Platforms', + license='Apache 2.0', + author='Molex', + author_email='lu.mao@molex.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Molex', + maintainer_email='lu.mao@molex.com', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC OTN platform PLATFORM', +) + diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/__init__.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/__init__.py new file mode 100644 index 00000000000..4a5c0ad8927 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis", "module", "fan", "fan_drawer", "psu", "thermal"] +from sonic_platform import * diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/chassis.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/chassis.py new file mode 100644 index 00000000000..88355e677f5 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/chassis.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python + +############################################################################# +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platformi information +# +############################################################################# + + +try: + import os + import re + import time + from sonic_py_common import device_info + from sonic_platform_base.device_base import DeviceBase + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.component import Component + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.module import Module + from sonic_platform.psu import Psu + from sonic_platform.thermal import Thermal + from sonic_platform.watchdog import Watchdog + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Chassis(ChassisBase): + """ + OTN-KVM Platform-specific Chassis class + """ + + def __init__(self): + + ChassisBase.__init__(self) + + # Initialize HAL + if not Initialize(): + print('HAL init failed.') + + # Get chassis device list + self.desc = device_info.get_platform_json_data() + + # module + for item in self.desc['chassis']['modules']: + module = Module(item) + self._module_list.append(module) + + fandrawer = FanDrawer(self.desc['chassis']['fan_drawers']) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + for item in self.desc['chassis']['psus']: + psu = Psu(item) + self._psu_list.append(psu) + + for item in self.desc['chassis']['thermals']: + thermal = Thermal(item) + self._thermal_list.append(thermal) + + for item in self.desc['chassis']['components']: + component = Component(item) + self._component_list.append(component) + + def __del__(self): + Destroy() + + def get_name(self): + """ + Retrieves the hardware product name for the chassis + + Returns: + A string containing the hardware product name for this chassis. + """ + return self.desc['chassis']['name'] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + return ChassisGetModel() + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + return ChassisGetSerial() + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return ChassisGetRevision() + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return ChassisGetBaseMac() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + + return None + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + return ChassisBase.REBOOT_CAUSE_NON_HARDWARE + + def get_supervisor_slot(self): + """ + Retrieves the physical-slot of the supervisor-module in the modular + chassis. On the supervisor or line-card modules, it will return the + physical-slot of the supervisor-module. + + On the fixed-platforms, the API can be ignored. + + Users of the API can catch the exception and return a default + ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. + + Returns: + An integer, the vendor specific physical slot identifier of the + supervisor module in the modular-chassis. + """ + return ChassisGetSlot() + + def get_my_slot(self): + """ + Retrieves the physical-slot of this module in the modular chassis. + On the supervisor, it will return the physical-slot of the supervisor + module. On the linecard, it will return the physical-slot of the + linecard module where this instance of SONiC is running. + + On the fixed-platforms, the API can be ignored. + + Users of the API can catch the exception and return a default + ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. + + Returns: + An integer, the vendor specific physical slot identifier of this + module in the modular-chassis. + """ + return ChassisGetSlot() + + def is_modular_chassis(self): + """ + Retrieves whether the sonic instance is part of modular chassis + + Returns: + A bool value, should return False by default or for fixed-platforms. + Should return True for supervisor-cards, line-cards etc running as part + of modular-chassis. + """ + return ChassisIsModular() + + def init_midplane_switch(self): + """ + Initializes the midplane functionality of the modular chassis. For + example, any validation of midplane, populating any lookup tables etc + can be done here. The expectation is that the required kernel modules, + ip-address assignment etc are done before the pmon, database dockers + are up. + + Returns: + A bool value, should return True if the midplane initialized + successfully. + """ + return True + + def get_module_index(self, module_name): + """ + Retrieves module index from the module name + + Args: + module_name: A string, prefixed by SUPERVISOR, LINE-CARD or FABRIC-CARD + Ex. SUPERVISOR0, LINE-CARD1, FABRIC-CARD5 + + Returns: + An integer, the index of the ModuleBase object in the module_list + """ + + index = 0 + for item in self._module_list: + if (item.get_name() == module_name): + break + index += 1 + + return index + + def get_thermal_manager(self): + """ + Retrieves thermal manager class on this chassis + :return: A class derived from ThermalManagerBase representing the + specified thermal manager. ThermalManagerBase is returned as default + """ + return None + + def get_port_or_cage_type(self, index): + """ + Retrieves sfp port or cage type corresponding to physical port + + Args: + index: An integer (>=0), the index of the sfp to retrieve. + The index should correspond to the physical port in a chassis. + For example:- + 1 for Ethernet0, 2 for Ethernet4 and so on for one platform. + 0 for Ethernet0, 1 for Ethernet4 and so on for another platform. + + Returns: + The masks of all types of port or cage that can be supported on the port + Types are defined in sfp_base.py + Eg. + Both SFP and SFP+ are supported on the port, the return value should be 0x0a + which is 0x02 | 0x08 + """ + return 0 + + def set_status_led(self, color): + """ + Sets the state of the system LED + + Args: + color: A string representing the color with which to set the + system LED + + Returns: + bool: True if system LED state is set successfully, False if not + """ + return ChassisSetLedState(color) + + def get_status_led(self): + """ + Gets the state of the system LED + + Returns: + A string, one of the valid LED color strings which could be vendor + specified. + """ + return ChassisGetLedState() + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + Specifically for SFP event, besides SFP plug in and plug out, + there are some other error event could be raised from SFP, when + these error happened, SFP eeprom will not be avalaible, XCVRD shall + stop to read eeprom before SFP recovered from error status. + status='2' I2C bus stuck, + status='3' Bad eeprom, + status='4' Unsupported cable, + status='5' High Temperature, + status='6' Bad cable. + """ + return (False, {}) diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/component.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/component.py new file mode 100644 index 00000000000..d448efbcc5e --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/component.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python + +######################################################################## +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in +# the platform +# +######################################################################## + +try: + import json + import os + import re + import subprocess + import tarfile + from sonic_platform_base.component_base import ComponentBase + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Component(ComponentBase): + """OTN-KVM Platform-specific Component class""" + + def __init__(self, desc): + + ComponentBase.__init__(self) + self.desc = desc + self.name = desc['name'] + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.name + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.desc['description'] + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + return ComponentGetFwVer(self.name) + + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + + Note: the firmware version will be read from image + + Args: + image_path: A string, path to firmware image + + Returns: + A string containing the available firmware version of the component + """ + return None + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + return False + + def update_firmware(self, image_path): + """ + Updates firmware of the component + + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + + Args: + image_path: A string, path to firmware image + + Returns: + Boolean False if image_path doesn't exist instead of throwing an exception error + Nothing when the update is successful + + Raises: + RuntimeError: update failed + """ + return True + + def auto_update_firmware(self, image_path, boot_type): + """ + Updates firmware of the component + + This API performs firmware update automatically based on boot_type: it assumes firmware installation + and/or creating a loading task during the reboot, if needed, in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically during the reboot. + The loading task will be created by API. + + Args: + image_path: A string, path to firmware image + boot_type: A string, reboot type following the upgrade + - none/fast/warm/cold + + Returns: + Output: A return code + return_code: An integer number, status of component firmware auto-update + - return code of a positive number indicates successful auto-update + - status_installed = 1 + - status_updated = 2 + - status_scheduled = 3 + - return_code of a negative number indicates failed auto-update + - status_err_boot_type = -1 + - status_err_image = -2 + - status_err_unknown = -3 + + Raises: + RuntimeError: auto-update failure cause + """ + return 1 diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan.py new file mode 100644 index 00000000000..7c98ca52eab --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python + +######################################################################## +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## + +import os.path + +try: + from sonic_platform_base.device_base import DeviceBase + from sonic_platform_base.fan_base import FanBase + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Fan(FanBase): + """OTN-KVM Platform-specific Fan class""" + + def __init__(self, desc): + FanBase.__init__(self) + + self.desc = desc + self.name = desc['name'] + + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + In OTN-KVM platforms, + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + + return FanGetDirection(self.name) + + def get_speed(self): + """ + Retrieves the speed of fan + Returns: + int: percentage of the max fan speed + """ + + return FanGetSpeed(self.name) + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + return FanGetTargetSpeed(self.name) + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + + return FanGetSpeedTolerance(self.name) + + def set_speed(self, speed): + """ + Set fan speed to expected value + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + bool: True if set success, False if fail. + """ + # Fan speeds are controlled by Smart-fussion FPGA. + return FanSetSpeed(self.name, speed) + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # No LED available for FanTray and PSU Fan + # Return True to avoid thermalctld alarm. + return FanSetLedState(self.name, color) + + def get_status_led(self): + """ + Gets the state of the Fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + + return FanGetLedState(self.name) + + def get_name(self): + """ + Retrieves the fan name + Returns: + string: The name of the device + """ + + return self.name + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + + return FanGetModel(self.name) + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + + return FanGetSerial(self.name) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + + return FanGetPresence(self.name) + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + + return FanGetStatus(self.name) + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return FanGetPositionInParent(self.name) + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return FanIsReplaceable(self.name) + diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan_drawer.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan_drawer.py new file mode 100644 index 00000000000..4762e22227e --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/fan_drawer.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +######################################################################## +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + import os + from sonic_platform_base.device_base import DeviceBase + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + """OTN-KVM Platform-specific Fan Drawer class""" + + def __init__(self, desc): + FanDrawerBase.__init__(self) + + self.desc = desc + self.name = desc['name'] + + for item in desc['fans']: + fan = Fan(item) + self._fan_list.append(fan) + + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Leds are controlled by Smart-fussion FPGA. + # Return True to avoid thermalctld alarm. + return FanDrawerSetLedState(self.name, color) + + def get_status_led(self): + """ + Gets the state of the Fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + return FanDrawerGetLedState(self.name) + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by Fan Drawer + + Returns: + A float, with value of the maximum consumable power of the + component. + """ + return None + + def get_name(self): + """ + Retrieves the fan name + Returns: + string: The name of the device + """ + return self.name diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/module.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/module.py new file mode 100644 index 00000000000..acd9b8e375c --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/module.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +######################################################################## +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Modules' information which are available in the platform +# +######################################################################## + + +try: + import os + from sonic_platform_base.module_base import ModuleBase + from sonic_platform.component import Component + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Module(ModuleBase): + """OTN-KVM Platform-specific Module class""" + + def __init__(self, desc): + ModuleBase.__init__(self) + + self.desc = desc + self.name = desc['name'] + for item in desc['components']: + component = Component(item) + self._component_list.append(component) + + def get_base_mac(self): + """ + Retrieves the base MAC address for the module + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + + return ModuleGetBaseMac(self.name) + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the module + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + return None + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.name + + def get_description(self): + """ + Retrieves the platform vendor's product description of the module + + Returns: + A string, providing the vendor's product description of the module. + """ + return self.desc['description'] + + def get_slot(self): + """ + Retrieves the platform vendor's slot number of the module + + Returns: + An integer, indicating the slot number in the chassis + """ + return ModuleGetSlot(self.name) + + def get_type(self): + """ + Retrieves the type of the module. + + Returns: + A string, the module-type from one of the predefined types: + MODULE_TYPE_SUPERVISOR, MODULE_TYPE_LINE or MODULE_TYPE_FABRIC + """ + return ModuleGetType(self.name) + + def get_oper_status(self): + """ + Retrieves the operational status of the module + + Returns: + A string, the operational status of the module from one of the + predefined status values: MODULE_STATUS_EMPTY, MODULE_STATUS_OFFLINE, + MODULE_STATUS_FAULT, MODULE_STATUS_PRESENT or MODULE_STATUS_ONLINE + """ + return ModuleGetStatus(self.name) + + def reboot(self, reboot_type): + """ + Request to reboot the module + + Args: + reboot_type: A string, the type of reboot requested from one of the + predefined reboot types: MODULE_REBOOT_DEFAULT, MODULE_REBOOT_CPU_COMPLEX, + or MODULE_REBOOT_FPGA_COMPLEX + + Returns: + bool: True if the request has been issued successfully, False if not + """ + return False + + + def set_admin_state(self, up): + """ + Request to keep the card in administratively up/down state. + The down state will power down the module and the status should show + MODULE_STATUS_OFFLINE. + The up state will take the module to MODULE_STATUS_FAULT or + MODULE_STAUS_ONLINE states. + + Args: + up: A boolean, True to set the admin-state to UP. False to set the + admin-state to DOWN. + + Returns: + bool: True if the request has been issued successfully, False if not + """ + return False + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by this module + + Returns: + A float, with value of the maximum consumable power of the + module. + """ + return None diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/platform.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/platform.py new file mode 100644 index 00000000000..0bed294e78d --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/platform.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """ + OTN-KVM Platform-specific class + """ + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() + diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/psu.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/psu.py new file mode 100644 index 00000000000..73f4f7fbe8c --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/psu.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python + +######################################################################## +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs' information which are available in the platform +# +######################################################################## + + +try: + import os + from sonic_platform_base.device_base import DeviceBase + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Psu(PsuBase): + """OTN-KVM Platform-specific PSU class""" + + def __init__(self, desc): + PsuBase.__init__(self) + # PSU is 1-based in OTN-KVM platforms + self.desc = desc + self.name = desc['name'] + + for item in desc['fans']: + fan = Fan(item) + self._fan_list.append(fan) + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + + return self.name + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + + return PsuGetVoltage(self.name) + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + + return PsuGetCurrent(self.name) + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + + return PsuGetPower(self.name) + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + + Returns: + A boolean, True if PSU has stablized its output voltages and + passed all its internal self-tests, False if not. + """ + + return PsuGetStatus(self.name) + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the + PSU status LED + Returns: + bool: True if status LED state is set successfully, False if + not + """ + + return PsuSetLedState(self.name, color) + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + + return PsuGetLedState(self.name) + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + + Returns: + A float number of current temperature in Celsius up to + nearest thousandth of one degree Celsius, e.g. 30.125 + """ + + return PsuGetTemp(self.name) + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + + Returns: + A float number, the high threshold temperature of PSU in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + return 90.0 + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + voltage_high_threshold = 12.5 + + return voltage_high_threshold + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + voltage_low_threshold = 11.5 + + return voltage_low_threshold + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + psu_maxpower = 120.0 + + return psu_maxpower + + def get_psu_power_warning_suppress_threshold(self): + """ + Retrieve the warning suppress threshold of the power on this PSU + The value can be volatile, so the caller should call the API each time it is used. + + Returns: + A float number, the warning suppress threshold of the PSU in watts. + """ + return 120.0 + + def get_psu_power_critical_threshold(self): + """ + Retrieve the critical threshold of the power on this PSU + The value can be volatile, so the caller should call the API each time it is used. + + Returns: + A float number, the critical threshold of the PSU in watts. + """ + return 120.0 + + def get_input_voltage(self): + """ + Retrieves current PSU voltage input + + Returns: + A float number, the input voltage in volts, + e.g. 12.1 + """ + + return PsuGetInputVoltage(self.name) + + def get_input_current(self): + """ + Retrieves the input current draw of the power supply + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + + return PsuGetInputCurrent(self.name) + + def get_presence(self): + """ + Retrieves the presence of the Power Supply Unit (PSU) + + Returns: + bool: True if PSU is present, False if not + """ + + return PsuGetPresence(self.name) + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + + return PsuGetModel(self.name) + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + + return PsuGetSerial(self.name) + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + + return PsuGetRevision(self.name) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return PsuIsReplaceable(self.name) diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/sfp.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/sfp.py new file mode 100644 index 00000000000..b6c2f9c7534 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/sfp.py @@ -0,0 +1,365 @@ +#!/usr/bin/env python + +############################################################################# +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import syslog + import time + from sonic_platform_base.sfp_base import SfpBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 + + +class Sfp(SfpBase): + """ + OTN-KVM Platform-specific Sfp class + """ + + def __init__(self, index): + SfpBase.__init__(self) + self.index = index + 1 + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ================================================================================ + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + type_abbrv_name |1*255VCHAR |type of SFP, abbreviated + hardware_rev |1*255VCHAR |hardware version of SFP + vendor_rev |1*255VCHAR |vendor revision of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ================================================================================ + """ + return None + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + return None + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + return None + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + + Returns: + A Boolean, True if reset enabled, False if disabled + """ + return True + + def get_rx_los(self): + """ + Retrieves the RX LOS (loss-of-signal) status of SFP + + Returns: + A list of boolean values, representing the RX LOS status + of each available channel, value is True if SFP channel + has RX LOS, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + return [True, True, True, True] + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A list of boolean values, representing the TX fault status + of each available channel, value is True if SFP channel + has TX fault, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + return [True, True, True, True] + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + return [True, True, True, True] + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + return 0x5 + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + return True + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + return True + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + A float representing the current temperature in Celsius + """ + return 40.5 + + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + A float representing the supply voltage in mV + """ + return 5001.1 + + def get_tx_bias(self): + """ + Retrieves the TX bias current of all SFP channels + + Returns: + A list of floats, representing TX bias in mA + for each available channel + E.g., for a tranceiver with four channels: ['110.09', '111.12', '108.21', '112.09'] + """ + return ['110.09', '111.12', '108.21', '112.09'] + + def get_rx_power(self): + """ + Retrieves the received optical power of all SFP channels + + Returns: + A list of floats, representing received optical + power in mW for each available channel + E.g., for a tranceiver with four channels: ['1.77', '1.71', '1.68', '1.70'] + """ + return ['1.77', '1.71', '1.68', '1.70'] + + def get_tx_power(self): + """ + Retrieves the TX power of all SFP channels + + Returns: + A list of floats, representing TX power in mW + for each available channel + E.g., for a tranceiver with four channels: ['1.86', '1.86', '1.86', '1.86'] + """ + return ['1.86', '1.86', '1.86', '1.86'] + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + return True + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + + Returns: + A boolean, True if successful, False if not + """ + return True + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + return True + + def read_eeprom(self, offset, num_bytes): + """ + read eeprom specfic bytes beginning from a random offset with size as num_bytes + + Args: + offset : + Integer, the offset from which the read transaction will start + num_bytes: + Integer, the number of bytes to be read + + Returns: + bytearray, if raw sequence of bytes are read correctly from the offset of size num_bytes + None, if the read_eeprom fails + """ + return None + + def write_eeprom(self, offset, num_bytes, write_buffer): + """ + write eeprom specfic bytes beginning from a random offset with size as num_bytes + and write_buffer as the required bytes + + Args: + offset : + Integer, the offset from which the read transaction will start + num_bytes: + Integer, the number of bytes to be written + write_buffer: + bytearray, raw bytes buffer which is to be written beginning at the offset + + Returns: + a Boolean, true if the write succeeded and false if it did not succeed. + """ + return True + + def get_error_description(self): + """ + Retrives the error descriptions of the SFP module + + Returns: + String that represents the current error descriptions of vendor specific errors + In case there are multiple errors, they should be joined by '|', + like: "Bad EEPROM|Unsupported cable" + """ + return "Bad EEPROM|Unsupported cable" diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/thermal.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/thermal.py new file mode 100644 index 00000000000..169ac0d146d --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/thermal.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python + +######################################################################## +# OTN-KVM +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## + + +try: + import os + from sonic_platform_base.thermal_base import ThermalBase + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Thermal(ThermalBase): + """OTN-KVM Platform-specific Thermal class""" + + + def __init__(self, desc): + ThermalBase.__init__(self) + self.desc = desc + self.name = desc['name'] + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + + return self.name + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + + Returns: + A float number of current temperature in Celsius up to + nearest thousandth of one degree Celsius, e.g. 30.125 + """ + + return ThermalGetTemp(self.name) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + + Returns: + A float number, the high threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + + return ThermalGetHighThreshold(self.name) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + + Returns: + A float number, the low threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + + return ThermalGetLowThreshold(self.name) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + + return ThermalSetHighThreshold(self.name, temperature) + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + + return ThermalSetLowThreshold(self.name, temperature) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of + thermal in Celsius up to nearest thousandth of one degree + Celsius, e.g. 30.125 + """ + + return ThermalGetHighCriticalThreshold(self.name) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + + Returns: + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + + return ThermalGetLowCriticalThreshold(self.name) + + def set_high_critical_threshold(self, temperature): + """ + Sets the critical high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + + Returns: + A boolean, True if threshold is set successfully, False if not + """ + + return ThermalSetHighCriticalThreshold(self.name, temperature) + + def set_low_critical_threshold(self, temperature): + """ + Sets the critical low threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + + Returns: + A boolean, True if threshold is set successfully, False if not + """ + + return ThermalSetLowCriticalThreshold(self.name, temperature) + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + + return ThermalGetMinimumRecorded(self.name) + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + + return ThermalGetMaximumRecorded(self.name) diff --git a/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/watchdog.py b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/watchdog.py new file mode 100644 index 00000000000..82db8188792 --- /dev/null +++ b/platform/otn-kvm/sonic-platform-modules-otn-kvm/ols-v/sonic_platform/watchdog.py @@ -0,0 +1,71 @@ +######################################################################## +# +# OTN-KVM +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +try: + from sonic_platform_base.watchdog_base import WatchdogBase + from HalPlatformApi.client import * +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Watchdog(WatchdogBase): + """ + Abstract base class for interfacing with a hardware watchdog module + """ + + def __init__(self): + print("INFO: Watchdog __init__") + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* available + value. + + Returns: + An integer specifying the *actual* number of seconds the watchdog + was armed with. On failure returns -1. + """ + print("ERROR: Platform did not implement arm()") + return -1 + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + print("ERROR: Platform did not implement disarm()") + return False + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + print("ERROR: Platform did not implement is_armed()") + return False + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds remaining on + the watchdog timer + + Returns: + An integer specifying the number of seconds remaining on thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + print("ERROR: Platform did not implement get_remaining_time()") + return -1 diff --git a/platform/otn-kvm/sonic-version.dep b/platform/otn-kvm/sonic-version.dep new file mode 100644 index 00000000000..1398415bdad --- /dev/null +++ b/platform/otn-kvm/sonic-version.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(SONIC_VERSION)_CACHE_MODE := none diff --git a/platform/otn-kvm/sonic-version.mk b/platform/otn-kvm/sonic-version.mk new file mode 100644 index 00000000000..9e21573227b --- /dev/null +++ b/platform/otn-kvm/sonic-version.mk @@ -0,0 +1,13 @@ +# sonic version yml file + +sonic_version=$(SONIC_GET_VERSION) +sonic_asic_platform=$(CONFIGURED_PLATFORM) + +export sonic_version +export sonic_asic_platform + +SONIC_VERSION = sonic_version.yml +$(SONIC_VERSION)_SRC_PATH = $(PLATFORM_PATH)/sonic-version +SONIC_MAKE_FILES += $(SONIC_VERSION) + +SONIC_PHONY_TARGETS += $(addprefix $(FILES_PATH)/, $(SONIC_VERSION)) diff --git a/platform/otn-kvm/sonic-version/Makefile b/platform/otn-kvm/sonic-version/Makefile new file mode 100644 index 00000000000..2b2386031c9 --- /dev/null +++ b/platform/otn-kvm/sonic-version/Makefile @@ -0,0 +1,10 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = sonic_version.yml + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + ./build_sonic_version.sh $(MAIN_TARGET) + + mv $(MAIN_TARGET) $(DEST)/ diff --git a/platform/otn-kvm/sonic-version/build_sonic_version.sh b/platform/otn-kvm/sonic-version/build_sonic_version.sh new file mode 100644 index 00000000000..2e3d5c42fb4 --- /dev/null +++ b/platform/otn-kvm/sonic-version/build_sonic_version.sh @@ -0,0 +1,8 @@ +export build_version="${sonic_version}" +export asic_type="${sonic_asic_platform}" +export commit_id="$(git rev-parse --short HEAD)" +export branch="$(git rev-parse --abbrev-ref HEAD)" +export build_date="$(date -u)" +export build_number="${BUILD_NUMBER:-0}" +export built_by="$USER@$BUILD_HOSTNAME" +j2 sonic_version.yml.j2 > $1 diff --git a/platform/otn-kvm/sonic-version/sonic_version.yml.j2 b/platform/otn-kvm/sonic-version/sonic_version.yml.j2 new file mode 120000 index 00000000000..2bbebeb2254 --- /dev/null +++ b/platform/otn-kvm/sonic-version/sonic_version.yml.j2 @@ -0,0 +1 @@ +../../../files/build_templates/sonic_version.yml.j2 \ No newline at end of file diff --git a/platform/otn-kvm/thrift.dep b/platform/otn-kvm/thrift.dep new file mode 100644 index 00000000000..372e0f1f1dd --- /dev/null +++ b/platform/otn-kvm/thrift.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(OTN_KVM_THRIFT_LIB_DEB)_CACHE_MODE := none diff --git a/platform/otn-kvm/thrift.mk b/platform/otn-kvm/thrift.mk new file mode 100644 index 00000000000..45379112590 --- /dev/null +++ b/platform/otn-kvm/thrift.mk @@ -0,0 +1,15 @@ +OTN_KVM_THRIFT_ROOT_URL = https://raw.githubusercontent.com/sonic-molex/sonic-libmlx/refs/heads/main + +OTN_KVM_THRIFT_LIB_DEB = libthrift_14_amd64.deb +$(OTN_KVM_THRIFT_LIB_DEB)_URL = "$(OTN_KVM_THRIFT_ROOT_URL)/$(OTN_KVM_THRIFT_LIB_DEB)" + +OTN_KVM_THRIFT_LIB_DEV_DEB = libthrift-dev_14_amd64.deb +$(OTN_KVM_THRIFT_LIB_DEV_DEB)_URL = "$(OTN_KVM_THRIFT_ROOT_URL)/$(OTN_KVM_THRIFT_LIB_DEV_DEB)" + +OTN_KVM_PYTHON3_SIX_DEB = python3-six_1.16.0-4_all.deb +$(OTN_KVM_PYTHON3_SIX_DEB)_URL = "$(OTN_KVM_THRIFT_ROOT_URL)/$(OTN_KVM_PYTHON3_SIX_DEB)" + +OTN_KVM_THRIFT_PYTHON3_DEB = python3-thrift_14_amd64.deb +$(OTN_KVM_THRIFT_PYTHON3_DEB)_URL = "$(OTN_KVM_THRIFT_ROOT_URL)/$(OTN_KVM_THRIFT_PYTHON3_DEB)" + +SONIC_ONLINE_DEBS += $(OTN_KVM_THRIFT_LIB_DEB) $(OTN_KVM_THRIFT_LIB_DEV_DEB) $(OTN_KVM_PYTHON3_SIX_DEB) $(OTN_KVM_THRIFT_PYTHON3_DEB) diff --git a/rules/config b/rules/config index 11cdd18f2b9..948c5008c7d 100644 --- a/rules/config +++ b/rules/config @@ -70,7 +70,7 @@ DEFAULT_PASSWORD = YourPaSsWoRd # SONIC_USE_PDDF_FRAMEWORK - Use PDDF generic drivers and plugins # Uncomment next line to enable: -SONIC_USE_PDDF_FRAMEWORK = y +SONIC_USE_PDDF_FRAMEWORK = n # SONIC_ROUTING_STACK - specify the routing-stack being elected to drive SONiC's control-plane. # Supported routing stacks on SONiC are: @@ -137,7 +137,7 @@ INCLUDE_SYSTEM_TELEMETRY = n INCLUDE_ICCPD = n # INCLUDE_SFLOW - build docker-sflow for sFlow support -INCLUDE_SFLOW = y +INCLUDE_SFLOW = n # INCLUDE_MGMT_FRAMEWORK - build docker-sonic-mgmt-framework for CLI and REST server support INCLUDE_MGMT_FRAMEWORK = y @@ -150,10 +150,10 @@ ENABLE_HOST_SERVICE_ON_START = y INCLUDE_RESTAPI ?= n # INCLUDE_NAT - build docker-nat for nat support -INCLUDE_NAT = y +INCLUDE_NAT = n # INCLUDE_DHCP_RELAY - build and install dhcp-relay package -INCLUDE_DHCP_RELAY = y +INCLUDE_DHCP_RELAY = n # INCLUDE_DHCP_SERVER - build and install dhcp-server package INCLUDE_DHCP_SERVER ?= n @@ -167,7 +167,7 @@ endif INCLUDE_P4RT = n # ENABLE_AUTO_TECH_SUPPORT - Enable the configuration for event-driven techsupport & coredump mgmt feature -ENABLE_AUTO_TECH_SUPPORT = y +ENABLE_AUTO_TECH_SUPPORT = n # ENABLE_TRANSLIB_WRITE - Enable translib write/config operations via the gNMI interface. # Uncomment to enable: @@ -177,16 +177,16 @@ ENABLE_AUTO_TECH_SUPPORT = y ENABLE_NATIVE_WRITE = y # INCLUDE_MACSEC - build docker-macsec for macsec support -INCLUDE_MACSEC = y +INCLUDE_MACSEC = n # INCLUDE_GBSYNCD - build docker-gbsyncd-* for gearbox support -INCLUDE_GBSYNCD ?= y +INCLUDE_GBSYNCD ?= n # INCLUDE_TEAMD - build docker-teamd for LAG protocol support -INCLUDE_TEAMD ?= y +INCLUDE_TEAMD ?= n # INCLUDE_ROUTER_ADVERTISER - build docker-router-advertiser for router advertisements support -INCLUDE_ROUTER_ADVERTISER ?= y +INCLUDE_ROUTER_ADVERTISER ?= n # INCLUDE_KUBERNETES - if set to y kubernetes packages are installed to be able to # run as worker node in kubernetes cluster. @@ -297,7 +297,7 @@ REGISTRY_SERVER_PATH ?= BUILD_MULTIASIC_KVM = n # INCLUDE_MUX - build docker-mux for dual ToR (Gemini) -INCLUDE_MUX = y +INCLUDE_MUX = n # ENABLE_ASAN - enable address sanitizer ENABLE_ASAN ?= n @@ -313,7 +313,7 @@ ENABLE_BOOTCHART = n # INCLUDE_FIPS - support FIPS feature, only for amd64 or arm64, armhf not supported yet # ENABLE_FIPS - support FIPS flag, if enabled, no additional config requred for the image to support FIPS -INCLUDE_FIPS ?= y +INCLUDE_FIPS ?= n ENABLE_FIPS ?= n # SONIC_SLAVE_DOCKER_DRIVER - set the sonic slave docker storage driver diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index 0b79fd936a0..d672ef5574d 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -23,6 +23,7 @@ $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_XCVRD_PY3) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_YCABLED_PY3) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_CHASSISD_PY3) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_STORMOND_PY3) +$(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(SONIC_LINECARDSYNCD_PY3) ifeq ($(PDDF_SUPPORT),y) $(DOCKER_PLATFORM_MONITOR)_PYTHON_WHEELS += $(PDDF_PLATFORM_API_BASE_PY3) diff --git a/rules/sonic-linecardsyncd.dep b/rules/sonic-linecardsyncd.dep new file mode 100644 index 00000000000..6b424b9fb0f --- /dev/null +++ b/rules/sonic-linecardsyncd.dep @@ -0,0 +1,10 @@ +SPATH := $($(SONIC_LINECARDSYNCD_PY3)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-linecardsyncd.mk rules/sonic-linecardsyncd.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files)) + +$(SONIC_LINECARDSYNCD_PY3)_CACHE_MODE := GIT_CONTENT_SHA +$(SONIC_LINECARDSYNCD_PY3)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(SONIC_LINECARDSYNCD_PY3)_DEP_FILES := $(DEP_FILES) +$(SONIC_LINECARDSYNCD_PY3)_SMDEP_FILES := $(SMDEP_FILES) +$(SONIC_LINECARDSYNCD_PY3)_SMDEP_PATHS := $(SPATH) diff --git a/rules/sonic-linecardsyncd.mk b/rules/sonic-linecardsyncd.mk new file mode 100644 index 00000000000..1b0a55b4846 --- /dev/null +++ b/rules/sonic-linecardsyncd.mk @@ -0,0 +1,8 @@ +# sonic-linecardsyncd (SONiC Chassis mgmt daemon) wheel package + +SONIC_LINECARDSYNCD_PY3 = sonic_linecardsyncd-1.0-py3-none-any.whl +$(SONIC_LINECARDSYNCD_PY3)_SRC_PATH = $(SRC_PATH)/sonic-platform-daemons/sonic-linecardsyncd +$(SONIC_LINECARDSYNCD_PY3)_DEPENDS = $(SONIC_PY_COMMON_PY3) $(SONIC_PLATFORM_COMMON_PY3) +$(SONIC_LINECARDSYNCD_PY3)_DEBS_DEPENDS = $(LIBSWSSCOMMON) $(PYTHON3_SWSSCOMMON) +$(SONIC_LINECARDSYNCD_PY3)_PYTHON_VERSION = 3 +SONIC_PYTHON_WHEELS += $(SONIC_LINECARDSYNCD_PY3) diff --git a/scripts/build_mirror_config.sh b/scripts/build_mirror_config.sh index 8b06866f9cf..08fec08e305 100755 --- a/scripts/build_mirror_config.sh +++ b/scripts/build_mirror_config.sh @@ -25,7 +25,12 @@ if [ "$ARCHITECTURE" == "armhf" ]; then DEFAULT_MIRROR_SECURITY_URLS=http://deb.debian.org/debian-security/ fi -if [ "$DISTRIBUTION" == "buster" ] || [ "$DISTRIBUTION" == "bullseye" ]; then +if [ "$DISTRIBUTION" == "buster" ]; then + DEFAULT_MIRROR_URLS=http://archive.debian.org/debian/ + DEFAULT_MIRROR_SECURITY_URLS=http://archive.debian.org/debian-security +fi + +if [ "$DISTRIBUTION" == "bullseye" ]; then DEFAULT_MIRROR_URLS=http://archive.debian.org/debian/ fi diff --git a/src/sonic-eventd/Makefile b/src/sonic-eventd/Makefile index 835d0732a0c..bc03d63c49d 100644 --- a/src/sonic-eventd/Makefile +++ b/src/sonic-eventd/Makefile @@ -1,12 +1,16 @@ RM := rm -rf EVENTD_TARGET := eventd EVENTD_TEST := tests/tests +EVENTDB_TEST := tests/eventdb EVENTD_TOOL := tools/events_tool EVENTD_PUBLISH_TOOL := tools/events_publish_tool.py RSYSLOG-PLUGIN_TARGET := rsyslog_plugin/rsyslog_plugin RSYSLOG-PLUGIN_TEST := rsyslog_plugin_tests/tests EVENTD_MONIT := tools/events_monit_test.py EVENTD_MONIT_CONF := tools/monit_events +EVENTDB_TARGET := eventdb +EVENTDB_DEFAULT_PROFILE := var/evprofile/default.json +EVENTDB_PROF := etc/eventd.json CP := cp MKDIR := mkdir @@ -19,7 +23,7 @@ PWD := $(shell pwd) ifneq ($(MAKECMDGOALS),clean) ifneq ($(strip $(C_DEPS)),) --include $(C_DEPS) $(OBJS) +-include $(C_DEPS) $(OBJS) $(EVENTDB_OBJS) endif endif @@ -29,7 +33,7 @@ endif -include rsyslog_plugin/subdir.mk -include rsyslog_plugin_tests/subdir.mk -all: sonic-eventd eventd-tests eventd-tool rsyslog-plugin rsyslog-plugin-tests +all: sonic-eventd eventd-tests eventd-tool rsyslog-plugin rsyslog-plugin-tests sonic-eventdb eventdb-tests sonic-eventd: $(OBJS) @echo 'Building target: $@' @@ -38,6 +42,13 @@ sonic-eventd: $(OBJS) @echo 'Finished building target: $@' @echo ' ' +sonic-eventdb: $(EVENTDB_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: G++ Linker' + $(CC) $(LDFLAGS) -o $(EVENTDB_TARGET) $(EVENTDB_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + eventd-tool: $(TOOL_OBJS) @echo 'Building target: $@' @echo 'Invoking: G++ Linker' @@ -45,6 +56,15 @@ eventd-tool: $(TOOL_OBJS) @echo 'Finished building target: $@' @echo ' ' +eventdb-tests: $(EVENTDB_TEST_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: G++ Linker' + $(CC) $(LDFLAGS) -o $(EVENTDB_TEST) $(EVENTDB_TEST_OBJS) $(LIBS) $(TEST_LIBS) + @echo 'Finished building target: $@' + $(EVENTDB_TEST) + @echo 'Finished running tests' + @echo ' ' + rsyslog-plugin: $(RSYSLOG-PLUGIN_OBJS) @echo 'Buidling Target: $@' @echo 'Invoking: G++ Linker' @@ -73,12 +93,16 @@ rsyslog-plugin-tests: $(RSYSLOG-PLUGIN-TEST_OBJS) install: $(MKDIR) -p $(DESTDIR)/usr/bin $(MKDIR) -p $(DESTDIR)/etc/monit/conf.d + $(MKDIR) -p $(DESTDIR)/etc/evprofile $(CP) $(EVENTD_TARGET) $(DESTDIR)/usr/bin $(CP) $(EVENTD_TOOL) $(DESTDIR)/usr/bin $(CP) $(EVENTD_PUBLISH_TOOL) $(DESTDIR)/usr/bin $(CP) $(RSYSLOG-PLUGIN_TARGET) $(DESTDIR)/usr/bin $(CP) $(EVENTD_MONIT) $(DESTDIR)/usr/bin $(CP) $(EVENTD_MONIT_CONF) $(DESTDIR)/etc/monit/conf.d + $(CP) $(EVENTDB_TARGET) $(DESTDIR)/usr/bin + $(CP) $(EVENTDB_PROF) $(DESTDIR)/etc/eventd.json + $(CP) $(EVENTDB_DEFAULT_PROFILE) $(DESTDIR)/etc/evprofile/default.json deinstall: $(RM) -rf $(DESTDIR)/usr diff --git a/src/sonic-eventd/debian/sonic-eventd.install b/src/sonic-eventd/debian/sonic-eventd.install index bdba566c77b..273b07adf18 100644 --- a/src/sonic-eventd/debian/sonic-eventd.install +++ b/src/sonic-eventd/debian/sonic-eventd.install @@ -1,3 +1,6 @@ usr/bin/eventd +usr/bin/eventdb usr/bin/events_tool usr/bin/events_publish_tool.py +etc/evprofile/default.json +etc/eventd.json diff --git a/src/sonic-eventd/etc/eventd.json b/src/sonic-eventd/etc/eventd.json new file mode 100644 index 00000000000..ee441eb329f --- /dev/null +++ b/src/sonic-eventd/etc/eventd.json @@ -0,0 +1,5 @@ +{ + "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records.", + "max-records": 40000, + "max-days": 30 +} diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp new file mode 100644 index 00000000000..46b49877ea8 --- /dev/null +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -0,0 +1,669 @@ + +#include +#include +#include +#include +#include +#include "eventconsume.h" +#include "loghandler.h" +#include "eventutils.h" +#include "events_common.h" + + +using namespace std::chrono; + +// map to store sequence-id for alarms +unordered_map cal_lookup_map; + +// temporary map to hold merge of default map of events and any event profile +EventMap static_event_table; + +std::atomic reload_config_flag(false); // Definition and initialization + +bool g_run = true; +uint64_t seq_id = 0; +uint64_t PURGE_SECONDS = 86400; + +typedef pair pi; +priority_queue, greater > event_history_list; + +map SYSLOG_SEVERITY = { + {EVENT_SEVERITY_CRITICAL_STR, LOG_ALERT}, + {EVENT_SEVERITY_MAJOR_STR, LOG_CRIT}, + {EVENT_SEVERITY_MINOR_STR, LOG_ERR}, + {EVENT_SEVERITY_WARNING_STR, LOG_WARNING}, + {EVENT_SEVERITY_INFORMATIONAL_STR, LOG_NOTICE} +}; + +map SYSLOG_SEVERITY_STR = { + {LOG_ALERT , EVENT_SEVERITY_CRITICAL_STR}, + {LOG_CRIT , EVENT_SEVERITY_MAJOR_STR}, + {LOG_ERR , EVENT_SEVERITY_MINOR_STR}, + {LOG_WARNING , EVENT_SEVERITY_WARNING_STR}, + {LOG_NOTICE , EVENT_SEVERITY_INFORMATIONAL_STR} +}; + +static string flood_ev_id; +static string flood_ev_action; +static string flood_ev_resource; +static string flood_ev_msg; + +EventConsume::EventConsume(DBConnector* dbConn, + string evProfile, + string dbProfile): + m_eventTable(dbConn, EVENT_HISTORY_TABLE_NAME), + m_alarmTable(dbConn, EVENT_CURRENT_ALARM_TABLE_NAME), + m_eventStatsTable(dbConn, EVENT_STATS_TABLE_NAME), + m_alarmStatsTable(dbConn, EVENT_ALARM_STATS_TABLE_NAME), + m_evProfile(evProfile), + m_dbProfile(dbProfile) { + + // open syslog connection + openSyslog(); + + // init stats + initStats(); + + // populate local queue of event histor table + read_events(); + + // read and apply eventd configuration files + // read eventd.json and apply it on history table. + // read default and custom profiles, build static_event_table + read_eventd_config(); + + SWSS_LOG_NOTICE("DONE WITH EventConsume constructor"); +} + +EventConsume::~EventConsume() { +} + +void EventConsume::run() +{ + + SWSS_LOG_ENTER(); + event_handle_t hsub = events_init_subscriber(); + + if (hsub == nullptr) { + SWSS_LOG_ERROR("Failed to initialize event subscriber"); + return; + } + + while (g_run) { + event_receive_op_t evt; + map_str_str_t evtOp; + if (reload_config_flag.load()) { + read_eventd_config(); + reload_config_flag.store(false); + } + + int rc = event_receive(hsub, evt); + if (rc != 0) { + SWSS_LOG_ERROR("Failed to receive rc=%d", rc); + continue; + } + handle_notification(evt); + } + events_deinit_subscriber(hsub); +} + +void EventConsume::read_eventd_config(bool read_all) { + // read manifest file for config options + if (read_all) { + read_config_and_purge(); + } + + // read from default map + static_event_table.clear(); + if (!parse(m_evProfile.c_str(), static_event_table)) { + SWSS_LOG_INFO("Can not initialize event map"); + closeSyslog(); + exit(0); + } + + SWSS_LOG_NOTICE("Event map is built as follows:"); + for (auto& x: static_event_table) { + SWSS_LOG_NOTICE(" %s (%s %s %s)", x.first.c_str(), x.second.severity.c_str(), x.second.enable.c_str(), x.second.static_event_msg.c_str()); + } +} + + +void EventConsume::handle_notification(const event_receive_op_t& evt) +{ + string ev_id, ev_msg, ev_src, ev_act, ev_timestamp, ev_type("EVENT"), + ev_static_msg(""), ev_reckey; + string ev_sev = string(EVENT_SEVERITY_INFORMATIONAL_STR); + bool is_raise = false; + bool is_clear = false; + bool is_ack = false; + vector vec; + + fetchFieldValues(evt, vec, ev_id, ev_msg, ev_src, ev_act, ev_timestamp); + + // flood protection. If a rogue application sends same event repeatedly, throttle repeated instances of that event + if (isFloodedEvent(ev_src, ev_act, ev_id, ev_msg)) { + return; + } + + // get static info + if (!staticInfoExists(ev_id, ev_act, ev_sev, ev_static_msg, vec)) { + return; + } + + // increment save seq-id for the newly received event + uint64_t new_seq_id = seq_id + 1; + + FieldValueTuple seqfv("id", to_string(new_seq_id)); + vec.push_back(seqfv); + + if (ev_act.length() > 0) { + SWSS_LOG_DEBUG("ev_act %s", ev_act.c_str()); + ev_type = "ALARM"; + string almkey = ev_id; + if (!ev_src.empty()) { + almkey += "|" + ev_src; + } + + if (ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) { + is_raise = true; + // add entry to the lookup map + cal_lookup_map.insert(make_pair(almkey, new_seq_id)); + + // add acknowledged field intializing it to false + FieldValueTuple seqfv1("acknowledged", "false"); + vec.push_back(seqfv1); + m_alarmTable.set(to_string(new_seq_id), vec); + + // update alarm counters + updateAlarmStatistics(ev_sev, ev_act); + } else if (ev_act.compare(EVENT_ACTION_CLEAR_STR) == 0) { + is_clear = true; + SWSS_LOG_DEBUG(" Received clear alarm for %s", almkey.c_str()); + + bool ack_flag = false; + // remove entry from local cache, alarm table + if (!udpateLocalCacheAndAlarmTable(almkey, ack_flag)) { + SWSS_LOG_ERROR("Received clear for non-existent alarm %s", almkey.c_str()); + return; + } + + // update alarm counters ONLY if it has not been ack'd before. + // This is because when alarm is ack'd, alarms/severity counter is reduced already. + if (!ack_flag) { + updateAlarmStatistics(ev_sev, ev_act); + } else { + // if it has been ack'd before, ack counter would have been incremented for this alrm. + // Now is the time reduce it. + clearAckAlarmStatistic(); + } + } else { + // ack/unack events comes with seq-id of raised alarm as resource field. + // fetch details of "raised" alarm record + string raise_act; + string raise_ack_flag; + string raise_ts; + + // fetch information from raised event record + if (!fetchRaiseInfo(vec, ev_src, ev_id, ev_sev, raise_act, raise_ack_flag, raise_ts)) + { + SWSS_LOG_ERROR("Action %s on a non-existent Alarm id %s", ev_act.c_str(), ev_src.c_str()); + return; + } + + if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { + if (raise_ack_flag.compare("true") == 0) { + SWSS_LOG_INFO("%s/%s is already acknowledged", ev_id.c_str(), ev_src.c_str()); + return; + } + if (raise_act.compare(EVENT_ACTION_RAISE_STR) == 0) { + is_ack = true; + SWSS_LOG_DEBUG("Received acknowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); + + // update the record with ack flag and ack-time and stats + updateAckInfo(is_ack, ev_timestamp, ev_sev, ev_act, ev_src); + } else { + SWSS_LOG_ERROR("Alarm %s/%s not in RAISE state", ev_id.c_str(), ev_src.c_str()); + return; + } + } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { + if (raise_ack_flag.compare("true") == 0) { + SWSS_LOG_DEBUG(" received un-ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); + + // update the record with ack flag and ack-time and stats + updateAckInfo(is_ack, ev_timestamp, ev_sev, ev_act, ev_src); + } else { + SWSS_LOG_INFO(" %s/%s is already un-acknowledged", ev_id.c_str(), ev_src.c_str()); + return; + } + } + } + } + // verify the size of history table; delete older entry; add new entry + seq_id = new_seq_id; + update_events(to_string(seq_id), ev_timestamp, vec); + + updateEventStatistics(true, is_raise, is_ack, is_clear); + + // raise a syslog message + writeToSyslog(ev_id.c_str(), (int)(SYSLOG_SEVERITY.find(ev_sev)->second), ev_type.c_str(), ev_act.c_str(), + ev_src.c_str(), ev_msg.c_str(), ev_static_msg.c_str()); + + return; +} + +void EventConsume::read_events() { + vector tuples; + m_eventTable.getContent(tuples); + + SWSS_LOG_ENTER(); + // find out last sequence-id; build local history list + for (auto tuple: tuples) { + for (auto fv: kfvFieldsValues(tuple)) { + if (fvField(fv) == "time-created") { + char* end; + uint64_t seq = strtoull(kfvKey(tuple).c_str(), &end,10); + if (seq > seq_id) { + seq_id = seq; + } + uint64_t val = strtoull(fvValue(fv).c_str(), &end,10); + event_history_list.push(make_pair( seq, val )); + } + } + } + SWSS_LOG_NOTICE("eventd sequence-id intialized to %lu", seq_id); +} + +void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { + vector vec; + vector temp; + + // severity counter names are of lower case + transform(ev_sev.begin(), ev_sev.end(), ev_sev.begin(), ::tolower); + + if (m_alarmStatsTable.get("state", vec)) { + for (auto fv: vec) { + if (!fv.first.compare("alarms")) { + if ((ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) || (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0)) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } else if (!fv.first.compare(ev_sev)) { + if ((ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) || (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0)) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } else if (!fv.first.compare("acknowledged")) { + if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } + m_alarmStatsTable.set("state", temp); + } else { + SWSS_LOG_ERROR("Can not update alarm statistics (table does not exist)"); + } +} + +void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack, bool is_clear) { + vector vec; + vector temp; + + if (m_eventStatsTable.get("state", vec)) { + for (auto fv: vec) { + if (!fv.first.compare("events")) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } else if (!fv.first.compare("raised")) { + if (is_raise) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } else if (!fv.first.compare("cleared")) { + if (is_clear) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } else if (!fv.first.compare("acked")) { + if (is_ack) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } + } + + m_eventStatsTable.set("state", temp); + } else { + SWSS_LOG_ERROR("Can not update event statistics (table does not exist)"); + } +} + +void EventConsume::modifyEventStats(string seq_id) { + vector rec; + m_eventTable.get(seq_id, rec); + bool is_raise = false; + bool is_clear = false; + bool is_ack = false; + for (auto fvr: rec) { + if (!fvr.first.compare("action")) { + if (!fvr.second.compare(EVENT_ACTION_RAISE_STR)) { + is_raise = true; + } else if (!fvr.second.compare(EVENT_ACTION_CLEAR_STR)) { + is_clear = true; + } + } + if (!fvr.first.compare("acknowledged")) { + if (!fvr.second.compare("true")) { + is_ack = true; + } + } + } + updateEventStatistics(false, is_raise, is_ack, is_clear); +} + +void EventConsume::purge_events() { + + uint32_t size = event_history_list.size(); + + while (size >= m_count) { + pair oldest_entry = event_history_list.top(); + SWSS_LOG_NOTICE("Rollover based on count(%d/%d). Deleting %lu", size, m_count, oldest_entry.first); + m_eventTable.del(to_string(oldest_entry.first)); + modifyEventStats(to_string(oldest_entry.first)); + event_history_list.pop(); + --size; + } + + const auto p1 = system_clock::now(); + unsigned tnow_seconds = duration_cast(p1.time_since_epoch()).count(); + + while (!event_history_list.empty()) { + pair oldest_entry = event_history_list.top(); + unsigned old_seconds = oldest_entry.second / 1000000000ULL; + + if ((tnow_seconds - old_seconds) > PURGE_SECONDS) { + SWSS_LOG_NOTICE("Rollover based on time (%lu days). Deleting %lu.. now %u old %u", (PURGE_SECONDS/m_days), oldest_entry.second, tnow_seconds, old_seconds); + m_eventTable.del(to_string(oldest_entry.first)); + modifyEventStats(to_string(oldest_entry.first)); + event_history_list.pop(); + } else { + return; + } + } + return; +} + +void EventConsume::read_config_and_purge() { + m_days = 0; + m_count = 0; + // read from the manifest file + parse_config(m_dbProfile.c_str(), m_days, m_count); + SWSS_LOG_NOTICE("max-days %d max-records %d", m_days, m_count); + + // update the nanosecond limit + PURGE_SECONDS *= m_days; + + // purge events based on # of days + purge_events(); +} + +void EventConsume::update_events(string seq_id, string ts, vector vec) { + // purge events based on # of days + purge_events(); + + // now add the event to the event table + m_eventTable.set(seq_id, vec); + + // store it into the event history list + char* end; + uint64_t seq = strtoull(seq_id.c_str(), &end, 10); + uint64_t val = strtoull(ts.c_str(), &end, 10); + event_history_list.push(make_pair( seq, val )); +} + +void EventConsume::resetAlarmStats(int alarms, int critical, int major, int minor, int warning, int acknowledged) { + vector temp; + FieldValueTuple fv; + map::iterator it; + for (it = SYSLOG_SEVERITY_STR.begin(); it != SYSLOG_SEVERITY_STR.end(); it++) { + // there wont be any informational alarms + if (it->second.compare(EVENT_SEVERITY_CRITICAL_STR) == 0) { + fv = FieldValueTuple("critical", to_string(critical)); + temp.push_back(fv); + } else if (it->second.compare(EVENT_SEVERITY_MAJOR_STR) == 0) { + fv = FieldValueTuple("major", to_string(major)); + temp.push_back(fv); + } else if (it->second.compare(EVENT_SEVERITY_MINOR_STR) == 0) { + fv = FieldValueTuple("minor", to_string(minor)); + temp.push_back(fv); + } else if (it->second.compare(EVENT_SEVERITY_WARNING_STR) == 0) { + fv = FieldValueTuple("warning", to_string(warning)); + temp.push_back(fv); + } + } + fv = FieldValueTuple("alarms", to_string(alarms)); + temp.push_back(fv); + fv = FieldValueTuple("acknowledged", to_string(acknowledged)); + temp.push_back(fv); + m_alarmStatsTable.set("state", temp); +} + +void EventConsume::clearAckAlarmStatistic() { + vector vec; + vector temp; + + if (m_alarmStatsTable.get("state", vec)) { + for (auto fv: vec) { + if (!fv.first.compare("acknowledged")) { + fv.second = to_string(stoi(fv.second.c_str())-1); + temp.push_back(fv); + m_alarmStatsTable.set("state", temp); + return; + } + } + } +} + + +void EventConsume::fetchFieldValues(const event_receive_op_t& evt, + vector& vec, + string& ev_id, + string& ev_msg, + string& ev_src, + string& ev_act, + string &ev_timestamp) { + + ev_timestamp = to_string(evt.publish_epoch_ms); + vec.push_back(FieldValueTuple("time-created", ev_timestamp)); + for (const auto& idx : evt.params) { + if (idx.first == "type-id") { + ev_id = idx.second; + vec.push_back(FieldValueTuple("type-id", ev_id)); + } else if (idx.first == "text") { + ev_msg = idx.second; + vec.push_back(FieldValueTuple("text", ev_msg)); + } else if (idx.first == "resource") { + ev_src = idx.second; + vec.push_back(idx); + } else if (idx.first == "action") { + ev_act = idx.second; + // for events, action is empty + if (!ev_act.empty()) { + vec.push_back(FieldValueTuple("action", ev_act)); + } + } + } +} + +bool EventConsume::isFloodedEvent(string ev_src, string ev_act, string ev_id, string ev_msg) { + // flood protection. If a rogue application sends same event repeatedly, throttle repeated instances of that event + if (!flood_ev_resource.compare(ev_src) && + !flood_ev_action.compare(ev_act) && + !flood_ev_id.compare(ev_id) && + !(flood_ev_msg.compare(ev_msg))) { + SWSS_LOG_INFO("Ignoring the event %s from %s action %s msg %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str(), ev_msg.c_str()); + return true; + } + + flood_ev_resource = ev_src; + flood_ev_action = ev_act; + flood_ev_id = ev_id; + flood_ev_msg = ev_msg; + return false; +} + +bool EventConsume::staticInfoExists(string &ev_id, string &ev_act, string &ev_sev, string &ev_static_msg, vector &vec) { + auto it = static_event_table.find(ev_id); + if (it != static_event_table.end()) { + EventInfo tmp = (EventInfo) (it->second); + // discard the event as event_static_map shows enable is false for this event + if (tmp.enable == EVENT_ENABLE_FALSE_STR) { + SWSS_LOG_NOTICE("Discarding event <%s> as it is set to disabled", ev_id.c_str()); + return false;; + } + + // get severity in the map and store it in the db + ev_sev = tmp.severity; + ev_static_msg = tmp.static_event_msg; + SWSS_LOG_DEBUG("static info: <%s> <%s> ", tmp.severity.c_str(), tmp.static_event_msg.c_str()); + + FieldValueTuple seqfv1("severity", tmp.severity); + vec.push_back(seqfv1); + return true; + } else { + // dont process the incoming alarms if action is neither raise nor clear + // for ack/unack, no need for this check + if ((ev_act.compare(EVENT_ACTION_ACK_STR) && ev_act.compare(EVENT_ACTION_UNACK_STR))) { + // TODO currently, applications may raise events but default evprofile doesnt contain + // ID info. This is planned for later. + // Change it back to SWSS_LOG_ERROR once event profile contains event-ids + SWSS_LOG_DEBUG("static info NOT FOUND for <%s> ", ev_id.c_str()); + return false; + } + } + return true; +} + +bool EventConsume::udpateLocalCacheAndAlarmTable(string almkey, bool &ack_flag) { + // find and remove the raised alarm + uint64_t lookup_seq_id = 0; + auto it = cal_lookup_map.find(almkey); + if (it != cal_lookup_map.end()) { + lookup_seq_id = (uint64_t) (it->second); + cal_lookup_map.erase(almkey); + + // get status of is_aknowledged flag so that we dont decrement counters twice + vector alm_rec; + m_alarmTable.get(to_string(lookup_seq_id), alm_rec); + for (auto fvr: alm_rec) { + if (!fvr.first.compare("acknowledged")) { + ack_flag = (fvr.second.compare("true") == 0) ? true : false; + break; + } + } + + // delete the record from alarm table + m_alarmTable.del(to_string(lookup_seq_id)); + } else { + // possible - when event profile removes alarms for which enable is false and application cleared them later. + // ignore by logging a debug message.. + SWSS_LOG_INFO("Received alarm-clear for non-existing alarm %s", almkey.c_str()); + return false; + } + return true; +} + +void EventConsume::initStats() { + vector vec; + // possible after a cold-boot or very first time + if (! m_eventStatsTable.get("state", vec)) { + FieldValueTuple fv; + vector temp; + + SWSS_LOG_DEBUG("resetting Event Statistics table"); + fv = FieldValueTuple("events", to_string(0)); + temp.push_back(fv); + fv = FieldValueTuple("raised", to_string(0)); + temp.push_back(fv); + fv = FieldValueTuple("cleared", to_string(0)); + temp.push_back(fv); + fv = FieldValueTuple("acked", to_string(0)); + temp.push_back(fv); + m_eventStatsTable.set("state", temp); + } + if (! m_alarmStatsTable.get("state", vec)) { + SWSS_LOG_DEBUG("resetting Alarm Statistics table"); + resetAlarmStats(0, 0, 0, 0, 0, 0); + } +} + +void EventConsume::updateAckInfo(bool is_ack, string ev_timestamp, string ev_sev, string ev_act, string ev_src) { + vector ack_vec; + + FieldValueTuple seqfv1("acknowledged", (is_ack ? "true" : "false")); + ack_vec.push_back(seqfv1); + + FieldValueTuple seqfv2("acknowledge-time", ev_timestamp); + ack_vec.push_back(seqfv2); + + // update alarm stats + updateAlarmStatistics(ev_sev, ev_act); + + // update alarm/event tables for the "raise" record with ack flag and ack timestamp + // for ack/unack, ev_src contains the "seq-id" + m_alarmTable.set(ev_src, ack_vec); + m_eventTable.set(ev_src, ack_vec); +} + + +bool EventConsume::fetchRaiseInfo(vector &vec, string ev_src, string &ev_id, string &ev_sev, string &raise_act, + string &raise_ack_flag, string &raise_ts) { + vector raise_vec; + if (!m_alarmTable.get(ev_src, raise_vec)) { + return false; + } + for (auto fv: raise_vec) { + if (!fv.first.compare("type-id")) { + ev_id = fv.second; + vec.push_back(fv); + } + if (!fv.first.compare("severity")) { + ev_sev = fv.second; + vec.push_back(fv); + } + if (!fv.first.compare("action")) { + raise_act = fv.second; + } + if (!fv.first.compare("acknowledged")) { + raise_ack_flag = fv.second; + } + if (!fv.first.compare("time-created")) { + raise_ts = fv.second; + } + } + return true; +} + + diff --git a/src/sonic-eventd/src/eventconsume.h b/src/sonic-eventd/src/eventconsume.h new file mode 100644 index 00000000000..ec5d8510679 --- /dev/null +++ b/src/sonic-eventd/src/eventconsume.h @@ -0,0 +1,56 @@ +#ifndef __EVENTCONSUME_H__ +#define __EVENTCONSUME_H__ + +#include +#include +#include "events.h" +#include "eventutils.h" +#include "dbconnector.h" +#include "subscriberstatetable.h" + +using namespace swss; +using namespace std; + +extern std::atomic reload_config_flag; + +class EventConsume +{ +public: + EventConsume(DBConnector *dbConn, + string evProfile =EVENTD_DEFAULT_MAP_FILE, + string dbProfile =EVENTD_CONF_FILE); + ~EventConsume(); + void read_eventd_config(bool read_all=true); + void run(); + +private: + Table m_eventTable; + Table m_alarmTable; + Table m_eventStatsTable; + Table m_alarmStatsTable; + u_int32_t m_days, m_count; + string m_evProfile; + string m_dbProfile; + + void handle_notification(const event_receive_op_t& evt); + void read_events(); + void updateAlarmStatistics(string ev_sev, string ev_act); + void updateEventStatistics(bool is_add, bool is_alarm, bool is_ack, bool is_clear); + void read_config_and_purge(); + void update_events(string seq_id, string ts, vector vec); + void purge_events(); + void modifyEventStats(string seq_id); + void clearAckAlarmStatistic(); + void resetAlarmStats(int, int, int, int, int, int); + void fetchFieldValues(const event_receive_op_t& evt , vector &, string &, string &, string &, string &, string &); + bool isFloodedEvent(string, string, string, string); + bool staticInfoExists(string &, string &, string &, string &, vector &); + bool udpateLocalCacheAndAlarmTable(string, bool &); + void initStats(); + void updateAckInfo(bool, string, string, string, string); + bool fetchRaiseInfo(vector &, string, string &, string &, string &, string &, string &); +}; + + +#endif /* __EVENTCONSUME_H__ */ + diff --git a/src/sonic-eventd/src/eventdb.cpp b/src/sonic-eventd/src/eventdb.cpp new file mode 100644 index 00000000000..96aaf10630a --- /dev/null +++ b/src/sonic-eventd/src/eventdb.cpp @@ -0,0 +1,29 @@ +#include "eventconsume.h" +#include + +static EventConsume *evtd_instance = NULL; + +void signalHandler(const int signal) { + + if (signal == SIGINT) { + reload_config_flag.store(true); + } +} + +int main() +{ + swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); + + swss::DBConnector eventDb("EVENT_DB", 0); + + // register signal SIGINT and signal handler + signal(SIGINT, signalHandler); + + EventConsume evtd(&eventDb); + evtd_instance = &evtd; + + evtd.run(); + + return 0; +} + diff --git a/src/sonic-eventd/src/eventutils.cpp b/src/sonic-eventd/src/eventutils.cpp new file mode 100644 index 00000000000..94a80bd4ba2 --- /dev/null +++ b/src/sonic-eventd/src/eventutils.cpp @@ -0,0 +1,103 @@ +#include "eventutils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "logger.h" +#include "table.h" + +using namespace swss; +using namespace std; + +using json = nlohmann::json; + +bool isValidSeverity(string severityStr) { + transform(severityStr.begin(), severityStr.end(), severityStr.begin(), ::toupper); + if (severityStr == EVENT_SEVERITY_MAJOR_STR) return true; + if (severityStr == EVENT_SEVERITY_CRITICAL_STR) return true; + if (severityStr == EVENT_SEVERITY_MINOR_STR) return true; + if (severityStr == EVENT_SEVERITY_WARNING_STR) return true; + if (severityStr == EVENT_SEVERITY_INFORMATIONAL_STR) return true; + return false; +} + +bool isValidEnable(string enableStr) { + if (enableStr == EVENT_ENABLE_TRUE_STR) return true; + if (enableStr == EVENT_ENABLE_FALSE_STR) return true; + return false; +} + +bool parse_config(const char *filename, unsigned int& days, unsigned int& count) { + days = EHT_MAX_DAYS; + count = EHT_MAX_ELEMS; + std::ifstream ifs(filename); + + if (!ifs.is_open()) { + std::cerr << "Failed to open file: " << filename << std::endl; + return false; + } + + json j; + try { + j = json::parse(ifs); + } + catch (const std::exception &e) { + SWSS_LOG_ERROR("Error parsing config file %s:%s ", filename, e.what()); + return false; + } + for (json::iterator it = j.begin(); it != j.end(); ++it) { + if(it.key() == "max-days") { + days = it.value(); + } + if(it.key() == "max-records") { + count = it.value(); + } + } + return true; +} + +bool parse(const char *filename, EventMap& tmp_event_table) { + ifstream file(filename); + if (!file.is_open()) { + SWSS_LOG_ERROR("Failed to open file: %s", filename); + return false; + } + + json j; + try { + file >> j; + } + catch (const std::exception &e) { + SWSS_LOG_ERROR("Error parsing profile file %s:%s ", filename, e.what()); + return false; + } + + if (!j.contains("events") || j["events"].empty()) { + SWSS_LOG_NOTICE("No entries in 'events' field in %s", filename); + return false; + } + + + for (const auto& elem : j["events"]) { + if (!elem.contains("name") || !elem.contains("severity") || + !elem.contains("enable")) { + SWSS_LOG_ERROR("Missing required fields in event entry in %s", filename); + continue; + } + struct EventInfo_t ev_info; + string ev_name = elem["name"]; + ev_info.severity = elem["severity"]; + ev_info.enable = elem["enable"]; + if (elem.contains("message")) { + ev_info.static_event_msg = elem["message"]; + } + tmp_event_table.emplace(ev_name, ev_info); + } + + return true; +} + diff --git a/src/sonic-eventd/src/eventutils.h b/src/sonic-eventd/src/eventutils.h new file mode 100644 index 00000000000..c835eeda01a --- /dev/null +++ b/src/sonic-eventd/src/eventutils.h @@ -0,0 +1,42 @@ +#ifndef __EVENTUTILS_H__ +#define __EVENTUTILS_H__ + +#include +#include + +const std::string EVENT_SEVERITY_CRITICAL_STR = "CRITICAL"; +const std::string EVENT_SEVERITY_MAJOR_STR = "MAJOR"; +const std::string EVENT_SEVERITY_MINOR_STR = "MINOR"; +const std::string EVENT_SEVERITY_WARNING_STR = "WARNING"; +const std::string EVENT_SEVERITY_INFORMATIONAL_STR = "INFORMATIONAL"; + +const std::string EVENT_ENABLE_TRUE_STR = "true"; +const std::string EVENT_ENABLE_FALSE_STR = "false"; + +const std::string EVENT_ACTION_RAISE_STR = "RAISE"; +const std::string EVENT_ACTION_CLEAR_STR = "CLEAR"; +const std::string EVENT_ACTION_ACK_STR = "ACKNOWLEDGE"; +const std::string EVENT_ACTION_UNACK_STR = "UNACKNOWLEDGE"; + +constexpr char EVENTD_DEFAULT_MAP_FILE[] = "/etc/evprofile/default.json"; + +constexpr size_t EHT_MAX_ELEMS = 40000; +constexpr size_t EHT_MAX_DAYS = 30; +constexpr char EVENTD_CONF_FILE[] = "/etc/eventd.json"; + +typedef struct EventInfo_t { + std::string severity; + std::string enable; + std::string static_event_msg; +} EventInfo; + +//unordered_map static_event_table; +typedef std::unordered_map EventMap; + +bool isValidSeverity(std::string severityStr); +bool isValidEnable(std::string enableStr); +bool parse_config(const char *filename, unsigned int& days, unsigned int& count); +bool parse(const char *filename, EventMap& tmp_event_table); + +#endif + diff --git a/src/sonic-eventd/src/loghandler.cpp b/src/sonic-eventd/src/loghandler.cpp new file mode 100644 index 00000000000..b5f47fe8c22 --- /dev/null +++ b/src/sonic-eventd/src/loghandler.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + + + +// Safe fallback for null or empty C-style strings +const char* safe(const char* s) { + return (s && std::strlen(s) > 0) ? s : ""; +} + + +extern "C" void openSyslog() { + openlog (NULL, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL4); +} + +extern "C" void writeToSyslog(char* ev_id, int ev_sev, char* ev_type, char* ev_act, + char* ev_src, char* ev_msg, char* ev_static_msg) { + int SYSLOG_FACILITY = LOG_LOCAL4; + + if (!ev_act || std::strlen(ev_act) == 0) { + const char LOG_FORMAT[] = "[%s], %%%s: %%%%%s: %s %s"; + // event Type + // Event Name + // Event Source + // Static Desc + // Dynamic Desc + + // raise a syslog message + syslog(LOG_MAKEPRI(ev_sev, SYSLOG_FACILITY), LOG_FORMAT, + safe(ev_type), safe(ev_id), safe(ev_src), safe(ev_static_msg), safe(ev_msg)); + } else { + const char LOG_FORMAT[] = "[%s] (%s), %%%s: %%%%%s: %s %s"; + // event Type + // event action + // Event Name + // Event Source + // Static Desc + // Dynamic Desc + // raise a syslog message + syslog(LOG_MAKEPRI(ev_sev, SYSLOG_FACILITY), LOG_FORMAT, + safe(ev_type), safe(ev_act), safe(ev_id), safe(ev_src), safe(ev_static_msg), safe(ev_msg)); + } +} + +extern "C" void closeSyslog() { + closelog (); +} + diff --git a/src/sonic-eventd/src/loghandler.h b/src/sonic-eventd/src/loghandler.h new file mode 100644 index 00000000000..cf642df909f --- /dev/null +++ b/src/sonic-eventd/src/loghandler.h @@ -0,0 +1,8 @@ +#include +extern "C" void openSyslog(); +extern "C" void writeToSyslog(const char* ev_id, int ev_sev, const char* ev_type, + const char* ev_act, const char* ev_src, const char* ev_msg, + const char* ev_static_msg); +extern "C" void closeSyslog(); + + diff --git a/src/sonic-eventd/src/subdir.mk b/src/sonic-eventd/src/subdir.mk index eb067fd6e86..2363a74a7df 100644 --- a/src/sonic-eventd/src/subdir.mk +++ b/src/sonic-eventd/src/subdir.mk @@ -1,9 +1,11 @@ CC := g++ TEST_OBJS += ./src/eventd.o +EVENTDB_TEST_OBJS += ./src/eventd.o ./src/eventconsume.o ./src/eventutils.o ./src/loghandler.o OBJS += ./src/eventd.o ./src/main.o +EVENTDB_OBJS += ./src/eventdb.o ./src/eventconsume.o ./src/loghandler.o ./src/eventutils.o -C_DEPS += ./src/eventd.d ./src/main.d +C_DEPS += ./src/eventd.d ./src/main.d ./src/eventdb.d ./src/eventconsume.d ./src/loghandler.d ./src/eventutils.d src/%.o: src/%.cpp @echo 'Building file: $<' @@ -11,3 +13,4 @@ src/%.o: src/%.cpp $(CC) -D__FILENAME__="$(subst src/,,$<)" $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" @echo 'Finished building: $<' @echo ' ' + diff --git a/src/sonic-eventd/tests/default.json b/src/sonic-eventd/tests/default.json new file mode 100644 index 00000000000..4346dc400de --- /dev/null +++ b/src/sonic-eventd/tests/default.json @@ -0,0 +1,24 @@ +{ + "__README__" : "This is default map of events that eventd uses. Developer can modify this file and send SIGINT to eventd to make it read and use the updated file. Alternatively developer can test the new event by adding it to a custom event profile and use 'event profile ' command to apply that profile without having to send SIGINT to eventd. Developer need to commit default.json file with the new event after testing it out. Supported severities are: CRITICAL, MAJOR, MINOR, WARNING and INFORMATIONAL. Supported enable flag values are: true and false.", + "events":[ + { + "name": "SYSTEM_STATE", + "severity": "INFORMATIONAL", + "enable": "true", + "message" : "" + }, + { + "name": "SENSOR_TEMP_HIGH", + "severity": "WARNING", + "enable": "true", + "message" : "" + }, + { + "name": "USER_LOGIN", + "severity": "INFORMATIONAL", + "enable": "true", + "message" : "" + } + ] +} + diff --git a/src/sonic-eventd/tests/eventd.json b/src/sonic-eventd/tests/eventd.json new file mode 100644 index 00000000000..a42c44a3cc4 --- /dev/null +++ b/src/sonic-eventd/tests/eventd.json @@ -0,0 +1,6 @@ +{ + "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records.", + "max-records": 200, + "max-days": 30 +} + diff --git a/src/sonic-eventd/tests/eventdb_database_config.json b/src/sonic-eventd/tests/eventdb_database_config.json new file mode 100644 index 00000000000..e21e9c19100 --- /dev/null +++ b/src/sonic-eventd/tests/eventdb_database_config.json @@ -0,0 +1,108 @@ +{ + "INSTANCES": { + "redis":{ + "hostname" : "127.0.0.1", + "port": 6379, + "unix_socket_path": "/var/run/redis/redis.sock" + }, + "redis1":{ + "hostname" : "127.0.0.1", + "port": 6380, + "unix_socket_path": "/var/run/redis/redis1.sock" + }, + "redis2":{ + "hostname" : "127.0.0.1", + "port": 6381, + "unix_socket_path": "/var/run/redis/redis2.sock" + }, + "redis3":{ + "hostname" : "127.0.0.1", + "port": 6382, + "unix_socket_path": "/var/run/redis/redis3.sock" + }, + "redis4":{ + "hostname" : "127.0.0.1", + "port": 6383, + "unix_socket_path": "/var/run/redis/redis4.sock" + } + }, + "DATABASES" : { + "APPL_DB" : { + "id" : 0, + "separator": ":", + "instance" : "redis" + }, + "ASIC_DB" : { + "id" : 1, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB" : { + "id" : 2, + "separator": ":", + "instance" : "redis" + }, + "CONFIG_DB" : { + "id" : 4, + "separator": "|", + "instance" : "redis" + }, + "PFC_WD_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB" : { + "id" : 6, + "separator": "|", + "instance" : "redis" + }, + "SNMP_OVERLAY_DB" : { + "id" : 7, + "separator": "|", + "instance" : "redis" + }, + "RESTAPI_DB": { + "id": 8, + "separator": "|", + "instance": "redis" + }, + "GB_ASIC_DB": { + "id": 9, + "separator": ":", + "instance": "redis" + }, + "GB_COUNTERS_DB": { + "id": 10, + "separator": ":", + "instance": "redis" + }, + "GB_FLEX_COUNTER_DB": { + "id": 11, + "separator": ":", + "instance": "redis" + }, + "STATE_DB2" : { + "id" : 13, + "separator": "|", + "instance" : "redis" + }, + "APPL_STATE_DB" : { + "id" : 14, + "separator": ":", + "instance" : "redis" + }, + "EVENT_DB" : { + "id" : 15, + "separator": ":", + "instance" : "redis" + } + }, + "VERSION" : "1.0" +} + diff --git a/src/sonic-eventd/tests/eventdb_database_config_global.json b/src/sonic-eventd/tests/eventdb_database_config_global.json new file mode 100644 index 00000000000..fbf502c52bc --- /dev/null +++ b/src/sonic-eventd/tests/eventdb_database_config_global.json @@ -0,0 +1,9 @@ +{ + "INCLUDES" : [ + { + "include" : "eventdb_database_config.json" + } + ], + "VERSION" : "1.0" +} + diff --git a/src/sonic-eventd/tests/eventdb_ut.cpp b/src/sonic-eventd/tests/eventdb_ut.cpp new file mode 100644 index 00000000000..1b684b1b520 --- /dev/null +++ b/src/sonic-eventd/tests/eventdb_ut.cpp @@ -0,0 +1,435 @@ +#include +#include "gtest/gtest.h" +#include "events_common.h" +#include "events.h" +#include +#include "dbconnector.h" +#include + +#include +#include "../src/eventd.h" +#include "../src/eventconsume.h" + +using namespace std; +using namespace swss; + +extern volatile bool g_run; +extern uint64_t seq_id; +extern uint64_t PURGE_SECONDS; +extern unordered_map cal_lookup_map; +typedef pair pi; +extern priority_queue, greater > event_history_list; +extern EventMap static_event_table; + + +#define TEST_DB "APPL_DB" +#define TEST_NAMESPACE "asic0" +#define INVALID_NAMESPACE "invalid" + +//extern void run_pub(void *mock_pub, const string wr_source, internal_events_lst_t &lst); + +string existing_file = "./tests//eventdb_database_config.json"; +string nonexisting_file = "./tests//database_config_nonexisting.json"; +string global_existing_file = "./tests//eventdb_database_config_global.json"; + + + +typedef struct { + map ev_data; + string severity; +} ev_data_struct; +map, ev_data_struct> event_data_t = { + {{"SYSTEM_STATE","NOTIFY"}, + {{{"type-id","SYSTEM_STATE"}, {"resource", "system-state"}, {"text", "System Ready"}}, + "INFORMATIONAL"}}, + {{"INTERFACE_OPER_STATE", "NOTIFY"}, + {{{"type-id", "INTERFACE_OPER_STATE"}, {"resource", "Ethernet1"}, {"text", "Operational Down"}, {"state", "up"}}, + "INFORMATIONAL"}}, + {{"SENSOR_TEMP_HIGH", "RAISE"}, + {{{"type-id", "SENSOR_TEMP_HIGH"}, {"resource", "cpu_sensor"}, {"action", "RAISE"}, {"text", "sensor temp 55C, threshold temp 52C"}}, + "WARNING"}}, + {{"SENSOR_TEMP_HIGH", "CLEAR"}, + {{{"type-id", "SENSOR_TEMP_HIGH"}, {"resource", "cpu_sensor"}, {"action", "CLEAR"}, {"text", "sensor temp 50C, threshold temp 52C"}}, + "WARNING"}} +}; + + +typedef struct { + int id; + string source; + string tag; + string rid; + string seq; +} test_data_t; + +const string event_profile = "tests/default.json"; +const string event_db_profile = "tests/eventd.json"; + +void delete_evdb(DBConnector& dbConn) +{ + auto keys = dbConn.keys("*"); + for (const auto& key : keys) + { + dbConn.del(key); + } +} + +void clear_eventdb_data() +{ + g_run = true; + seq_id =0; + cal_lookup_map.clear(); + PURGE_SECONDS = 86400; + event_history_list = priority_queue, greater >(); + static_event_table.clear(); +} + +void run_pub(void *mock_pub, const string wr_source, internal_events_lst_t &lst) +{ + for(internal_events_lst_t::const_iterator itc = lst.begin(); itc != lst.end(); ++itc) { + EXPECT_EQ(0, zmq_message_send(mock_pub, wr_source, *itc)); + } +} + +class EventDbFixture : public ::testing::Test { + protected: + void SetUp() override { + zctx = zmq_ctx_new(); + EXPECT_TRUE(NULL != zctx); + + /* Run proxy to enable receive as capture test needs to receive */ + pxy = new eventd_proxy(zctx); + EXPECT_TRUE(NULL != pxy); + + /* Starting proxy */ + EXPECT_EQ(0, pxy->init()); + DBConnector eventDb("EVENT_DB", 0, true); + //delete any entries in the EVENT_DB + delete_evdb(eventDb); + evtConsume= new EventConsume(&eventDb, event_profile, event_db_profile); + consumerThread = std::thread(&EventConsume::run, evtConsume); + } + + void TearDown() override { + g_run = false; + + if (consumerThread.joinable()) { + consumerThread.join(); // Wait for clean exit + } + + delete evtConsume; + evtConsume = nullptr; + + delete pxy; + pxy= nullptr; + + zmq_ctx_term(zctx); + zctx = nullptr; + + clear_eventdb_data(); + } + EventConsume *evtConsume; + void *zctx; + eventd_proxy *pxy; + std::thread consumerThread; +}; + + +void *init_publish(void *zctx) +{ + void *mock_pub = zmq_socket (zctx, ZMQ_PUB); + EXPECT_TRUE(NULL != mock_pub); + EXPECT_EQ(0, zmq_connect(mock_pub, get_config(XSUB_END_KEY).c_str())); + + /* Provide time for async connect to complete */ + this_thread::sleep_for(chrono::milliseconds(200)); + + return mock_pub; +} + +internal_event_t create_ev(const int id, const int ev_id, const string& event, + const string& action, + map> &verify_data) +{ + internal_event_t event_data; + stringstream ss; + + test_data_t data; + data.id = id; + data.source = "source" + to_string(id); + data.tag = "tag" + to_string(id); + data.rid = "guid-" + to_string(id); + data.seq = to_string(id); + + event_data[EVENT_STR_DATA] = convert_to_json( + data.source + ":" + data.tag, map(event_data_t[make_pair(event, action)].ev_data)); + event_data[EVENT_RUNTIME_ID] = data.rid; + event_data[EVENT_SEQUENCE] = data.seq; + auto timepoint = system_clock::now(); + ss << duration_cast(timepoint.time_since_epoch()).count(); + + event_data[EVENT_EPOCH] = ss.str(); + unordered_map ev_val(event_data_t[make_pair(event, action)].ev_data.begin(), + event_data_t[make_pair(event, action)].ev_data.end()); + ev_val.insert({{"id", to_string(ev_id)}}); + ev_val.insert({{"time-created", ss.str()}}); + ev_val.insert({{"severity", event_data_t[make_pair(event, action)].severity}}); + + if (action == "RAISE") { + ev_val.insert({{"acknowledged", "false"}}); + ev_val.insert({{"action", action}}); + } + verify_data.insert({to_string(ev_id), ev_val}); + + return event_data; +} + + +void verify_events(map> verifyData) +{ + DBConnector eventDb("EVENT_DB", 0, true); + auto dbKeys = eventDb.keys("EVENT:*"); + EXPECT_EQ(verifyData.size(), dbKeys.size()); + + for (const auto& vKey : verifyData) + { + string evtKey = "EVENT:" + vKey.first; + EXPECT_TRUE(count(dbKeys.begin(), dbKeys.end(), evtKey) == 1); + auto ev = eventDb.hgetall(evtKey); + EXPECT_TRUE(ev == verifyData[vKey.first]); + } +} + + +void verify_alarms_clear(map> verifyData) +{ + DBConnector eventDb("EVENT_DB", 0, true); + auto dbKeys = eventDb.keys("ALARM:*"); + EXPECT_EQ(0, dbKeys.size()); +} + +void verify_alarms_raise(map> verifyData) +{ + DBConnector eventDb("EVENT_DB", 0, true); + auto dbKeys = eventDb.keys("ALARM:*"); + EXPECT_EQ(verifyData.size(), dbKeys.size()); + + for (const auto& vKey : verifyData) + { + string almKey = "ALARM:" + vKey.first; + EXPECT_TRUE(count(dbKeys.begin(), dbKeys.end(), almKey) == 1); + auto ev = eventDb.hgetall(almKey); + EXPECT_TRUE(ev == verifyData[vKey.first]); + } +} + +TEST_F(EventDbFixture, validate_events) +{ + printf("Validate events TEST started\n"); + + internal_events_lst_t wr_evts; + string wr_source("eventd-test"); + + void *mock_pub = init_publish(zctx); + + map> verify_data; + + wr_evts.push_back(create_ev(1, 1, "SENSOR_TEMP_HIGH", "RAISE", verify_data)); + wr_evts.push_back(create_ev(2, 2, "SYSTEM_STATE", "NOTIFY", verify_data)); + + run_pub(mock_pub, wr_source, wr_evts); + + this_thread::sleep_for(chrono::milliseconds(2000)); + + // verify events logged in DB. + verify_events(verify_data); + + //send events to close eventdb task + g_run = false; + wr_evts.clear(); + wr_evts.push_back(create_ev(301, 3, "SYSTEM_STATE", "NOTIFY", verify_data)); + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + zmq_close(mock_pub); + + printf("Validate events TEST completed\n"); + +} + + +TEST_F(EventDbFixture, validate_alarms) +{ + printf("Validate alarms TEST started\n"); + internal_events_lst_t wr_evts; + string wr_source("eventd-test"); + void *mock_pub = init_publish(zctx); + + map> verify_data; + wr_evts.push_back(create_ev(3, 1, "SENSOR_TEMP_HIGH", "RAISE", verify_data)); + + run_pub(mock_pub, wr_source, wr_evts); + + this_thread::sleep_for(chrono::milliseconds(2000)); + + // verify events logged in DB. + verify_events(verify_data); + verify_alarms_raise(verify_data); + + wr_evts.clear(); + wr_evts.push_back(create_ev(4, 2, "SENSOR_TEMP_HIGH", "CLEAR", verify_data)); + + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + verify_events(verify_data); + verify_alarms_clear(verify_data); + g_run = false; + wr_evts.clear(); + wr_evts.push_back(create_ev(302, 3, "SYSTEM_STATE", "NOTIFY", verify_data)); + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + zmq_close(mock_pub); + printf("Validate alarms TEST completed\n"); +} + + +TEST_F(EventDbFixture, expiry_purge) +{ + printf("Expiry purge TEST started\n"); + internal_events_lst_t wr_evts; + string wr_source("eventd-test"); + void *mock_pub = init_publish(zctx); + map> verify_data; + //set epoch time back to 31 days + auto timepoint = system_clock::now(); + auto epochTimeNs = duration_cast(timepoint.time_since_epoch()).count(); + epochTimeNs = epochTimeNs - (32UL * 24 * 60 * 60 * 1000 * 1000 * 1000); + auto ev_data = create_ev(5, 1, "SENSOR_TEMP_HIGH", "RAISE", verify_data); + + ev_data[EVENT_EPOCH] = to_string(epochTimeNs); + verify_data["1"]["time-created"] = ev_data[EVENT_EPOCH]; + wr_evts.push_back(ev_data); + + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + + // verify events logged in DB. + verify_events(verify_data); + verify_alarms_raise(verify_data); + + wr_evts.clear(); + verify_data.clear(); + wr_evts.push_back(create_ev(6, 2, "SENSOR_TEMP_HIGH", "CLEAR", verify_data)); + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + + verify_events(verify_data); + verify_alarms_clear(verify_data); + wr_evts.clear(); + g_run = false; + wr_evts.push_back(create_ev(303, 3, "SYSTEM_STATE", "NOTIFY", verify_data)); + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + zmq_close(mock_pub); + printf("Expiry purge TEST completed\n"); +} + + +TEST_F(EventDbFixture, rollover_purge) +{ + printf("Rollover purge TEST started\n"); + internal_events_lst_t wr_evts; + string wr_source("eventd-test"); + void *mock_pub = init_publish(zctx); + map> verify_data; + int i=0,j=6; + + for (; i <= 198; i+=2, j+=2) + { + wr_evts.push_back(create_ev(j+1, i+1, "SENSOR_TEMP_HIGH", "RAISE", verify_data)); + wr_evts.push_back(create_ev(j+2, i+2, "SENSOR_TEMP_HIGH", "CLEAR", verify_data)); + } + + run_pub(mock_pub, wr_source, wr_evts); + + this_thread::sleep_for(chrono::milliseconds(5000)); + + // verify events logged in DB. + verify_events(verify_data); + // This will make it out of limit + wr_evts.push_back(create_ev(j+1, i+1, "SENSOR_TEMP_HIGH", "RAISE", verify_data)); + run_pub(mock_pub, wr_source, wr_evts); + + this_thread::sleep_for(chrono::milliseconds(2000)); + + DBConnector eventDb("EVENT_DB", 0, true); + auto dbKeys = eventDb.keys("EVENT:*"); + EXPECT_EQ(200, dbKeys.size()); + EXPECT_TRUE(count(dbKeys.begin(), dbKeys.end(), "EVENT:1") == 0); + EXPECT_TRUE(count(dbKeys.begin(), dbKeys.end(), "EVENT:2") == 1); + EXPECT_TRUE(count(dbKeys.begin(), dbKeys.end(), "EVENT:" + to_string(i+1)) == 1); + g_run = false; + wr_evts.push_back(create_ev(303, 3, "SYSTEM_STATE", "NOTIFY", verify_data)); + run_pub(mock_pub, wr_source, wr_evts); + this_thread::sleep_for(chrono::milliseconds(2000)); + zmq_close(mock_pub); + printf("Rollover purge TEST completed\n"); +} + +class SwsscommonEnvironment : public ::testing::Environment { +public: + // Override this to define how to set up the environment + void SetUp() override { + // by default , init should be false + cout << "Default : isInit = " << SonicDBConfig::isInit() << endl; + EXPECT_FALSE(SonicDBConfig::isInit()); + EXPECT_THROW(SonicDBConfig::initialize(nonexisting_file), runtime_error); + + EXPECT_FALSE(SonicDBConfig::isInit()); + + // load local config file, init should be true + SonicDBConfig::initialize(existing_file); + cout << "INIT: load local db config file, isInit = " << SonicDBConfig::isInit() << endl; + EXPECT_TRUE(SonicDBConfig::isInit()); + + // Test the database_global.json file + // by default , global_init should be false + cout << "Default : isGlobalInit = " << SonicDBConfig::isGlobalInit() << endl; + EXPECT_FALSE(SonicDBConfig::isGlobalInit()); + + // Call an API which actually needs the data populated by SonicDBConfig::initializeGlobalConfig + // EXPECT_THROW(SonicDBConfig::getDbId(EVENT_DB, TEST_NAMESPACE), runtime_error); + + // load local global file, init should be true + SonicDBConfig::initializeGlobalConfig(global_existing_file); + cout<<"INIT: load global db config file, isInit = "<' command to apply that profile without having to send SIGINT to eventd. Developer need to commit default.json file with the new event after testing it out. Supported severities are: CRITICAL, MAJOR, MINOR, WARNING and INFORMATIONAL. Supported enable flag values are: true and false.", + "events":[ + { + "name": "SYSTEM_STATE", + "severity": "INFORMATIONAL", + "enable": "true", + "message" : "" + } + ] +} + diff --git a/src/sonic-mgmt-common b/src/sonic-mgmt-common index ec3ef8e7763..3517a5ed28a 160000 --- a/src/sonic-mgmt-common +++ b/src/sonic-mgmt-common @@ -1 +1 @@ -Subproject commit ec3ef8e7763325bbd36b5b924a3f99a8e385bb6d +Subproject commit 3517a5ed28aa4786e1b387916feee50c213867a5 diff --git a/src/sonic-mgmt-framework b/src/sonic-mgmt-framework index 2248203a476..63f17a48f63 160000 --- a/src/sonic-mgmt-framework +++ b/src/sonic-mgmt-framework @@ -1 +1 @@ -Subproject commit 2248203a47698c7598b6d745f6a1ca27813b4327 +Subproject commit 63f17a48f63884b996fab0c256274419e24e4fc6 diff --git a/src/sonic-platform-daemons b/src/sonic-platform-daemons index 60e7224c7d0..1fbe331d8c3 160000 --- a/src/sonic-platform-daemons +++ b/src/sonic-platform-daemons @@ -1 +1 @@ -Subproject commit 60e7224c7d0d398a8bbb055796d19e0a556f1916 +Subproject commit 1fbe331d8c362954a21e4e8e0739f883cdb29bc5 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 0ab1be1f889..3fa43ec3906 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 0ab1be1f8899722f46166bc64d4c597d1f9e0c89 +Subproject commit 3fa43ec39067b9bebf0568473a26192a3d6ddbf1 diff --git a/src/sonic-swss b/src/sonic-swss index a4d09dd8b28..a416871e443 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit a4d09dd8b28734cecec25fd78e16d3bd37c3cdb1 +Subproject commit a416871e443a3c9eca37ead72f6267e69a783283 diff --git a/src/sonic-swss-common b/src/sonic-swss-common index d38e6d9fc7a..57da2cbd741 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit d38e6d9fc7a62d77dc5964fea33dfd6d45b84cbe +Subproject commit 57da2cbd741afc8c28875d697f1bc09f0cdb980e diff --git a/src/sonic-utilities b/src/sonic-utilities index ac66b67e13e..dcd9d7fbdaa 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit ac66b67e13e1ffad0e7c132b256e1441b3f1bc4e +Subproject commit dcd9d7fbdaacaad1430745b51cc87167a7d1395f diff --git a/src/sonic-yang-models/yang-models/sonic-alarm.yang b/src/sonic-yang-models/yang-models/sonic-alarm.yang new file mode 100644 index 00000000000..4a6f78da1eb --- /dev/null +++ b/src/sonic-yang-models/yang-models/sonic-alarm.yang @@ -0,0 +1,144 @@ +module sonic-alarm { + + namespace "http://github.com/sonic-net/sonic-alarm"; + prefix salarm; + yang-version 1.1; + + import sonic-event { + prefix event; + } + + // meta + organization + "SONiC"; + + contact + "SONiC"; + + description + "This module defines operational state data for SONiC alarms."; + + revision "2024-01-30" { + description + "Initial revision."; + } + + + grouping alarm-state { + + leaf id { + type string; + description "Sequence identifier for an alarm."; + } + + leaf resource { + type string; + description "The item that is under alarm within the device."; + } + + leaf text { + type string; + description "Dynamic message raised with the alarm."; + } + + leaf time-created { + type uint64; + description + "The time at which the alarm was raised by the system. + Expressed in nanoseconds since Unix epoch."; + } + + leaf type-id { + type string; + description "Type of the alarm raised"; + } + + leaf severity { + type event:severity-type; + description + "Severity of a raised condition."; + } + + leaf acknowledged { + type boolean; + description + "This denotes whether an alarm is acknowledged by the operator. + An acknowledged alarm is not considered in determining the + health of the system."; + } + + leaf acknowledge-time { + type uint64; + description + "The time at which alarm is acknowledged by the system. + This value is expressed as nanoseconds since the Unix Epoch."; + } + + } + + container sonic-alarm { + + container ALARM { + + list ALARM_LIST { + key "id"; + uses alarm-state; + } + } + + container ALARM_STATS { + + + list ALARM_STATS_LIST { + + key "id"; + leaf id { + type enumeration { + enum state; + } + description + "Table identifier value defined as state."; + } + + leaf alarms { + type uint64; + description + "Total alarms in the system."; + } + + leaf critical { + type uint64; + description + "Total critical alarms in the system."; + } + + leaf major { + type uint64; + description + "Total major alarms in the system."; + } + + leaf minor { + type uint64; + description + "Total minor alarms in the system."; + } + + leaf warning { + type uint64; + description + "Total warnings in the system."; + } + + leaf acknowledged { + type uint64; + description + "Total acknowledged alarms in the system."; + } + + } + } + } +} + + diff --git a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang index f0c377048cf..60737fe368f 100644 --- a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang +++ b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang @@ -100,7 +100,7 @@ module sonic-device_metadata { leaf type { type string { length 1..255; - pattern "ToRRouter|LeafRouter|SpineChassisFrontendRouter|ChassisBackendRouter|ASIC|MgmtToRRouter|SpineRouter|BackEndToRRouter|BackEndLeafRouter|EPMS|MgmtTsToR|BmcMgmtToRRouter|SonicHost|not-provisioned"; + pattern "ToRRouter|LeafRouter|SpineChassisFrontendRouter|ChassisBackendRouter|ASIC|MgmtToRRouter|SpineRouter|BackEndToRRouter|BackEndLeafRouter|EPMS|MgmtTsToR|BmcMgmtToRRouter|SonicHost|not-provisioned|SonicOtn"; } } @@ -194,7 +194,7 @@ module sonic-device_metadata { leaf switch_type { type string { - pattern "chassis-packet|fabric|npu|voq|dpu"; + pattern "chassis-packet|fabric|npu|voq|dpu|otn"; } description "Type of switch. Default is NPU, on a VOQ switch voq is used for a regular switching device while fabric is used for a fabric device. diff --git a/src/sonic-yang-models/yang-models/sonic-event.yang b/src/sonic-yang-models/yang-models/sonic-event.yang new file mode 100644 index 00000000000..a7c4dd23743 --- /dev/null +++ b/src/sonic-yang-models/yang-models/sonic-event.yang @@ -0,0 +1,136 @@ + module sonic-event { + namespace "http://github.com/sonic-net/sonic-event"; + prefix sevents; + yang-version 1.1; + + organization + "SONiC"; + + contact + "SONiC"; + + description + "This module defines operational state data for SONiC events."; + + revision "2024-01-30" { + description + "Initial revision."; + } + + typedef severity-type { + type enumeration { + enum CRITICAL; + enum MAJOR; + enum MINOR; + enum WARNING; + enum INFORMATIONAL; + } + description + "Severity of a raised condition."; + } + + typedef action-type { + type enumeration { + enum RAISE; + enum CLEAR; + enum ACKNOWLEDGE; + enum UNACKNOWLEDGE; + } + description + "Action on a raised condition."; + } + + grouping event-state { + + leaf id { + type string; + description "Sequence identifier for events."; + } + + leaf resource { + type string; + description "The item in the device that raised the event."; + } + + leaf text { + type string; + description "Dynamic message raised with the event."; + } + + leaf time-created { + type uint64; + description + "The time at which the event was raised by the system. + Expressed in epoch time."; + } + + leaf type-id { + type string; + description "Type of event raised by the device."; + } + + leaf severity { + type severity-type; + description + "Severity of the event."; + } + + leaf action { + type action-type; + description "Action on the event."; + } + } + + container sonic-event { + + container EVENT { + + list EVENT_LIST { + key "id"; + uses event-state; + } + } + + container EVENT_STATS { + + + list EVENT_STATS_LIST { + + key "id"; + leaf id { + type enumeration { + enum state; + } + description + "Table identifier value defined as state."; + } + + leaf events { + type uint64; + description + "Total number of events in the system store."; + } + + leaf raised { + type uint64; + description + "Total number of events for raise operation in system store."; + } + + leaf acked { + type uint64; + description + "Total number of events for ack operation in system store."; + } + + leaf cleared { + type uint64; + description + "Total number of events for clear operation in system store."; + } + } + } + } + } + + diff --git a/src/sonic-yang-models/yang-models/sonic-events-common.yang b/src/sonic-yang-models/yang-models/sonic-events-common.yang index ed6c81a7b90..28bd7eaa978 100644 --- a/src/sonic-yang-models/yang-models/sonic-events-common.yang +++ b/src/sonic-yang-models/yang-models/sonic-events-common.yang @@ -21,11 +21,53 @@ module sonic-events-common { "Common reusable definitions"; } + typedef action-type { + type enumeration { + enum RAISE { + description "Event with raise alarm action."; + } + enum CLEAR { + description "Event with clear alarm action."; + } + } + description + "This type defines the actions associated with an event notification."; + } + grouping sonic-events-cmn { leaf timestamp { type yang:date-and-time; description "time of the event"; } + + leaf type-id { + type string; + description + "The abbreviated name of the event, for example FAN_SPEED_STATUS, + SYSTEM_STATUS, or PSU_FAULTY."; + } + + leaf resource { + type string; + description + "The item generating the event. for example eth1, cpu_sensor"; + } + + leaf text { + type string; + description + "The string used to inform operators about the event. This + MUST contain enough information for an operator to be able + to understand the problem. If this string contains structure, + this format should be clearly documented for programs to be + able to parse that information"; + } + + leaf action { + type action-type; + description + "This denotes the action associated with the event."; + } } grouping sonic-events-usage { From 363f4a390984b2e532a0c0bf028020ef74c61b1e Mon Sep 17 00:00:00 2001 From: Hemanth Kumar Tirupati Date: Mon, 29 Sep 2025 13:24:58 -0700 Subject: [PATCH 2/2] Fix build sources (#23962) Fix build sources --- scripts/build_mirror_config.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build_mirror_config.sh b/scripts/build_mirror_config.sh index 08fec08e305..a5e13418847 100755 --- a/scripts/build_mirror_config.sh +++ b/scripts/build_mirror_config.sh @@ -27,9 +27,9 @@ fi if [ "$DISTRIBUTION" == "buster" ]; then DEFAULT_MIRROR_URLS=http://archive.debian.org/debian/ - DEFAULT_MIRROR_SECURITY_URLS=http://archive.debian.org/debian-security + DEFAULT_MIRROR_SECURITY_URLS=http://archive.debian.org/debian-security/ fi - + if [ "$DISTRIBUTION" == "bullseye" ]; then DEFAULT_MIRROR_URLS=http://archive.debian.org/debian/ fi