#!/usr/bin/perl
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (c) 2012 Mellanox Technologies. All rights reserved.
#
# This Software is licensed under one of the following licenses:
#
# 1) under the terms of the "Common Public License 1.0" a copy of which is
#    available from the Open Source Initiative, see
#    http://www.opensource.org/licenses/cpl.php.
#
# 2) under the terms of the "The BSD License" a copy of which is
#    available from the Open Source Initiative, see
#    http://www.opensource.org/licenses/bsd-license.php.
#
# 3) under the terms of the "GNU General Public License (GPL) Version 2" a
#    copy of which is available from the Open Source Initiative, see
#    http://www.opensource.org/licenses/gpl-license.php.
#
# Licensee has the right to choose one of the above licenses.
#
# Redistributions of source code must retain the above copyright
# notice and one of the license notices.
#
# Redistributions in binary form must reproduce both the above copyright
# notice, one of the license notices in the documentation
# and/or other materials provided with the distribution.


use strict;
use File::Basename;
use File::Path;
use File::Find;
use File::Copy;
use File::Compare;
use File::Glob qw/:bsd_glob/;
use Cwd;
use Term::ANSIColor qw(:constants);

my $WDIR = dirname(Cwd::abs_path $0);
require("$WDIR/common.pl");

use sigtrap 'handler', \&sig_handler, 'normal-signals';
my $PREREQUISIT = "172";
my $SUCCESS = "0";
my $ERROR = "1";
my $EINVAL = "22";
my $ENOSPC = "28";
my $NONOFEDRPMS = "174";

$ENV{"LANG"} = "C";

$| = 1;

chdir $WDIR;
my $CWD     = getcwd;

my $TMPDIR  = '/tmp';
my $netdir;

if (! -e ".mlnx" and ! -e "mlnx") {
    print RED ".mlnx file not found. Cannot continue...", RESET "\n";
    exit $PREREQUISIT;
}

my $MLNX_OFED_LINUX_VERSION = `cat .mlnx 2> /dev/null || cat mlnx`;
chomp $MLNX_OFED_LINUX_VERSION;
my $major_version = (split '-', $MLNX_OFED_LINUX_VERSION)[0];
my $prev_major_version = '';
my $major_update = 1;
my $LOCK_EXCLUSIVE = 2;
my $UNLOCK         = 8;
#Setup some defaults
my $KEY_ESC=27;
my $KEY_CNTL_C=3;
my $KEY_ENTER=13;

my $BASIC = 1;
my $HPC = 2;
my $ALL = 3;
my $CUSTOM = 4;
my $VMA = 5;
my $VMAVPI = 6;
my $VMAETH = 7;

my $interactive = 0;
my $kernel_only = 0;
my $quiet = 0;
my $verbose = 1;
my $verbose2 = 0;
my $verbose3 = 0;
my $verify = 1;

my $pfc = 0x0;

my $print_available = 0;

my $clear_string = `clear`;

my $arch = `uname -m`;
chomp $arch;
my $kernel = `uname -r`;
chomp $kernel;
my $kernel_sources = "/lib/modules/$kernel/build";
chomp $kernel_sources;

my $vendor_pre_install = "";
my $vendor_post_install = "";
my $vendor_pre_uninstall = "";
my $vendor_post_uninstall = "";

# list of scripts to run for each package
my %package_pre_install_script = ();
my %package_post_install_script = ();

my $force_rpm_install = 0;
my @rpms_to_install = ();
my $update_limits_conf_soft = 1;
my $update_limits_conf_hard = 1;
my $update_firmware = 1;
my $umad_dev_rw = 0;
my $umad_dev_na = 0;
my $enable_affinity = 0;
my $enable_mlnx_tune = 0;
my $firmware_update_only = 0;
my $fw_update_flags = "";
my $boib_port;
my $err = 0;
my $force = 0;
my $update = 0;
my %fw = ();
my $DISTRO = "";
my $skip_distro_check = 0;
my $skip_kmp_check = 0;
my $skip_unsupported_devices_check = 0;
my $post_start_delay = 0;
my $rpmbuild_flags = "";
my $rpminstall_flags = "";
my $rpminstall_parameter = "-i";
my $speed_up_kmp = 0;
my $required_space = 0;
my $knem_prefix = '';
my $dpdk_prefix = '/opt/mellanox/dpdk';
my $do_copy_udev = 0;

my $RPM = 'rpm --nosignature';

# Define RPMs environment
my $dist_rpm;
my $dist_rpm_ver = 0;
my $dist_rpm_rel = 0;
my $add_kernel_support = 0;
my $add_kernel_support_build_only = 0;
my $add_kernel_support_flags = "";
my $auto_add_kernel_support = 0;
my $enable_opensm = 0;
my @components = qw/kernel user/;

my $MLNX_OFED_ARCH = "";
if ( -e ".arch" or -e "arch") {
    $MLNX_OFED_ARCH = `cat .arch 2> /dev/null || cat arch`;
    chomp $MLNX_OFED_ARCH;

    if ($arch =~ /i[0-9]86/ and $MLNX_OFED_ARCH ne "i686" or
        $arch !~ /i[0-9]86/ and $MLNX_OFED_ARCH ne $arch) {
        print RED "Error: This package is intended for a $MLNX_OFED_ARCH architecture" , RESET "\n";
        exit $PREREQUISIT;
    }
}

my $is_ux = 0;
if ( -e "$CWD/ux") {
    $is_ux = 1;
}

my $supported_kernels = "unsupported";
if ( -e "$CWD/.supported_kernels") {
    $supported_kernels = "$CWD/.supported_kernels";
} elsif ( -e "$CWD/supported_kernels") {
    $supported_kernels = "$CWD/supported_kernels";
}

my $MLNX_OFED_DISTRO = `cat distro 2> /dev/null`;
chomp $MLNX_OFED_DISTRO;

my $SRPMS = $CWD . '/' . 'SRPMS/';
chomp $SRPMS;
my $RPMS  = $CWD . '/RPMS'; # . $arch;
chomp $RPMS;
if (not -d $RPMS) {
    mkpath([$RPMS]);
}

my $config = $TMPDIR . '/ofed.conf';
chomp $config;
my $config_net;

my $TOPDIR = "/var/tmp/" . "OFED_topdir";
chomp $TOPDIR;

my $default_prefix = '/usr';
chomp $default_prefix;
my $prefix = $default_prefix;

my $target_cpu  = `$RPM --eval '%{_target_cpu}'`;
chomp $target_cpu;

my $target_cpu32 = "";
if ($arch eq "x86_64") {
    if ( -e "/etc/SuSE-release") {
        $target_cpu32 = 'i586';
    } elsif ($DISTRO =~ /XenServer/) {
        $target_cpu32 = 'i386';
    } else {
        $target_cpu32 = 'i686';
    }
}
elsif ($arch eq "ppc64") {
    $target_cpu32 = 'ppc';
}
chomp $target_cpu32;

my $optflags  = `$RPM --eval '%{optflags}'`;
chomp $optflags;

my $mandir      = `$RPM --eval '%{_mandir}'`;
chomp $mandir;
my $sysconfdir  = "/etc";
chomp $sysconfdir;
my %main_packages = ();
my @selected_packages = ();
my @selected_by_user = ();
my @selected_modules_by_user = ();
my @packages_to_uninstall = ();
my @dependant_packages_to_uninstall = ();
my %selected_for_uninstall = ();
my %non_ofed_for_uninstall = ();
my %ibdevice = ();

my $install_option = 'all';
my $force_all = 0;
if (-e ".def_option" ) {
    $install_option = `cat .def_option 2>/dev/null`;
    chomp $install_option;
}
my $user_space_only = 0;

my $PACKAGE = 'MLNX_OFED_LINUX';
my $INSTALLER = 'mlnxofedinstall';
if ($install_option eq 'eth-only' or -e "$CWD/install") {
    $PACKAGE = "mlnx-en";
    $INSTALLER = "install";
}
my $is_mlnx_en = 0;
if (-e "$CWD/install") {
    $is_mlnx_en = 1;
}

my $is_bf = `lspci -s 00:00.0 2> /dev/null | grep -wq "PCI bridge: Mellanox Technologies" && echo 1 || echo 0`;
chomp $is_bf;

my $with_bluefield = 0;
if  ($is_bf) {
    $with_bluefield = 1;
}

my $mlnx_en_pkgs = "";
my $mlnx_en_only_pkgs = "mlnx.*en|mstflint|ofed-scripts|mlnx-fw-updater|^rdma\$";
my $mlnx_en_rdma_pkgs = "$mlnx_en_only_pkgs|ofa_kernel|libibverbs|libmlx|librdmacm|libvma|sockperf|ibutils|rdma-core";

sub usage
{
   print GREEN;
   print "\n";
   print "Usage: $0 [OPTIONS]\n";

   print "\n";
   print "Installation control:\n";
   print "    --force              Force installation\n";
   print "    --tmpdir             Change tmp directory. Default: $TMPDIR\n";
   print "    -k|--kernel <version>\n";
   print "                         Default on this system: $kernel\n";
   print "    -s|--kernel-sources <path>\n";
   print "                         Default on this system: $kernel_sources\n";
   print "    -U|--update          Update installed version\n";
   print "    --with-32bit         Install 32-bit libraries. Relevant for x86_64 platforms\n";
   print "    --without-32bit      Skip 32-bit libraries installation (Default). Relevant for x86_64 platforms\n";
   print "    --distro             Set Distro name for the running OS (e.g: rhel6.5, sles12sp3). Default: Use auto-detection\n";
   print "    --skip-distro-check  Do not check $PACKAGE vs Distro matching\n";
   print "    --without-depcheck   Run the installation without verifying that all required Distro's packages are installed\n";
   print "    --check-deps-only    Check for missing required Distro's packages and exit\n";
   print "    --print-distro       Print distribution name and exit\n";
   print "\n";
   print "    --add-kernel-support\n";
   print "                         Add kernel support (Run mlnx_add_kernel_support.sh) and install it\n";
   print "    --add-kernel-support-build-only\n";
   print "                         Add kernel support (Run mlnx_add_kernel_support.sh) and exit\n";
   print "\n";
   print "    --kernel-extra-args '<args>'\n";
   print "                         pass <args> to kernel configure script (single paraeter, space separated)\n";
   print "                         - Pass it along with --add-kernel-support\n";
   print "\n";
   print "    --kmp                Install kernel RPMs with KMP support if available\n";
   print "                         - Enabled by default with official $PACKAGE releases\n";
   print "                         - Disabled by default if new $PACKAGE was created with mlnx_add_kernel_support.sh\n";
   print "                         - Passing it along with --add-kernel-support will pass --kmp to mlnx_add_kernel_support.sh\n";
   print "    --disable-kmp        Install kernel RPMs without KMP support if available\n";
   print "                         - Enabled by default if new $PACKAGE was created with mlnx_add_kernel_support.sh\n";
   print "    --skip-kmp-verify    Do not check if the KMP rpms are compatiable with the target kernel\n";
   print "    --speed-up-kmp       Speed up KMP RPMs installation by skipping %post section and running the required operations once for all KMPs\n";
   print "\n";
   print "    --umad-dev-rw        Grant non root users read/write permission for umad devices instead of default\n";
   print "    --umad-dev-na        Prevent from non root users read/write access for umad devices. Overrides '--umad-dev-rw'\n";
   print "    --enable-mlnx_tune   Enable Running the mlnx_tune utility\n";
   print "    --enable-affinity    Run mlnx_affinity script upon boot\n";
   print "    --disable-affinity   Disable mlnx_affinity script (Default)\n";
   print "    --skip-unsupported-devices-check\n";
   print "                         Don't abort if system has an older, unsupported card\n";
if (not ($install_option eq 'eth-only' or $is_mlnx_en)) {
   print "    --enable-opensm      Run opensm upon boot\n";
}
   print "\n";
   print "    --package-install-options\n";
   print "                         RPM install options to use when installing RPM packages (comma separated list)\n";
   print "    --pre-install-<package> <path to script>\n";
   print "                         Run given script before given package's install\n";
   print "    --post-install-<package> <path to script>\n";
   print "                         Run given script after given package's install\n";
   print "\n";
   print "Firmware update control:\n";
   print "    --without-fw-update  Skip firmware update\n";
   print "    --fw-update-only     Update firmware. Skip driver installation\n";
   print "    --force-fw-update    Force firmware update\n";
   print "    --fw-image-dir       Firmware images directory to use instead of default package content\n";
   print "\n";
   print "Package selection:\n";
   print "    -c|--config <packages config_file>\n";
   print "                         Example of the config file can be found under docs\n";
if (not ($install_option eq 'eth-only' or $is_mlnx_en)) {
   print "    --all                Install all available packages\n";
   print "    --bluefield          Install BlueField packages\n";
   print "    --hpc                Install minimum packages required for HPC\n";
   print "    --basic              Install minimum packages for basic functionality\n";
} else {
   print "    --eth-only           Install Ethernet drivers only (Default option)\n";
}
   print "    --dpdk               Install minimum packages required for DPDK\n";
   print "    --ovs-dpdk           Install DPDK and OVS packages\n";
   print "    --vma                Install minimum packages required for VMA\n";
   print "    --xlio                Install minimum packages required for XLIO\n";
if (not ($install_option eq 'eth-only' or $is_mlnx_en)) {
   print "    --guest              Install minimum packages required by guest OS\n";
   print "    --hypervisor         Install minimum packages required by hypervisor OS\n";
   print "    --with-fabric-collector\n";
   print "                         Enable installing fabric-collector package\n";
   print "    --with-nvmf          Enable NVMEoF support\n";
   print "    --with-nfsrdma       Enable NFSoRDMA support\n";
   print "    --without-nfsrdma    Disable NFSoRDMA support (Default)\n";
}
   print"\n";
   print "Extra package filtering:\n";
if (not ($install_option eq 'eth-only' or $is_mlnx_en)) {
   print "    --kernel-only        Install kernel space packages only\n";
   print "    --user-space-only    Filter selected packages and install only User Space packages\n";
}
   print "    --without-<package>  Do not install package\n";
   print "    --with-<package>     Force installing package\n";
   print "\n";
   print "Miscellaneous:\n";
   print "    -h|--help            Display this help message and exit\n";
   print "    --post-start-delay <sec>\n";
   print "                         Set openibd POST_START_DELAY parameter in seconds. (Default 0)\n";
   print "    -p|--print-available Print available packages for current platform\n";
   print "                         And create corresponding ofed.conf file\n";
if (not ($install_option eq 'eth-only' or $is_mlnx_en)) {
   print "    --copy-ifnames-udev  Copy compatibility udev rules for interface names\n";
}
   print "\n";
   print "Output control:\n";
   print "    -v|-vv|-vvv          Set verbosity level\n";
   print "    -q                   Set quiet - no messages will be printed\n";
   print RESET "\n\n";
}

# Returns the version of CUDA installed, but only if it is >= 11.2
# Format: 11-2
sub get_installed_cuda_version() {
    my $rpm_output;
    my $top_ver_str = "";
    my $top_ver_num = 0;
    open($rpm_output, '-|', "rpm -qa")
      or die("Failed to run rpm -qa for cuda availability: $!");
    while (<$rpm_output>) {
        next unless /^^cuda-cudart-([0-9]+-[0-9]+)-/;
        my $ver_str = $1;
        my $ver_num = $ver_str;
        $ver_num =~ s/-/./;
        if ($ver_num > $top_ver_num) {
            $top_ver_str = $ver_str;
            $top_ver_num = $ver_num;
        }
    }
    close($rpm_output);
    return $top_ver_str;
}
my $cuda_version = get_installed_cuda_version();

my $sysfsutils;
my $sysfsutils_devel;

my $config_given = 0;
my $config_net_given = 0;
my $kernel_given = 0;
my $kernel_source_given = 0;
my $check_linux_deps = 1;
my $check_deps_only = 0;
my $print_distro = 0;
my $uninstall = 1;
my $kmp = 1;
# By default, if we have non-KMP rpms for running kernel, we will use them even if
# KMP is supported (someone can run add-kernel-support on KMP supported kernel).
# when --kmp is given, override this behaviour and use KMP rpms if supported and compatible.
my $kmp_flag_given = 0;
my %disabled_packages;
my %force_enable_packages;
my %packages_deps = ();
my %modules_deps = ();
my $force_kmp = 0;
my $kmp_install_done = 0;
my $with_vma = 0;
my $with_xlio = 0;
my $with_fabric_collector = 0;
my $package_manager = "";
my $with_nvme = 0;
my $with_nfsrdma = 0;
my $with_ovs_dpdk = 0;
my $install32 = 0;
my $kernel_extra_args = "";
my $kernel_extra = 0;

my @saved_ARGV = ();
my $CMD = "$0 " . join(' ', @ARGV);
while ( $#ARGV >= 0 ) {

   my $cmd_flag = shift(@ARGV);

    push (@saved_ARGV, $cmd_flag) unless ($cmd_flag =~ /add-kernel-support|--skip-repo|--kernel-version/);
    if ( $cmd_flag eq "--kernel-version" ) {
        push (@saved_ARGV, "--kernel")
    }

    if ( $cmd_flag eq "-c" or $cmd_flag eq "--config" ) {
        $config = shift(@ARGV);
        push (@saved_ARGV, $config);
        $interactive = 0;
        $config_given = 1;
    } elsif ( $cmd_flag eq "--disable-kmp" ) {
        $kmp = 0;
        $kmp_flag_given = 0;
    } elsif ( $cmd_flag eq "--enable-gds" ) {
        # Left for backward compatibility
    } elsif ( $cmd_flag eq "-n" or $cmd_flag eq "--net" ) {
        $config_net = shift(@ARGV);
        push (@saved_ARGV, $config_net);
        $config_net_given = 1;
    } elsif ( $cmd_flag eq "-k" or $cmd_flag eq "--kernel" or $cmd_flag eq "--kernel-version" ) {
        $kernel = shift(@ARGV);
        $kernel_given = 1;
        push (@saved_ARGV, $kernel);
    } elsif ( $cmd_flag eq "-s" or $cmd_flag eq "--kernel-sources" ) {
        $kernel_sources = shift(@ARGV);
        $kernel_source_given = 1;
        push (@saved_ARGV, $kernel_sources);
    } elsif ( $cmd_flag eq "-U" or $cmd_flag eq "--update" ) {
        $update = 1;
    } elsif ( $cmd_flag eq "-p" or $cmd_flag eq "--print-available" ) {
        $print_available = 1;
    } elsif ( $cmd_flag eq "--all" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $interactive = 0;
        $install_option = 'all';
        $force_all = 1;
    } elsif ( $cmd_flag eq "--bluefield" ) {
        $interactive = 0;
        # Do not override other install options to enable bluefield packages as an extension
        $install_option = 'bluefield' if ($install_option eq 'all' and not $force_all);
        $with_bluefield = 1;
        $with_nvme = 1;
    } elsif ( $cmd_flag eq "--hpc" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $interactive = 0;
        $install_option = 'hpc';
    } elsif ( $cmd_flag eq "--with-nfsrdma" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $with_nfsrdma = 1;
    } elsif ( $cmd_flag eq "--without-nfsrdma" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $with_nfsrdma = 0;
    } elsif ( $cmd_flag eq "--with-nvmf" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $with_nvme = 1;
    } elsif ( $cmd_flag eq "--with-vma" and not ($install_option eq 'eth-only' or $is_mlnx_en)) {
        $with_vma = 1;
    } elsif ( $cmd_flag eq "--vma" and !$is_mlnx_en) {
        $interactive = 0;
        $install_option = 'vma';
        $with_vma = 1;
    } elsif ( $cmd_flag eq "--vma" and  $is_mlnx_en) {
        $interactive = 0;
        $install_option = 'vmaeth';
        $with_vma = 1;
    } elsif ( $cmd_flag eq "--vma-eth" ) {
        $interactive = 0;
        $install_option = 'vmaeth';
        $with_vma = 1;
    } elsif ( $cmd_flag eq "--vma-vpi" ) {
        $interactive = 0;
        $install_option = 'vmavpi';
        $with_vma = 1;
    } elsif ( $cmd_flag eq "--xlio" ) {
        $interactive = 0;
        $install_option = 'xlio';
        $with_xlio = 1;
    } elsif ( $cmd_flag eq "--with-xlio" ) {
        $with_xlio = 1;
    } elsif ( $cmd_flag eq "--basic" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $interactive = 0;
        $install_option = 'basic';
    } elsif ( $cmd_flag eq "--guest" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $interactive = 0;
        $install_option = 'guest-os';
        $update_firmware = 0;
    } elsif ( $cmd_flag eq "--hypervisor" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $interactive = 0;
        $install_option = 'hypervisor-os';
    } elsif ( $cmd_flag eq "--kernel-only" ) {
        $interactive = 0;
        $kernel_only = 1;
        $install_option = 'kernel-only';
        @components = qw/kernel/;
    } elsif ( $cmd_flag eq "--user-space-only" ) {
        $user_space_only = 1;
        @components = qw/user/;
    } elsif ( $cmd_flag eq "--dpdk" ) {
        $interactive = 0;
        $install_option = 'dpdk';
    } elsif ( $cmd_flag eq "--ovs-dpdk" ) {
        $with_ovs_dpdk = 1;
    } elsif ( $cmd_flag eq "--upstream-libs" ) {
        # Keep for backward compatibility
    } elsif ( $cmd_flag eq "--umad-dev-rw" ) {
        $umad_dev_rw = 1;
    } elsif ( $cmd_flag eq "--umad-dev-na" ) {
        $umad_dev_na = 1;
    } elsif ( $cmd_flag eq "--msm" ) {
        $interactive = 0;
        $install_option = 'msm';
        $enable_opensm = 1;
    } elsif ( $cmd_flag eq "--eth-only" ) {
        $interactive = 0;
        $install_option = 'eth-only';
    } elsif ( $cmd_flag eq "--with-32bit" ) {
        if (supported32bit()) {
            $install32 = 1;
        }
    } elsif ( $cmd_flag eq "--without-32bit" ) {
        $install32 = 0;
    } elsif ( $cmd_flag eq "--without-depcheck" ) {
        $check_linux_deps = 0;
    } elsif ( $cmd_flag eq "--check-deps-only" ) {
        $check_deps_only = 1;
    } elsif ( $cmd_flag eq "--print-distro" ) {
        $print_distro = 1;
    } elsif ( $cmd_flag eq "--without-fw-update" ) {
        $update_firmware = 0;
    } elsif ( $cmd_flag eq "--force-fw-update" ) {
        $update_firmware = 1;
        $fw_update_flags .= " --force-fw-update";
    } elsif ( $cmd_flag eq "--fw-update-only" ) {
        $update_firmware = 1;
        $firmware_update_only = 1;
    } elsif ( $cmd_flag eq "--fw-dir" ) {
        my $firmware_directory = shift(@ARGV);
        $fw_update_flags .= " --fw-dir $firmware_directory";
        push (@saved_ARGV, $firmware_directory);
    } elsif ( $cmd_flag eq "--fw-image-dir" ) {
        my $fw_image_dir = shift(@ARGV);
        $fw_update_flags .= " --fw-image-dir $fw_image_dir";
        push (@saved_ARGV, $fw_image_dir);
    } elsif ( $cmd_flag eq "--enable-affinity" ) {
        $enable_affinity = 1;
    } elsif ( $cmd_flag eq "--disable-affinity" ) {
        $enable_affinity = 0;
    } elsif ( $cmd_flag eq "--enable-opensm" and not ($install_option eq 'eth-only' or $is_mlnx_en) ) {
        $enable_opensm = 1;
    } elsif ( $cmd_flag eq "--force" ) {
        $force = 1;
    } elsif ( $cmd_flag eq "--force-kmp" ) {
        $force_kmp = 1;
    } elsif ( $cmd_flag eq "--speed-up-kmp" ) {
        $speed_up_kmp = 1;
    } elsif ( $cmd_flag eq "--enable-sriov" ) {
        $fw_update_flags .= " --enable-sriov";
    } elsif ( $cmd_flag eq "-q" ) {
        $fw_update_flags .= " -q";
        $quiet = 1;
    } elsif ( $cmd_flag eq "-v" ) {
        $verbose = 1;
        $fw_update_flags .= " -v";
    } elsif ( $cmd_flag eq "-vv" ) {
        $verbose = 1;
        $verbose2 = 1;
        $fw_update_flags .= " -v";
    } elsif ( $cmd_flag eq "-vvv" ) {
        $verbose = 1;
        $verbose2 = 1;
        $verbose3 = 1;
        $fw_update_flags .= " -v";
    } elsif ( $cmd_flag eq "--skip-verify" ) {
        $verify = 0;
    } elsif ( $cmd_flag eq "--add-kernel-support" ) {
        $add_kernel_support = 1;
        $add_kernel_support_build_only = 0;
    } elsif ( $cmd_flag eq "--add-kernel-support-build-only" ) {
        $add_kernel_support = 1;
        $add_kernel_support_build_only = 1;
    } elsif ( $cmd_flag eq "--kernel-extra-args" ) {
        $kernel_extra = 1;
        $kernel_extra_args = shift(@ARGV);
    } elsif ( $cmd_flag eq "--kmp" ) {
        $add_kernel_support_flags .= " --kmp";
        $kmp_flag_given = 1;
    } elsif ( $cmd_flag eq "--skip-kmp-verify" ) {
        $skip_kmp_check = 1;
    } elsif ( $cmd_flag eq "--skip-repo" ) {
        $add_kernel_support_flags .= " --skip-repo";
    } elsif ( $cmd_flag eq "--auto-add-kernel-support" ) {
        $auto_add_kernel_support = 1;
    } elsif ( $cmd_flag eq "--post-start-delay" ) {
        $post_start_delay = shift(@ARGV);
        push (@saved_ARGV, $post_start_delay);
    } elsif ( $cmd_flag eq "--skip-distro-check" ) {
        $skip_distro_check = 1;
    } elsif ( $cmd_flag eq "--skip-unsupported-devices-check" ) {
        $skip_unsupported_devices_check = 1;
    } elsif ( $cmd_flag eq "--pfc" ) {
        $pfc = shift(@ARGV);
        push (@saved_ARGV, $pfc);
    } elsif ($cmd_flag eq "--with-fabric-collector" and not ($install_option eq 'eth-only' or $is_mlnx_en)) {
        $with_fabric_collector = 1;
    } elsif ( $cmd_flag eq "--enable-mlnx_tune" ) {
        $enable_mlnx_tune = 1;
    } elsif ( $cmd_flag eq "--copy-ifnames-udev" ) {
        $do_copy_udev = 1;
    } elsif ( $cmd_flag eq "--tmpdir" ) {
        $TMPDIR = shift(@ARGV);
        $TMPDIR = clean_path($TMPDIR);
        $config = $TMPDIR . '/ofed.conf' if (not $config_given);
        push (@saved_ARGV, $TMPDIR);
    } elsif ( $cmd_flag =~ /--without|--disable/ ) {
        my $pckg = $cmd_flag;
        $pckg =~ s/--without-|--disable-//;
        $disabled_packages{$pckg} = 1;
    } elsif ( $cmd_flag =~ /--with-|--enable-/ ) {
        my $pckg = $cmd_flag;
        $pckg =~ s/--with-|--enable-//;
        $force_enable_packages{$pckg} = 1;
    } elsif ( $cmd_flag eq "--distro" ) {
        $DISTRO = shift(@ARGV);
        push (@saved_ARGV, $DISTRO);
    } elsif ( $cmd_flag =~ /--pre-install-/) {
        my $pckg = $cmd_flag;
        $pckg =~ s/--pre-install-//;
        my $script = shift(@ARGV);
        $package_pre_install_script{$pckg} = $script;
        push (@saved_ARGV, $script);
    } elsif ( $cmd_flag =~ /--post-install-/) {
        my $pckg = $cmd_flag;
        $pckg =~ s/--post-install-//;
        my $script = shift(@ARGV);
        $package_post_install_script{$pckg} = $script;
        push (@saved_ARGV, $script);
    } elsif ( $cmd_flag eq "--package-install-options" ) {
        my $install_opt = shift(@ARGV);
        push (@saved_ARGV, "$install_opt");
        $install_opt =~ s/,/ /g;
        $rpminstall_flags .= " $install_opt";
    } elsif ( $cmd_flag eq "--help" or $cmd_flag eq "-h" ) {
        usage();
        exit 0;
    } elsif ( $cmd_flag eq "--script-version") {
        print_script_version();
        exit 0;
    } else {
        print RED "\nUnsupported installation option: '$cmd_flag'", RESET "\n";
        print "To see list of supported options, run: $0 --help\n";
        exit $EINVAL;
    }
}

if ($user_space_only and $kernel_only) {
    print RED "\nError: The options '--kernel-only' and '--user-space-only' are incompatible. Aborting.", RESET "\n";
    exit 1;
}

if ((not $add_kernel_support_build_only) and (not $print_available) and (not $print_distro)) {
    check_root_user();
}

my $modules_list = "$TMPDIR/mlnx_kos.$$";
system("/bin/rm -f $modules_list >/dev/null 2>&1");

for my $ver_file (qw{/etc/os-release /etc/issue}){
    next unless (-e $ver_file);

    my $format = '[%{NAME}]-[%{VERSION}]-[%{RELEASE}]\n';
    my $dist_rpm_str = `rpm -qf --queryformat '$format' $ver_file 2> /dev/null | grep -v "is not owned by any package" | head -1`;
    chomp $dist_rpm_str;
    next unless ($dist_rpm_str);

    $dist_rpm = $dist_rpm_str;
    last;
}
if (not defined $dist_rpm) {
    $dist_rpm = "unsupported";
}

if ($kernel_given and not $kernel_source_given) {
    if (-d "/lib/modules/$kernel/build") {
        $kernel_sources = "/lib/modules/$kernel/build";
    }
    else {
        print RED "Provide path to the kernel sources for $kernel kernel.", RESET "\n";
        exit 1;
    }
}

