sonic-buildimage/platform/pddf/i2c/utils/pddf_util.py
FuzailBrcm 771a1170d8
[pddf]: Adding and enabling S3IP support in PDDF (#15073)
Why I did it
The S3IP (Simplified Switch System INtegration Program) sysfs specification defines a unified interface to access peripheral hardware on devices from different vendors, making it easier for SONiC to support different devices and platforms.

PDDF is a framework to simplify the driver and SONiC platform APIs development for new platforms. This effort is first step in combining the two frameworks.

This specific PR adds support for pddf-s3ip-init.service and enables it in PDDF.
2023-05-18 13:13:16 -07:00

613 lines
24 KiB
Python
Executable File

#!/usr/bin/env python
"""
Usage: %(scriptName)s [options] command object
options:
-h | --help : this help message
-d | --debug : run with debug mode
-f | --force : ignore error during installation or clean
command:
install : install drivers and generate related sysfs nodes
clean : uninstall drivers and remove related sysfs nodes
switch-pddf : switch to pddf mode, installing pddf drivers and generating sysfs nodes
switch-nonpddf : switch to per platform, non-pddf mode
"""
import logging
import getopt
import os
import shutil
import subprocess
import sys
from sonic_py_common import device_info
import pddfparse
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'
PROJECT_NAME = 'PDDF'
version = '1.1'
verbose = False
DEBUG = False
args = []
ALL_DEVICE = {}
FORCE = 0
kos = []
perm_kos = []
devs = []
# Instantiate the class pddf_obj
try:
pddf_obj = pddfparse.PddfParse()
except Exception as e:
print("%s" % str(e))
sys.exit()
if DEBUG == True:
print(sys.argv[0])
print('ARGV :', sys.argv[1:])
def main():
global DEBUG
global args
global FORCE
global kos
if len(sys.argv)<2:
show_help()
options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help',
'debug',
'force',
])
if DEBUG == True:
print(options)
print(args)
print(len(sys.argv))
# generate the KOS list from pddf device JSON file
if 'std_perm_kos' in pddf_obj.data['PLATFORM'].keys():
kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos'])
perm_kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos'])
kos.extend(pddf_obj.data['PLATFORM']['std_kos'])
kos.extend(pddf_obj.data['PLATFORM']['pddf_kos'])
kos = ['modprobe '+i for i in kos]
if 'custom_kos' in pddf_obj.data['PLATFORM']:
custom_kos = pddf_obj.data['PLATFORM']['custom_kos']
kos.extend(['modprobe -f '+i for i in custom_kos])
for opt, arg in options:
if opt in ('-h', '--help'):
show_help()
elif opt in ('-d', '--debug'):
DEBUG = True
logging.basicConfig(level=logging.INFO)
elif opt in ('-f', '--force'):
FORCE = 1
else:
logging.info('no option')
for arg in args:
if arg == 'install':
do_install()
elif arg == 'clean':
do_uninstall()
elif arg == 'switch-pddf':
do_switch_pddf()
elif arg == 'switch-nonpddf':
do_switch_nonpddf()
else:
show_help()
return 0
def show_help():
print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print("[PDDF]"+txt)
return
def log_os_system(cmd, show):
logging.info('Run :'+cmd)
status, output = subprocess.getstatusoutput(cmd)
my_log (cmd +"with result:" + str(status))
my_log (" output:"+output)
if status:
logging.info('Failed :'+cmd)
if show:
print('Failed :'+cmd)
return status, output
def driver_check():
ret, lsmod = log_os_system("lsmod| grep pddf", 0)
if ret:
return False
logging.info('mods:'+lsmod)
if len(lsmod) ==0:
return False
return True
def get_path_to_device():
# Get platform and hwsku
(platform, hwsku) = device_info.get_platform_and_hwsku()
# Load platform module from source
platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
return platform_path
def get_path_to_pddf_plugin():
pddf_path = "/".join([PLATFORM_ROOT_PATH, "pddf/plugins"])
return pddf_path
def config_pddf_utils():
device_path = get_path_to_device()
pddf_path = get_path_to_pddf_plugin()
# ##########################################################################
SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl'])
SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py3-none-any.whl'])
SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl.orig'])
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 1)
if status:
if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG):
# Platform API 2.0 is supported
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG):
# bsp whl pkg is present but not installed on host <special case>
if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK):
log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1)
# PDDF whl package exist ... this must be the whl package created from
# PDDF 2.0 ref API classes and some changes on top of it ... install it
log_os_system('sync', 1)
shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG)
log_os_system('sync', 1)
print("Attemting to install the PDDF sonic_platform wheel package ...")
if os.path.getsize(SONIC_PLATFORM_BSP_WHL_PKG) != 0:
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1)
if status:
print("Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG))
return status
else:
print("Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG))
else:
print("Error: Failed to copy {} properly. Exiting ...".format(SONIC_PLATFORM_PDDF_WHL_PKG))
return -1
else:
# PDDF with platform APIs 1.5 must be supported
device_plugin_path = "/".join([device_path, "plugins"])
backup_path = "/".join([device_plugin_path, "orig"])
print("Loading PDDF generic plugins (1.0)")
if os.path.exists(backup_path) is False:
os.mkdir(backup_path)
log_os_system("mv "+device_plugin_path+"/*.*"+" "+backup_path, 0)
for item in os.listdir(pddf_path):
shutil.copy(pddf_path+"/"+item, device_plugin_path+"/"+item)
shutil.copy('/usr/local/bin/pddfparse.py', device_plugin_path+"/pddfparse.py")
else:
# sonic_platform whl pkg is installed 2 possibilities, 1) bsp 2.0 classes
# are installed, 2) system rebooted and either pddf/bsp 2.0 classes are already installed
if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG):
if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK):
# bsp 2.0 classes are installed. Take a backup and copy pddf 2.0 whl pkg
log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1)
log_os_system('sync', 1)
shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG)
log_os_system('sync', 1)
# uninstall the existing bsp whl pkg
status, output = log_os_system("pip3 uninstall sonic-platform -y &> /dev/null", 1)
if status:
print("Error: Unable to uninstall BSP sonic-platform whl package")
return status
print("Attempting to install the PDDF sonic_platform wheel package ...")
if os.path.getsize(SONIC_PLATFORM_BSP_WHL_PKG) != 0:
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1)
if status:
print("Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG))
return status
else:
print("Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG))
else:
print("Error: Failed to copy {} properly. Exiting ...".format(SONIC_PLATFORM_PDDF_WHL_PKG))
return -1
else:
# system rebooted in pddf mode
print("System rebooted in PDDF mode, hence keeping the PDDF 2.0 classes")
else:
# pddf whl package doesnt exist
print("Error: PDDF 2.0 classes doesnt exist. PDDF mode can not be enabled")
sys.exit(1)
# ##########################################################################
# Take a backup of orig fancontrol
if os.path.exists(device_path+"/fancontrol"):
log_os_system("mv "+device_path+"/fancontrol"+" "+device_path+"/fancontrol.bak", 0)
# Create a link to fancontrol of PDDF
if os.path.exists(device_path+"/pddf/fancontrol") and not os.path.exists(device_path+"/fancontrol"):
shutil.copy(device_path+"/pddf/fancontrol",device_path+"/fancontrol")
# BMC support
f_sensors="/usr/bin/sensors"
f_sensors_org="/usr/bin/sensors.org"
f_pddf_sensors="/usr/local/bin/pddf_sensors"
if os.path.exists(f_pddf_sensors) is True:
if os.path.exists(f_sensors_org) is False:
shutil.copy(f_sensors, f_sensors_org)
shutil.copy(f_pddf_sensors, f_sensors)
return 0
def cleanup_pddf_utils():
device_path = get_path_to_device()
SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl'])
SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py3-none-any.whl'])
SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl.orig'])
# ##########################################################################
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 1)
if status:
# PDDF Platform API 2.0 is not supported but system is in PDDF mode, hence PDDF 1.0 plugins are present
device_plugin_path = "/".join([device_path, "plugins"])
backup_path = "/".join([device_plugin_path, "orig"])
if os.path.exists(backup_path) is True:
for item in os.listdir(device_plugin_path):
if os.path.isdir(device_plugin_path+"/"+item) is False:
os.remove(device_plugin_path+"/"+item)
log_os_system("mv "+backup_path+"/*"+" "+device_plugin_path, 1)
os.rmdir(backup_path)
else:
print("\nERR: Unable to locate original device files...\n")
else:
# PDDF 2.0 apis are supported and PDDF whl package is installed
if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG):
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK):
# platform is 2.0 compliant and original bsp 2.0 whl package exist
log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG_BK+' '+SONIC_PLATFORM_BSP_WHL_PKG, 1)
status, output = log_os_system("pip3 uninstall sonic-platform -y &> /dev/null", 1)
if status:
print("Error: Unable to uninstall PDDF sonic-platform whl package")
return status
print("Attemting to install the BSP sonic_platform wheel package ...")
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1)
if status:
print("Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG))
return status
else:
print("Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG))
else:
# platform doesnt support 2.0 APIs but PDDF is 2.0 based
# remove and uninstall the PDDF whl package
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG):
os.remove(SONIC_PLATFORM_BSP_WHL_PKG)
status, output = log_os_system("pip3 uninstall sonic-platform -y &> /dev/null", 1)
if status:
print("Error: Unable to uninstall PDDF sonic-platform whl package")
return status
else:
# something seriously wrong. System is in PDDF mode but pddf whl pkg is not present
print("Error: Fatal error as the system is in PDDF mode but the pddf .whl original is not present")
# ################################################################################################################
if os.path.exists(device_path+"/fancontrol"):
os.remove(device_path+"/fancontrol")
if os.path.exists(device_path+"/fancontrol.bak"):
log_os_system("mv "+device_path+"/fancontrol.bak"+" "+device_path+"/fancontrol", 0)
# BMC support
f_sensors="/usr/bin/sensors"
f_sensors_org="/usr/bin/sensors.org"
if os.path.exists(f_sensors_org) is True:
shutil.copy(f_sensors_org, f_sensors)
return 0
def create_pddf_log_files():
if not os.path.exists('/var/log/pddf'):
log_os_system("sudo mkdir /var/log/pddf", 1)
log_os_system("sudo touch /var/log/pddf/led.txt", 1)
log_os_system("sudo touch /var/log/pddf/psu.txt", 1)
log_os_system("sudo touch /var/log/pddf/fan.txt", 1)
log_os_system("sudo touch /var/log/pddf/xcvr.txt", 1)
log_os_system("sudo touch /var/log/pddf/sysstatus.txt", 1)
log_os_system("sudo touch /var/log/pddf/cpld.txt", 1)
log_os_system("sudo touch /var/log/pddf/cpldmux.txt", 1)
log_os_system("sudo touch /var/log/pddf/client.txt", 1)
log_os_system("sudo touch /var/log/pddf/mux.txt", 1)
log_os_system("sudo touch /var/log/pddf/fpgapci.txt", 1)
def driver_install():
global FORCE
# check for pre_driver_install script
if os.path.exists('/usr/local/bin/pddf_pre_driver_install.sh'):
status, output = log_os_system('/usr/local/bin/pddf_pre_driver_install.sh', 1)
if status:
print("Error: pddf_pre_driver_install script failed with error %d"%status)
return status
# For debug
print(output)
# Removes the perm_kos first, then reload them in a proper sequence
for mod in perm_kos:
cmd = "modprobe -rq " + mod
status, output = log_os_system(cmd, 1)
if status:
print("driver_install: Unable to unload {}".format(mod))
# Don't exit but continue
log_os_system("depmod", 1)
for i in range(0,len(kos)):
status, output = log_os_system(kos[i], 1)
if status:
print("driver_install() failed with error %d"%status)
if FORCE == 0:
return status
output = config_pddf_utils()
if output:
print("config_pddf_utils() failed with error %d"%output)
# check for post_driver_install script
if os.path.exists('/usr/local/bin/pddf_post_driver_install.sh'):
status, output = log_os_system('/usr/local/bin/pddf_post_driver_install.sh', 1)
if status:
print("Error: pddf_post_driver_install script failed with error %d"%status)
return status
# Useful for debugging
print(output)
return 0
def driver_uninstall():
global FORCE
status = cleanup_pddf_utils()
if status:
print("cleanup_pddf_utils() failed with error %d"%status)
for i in range(0,len(kos)):
# if it is in perm_kos, do not remove
if (kos[-(i+1)].split())[-1] in perm_kos or 'i2c-i801' in kos[-(i+1)]:
continue
rm = kos[-(i+1)].replace("modprobe", "modprobe -rq")
rm = rm.replace("insmod", "rmmod")
status, output = log_os_system(rm, 1)
if status:
print("driver_uninstall() failed with error %d"%status)
if FORCE == 0:
return status
return 0
def device_install():
global FORCE
# check for pre_device_creation script
if os.path.exists('/usr/local/bin/pddf_pre_device_create.sh'):
status, output = log_os_system('/usr/local/bin/pddf_pre_device_create.sh', 1)
if status:
print("Error: pddf_pre_device_create script failed with error %d"%status)
return status
# trigger the pddf_obj script for FAN, PSU, CPLD, MUX, etc
status = pddf_obj.create_pddf_devices()
if status:
print("Error: create_pddf_devices() failed with error %d"%status)
if FORCE == 0:
return status
# check for post_device_create script
if os.path.exists('/usr/local/bin/pddf_post_device_create.sh'):
status, output = log_os_system('/usr/local/bin/pddf_post_device_create.sh', 1)
if status:
print("Error: pddf_post_device_create script failed with error %d"%status)
return status
# Useful for debugging
print(output)
return
def device_uninstall():
global FORCE
# Trigger the paloparse script for deletion of FAN, PSU, OPTICS, CPLD clients
status = pddf_obj.delete_pddf_devices()
if status:
print("Error: delete_pddf_devices() failed with error %d"%status)
if FORCE == 0:
return status
return
def do_install():
print("Checking system....")
if not os.path.exists('/usr/share/sonic/platform/pddf_support'):
print(PROJECT_NAME.upper() +" mode is not enabled")
return
if driver_check()== False :
print(PROJECT_NAME.upper() +" has no PDDF driver installed....")
create_pddf_log_files()
print("Installing ...")
status = driver_install()
if status:
return status
else:
print(PROJECT_NAME.upper() +" drivers detected....")
print("Creating devices ...")
status = device_install()
if status:
return status
# Check if S3IP support is enabled, if yes, start the service in no block mode
if 'enable_s3ip' in pddf_obj.data['PLATFORM'].keys() and pddf_obj.data['PLATFORM']['enable_s3ip'] == 'yes':
log_os_system('systemctl enable pddf-s3ip-init.service', 1)
log_os_system('systemctl start --no-block pddf-s3ip-init.service', 1)
return
def do_uninstall():
print("Checking system....")
if not os.path.exists('/usr/share/sonic/platform/pddf_support'):
print(PROJECT_NAME.upper() +" mode is not enabled")
return
if os.path.exists('/var/log/pddf'):
print("Remove pddf log files.....")
log_os_system("sudo rm -rf /var/log/pddf", 1)
print("Remove all the devices...")
status = device_uninstall()
if status:
return status
if driver_check()== False :
print(PROJECT_NAME.upper() +" has no PDDF driver installed....")
else:
print("Removing installed driver....")
status = driver_uninstall()
if status:
if FORCE == 0:
return status
return
def do_switch_pddf():
try:
import pddf_switch_svc
except ImportError:
print("Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform")
sys.exit()
print("Check the pddf support...")
status = pddf_switch_svc.check_pddf_support()
if not status:
print("PDDF is not supported on this platform")
return status
print("Checking system....")
if os.path.exists('/usr/share/sonic/platform/pddf_support'):
print(PROJECT_NAME.upper() +" system is already in pddf mode....")
else:
print("Check if the native sonic-platform whl package is installed in the pmon docker")
status, output = log_os_system("docker exec -it pmon pip3 show sonic-platform", 1)
if not status:
# Need to remove this whl module
status, output = log_os_system("docker exec -it pmon pip3 uninstall sonic-platform -y", 1)
if not status:
print("Successfully uninstalled the native sonic-platform whl pkg from pmon container")
else:
print("Error: Unable to uninstall the sonic-platform whl pkg from pmon container."
" Do it manually before moving to nonpddf mode")
return status
print("Stopping the pmon service ...")
status, output = log_os_system("systemctl stop pmon.service", 1)
if status:
print("Pmon stop failed")
if FORCE==0:
return status
print("Stopping the platform services..")
status = pddf_switch_svc.stop_platform_svc()
if not status:
if FORCE==0:
return status
print("Creating the pddf_support file...")
if os.path.exists('/usr/share/sonic/platform'):
log_os_system("touch /usr/share/sonic/platform/pddf_support", 1)
else:
print("/usr/share/sonic/platform path doesn't exist. Unable to set pddf mode")
return -1
print("Starting the PDDF platform service...")
status = pddf_switch_svc.start_platform_pddf()
if not status:
if FORCE==0:
return status
print("Restart the pmon service ...")
status, output = log_os_system("systemctl start pmon.service", 1)
if status:
print("Pmon restart failed")
if FORCE==0:
return status
return
def do_switch_nonpddf():
try:
import pddf_switch_svc
except ImportError:
print("Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform")
sys.exit()
print("Checking system....")
if not os.path.exists('/usr/share/sonic/platform/pddf_support'):
print(PROJECT_NAME.upper() +" system is already in non-pddf mode....")
else:
print("Check if the sonic-platform whl package is installed in the pmon docker")
status, output = log_os_system("docker exec -it pmon pip3 show sonic-platform", 1)
if not status:
# Need to remove this whl module
status, output = log_os_system("docker exec -it pmon pip3 uninstall sonic-platform -y", 1)
if not status:
print("Successfully uninstalled the sonic-platform whl pkg from pmon container")
else:
print("Error: Unable to uninstall the sonic-platform whl pkg from pmon container."
" Do it manually before moving to nonpddf mode")
return status
print("Stopping the pmon service ...")
status, output = log_os_system("systemctl stop pmon.service", 1)
if status:
print("Stopping pmon service failed")
if FORCE==0:
return status
print("Stopping the PDDF platform service...")
status = pddf_switch_svc.stop_platform_pddf()
if not status:
if FORCE==0:
return status
print("Removing the pddf_support file...")
if os.path.exists('/usr/share/sonic/platform'):
log_os_system("rm -f /usr/share/sonic/platform/pddf_support", 1)
else:
print("/usr/share/sonic/platform path doesnt exist. Unable to set non-pddf mode")
return -1
print("Starting the platform services...")
status = pddf_switch_svc.start_platform_svc()
if not status:
if FORCE==0:
return status
print("Restart the pmon service ...")
status, output = log_os_system("systemctl start pmon.service", 1)
if status:
print("Restarting pmon service failed")
if FORCE==0:
return status
return
if __name__ == "__main__":
main()