Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 99 additions & 5 deletions platform/nvidia-bluefield/nasa-cli-helper/nasa-cli-helper.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
#
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -16,20 +17,112 @@
# limitations under the License.
#

import re
import sys
import argparse
import docker
import config.plugins.nvidia_bluefield as nvda_bf

try:
from sonic_py_common import device_info
except ImportError:
device_info = None

SAI_PROFILE_FILENAME = 'sai.profile'
CT_AGING_IN_SECONDS_KEY = 'CT_AGING_IN_SECONDS'
CT_AGING_DEFAULT_SECONDS = 1


def get_sai_profile_path():
"""Return path to sai.profile under device tree for current platform/HwSKU."""
if device_info is None:
return None
platform, hwsku = device_info.get_platform_and_hwsku()
if not platform or not hwsku:
return None
return f'/usr/share/sonic/device/{platform}/{hwsku}/{SAI_PROFILE_FILENAME}'


def get_aging_interval():
"""Read CT_AGING_IN_SECONDS from sai.profile. If not present, return default 1."""
sai_profile_path = get_sai_profile_path()
if not sai_profile_path:
print("Error: Could not get platform/HwSKU", file=sys.stderr)
sys.exit(1)
try:
with open(sai_profile_path, 'r') as f:
content = f.read()
except (FileNotFoundError, OSError):
return CT_AGING_DEFAULT_SECONDS

pattern = re.compile(r'^' + re.escape(CT_AGING_IN_SECONDS_KEY) + r'=(\d+)', re.MULTILINE)
match = pattern.search(content)
if match:
return int(match.group(1))
return CT_AGING_DEFAULT_SECONDS


def set_aging_interval(seconds):
"""Update CT_AGING_IN_SECONDS in sai.profile. Add line if missing, else replace."""
sai_profile_path = get_sai_profile_path()
if not sai_profile_path:
print("Error: Could not get platform/HwSKU (sonic_py_common.device_info not available or returned empty).", file=sys.stderr)
sys.exit(1)
try:
with open(sai_profile_path, 'r') as f:
content = f.read()
except FileNotFoundError:
print(f"Error: {sai_profile_path} not found.", file=sys.stderr)
sys.exit(1)
except OSError as e:
print(f"Error: Failed to read sai.profile: {e}", file=sys.stderr)
sys.exit(1)

new_line = f'{CT_AGING_IN_SECONDS_KEY}={seconds}'
pattern = re.compile(r'^.*' + re.escape(CT_AGING_IN_SECONDS_KEY) + r'=.*$', re.MULTILINE)
if pattern.search(content):
content = pattern.sub(new_line, content, count=1)
else:
content = content.rstrip()
if content and not content.endswith('\n'):
content += '\n'
content += new_line + '\n'

try:
with open(sai_profile_path, 'w') as f:
f.write(content)
except OSError as e:
print(f"Error: Failed to write sai.profile: {e}", file=sys.stderr)
sys.exit(1)

print(f"CT_AGING_IN_SECONDS has been set to {seconds}.", file=sys.stderr)
print("Please run config reload or reboot for the change to take effect.", file=sys.stderr)


def main():
parser = argparse.ArgumentParser(description='NASA CLI Helper for NVIDIA BlueField')
parser.add_argument('command', choices=['get_packet_debug_mode', 'get_sai_debug_mode'],
help='Command to execute')
parser.add_argument('command', choices=['get_packet_debug_mode', 'get_sai_debug_mode', 'get_aging_interval', 'set_aging_interval'],
help='Command to execute')
parser.add_argument('-f', '--filename', action='store_true',
help='Show filename instead of status')
help='Show filename instead of status (for get_* commands)')
parser.add_argument('value', nargs='?', type=int, default=None,
help='Aging interval in seconds (for set_aging_interval; default 1)')

args = parser.parse_args()

if args.command == 'get_aging_interval':
seconds = get_aging_interval()
print(f"{seconds}")
return

if args.command == 'set_aging_interval':
seconds = args.value if args.value is not None else CT_AGING_DEFAULT_SECONDS
if seconds < 1:
print("Error: aging interval must be >= 1 second.", file=sys.stderr)
sys.exit(1)
set_aging_interval(seconds)
return

try:
docker_client = docker.from_env()
except docker.errors.DockerException as e:
Expand All @@ -44,11 +137,12 @@ def main():
except Exception as e:
print(f"Error: Failed to execute '{args.command}': {e}", file=sys.stderr)
sys.exit(1)

if args.filename:
print(filename)
else:
print(status)


if __name__ == '__main__':
main()