if ($with_ovs_dpdk and $arch !~ /x86_64|aarch64/) {
    print YELLOW "\nWARNING: The '--ovs-dpdk' option is supported only on x86_64 and aarch64. Disabling...", RESET "\n";
    $with_ovs_dpdk = 0;
}

#
# logging
#
my $ofedlogs = "$TMPDIR/$PACKAGE.$$.logs";
mkpath([$ofedlogs]);
my $glog = "$ofedlogs/general.log";
rmtree $glog;
open(GLOG, ">$glog") or die "Can't open $glog: $!\n";
close(GLOG);

sub print_and_log
{
    my $msg = shift @_;
    my $verb = shift @_;

    open(GLOG, ">>$glog") or die "Can't open $glog: $!\n";
    print GLOG "$msg";
    close(GLOG);

    if ($verb) {
        print "$msg";
    }
}

sub print_and_log_colored
{
    my $msg = shift @_;
    my $verb = shift @_;
    my $color = shift @_;

    open(GLOG, ">>$glog") or die "Can't open $glog: $!\n";
    print GLOG "$msg\n";
    close(GLOG);

    if ($verb) {
        if ($color eq "RED") {
            print RED "$msg", RESET "\n";
        } elsif ($color eq "YELLOW") {
            print YELLOW "$msg", RESET "\n";
        } elsif ($color eq "GREEN") {
            print GREEN "$msg", RESET "\n";
        } else {
            print "$msg\n";
        }
    }
}

print_and_log("Install command: $CMD\n", 0);

my $rpm_distro = '';

# don't auto-detect distro if it's provided by the user.
if ($DISTRO eq "") {
    print_and_log("Distro was not provided, trying to auto-detect the current distro...\n", $verbose2);
    print_and_log("dist_rpm: $dist_rpm\n", $verbose2);
    ($rpm_distro, $DISTRO) = parse_rpm_dist($dist_rpm, $kernel);

    if ($DISTRO eq "") {
        print_and_log_colored("Current operation system is not supported!", 1, "RED");
        exit 1;
    }

    print_and_log("Auto-detected $DISTRO distro.\n", $verbose2);
} else {
    print_and_log("Using provided distro: $DISTRO\n", $verbose2);

    $rpm_distro = $DISTRO;
    $rpm_distro = lc($rpm_distro);
    $rpm_distro =~ s/\./u/g;

    $DISTRO = uc ($DISTRO);
    if ($DISTRO =~ /SLES/) {
        $DISTRO =~ s/SP.*//g;
    } elsif ($DISTRO =~ /EULER/) {
        # Do nothing. Don't mangle OPENEULER.
        # FIXME: the one below is probably intended for openSUSE. Remove.
    } elsif ($DISTRO =~ /OPEN/) {
        $DISTRO =~ s/OPEN/open/g;
    }
}
if ($print_distro) {
    print_and_log("Printing distribution name and exiting:\n", $verbose2);
    print "$rpm_distro\n";
    exit 0;
}

sub warning($) {
    my $msg = shift @_;
    print_and_log_colored($msg, 1, "YELLOW");
}

my $gcc = "gcc";
my $gcc_cpp = "gcc-c++";
my $libstdc = '';
my $libgcc = 'libgcc';
my $libgfortran = '';
my $fortran = 'gcc-gfortran';
my $curl_devel = 'curl-devel';
my $libnl_devel = 'libnl-devel';
my $libnl3_devel = 'libnl3-devel';
my $libdb_devel = 'libdb-devel';
my $elfutils_devel = 'elfutils-devel';
my $iptables_devel = 'iptables-devel';
my $libmnl = 'libmnl';
my $libnl = 'libnl';
my $libnl3 = 'libnl3';
my $glib2 = 'glib2';
my $glib2_devel = 'glib2-devel';
my $glibc_devel = 'glibc-devel';
my $openssl_devel = 'openssl-devel';
my $openssl = 'openssl';
my $libcurl = 'libcurl';
my $python = "python";
my $python2 = "python2";
my $python_devel = "python-devel";
my $pkgconfig = "pkgconfig";
my $tcl_devel = 'tcl-devel';
my $zlib_devel = 'zlib-devel';
my $srvtool = "";
my $pciutils_libs = "pciutils-libs";
my $libusb = "libusbx";
my $libusb_devel = "libusbx-devel";
my $fuse_libs = "fuse-libs";

if ($DISTRO eq "openSUSE_TUMBLEWEED") {
    $libstdc = 'libstdc++6';
    $pkgconfig = "python-pkgconfig";
    $libgcc = 'libgcc_s1';
    $glib2 = "glib2-tools";
} elsif ($DISTRO eq "openSUSE12.1") {
    $libstdc = 'libstdc++46';
    $libgcc = 'libgcc46';
    $libgfortran = 'libgfortran46';
    $fortran = 'libgfortran46';
    $curl_devel = 'libcurl-devel';
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3-200';
    $glib2 = "glib2-tools";
    $libcurl = "libcurl4";
    $pkgconfig = "pkg-config";
} elsif ($DISTRO =~ m/SLES12/) {
    $libstdc = 'libstdc++6';
    $libgcc = 'libgcc_s1';
    $libgfortran = 'libgfortran3';
    $curl_devel = 'libcurl-devel';
    $fortran = "gcc-fortran";
    $openssl_devel = 'libopenssl-devel';
    $openssl = 'libopenssl1_0_0';
    $libcurl = "libcurl4";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3-200';
    $glib2 = 'libglib-2_0-0';
    $pkgconfig = "pkg-config";
    $libdb_devel = 'libdb-4_8-devel';
    $elfutils_devel = 'libelf-devel';
    $iptables_devel = 'libxtables-devel';
    $libmnl = 'libmnl0';
} elsif ($DISTRO =~ m/SLES15/) {
    $libstdc = 'libstdc++6-devel-gcc7';
    $libgcc = 'libgcc_s1';
    $curl_devel = 'libcurl-devel';
    $fortran = "gcc-fortran";
    $openssl_devel = 'libopenssl-devel';
    $openssl = 'libopenssl1_1';
    $libcurl = "libcurl4";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3-200';
    $glib2 = 'libglib-2_0-0';
    $pkgconfig = "pkg-config";
    $libdb_devel = 'libdb-4_8-devel';
    $elfutils_devel = 'libelf-devel';
    $libmnl = 'libmnl0';
    $iptables_devel = 'libxtables-devel';
    $libgfortran = "libgfortran4";
    $python = "python3";
    $python_devel = "python3-devel";
} elsif ($DISTRO =~ m/RHEL|OL|FC|POWERKVM|EULER|BCLINUX|ALIOS/) {
    $libstdc = 'libstdc++';
    $libgcc = 'libgcc';
    $libgfortran = 'gcc-gfortran';
    $curl_devel = 'libcurl-devel';
    if ($DISTRO =~ /FC19|FC[2-9]|OL[7-9]|RHEL[7-9]|POWERKVM|EULER|BCLINUX|ALIOS/) {
        $openssl = 'openssl-libs';
    }
    if ($DISTRO =~ /RHEL6\.|OL6\./) {
        $libdb_devel = 'db4-devel';
        $libnl3 = '';
        $libnl3_devel = '';
    }
    if ($DISTRO =~ m/EULER/) {
        $libnl_devel = 'libnl3-devel';
    }
}else {
    $libstdc = 'libstdc++';
}

if ($DISTRO =~ /(SLES|openSUSE)1[25] | openSUSE_TUMBLEWEED/x) {
    $libnl3 = 'libnl3-200';
    $pciutils_libs = "libpci3";
    $libusb = "libusb-1_0-0";
    $libusb_devel = "libusb-1_0-devel";
    $fuse_libs = "libfuse2";
}

my $libstdc_devel = "$libstdc-devel";
my $libexpat = "expat";
my $libexpat_devel = "";
my $tk = "tk";
my $insserv_compat = "";

if ($DISTRO =~ m/SLES12/) {
    $libstdc_devel = 'libstdc++-devel';
} elsif ($DISTRO =~ m/SLES15/){
    $srvtool = "insserv-compat";
    $libstdc_devel = "libstdc++6-devel-gcc7";
    $insserv_compat = "insserv-compat";
} elsif ($DISTRO eq "openSUSE_TUMBLEWEED") {
    $libstdc_devel = 'libstdc++6-devel-gcc5';
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3-200';
} elsif ($DISTRO =~ m/RHEL5.[4-6]|RHEL6|RHEL7|OL6|OL7|EULER|BCLINUX7|ALIOS/) {
    $libexpat_devel = "expat-devel";
} elsif ($DISTRO =~ m/RHEL5.3/) {
    $libexpat_devel = "expat-devel";
} elsif ($DISTRO =~ m/WINDRIVER6/) {
    $gcc = "toolchain-wrappers";
    $gcc_cpp = "toolchain-wrappers";
    $python = "python-core";
    $python_devel = "python-dev";
    $libgcc = 'libgcc1';
    $libnl_devel = 'libnl-3-dev';
    $libnl = 'libnl-3-200';
    $libstdc = "libstdc++6";
    $libstdc_devel = "libstdc++-dev";
    $libexpat = "libexpat1";
    $libexpat_devel = "libexpat-dev";
    $tk = "";
    $curl_devel = 'curl-dev';
    $glib2 = 'libglib-2.0-0';
    $glib2_devel = 'libglib-2.0-dev';
    $glibc_devel = 'libc6-dev';
    $tcl_devel = 'tcl-dev';
    $zlib_devel = 'libz-dev';
} elsif ($DISTRO =~ m/POWERKVM | FC2[2-9] | FC3./x) {
   $libexpat_devel = "expat-devel";
   $libnl_devel = 'libnl3-devel';
   $libnl = 'libnl3';
} elsif ($DISTRO =~ m/BLUENIX1/) {
    $gcc_cpp = "g++";
    $python = "python-core";
    $python_devel = "python-dev";
    $libgcc = 'libgcc1';
    $libnl_devel = 'libnl-3-dev';
    $libnl = 'libnl-3-200';
    $libstdc = "libstdc++6";
    $libstdc_devel = "libstdc++-dev";
    $libexpat = "libexpat1";
    $libexpat_devel = "libexpat-dev";
    $tk = "";
    $curl_devel = 'curl-dev';
    $glib2 = 'libglib-2.0-0';
    $glib2_devel = 'libglib-2.0-dev';
    $glibc_devel = 'libc6-dev';
    $tcl_devel = 'tcl-dev';
    $zlib_devel = 'libz-dev';
} else {
    $libexpat_devel = "expat-devel";
}

my $libudev = "libudev";
my $libudev_devel = "libudev-devel";
if ($DISTRO =~ m/SLES12|SLES15/) {
    $libudev = "libudev1";
    $python2 = "python";
} elsif ($DISTRO =~ m/RHEL[7-9]|OL[78]|FC|EULER|POWERKVM|BCLINUX|ALIOS|CTYUNOS/) {
    $libudev = "systemd-libs";
    $libudev_devel = "systemd-devel";
} elsif ($DISTRO =~ m/WINDRIVER6/) {
    $libudev = "libudev0";
    $libudev_devel = "udev-dev";
} elsif ($DISTRO =~ m/BLUENIX1|XenServer/) {
    $libudev = "";
    $libudev_devel = "";
}

my $kernel_modules_extra = "";
if ($DISTRO =~ m/RHEL8/ and $DISTRO !~ /RHEL8.6/) {
    $kernel_modules_extra = "kernel-modules-extra";
}

if ($DISTRO =~ /UOS/) {
    $python = "python2";
    $python_devel = "python2-devel";
    $pkgconfig = "pkgconf";
    $fuse_libs = "fuse";
    $pciutils_libs = "pciutils";
    $libnl = "libnl3";
    $libnl_devel = "libnl3-devel";
    $libudev = "systemd-libs";
    $libudev_devel = "systemd-devel";
}

# Suffix for 32 and 64 bit packages
my $is_suse_suff64 = $arch eq "ppc64" && $DISTRO !~ /SLES12/;
my $suffix_32bit = ($DISTRO =~ m/SLES|openSUSE/ && !$is_suse_suff64) ? "-32bit" : ".$target_cpu32";
my $suffix_64bit = ($DISTRO =~ m/SLES|openSUSE/ &&  $is_suse_suff64) ? "-64bit" : "";
if ($DISTRO =~ m/SLES|openSUSE/) {
    $sysfsutils = "sysfsutils";
    $sysfsutils_devel = "sysfsutils";
} elsif ($DISTRO =~ m/RHEL5/) {
    $sysfsutils = "libsysfs";
    $sysfsutils_devel = "libsysfs";
} elsif ($DISTRO =~ m/RHEL6|RHEL7|OL6|OL7|POWERKVM|EULEROS2.0SP[235]|BCLINUX7|ALIOS/) {
    $sysfsutils = "libsysfs";
    $sysfsutils_devel = "libsysfs";
} elsif ($DISTRO =~ m/BLUENIX1/) {
    $sysfsutils = "sysfsutils";
    $sysfsutils_devel = "sysfsutils-dev"
}

if ($DISTRO =~ m/FC2[6-9]/x) {
    $srvtool = "chkconfig";
    $python = "python2";
    $python_devel = "python2-devel";
    $pkgconfig = "pkgconf-pkg-config";
}

if ($DISTRO =~ m/FC3./x) {
    $srvtool = "chkconfig";
    $python = "python3";
    $python_devel = "python3-devel";
    $pkgconfig = "pkgconf-pkg-config";
}

if ($DISTRO =~ m/RHEL8 | OL8/x) {
    $python = "python36";
    $python_devel = "python36-devel";
    $pkgconfig = "pkgconf-pkg-config";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
}

if ($DISTRO =~ m/RHEL9/x) {
    $python = "python3";
    $python_devel = "python3-devel";
    $pkgconfig = "pkgconf-pkg-config";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
}

if ($DISTRO =~ m/EULEROS2.0SP8/x) {
    $python = "python2";
    $python_devel = "python2-devel";
    $pkgconfig = "pkgconf-pkg-config";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
}

if ($DISTRO =~ m/OPENEULER | EULEROS2.0SP9 | EULEROS2.0SP10 | BCLINUX21 | CTYUNOS/x) {
    $python = "python3";
    $python_devel = "python3-devel";
    $pkgconfig = "pkgconf";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
    $fuse_libs = "fuse-devel";
    $pciutils_libs = "pciutils-devel";
}

if ($DISTRO =~ m/KYLIN/x) {
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
    $libudev = "systemd-libs";
    $libudev_devel = "systemd-devel";
    $python = "python2";
    $python_devel = "python2-devel";
    $fuse_libs = "fuse";
    $pkgconfig = "pkgconf";
    $pciutils_libs = "pciutils";
}


my $update_initrd_cmd = "dracut -f";

# build with libnl3 on RHEL7, the libnl3-devel here comes from Optional packages
if ($DISTRO =~ m/RHEL7|OL7|BCLINUX7|ALIOS/) {
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
}

if ($DISTRO =~ m/RHEL7|OL7|XenServer|BCLINUX7|ALIOS/) {
    $python2 = "python";
}

if ($DISTRO =~ m/FC3./x) {
    $insserv_compat = "chkconfig";
    $python2 = "python27";
}

if ($DISTRO =~ m/BCLINUX8/) {
    $python = "python36";
    $python_devel = "python36-devel";
    $libnl_devel = 'libnl3-devel';
    $libnl = 'libnl3';
    $pkgconfig = "pkgconf-pkg-config";
}

my $network_dir;
if ($DISTRO =~ m/SLES/) {
    $network_dir = "/etc/sysconfig/network";
}
elsif ($DISTRO =~ m/BLUENIX1/) {
    $network_dir = "/etc/network";
} else {
    $network_dir = "/etc/sysconfig/network-scripts";
}

if (not supported32bit()) {
    $install32 = 0;
}

if ($update and $install32) {
    print_and_log_colored("Update is not supported for 32-bit libraries.", 1, "RED");
    exit $ENOSPC if (not $force);
    print_and_log_colored("Disabling update. The previous version will be removed...", 1, "YELLOW");
    $update = 0;
}

$uninstall = 0 if ($update);
$rpminstall_parameter = "-U" if ($update);
my $bf_krpm_regex = "(gpio-mlxbf|i2c-mlx|mlxbf-livefish|mlx-bootctl|pka-mlxbf|tmfifo|mlxbf-gige|mlx-trio|gpio-mlxbf2|mlx-pmc)";

if ("$MLNX_OFED_DISTRO" eq "skip-distro-check") {
    $skip_distro_check = 1;
}
if (not $skip_distro_check and not $is_ux) {
    if ($MLNX_OFED_DISTRO =~ /rhel/ and $DISTRO =~ /OL/) {
        # enable using RHEL pacakge on OL distros
        $DISTRO =~ s/OL/RHEL/g;
        $rpm_distro =~ s/ol/rhel/g;
    }
    if ($MLNX_OFED_DISTRO ne lc($DISTRO) and $MLNX_OFED_DISTRO ne $rpm_distro) {
        print_and_log_colored("Error: The current $PACKAGE is intended for $MLNX_OFED_DISTRO", 1, "RED");
        exit $PREREQUISIT;
    }
}

my $openvswitch = "";
if (($with_bluefield or $with_ovs_dpdk) and
        $DISTRO =~ /RHEL[78] | FC3[0-9]/x) {
    $openvswitch = "openvswitch";
}

sub invoke_add_kernel_support
{
    my $new_package = "$PACKAGE-$MLNX_OFED_LINUX_VERSION-" . lc($DISTRO) . "-ext";
    my $flags = $add_kernel_support_flags;
    if ($force) {
        $flags .= " --force";
    }
    for my $key ( keys %disabled_packages ) {
        $flags .= " --without-$key";
    }
    if (not $check_linux_deps) {
        $flags .= " --without-depcheck";
    }
    my $dist = $DISTRO;
    if ($dist =~ /SLES|SUSE/i) {
        $dist = $rpm_distro;
    }
    if ($kernel_extra) {
        $ENV{'MLNX_EXTRA_FLAGS'} = "$ENV{'MLNX_EXTRA_FLAGS'} --kernel-extra-args $kernel_extra_args";
    }
    system("TMP=$TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel '$CWD/mlnx_add_kernel_support.sh' -m '$CWD' -k $kernel -s '$kernel_sources' --make-tgz --name $new_package --yes $flags --distro $dist");
    my $res = $? >> 8;
    my $sig = $? & 127;
    # mlnx_add_kernel_support.sh gives exit status 30 when kernel already supported (w/o KMP support).
    if ($sig == 30 or $res == 30) {
        print_and_log("Kernel $kernel is already supported.\n", ($verbose2 or $add_kernel_support_build_only) ? 1 : 0);
        if ($add_kernel_support_build_only) {
            exit $SUCCESS;
        }
        print_and_log("Resuming installation from current MLNX_OFED package...\n", $verbose2);
        uninstall();
        return;
    }
    if ($sig or $res) {
        print_and_log_colored("Failed to build $PACKAGE for $kernel", 1, "RED");
        exit $ERROR;
    }

    if ( -e "$TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package.tgz") {
        if ($add_kernel_support_build_only) {
            print_and_log("New image ready at: $TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package.tgz\n", 1);
            exit $SUCCESS;
        }
        uninstall();
        print_and_log_colored("Installing $TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package", 1, "GREEN");
        system("/bin/rm -rf $TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package");
        system("cd $TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel; tar xzf $new_package.tgz");
        print_and_log("$TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package/$INSTALLER --force @saved_ARGV\n", 1);
        system("$TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package/$INSTALLER", "--force", @saved_ARGV);
        my $res = $? >> 8;
        my $sig = $? & 127;
        if ($sig or $res) {
            print_and_log_colored("Failed to install $new_package for $kernel", 1, "RED");
            exit $ERROR;
        }
    } else {
        print_and_log_colored("New package was not created at '$TMPDIR/$PACKAGE-$MLNX_OFED_LINUX_VERSION-$kernel/$new_package.tgz' !", 1, "RED");
        exit $ERROR;
    }
    exit $SUCCESS;
}

my $components_filter = get_components_filter(0, [@components]);

if ($add_kernel_support and not $print_available) {
    invoke_add_kernel_support();
}

if ($config_given and $install_option) {
    $install_option = '';
}

if ($config_given and not -e $config) {
    print_and_log_colored("$config does not exist", 1, "RED");
    exit $ERROR;
}

if (not $config_given and -e $config) {
    move($config, "$config.save");
}

if ($quiet) {
    $verbose = 0;
    $verbose2 = 0;
    $verbose3 = 0;
}

my %ifcfg = ();
if ($config_net_given and not -e $config_net) {
    print_and_log_colored("$config_net does not exist", 1, "RED");
    exit $ERROR;
}

my $eth_dev;
if ($config_net_given) {
    open(NET, "$config_net") or die "Can't open $config_net: $!";
    while (<NET>) {
        my ($param, $value) = split('=');
        chomp $param;
        chomp $value;
        my $dev = $param;
        $dev =~ s/(.*)_(ib[0-9]+)/$2/;
        chomp $dev;

        if ($param =~ m/IPADDR/) {
            $ifcfg{$dev}{'IPADDR'} = $value;
        }
        elsif ($param =~ m/NETMASK/) {
            $ifcfg{$dev}{'NETMASK'} = $value;
        }
        elsif ($param =~ m/NETWORK/) {
            $ifcfg{$dev}{'NETWORK'} = $value;
        }
        elsif ($param =~ m/BROADCAST/) {
            $ifcfg{$dev}{'BROADCAST'} = $value;
        }
        elsif ($param =~ m/ONBOOT/) {
            $ifcfg{$dev}{'ONBOOT'} = $value;
        }
        elsif ($param =~ m/LAN_INTERFACE/) {
            $ifcfg{$dev}{'LAN_INTERFACE'} = $value;
        }
        else {
            print_and_log_colored("Unsupported parameter '$param' in $config_net", $verbose2, "RED");
        }
    }
    close(NET);
}

my $kernel_rel = $kernel;
$kernel_rel =~ s/-/_/g;
if ($DISTRO =~ /KYLIN/ ) {
    $kernel_rel = "$kernel_rel.ky10";
}

if ($DISTRO =~ m/WINDRIVER6|BLUENIX1/) {
    $rpminstall_flags .= ' --nodeps';
}

if (not $check_linux_deps) {
    $rpminstall_flags .= ' --nodeps';
}

if ($kmp and ($DISTRO =~ m/XenServer|RHEL5.2|FC|WINDRIVER6|POWERKVM|BLUENIX1|KYLIN/ or $kernel =~ /xs|fbk|fc|debug/)) {
    $kmp = 0;
}

# Disable KMP for kernels incompatible with the original Distro's kernel
if ($kmp) {
    # RHEL
    if (($DISTRO eq "EULEROS2.0SP2" and $kernel !~ /3.10.0-327.*$arch/) or
        ($DISTRO eq "EULEROS2.0SP3" and $kernel !~ /3.10.0-514.*$arch/) or
        ($DISTRO eq "EULEROS2.0SP5" and $kernel !~ /3.10.0-862\..*eulerosv2r7\.$arch/) or
        ($DISTRO eq "EULEROS2.0SP8" and $kernel !~ /4.19.36-vhulk1907\..*\.$arch/) or
        ($DISTRO eq "EULEROS2.0SP9" and $arch eq "x86_64" and $kernel !~ /4.18.0-147.5.*$arch/) or
        ($DISTRO eq "EULEROS2.0SP9" and $arch eq "aarch64" and $kernel !~ /4.19.90-vhulk*.*\.$arch/) or
        ($DISTRO eq "OPENEULER20.03" and $kernel !~ /4.19.90-.*\.$arch/) or
        ($DISTRO =~ "RHEL8" and $kernel !~ /4.18.0-.*el8.*$arch/) or
        ($DISTRO eq "RHEL7.4ALTERNATE" and $kernel !~ /4.11.0-.*el7a.*$arch/) or
        ($DISTRO eq "RHEL7.5ALTERNATE" and $kernel !~ /4.14.0-.*el7a.*$arch/) or
        ($DISTRO eq "RHEL7.6ALTERNATE" and $kernel !~ /4.14.0-.*el7a.*$arch/) or
        ($DISTRO =~ /RHEL7\.\d+$/ and $kernel !~ /3.10.0-.*el7.*$arch/) or
        ($DISTRO =~ "RHEL6" and $kernel !~ /2.6.32-.*el6.*$arch/)) {
        $kmp = 0;
    }
    # SLES
    if (($rpm_distro eq "sles12sp1" and $kernel !~ /3.12.[1-9]+-[0-9].*/) or
        ($rpm_distro eq "sles12sp2" and $kernel !~ /4.4.[1-9]+-[0-9].*/) or
        ($rpm_distro eq "sles12sp3" and $kernel !~ /4.4.[0-9]+-[0-9].*/) or
        ($rpm_distro eq "sles12sp4" and $kernel !~ /4.12.[0-9]+-[0-9].*/) or
        ($rpm_distro eq "sles12sp0" and $kernel !~ /3.12.[1-9][2-9]-[0-9].*/) or
        ($rpm_distro eq "sles15sp0" and $kernel !~ /4.12.[1-9][2-9]-[0-9].*/) or
        ($rpm_distro eq "sles15sp1" and $kernel !~ /4.12.14-[0-9].*/)) {
        $kmp = 0;
    }
    # OpenSUSE
    if (($DISTRO eq "openSUSE12.1" and $kernel !~ /3\.1\.[0-9]/) or
        ($DISTRO eq "openSUSE_TUMBLEWEED" and $kernel !~ /4\.3\.0/)) {
        $kmp = 0;
    }
    # Oracle
    if (($DISTRO =~ /^(OL7\.[016-9] | OL6\.[1-6] | OL5\..*)$/x)
        or ($DISTRO eq "OL6.7" and $kernel !~ /3\.8\.13-68\..*el6uek/)
        or ($DISTRO eq "OL6.8" and $kernel !~ /4\.1\.12-37\..*el6uek/)
        or ($DISTRO eq "OL6.9" and $kernel !~ /4\.1\.12-61\..*el6uek/)
        or ($DISTRO eq "OL6.10" and $kernel !~ /4\.1\.12-124\..*el6uek/)
        or ($DISTRO eq "OL7.2" and $kernel !~ /3\.8\.13-92\..*el7uek/)
        or ($DISTRO eq "OL7.3" and $kernel !~ /4\.1\.12-61\..*el7uek/)
        or ($DISTRO eq "OL7.4" and $kernel !~ /4\.1\.12-94\..*el7uek/)
        or ($DISTRO eq "OL7.5" and $kernel !~ /4\.14\.35-1818\..*el7uek/)
       ) {
        $kmp = 0;
    }
}

# was add kernel support ran for this kernel and --kmp not given?
if (not $kmp_flag_given and isKernelSupported()) {
    $kmp = 0;
}

# $speed_up_kmp is supported on RHEL only
if ($DISTRO !~ /RHEL/ or not $kmp) {
    print_and_log("WARNING: Speed up kmp is supported on RHEL only with in-box the kernel. Turning off...\n") if ($speed_up_kmp);
    $speed_up_kmp = 0;
}

if ($DISTRO =~ /SLES|SUSE/) {
    $package_manager = "zypper";
} elsif ($DISTRO =~ /BLUENIX/) {
    $package_manager = "smart";
} else {
    $package_manager = "yum";
}

my @distro_ofed_packages = (
                        "libamso", "libamso-devel", "dapl2", "dapl2-devel", "mvapich", "mvapich2", "mvapich2-devel",
                        "mvapich-devel", "libboost_mpi1_36_0", "libmthca-rdmav2", "libcxgb3-rdmav2",
                        "libmlx4-rdmav2", "libibmad1", "libibumad1", "libibcommon1", "ofed", "ofed-doc", "ofa",
                        "libibumad3", "mpitests-mvapich", "mpitests-mvapich2", "openmpi",
                        "rdma-ofa-agent", "rdma", "rdma-core", "rdma-core-devel", "rsocket", "libosmcomp3",
                        "libcxgb4","libcxgb4_sock","libcxgb4-debuginfo","libcxgb4_sock-devel","libcxgb4_udp",
                        "libcxgb4-devel","libcxgb4_sock-debuginfo","libcxgb4_udp-debuginfo","libcxgb4_udp-devel",
                        "libibmad5", "libmlx5", "librxe", "librxe-devel-static", "librxe-debuginfo",
                        );

my @mlnx_en_packages = (
                       "mlnx_en", "mlnx-en-devel", "mlnx_en-devel", "mlnx_en-doc", "mlnx-ofc", "mlnx-ofc-debuginfo",
                       "hp-mlnx-en", "mellanox-mlnx-en", "rdma", "rdma-core" ,"rdma-core-devel"
                        );

# List of all available packages sorted following dependencies
my $kernel_rpm;
my $knem_rpm = "knem";
my $knem_mods = "knem-modules";
my $xpmem_mods = "xpmem-modules";
my $kernel_mft_rpm;
my $en_kernel_rpm;

if ($kmp) {
    $kernel_rpm = "mlnx-ofa_kernel";
    $knem_mods = ""; # we have KMPs instead
    $xpmem_mods = "xpmem";
    $kernel_mft_rpm = "kernel-mft-mlnx";
    $en_kernel_rpm = "mlnx-en";
} else {
    $kernel_rpm = "mlnx-ofa_kernel-modules";
    $kernel_mft_rpm = "kernel-mft";
    $en_kernel_rpm = "mlnx_en";
}

