HEX
Server: nginx/1.22.1
System: Linux VM-16-9-centos 3.10.0-1160.99.1.el7.x86_64 #1 SMP Wed Sep 13 14:19:20 UTC 2023 x86_64
User: www (1001)
PHP: 7.3.31
Disabled: passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Upload Files
File: //lib64/mstflint/python_tools/mstprivhost/mstprivhost.py
#copyright (c) 2004-2020 Mellanox Technologies LTD. All rights reserved.   
#                                                                           
# This software is available to you under a choice of one of two            
# licenses.  You may choose to be licensed under the terms of the GNU       
# General Public License (GPL) Version 2, available from the file           
# COPYING in the main directory of this source tree, or the                 
# OpenIB.org BSD license below:                                             
#                                                                           
#     Redistribution and use in source and binary forms, with or            
#     without modification, are permitted provided that the following       
#     conditions are met:                                                   
#                                                                           
#      - Redistributions of source code must retain the above               
#        copyright notice, this list of conditions and the following        
#        disclaimer.                                                        
#                                                                           
#      - Redistributions in binary form must reproduce the above            
#        copyright notice, this list of conditions and the following        
#        disclaimer in the documentation and/or other materials             
#        provided with the distribution.                                    
#                                                                           
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,         
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE OF                   
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                     
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS       
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN        
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN         
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE          
# SOFTWARE.                                                                 
#--                                                                         


from __future__ import print_function

import argparse
import os
import subprocess
import sys
import tempfile
import math

import tools_version

PROG = 'mstprivhost'
TOOL_VERSION = "1.0.0"

CMD_HELP = """\
restrict:  Set host 1 (ARM) privileged, host 0 (x86_64) restricted.
privilege: Set host 1 (ARM) privileged, host 0 (x86_64) privileged
           (back to default).
query:     Query current host configuration.
"""

DESCRIPTION = """\
restrict or privilege host
Note: New configurations takes effect immediately.
Note: privileged host - host has all supported privileges.
      restricted host - host is not allowed to modify global
      per port/parameters or access other hosts parametersis.

"""

DISABLE_RSHIM_HELP = """\
When TRUE, the host does not have an RSHIM function
to access the embedded CPU registers
"""

DISABLE_TRACER_HELP = """\
When TRUE, the host will not be allowed to own the Tracer
"""

DISABLE_COUNTER_RD_HELP = """\
When TRUE, the host will not be allowed to read Physical port counters
"""

DISABLE_PORT_OWNER_HELP = """\
When TRUE, the host will not be allowed to be Port Owner
"""

def _log(level, msg, *args, **kw):
    if args:
        msg = msg % args
    print(level, msg, end=kw.get('end', '\n'))


def info(msg, *args, **kw):
    _log("-I-", msg, *args, **kw)


def error(msg, *args, **kw):
    _log("-E-", msg, *args, **kw)


class PrivilegeException(Exception):
    pass