my @bf_only_kernel_packages = ("gpio-mlxbf", "i2c-mlx", "mlxbf-livefish", "mlx-bootctl", "pka-mlxbf", "tmfifo", "mlx-trio", "gpio-mlxbf2", "mlx-pmc", "mlxbf-gige");
my @kernel_packages = ($kernel_rpm, "mlnx-ofa_kernel-devel", "mlnx-ofa_kernel-source", "$kernel_mft_rpm", "$knem_rpm", $knem_mods, $xpmem_mods, 'iser', 'srp', 'isert', 'mlnx-nfsrdma', 'mlnx-nvme', 'mlnx-rdma-rxe', @bf_only_kernel_packages);

my @basic_kernel_modules = ("core", "mlxfw", "ipoib");
my @ulp_modules = ("sdp", "srp", "srpt", "rds", "iser", 'isert');
my @kernel_modules = (@basic_kernel_modules, @ulp_modules);

my $kernel_configure_options;
my $user_configure_options;

my @misc_packages = ("mlnxofed-docs", "ofed-scripts", "mlnx-tools", "neohost-backend", "neohost-sdk");

# The entries will be added later in add_new_mpitests_pkg function.
my @mpitests_packages = ();

my @mpi_packages = ( "mpi-selector",
                     "openmpi",
                     @mpitests_packages
                    );

my @user_packages = (
                     "libibverbs", "rdma-core-devel",
                     "libibverbs-utils",
                     "rdma-core-debuginfo",
                     "libibumad",
                     "ibsim", "ibsim-debuginfo", "ibacm",
                     "librdmacm", "librdmacm-utils",
                     "opensm", "opensm-libs", "opensm-devel", "opensm-debuginfo", "opensm-static",
                     "dapl", "dapl-devel", "dapl-devel-static", "dapl-utils", "dapl-debuginfo",
                     "perftest", "multiperf", "mstflint", "mft",
                     "srp_daemon",
                     "ibutils2", "cc_mgr", "dump_pr", "ar_mgr", "ibdump",
                     "infiniband-diags",
                     "dpcp",
                     "ucx", "ucx-devel", "ucx-static", "sharp",
                     "ucx-cma", "ucx-ib", "ucx-ib-cm", "ucx-rdmacm", "ucx-cuda", "ucx-gdrcopy", "ucx-knem", "ucx-xpmem",
                     @mpi_packages, "hcoll", "hcoll-cuda",
                     "libvma", "libvma-utils", "libvma-devel", "libvma-debuginfo",
                     "libxlio", "libxlio-utils", "libxlio-devel",
                     "sockperf",
                     "fabric-collector", "fabric-collector-debuginfo",
                     "mlnx-ethtool", "mlnx-iproute2", "neohost-backend", "neohost-sdk",
                     "$openvswitch", "spdk",
                     "libpka", "mlxbf-bootctl", "mlxbf-bootimages", "bfscripts", "nvme-snap", "rshim",
                     "xpmem", "libxpmem", "$xpmem_mods",
                     "clusterkit",
                     );

my $systemd_rpm_macros = "systemd";
if ($DISTRO =~ /SLES/) {
    $systemd_rpm_macros = "systemd-rpm-macros";
}

# List of packages that were included in the previous OFED releases
# for uninstall purpose

my @mft_packages = (
                   "mft-int", "kernel-mft", "mft-compat", "mft-oem",
                   );

my @dpdk_packages = (
                   "mlnx-dpdk", "mlnx-dpdk-devel",
                   );

my @prev_ofed_packages = (
    "kernel-ib", "kernel-ib-devel", "mlnx-ofa_kernel", "mlnx-ofa_kernel-source",
    "mpich_mlx", "ibtsal", "openib",
    "opensm", "opensm-devel", "opensm-libs", "opensm-libs3",
    "opensm-debuginfo", "opensm-static",
    "libopensmssa", "libopensmssa-debuginfo", "ibssa", "ibssa-debuginfo",
    "ibacm_ssa", "ibacm_ssa-devel","ibacm_ssa-debuginfo",
    "mpi_ncsa", "mpi_osu", "thca", "ib-osm", "osm", "diags", "ibadm",
    "ib-diags", "ibgdiag", "ibdiag", "ib-management",
    "ib-verbs", "ib-ipoib", "ib-cm", "ib-sdp", "ib-dapl",
    "udapl", "udapl-devel", "libdat", "libibat", "ib-kdapl", "ib-srp", "ib-srp_target",
    "libehca", "libehca-devel-static", "libehca-debuginfo",
    "libibcm", "libibcm-devel", "libibcm-debuginfo",
    "ibvexdmtools", "libibcommon", "libibcommon-devel",
    "libibmad", "libibmad-devel", "libibmad-static", "libibmad-debuginfo",
    "libibumad", "libibumad-devel", "libibumad-static", "libibumad-debuginfo",
    "ibsim", "ibsim-debuginfo", "ibacm",
    "ar_mgr", "dump_pr",
    "hcoll", "hcoll-cuda",
    "knem",
    "qperf",
    "ucx", "ucx-cma", "ucx-cuda", "ucx-devel", "ucx-gdrcopy", "ucx-ib", "ucx-ib-cm",
    "ucx-knem", "ucx-rdmacm",
    "libibprof",
    "libibverbs1", "libibverbs", "libibverbs-devel", "libibverbs-utils",
    "libibverbs-devel-static", "libibverbs-runtime", "libibverbs1-32bit",
    "libibverbs-debuginfo",
    "libipathverbs", "libipathverbs-devel", "libipathverbs-debuginfo",
    "libmthca", "libmthca-devel-static", "libmthca-debuginfo",
    "libmlx5", "libmlx5-devel", "libmlx5-debuginfo",
    "libmlx4", "libmlx4-devel", "libmlx4-debuginfo",
    "mlx4_accl", "mlx4_accl_sys",
    "librdmacm1", "librdmacm", "librdmacm-utils", "librdmacm-devel", "librdmacm-debuginfo",
    "openib-diags", "openib-mstflint", "openib-perftest", "openib-srptools", "openib-tvflash",
    "openmpi", "openmpi-devel", "openmpi-libs",
    "openmpi-psm", "compat-openmpi", "compat-openmpi-psm", "mpitests-openmpi",
    @mpi_packages,
    "openshmem", "bupc", "fca",
    "ibutils", "ibutils-devel", "ibutils-libs",
    "ibutils2", "ibutils2-devel",
    "libnes", "libnes-devel", "libnes-devel-static", "libnes-debuginfo",
    "infinipath-psm", "infinipath-psm-devel",
    "mellanox-firmware", "mellanox-ofed", "mlnxofed",
    @mft_packages,
    "compat-dapl", "compat-dapl-devel", "compat-dapl-utils",
    "dapl", "dapl-devel", "dapl-devel-static", "dapl-utils", "dapl-debuginfo",
    "mvapich", "mvapich2",
    "mvapich_gcc", "openmpi_gcc", "mvapich2_gcc", "mpitests_mvapich2", "mpitests_openmpi",
    "fabric-collector", "fabric-collector-debuginfo",
    "libsdp", "libsdp-devel", "libsdp-debuginfo",
    "sdpnetstat-debuginfo", "sdpnetstat",
    "intel-mic-ofed-dapl-utils",
    "mlnx-ethtool", "mlnx-ethtool-debuginfo",
    "mlnx-iproute2",
    "libdisni", "libdisni-devel", "libdisni-debuginfo",
    "$openvswitch", "spdk",
    "libpka", "mlxbf-bootctl", "mlxbf-bootimages", "bfscripts", "nvme-snap", "rshim",
    "perftest", "multiperf", "multiperf-debuginfo",
    "libusnic_verbs",
    "mlnx-fw-updater",
    "srp_daemon",
    "libmlx5-1",
    "mxm",
    "mellanox-mlnxen",
    "libiwpm",
    "infiniband-diags", "infiniband-diags-compat", "libibnetdisc5",
    "infiniband-diags-devel", "infiniband-guest",
    "mlx-steering-dump",
    "libmlx5-rdmav2",
    "librxe", "librxe-devel-static", "librxe-debuginfo",
    "libmverbs", "libmverbs-devel", , "libmqe", "libmqe-devel",
    "libcxgb3", "libcxgb3-devel", "libcxgb3-debuginfo",
    "libcxgb4", "libcxgb4-devel", "libcxgb4-debuginfo",
    "compat-opensm-libs", "opensm-libs3",
    "mstflint",
    "qlvnictools", "srptools", "rds-tools", "rds-devel", "rnfs-utils",
    "ofed-docs", "ofed-scripts", "mlnx-tools",
    "libamso-rdmav2", "libamso-rdmav2-devel",
    "hp-mlnx_ofed", "mellanox-mlnx_en",
    "libvma", "libvma-utils", "libvma-devel", "libvma-debuginfo",
    "sockperf", "sockperf-debuginfo",
    "neohost-backend", "neohost-sdk",
    );

my @basic_kernel_packages = ($kernel_rpm, "mlnx-ofa_kernel-devel", "$kernel_mft_rpm", "iser", "srp", 'isert', 'mlnx-nfsrdma', 'mlnx-nvme', 'mlnx-rdma-rxe', 'mlxbf-gige');
my @basic_user_packages = (@misc_packages, "libibverbs", "libibverbs-utils",
                            "librdmacm", "librdmacm-utils",
                            "mstflint", "mft", "mlnx-ethtool", "mlnx-iproute2");

my @bluefield_kernel_packages = ();
if ($is_bf) {
	push(@basic_kernel_packages, @bf_only_kernel_packages);
	@bluefield_kernel_packages = (@basic_kernel_packages, $knem_rpm, $knem_mods);
} else {
	@bluefield_kernel_packages = (@basic_kernel_packages, @bf_only_kernel_packages, $knem_rpm, $knem_mods);
}

my @bluefield_kernel_modules = ("core", "mlxfw", "mlx5", "ipoib", "iser", "isert");
my @bluefield_user_packages = ("libibverbs", "rdma-core-devel", "libibverbs-utils", "librdmacm", "librdmacm-utils", "ibacm", "perftest","mstflint", "infiniband-diags", "opensm", "opensm-libs", "opensm-devel", "opensm-static", "mft", "mft-oem", "ibutils2", "mlnx-ethtool", "mlnx-iproute2", "openvswitch", "libpka", "mlxbf-bootctl", "mlxbf-bootimages", "bfscripts", "nvme-snap", "spdk", "ucx", "ucx-devel", "ucx-static", "ucx-cma", "ucx-ib", "ucx-ib-cm", "ucx-knem", "ucx-rdmacm");
my @hpc_kernel_packages = (@basic_kernel_packages, "$knem_rpm", $knem_mods);
my @hpc_kernel_modules = (@basic_kernel_modules);
my @hpc_user_packages = (@basic_user_packages, "ucx", "ucx-devel", "ucx-static", "ibacm", "librdmacm",
                        "ucx-cma", "ucx-ib", "ucx-ib-cm", "ucx-knem", "ucx-rdmacm", "ucx-xpmem",
                        "librdmacm-utils", "dapl", "dapl-devel", "dapl-devel-static", "dapl-utils",
                        "infiniband-diags", "ibutils2", "cc_mgr", "dump_pr", "ar_mgr", "ibdump", "mstflint", "perftest", "multiperf", @mpi_packages, "hcoll", "sharp");

my @vma_kernel_packages = (@basic_kernel_packages);
my @vma_kernel_modules = (@basic_kernel_modules);
my @vmavpi_user_packages = ("libibverbs", "rdma-core-devel", "libibverbs-utils",
                            "ibacm", "librdmacm", "librdmacm-utils", "perftest", "multiperf", "mstflint", "infiniband-diags",
                            "opensm", "opensm-libs", "opensm-devel", "opensm-static", "mft", "ibutils2", "ibdump", @misc_packages, "libvma", "libvma-utils", "libvma-devel", "sockperf", "mlnx-ethtool",
                            "mlnx-iproute2", "dpcp", "rshim",
                            );
my @vma_user_packages = (@vmavpi_user_packages);
my @vmaeth_user_packages = ("libibverbs", "rdma-core-devel", "libibverbs-utils",
                            "ibacm", "librdmacm", "librdmacm-utils", "perftest", "multiperf", "mstflint", "mft", "ibutils2",
                            "rshim", 
                            @misc_packages, "libvma", "libvma-utils", "libvma-devel", "sockperf", "mlnx-ethtool", "mlnx-iproute2", "dpcp");

my @xlio_kernel_packages = (@basic_kernel_packages);
my @xlio_kernel_modules = (@basic_kernel_modules);
my @xlio_user_packages = ("libibverbs", "rdma-core-devel", "libibverbs-utils",
                            "ibacm", "librdmacm", "librdmacm-utils", "perftest", "multiperf", "mstflint", "infiniband-diags",
                            "opensm", "opensm-libs", "opensm-devel", "opensm-static", "mft", "ibutils2", "ibdump", @misc_packages, "sockperf", "mlnx-ethtool",
                            "mlnx-iproute2", "dpcp", "libxlio", "libxlio-utils", "libxlio-devel", "rshim",
                            );
my @msm_kernel_packages = ($kernel_rpm, "$kernel_mft_rpm", "iser", "srp", 'isert', 'mlnx-nfsrdma', 'mlnx-nvme', 'mlnx-rdma-rxe');
my @msm_kernel_modules = (@basic_kernel_modules);
my @msm_user_packages = (@basic_user_packages,
                        "infiniband-diags", "opensm", "mstflint",
                        );

my @hypervisor_kernel_packages = (@basic_kernel_packages);
my @guest_kernel_packages = (@basic_kernel_packages);
my @guest_kernel_modules = ("ipoib","core","mlxfw","mlx4_ib","srp");
my @hypervisor_kernel_modules = ("ipoib","core","mlxfw","srp");

my @sroiv_common_user_packages = ("udapl","ofed-scripts",
					"ibacm","librdmacm","librdmacm-utils",
					"libibverbs","rdma-core-devel","libibverbs-utils",
					"libibumad",
					"perftest", "multiperf",
					"mlnx-tools",
					"srp_daemon", "mlnx-ethtool", "mlnx-iproute2");

my @hypervisor_user_packages = (@sroiv_common_user_packages,"infiniband-diags","osm","mstflint","ofed-docs",
					"dapl","dapl-devel","dapl-devel-static","dapl-utils",
					"opensm","opensm-libs","opensm-devel","opensm-static","ibutils2","mft",
					);
my @guest_user_packages = (@sroiv_common_user_packages,"infiniband-diags", @mpi_packages);

my @eth_kernel_packages = ($en_kernel_rpm, "mlnx-en-utils", "mlnx-en-sources", "mlnx-en-doc");
my @eth_kernel_modules = ("core", "mlxfw", "mlx5");
my @eth_user_packages = ("mstflint");

my @dpdk_kernel_packages = ($kernel_rpm, "mlnx-ofa_kernel-devel", "$kernel_mft_rpm");
if ($is_bf) {
	push(@dpdk_kernel_packages, @bf_only_kernel_packages);
}
my @dpdk_kernel_modules = (@kernel_modules);
my @dpdk_user_packages = ("libibverbs", "rdma-core-devel", "libibverbs-utils", "librdmacm", "librdmacm-utils", "ibacm", "mlnx-ethtool", "mlnx-iproute2", "mstflint", "mft");

# all_packages is required to save ordered (following dependencies) list of
# packages. Hash does not saves the order
my @all_packages = (@kernel_packages, @user_packages, @misc_packages);

my @ucx_dist_build_req = (
    "$pkgconfig", "$libstdc_devel", "$gcc_cpp", "binutils-devel", "$libstdc"
);

my %kernel_modules_info = (
        'core' =>
            { name => "core", available => 1, selected => 1,
            included_in_rpm => 1, requires => [], },
        'mlxfw' =>
            { name => "mlxfw", available => 1, selected => 1,
            included_in_rpm => 1, requires => [], },
        'mthca' =>
            { name => "mthca", available => 0, selected => 1,
            included_in_rpm => 1, requires => ["core"], },
        'mlx4' =>
            { name => "mlx4", available => 1, selected => 1,
            included_in_rpm => 1, requires => ["core"], },
        'mlx4_en' =>
            { name => "mlx4_en", available => 1, selected => 0,
            included_in_rpm => 1, requires => ["core"], },
        'mlx4_vnic' =>
            { name => "mlx4_vnic", available => 0, selected => 0,
            included_in_rpm => 1, requires => ["core","mlx4_ib","mlx4_en"], },
        'mlx4_fc' =>
            { name => "mlx4_fc", available => 0, selected => 0,
            included_in_rpm => 0, requires => ["core","mlx4_en"], },
        'ipoib' =>
            { name => "ipoib", available => 1, selected => 1,
            included_in_rpm => 1, requires => ["core"], },
        'sdp' =>
            { name => "sdp", available => 0, selected => 1,
            included_in_rpm => 0, requires => ["core", "ipoib"], },
        'srp' =>
            { name => "srp", available => 1, selected => 1,
            included_in_rpm => 1, requires => ["core", "ipoib"], },
        'srpt' =>
            { name => "srpt", available => 0, selected => 0,
            included_in_rpm => 1, requires => ["core"], },
        'rds' =>
            { name => "rds", available => 0, selected => 1,
            included_in_rpm => 1, requires => ["core", "ipoib"], },
        'e_ipoib' =>
            { name => "e_ipoib", available => 0, selected => 0,
            included_in_rpm => 0, requires => ["core", "ipoib"], },
        'iser' =>
            { name => "iser", available => 0, selected => 0,
            included_in_rpm => 0, requires => ["core", "ipoib"], ofa_req_inst => [] },
        'isert' =>
            { name => "isert", available => 1, selected => 0,
            included_in_rpm => 0, requires => ["core", "ipoib"], ofa_req_inst => [] },
        'nfsrdma' =>
            { name => "nfsrdma", available => 0, selected => 0,
            included_in_rpm => 0, requires => ["core", "ipoib"], },
        'mlx5_fpga_tools' =>
            { name => "mlx5_fpga_tools", available => 1, selected => 0,
            included_in_rpm => 0, requires => ["core"], },
        );