class PrivilegeMgr(object):
    CONFIG_CMD_LINE = "mstconfig -d %s -f %s --yes set_raw"
    QUERY_CMD_LINE = "mstconfig -d %s -f %s --yes get_raw"
    MCRA_CMD_LINE = "mstmcra %s 0xf0014.0:16"
    BLUE_FIELD_DEV_ID = 0x211
    BLUE_FIELD2_DEV_ID = 0x214
    TITLE = "MLNX_RAW_TLV_FILE\n"
    RAW_BYTES = "0x03000204 0x07000083 0x00000000"

    LIMITED = 0x10000000
    DISABLE_PORT_OWNER = 0x01
    DISABLE_COUNTER_RD = 0x02
    DISABLE_TRACER = 0x04
    DISABLE_RSHIM = 0x08

    RESTRICT_BYTES = "0x03000204 0x07000083 0x00000000 0x1000000f"
    PRIVILEGE_BYTES = "0x03000204 0x07000083 0x00000000 0x00000000"

    def __init__(self, device, query, privilege, disable_rshim, disable_tracer,
                 disable_counter_rd, disable_port_owner):
        self._privilege = privilege
        self._device = device
        self._query = query
        self._disable_rshim = disable_rshim
        self._disable_tracer = disable_tracer
        self._disable_counter_rd = disable_counter_rd
        self._disable_port_owner = disable_port_owner
        self._file_p = tempfile.NamedTemporaryFile(
            suffix='.raw', prefix="nvconfig_setting_")
        self._file_name = self._file_p.name
        self._nv_host_priv_conf = 0
        self._current_conf = None

    def updateTlvFile(self, print_info_msgs = False):
        if print_info_msgs:
            info("preparing configuration file...", end='')
        # use encode for compatibility with python 2/3
        self._file_p.seek(0)
        self._file_p.write(self.TITLE.encode())
        nv_host_priv_conf_str = '0x%08x' % self._nv_host_priv_conf
        conf_bytes = " ".join((self.RAW_BYTES, nv_host_priv_conf_str))
        self._file_p.write(conf_bytes.encode())
        self._file_p.flush()
        if print_info_msgs:
            print("Done!")

    @staticmethod
    def _exec_cmd(cmd):
        p = subprocess.Popen(cmd,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             shell=True)
        stdout, stderr = p.communicate()
        exit_code = p.wait()

        return (exit_code, stdout, stderr)

    def printTitle(self, title):
        print(title)
        print("-"*len(title))

    def printConfInfo(self):
        current_conf = self.queryConf()
        if current_conf is not None:
            self.printTitle("Current device configurations:")
            print("%-30s: %s"%("level", current_conf["level"]))
            self.printTitle("\nPort functions status:")
            print("%-30s: %s"%("disable_rshim", current_conf["disable_rshim"]))
            print("%-30s: %s"%("disable_tracer", current_conf["disable_tracer"]))
            print("%-30s: %s"%("disable_port_owner", current_conf["disable_port_owner"]))
            print("%-30s: %s\n"%("disable_counter_rd", current_conf["disable_counter_rd"]))
        return current_conf is None

    def queryConf(self):
        current_conf = {"level" : "PRIVILEGED", "disable_rshim": "FALSE",
                        "disable_tracer" : "FALSE", "disable_port_owner" : "FALSE",
                        "disable_counter_rd" : "FALSE"}
        # updateTlvFile file for query
        self.updateTlvFile()
        # run query operation
        cmd = self.QUERY_CMD_LINE % (self._device,self._file_name)
        exit_code, stdout, stderr = self._exec_cmd(cmd)

        if exit_code != 0:
            error("Failed to query device configurations")
            return None
        else :
            indexOfData = stdout.index('Data') + 6
            conf_data = int(stdout[indexOfData:indexOfData+13], 16)
            level =  (conf_data & self.LIMITED) >> int(math.log(self.LIMITED, 2))
            disable_rshim = (conf_data & self.DISABLE_RSHIM) >>\
                                    int(math.log(self.DISABLE_RSHIM, 2))
            disable_tracer = (conf_data & self.DISABLE_TRACER) >>\
                                    int(math.log(self.DISABLE_TRACER, 2))
            disable_port_owner = (conf_data & self.DISABLE_PORT_OWNER) >>\
                                    int(math.log(self.DISABLE_PORT_OWNER, 2))
            disable_counter_rd = (conf_data & self.DISABLE_COUNTER_RD) >>\
                                    int(math.log(self.DISABLE_COUNTER_RD, 2))
            current_conf.update({"level": "RESTRICTED" if level else "PRIVILEGED"}) 
            current_conf.update({"disable_rshim": "TRUE" if disable_rshim else "FALSE"})
            current_conf.update({"disable_tracer": "TRUE" if disable_tracer else "FALSE"})
            current_conf.update({"disable_port_owner": "TRUE" if disable_port_owner else "FALSE"})
            current_conf.update({"disable_counter_rd": "TRUE" if disable_counter_rd else "FALSE"})
        return current_conf


    def setPrivConf(self, re_restrict):
        self._nv_host_priv_conf = 0
        self.updateTlvFile(not re_restrict)
        if not re_restrict:
            info("configuring device...", end='')
        cmd = self.CONFIG_CMD_LINE % (self._device, self._file_name)
        exit_code, stdout, stderr = self._exec_cmd(cmd)
        if exit_code != 0 and not re_restrict:
            print("Failed")
            error("Removing the restriction only effective on the ARM side")
        if exit_code == 0 and not re_restrict:
            print("Done!")
        return exit_code

    def setRestrictConf(self):
        self._nv_host_priv_conf = self.LIMITED
        if self._disable_rshim:
            self._nv_host_priv_conf |= self.DISABLE_RSHIM
        if self._disable_tracer:
            self._nv_host_priv_conf |= self.DISABLE_TRACER
        if self._disable_counter_rd:
            self._nv_host_priv_conf |= self.DISABLE_COUNTER_RD
        if self._disable_port_owner:
            self._nv_host_priv_conf |= self.DISABLE_PORT_OWNER
        self.updateTlvFile(True)
        info("configuring device...", end='')
        cmd = self.CONFIG_CMD_LINE % (self._device, self._file_name)
        exit_code, stdout, stderr = self._exec_cmd(cmd)
        if exit_code != 0:
            print("Failed")
            info("Host is already restricted")
            exit_code = 0
        else:
            print("Done!")
        return exit_code

    def setConf(self):
        current_conf = self.queryConf()
        exit_code = 0
        if (not self._privilege) and current_conf and (current_conf["level"] == "RESTRICTED"):
            self.setPrivConf(True)
            self.setRestrictConf()
        elif not self._privilege:
            self.setRestrictConf()
        elif self._privilege:
            exit_code = self.setPrivConf(False)
        return exit_code

    def configure(self):
        if self._query:
            return self.printConfInfo()
        else:
            return self.setConf()

    def cleanup(self):
        self._file_p.close()
        if os.path.isfile(self._file_name):
            os.remove(self._file_name)

    def validate(self):
        # get device ID
        cmd_line = self.MCRA_CMD_LINE % self._device
        exit_code, stdout, _ = self._exec_cmd(cmd_line)
        if exit_code != 0:
            raise PrivilegeException("Unknown device '%s'!" % self._device)
        dev_id = int(stdout, 16)
        if dev_id not in (self.BLUE_FIELD_DEV_ID, self.BLUE_FIELD2_DEV_ID):
            raise PrivilegeException(
                "Device '%s' is not supported, "
                "only BlueField devices are supported!" % self._device)