my %packages_info = (
        # Kernel packages
        'mlnx-ofa_kernel' =>
           { name => "mlnx-ofa_kernel", parent => "mlnx-ofa_kernel",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel", dist_req_build => [],
           dist_req_inst => ["ethtool", "lsof", "pciutils", "$srvtool"],
           ofa_req_build => [],
           ofa_req_inst => ["ofed-scripts", "mlnx-tools"],
           soft_req => ["ofed-scripts"],
           configure_options => '' },
        'mlnx-ofa_kernel-devel' =>
           { name => "mlnx-ofa_kernel-devel", parent => "mlnx-ofa_kernel",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel", dist_req_build => [],
           dist_req_inst => ["make"], ofa_req_build => [], ofa_req_inst => ["ofed-scripts", 'mlnx-ofa_kernel'], configure_options => '' },
        'mlnx-ofa_kernel-source' =>
           { name => "mlnx-ofa_kernel-devel", parent => "mlnx-ofa_kernel",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1,
           mode => "kernel",
           dist_req_build => [],
           dist_req_inst => [],
           ofa_req_build => [],
           ofa_req_inst => [],
           },
        'mlnx-ofa_kernel-modules' =>
            { name => "mlnx-ofa_kernel-modules", parent => "mlnx-ofa_kernel",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
            dist_req_inst => ["lsof","pciutils"],
            ofa_req_build => [], ofa_req_inst => ["mlnx-ofa_kernel", "ofed-scripts"],
            soft_req => ["ofed-scripts"] },
        'mlnx-tools' =>
            { name => "mlnx-tools", parent => "mlnx-tools",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [],
            dist_req_inst => ["$python"],
            ofa_req_build => [],
            ofa_req_inst => [],
            userspace_install_early => 1,
            },
        'kernel-mft' =>
            { name => "kernel-mft", parent => "kernel-mft",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [], ofa_req_inst => ["ofed-scripts"], configure_options => '' },
	'kernel-mft-mlnx' =>
            { name => "kernel-mft-mlnx", parent => "kernel-mft-mlnx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [], ofa_req_inst => ["ofed-scripts"], configure_options => '' },
         'neohost-backend' =>
            { name => "neohost-backend", parent => "neohost-backend",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [], ofa_req_inst => [], configure_options => '' },
         'neohost-sdk' =>
            { name => "neohost-sdk", parent => "neohost-sdk",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [], ofa_req_inst => ["neohost-backend"], configure_options => '' },
        'knem' =>
            { name => "knem", parent => "knem",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [], ofa_req_inst => [], configure_options => '' },
        # this one is used when KMP is disabled to proivde the kernel modules only
        'knem-modules' =>
            { name => "knem-modules", parent => "knem",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["knem"],
            ofa_req_inst => ["knem"],
            configure_options => '' },
        'xpmem' =>
            { name => "xpmem", parent => "xpmem",
            available => 1, mode => "kernel",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => [],
            },
        'xpmem-modules' =>
            { name => "libxpmem", parent => "xpmem",
            available => 1, mode => "kernel",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ['xpmem'],
            },
        'libxpmem' =>
            { name => "libxpmem", parent => "xpmem",
            available => 1, mode => "kernel",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => [],
            },
        'libxpmem-devel' =>
            { name => "libxpmem-devel", parent => "xpmem",
            available => 1, mode => "kernel",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ['libxpmem'],
            },

        'mlnx-en' =>
           { name => "mlnx-en", parent => "mlnx-en",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel",
           dist_req_build => [],
           dist_req_inst => ["ethtool", "lsof", "pciutils"],
           ofa_req_build => [],
           ofa_req_inst => ['mlnx-en-utils'],
           configure_options => '' },
        'mlnx_en' =>
           { name => "mlnx_en", parent => "mlnx-en",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel",
           dist_req_build => [],
           dist_req_inst => ["ethtool", "lsof", "pciutils"],
           ofa_req_build => [],
           ofa_req_inst => ['mlnx-en-utils'],
           configure_options => '' },
        'mlnx-en-utils' =>
           { name => "mlnx-en-utils", parent => "mlnx-en",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel",
           dist_req_build => [],
           dist_req_inst => [],
           ofa_req_build => [],
           ofa_req_inst => ['ofed-scripts', "mlnx-tools"],
           configure_options => '' },
        'mlnx-en-sources' =>
           { name => "mlnx-en-sources", parent => "mlnx-en",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel",
           dist_req_build => [],
           dist_req_inst => [],
           ofa_req_build => [],
           ofa_req_inst => [],
           configure_options => '' },
        'mlnx-en-doc' =>
           { name => "mlnx-en-doc", parent => "mlnx-en",
           selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
           available => 1, mode => "kernel",
           dist_req_build => [],
           dist_req_inst => [],
           ofa_req_build => [],
           ofa_req_inst => [],
           configure_options => '' },

        # User space libraries
        'libibverbs' =>
            { name => "libibverbs", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build =>
            ( $install32 == 1 )?["$pkgconfig","gcc__3.3.3", "glibc-devel$suffix_64bit","glibc-devel$suffix_32bit", "$libnl_devel"."$suffix_64bit", ($DISTRO =~ /SUSE/)?"$libnl_devel"."$suffix_32bit":(($arch =~ /ppc/)?"$libnl_devel":"$libnl_devel.$target_cpu32")]:["$pkgconfig","gcc__3.3.3", "glibc-devel$suffix_64bit", "$libnl_devel"."$suffix_64bit"],
            dist_req_inst => ( $install32 == 1 )?["$pkgconfig","$libnl"."$suffix_64bit", ($dist_rpm !~ /sles-release-11.1/)?"$libnl"."$suffix_32bit":"$libnl.$target_cpu32"]:["$pkgconfig","$libnl"."$suffix_64bit"] ,
            ofa_req_build => [],
            ofa_req_inst => ["ofed-scripts", "rdma-core"],
            install32 => 1, exception => 0, configure_options => '',
            userspace_install_early => 1,
            },
        'libibverbs-utils' =>
            { name => "libibverbs-utils", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [],
            ofa_req_inst => ["libibverbs"],
            install32 => 0, exception => 0 },

        # Management
        'libibumad' =>
            { name => "libibumad", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["libtool"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["rdma-core"],
            install32 => 1, exception => 0, configure_options => '' },

        'opensm' =>
            { name => "opensm", parent => "opensm",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["bison", "flex"],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["opensm-libs", "libibumad"],
            install32 => 0, exception => 0, configure_options => '' },
        'opensm-devel' =>
            { name => "opensm-devel", parent => "opensm",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["rdma-core-devel", "opensm-libs"],
            install32 => 0, exception => 0 },
        'opensm-libs' =>
            { name => "opensm-libs", parent => "opensm",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["bison", "flex"],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["libibumad"],
            install32 => 0, exception => 0 },
        'opensm-static' =>
            { name => "opensm-static", parent => "opensm",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["rdma-core-devel", "opensm-libs"],
            install32 => 0, exception => 0 },

        'ibsim' =>
            { name => "ibsim", parent => "ibsim",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["rdma-core-devel", "rdma-core-devel"],
            ofa_req_inst => ["libibumad", "infiniband-diags"],
            install32 => 0, exception => 0, configure_options => '' },

        'ibacm' =>
            { name => "ibacm", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel", "rdma-core-devel", "mlnx-ofa_kernel-devel"],
            ofa_req_inst => ["libibverbs", "libibumad", "rdma-core"],
            install32 => 0, exception => 0, configure_options => '' },
        'librdmacm' =>
            { name => "librdmacm", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["libibverbs", "rdma-core"],
            install32 => 1, exception => 0, configure_options => '' },
        'librdmacm-utils' =>
            { name => "librdmacm-utils", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["librdmacm", "rdma-core-devel"],
            install32 => 0, exception => 0 },

        'perftest' =>
            { name => "perftest", parent => "perftest",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["pciutils-devel"],
            dist_req_inst => [], ofa_req_build => ["rdma-core-devel", "librdmacm"],
            ofa_req_inst => ["libibverbs", "librdmacm", "libibumad"],
            install32 => 0, exception => 0, configure_options => '' },

        'mft' =>
            { name => "mft", parent => "mft",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["$libexpat", "$libexpat_devel", "tcl__8.4", "$tcl_devel" . "__8.4", "$tk", $libstdc_devel ],
            dist_req_inst => ["$libexpat", "tcl__8.4", "$tk", $libstdc],
            ofa_req_build => [], ofa_req_inst => [], configure_options => '' },

        'mft-oem' =>
            { name => "mft-oem", parent => "mft-oem",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["$libexpat", "$libexpat_devel", "tcl__8.4", "tcl-devel__8.4", "$tk", $libstdc_devel ],
            dist_req_inst => ["$libexpat", "tcl__8.4", "$tk", $libstdc],
            ofa_req_build => [], ofa_req_inst => [], configure_options => '' },

        'mstflint' =>
            { name => "mstflint", parent => "mstflint",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => ["zlib-devel$suffix_64bit", "$libstdc_devel$suffix_64bit", "gcc-c++", "$openssl_devel"],
            dist_req_inst => ["$openssl"], ofa_req_build => [],
            ofa_req_inst => [],
            install32 => 0, exception => 0, configure_options => '' },

        'ibutils2' =>
            { name => "ibutils2", parent => "ibutils2",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0, internal => 1,
            available => 1, mode => "user", dist_req_build => ["tcl__8.4", "$tcl_devel" . "__8.4", "$libstdc_devel"],
            dist_req_inst => ["tcl__8.4", "$libstdc"], ofa_req_build => ["rdma-core-devel", "infiniband-diags"],
            ofa_req_inst => ["libibumad", "infiniband-diags"],
            install32 => 0, exception => 0, configure_options => '' },

        'ar_mgr' =>
            { name => "ar_mgr", parent => "ar_mgr",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0, internal => 1,
            available => 1, mode => "user", dist_req_build => ["$libstdc_devel"],
            dist_req_inst => ["$libstdc"], ofa_req_build => ["opensm-libs", "opensm-devel", "ibutils2"],
            ofa_req_inst => ["opensm", "ibutils2"],
            install32 => 0, exception => 0, configure_options => '' },

        'cc_mgr' =>
            { name => "cc_mgr", parent => "cc_mgr",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0, internal => 1,
            available => 1, mode => "user", dist_req_build => ["$libstdc_devel"],
            dist_req_inst => ["$libstdc"], ofa_req_build => ["opensm-libs", "opensm-devel", "ibutils2"],
            ofa_req_inst => ["opensm", "ibutils2"],
            install32 => 0, exception => 0, configure_options => '' },

        'dump_pr' =>
            { name => "dump_pr", parent => "dump_pr",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0, internal => 1,
            available => 1, mode => "user", dist_req_build => ["$libstdc_devel"],
            dist_req_inst => ["$libstdc"], ofa_req_build => ["opensm-libs", "opensm-devel"],
            ofa_req_inst => ["opensm"],
            install32 => 0, exception => 0, configure_options => '' },

        'ibdump' =>
            { name => "ibdump", parent => "ibdump",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0, internal => 1,
            available => 1, mode => "user", dist_req_build => ["$libstdc_devel"],
            dist_req_inst => ["$libstdc"], ofa_req_build => ["rdma-core-devel", "mstflint"],
            ofa_req_inst => ["libibverbs", "mstflint"],
            install32 => 0, exception => 0, configure_options => '' },

        'infiniband-diags' =>
            { name => "infiniband-diags", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["$glib2_devel"],
            dist_req_inst => ["$glib2"], ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ["libibumad"],
            install32 => 0, exception => 0, configure_options => '' },

        'dapl' =>
            { name => "dapl", parent => "dapl",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["libibverbs", "rdma-core-devel", "librdmacm"],
            ofa_req_inst => ["libibverbs", "librdmacm"],
            install32 => 0, exception => 0, configure_options => '' },
        'dapl-devel' =>
            { name => "dapl-devel", parent => "dapl",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["libibverbs","rdma-core-devel", "librdmacm"],
            ofa_req_inst => ["dapl"],
            install32 => 0, exception => 0, configure_options => '' },
        'dapl-devel-static' =>
            { name => "dapl-devel-static", parent => "dapl",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["libibverbs","rdma-core-devel", "librdmacm"],
            ofa_req_inst => ["dapl"],
            install32 => 0, exception => 0, configure_options => '' },
        'dapl-utils' =>
            { name => "dapl-utils", parent => "dapl",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["libibverbs","rdma-core-devel", "librdmacm"],
            ofa_req_inst => ["dapl"],
            install32 => 0, exception => 0, configure_options => '' },

        'ucx' =>
            { name => "ucx", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => ["$pkgconfig","$libstdc"],
            ofa_req_build => ["rdma-core-devel", "knem", "libxpmem-devel"],
            ofa_req_inst => [],
            soft_req => ["libxpmem-devel"],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-devel' =>
            { name => "ucx-devel", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => ["$pkgconfig","$libstdc"],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ['ucx'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-static' =>
            { name => "ucx-static", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => ["$pkgconfig","$libstdc"],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ['ucx'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-cma' =>
            { name => "ucx-cma", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ['ucx'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-cuda' =>
            { name => "ucx-cuda", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user",
            dist_req_build => [
                @ucx_dist_build_req, "cuda-libraries-$cuda_version",
                "cuda-cudart-devel-$cuda_version",
                'nvidia-driver-devel',
            ],
            dist_req_inst => ["cuda-cudart-$cuda_version"],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ['ucx'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-gdrcopy' =>
            { name => "ucx-gdrcopy", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user",
            dist_req_build => [@ucx_dist_build_req, 'gdrcopy', 'gdrcopy-devel'],
            dist_req_inst => ['gdrcopy'],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ['ucx'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-ib' =>
            { name => "ucx-ib", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => ['ucx', 'libibverbs'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-knem' =>
            { name => "ucx-knem", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel", 'knem'],
            ofa_req_inst => ['ucx', 'knem'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-rdmacm' =>
            { name => "ucx-rdmacm", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel", 'librdmacm'],
            ofa_req_inst => ['ucx', 'librdmacm'],
            install32 => 0, exception => 0, configure_options => '' },
        'ucx-xpmem' =>
            { name => "ucx-xpmem", parent => "ucx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [@ucx_dist_build_req],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core-devel", 'libxpmem-devel'],
            ofa_req_inst => ['ucx', 'libxpmem'],
            install32 => 0, exception => 0,},

        'mpi-selector' =>
            { name => "mpi-selector", parent => "mpi-selector",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["tcsh"],
            dist_req_inst => ["tcsh"], ofa_req_build => [],
            ofa_req_inst => [],
            userspace_install_early => 1,
            install32 => 0, exception => 0, configure_options => '' },

        'openmpi' =>
            { name => "openmpi", parent => "openmpi",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => ["$libgfortran","$libstdc_devel"],
            dist_req_inst => ["$libgfortran","$libstdc"],
            ofa_req_build => ["rdma-core-devel", "hcoll", "ucx", "ucx-devel", "ucx-static", "$knem_rpm", "$knem_mods", "sharp"],
            ofa_req_inst => ["libibverbs", "librdmacm", "mpi-selector", "hcoll", "ucx", "$knem_rpm", "$knem_mods", "sharp"],
            soft_req => ["mpi-selector","hcoll", "ucx", "ucx-devel", "ucx-static", "$knem_rpm", "$knem_mods", "sharp"],
            install32 => 0, exception => 0, configure_options => '' },

# Note: this node of 'mpitests' is a generic node, it should stay available=0.
# the real mpitests packages that will be installed are defined in function "add_new_mpitests_pkg".
# mpitests will be compiled with all available openmpi/mvapich versions.
        'mpitests' =>
            { name => "mpitests", parent => "mpitests",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => ["rdma-core-devel"],
            ofa_req_inst => [],
            install32 => 0, exception => 0, configure_options => '' },

        'clusterkit' =>
            { name => "clusterkit", parent => "clusterkit",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [
                "$fortran", "$curl_devel",
                "cuda-cudart-devel-$cuda_version", "cuda-nvcc-$cuda_version"
            ],
            dist_req_inst => [],
            ofa_req_build => ["mpitests_openmpi"],
            ofa_req_inst => ["openmpi"],
            install32 => 0, exception => 0, configure_options => '' },

        'mlnxofed-docs' =>
            { name => "mlnxofed-docs", parent => "mlnxofed-docs",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => [], ofa_req_build => [],
            ofa_req_inst => [],
            install32 => 0, exception => 0 },

        'ofed-scripts' =>
            { name => "ofed-scripts", parent => "ofed-scripts",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => ["$python"], ofa_req_build => [],
            ofa_req_inst => [],
            install32 => 0, exception => 0 },
        'hcoll' =>
            { name => "hcoll", parent=> "hcoll",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["gcc-c++","$libstdc_devel","$libstdc", "$openssl_devel"],
             dist_req_inst => ["$openssl"],
             ofa_req_build => ["rdma-core-devel", "sharp", "ucx-devel"],
             ofa_req_inst => ["libibverbs", "librdmacm", "infiniband-diags", "libibumad", "sharp"], install32 => 0, exception => 0,
             soft_req => ["sharp"] },
        'hcoll-cuda' =>
            { name => "hcoll-cuda", parent => "hcoll",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 0, mode => "user",
            dist_req_build => [
                "$gcc_cpp","$libstdc_devel","$libstdc", "$openssl_devel",
                "cuda-cudart-devel-$cuda_version", "cuda-nvcc-$cuda_version",
            ],
            dist_req_inst => ["cuda-cudart-$cuda_version"],
            ofa_req_build => ["rdma-core-devel", "sharp", "ucx-devel"],
            soft_req => [],
            ofa_req_inst => ['hcoll'],
            optional_subpackage => 1,
            install32 => 0, exception => 0, configure_options => '' },
        'sharp' =>
            { name => "sharp", parent=> "sharp",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$gcc_cpp","$libstdc_devel","$libstdc", "binutils-devel"],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["libibverbs", "libibumad", "librdmacm", "infiniband-diags", "ucx"],
             soft_req => ["ucx", "ucx-devel", "ucx-static"],
			 install32 => 0, exception => 0 },

        'libvma' =>
            { name => "libvma", parent=> "libvma",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$libnl_devel"],
             dist_req_inst => ["$libnl"],
             ofa_req_build => ["rdma-core-devel", "dpcp"],
             ofa_req_inst => ["libibverbs", "librdmacm", "dpcp"],
             soft_req => ["dpcp"],
             install32 => 0, exception => 0 },
        'libvma-utils' =>
            { name => "libvma-utils", parent=> "libvma",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$libnl_devel"],
             dist_req_inst => ["$libnl"],
             ofa_req_build => ["rdma-core-devel", "dpcp"],
             ofa_req_inst => ["libibverbs", "librdmacm", "libvma"],
             soft_req => ["dpcp"],
             install32 => 0, exception => 0 },
        'libvma-devel' =>
            { name => "libvma-devel", parent=> "libvma",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$libnl_devel"],
             dist_req_inst => ["$libnl"],
             ofa_req_build => ["rdma-core-devel", "dpcp"],
             ofa_req_inst => ["libibverbs", "librdmacm", "libvma"],
             soft_req => ["dpcp"],
             install32 => 0, exception => 0 },

        'libxlio' =>
            { name => "libxlio", parent=> "libxlio",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$libnl_devel", "$systemd_rpm_macros"],
             dist_req_inst => ["$libnl"],
             ofa_req_build => ["rdma-core-devel", "dpcp"],
             ofa_req_inst => ["libibverbs", "librdmacm", "dpcp"],
             soft_req => [],
             install32 => 0, exception => 0 },
        'libxlio-utils' =>
            { name => "libxlio-utils", parent=> "libxlio",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$libnl_devel", "$systemd_rpm_macros"],
             dist_req_inst => ["$libnl"],
             ofa_req_build => ["rdma-core-devel", "dpcp"],
             ofa_req_inst => ["libibverbs", "librdmacm", "libxlio"],
             install32 => 0, exception => 0 },
        'libxlio-devel' =>
            { name => "libxlio-devel", parent=> "libxlio",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$libnl_devel", "$systemd_rpm_macros"],
             dist_req_inst => ["$libnl"],
             ofa_req_build => ["rdma-core-devel", "dpcp"],
             ofa_req_inst => ["libibverbs", "librdmacm", "libxlio", "dpcp"],
             install32 => 0, exception => 0 },

        'dpcp' =>
            { name => "dpcp", parent=> "dpcp",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => ["$pkgconfig", "automake", "autoconf", "libtool", "$gcc_cpp"],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["libibverbs"],
             install32 => 0, exception => 0 },
        'dpcp-debuginfo' =>
            { name => "dpcp-debuginfo", parent=> "dpcp",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => [],
             install32 => 0, exception => 0 },

        'sockperf' =>
            { name => "sockperf", parent=> "sockperf",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_build => ["doxygen"],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => [], install32 => 0, exception => 0 },

        'fabric-collector' =>
            { name => "fabric-collector", parent=> "fabric-collector",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => ["$libcurl"],
             ofa_req_inst => ["infiniband-diags", "libibumad", "opensm-libs"], install32 => 0, exception => 0 },

         'iser' =>
             { name => "iser", parent => "iser",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
             dist_req_inst => ["pciutils"],
             ofa_req_build => ["mlnx-ofa_kernel-devel"],
             ofa_req_inst => ["ofed-scripts","$kernel_rpm"], configure_options => '' },

         'isert' =>
             { name => "isert", parent => "isert",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
             dist_req_inst => ["pciutils"],
             ofa_req_build => ["mlnx-ofa_kernel-devel"],
             ofa_req_inst => ["ofed-scripts","$kernel_rpm"], configure_options => '' },

        'srp' =>
            { name => "srp", parent => "srp",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
            dist_req_inst => ["pciutils"],
            ofa_req_build => ["mlnx-ofa_kernel-devel"],
            ofa_req_inst => ["ofed-scripts","$kernel_rpm"], configure_options => '' },

        'mlnx-nfsrdma' =>
            { name => "mlnx-nfsrdma", parent => "mlnx-nfsrdma",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
            dist_req_inst => ["pciutils"],
            ofa_req_build => ["mlnx-ofa_kernel-devel"],
            ofa_req_inst => ["ofed-scripts","$kernel_rpm"], configure_options => '' },

        'mlnx-nvme' =>
            { name => "mlnx-nvme", parent => "mlnx-nvme",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
            dist_req_inst => ["pciutils"],
            ofa_req_build => ["mlnx-ofa_kernel-devel"],
            ofa_req_inst => ["ofed-scripts","$kernel_rpm"], configure_options => '' },

        'mlnx-rdma-rxe' =>
            { name => "mlnx-rdma-rxe", parent => "mlnx-rdma-rxe",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "gcc"],
            dist_req_inst => [],
            ofa_req_build => ["mlnx-ofa_kernel-devel"],
            ofa_req_inst => ["ofed-scripts","$kernel_rpm"], configure_options => '' },

        'gpio-mlxbf' =>
            { name => "gpio-mlxbf", parent => "gpio-mlxbf",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'i2c-mlx' =>
            { name => "i2c-mlx", parent => "i2c-mlx",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'mlxbf-livefish' =>
            { name => "mlxbf-livefish", parent => "mlxbf-livefish",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'mlx-bootctl' =>
            { name => "mlx-bootctl", parent => "mlx-bootctl",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'pka-mlxbf' =>
            { name => "pka-mlxbf", parent => "pka-mlxbf",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'tmfifo' =>
            { name => "tmfifo", parent => "tmfifo",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'mlxbf-gige' =>
            { name => "mlxbf-gige", parent => "mlxbf-gige",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'mlx-trio' =>
            { name => "mlx-trio", parent => "mlx-trio",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'gpio-mlxbf2' =>
            { name => "gpio-mlxbf2", parent => "gpio-mlxbf2",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'mlx-pmc' =>
            { name => "mlx-pmc", parent => "mlx-pmc",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "kernel", dist_req_build => ["make", "$gcc"],
            dist_req_inst => [],
            ofa_req_build => [],
            ofa_req_inst => ["$kernel_rpm"], configure_options => '' },

        'libpka' =>
            { name => "libpka", parent=> "libpka",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_build => ["$openssl_devel"],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => [], install32 => 0, exception => 0 },

        'mlxbf-bootctl' =>
            { name => "mlxbf-bootctl", parent=> "mlxbf-bootctl",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => [], install32 => 0, exception => 0 },

        'mlxbf-bootimages' =>
            { name => "mlxbf-bootimages", parent=> "mlxbf-bootimages",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => [], install32 => 0, exception => 0 },

        'bfscripts' =>
            { name => "bfscripts", parent=> "bfscripts",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => ["mlxbf-bootctl", "mlxbf-bootimages"], install32 => 0, exception => 0 },

        'rshim' =>
            { name => "rshim", parent=> "rshim",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => ["$pciutils_libs", "$libusb", "$fuse_libs", "$kernel_modules_extra"],
             dist_req_build => ["pciutils-devel", "$libusb_devel", "fuse-devel"],
             ofa_req_build => [],
             ofa_req_inst => [], install32 => 0, exception => 0 },

        'nvme-snap' =>
            { name => "nvme-snap", parent=> "nvme-snap",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["rdma-core"], install32 => 0, exception => 0 },

        'mlnx-dpdk' =>
            { name => "mlnx-dpdk", parent=> "mlnx-dpdk",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["rdma-core"], install32 => 0, exception => 0 },

        'mlnx-dpdk-devel' =>
            { name => "mlnx-dpdk-devel", parent=> "mlnx-dpdk",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => ["mlnx-dpdk"],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["mlnx-dpdk"], install32 => 0, exception => 0 },

        'mlnx-dpdk-doc' =>
            { name => "mlnx-dpdk-doc", parent=> "mlnx-dpdk",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["mlnx-dpdk"], install32 => 0, exception => 0 },

        'mlnx-dpdk-tools' =>
            { name => "mlnx-dpdk-tools", parent=> "mlnx-dpdk",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["mlnx-dpdk"], install32 => 0, exception => 0 },

        'mlnx-dpdk-debuginfo' =>
            { name => "mlnx-dpdk-debuginfo", parent=> "mlnx-dpdk",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["mlnx-dpdk"], install32 => 0, exception => 0 },

        'openvswitch' =>
            { name => "openvswitch", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_inst => ["openssl", "unbound"],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["rdma-core"], install32 => 0, exception => 0 },

        'openvswitch-devel' =>
            { name => "openvswitch-devel", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"], install32 => 0, exception => 0 },

        'openvswitch-ipsec' =>
            { name => "openvswitch-ipsec", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"], install32 => 0, exception => 0 },

        'openvswitch-selinux-policy' =>
            { name => "openvswitch-selinux-policy", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"], install32 => 0, exception => 0 },

        'python-openvswitch' =>
            { name => "python-openvswitch", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_build => [],
             dist_req_inst => ["python", "python-six"],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"], install32 => 0, exception => 0 },

        'python3-openvswitch' =>
            { name => "python3-openvswitch", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_build => [],
             dist_req_inst => ["$python", "python3-six"],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"],
             install32 => 0,
             exception => 0
             },

        'openvswitch-test' =>
            { name => "openvswitch-test", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"], install32 => 0, exception => 0 },

        'network-scripts-openvswitch' =>
            { name => "network-scripts-openvswitch", parent=> "openvswitch",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_build => [],
             dist_req_inst => ["network-scripts"],
             ofa_req_build => [],
             ofa_req_inst => ["openvswitch"],
             install32 => 0,
             exception => 0
             },

        'mlx-steering-dump' =>
            { name => "mlx-steering-dump", parent => "mlx-steering-dump",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user", dist_req_build => [],
            dist_req_inst => ["$python2"], ofa_req_build => [],
            ofa_req_inst => [],
            install32 => 0, exception => 0 },

	    'mlnx-ethtool' =>
		{ name => "mlnx-ethtool", parent=> "mlnx-ethtool",
		 selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
		 available => 1, mode => "user",
             dist_req_inst => [$libmnl],
             dist_req_build => ["$pkgconfig", "libmnl-devel"],
		 dist_req_inst => [],
		 ofa_req_build => [],
		 ofa_req_inst => [], install32 => 0, exception => 0 },

        'spdk' =>
            { name => "spdk", parent=> "spdk",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 1, mode => "user",
             dist_req_build => ["CUnit-devel", "libaio-devel", "openssl-devel", "libuuid-devel", "libiscsi-devel", "python-pep8", "lcov", "clang-analyzer", "graphviz", "python-configshell", "ncurses-devel"],
             dist_req_inst => ["python", "sg3_utils", "avahi"],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["rdma-core"], install32 => 0, exception => 0 },

        'mlnx-iproute2' =>
		{ name => "mlnx-iproute2", parent=> "mlnx-iproute2",
		 selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
		 available => 1, mode => "user",
		 dist_req_inst => [$libmnl],
         dist_req_build => [$iptables_devel, $elfutils_devel, "libmnl-devel", $libdb_devel, "libselinux-devel", "bison", "flex"],
		 ofa_req_build => [],
		 ofa_req_inst => [], install32 => 0, exception => 0 },

        'multiperf' =>
            { name => "multiperf", parent=> "multiperf",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => ["rdma-core-devel"],
             ofa_req_inst => ["libibverbs"], install32 => 0, exception => 0 },

        # this package is listed here only for uninstall and --without.. flag support
        'mlnx-fw-updater' =>
            { name => "mlnx-fw-updater", parent=> "mlnx-fw-updater",
             selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
             available => 0, mode => "user",
             dist_req_inst => [],
             dist_req_build => [],
             dist_req_inst => [],
             ofa_req_build => [],
             ofa_req_inst => [], install32 => 0, exception => 0 },

        'rdma-core' =>
            { name => "rdma-core", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_inst => [
                "$pkgconfig", "$libudev",
                ($libnl3 ne "") ? (
                    "$libnl3"."$suffix_64bit",
                    ($install32 == 1) ? (
                        ($dist_rpm !~ /sles-release-11.1/) ? "$libnl3"."$suffix_32bit" :
                            "$libnl3.$target_cpu32"
                    ) : (),
                ) : (),
            ] ,
            ofa_req_build => ["mlnx-ofa_kernel-devel"],
            ofa_req_inst => ["ofed-scripts"],
            install32 => 1, exception => 0, configure_options => '' },
        'rdma-core-devel' =>
            { name => "rdma-core-devel", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core"],
            ofa_req_inst => ["rdma-core", "libibverbs", "librdmacm", "infiniband-diags", "libibumad"],
            install32 => 1, exception => 0, configure_options => '' },
        'rdma-core-debuginfo' =>
            { name => "rdma-core-debuginfo", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core"],
            ofa_req_inst => ["rdma-core"],
            install32 => 1, exception => 0, configure_options => '' },
        'python3-pyverbs' =>
            { name => "python3-pyverbs", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core"],
            ofa_req_inst => ["rdma-core", "libibverbs", "librdmacm", "infiniband-diags", "libibumad"],
            install32 => 1, exception => 0, configure_options => '' },
        'srp_daemon' =>
            { name => "srp_daemon", parent => "rdma-core",
            selected => 0, installed => 0, rpm_exist => 0, rpm_exist32 => 0,
            available => 1, mode => "user",
            dist_req_build => [],
            dist_req_inst => [],
            ofa_req_build => ["rdma-core", "rdma-core-devel"],
            ofa_req_inst => ["rdma-core", "libibumad", "libibverbs"],
            install32 => 0, exception => 0, configure_options => '' },
);

foreach my $package (keys %packages_info) {
    if (not exists $packages_info{$package}{'configure_options'}) {
        $packages_info{$package}{'configure_options'} = '';
    }
}

if (($DISTRO =~ /RHEL | FC | OL | BCLINUX/x) and ($DISTRO !~ /RHEL6 | OL6/x)) {
    push @{$packages_info{'mpi-selector'}{'dist_req_inst'}}, "perl-Getopt-Long";
}

foreach (keys %packages_info) {
    my $entry = $packages_info{$_};
    next unless ($entry->{'mode'} eq 'kernel');
    next unless ($DISTRO =~ /RHEL8 | OL8 | FC29 | FC3./x);

    push @{$entry->{'dist_req_build'}}, 'kernel-rpm-macros';
}

my @hidden_packages = ();

my %MPI_SUPPORTED_COMPILERS = (gcc => 0, pgi => 0, intel => 0);

my %gcc = ('gcc' => 0, 'gfortran' => 0, 'g77' => 0, 'g++' => 0);
my %pgi = ('pgf77' => 0, 'pgf90' => 0, 'pgCC' => 0);
my %intel = ('icc' => 0, 'icpc' => 0, 'ifort' => 0);

sub sig_handler
{
    exit $ERROR;
}

sub getch
{
        my $c;
#        system("stty -echo raw");
        $c=getc(STDIN);
#        system("stty echo -raw");
#        # Exit on Ctrl+c or Esc
#        if ($c eq "\cC" or $c eq "\e") {
#            print "\n";
#            exit $ERROR;
#        }
#        print "$c\n";
        return $c;
}

sub get_rpm_name_arch($)
{
    my $rpm = shift;
    my $ret = `$RPM --queryformat "[%{NAME}] [%{ARCH}]" -qp '$rpm' 2>/dev/null | grep -v Freeing`;
    chomp $ret;
    return $ret;
}

sub get_rpm_ver($)
{
    my $rpm = shift;
    my $ret = `$RPM --queryformat "[%{VERSION}]\n" -qp '$rpm' 2>/dev/null | uniq`;
    chomp $ret;
    return $ret;
}

sub get_rpm_rel($)
{
    my $rpm = shift;
    my $ret = `$RPM --queryformat "[%{RELEASE}]\n" -qp '$rpm' 2>/dev/null | uniq`;
    chomp $ret;
    return $ret;
}

sub get_rpm_name_ver_rel_arch($)
{
    my $rpm = shift;
    my $ret = `$RPM --queryformat "[%{NAME}]-[%{VERSION}]-[%{RELEASE}].[%{ARCH}]\n" -qp '$rpm' 2>/dev/null | uniq`;
    chomp $ret;
    return $ret;
}

# Get RPM name and version of the INSTALLED package
sub get_rpm_ver_inst
{
    my $ret;
    $ret = `$RPM --queryformat '[%{VERSION}]\n' -q @_ 2>/dev/null | uniq`;
    chomp $ret;
    return $ret;
}

sub get_rpm_rel_inst
{
    my $ret = `$RPM --queryformat "[%{RELEASE}]\n" -q @_ 2>/dev/null | uniq`;
    chomp $ret;
    return $ret;
}

sub get_rpm_info($)
{
    my $rpm = shift;
    my $ret = `$RPM --queryformat "[%{NAME}] [%{VERSION}] [%{RELEASE}] [%{SIZE}] [%{DESCRIPTION}]" -qp '$rpm' 2>/dev/null`;
    chomp $ret;
    return $ret;
}

sub supported32bit
{
    if (not -e "/usr/lib/crt1.o") {
        print RED "glibc-devel 32bit is required to install 32-bit libraries.", RESET "\n" if ($verbose2);
        return 0;
    }

    return 1;
}

# Check whether compiler $1 exist
sub set_compilers
{
    if (`which gcc 2> /dev/null`) {
        $gcc{'gcc'} = 1;
    }
    if (`which g77 2> /dev/null`) {
        $gcc{'g77'} = 1;
    }
    if (`which g++ 2> /dev/null`) {
        $gcc{'g++'} = 1;
    }
    if (`which gfortran 2> /dev/null`) {
        $gcc{'gfortran'} = 1;
    }

    if (`which pgcc 2> /dev/null`) {
        $pgi{'pgcc'} = 1;
    }
    if (`which pgCC 2> /dev/null`) {
        $pgi{'pgCC'} = 1;
    }
    if (`which pgf77 2> /dev/null`) {
        $pgi{'pgf77'} = 1;
    }
    if (`which pgf90 2> /dev/null`) {
        $pgi{'pgf90'} = 1;
    }

    if (`which icc 2> /dev/null`) {
        $intel{'icc'} = 1;
    }
    if (`which icpc 2> /dev/null`) {
        $intel{'icpc'} = 1;
    }
    if (`which ifort 2> /dev/null`) {
        $intel{'ifort'} = 1;
    }
}

sub set_cfg
{
    my $rpm_full_path = shift @_;
    my $force_name = shift @_;

    # Skip non relevant RPMs in UX package
    my $fname = $rpm_full_path;
    $fname =~ s@$RPMS@@g;
    if ($fname =~ /ofa_kernel|knem|kernel-mft-mlnx|mlnx-en/ and
        $fname !~ m(/ucx-knem) and
        $fname !~ /$rpm_distro\./ and
        $fname !~ /mlnx-ofa_kernel-modules|mlnx-ofa_kernel-devel|knem-modules/) {
        return;
    }

    my $info = get_rpm_info($rpm_full_path);
    my $name = (split(/ /,$info,5))[0];
    my $version = (split(/ /,$info,5))[1];

    if ($name eq "mft-ppc64_trg") {
        $name = "mft";
    }
    # W/A for kmp packages that has only kmod and kmp rpms
    if ( $kmp and $name =~ /kmp|kmod/ and
        $name =~ /$bf_krpm_regex|kernel-mft-mlnx|iser|srp|mlnx-en|mlnx-nfsrdma|mlnx-nvme|mlnx-rdma-rxe/ ) {
        $name =~ s/kmod-//g;
        $name =~ s/-kmp.*//g;
    }

    # W/A for version numbers of RPMs in SLES
    if ($name eq "mlnx-en") {
        $version =~ s/_.*//g;
    }

    if ($force_name ne "") {
        $name = $force_name;
    }

    ( $main_packages{$name}{$version}{'name'},
      $main_packages{$name}{$version}{'version'},
      $main_packages{$name}{$version}{'release'},
      $main_packages{$name}{$version}{'size'},
      $main_packages{$name}{$version}{'description'} ) = split(/ /,$info,5);
      $main_packages{$name}{$version}{'rpmpath'}   = $rpm_full_path;
      $main_packages{$name}{$version}{'name'} = $name;

    # W/A for version numbers of RPMs in SLES
    if ($name eq "mlnx-en") {
        $main_packages{$name}{$version}{'version'} =~ s/_.*//g;
    }

    if ($name eq "mft") {
        $main_packages{$name}{$version}{'name'} = "mft";
    }
    if ($force_name ne "") {
        $main_packages{$name}{$version}{'name'} = $force_name;
    }

    print_and_log("set_cfg: " .
             "name: $name, " .
             "original name: $main_packages{$name}{$version}{'name'}, " .
             "version: $main_packages{$name}{$version}{'version'}, " .
             "release: $main_packages{$name}{$version}{'release'}, " .
             "rpmpath: $main_packages{$name}{$version}{'rpmpath'}, " .
             "size: $main_packages{$name}{$version}{'size'}\n", $verbose3);

    # W/A for mlnx-en when KMP=0
    if ($name eq "mlnx-en-utils") {
        set_cfg($rpm_full_path, "mlnx-en");
    }
}

# set a given property to a given value for all packages with name matching the given name.
sub set_property_for_packages_like
{
    my $name = shift @_;
    my $property = shift @_;
    my $value = shift @_;

    for my $key (keys %packages_info) {
        if ($key =~ /$name/) {
            $packages_info{$key}{$property} = $value;
        }
    }
}

sub disable_package
{
    my $key = shift;

    if (exists $packages_info{$key}) {
	    $packages_info{$key}{'disable_package'} = 1;
        $packages_info{$key}{'available'} = 0;
        for my $requester (@{$packages_deps{$key}{'required_by'}}) {
	        next if (exists $packages_info{$requester}{'disable_package'});
            disable_package($requester);
        }
    }
    # modules
    if (exists $kernel_modules_info{$key}) {
        $kernel_modules_info{$key}{'available'} = 0;
        for my $requester (@{$modules_deps{$key}{'required_by'}}) {
            disable_package($requester);
        }
    }

    if (not (exists $packages_info{$key} or exists $kernel_modules_info{$key})) {
        print_and_log_colored("Unsupported package: $key", (not $quiet), "YELLOW");
    }
}

# used for blocking packages that are replaced with rdma-core and vice versa
sub block_package
{
    my $key = shift;

    if (exists $packages_info{$key}) {
        $packages_info{$key}{'available'} = 0;
        $packages_info{$key}{'disabled'} = 1;
    }
    # modules
    if (exists $kernel_modules_info{$key}) {
        $kernel_modules_info{$key}{'available'} = 0;
        $kernel_modules_info{$key}{'disabled'} = 1;
    }
}

sub enable_package
{
    my $key = shift;

    return unless (exists $packages_info{$key});
    return if (exists $packages_info{$key}{'enabled_package'});

    $packages_info{$key}{'available'} = 1;
    $packages_info{$key}{'enabled_package'} = 1;
    for my $req ( @{ $packages_info{$key}{'ofa_req_inst'} } ) {
        enable_package($req);
    }
}

sub enable_module
{
    my $key = shift;

    if (exists $kernel_modules_info{$key}) {
        $kernel_modules_info{$key}{'available'} = 1;
        for my $req ( @{ $kernel_modules_info{$key}{'requires'} } ) {
            enable_module($req);
        }
    }
}

sub add_enabled_pkgs_by_user
{
    ##############
    # handle with/enable flags
    for my $key ( keys %force_enable_packages ) {
        ### fix kernel package name
	# backward compatibility for old rpm name
        if ($key =~ /kernel-ib/) {
            $key =~ s/kernel-ib/mlnx-ofa_kernel/g;
        }
        # if kmp not supported
        if ($key eq "mlnx-ofa_kernel" and not $kmp) {
            $key =~ s/mlnx-ofa_kernel/mlnx-ofa_kernel-modules/;
        }
        if ($key =~ m/kernel-mft-mlnx/ and not $kmp) {
            $key =~ s/-mlnx//;
        }
        if ($key eq "mlnx-en" and not $kmp) {
            $key = "mlnx_en";
        }
        if ($key eq "knem" and not $kmp) {
            # knem (user space) will be added automatically since knem-modules needs it
            $key = "knem-modules";
        }
        # if kmp supported
        if ($key eq "mlnx-ofa_kernel-modules" and $kmp) {
            $key =~ s/mlnx-ofa_kernel-modules/mlnx-ofa_kernel/;
        }
        if ($key =~ m/kernel-mft/ and $key !~ m/mlnx/ and $kmp) {
            $key .= "-mlnx";
        }
        if ($key eq "mlnx_en" and $kmp) {
            $key = "mlnx-en";
        }
        if ($key eq "knem-modules" and $kmp) {
            $key = "knem";
        }

        if ((exists $packages_info{$key}) and (exists $packages_info{$key}{'parent'})) {
            next if ($packages_info{$key}{'disabled'});
            enable_package($key);
            push (@selected_by_user, $key);
        }
        if (exists $kernel_modules_info{$key}) {
            next if ($kernel_modules_info{$key}{'disabled'});
            enable_module($key);
            push (@selected_modules_by_user , $key);
        }

        if (not (exists $packages_info{$key} or exists $kernel_modules_info{$key})) {
            print_and_log_colored("Unsupported package: $key", (not $quiet), "YELLOW");
        }
    }
}

# Set packages availability depending OS/Kernel/arch
sub set_availability
{
    set_compilers();

    if ($user_space_only) {
        $packages_info{"mlnx-ofa_kernel"}{"mode"} = "user";
    }

    if ($is_bf) {
        # Avoid rshim installation on BlueField
        $packages_info{'rshim'}{'available'} = 0;
    }

    if ($arch =~ m/aarch64/ and $DISTRO =~ /ALTERNATE/) {
        if ($with_bluefield) {
            $packages_info{'sockperf'}{'available'} = 0;
            $packages_info{'sockperf-debuginfo'}{'available'} = 0;
        }
    } else {
        for my $package (@bf_only_kernel_packages) {
            $packages_info{$package}{'available'} = 0;
        }
        $packages_info{'libpka'}{'available'} = 0;
        $packages_info{'spdk'}{'available'} = 0;
        $packages_info{'mlxbf-bootctl'}{'available'} = 0;
        $packages_info{'mlxbf-bootimages'}{'available'} = 0;
        $packages_info{'bfscripts'}{'available'} = 0;
    }

    if ($arch =~ m/aarch64/ and $DISTRO =~ m/ALTERNATE/) {
        $packages_info{'nvme-snap'}{'available'} = 1;
    }

    if ($kernel =~ /^4\.5/) {
        $packages_info{'tmfifo'}{'available'} = 0;
    }

    if ($DISTRO !~ /RHEL[78] | FC3[0-9]/x) {
        $packages_info{'openvswitch'}{'available'} = 0;
        for my $package (@dpdk_packages) {
            $packages_info{$package}{'available'} = 0;
        }
    }

    if ($arch =~ /ppc/){
        $packages_info{'srp'}{'available'} = 0;
    }

    # require numa stuff where supported inbox
    if ($DISTRO =~ /RHEL|OL|FC|POWERKVM|EULEROS|BCLINUX|ALIOS/) {
        push(@{$packages_info{'openmpi'}{'dist_req_build'}}, 'numactl-devel');
        push(@{$packages_info{'ucx'}{'dist_req_build'}}, 'numactl-devel');
        push(@{$packages_info{'hcoll'}{'dist_req_build'}}, 'numactl-devel');
        push(@{$packages_info{'mlnx-dpdk'}{'dist_req_build'}}, 'numactl-devel');
        push(@{$packages_info{'openvswitch'}{'ofa_req_build'}}, 'mlnx-dpdk-devel') if ($with_ovs_dpdk);
        push(@{$packages_info{"libibverbs"}{'dist_req_build'}}, "numactl-devel$suffix_64bit");
        push(@{$packages_info{"libibverbs"}{'dist_req_build'}}, "numactl-devel$suffix_32bit") if ($install32 == 1);

        my $numactl = "numactl";
        if ($DISTRO =~ /FC19|FC[2-9]|OL[7-9]|RHEL[7-9]|POWERKVM|EULEROS|BCLINUX|ALIOS/) {
            $numactl = "numactl-libs";
        }
        push(@{$packages_info{'openmpi'}{'dist_req_inst'}}, "$numactl");
        push(@{$packages_info{'ucx'}{'dist_req_inst'}}, "$numactl");
        push(@{$packages_info{'hcoll'}{'dist_req_inst'}}, "$numactl");
        push(@{$packages_info{'mlnx-dpdk'}{'dist_req_inst'}}, "$numactl");
        push(@{$packages_info{"libibverbs"}{'dist_req_inst'}}, "${numactl}${suffix_64bit}");
        push(@{$packages_info{"libibverbs"}{'dist_req_inst'}}, "${numactl}${suffix_32bit}") if ($install32 == 1);
    }

    # mvapich and openmpi
    if ($gcc{'gcc'}) {
        $packages_info{'openmpi'}{'available'} = 1;
        set_property_for_packages_like('mpitests_openmpi', 'available', 1);
    }

    if ($arch !~ m/x86_64|ppc64le|aarch|arm/ or $DISTRO =~ /RHEL5|XenServer/) {
        for my $package (@mpi_packages) {
            $packages_info{$package}{'available'} = 0;
        }
        $packages_info{'ucx'}{'available'} = 0;
        $packages_info{'ucx-devel'}{'available'} = 0;
        $packages_info{'ucx-static'}{'available'} = 0;
        $packages_info{'ucx-cma'}{'available'} = 0;
        $packages_info{'ucx-ib'}{'available'} = 0;
        $packages_info{'ucx-ib-cm'}{'available'} = 0;
        $packages_info{'ucx-rdmacm'}{'available'} = 0;
        $packages_info{"$knem_rpm"}{'available'} = 0;
        $packages_info{"$knem_mods"}{'available'} = 0 if ($knem_mods ne "");
        $packages_info{'hcoll'}{'available'} = 0;
        $packages_info{'sharp'}{'available'} = 0;
    }

    if ($DISTRO =~ m/WINDRIVER6/) {
        $kernel_modules_info{'mthca'}{'available'} = 0;
        $kernel_modules_info{'nfsrdma'}{'available'} = 0;
        $packages_info{'mlnx-nfsrdma'}{'available'} = 0;
        $packages_info{'mlnx-nvme'}{'available'} = 0;
        $packages_info{'mlnx-rdma-rxe'}{'available'} = 0;
        $kernel_modules_info{'rds'}{'available'} = 0;
        $kernel_modules_info{'sdp'}{'available'} = 0;
        $kernel_modules_info{'srpt'}{'available'} = 0;
        $packages_info{'knem'}{'available'} = 0;
        $packages_info{"$knem_mods"}{'available'} = 0 if ($knem_mods ne "");
        for my $package (@mpi_packages) {
            $packages_info{$package}{'available'} = 0;
        }
        $packages_info{'ucx'}{'available'} = 0;
        $packages_info{'ucx-devel'}{'available'} = 0;
        $packages_info{'ucx-static'}{'available'} = 0;
        $packages_info{'ucx-cma'}{'available'} = 0;
        $packages_info{'ucx-ib'}{'available'} = 0;
        $packages_info{'ucx-ib-cm'}{'available'} = 0;
        $packages_info{'ucx-rdmacm'}{'available'} = 0;
        $packages_info{"$knem_rpm"}{'available'} = 0;
        $packages_info{"$knem_mods"}{'available'} = 0 if ($knem_mods ne "");
        $packages_info{'hcoll'}{'available'} = 0;
        $packages_info{'sharp'}{'available'} = 0;
    }

    if ($cuda_version ne '') {
        $packages_info{'ucx-cuda'}{'available'} = 1;
        $packages_info{'hcoll-cuda'}{'available'} = 1;
        $packages_info{'clusterkit'}{'available'} = 1;
    }
    if (is_installed("gdrcopy")) {
        $packages_info{'ucx-gdrcopy'}{'available'} = 1;
    }

    if ( not ($with_vma or $with_xlio) or ($arch !~ m/x86_64|ppc64|aarch64/) or $DISTRO =~ /XenServer|WINDRIVER6/) {
        for my $package (qw/
            libvma libvma-utils libvma-devel
            sockperf
            libxlio libxlio-utils libxlio-devel
        /) {
            $packages_info{$package}{'available'} = 0;
        }
    }

    if ($DISTRO !~ /RHEL8.3/ or $arch ne 'x86_64') {
        for my $package (qw/libxlio libxlio-utils libxlio-devel/) {
            $packages_info{$package}{'available'} = 0;
        }
    }
    if ($kernel_only) {
        for my $package (qw/libxpmem libxpmem-devel/) {
            $packages_info{$package}{'available'} = 0;
        }
    }

    # disable sockperf on SLES due to build issues
    if ($DISTRO =~ /POWERKVM/) {
       $packages_info{'sockperf'}{'available'} = 0;
    }

    # enable fabric-collector only if --with-fabric-collector was given and the OS is supported.
    if ( not ($with_fabric_collector and
             ($DISTRO =~ /RHEL6/ or
              $DISTRO =~ /RHEL7/ or
              $rpm_distro =~ /sles12sp/)) ) {
       $packages_info{'fabric-collector'}{'available'} = 0;
       print_and_log_colored("Unsupported package: fabric-collector", (not $quiet), "YELLOW") if ($with_fabric_collector);
    }

    if ($arch =~ /arm|aarch/i) {
        $packages_info{'dapl'}{'available'} = 0;
        $packages_info{'dapl-devel'}{'available'} = 0;
        $packages_info{'dapl-devel-static'}{'available'} = 0;
        $packages_info{'dapl-utils'}{'available'} = 0;
        $packages_info{'dapl-debuginfo'}{'available'} = 0;
    }

    if ($kernel =~ /fbk/ or $arch =~ /arm|aarch/) {
       $kernel_modules_info{'sdp'}{'available'} = 0;
    }

    if ($kernel =~ /fbk36/) {
       $kernel_modules_info{'rds'}{'available'} = 0;
    }
    # turn on isert if we are on follow OS and arch
    if (not ($rpm_distro =~ /
            rhel7u[2-9] | rhel[89] |
            ol7u4 |
            sles12sp[1-5] | sles15sp |
            fc2[789] | fc3[0-9]
        /x and $kernel =~ /
            fbk16 | ^4\.[4-9] | ^4\.1[0-9]\. | ^4\.20 | ^[5-9] |
            ^4\.1\.12-94 |                                  # OL7.4
            3.10.0-.*el7 | 3.12.28-4 | 3.12.49- | 3.12.48- |
            4\.18\.0-.*el8
        /x
    )) {
       $kernel_modules_info{'isert'}{'available'} = 0;
       $packages_info{'isert'}{'available'} = 0;
    }

    # disable iproute2 for unsupported OSs
    if ($rpm_distro =~ /fc23|powerkvm|xenserver|windriver/) {
        $packages_info{'mlnx-iproute2'}{'available'} = 0;
    }

    if ($arch =~ /ppc64/ and $rpm_distro =~ /rhel7u[0-1]/) {
        $packages_info{'mlnx-iproute2'}{'available'} = 0;
    }

    if (
        ($rpm_distro =~ /rhel7[2-9]/x and $arch =~ /x86_64|ppc64|ppc64le/) or
        ($rpm_distro =~ /ol7 | fc27 | euleros2u0sp3/x and $arch =~ /x86_64/) or
        ($rpm_distro =~ /sles12sp[34] | sles15sp1/x and $arch =~ /x86_64/) or
        ($rpm_distro =~ /sles12sp5 | sles15sp0/x and $arch =~ /x86_64|ppc64|ppc64le/) or
        0) {
            $packages_info{'neohost-backend'}{'available'} = 1;
            $packages_info{'neohost-sdk'}{'available'} = 1;
    }

    if ($DISTRO =~ /RHEL6.4|RHEL6.5|RHEL7\.[0-5]/ and $arch =~ m/x86_64/) {
       $packages_info{'multiperf'}{'available'} = 1;
    }

    if (($arch ne 'x86_64') or ($kernel !~ /
              ^4\.12\.14-94\b   # SLES12 SP4
            | ^4\.12\.14-120\b  # SLES12 SP5
            | ^4\.12\.14-195\b  # SLES15 SP1
            | ^5\.3\.18-22\b    # SLES15SP2
            | ^5\.3\.18-57\b    # SLES15SP3
            | ^5\.14\.21-\b     # SLES15SP4
            | ^3\.10\.0-(\d+)\b # RHEL 7.x
            | ^4\.18\.0-(\d+)\b # RHEL 8.x
            | ^5\.14\.0-(\d+)\b # RHEL 9.x
            | ^5\.13\b          # Latest rebase's base
            | ^5\.15\b
            | ^5\.17\b
            | ^5\.18\b          # Latest mainline
            /x
        ) or (
            # RHEL7: >= 7.5:
            ($kernel =~ /^3\.10\.0-(\d+)\b/) and ($1 < 862)
        ) or
        $rpm_distro =~ /euleros/ or
        not $with_nfsrdma
    ) {
        if ($with_nfsrdma) {
            # user asked to install it, but it's not supported by the kernel
            print_and_log_colored("WARNING: NFSoRDMA is not supported over kernel $kernel, will continue installation without it.\n", 1, "YELLOW");
        }
        $kernel_modules_info{'nfsrdma'}{'available'} = 0;
        $packages_info{'mlnx-nfsrdma'}{'available'} = 0;
    }

    if (
        not $with_nvme or
        ($kernel =~ /lustre/) or
        not (
            ($kernel =~ /^[5-9]|^4\.[8-9]|^4\.[12][0-9]/) or
            ($rpm_distro =~ /sles12sp3/ and $kernel =~ /^4\.4/) or
            ($rpm_distro =~ /sles12sp4/ and $kernel =~ /^4\.12/) or
            ($DISTRO =~ /RHEL7.[2-9]|RHEL6.3/ and $kernel =~ /3.10.0/)
        )
    ) {
        if ($with_nvme) {
            # user asked to install it, but it's not supported by the kernel
            print_and_log_colored("WARNING: NVMEoF is not supported over kernel $kernel, will continue installation without it.\n", 1, "YELLOW");
        }
        $packages_info{'mlnx-nvme'}{'available'} = 0;
    }

    if ($kernel !~ /^[5-9]|^4\.[8-9]|^4\.1[0-9]\./) {
        $packages_info{'mlnx-rdma-rxe'}{'available'} = 0;
    }

    # turn off srp and iser if we are not on follow OS and arch
    if (not ($rpm_distro =~ /
            rhel6u[8-9] | rhel6u10 | rhel7u[1-9] | rhel[89] |
            ol6u9 | ol7u4 |
            sles12sp[1-5] | sles15sp |
            fc2[789] | fc3[0-9]
        /x and $kernel =~ /
            ^3.1[6-9] | ^[4-9] |
            3.10.0.*el7.* | 3.*-default | 2.6.32.*el6.*
        /x)
    ) {
        $kernel_modules_info{'srp'}{'available'} = 0;
        $packages_info{'srp'}{'available'} = 0;
        $kernel_modules_info{'iser'}{'available'} = 0;
        $packages_info{'iser'}{'available'} = 0;
    }

    # make sure user cannot force adding disabled package using --with flag
    block_package("multiperf");
    block_package("multiperf-debuginfo");

    ##############
    # handle without/disable flags
    if (keys %disabled_packages) {
        # build deps list
        for my $pkg (keys %packages_info) {
            for my $req ( @{ $packages_info{$pkg}{'ofa_req_inst'}} , @{ $packages_info{$pkg}{'ofa_req_build'}} ) {
                next if not $req;
                push (@{$packages_deps{$req}{'required_by'}}, $pkg);
            }
        }
        for my $mod (keys %kernel_modules_info) {
            for my $req ( @{ $kernel_modules_info{$mod}{'requires'} } ) {
                next if not $req;
                push (@{$modules_deps{$req}{'required_by'}}, $mod);
            }
        }
        # disable packages
        for my $key ( keys %disabled_packages ) {
            disable_package($key);
        }
    }
    # end of handle without/disable flags

    #
    # keep this at the end of the function.
    #
    # debuginfo RPM currently are not supported on SuSE and Ubuntu
    if ($DISTRO =~ m/SLES|SUSE|WINDRIVER6|POWERKVM/) {
        for my $package (@all_packages) {
            if ($package =~ m/-debuginfo/) {
                $packages_info{$package}{'available'} = 0;
            }
        }
    }

    add_enabled_pkgs_by_user();
}

# Some packages may be rebuilt for a different kernel version.
# Therefore we only allow them if the kernel version encoded in the rpm
# release string matches the kernel version we target.
sub check_kernel_matches($$) {
    my ($rpm_arch, $kernel_from_release) = @_;

    if ($rpm_arch ne $target_cpu) {
        return 0;
    }
    if ($DISTRO =~ /CTYUNOS/) {
        return ("$kernel_from_release" eq "$kernel_rel.ctl2");
    }
    return ("$kernel_from_release" eq "$kernel_rel");
}

# Set rpm_exist parameter for existing RPMs
sub set_existing_rpms
{
    my $glob = "$RPMS/*.rpm";

    for my $binrpm (glob $glob) {
        my ($rpm_name, $rpm_arch) = (split ' ', get_rpm_name_arch($binrpm));
        my $ver = get_rpm_ver($binrpm);
        my $ver_no_rel = $ver; #version without kernel release
        $ver_no_rel =~ s/_.*//g;
        my $kernel_from_release = get_rpm_rel($binrpm);
        chomp $kernel_from_release;
        $kernel_from_release =~ s/.*\.kver\.//g;
        $kernel_from_release =~ s/_OFED.*//g;

        print_and_log("Found RPM: $rpm_name $ver, $rpm_arch\n", $verbose2);
        if ( $rpm_name =~ /$bf_krpm_regex|knem-modules|kernel-mft|iser|srp$|mlnx-nfsrdma|mlnx-nvme|mlnx-rdma-rxe/ and
             $rpm_name !~ /kmp|kmod/) {
            if ($kmp) {
                print_and_log("KMP=1 -> ignoring $rpm_name $ver\n", $verbose2);
                next;
            }
            if (check_kernel_matches($rpm_arch, $kernel_from_release)) {
                set_cfg ($binrpm);
                $packages_info{$rpm_name}{$ver}{'rpm_exist'} = 1;
                print_and_log("$rpm_name $ver RPM exist\n", $verbose2);
            }
        } elsif ($rpm_name =~ /mlnx-ofa_kernel-modules/) {
            if (check_kernel_matches($rpm_arch, $kernel_from_release)) {
                set_cfg ($binrpm);
                $packages_info{$rpm_name}{$ver}{'rpm_exist'} = 1;
                print_and_log("$rpm_name $ver RPM exist\n", $verbose2);
            }
        } elsif ($rpm_name =~ /mlnxofed-docs|bfscripts/) {
            set_cfg ($binrpm);
            $packages_info{$rpm_name}{$ver}{'rpm_exist'} = 1;

        # W/A for kmp packages that has only kmod and kmp rpms
        } elsif ($rpm_name =~ /kmp|kmod/ and
                 $rpm_name =~ /$bf_krpm_regex|kernel-mft-mlnx|iser|srp|mlnx-en|mlnx-nfsrdma|mlnx-nvme|mlnx-rdma-rxe/) {
                if (not $kmp) {
                    print_and_log("KMP=0 -> ignoring $rpm_name $ver\n", $verbose2);
                    next;
                }
                set_cfg ($binrpm);
                my $pkname = $rpm_name;
                $pkname =~ s/kmod-//g;
                $pkname =~ s/-kmp.*//g;
                # W/A for version numbers of RPMs in SLES
                my $tmpver = $ver;
                if ($pkname =~ "mlnx-en") {
                    $tmpver =~ s/_.*//g;
                }
                $packages_info{"$pkname"}{$tmpver}{'rpm_exist'} = 1;
                $packages_info{$rpm_name}{$tmpver}{'rpm_exist'} = 1;
                print_and_log("$rpm_name $ver RPM exist\n", $verbose2);
        } elsif($rpm_name =~ /mpitests/) {
                # make a new node for this rpm in packages_info
                clone_pkg_info_node("mpitests", $rpm_name);
                # enable it
                $packages_info{$rpm_name}{'available'} = 1;
                $packages_info{$rpm_name}{'parent'} = $rpm_name;
                # add requirements
                my $mpi = "";
                my $base = "";
                if ($rpm_name =~ /__/) {
                    $mpi = $rpm_name;
                    $mpi =~ s/mpitests_//g; # mpi = name_ver
                    $base = (split('__', $mpi))[0];
                } else {
                    $base = (split('_', $rpm_name))[1];
                }
                push(@{$packages_info{$rpm_name}{'ofa_req_build'}}, $base);
                push(@{$packages_info{$rpm_name}{'ofa_req_inst'}}, $base);
                # add it to relevant packages groups
                push(@user_packages, $rpm_name);
                push(@all_packages, $rpm_name);
                push(@hpc_user_packages, $rpm_name);
                push(@guest_user_packages, $rpm_name);
                push(@mpi_packages, $rpm_name);
                set_cfg ($binrpm);
                $packages_info{$rpm_name}{$ver}{'rpm_exist'} = 1;
                print_and_log("$rpm_name $ver RPM exist\n", $verbose2);
        } else {
            set_cfg ($binrpm);
            if ($rpm_name =~ /^mft/) {
                # TBD: Commented out to support mft-oem
                # $rpm_name = "mft";
                $packages_info{$rpm_name}{$ver}{'rpm_exist'} = 1;
                print_and_log("$rpm_name $ver RPM exist\n", $verbose2);
            }
            if (($rpm_arch eq $target_cpu) or ($rpm_arch eq 'noarch')) {
                $packages_info{$rpm_name}{$ver}{'rpm_exist'} = 1;
                print_and_log("$rpm_name $ver RPM exist\n", $verbose2);
                if ($rpm_arch eq 'noarch') {
                    $packages_info{$rpm_name}{$ver}{'is_noarch'} = 1;
                }
            }
            elsif ($rpm_arch eq $target_cpu32) {
                $packages_info{$rpm_name}{$ver}{'rpm_exist32'} = 1;
                print_and_log("$rpm_name $ver 32-bit RPM exist\n", $verbose2);
            }
        }
    }
}

sub clone_pkg_info_node
{
    my $name = shift @_;
    my $new_name = shift @_;

    for my $key (keys %{$packages_info{$name}}) {
        if(ref($packages_info{$name}{$key}) eq 'ARRAY') {
            # copy array content, not ref
            @{$packages_info{$new_name}{$key}} = @{$packages_info{$name}{$key}};
        } else {
            $packages_info{$new_name}{$key} = $packages_info{$name}{$key};
        }
    }
}

sub is_rpm_available
{
    my $name = shift;

    for my $ver (keys %{$main_packages{$name}}) {
        if ($main_packages{$name}{$ver}{'rpmpath'}) {
            return 1;
        }
    }

    return 0;
}

# Select package for installation
sub select_packages
{
    my $cnt = 0;
    if ($config_given) {
        open(CONFIG, "$config") || die "Can't open $config: $!";;
        flock CONFIG, $LOCK_EXCLUSIVE;
        while(<CONFIG>) {
            next if (m@^\s+$|^#.*@);
            my ($package,$selected) = (split '=', $_);
            $package =~ s/ //g;
            $selected =~ s/ //g;
            chomp $package;
            chomp $selected;

            ### fix kernel package name
            # backward compatibility for old rpm name
            if ($package =~ /kernel-ib/) {
                $package =~ s/kernel-ib/mlnx-ofa_kernel/g;
            }
            # if kmp not supported
            if ($package eq "mlnx-ofa_kernel" and not $kmp) {
                $package =~ s/mlnx-ofa_kernel/mlnx-ofa_kernel-modules/;
            }
            if ($package =~ m/kernel-mft-mlnx/ and not $kmp) {
                $package =~ s/-mlnx//;
            }
            if ($package eq "knem" and not $kmp) {
                # knem (user space) will be added automatically since knem-modules needs it
                $package = "knem-modules";
            }
            if ($package eq "mlnx-en" and not $kmp) {
                $package = "mlnx_en";
            }
            # if kmp supported
            if ($package eq "mlnx-ofa_kernel-modules" and $kmp) {
                $package =~ s/mlnx-ofa_kernel-modules/mlnx-ofa_kernel/;
            }
            if ($package =~ m/kernel-mft/ and $package !~ m/mlnx/ and $kmp) {
                $package .= "-mlnx";
            }
            if ($package eq "mlnx_en" and $kmp) {
                $package = "mlnx-en";
            }
            if ($package eq "knem-modules" and $kmp) {
                $package = "knem";
            }

            print_and_log("$package=$selected\n", $verbose3);

            if ($package eq "install32") {
                if (supported32bit()) {
                    $install32 = 1 if ($selected);
                }
                next;
            }

            if (substr($package,0,length("vendor_config")) eq "vendor_config") {
                    next;
            }

            if ($package eq "vendor_pre_install") {
                    if ( -e $selected ) {
                            $vendor_pre_install = dirname($selected) . '/' . basename($selected);
                    }
                    else {
                            print_and_log_colored("\nVendor script $selected is not found", (not $quiet), "RED");
                            exit $ERROR
                    }
                    next;
            }

            if ($package eq "vendor_post_install") {
                    if ( -e $selected ) {
                            $vendor_post_install = dirname($selected) . '/' . basename($selected);
                    }
                    else {
                            print_and_log_colored("\nVendor script $selected is not found", (not $quiet), "RED");
                            exit $ERROR
                    }
                    next;
            }

            if ($package eq "vendor_pre_uninstall") {
                    if ( -e $selected ) {
                            $vendor_pre_uninstall = dirname($selected) . '/' . basename($selected);
                    }
                    else {
                            print_and_log_colored("\nVendor script $selected is not found", (not $quiet), "RED");
                            exit $ERROR
                    }
                next;
            }

            if ($package eq "vendor_post_uninstall") {
            if ( -e $selected ) {
                $vendor_post_uninstall = dirname($selected) . '/' . basename($selected);
            }
            else {
                print_and_log_colored("\nVendor script $selected is not found", (not $quiet), "RED");
                exit $ERROR
            }
                next;
            }

            if ($package eq "kernel_configure_options" or $package eq "OFA_KERNEL_PARAMS") {
                $kernel_configure_options = $selected;
                next;
            }

            if ($package eq "user_configure_options") {
                $user_configure_options = $selected;
                next;
            }

            if ($package =~ m/configure_options/) {
                my $pack_name = (split '_', $_)[0];
                $packages_info{$pack_name}{'configure_options'} = $selected;
                next;
            }

            if (not $packages_info{$package}{'parent'}) {
                   print_and_log_colored("Unsupported package: $package", (not $quiet), "YELLOW");
                   next;
            }

            if (not $packages_info{$package}{'available'} and $selected eq 'y') {
                print_and_log("$package is not available on this platform\n", (not $quiet));
                next;
            }

            if ($package eq "update_firmware") {
                $update_firmware = $selected;
                next;
            }

            if ( $selected eq 'y' ) {
                push (@selected_by_user, $package);
                print_and_log("select_package: selected $package\n", $verbose2);
                $cnt ++;
            }
        }
        flock CONFIG, $UNLOCK;
    }
    else {
        open(CONFIG, ">>$config") || die "Can't open $config: $!";
        print CONFIG "prefix=$prefix\n";
        if ($install32) {
                print CONFIG "install32=1\n";
        }
        if ($install_option eq 'all') {
            for my $package ( @all_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'bluefield') {
            for my $package ( @bluefield_user_packages, @bluefield_kernel_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                next if ($kernel_only and $packages_info{$package}{'mode'} ne 'kernel');
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'hpc') {
            for my $package ( @hpc_user_packages, @hpc_kernel_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option =~ m/vma/) {
            my @list = ();
            if ($install_option eq 'vma') {
                @list = (@vma_user_packages);
            } elsif ($install_option eq 'vmavpi') {
                @list = (@vmavpi_user_packages);
            } elsif ($install_option eq 'vmaeth') {
                @list = (@vmaeth_user_packages);
            }
            for my $package ( @list, @vma_kernel_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option =~ m/xlio/) {
            for my $package ( @xlio_user_packages, @xlio_kernel_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'basic') {
            for my $package (@basic_user_packages, @basic_kernel_packages) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'msm') {
            for my $package ( @msm_user_packages, @msm_kernel_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'guest-os') {
            for my $package ( @guest_kernel_packages, @guest_user_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'hypervisor-os') {
            for my $package ( @hypervisor_kernel_packages, @hypervisor_user_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'kernel-only') {
            for my $package ( @all_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not $packages_info{$package}{'mode'} eq 'kernel');
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option eq 'eth-only') {
            for my $package ( @eth_kernel_packages, @eth_user_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        elsif ($install_option =~ m/dpdk/) {
            for my $package ( @dpdk_user_packages, @dpdk_kernel_packages ) {
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                push (@selected_by_user, $package);
                print CONFIG "$package=y\n";
                $cnt ++;
            }
        }
        else {
            print_and_log_colored("\nUnsupported installation option: $install_option", 1, "RED");
            exit $ERROR;
        }
    }

    if ($with_bluefield and $install_option ne 'bluefield') {
        for my $package ( @bluefield_user_packages, @bluefield_kernel_packages ) {
            next if (grep /^$package$/, @selected_by_user);
            next if (not $packages_info{$package}{'available'});
            next if (not is_rpm_available($package));
            next if ($kernel_only and $packages_info{$package}{'mode'} ne 'kernel');
            push (@selected_by_user, $package);
            print CONFIG "$package=y\n";
            $cnt ++;
        }
    }

    if ($with_ovs_dpdk) {
        for my $package ( @dpdk_packages, "openvswitch") {
            next if (grep /^$package$/, @selected_by_user);
            next if (not $packages_info{$package}{'available'});
            next if (not is_rpm_available($package));
            next if ($kernel_only and $packages_info{$package}{'mode'} ne 'kernel');
            push (@selected_by_user, $package);
            print CONFIG "$package=y\n";
            $cnt ++;
        }
    }

    close(CONFIG);

    return $cnt;
}

sub mark_for_uninstall
{
    my $package = shift @_;

    return if ($is_mlnx_en and $package =~ /mft/);

    if (not $selected_for_uninstall{$package}) {
        push (@dependant_packages_to_uninstall, "$package");
        $selected_for_uninstall{$package} = 1;
        my $pname = $package;
        $pname =~ s@-[0-9].*@@g;
        if (not (exists $packages_info{$pname} or $pname =~ /mlnx-ofed-/)) {
            $non_ofed_for_uninstall{$pname} = 1;
        }
    }
}

my %check_uninstall = ();
sub get_requires
{
    my $package = shift @_;

    # Strip RPM version
    my $pname = `$RPM -q --queryformat "[%{NAME}]" $package 2>/dev/null`;
    chomp $pname;

    if ($check_uninstall{$package}) {
        return; # already checked here
    }
    $check_uninstall{$package} = 1;

    if ($pname eq "rdma") {
        # don't remove packages that needs rdma package
        return;
    }

    my @what_requires = `$RPM -q --whatrequires $pname 2> /dev/null | grep -v "no package requires" 2> /dev/null`;

    for my $pack_req (@what_requires) {
        chomp $pack_req;
        print_and_log("get_requires: $pname is required by $pack_req\n", $verbose2);
        get_requires($pack_req);
        mark_for_uninstall($pack_req);
    }
}

# return 0 if pacakge not selected
# return 1 if pacakge selected
sub select_dependent
{
    my $package = shift @_;

    if ($user_space_only and ($packages_info{$package}{'mode'} eq 'kernel')) {
        print_and_log("select_dependent: in user-space-only mode, skipping kernel package: $package\n", $verbose2);
        return 0;
    }

    my $scanned = 0;
    for my $ver (keys %{$main_packages{$package}}) {
        $scanned = 1;

        # prevent loop
        if (not exists $packages_info{$package}{'entered_select_dependent'}) {
            $packages_info{$package}{'entered_select_dependent'}  = 1;
        } else {
            return 0 if (not $packages_info{$package}{'available'});
            return 1;
        }

        if ( (not $packages_info{$package}{$ver}{'rpm_exist'}) or
             ($install32 and $packages_info{$package}{$ver}{'install32'} and not $packages_info{$package}{$ver}{'rpm_exist32'}) ) {
            print_and_log("resolve_dependencies: $package $ver does not exist. Skip dependencies check\n", $verbose2);
            return 0;
        }

        for my $req ( @{ $packages_info{$package}{'ofa_req_inst'} } ) {
            next if not $req;
            print_and_log("resolve_dependencies: $package requires $req for rpm install\n", $verbose2);
            my $req_selected = 0;
            if ($packages_info{$req}{'available'}) {
                if (not $packages_info{$req}{'selected'}) {
                    $req_selected = select_dependent($req);
                } else {
                    $req_selected = 1;
                }
            }
            if (not $req_selected and not grep( /^$req$/, @{ $packages_info{$package}{'soft_req'} } )) {
                print_and_log("select_dependent: $req requiement not satisfied for $package, skipping it\n", $verbose2);
                $packages_info{$package}{'available'} = 0;
                return 0;
            }
        }

        if (not $packages_info{$package}{'selected'}) {
            return 0 if (not $packages_info{$package}{'available'});
            $packages_info{$package}{'selected'} = 1;
            push (@selected_packages, $package);
            $required_space += $main_packages{$package}{$ver}{'size'};
            print_and_log("select_dependent: Selected package $package $ver size $main_packages{$package}{$ver}{'size'}\n", $verbose2);
            return 1;
        }
    }
    if ($scanned eq "0") {
        print_and_log("resolve_dependencies: $package does not exist. Skip dependencies check\n", $verbose2);
    }
    # if we get here, then nothing got selected.
    return 0;
}

sub resolve_dependencies
{
    for my $package ( @selected_by_user ) {
            # Get the list of dependencies
            select_dependent($package);
        }
}

sub check_linux_dependencies
{
    my $err = 0;
    my $p1 = 0;
	my %missing_packages = ();
    if (! $check_linux_deps) {
        return 0;
    }

    for my $package ( @selected_packages ) {
        # Check installation requirements
        for my $req ( @{ $packages_info{$package}{'dist_req_inst'} } ) {
            my ($req_name, $req_version) = (split ('__',$req));
            next if not $req_name;
            if (not is_installed($req_name)) {
                if ($req_name =~ /libgfortran/) {
                    print_and_log("Warning: $req_name rpm is required to run $package\n", not $quiet);
                    print_and_log("$req_name is available on $DISTRO SDK DVD\n", not $quiet);
                } else {
                    print_and_log_colored("$req_name rpm is required to install $package", $verbose2, "RED");
                    $missing_packages{"$req_name"} = 1;
                    $err++;
                }
            }
            if ($req_version) {
                my $inst_version = get_rpm_ver_inst($req_name);
                print_and_log("check_linux_dependencies: $req_name installed version $inst_version, required $req_version\n", $verbose3);
                if ($inst_version lt $req_version) {
                    print_and_log_colored("$req_name-$req_version rpm is required to install $package", $verbose2, "RED");
                    $missing_packages{"$req_name-$req_version"} = 1;
                    $err++;
                }
            }
        }
        if ($install32) {
            # if (not -e "/usr/lib/crt1.o") {
            #     if (! $p1) {
            #         print RED "glibc-devel 32bit is required to install 32-bit libraries.", RESET "\n";
            #         $p1 = 1;
            #         $err++;
            #     }
            # }
            if ($arch eq "ppc64") {
                my @libstdc32 = </usr/lib/libstdc++.so.*>;
                if ($package eq "mstflint") {
                    if (not scalar(@libstdc32)) {
                        print_and_log_colored("$libstdc 32bit is required to install mstflint.", $verbose2, "RED");
                        $missing_packages{"$libstdc$suffix_32bit"} = 1;
                        $err++;
                    }
                }
                elsif ($package =~ /openmpi/) {
                    my @libsysfs = </usr/lib/libsysfs.so.*>;
                    if (not scalar(@libstdc32)) {
                        print_and_log_colored("$libstdc 32bit is required to install openmpi.", $verbose2, "RED");
                        $missing_packages{"$libstdc$suffix_32bit"} = 1;
                        $err++;
                    }
                    if (not scalar(@libsysfs)) {
                        print_and_log_colored("$sysfsutils 32bit is required to install openmpi.", $verbose2, "RED");
                        $missing_packages{"$sysfsutils$suffix_32bit"} = 1;
                        $err++;
                    }
                }
            }
        }
    }
    if ($err) {
        # display a summary of missing packages
        if (keys %missing_packages) {
            print_and_log_colored("Error: One or more required packages for installing $PACKAGE are missing.", 1, "RED");
            print_and_log_colored("Please install the missing packages using your Linux distribution Package Management tool.", 1, "RED");
            print_and_log("Run:\n$package_manager install " . join(' ', (keys %missing_packages)) . "\n", 1);
        }
        exit $PREREQUISIT;
    }

    if ($check_deps_only) {
        print_and_log("All required packages are installed, the system is ready for $PACKAGE installation.\n", 1);
        exit 0;
    }
}

sub check_disk_space
{
    my $dir = "/usr";
    # Required diskspace in KB
    $required_space = sprintf("%d", $required_space / 1024);
    # Free space in KB
    my $freespace = `df $dir | grep -v '^Filesystem' | awk 'NF==6{print \$4}NF==5{print \$3}{}'`;
    chomp $freespace;

    print_and_log("Available disk space: $freespace KB Required disk space: $required_space KB\n", $verbose3);

    if ($freespace < $required_space) {
        print_and_log_colored("Not enough free space. Required $required_space KB", 1, "RED");
        exit $ENOSPC;
    }
}

# Print the list of selected packages
sub print_selected
{
    print_and_log_colored("\nBelow is the list of ${PACKAGE} packages that you have chosen
    \r(some may have been added by the installer due to package dependencies):\n", 1, "GREEN");
    for my $package ( @selected_packages ) {
        print_and_log("$package\n", 1);
    }
    if ($install32) {
        print_and_log("32-bit binaries/libraries will be created\n", 1);
    }
    print_and_log("\n", 1);
}

sub build_kernel_rpm
{
        print_and_log("Not available\n", 1);
}

# Build RPM from source RPM
sub build_rpm
{
        print_and_log("Not available\n", 1);
}

sub install_verify
{
    my $package = shift @_;
    my $log = shift @_;
    my $res = 0;
    my $sig = 0;

    print_and_log("Verifying $package\n", $verbose2);
    system("$RPM -q $package >> $log 2>&1");
    $res = $? >> 8;
    $sig = $? & 127;
    if ($sig or $res) {
        print_and_log_colored("$package RPM was not installed", 1, "RED");
        addSetupInfo ("$log");
        print_and_log_colored("See $log", 1, "RED");
        exit $ERROR;
    }
}

sub install_kernel_rpm
{
    my $name = shift @_;
    my $ver = shift @_;
    my $cmd;
    my $res = 0;
    my $sig = 0;

    my $version = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'version'};

    # release number is from binary rpm with kver
    my $release = "$main_packages{$packages_info{$name}{'parent'}}{$ver}{'release'}";
    $release =~ s/\.kver\..*//g;
    $release =~ s/\.$rpm_distro.*//g;
    if ($DISTRO =~ /KYLIN/) {
        $release =~ s/\.$rpm_distro\.ky10$//g;
    }
    $release = "${release}.kver.${kernel_rel}";

    my $arch = $target_cpu;

    if (exists $package_pre_install_script{$name}) {
        print_and_log("Running $name pre install script: $package_pre_install_script{$name}\n", $verbose);
        ex("$package_pre_install_script{$name}");
    }

    # will enter this block if  KMP is enabled and this is a package that supports kmp
    if (($name =~ /$bf_krpm_regex|ofa_kernel|knem|^xpmem|kernel-mft-mlnx|iser|srp|mlnx-en$|mlnx-nfsrdma|mlnx-nvme|mlnx-rdma-rxe/) and $kmp) {
        if ($DISTRO =~ /RHEL5|XenServer/ and $target_cpu eq "i386") {
            $arch = 'i686';
        }

        my $krpm = '';
        my $kver = '';
        if ($DISTRO =~ /SLES/) {
            $krpm = `$RPM -qf /lib/modules/$kernel 2> /dev/null | grep kernel | head -1`;
            chomp $krpm;
            $kver =`$RPM -q --queryformat "[%{VERSION}]\n" $krpm 2> /dev/null | head -1`;
            chomp $kver;
            if ($name =~ /kmp/ and $kver !~ /$kernel_rel/) {
                return;
            }

        }

        $cmd = "$RPM $rpminstall_parameter -vh $rpminstall_flags";
        $cmd .= " --nodeps";
        $cmd .= " -F" if ($update);
        $cmd .= " '$main_packages{$name}{$ver}{'rpmpath'}'";

        # KMP packages that have only kmod/kmp rpms
        if ($name !~ /$bf_krpm_regex|kernel-mft-mlnx|iser|srp|mlnx-en|mlnx-nfsrdma|mlnx-nvme|mlnx-rdma-rxe/) {
            print_and_log("Installing $name RPM\n", $verbose);
            print_and_log("Running $cmd\n", $verbose2);
            system("$cmd 1> $ofedlogs/$name-$ver.rpminstall.log 2> $ofedlogs/$name-$ver.rpminstall.err.log");
            $res = $? >> 8;
            $sig = $? & 127;
            if ($sig or $res) {
                print_and_log_colored("Failed to install $name $ver RPM", 1, "RED");
                addSetupInfo ("$ofedlogs/$name-$ver.rpminstall.err.log");
                print_and_log_colored("See $ofedlogs/$name-$ver.rpminstall.err.log", 1, "RED");
                exit $ERROR;
            }
            system("cat $ofedlogs/$name-$ver.rpminstall.log") if (not $quiet);
            system("/sbin/depmod $kernel > /dev/null 2>&1");

            if ($name =~ /mlnx-ofa_kernel-(devel|source)/) {
                if (exists $package_post_install_script{$name}) {
                    print_and_log("Running $name post install script: $package_post_install_script{$name}\n", $verbose);
                    ex("$package_post_install_script{$name}");
                }
                return;
            }
        }

        my @kmp_packages;
        if ($DISTRO =~ /SLES|SUSE/) {
            @kmp_packages = <$RPMS/$name-kmp*.$rpm_distro.$arch.rpm>;
        } else {
            @kmp_packages = <$RPMS/kmod*$name-*.$rpm_distro.$arch.rpm>;
        }
        if (not @kmp_packages) {
            print_and_log_colored("$name KMP rpms do not exist", 1, "RED");
            exit $ERROR;
        }

        # Install kernel-mft-mlnx-utils when available - relevant only when KMP=1
        if ($name =~ /kernel-mft-mlnx/) {
            my @mft_utils = <$RPMS/$name-utils*.$rpm_distro.$arch.rpm>;
            if (@mft_utils) {
                push(@kmp_packages, $mft_utils[0]);
            }
        }

        for my $kmp_package (@kmp_packages) {
            $cmd = "$RPM $rpminstall_parameter -vh $rpminstall_flags";
            $cmd .= " --nodeps";
            $cmd .= " -F" if ($update);
            if ($speed_up_kmp) {
                $cmd .= " --nopost";
                system("$RPM -qpl '$kmp_package' | grep '\\.ko\$' >> $modules_list");
            }
            $cmd .= " '$kmp_package'";

            my $kmpname =`$RPM -qp --queryformat "[%{NAME}]\n" '$kmp_package' 2>/dev/null`;
            chomp $kmpname;
            print_and_log("Installing $kmpname $ver RPM\n", $verbose);
            print_and_log("Running $cmd\n", $verbose2);
            system("$cmd 1> $ofedlogs/$kmpname-$ver.rpminstall.log 2> $ofedlogs/$kmpname-$ver.rpminstall.err.log");
            $res = $? >> 8;
            $sig = $? & 127;
            if ($sig or $res) {
                print_and_log_colored("Failed to install $name $ver RPM", 1, "RED");
                addSetupInfo ("$ofedlogs/$kmpname-$ver.rpminstall.log");
                print_and_log_colored("See $ofedlogs/$kmpname-$ver.rpminstall.log", 1, "RED");
                exit $ERROR;
            }
            system("grep -v Updating $ofedlogs/$kmpname-$ver.rpminstall.log | head -2") if (not $quiet);

            if (exists $package_post_install_script{$kmpname}) {
                print_and_log("Running $kmpname post install script: $package_post_install_script{$kmpname}\n", $verbose);
                ex("$package_post_install_script{$kmpname}");
            }
        }
        system("/sbin/depmod $kernel > /dev/null 2>&1");
        return;
    }

    if ($DISTRO =~ /CTYUNOS/) {
        $release = "$release.ctl2";
    }

    if ((
          $name =~ /mlnx-ofa_kernel/ and not (
            ($name eq "mlnx-ofa_kernel-devel" and not $kmp) or
            ($name eq "mlnx-ofa_kernel-modules")
          )
        ) or
        ($name =~ /mlnx-en/) or
        (($name eq 'xpmem') or ($name =~ /libxpmem/)) or
        ($name =~ /knem/ and $name ne "knem-modules")) {
        $release = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'release'};
    }
    if ($name eq "xpmem-modules") {
        $release =~ s/\.kver/.$rpm_distro.kver/;
    }

    if ($name =~ /mlnx-ofa_kernel/ and $DISTRO =~ /RHEL5|XenServer/ and $target_cpu eq "i386") {
        $arch = 'i686';
    }
    my $package = "$RPMS/$name-$version-$release.$arch.rpm";

    if (not -e $package) {
        my $rpmrel_nodist = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'release'};
        $rpmrel_nodist =~ s/\.$rpm_distro$//g;
        if (-e "$RPMS/$name-$version-$kernel_rel.$arch.rpm") {
            $package = "$RPMS/$name-$version-$kernel_rel.$arch.rpm";
        } elsif (-e "$RPMS/$name-$version-${kernel_rel}_$rpmrel_nodist.$arch.rpm") {
            $package = "$RPMS/$name-$version-${kernel_rel}_$rpmrel_nodist.$arch.rpm";
        } else {
            print_and_log_colored("$package does not exist", 1, "RED");
            exit $ERROR;
        }
    }

    $cmd = "$RPM $rpminstall_parameter -vh $rpminstall_flags";
    if ($name =~ /mlnx-ofa_kernel/ and $DISTRO =~ /BLUENIX1/) {
        # W/A for python(abi) dependency on Mellanox Bluenix
        $cmd .= " --nodeps";
    }
    if ($DISTRO =~ m/SLES|SUSE|XenServer/) {
        # W/A for ksym dependencies on SLES, XenServer
        $cmd .= " --nodeps";
    }
    $cmd .= " -F" if ($update);
    $cmd .= " '$package'";

    my $no_verify = ($update and not is_installed("$name-$version"));
    print_and_log("Installing $name $ver RPM\n", $verbose);
    print_and_log("Running $cmd\n", $verbose2);
    system("$cmd >> $ofedlogs/$name-$ver.rpminstall.log 2>&1");
    $res = $? >> 8;
    $sig = $? & 127;
    if ($sig or $res) {
        print_and_log_colored("Failed to install $name $ver RPM", 1, "RED");
        addSetupInfo ("$ofedlogs/$name-$ver.rpminstall.log");
        print_and_log_colored("See $ofedlogs/$name-$ver.rpminstall.log", 1, "RED");
        exit $ERROR;
    }
    system("cat $ofedlogs/$name-$ver.rpminstall.log") if (not $quiet);

    if ($verify and not $no_verify) {
        install_verify("$name-$version", "$ofedlogs/$name-$ver.rpminstall.log");
    }

    if (exists $package_post_install_script{$name}) {
        print_and_log("Running $name post install script: $package_post_install_script{$name}\n", $verbose);
        ex("$package_post_install_script{$name}");
    }

}

sub install_rpm ($) {
    my $binrpm = shift;
    my $cmd;
    my $res;
    my $sig;

    $cmd = "$RPM $rpminstall_parameter -vh $rpminstall_flags";
    $cmd .= " --force";
    $cmd .= " --nodeps";

    my ($rpm_name, $rpm_arch) = (split ' ', get_rpm_name_arch($binrpm));

    my $binrpm_rel_ver = is_installed($rpm_name . '-' . get_rpm_ver($binrpm) . '-' . get_rpm_rel($binrpm));
    if (is_installed($binrpm_rel_ver)) {
        $cmd .= " -F";
    }

    if ($rpm_name =~ /ibacm/) {
        $cmd .= " --noscripts";
    }

    $cmd .= " '$binrpm'";

    if (exists $package_pre_install_script{$rpm_name}) {
        print_and_log("Running $rpm_name pre install script: $package_pre_install_script{$rpm_name}\n", $verbose);
        ex("$package_pre_install_script{$rpm_name}");
    }

    print_and_log("$cmd\n", $verbose2);
    system("$cmd > $ofedlogs/$rpm_name.$rpm_arch.rpminstall.log 2>&1");
    $res = $? >> 8;
    $sig = $? & 127;
    if ($sig or $res) {
        print_and_log_colored("Failed to install $rpm_name RPM", 1, "RED");
        addSetupInfo ("$ofedlogs/$rpm_name.$rpm_arch.rpminstall.log");
        print_and_log_colored("See $ofedlogs/$rpm_name.$rpm_arch.rpminstall.log", 1, "RED");
        exit $ERROR;
    }

    if (not $quiet) {
        if ($verbose2) {
            system("cat $ofedlogs/$rpm_name.$rpm_arch.rpminstall.log") if (not $quiet);
        } else {
            system("grep -v Updating $ofedlogs/$rpm_name.$rpm_arch.rpminstall.log | head -2") if (not $quiet);
        }
    }

    # Add command line to the log file
    open (LOG, ">>$ofedlogs/$rpm_name.$rpm_arch.rpminstall.log");
    print LOG "Executed command: $cmd\n";
    close LOG;

    if (exists $package_post_install_script{$rpm_name}) {
        print_and_log("Running $rpm_name post install script: $package_post_install_script{$rpm_name}\n", $verbose);
        ex("$package_post_install_script{$rpm_name}");
    }
}

# Run RPM install command
sub install_rpms
{
    my $cmd;
    my $res = 0;
    my $sig = 0;

    print_and_log("Installing user level RPMs:\n", (not $quiet));
    foreach my $binrpm (@rpms_to_install) {
        install_rpm($binrpm);
    }

    if ($verify) {
        foreach my $binrpm (@rpms_to_install) {
            my $package = get_rpm_name_ver_rel_arch($binrpm);
            install_verify("$package", "$ofedlogs/mlnxofed.rpminstall.log");
        }
    }
}

sub install_rpm_32
{
    my $name = shift @_;
    my $ver = shift @_;
    my $dir;
    my $package;

    my $version = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'version'};
    my $release = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'release'};

    $package = "$RPMS/$name-$version-$release.$target_cpu32.rpm";

    if (not -e $package) {
        print_and_log_colored("$package $ver does not exist", 1, "RED");
        return;
    }

    if ($DISTRO =~ m/SLES|SUSE/) {
        $force_rpm_install = 1;
    }
    push @rpms_to_install, $package;

}

# Install required RPM
sub mark_rpm_required
{
    my $name = shift @_;
    my $ver = shift @_;
    my $dir;
    my $package;

    my $version = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'version'};
    my $release = $main_packages{$packages_info{$name}{'parent'}}{$ver}{'release'};
    my $arch = $target_cpu;
    if ($packages_info{$name}{$ver}{'is_noarch'}) {
        $arch = 'noarch';
    }
    if ($name =~ /mlnxofed-docs|bfscripts/) {
        $package = "$RPMS/$name-$version-$release.noarch.rpm";
    }
    elsif ($name eq 'mft' and $target_cpu =~ /i[0-9]86/) {
        $package = "$RPMS/$name-$version-$release.x86.rpm";
    }
    elsif ($name eq 'mft' and $target_cpu =~ /ppc64/) {
        $package = $main_packages{$name}{$ver}{'rpmpath'};
    }
    elsif ($name eq 'mft' and $target_cpu =~ /arm|aarch/) {
        $package = "$RPMS/$name-$version-$release.arm64.rpm";
    }
    elsif ($name eq 'mft-oem' and $target_cpu =~ /arm|aarch/) {
        $package = "$RPMS/$name-$version-$release.arm64.rpm";
    }
    else {
        $package = "$RPMS/$name-$version-$release.$arch.rpm";
    }

    if (not -e $package) {
        print_and_log_colored("$package $ver does not exist", 1, "RED");
        exit $ERROR;
    }

    if ($packages_info{$name}{'userspace_install_early'}) {
        print_and_log("Install userspace package now and not after kernel packages: $name\n", $verbose2);
        install_rpm($package);

        return;
    }

    push @rpms_to_install, $package;

    if ($install32 and $packages_info{$name}{'install32'}) {
        if (not $packages_info{$name}{$ver}{'rpm_exist32'}) {
            print_and_log_colored("$name $ver 32bit rpm was not created for this platform.", 1, "RED");
        } else {
            install_rpm_32($name, $ver);
        }
    }
}

sub print_package_info
{
    print_and_log("\n\nDate:" . localtime(time) . "\n", 1);
    for my $key ( keys %main_packages ) {
        print_and_log("$key:\n", 1);
        print_and_log("======================================\n", 1);
        for my $ver ( keys %{$main_packages{$key}} ) {
            print_and_log("-------------------------------\n", 1);
            my %pack = %{$main_packages{$key}{$ver}};
            for my $subkey ( keys %pack ) {
                print_and_log($subkey . ' = ' . $pack{$subkey} . "\n", 1);
            }
        }
        print_and_log("\n", 1);
    }
}

sub is_installed
{
    my $res = 0;
    my $name = shift @_;

    system("$RPM -q $name > /dev/null 2>&1");
    $res = $? >> 8;

    return not $res;
}

sub count_ports
{
    my $cnt = 0;
    open(LSPCI, "/sbin/lspci -n|");

    while (<LSPCI>) {
        if (/15b3:5e8c|15b3:6274/) {
            $cnt ++;    # InfiniHost III Lx mode
        }
        elsif (/15b3/) {
            $cnt += 2;
        }
    }
    close (LSPCI);

    return $cnt;
}

sub is_valid_ipv4
{
    my $ipaddr = shift @_;

    if( $ipaddr =~ m/^(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)/ ) {
        if($1 <= 255 && $2 <= 255 && $3 <= 255 && $4 <= 255) {
            return 0;
        }
    }
    return 1;
}

sub is_carrier
{
    my $ifcheck = shift @_;
    open(IFSTATUS, "ip link show dev $ifcheck |");
    while ( <IFSTATUS> ) {
        next unless m@(\s$ifcheck).*@;
        if( m/NO-CARRIER/ or not m/UP/ ) {
            close(IFSTATUS);
            return 0;
        }
    }
    close(IFSTATUS);
    return 1;
}

sub config_interface
{
    my $interface = shift @_;
    my $ans;
    my $dev = "ib$interface";
    my $target = "$network_dir/ifcfg-$dev";
    my $ret;
    my $ip;
    my $nm;
    my $nw;
    my $bc;
    my $onboot = 1;
    my $found_eth_up = 0;

    if ($interactive) {
        print "\nDo you want to configure $dev? [Y/n]:";
        $ans = getch();
        if ($ans =~ m/[nN]/) {
            return;
        }
        if (-e $target) {
            print "\nThe current IPoIB configuration for $dev is:\n";
            open(IF,$target);
            while (<IF>) {
                print $_;
            }
            close(IF);
            print "\nDo you want to change this configuration? [y/N]:";
            $ans = getch();
            if ($ans !~ m/[yY]/) {
                return;
            }
        }
        print "\nEnter an IP Adress: ";
        $ip = <STDIN>;
        chomp $ip;
        $ret = is_valid_ipv4($ip);
        while ($ret) {
            print "\nEnter a valid IPv4 Adress: ";
            $ip = <STDIN>;
            chomp $ip;
            $ret = is_valid_ipv4($ip);
        }
        print "\nEnter the Netmask: ";
        $nm = <STDIN>;
        chomp $nm;
        $ret = is_valid_ipv4($nm);
        while ($ret) {
            print "\nEnter a valid Netmask: ";
            $nm = <STDIN>;
            chomp $nm;
            $ret = is_valid_ipv4($nm);
        }
        print "\nEnter the Network: ";
        $nw = <STDIN>;
        chomp $nw;
        $ret = is_valid_ipv4($nw);
        while ($ret) {
            print "\nEnter a valid Network: ";
            $nw = <STDIN>;
            chomp $nw;
            $ret = is_valid_ipv4($nw);
        }
        print "\nEnter the Broadcast Adress: ";
        $bc = <STDIN>;
        chomp $bc;
        $ret = is_valid_ipv4($bc);
        while ($ret) {
            print "\nEnter a valid Broadcast Adress: ";
            $bc = <STDIN>;
            chomp $bc;
            $ret = is_valid_ipv4($bc);
        }
        print "\nStart Device On Boot? [Y/n]:";
        $ans = getch();
        if ($ans =~ m/[nN]/) {
            $onboot = 0;
        }

        print GREEN "\nSelected configuration:\n";
        print "DEVICE=$dev\n";
        print "IPADDR=$ip\n";
        print "NETMASK=$nm\n";
        print "NETWORK=$nw\n";
        print "BROADCAST=$bc\n";
        if ($DISTRO =~ /RHEL6|RHEL7|POWERKVM|EULEROS2.0SP[235]|BCLINUX7|ALIOS/) {
            print "NM_CONTROLLED=yes\n";
            print "TYPE=InfiniBand\n";
        }
        if ($onboot) {
            print "ONBOOT=yes\n";
        }
        else {
            print "ONBOOT=no\n";
        }
        print "\nDo you want to save the selected configuration? [Y/n]:";
        $ans = getch();
        if ($ans =~ m/[nN]/) {
            return;
        }
    }
    else {
        if (not $config_net_given) {
            return;
        }
        print "Going to update $target\n" if ($verbose2);
        if ($ifcfg{$dev}{'LAN_INTERFACE'}) {
            $eth_dev = $ifcfg{$dev}{'LAN_INTERFACE'};
            if (not -e "/sys/class/net/$eth_dev") {
                print "Device $eth_dev is not present\n" if (not $quiet);
                return;
            }
            if ( is_carrier ($eth_dev) ) {
                $found_eth_up = 1;
            }
        }
        else {
            # Take the first existing Eth interface
            my @eth_devs = </sys/class/net/eth*>;
            for my $tmp_dev ( @eth_devs ) {
                $eth_dev = $tmp_dev;
                $eth_dev =~ s@/sys/class/net/@@g;
                if ( is_carrier ($eth_dev) ) {
                    $found_eth_up = 1;
                    last;
                }
            }
        }

        if ($found_eth_up) {
            get_net_config($eth_dev, \%ifcfg, $DISTRO);
        }

        if (not $ifcfg{$dev}{'IPADDR'}) {
            print "IP address is not defined for $dev\n" if ($verbose2);
            print "Skipping $dev configuration...\n" if ($verbose2);
            return;
        }
        if (not $ifcfg{$dev}{'NETMASK'}) {
            print "Netmask is not defined for $dev\n" if ($verbose2);
            print "Skipping $dev configuration...\n" if ($verbose2);
            return;
        }
        if (not $ifcfg{$dev}{'NETWORK'}) {
            print "Network is not defined for $dev\n" if ($verbose2);
            print "Skipping $dev configuration...\n" if ($verbose2);
            return;
        }
        if (not $ifcfg{$dev}{'BROADCAST'}) {
            print "Broadcast address is not defined for $dev\n" if ($verbose2);
            print "Skipping $dev configuration...\n" if ($verbose2);
            return;
        }

        my @ipib = (split('\.', $ifcfg{$dev}{'IPADDR'}));
        my @nmib = (split('\.', $ifcfg{$dev}{'NETMASK'}));
        my @nwib = (split('\.', $ifcfg{$dev}{'NETWORK'}));
        my @bcib = (split('\.', $ifcfg{$dev}{'BROADCAST'}));

        my @ipeth = (split('\.', $ifcfg{$eth_dev}{'IPADDR'}));
        my @nmeth = (split('\.', $ifcfg{$eth_dev}{'NETMASK'}));
        my @nweth = (split('\.', $ifcfg{$eth_dev}{'NETWORK'}));
        my @bceth = (split('\.', $ifcfg{$eth_dev}{'BROADCAST'}));

        for (my $i = 0; $i < 4 ; $i ++) {
            if ($ipib[$i] =~ m/\*/) {
                if ($ipeth[$i] =~ m/(\d\d?\d?)/) {
                    $ipib[$i] = $ipeth[$i];
                }
                else {
                    print "Cannot determine the IP address of the $dev interface\n" if (not $quiet);
                    return;
                }
            }
            if ($nmib[$i] =~ m/\*/) {
                if ($nmeth[$i] =~ m/(\d\d?\d?)/) {
                    $nmib[$i] = $nmeth[$i];
                }
                else {
                    print "Cannot determine the netmask of the $dev interface\n" if (not $quiet);
                    return;
                }
            }
            if ($bcib[$i] =~ m/\*/) {
                if ($bceth[$i] =~ m/(\d\d?\d?)/) {
                    $bcib[$i] = $bceth[$i];
                }
                else {
                    print "Cannot determine the broadcast address of the $dev interface\n" if (not $quiet);
                    return;
                }
            }
            if ($nwib[$i] !~ m/(\d\d?\d?)/) {
                $nwib[$i] = $nweth[$i];
            }
        }

        $ip = "$ipib[0].$ipib[1].$ipib[2].$ipib[3]";
        $nm = "$nmib[0].$nmib[1].$nmib[2].$nmib[3]";
        $nw = "$nwib[0].$nwib[1].$nwib[2].$nwib[3]";
        $bc = "$bcib[0].$bcib[1].$bcib[2].$bcib[3]";

        print GREEN "IPoIB configuration for $dev\n";
        print "DEVICE=$dev\n";
        print "IPADDR=$ip\n";
        print "NETMASK=$nm\n";
        print "NETWORK=$nw\n";
        print "BROADCAST=$bc\n";
        if ($onboot) {
            print "ONBOOT=yes\n";
        }
        else {
            print "ONBOOT=no\n";
        }
        print RESET "\n";
    }

    open(IF, ">$target") or die "Can't open $target: $!";
    if ($DISTRO =~ m/SLES|SUSE/) {
        print IF "BOOTPROTO='static'\n";
        print IF "IPADDR='$ip'\n";
        print IF "NETMASK='$nm'\n";
        print IF "NETWORK='$nw'\n";
        print IF "BROADCAST='$bc'\n";
        print IF "REMOTE_IPADDR=''\n";
        if ($onboot) {
            print IF "STARTMODE='onboot'\n";
        }
        else {
            print IF "STARTMODE='manual'\n";
        }
        print IF "WIRELESS=''\n";
    }
    else {
        print IF "DEVICE=$dev\n";
        print IF "BOOTPROTO=static\n";
        print IF "IPADDR=$ip\n";
        print IF "NETMASK=$nm\n";
        print IF "NETWORK=$nw\n";
        print IF "BROADCAST=$bc\n";
        if ($DISTRO =~ /RHEL6|RHEL7|POWERKVM|EULEROS2.0SP[235]|BCLINUX7|ALIOS/) {
            print IF "NM_CONTROLLED=yes\n";
            print IF "TYPE=InfiniBand\n";
        }
        if ($onboot) {
            print IF "ONBOOT=yes\n";
        }
        else {
            print IF "ONBOOT=no\n";
        }
    }
    close(IF);
}

sub ipoib_config
{
    if ($interactive) {
        print "\nThe default IPoIB interface configuration is based on DHCP.";
        print "\nNote that a special patch for DHCP is required for supporting IPoIB.";
        print "\nThe patch is available under docs/dhcp";
        print "\nIf you do not have DHCP, you must change this configuration in the following steps.\n";
    }

    my $ports_num = count_ports();
    for (my $i = 0; $i < $ports_num; $i++ ) {
        config_interface($i);
    }

    if ($interactive) {
        print GREEN "IPoIB interfaces configured successfully",RESET "\n";
        print "Press any key to continue ...";
        getch();
    }

    if ( -e "/etc/sysconfig/network/config") {
        my $nm = `grep ^NETWORKMANAGER=yes /etc/sysconfig/network/config`;
        chomp $nm;
        if ($nm) {
            print RED "Please set NETWORKMANAGER=no in the /etc/sysconfig/network/config", RESET "\n";
        }
    }

}

sub is_included($) {
    my $package = shift;
    return exists $main_packages{$package};
}

sub get_uninstall_env_str() {
    my $components_str = 'MLNX_OFED_COMPONENTS="'. join(" ", @components) . '"';
    my $keep_packages_regex = 'openvswitch';
    if (not is_included('spdk')) {
        $keep_packages_regex .= '|spdk';
    }
    my $keep_packages_str = "MLNX_OFED_KEEP_PACKAGES_REGEX=\"$keep_packages_regex\"";
    return "$components_str $keep_packages_str";
}
sub uninstall_mlnx_en
{
    my $res = 0;
    my $sig = 0;
    my $cnt = 0;

    if ( -e "/sbin/mlnx_en_uninstall.sh" ) {
        print_and_log("Uninstalling MLNX_EN driver\n", (not $quiet));
        my $env_str = get_uninstall_env_str();
        system("yes | $env_str /sbin/mlnx_en_uninstall.sh > $ofedlogs/mlnx_en_uninstall.log 2>&1");
        $res = $? >> 8;
        $sig = $? & 127;
        if ($sig or $res) {
            print_and_log_colored("Failed to uninstall MLNX_EN driver", 1, "RED");
            addSetupInfo ("$ofedlogs/mlnx_en_uninstall.log");
            print_and_log_colored("See $ofedlogs/mlnx_en_uninstall.log", 1, "RED");
            exit $ERROR;
        }
    }

    my $mlnx_en_cnt = 0;
    my $mlnx_en_rpms;
    my @other_mlnx_en_rpms = `$RPM -qa --queryformat "[%{NAME}]\n" 2> /dev/null | grep -E 'mlnx.en|mlx.*en' | grep -v '^kernel-module'`;
    for my $package (@mlnx_en_packages, @other_mlnx_en_rpms) {
        chomp $package;
        if ((is_installed $package) and $components_filter->($package)) {
            $mlnx_en_rpms .= " $package";
            $mlnx_en_cnt ++;
        }
    }

    if ($mlnx_en_cnt) {
            my $cmd = "$RPM -e --allmatches --nodeps";
            $cmd .= " $mlnx_en_rpms";
            print_and_log("Uninstalling MLNX_EN driver\n", (not $quiet));
            system("$cmd >> $ofedlogs/mlnx_en_uninstall.log 2>&1");
            $res = $? >> 8;
            $sig = $? & 127;
            if ($sig or $res) {
                print_and_log_colored("Failed to uninstall MLNX_EN driver", 1, "RED");
                addSetupInfo ("$ofedlogs/mlnx_en_uninstall.log");
                print_and_log_colored("See $ofedlogs/mlnx_en_uninstall.log", 1, "RED");
                exit $ERROR;
            }
    }

}

sub uninstall_mft
{
    my $res = 0;
    my $sig = 0;
    my $cnt = 0;

    return if ($is_mlnx_en);

    my $mft_rpms;
    for my $package (@mft_packages) {
        chomp $package;
        if (is_installed($package)) {
            $mft_rpms .= " $package";
            if (not $selected_for_uninstall{$package}) {
                push (@packages_to_uninstall, $package);
                $selected_for_uninstall{$package} = 1;
            }
        }
    }

    if (open (KMP_RPMS, "$RPM -qa --queryformat \"[%{NAME}]\n\" *kernel-mft* 2>/dev/null | grep kernel-mft |")) {
        my $kmp_cnt = 0;
        my $kmp_rpms;
        while(<KMP_RPMS>) {
            chomp $_;
            $kmp_rpms .= " $_";
            $kmp_cnt ++;
        }
        close KMP_RPMS;

	    if ($kmp_cnt) {
            system("$RPM -e --allmatches --nodeps $kmp_rpms >> $ofedlogs/kmp_rpms_uninstall.log 2>&1");
            $res = $? >> 8;
            $sig = $? & 127;
            if ($sig or $res) {
                print_and_log_colored("Failed to uninstall kernel-mft-mlnx KMP RPMs", 1, "RED");
                exit $ERROR;
            }
        }
    }
}

# Try to remove a package, if failed, retry with adding --noscripts flag
# Use it as W/A for known possible problematic packages
sub remove_od_noscripts
{
    my $pname = shift;

    return unless (is_installed($pname));
    my $cmd = "$RPM -e --allmatches --nodeps $pname";
    print_and_log("\n$cmd\n", (not $quiet));
    open (LOG, "+>$ofedlogs/ofed_uninstall.log");
    print LOG "$cmd\n";
    close LOG;
    system("$cmd >> $ofedlogs/ofed_uninstall.log 2>&1");
    my $res = $? >> 8;
    my $sig = $? & 127;
    if ($sig or $res) {
        $cmd = "rpm -e --allmatches --nodeps --noscripts $pname";
        print_and_log("\n$cmd\n", (not $quiet));
        system("$cmd >> $ofedlogs/ofed_uninstall.log 2>&1");
        $res = $? >> 8;
        $sig = $? & 127;
        if ($sig or $res) {
            print_and_log_colored("Failed to uninstall $pname", 1, "RED");
            addSetupInfo ("$ofedlogs/ofed_uninstall.log");
            print_and_log_colored("See $ofedlogs/ofed_uninstall.log", 1, "RED");
            exit $ERROR;
        }
    }
}

sub force_uninstall
{
    my $res = 0;
    my $sig = 0;
    my $cnt = 0;
    my @other_ofed_rpms = `$RPM -qa --queryformat "[%{NAME}]\n" 2> /dev/null | grep -wE "rdma|ofed|openib" | grep -vEw "glusterfs|kernel-module|^xen|ovsvf-config|opensmtpd"`;
    my $cmd = "$RPM -e --allmatches --nodeps";

    my @to_remove_packages = (@all_packages, @hidden_packages, @prev_ofed_packages, @other_ofed_rpms, @distro_ofed_packages, @dpdk_packages);
    if (not is_included('spdk')) {
        @to_remove_packages = grep !/^spdk/, @to_remove_packages;
    }
    for my $package (@to_remove_packages) {
        chomp $package;
        next if ($is_mlnx_en and $package =~ /mft/);
        next if ($is_mlnx_en and $package !~ /$mlnx_en_pkgs/);
        next if ($package eq "mpi-selector" or $package =~ /^kernel-module|glusterfs|^xen|ovsvf-config|opensmtpd/);
        if (is_installed($package)) {
            push (@packages_to_uninstall, $package);
            $selected_for_uninstall{$package} = 1;
        }
        if (is_installed("$package-static")) {
            push (@packages_to_uninstall, "$package-static");
            $selected_for_uninstall{$package} = 1;
        }
        if ($suffix_32bit and is_installed("$package$suffix_32bit")) {
            push (@packages_to_uninstall,"$package$suffix_32bit");
            $selected_for_uninstall{$package} = 1;
        }
        if ($suffix_64bit and is_installed("$package$suffix_64bit")) {
            push (@packages_to_uninstall,"$package$suffix_64bit");
            $selected_for_uninstall{$package} = 1;
        }
    }

    for my $package (@packages_to_uninstall) {
        get_requires($package);
    }

    if (not $force and keys %non_ofed_for_uninstall) {
        print_and_log("\nError: One or more packages depends on $PACKAGE.\nThose packages should be removed before uninstalling $PACKAGE:\n\n", 1);
        print_and_log(join(" ", (keys %non_ofed_for_uninstall)) . "\n\n", 1);
        print_and_log("To force uninstallation use '--force' flag.\n", 1);
        exit $NONOFEDRPMS;
    }

    for my $package (@packages_to_uninstall, @dependant_packages_to_uninstall) {
        if ("$package" eq "ofed" and is_installed("ofed")) {
            # W/A for SLES 10 SP4 in-box ofed RPM uninstall issue
            remove_od_noscripts("ofed");
            next;
        }
        if (is_installed($package) and $components_filter->($package)) {
            $cmd .= " $package";
            $cnt ++;
        }
    }

    if ($cnt) {
        print_and_log("\n$cmd\n", (not $quiet));
        open (LOG, "+>$ofedlogs/ofed_uninstall.log");
        print LOG "$cmd\n";
        close LOG;
        system("$cmd >> $ofedlogs/ofed_uninstall.log 2>&1");
        $res = $? >> 8;
        $sig = $? & 127;
        if ($sig or $res) {
            print_and_log_colored("Failed to uninstall the previous installation", 1, "RED");
            addSetupInfo ("$ofedlogs/ofed_uninstall.log");
            print_and_log_colored("See $ofedlogs/ofed_uninstall.log", 1, "RED");
            exit $ERROR;
        }
    }
}

# if we install the drivers without KMP support, and then installed a new kernel
# it might still create weak-updates symlinks to our modules, and once we remove
# our rpms, no one will remove those links since our rpms do not know to run
# the systems tools that are responsible for removing the links.
# Note: if we have ofed kmp rpms installed, then we don't need to do anything here.
sub remove_weak_updates_symlinks
{
    my $ofed_kpkgs = "";
    my $got_kmps = 0;

    if ($DISTRO !~ /RHEL | ^OL/x) {
        return;
    }

    # get list of installed packages
    for my $package (qw(srp iser ofa_kernel knem ummunotify mlnx-sdp mlnx-rds mlnx-nfsrdma mlnx-nvme mlnx-rdma-rxe kernel-mft gpio-mlxbf i2c-mlx mlxbf-livefish mlx-bootctl pka-mlxbf tmfifo mlxbf-gige mlx-trio gpio-mlxbf2 mlx-pmc)) {
        my $regEx = "*$package*";
        if (open (OFED_KRPMS, "$RPM -qa --queryformat \"[%{NAME}]\n\" $regEx | grep -E $regEx |")) {
            while(<OFED_KRPMS>) {
                chomp $_;
                if ($_ =~ /kmp|kmod/) {
                    $got_kmps = 1;
                    last;
                }
                $ofed_kpkgs .= " $_";
            }
            close OFED_KRPMS;
            if ($got_kmps) {
                last;
            }
        }
    }
    if ($got_kmps or $ofed_kpkgs eq "") {
        return;
    }

    # get list of KO files
    my $tmpfile = "/var/run/rpm_ofed_kernel_modules";
    system("rpm -ql $ofed_kpkgs | grep '\.ko\$' > $tmpfile");
    if (-z $tmpfile) {
        system("/bin/rm -f $tmpfile >/dev/null 2>&1");
        return;
    }

    # remove existing symlinks
    my $wm_tool = "/sbin/weak-modules";
    if (-e "$wm_tool") {
        system("cat $tmpfile | $wm_tool --remove-modules --no-initramfs --delete-modules >/dev/null 2>&1");
    }

    system("/bin/rm -f $tmpfile >/dev/null 2>&1");
}

sub uninstall
{
    my $res = 0;
    my $sig = 0;
    my $distro_rpms = '';

    return 0 if (not $uninstall);

    if ($install_option eq 'eth-only') {
        $mlnx_en_pkgs = $mlnx_en_only_pkgs;
    } else {
        $mlnx_en_pkgs = $mlnx_en_rdma_pkgs;
    }

    remove_weak_updates_symlinks();

    uninstall_mlnx_en();

    uninstall_mft();

    my $ofed_uninstall = `which ofed_uninstall.sh 2> /dev/null`;
    chomp $ofed_uninstall;
    if (-e "$ofed_uninstall") {
        print_and_log("Uninstalling the previous version of $PACKAGE\n", (not $quiet));
        my $uninstall_flags = "";
        if ($force) {
            $uninstall_flags .= " --force";
        }
        if (`$ofed_uninstall --help 2>/dev/null | grep -- keep-mft 2>/dev/null` ne "") {
            $uninstall_flags .= " --keep-mft";
        }

        # W/A for bad releases
        if (is_installed("neohost-backend")) {
            system("rpm -e neohost-backend neohost-sdk >> $ofedlogs/ofed_uninstall.log 2>&1");
        }
        if (is_installed("infiniband-diags")) {
            system("rpm -e --nodeps infiniband-diags >> $ofedlogs/ofed_uninstall.log 2>&1");
        }

        my $env_str = get_uninstall_env_str();
        print_and_log("Running: $env_str ofed_uninstall.sh $uninstall_flags", $verbose2);
        system("yes | $env_str ofed_uninstall.sh $uninstall_flags >> $ofedlogs/ofed_uninstall.log 2>&1");
        $res = $? >> 8;
        $sig = $? & 127;
        if ($sig or $res) {
            if ($res == 174) {
                print_and_log("Error: One or more packages depends on $PACKAGE.\nThese packages should be removed before uninstalling $PACKAGE:\n", 1);
                system("cat $ofedlogs/ofed_uninstall.log | perl -ne '/Those packages should be/ && do {\$a=1; next}; /To force uninstallation use/ && do {\$a=0}; print if \$a'");
                print_and_log("To force uninstallation use '--force' flag.\n", 1);
                addSetupInfo ("$ofedlogs/ofed_uninstall.log");
                print_and_log_colored("See $ofedlogs/ofed_uninstall.log", 1, "RED");
                exit $NONOFEDRPMS;
            }
            print_and_log_colored("Failed to uninstall the previous installation", 1, "RED");
            addSetupInfo ("$ofedlogs/ofed_uninstall.log");
            print_and_log_colored("See $ofedlogs/ofed_uninstall.log", 1, "RED");
            exit $ERROR;
        }
    }

    # Uninstall leftovers and previous OFED packages
    force_uninstall();

    # uninstall KMP packages
    for my $package (qw(srp iser isert ofa_kernel knem xpmem ummunotify mlnx-sdp mlnx-rds mlnx-nfsrdma mlnx-nvme mlnx-rdma-rxe gpio-mlxbf i2c-mlx mlxbf-livefish mlx-bootctl pka-mlxbf tmfifo mlxbf-gige mlx-trio gpio-mlxbf2 mlx-pmc)) {
        last if ($user_space_only);
        my $regEx;
        if ($package !~ /$bf_krpm_regex|iser|srp$/) {
            $regEx = "*$package*";
        } else {
            $regEx = "\"kmod-$package*|$package-kmp*\"";
        }
        if (open (KMP_RPMS, "$RPM -qa --queryformat \"[%{NAME}]\n\" $regEx | grep -E $regEx |")) {
            my $kmp_cnt = 0;
            my $kmp_rpms;
            while(<KMP_RPMS>) {
                chomp $_;
                next if ($_ eq "mlnx-ofa_kernel");
                $kmp_rpms .= " $_";
                $kmp_cnt ++;
            }
            close KMP_RPMS;

            if ($kmp_cnt) {
                if ($package eq "ofa_kernel") {
                    remove_od_noscripts("mlnx-ofa_kernel");
                }
                print_and_log("rpm -e --allmatches --nodeps $kmp_rpms\n", $verbose);
                system("$RPM -e --allmatches --nodeps $kmp_rpms >> $ofedlogs/kmp_$package\_rpms_uninstall.log 2>&1");
                $res = $? >> 8;
                $sig = $? & 127;
                if ($sig or $res) {
                    print_and_log_colored("Failed to uninstall $package KMP RPMs", 1, "RED");
                    addSetupInfo ("$ofedlogs/kmp_$package\_rpms_uninstall.log");
                    print_and_log_colored("See $ofedlogs/kmp_$package\_rpms_uninstall.log", 1, "RED");
                    exit $ERROR;
                }
            }
        }
    }

    if ( -d "/lib/modules/$kernel/kernel/drivers/net/mtnic" ) {
        print_and_log("Uninstalling mtnic driver...\n", (not $quiet));
        system("/sbin/rmmod mtnic > /dev/null 2>&1");
        system("/bin/rm -rf /lib/modules/$kernel/kernel/drivers/net/mtnic");
        system("/sbin/depmod $kernel > /dev/null 2>&1");
    }

}

sub install
{
    print_and_log("\nStarting $PACKAGE-$MLNX_OFED_LINUX_VERSION installation ...\n\n", (not $quiet));
    # Install selected RPMs
    for my $package ( @selected_packages ) {
        for my $ver (keys %{$main_packages{$package}}) {
            if ($packages_info{$package}{'mode'} eq "user") {
                if (not $packages_info{$package}{$ver}{'rpm_exist'}) {
                    if ($package =~ m/pgi|intel/) {
                        print_and_log_colored("$package $ver was not created for this platform.", 1, "RED");
                        next;
                    } else {
                        print_and_log_colored("$package $ver was not created", 1, "RED");
                        next;
                    }
                }
                print_and_log("$package $ver added to the list of RPMs\n", $verbose2);
                mark_rpm_required($package, $ver);
            }
            else {
                if (not $packages_info{$package}{$ver}{'rpm_exist'}) {
                        print_and_log_colored("$package $ver was not created", 1, "RED");
                        next;
                }
                print_and_log("$package $ver added to the list of RPMs\n", $verbose2);
                install_kernel_rpm($package, $ver);
            }
        }
    }
    if ($speed_up_kmp) {
        if (-x "/sbin/weak-modules") {
            system("/sbin/depmod $kernel > /dev/null 2>&1");
            system("cat $modules_list | /sbin/weak-modules --add-modules");
            unlink $modules_list;
        }
    }
    install_rpms();
}

sub is_less_then
{
        my $a = shift @_;
        my $b = shift @_;

        my @a = (split('\.', $a));
        my @b = (split('\.', $b));

        if ($a[0] < $b[0]
            or ($a[0] == $b[0] and $a[1] < $b[1])
            or ($a[0] == $b[0] and $a[1] == $b[1] and $a[2] < $b[2])) {
                return 1;
        }
        return 0;
}

sub addSetupInfo
{
    my $log = shift @_;

    print_and_log("Collecting debug info...\n", (not $quiet));

    if (not open (LOG, ">> $log")) {
        print "-E- Can't open $log for appending!\n";
        return;
    }

    print LOG "\n\n\n---------------- START OF DEBUG INFO -------------------\n";
    print LOG "Install command: $CMD\n";

    print LOG "\nVars dump:\n";
    print LOG "- ofedlogs: $ofedlogs\n";
    print LOG "- MLNX_OFED_LINUX_VERSION: $MLNX_OFED_LINUX_VERSION\n";
    print LOG "- MLNX_OFED_ARCH: $MLNX_OFED_ARCH\n";
    print LOG "- MLNX_OFED_DISTRO: $MLNX_OFED_DISTRO\n";
    print LOG "- DISTRO: $DISTRO\n";
    print LOG "- dist_rpm: $dist_rpm\n";
    print LOG "- rpm_distro: $rpm_distro\n";
    print LOG "- arch: $arch\n";
    print LOG "- kernel: $kernel\n";
    print LOG "- kmp: $kmp\n";
    print LOG "- supported_kernels: " . `cat '$supported_kernels'`;
    print LOG "- major_update: $major_update\n";
    print LOG "- major_version: $major_version\n";
    print LOG "- prev_major_version: $prev_major_version\n";
    print LOG "- is_ux: $is_ux\n";
    print LOG "- config: $config\n";
    print LOG "- target_cpu: $target_cpu\n";
    print LOG "- update: $update\n";
    print LOG "- update_firmware: $update_firmware\n";

    print LOG "\nSetup info:\n";
    print LOG "\n- uname -r: " . `uname -r 2>&1`;
    print LOG "\n- uname -m: " . `uname -m 2>&1`;
    print LOG "\n- rpm -qf /etc/issue: " . `rpm -qf /etc/issue 2>&1`;
    print LOG "\n- cat /etc/issue: " . `cat /etc/issue 2>&1`;
    print LOG "\n- rpm -qf /etc/os-release: " . `rpm -qf /etc/os-release 2>&1`;
    print LOG "\n- cat /etc/os-release: " . `cat /etc/os-release 2>&1`;
    print LOG "\n- cat /proc/version: " . `cat /proc/version 2>&1`;
    print LOG "\n- gcc --version: " . `gcc --version 2>&1`;
    print LOG "\n- lspci -n | grep 15b3: " . `lspci -n 2>&1 | grep 15b3`;
    print LOG "\n- rpm -qa: " . `rpm -qa 2>&1`;

    print LOG "---------------- END OF DEBUG INFO -------------------\n";
    close (LOG);
}

sub ex
{
    my $cmd = shift @_;

    system("$cmd 2>&1");
    my $res = $? >> 8;
    my $sig = $? & 127;
    if ($sig or $res) {
        print_and_log_colored("Command execution failed: $cmd", 1, "RED");
        exit 1;
    }
}

sub isKernelSupported
{
    my $m = 0;

    my @supported_kernels = ();
    if ($install_option eq 'eth-only') {
        @supported_kernels = `$RPM -qlp '$RPMS'/mlnx_en*rpm 2>/dev/null | grep lib.modules | awk -F '/' '{print\$4}' | grep -v '^\$' | sort -u`;
    } else {
        @supported_kernels = `$RPM -qlp '$RPMS'/mlnx-ofa_kernel-modules*rpm 2>/dev/null | grep lib.modules | awk -F '/' '{print\$4}' | grep -v '^\$' | sort -u`;
    }
    for my $sk (@supported_kernels) {
        chomp $sk;
        if ($sk eq $kernel) {
            $m = 1;
            last;
        }
    }

    return $m;
}

### MAIN AREA ###
sub main
{
    my $ans;

    if ($print_available) {
        my @list = ();
        set_existing_rpms();
        set_availability();

        if (!$install_option) {
            $install_option = 'all';
        }

        $config = $TMPDIR . "/ofed-$install_option.conf";
        chomp $config;
        if ($install_option eq 'all') {
            @list = (@all_packages);
        }
        elsif ($install_option eq 'bluefield') {
            if ($kernel_only) {
                @list = (@bluefield_kernel_packages);
            } else {
                @list = (@bluefield_user_packages, @bluefield_kernel_packages);
            }
        }
        elsif ($install_option eq 'hpc') {
            @list = (@hpc_user_packages, @hpc_kernel_packages);
        }
        elsif ($install_option =~ m/vma/) {
            if ($install_option eq 'vma') {
                @list = (@vma_user_packages, @vma_kernel_packages);
            } elsif ($install_option eq 'vmavpi') {
                @list = (@vmavpi_user_packages, @vma_kernel_packages);
            } elsif ($install_option eq 'vmaeth') {
                @list = (@vmaeth_user_packages, @vma_kernel_packages);
            }
            @kernel_modules = (@vma_kernel_modules);
        }
        elsif ($install_option =~ m/xlio/) {
            @list = (@xlio_user_packages, @xlio_kernel_packages);
            @kernel_modules = (@xlio_kernel_modules);
        }
        elsif ($install_option eq 'basic') {
            @list = (@basic_user_packages, @basic_kernel_packages);
        }
        elsif ($install_option eq 'msm') {
            @list = (@msm_user_packages, @msm_kernel_packages);
        }
        elsif ($install_option eq 'hypervisor-os') {
            @list = (@hypervisor_user_packages, @hypervisor_kernel_packages);
        }
        elsif ($install_option eq 'guest-os') {
            @list = (@guest_user_packages, @guest_kernel_packages);
        }
        elsif ($install_option eq 'kernel-only') {
            for my $package ( @all_packages ) {
                next if (not $packages_info{$package}{'mode'} eq 'kernel');
                push (@list, $package);
            }
        }
        elsif ($install_option eq 'eth-only') {
            @list = (@eth_user_packages, @eth_kernel_packages);
		}
        elsif ($install_option =~ m/dpdk/) {
            @list = (@dpdk_user_packages, @dpdk_kernel_packages);
        }

        if ($with_bluefield and $install_option ne 'bluefield') {
            for my $package ( @bluefield_user_packages, @bluefield_kernel_packages ) {
                next if (grep /^$package$/, @list);
                next if (not $packages_info{$package}{'available'});
                next if (not is_rpm_available($package));
                next if ($kernel_only and $packages_info{$package}{'mode'} ne 'kernel');
                push (@list, $package);
            }
        }

        if ($with_ovs_dpdk) {
            for my $package ( @dpdk_packages, "openvswitch") {
                next if (grep /^$package$/, @list);
                next if (not $packages_info{$package}{'available'});
                next if ($kernel_only and $packages_info{$package}{'mode'} ne 'kernel');
                next if (not is_rpm_available($package));
                push (@list, $package);
            }
        }

        @selected_by_user = (@list);
        add_enabled_pkgs_by_user();
        resolve_dependencies();
        open(CONFIG, ">$config") || die "Can't open $config: $!";;
        flock CONFIG, $LOCK_EXCLUSIVE;
        print "\nMLNX_OFED packages: ";
        for my $package ( @selected_packages ) {
            if ($packages_info{$package}{'available'} and is_rpm_available($package)) {
                print $package . ' ';
                print CONFIG "$package=y\n";
            }
        }
        flock CONFIG, $UNLOCK;
        close(CONFIG);
        print "\n";
        print GREEN "Created $config", RESET "\n";
        exit $SUCCESS;
    }

    warn("Logs dir: $ofedlogs\n");
    warn("General log file: $glog\n");

    if (not $firmware_update_only) {
        my $num_selected = 0;

        if ($force_enable_packages{'srp'} and $arch =~ /ppc/) {
            print_and_log_colored("WARNING: srp module installaion was forced, ibmvscsi module will not be operational after $PACKAGE installation!", 1, "YELLOW");
        }
        if (not ($skip_unsupported_devices_check or $check_deps_only or !$update_firmware)) {
            unsupported_devices_check();
        }

        # Set RPMs info for available source RPMs
        set_existing_rpms();
        set_availability();
        $num_selected = select_packages();
        if (grep /^libibverbs$/, @selected_by_user) {
            push @{$packages_info{'mlnx-ofa_kernel'}{'ofa_req_inst'}}, 'libibverbs';
        }

        resolve_dependencies();
        check_disk_space();

        # skip kernel check when in user space mode only
        if (not $user_space_only and not $check_deps_only) {
            my $match = 0;
            # if kmp is not supported by the OS, check the supported kernels list
            if (not $kmp)
            {
                $match = isKernelSupported();
            } else {
                # if kmp is supported, verify that the kernel modules we have are really
                # compatible with the kerenl (sometimes the KABI gets broken).
                my $ofakmp = "";
                my $kmp_package = "mlnx-ofa_kernel";
                if ($install_option eq 'eth-only') {
                    $kmp_package = "mlnx-en";
                }
                # Check also selected standalone packages
                for my $kerpkg (qw(srp iser isert knem xpmem mlnx-nfsrdma mlnx-nvme mlnx-rdma-rxe gpio-mlxbf i2c-mlx mlxbf-livefish mlx-bootctl pka-mlxbf tmfifo mlxbf-gige mlx-trio gpio-mlxbf2 mlx-pmc)) {
                    if (grep(/^$kerpkg$/, @selected_packages)) {
                        $kmp_package = "$kmp_package,$kerpkg";
                    }
                }
                if ($DISTRO =~ /RHEL | ^OL | EULER | ALIOS | BCLINUX/x) {
                    $ofakmp = join(',', glob("$RPMS/kmod-{$kmp_package}*.$rpm_distro.$arch.rpm"));
                } elsif ($DISTRO =~ /SLES|SUSE/) {
                    my $kflavor = "";
                    if ($kernel =~ /.*-(default|trace|ppc64|bigsmp|debug|ppc|kdump|kdumppae|smp|vmi|vmipae|xen|xenpae|pae)/) {
                        $kflavor = $1;
                    }
                    $ofakmp = join(',', glob("$RPMS/{$kmp_package}-kmp-$kflavor*.$rpm_distro.$arch.rpm"));
                }
                if (not $skip_kmp_check and -e "$CWD/is_kmp_compat.sh") {
                    print("Verifying KMP rpms compatibility with target kernel...\n");
                    my $kcmd = "'$CWD/is_kmp_compat.sh' --kernel '$kernel' --path '$ofakmp' --tmp '$TMPDIR'";
                    system("echo $kcmd > $ofedlogs/is_kmp_compat_check.log 2>/dev/null");
                    system("$kcmd >> $ofedlogs/is_kmp_compat_check.log 2>&1");
                    my $res = $? >> 8;
                    my $sig = $? & 127;
                    if ($sig or $res) {
                        # Check if specific kernel support was already added and re-run with KMP disabled.
                        # We'll get here when there are ABI issues with updated kernel, and use already ran mlnx_add_kernel_support.sh
                        if ( isKernelSupported() ) {
                            print_and_log_colored("Detected KMP rpms incompatibility.\nWill run installation without KMP support since mlnx_add_kernel_support.sh already ran.", $verbose, "YELLOW");
                            my $cmd1 = "$0 --disable-kmp @saved_ARGV";
                            print_and_log("Running: $cmd1\n", $verbose2);
                            system("$cmd1");
                            my $res = $? >> 8;
                            my $sig = $? & 127;
                            if ($sig or $res) {
                                print_and_log_colored("Installation failed!", 1, "RED");
                                exit $ERROR;
                            }
                            exit 0;
                        }
                        print_and_log_colored("The kernel KMP rpms coming with $PACKAGE are not compatible with kernel: $kernel", 1, "RED");
                        print_and_log("See log at $ofedlogs/is_kmp_compat_check.log\n\n", 1);
                        if ($auto_add_kernel_support) {
                            $add_kernel_support_flags .= " --kmp";
                        }
                    } else {
                        $match = 1;
                    }
                } else {
                    # skip kmp compat check
                    $match = 1;
                }
            }
            if (not $match) {
                print_and_log_colored("The $kernel kernel is installed, $PACKAGE does not have drivers available for this kernel.", 1, "RED");
                if ($auto_add_kernel_support) {
                    print_and_log("Auto add kernel support requested, going to run mlnx_add_kernel_support.sh...\n", 1);
                    invoke_add_kernel_support();
                }
                print_and_log_colored("You can run mlnx_add_kernel_support.sh in order to to generate an $PACKAGE package with drivers for this kernel.", 1, "RED");
                print_and_log_colored("Or, you can provide '--add-kernel-support' flag to generate an $PACKAGE package and automatically start the installation.", 1, "RED");
                exit $ERROR;
            }
        }

        check_linux_dependencies();
        if ($verbose2) {
            print_selected();
        }

        if (not $num_selected) {
            print_and_log_colored("$num_selected packages selected. Exiting...", 1, "RED");
            exit $ERROR;
        }
        print_and_log("Detected Linux Distribution: $DISTRO\n", $verbose3);

        print "This program will install the $PACKAGE package on your machine.\n"
            . "Note that all other Mellanox, OEM, OFED, RDMA or Distribution IB packages will be removed.\n"
            . "Those packages are removed due to conflicts with $PACKAGE, do not reinstall them.\n\n" if (not $quiet and not $update);

        if (not $force and not $quiet) {
            print "Do you want to continue?[y/N]:";
            $ans = getch();
            print "\n";
            if ($ans !~ m/[yY]/) {
                exit $ERROR;
            }
        }

        # Set previous OFED version if available
        if (is_installed("ofed-scripts")) {
            $prev_major_version =`$RPM -q --queryformat "[%{VERSION}]" "ofed-scripts" 2> /dev/null | head -1`;
            if ($prev_major_version eq $major_version) {
                $major_update = 0;
            }
        }

        # Uninstall the previous installations
        uninstall();
        my $vendor_ret;
        if (length($vendor_pre_install) > 0) {
                print_and_log("\nRunning vendor pre install script: $vendor_pre_install\n", (not $quiet));
                $vendor_ret = system ( "$vendor_pre_install", "CONFIG=$config",
                    "RPMS=$RPMS", "SRPMS=$SRPMS", "PREFIX=$prefix", "TOPDIR=$TOPDIR", "QUIET=$quiet" );
                if ($vendor_ret != 0) {
                        print_and_log_colored("\nExecution of vendor pre install script failed.", (not $quiet), "RED");
                        exit $ERROR;
                }
        }

        install();

        system("/sbin/ldconfig > /dev/null 2>&1");

        if ( -e "/etc/modprobe.conf.dist" and not $user_space_only) {
            open(MDIST, "/etc/modprobe.conf.dist") or die "Can't open /etc/modprobe.conf.dist: $!";
            my @mdist_lines;
            while (<MDIST>) {
                push @mdist_lines, $_;
            }
            close(MDIST);

            open(MDIST, ">/etc/modprobe.conf.dist") or die "Can't open /etc/modprobe.conf.dist: $!";
            foreach my $line (@mdist_lines) {
                chomp $line;
                if ($line =~ /^\s*install ib_core|^\s*alias ib|^\s*alias net-pf-26 ib_sdp/) {
                    print MDIST "# $line\n";
                } else {
                    print MDIST "$line\n";
                }
            }
            close(MDIST);
        }

        if (length($vendor_pre_uninstall) > 0) {
                system "cp $vendor_pre_uninstall $prefix/sbin/vendor_pre_uninstall.sh";
        }
        if (length($vendor_post_uninstall) > 0) {
                system "cp $vendor_post_uninstall $prefix/sbin/vendor_post_uninstall.sh";
        }
        if (length($vendor_post_install) > 0) {
                print_and_log("\nRunning vendor post install script: $vendor_post_install\n", (not $quiet));
                $vendor_ret = system ( "$vendor_post_install", "CONFIG=$config",
                    "RPMS=$RPMS", "SRPMS=$SRPMS", "PREFIX=$prefix", "TOPDIR=$TOPDIR", "QUIET=$quiet");
                if ($vendor_ret != 0) {
                        print_and_log_colored("\nExecution of vendor post install script failed.", (not $quiet), "RED");
                        exit $ERROR;
                }
        }

#        if ( -e "/etc/modprobe.d/mlx4_en.conf") {
#            open(MDIST, ">>/etc/modprobe.d/mlx4_en.conf") or die "Can't open /etc/modprobe.d/mlx4_en.conf: $!";
#            print MDIST "\n\n# Configure Flow Control\n";
#            print MDIST "# pfctx:Priority based Flow Control policy on TX[7:0]. Per priority bit mask (uint)\n";
#            print MDIST "# pfcrx:Priority based Flow Control policy on RX[7:0]. Per priority bit mask (uint)\n";
#            print MDIST "options mlx4_core pfctx=$pfc pfcrx=$pfc\n";
#            close(MDIST);
#        }

        if ($do_copy_udev) {
            copy_udev_rules($verbose2);
        }

        if ($kernel_modules_info{'ipoib'}{'selected'} and not $user_space_only) {
            ipoib_config();

            # Decrease send/receive queue sizes on 32-bit arcitecture
            # BUG: https://bugs.openfabrics.org/show_bug.cgi?id=1420
            if ($arch =~ /i[3-6]86/) {
                if ( -e "/etc/modprobe.d/ib_ipoib.conf") {
                    open(MODPROBE_CONF, ">>/etc/modprobe.d/ib_ipoib.conf");
                    print MODPROBE_CONF "options ib_ipoib send_queue_size=64 recv_queue_size=128\n";
                    close MODPROBE_CONF;
                }
            }

            # BUG: https://bugs.openfabrics.org/show_bug.cgi?id=1449
            if ( -e "/etc/modprobe.d/ipv6") {
                open(IPV6, "/etc/modprobe.d/ipv6") or die "Can't open /etc/modprobe.d/ipv6: $!";
                my @ipv6_lines;
                while (<IPV6>) {
                    push @ipv6_lines, $_;
                }
                close(IPV6);

                open(IPV6, ">/etc/modprobe.d/ipv6") or die "Can't open /etc/modprobe.d/ipv6: $!";
                foreach my $line (@ipv6_lines) {
                    chomp $line;
                    if ($line =~ /^\s*install ipv6/) {
                        print IPV6 "# $line\n";
                    } else {
                        print IPV6 "$line\n";
                    }
                }
                close(IPV6);
            }
        }

        if ( not $quiet ) {
            check_pcie_link();
        }

        print_and_log_colored("\nInstallation finished successfully.", (not $quiet), "GREEN");
        print "\n\n";

        my @openmpi_mca_params;
        # Openmpi post-install action
        if (-d "$prefix/mpi") {
            @openmpi_mca_params = `find $prefix/mpi -name openmpi-mca-params.conf 2> /dev/null`;
            for my $openmpi_conf (@openmpi_mca_params) {
                chomp $openmpi_conf;
                system("echo coll_fca_enable = 0 >> $openmpi_conf 2>&1");
                system("echo coll = ^ml >> $openmpi_conf");
            }
        }
    } # not firmware_update_only

    # update FW
    my $fwerr = 0;
    if (not exists $disabled_packages{"mlnx-fw-updater"}) {
        my $fwup = $update_firmware ? 'yes' : 'no';
        my ($fwbin) = glob("$RPMS/mlnx-fw-updater*.$arch.rpm");
        if (-e "$fwbin") {
            if (is_installed("mlnx-fw-updater")) {
                print_and_log("Removing old version of mlnx-fw-updater...\n", $verbose);
                system("$RPM -e --allmatches mlnx-fw-updater >/dev/null");
            }
            my $cmd = "FW_UPDATE_FLAGS='--log $ofedlogs/fw_update.log $fw_update_flags --tmpdir $TMPDIR' RUN_FW_UPDATER='$fwup' $RPM -ivh '$fwbin'";
            if ($DISTRO =~ m/WINDRIVER6/) {
                $cmd .= " --nodeps";
            }
            print_and_log("Running: $cmd\n", $verbose2);
            system("$cmd");
            $fwerr = `grep EXIT_STATUS: $ofedlogs/fw_update.log 2>/dev/null`;
            chomp $fwerr;
            $fwerr =~ s/EXIT_STATUS://g;
            $fwerr =~ s/\s//g;
            $fwerr = $update_firmware if("$fwerr" eq "");
        } elsif ($update_firmware) {
            # rpm doesn't exist and FW update was requested.
            print_and_log_colored("Error: mlnx-fw-updater rpm doesn't exist! Cannot perform firmware update!", 1, "RED");
            $fwerr = 2;# DEVICE_INI_MISSING
        }
    }
    exit $fwerr if ($firmware_update_only);

    # Update limits.conf (but not for Containers)
    if (! -e "/.dockerenv" and `grep docker /proc/self/cgroup 2>/dev/null` eq "") {
        if ( -e "/etc/security/limits.conf") {
            open(LIMITS, "/etc/security/limits.conf");
            while (<LIMITS>) {
                if (/soft\s*memlock/) {
                    $update_limits_conf_soft = 0;
                }
                if (/hard\s*memlock/) {
                    $update_limits_conf_hard = 0;
                }
            }
            close LIMITS;

            if($update_limits_conf_soft or $update_limits_conf_hard) {
                print_and_log("Configuring /etc/security/limits.conf.\n", (not $quiet));
            }

            open(LIMITS, ">>/etc/security/limits.conf");
            if($update_limits_conf_soft) {
                print LIMITS "* soft memlock unlimited\n";
            }
            if($update_limits_conf_hard) {
                print LIMITS "* hard memlock unlimited\n";
            }
            close LIMITS;
        }
    }

    # Update ofed_info
    if ( -e "/usr/bin/ofed_info") {
        my @ofed_info;
        open(INFO, "/usr/bin/ofed_info");
        while (<INFO>) {
           push @ofed_info, $_;
        }
        close(INFO);
        open(INFO, ">/usr/bin/ofed_info");
        foreach my $line (@ofed_info) {
           if ($line =~ m/^OFED/) {
              chomp $line;
              $line =~ s/://;
              $line =~ s/internal-//;
              $line = "$PACKAGE-$MLNX_OFED_LINUX_VERSION ($line):";
           } elsif ($line =~ m/^if/ and $line =~ m/exit/ and $line =~ /X-s/) {
              $line = "if [ \"X\$1\" == \"X-s\" ]; then echo $PACKAGE-$MLNX_OFED_LINUX_VERSION:; exit 0; fi\n";
           } elsif ($line =~ m/^if/ and $line =~ m/exit/ and $line =~ /X-n/) {
              $line = "if [ \"X\$1\" == \"X-n\" ]; then echo $MLNX_OFED_LINUX_VERSION; exit 0; fi\n";
           } elsif ($line =~ /\|openvswitch/ and not $packages_info{'openvswitch'}{'available'})  {
             # There are packages that were not installed by us but may
             # be present on the system, and it would be dangerous to
             # remove them:
             $line =~ s/\|openvswitch//;
           } elsif ($line =~ /\|spdk/ and not is_included('spdk'))  {
             $line =~ s/\|spdk//;
           }
           $line =~ s/OFED-internal/$PACKAGE/g;
           print INFO "$line";
        }
        close(INFO);
    }

    # Comment core modules loading hack from /etc/modprobe.conf.dist
    if ( -e "/etc/modprobe.conf.dist" and not $user_space_only) {
        my @lines;
        open(FD, "/etc/modprobe.conf.dist");
        while (<FD>) {
            push @lines, $_;
        }
        close (FD);

        open(FD, ">/etc/modprobe.conf.dist");
        foreach my $line (@lines) {
            chomp $line;
            if ($line =~ m/(^install ib_core).*/) {
                    print FD "# $line\n";
            } else {
                    print FD "$line\n";
            }
        }
        close (FD);
    }

    # Make IPoIB interfaces be unmanaged on XenServer
    if ($DISTRO =~ m/XenServer/) {
        my $ports_num = count_ports();
        for (my $i = 0; $i < $ports_num; $i++ ) {
            my $uuid = `xe pif-list 2> /dev/null | grep -B2 ib$i | grep uuid | cut -d : -f 2 | sed -e 's/ //g'`;
            chomp $uuid;
            if ($uuid) {
                system ("xe pif-forget uuid=$uuid > /dev/null 2>&1");
            }
        }
    }

    if ($umad_dev_rw or $umad_dev_na) {
        set_umad_permissions($umad_dev_na);
    }

    if ( -e "/etc/infiniband/openib.conf.rpmsave" ) {
        if (compare("/etc/infiniband/openib.conf","/etc/infiniband/openib.conf.rpmsave") != 0) {
            # In case of major update override openib.conf
            if ($major_update) {
                print_and_log("\nWARNING: Original /etc/infiniband/openib.conf saved as /etc/infiniband/openib.conf.rpmsave\n", (not $quiet));
            } else {
                move("/etc/infiniband/openib.conf", "/etc/infiniband/openib.conf.rpmnew");
                move("/etc/infiniband/openib.conf.rpmsave", "/etc/infiniband/openib.conf");
                print_and_log("\nWARNING: /etc/infiniband/openib.conf saved as /etc/infiniband/openib.conf.rpmnew\n", (not $quiet));
            }
        }
    }

    if ( -e "/etc/infiniband/connectx.conf.rpmsave" ) {
        # connectx.conf usage did not change. So, it should not be overriden.
        if (compare("/etc/infiniband/connectx.conf","/etc/infiniband/connectx.conf.rpmsave") != 0) {
            if (-s "/etc/infiniband/connectx.conf") {
                move("/etc/infiniband/connectx.conf", "/etc/infiniband/connectx.conf.rpmnew");
                print_and_log("\nWARNING: /etc/infiniband/connectx.conf saved as /etc/infiniband/connectx.conf.rpmnew\n", (not $quiet));
            }
            move("/etc/infiniband/connectx.conf.rpmsave", "/etc/infiniband/connectx.conf");
        }
    }

    if ( -e "/etc/srp_daemon.conf.rpmsave" ) {
        if (compare("/etc/srp_daemon.conf","/etc/srp_daemon.conf.rpmsave") != 0) {
            # In case of major update override srp_daemon.conf
            if ($major_update) {
                print_and_log("\nWARNING: Original /etc/srp_daemon.conf saved as /etc/srp_daemon.conf.rpmsave\n", (not $quiet));
            } else {
                move("/etc/srp_daemon.conf", "/etc/srp_daemon.conf.rpmnew");
                move("/etc/srp_daemon.conf.rpmsave", "/etc/srp_daemon.conf");
                print_and_log("\nWARNING: /etc/srp_daemon.conf saved as /etc/srp_daemon.conf.rpmnew\n", (not $quiet));
            }
        }
    }

    if ( -e "/etc/fabric_collector/fb_collector.conf.rpmsave" ) {
        if (compare("/etc/fabric_collector/fb_collector.conf","/etc/fabric_collector/fb_collector.conf.rpmsave") != 0) {
            # In case of major update override fb_collector.conf
            if ($major_update) {
                print_and_log("\nWARNING: Original /etc/fabric_collector/fb_collector.conf saved as /etc/fabric_collector/fb_collector.conf.rpmsave\n", (not $quiet));
            } else {
                move("/etc/fabric_collector/fb_collector.conf", "/etc/fabric_collector/fb_collector.conf.rpmnew");
                move("/etc/fabric_collector/fb_collector.conf.rpmsave", "/etc/fabric_collector/fb_collector.conf");
                print_and_log("\nWARNING: /etc/fabric_collector/fb_collector.conf saved as /etc/fabric_collector/fb_collector.conf.rpmnew\n", (not $quiet));
            }
        }
    }

    if ( -e "/etc/rdma/ibacm_opts.cfg.rpmsave" ) {
        if (compare("/etc/rdma/ibacm_opts.cfg","/etc/rdma/ibacm_opts.cfg.rpmsave") != 0) {
            # In case of major update override the conf
            if ($major_update) {
                print_and_log("\nWARNING: Original /etc/rdma/ibacm_opts.cfg saved as /etc/rdma/ibacm_opts.cfg.rpmsave\n", (not $quiet));
            } else {
                move("/etc/rdma/ibacm_opts.cfg", "/etc/rdma/ibacm_opts.cfg.rpmnew");
                move("/etc/rdma/ibacm_opts.cfg.rpmsave", "/etc/rdma/ibacm_opts.cfg");
                print_and_log("\nWARNING: /etc/rdma/ibacm_opts.cfg saved as /etc/rdma/ibacm_opts.cfg.rpmnew\n", (not $quiet));
            }
        }
    }

    if ($DISTRO =~ m/RHEL5/) {
        if ( -e "/etc/init.d/openibd" ) {
            my $filter = 0;
            my @lines;
            open(FD, "/etc/init.d/openibd");
            while (<FD>) {
                push @lines, $_;
            }
            close (FD);
            open(FD, ">/etc/init.d/openibd");
            foreach my $line (@lines) {
                chomp $line;
                if ($line =~ m/### BEGIN INIT INFO/) {
                        $filter = 1;
                        next;
                } elsif ($line =~ m/### END INIT INFO/) {
                        $filter = 0;
                        next;
                }
                print FD "$line\n" if (not $filter);
            }
            close (FD);
            system("/sbin/chkconfig --del openibd > /dev/null 2>&1");
            system("/sbin/chkconfig --add openibd > /dev/null 2>&1");
        }
    }

    if (is_installed("ibacm")) {
        # Disable ibacm daemon by default
        system("chkconfig --del ibacm > /dev/null 2>&1");
    }

    if ( -e "/etc/infiniband/openib.conf") {
        my @lines;
        open(FD, "/etc/infiniband/openib.conf");
        while (<FD>) {
            push @lines, $_;
        }
        close (FD);
        # Do not start SDP
        # Do not start QIB to prevent http://bugs.openfabrics.org/bugzilla/show_bug.cgi?id=2262
        open(FD, ">/etc/infiniband/openib.conf");
        foreach my $line (@lines) {
            chomp $line;
            if ($line =~ m/(^SDP_LOAD=|^QIB_LOAD=).*/) {
                    print FD "${1}no\n";
            } elsif ($line =~ m/(^SET_IPOIB_CM=).*/ and $with_vma) {
                # Set IPoIB Datagram mode in case of VMA installation
                print FD "SET_IPOIB_CM=no\n";
            } else {
                    print FD "$line\n";
            }
        }
        close (FD);
    }

    if (is_installed("$knem_rpm")) {
        # for RH
        if (-d "/etc/sysconfig/modules/") {
            open(FD, ">/etc/sysconfig/modules/knem.modules");
            print FD "/sbin/modprobe knem > /dev/null 2>&1\n";
            close (FD);
            system("chmod +x /etc/sysconfig/modules/knem.modules");
            system ("/sbin/modprobe -r knem > /dev/null 2>&1");
            system ("/etc/sysconfig/modules/knem.modules > /dev/null 2>&1");
        # for SLES
        } elsif ( -e "/etc/sysconfig/kernel") {
            my @lines;
            open(FD, "/etc/sysconfig/kernel");
            while (<FD>) {
                push @lines, $_;
            }
            close (FD);
            open(FD, ">/etc/sysconfig/kernel");
            foreach my $line (@lines) {
                chomp $line;
                if ($line !~ m/knem/ and $line =~ m/^MODULES_LOADED_ON_BOOT=\"(.*)\"/) {
                        print FD "MODULES_LOADED_ON_BOOT=\"$1 knem\"\n";
                } else {
                        print FD "$line\n";
                }
            }
            close (FD);
            system ("/sbin/modprobe -r knem > /dev/null 2>&1");
            system ("/sbin/modprobe knem > /dev/null 2>&1");
        }
    }

    if ($DISTRO =~ m/OL/ and $kernel =~ m/2.6.32-279.19.1.el6/) {
        my @lines;
        open(FD, "/etc/infiniband/openib.conf");
        while (<FD>) {
            push @lines, $_;
        }
        close (FD);

        open(FD, ">/etc/infiniband/openib.conf");
        foreach my $line (@lines) {
            chomp $line;
            if ($line =~ m/(^RUN_SYSCTL=).*/) {
                    print FD "${1}no\n";
            } else {
                    print FD "$line\n";
            }
        }
        close (FD);
    }

    # Enable/disable mlnx_affinity upon boot
    if ( -e "/etc/infiniband/openib.conf") {
        my @lines;
        open(FD, "/etc/infiniband/openib.conf");
        while (<FD>) {
            push @lines, $_;
        }
        close (FD);

        open(FD, ">/etc/infiniband/openib.conf");
        foreach my $line (@lines) {
            chomp $line;
            if ($line =~ m/(^RUN_AFFINITY_TUNER=).*/) {
                if ($enable_affinity) {
                    print FD "${1}yes\n";
                } else {
                    print FD "${1}no\n";
                }
            } else {
                    print FD "$line\n";
            }
        }
        close (FD);
    }

    # Enable/disable mlnx_tune
    if ( -e "/etc/infiniband/openib.conf") {
        my @lines;
        open(FD, "/etc/infiniband/openib.conf");
        while (<FD>) {
            push @lines, $_;
        }
        close (FD);

        open(FD, ">/etc/infiniband/openib.conf");
        foreach my $line (@lines) {
            chomp $line;
            if ($line =~ m/(^RUN_MLNX_TUNE=).*/) {
                if ($enable_mlnx_tune) {
                    print FD "${1}yes\n";
                } else {
                    print FD "${1}no\n";
                }
            } else {
                    print FD "$line\n";
            }
        }
        close (FD);
    }

    my $set_delay = 0;
    if ($post_start_delay) {
        if ( -e "/etc/infiniband/openib.conf") {
            my @lines;
            open(FD, "/etc/infiniband/openib.conf");
            while (<FD>) {
                push @lines, $_;
            }
            close (FD);

            open(FD, ">/etc/infiniband/openib.conf");
            foreach my $line (@lines) {
                chomp $line;
                if ($line =~ m/(^POST_START_DELAY=).*/) {
                    print FD "${1}$post_start_delay\n";
                    $set_delay ++;
                } else {
                    print FD "$line\n";
                }
            }
            if (not $set_delay) {
                print FD "\n# Seconds to sleep after openibd start finished and before releasing the shell\n";
                print FD "POST_START_DELAY=$post_start_delay\n";
            }
            close (FD);
        }
    }

    my $mlnx_conf = "/etc/modprobe.d/mlnx.conf";
    if ($with_vma and -e "$mlnx_conf" and not $user_space_only) {
        my @lines;
        open(FD, "$mlnx_conf");
        while (<FD>) {
            push @lines, $_;
        }
        close (FD);
        open(FD, ">$mlnx_conf");
        foreach my $line (@lines) {
            chomp $line;
            print FD "$line\n" unless ($line =~ /disable_raw_qp_enforcement|fast_drop|log_num_mgm_entry_size/);
        }
        print FD "options mlx4_core fast_drop=1\n";
        print FD "options mlx4_core log_num_mgm_entry_size=-1\n";
        close (FD);
    }

    if ($enable_opensm or $install_option eq 'msm') {
        # Switch on opensmd service
        if (-e "/sbin/chkconfig") {
            system("/sbin/chkconfig --add opensmd > /dev/null 2>&1");
            system("/sbin/chkconfig --set opensmd on > /dev/null 2>&1");
            system("/sbin/chkconfig --level 345 opensmd on > /dev/null 2>&1");
        } elsif (-e "/usr/sbin/update-rc.d") {
            system("/usr/sbin/update-rc.d opensmd defaults > /dev/null 2>&1");
        } else {
            system("/usr/lib/lsb/install_initd /etc/init.d/opensmd > /dev/null 2>&1");
        }
    } else {
        # Switch off opensmd service
        if (-e "/sbin/chkconfig") {
            system("/sbin/chkconfig --del opensmd > /dev/null 2>&1");
            system("/sbin/chkconfig --set opensmd off > /dev/null 2>&1");
            system("/sbin/chkconfig opensmd off > /dev/null 2>&1");
        } elsif (-e "/usr/sbin/update-rc.d") {
            system("/usr/sbin/update-rc.d -f opensmd remove > /dev/null 2>&1");
        } else {
            system("/usr/lib/lsb/remove_initd /etc/init.d/opensmd > /dev/null 2>&1");
        }
    }

    if (grep /mlnx-ofa_kernel-modules/, @selected_packages) {
        if ($update_initrd_cmd) {
            print_and_log_colored("You may need to update your initramfs before next boot. To do that, run:\n", (not $quiet), "GREEN");
            print_and_log("   $update_initrd_cmd\n", (not $quiet));
        }
    }

    if (not $user_space_only) {
        if ($install_option eq 'eth-only') {
            print_and_log_colored("To load the new driver, run:\n/etc/init.d/mlnx-en.d restart", (not $quiet), "GREEN");
        } else {
            print_and_log_colored("To load the new driver, run:\n/etc/init.d/openibd restart", (not $quiet), "GREEN");
            if ($with_nvme) {
                print_and_log("Note: In order to load the new nvme-rdma and nvmet-rdma modules, the nvme module must be reloaded.\n", 1);
            }
        }
    }
}

main();
exit $err;