def parse_args():
    parser = argparse.ArgumentParser(
        prog=PROG, description=DESCRIPTION,
        formatter_class=argparse.RawTextHelpFormatter)
    version = tools_version.GetVersionString(PROG, TOOL_VERSION)
    parser.add_argument("-v", "--version", action="version", version=version,
                        help="show program's version number and exit")
    # options arguments
    options_group = parser.add_argument_group('Options')
    options_group.add_argument(
        '--device',
        '-d',
        required=True,
        help='Device to work with.')

    # command arguments
    command_group = parser.add_argument_group('Commands')
    command_group.add_argument(
        'command',
        nargs=1,
        choices=["r", "restrict", "p", "privilege", "q", "query"],
        help=CMD_HELP)
    options_group.add_argument('--disable_rshim', action="store_true",
                               help=DISABLE_RSHIM_HELP)
    options_group.add_argument('--disable_tracer', action="store_true",
                               help=DISABLE_TRACER_HELP)
    options_group.add_argument('--disable_counter_rd', action="store_true",
                               help=DISABLE_COUNTER_RD_HELP)
    options_group.add_argument('--disable_port_owner', action="store_true",
                               help=DISABLE_PORT_OWNER_HELP)
    args = parser.parse_args()
    
    disable_flags = args.disable_rshim or args.disable_tracer or \
                args.disable_counter_rd or args.disable_port_owner
    rest_flags = args.command[0] in ("r", "restrict")
    priv_flags = args.command[0] in ("p", "privilege")
    query_flags = args.command[0] in ("q", "query")
    if priv_flags and disable_flags:
        parser.error("disable flags are not allowed in privilege mode")
    if query_flags and (priv_flags or rest_flags or disable_flags):
        parser.error("privilege or restrict commands are not allowed with query")
    return args


def main():
    args = parse_args()
    device = args.device
    command = args.command[0]
    query = False
    privilege = False
    if command in ("p", "privilege"):
        privilege = True
    elif command in ("r", "restrict"):
        privilege = False
    elif command in ("q", "query"):
        query = True
    retcode = 0
    mgr = PrivilegeMgr(device,query, privilege, args.disable_rshim,
                       args.disable_tracer, args.disable_counter_rd,
                       args.disable_port_owner)
    try:
        mgr.validate()
        mgr.updateTlvFile()
        retcode = mgr.configure()
    except PrivilegeException as exc:
        error(str(exc))
        retcode = 1
    except Exception as exc:
        error("got an error: %s", str(exc))
        retcode = 1
    except(KeyboardInterrupt, SystemExit):
        print("\nInterrupted!\nExiting")
        retcode = 1
    finally:
        mgr.cleanup()
    return retcode


if __name__ == "__main__":
    sys.exit(main())