#! /bin/bash
#
# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# This software product is a proprietary product of Mellanox Technologies Ltd.
# (the "Company") and all right, title, and interest in and to the software
# product, including all associated intellectual property rights, are and
# shall remain exclusively with the Company.
#
# This software product is governed by the End User License Agreement
# provided with the software product.
#

mftconfig=mstconfig
if [ -x /usr/bin/mlxconfig ]; then
	mftconfig=mlxconfig
fi

get_eswitch_mode()
{
	pci_dev=$1
	shift

	devlink dev eswitch show pci/${pci_dev} 2> /dev/null | cut -d ' ' -f 3
}

pci=`lspci -nD -d 15b3: | grep 'a2d[26c]\|101d\|1021' | head -n 1`
emu_manager=`echo $pci | cut -d ' ' -f 1`

if [[ -f /opt/mellanox/mlnx_virtnet/virtnet.conf ]]; then
	_emu_manager=`grep "ib_dev_p0" /opt/mellanox/mlnx_virtnet/virtnet.conf | \
				 tr -d ' ' | cut -d '"' -f 4 | sort | head -n1`
	if [[ ! -z $_emu_manager ]]; then
		emu_manager=`basename $(readlink "/sys/class/infiniband/$_emu_manager/device")`
	fi
fi

if [[ -z $emu_manager ]]; then
	echo "Error: no valid emulation manager is defined"
	exit 1
fi

eswitch_mode="get_eswitch_mode ${emu_manager}"

COUNT=0
until [ $COUNT -eq 120 ] || [ "`${eswitch_mode}`" == "switchdev" ]; do
	sleep 1
	echo "Waiting for device ${emu_manager} to be switchdev mode for ${COUNT} seconds"
	let $(( COUNT++ ))
done

if [ "`${eswitch_mode}`" != "switchdev" ]; then
	echo "${emu_manager} is not in switch dev mode"
	exit 2
fi

configs=`$mftconfig -d ${emu_manager} -e q VIRTIO_NET_EMULATION_ENABLE \
					   PF_BAR2_ENABLE \
					   HIDE_PORT2_PF \
					   PER_PF_NUM_SF \
					   PCI_SWITCH_EMULATION_ENABLE \
					   PCI_SWITCH_EMULATION_NUM_PORT \
					   VIRTIO_NET_EMULATION_NUM_VF \
					   VIRTIO_NET_EMULATION_NUM_PF \
					   VIRTIO_NET_EMULATION_NUM_MSIX \
					   SRIOV_EN \
					   PF_SF_BAR_SIZE \
					   PF_TOTAL_SF`

if [[ -z `echo "$configs" 2> /dev/null | grep -o "VIRTIO_NET_EMULATION_ENABLE.*" | awk '{print $3}' |\
      grep True` ]]; then
	echo "${emu_manager} doesn't have VIRTIO_NET_EMULATION_ENABLE set"
	exit 250
fi

config_file="/opt/mellanox/mlnx_virtnet/virtnet.conf"
p2=`$mftconfig -d ${emu_manager} -e q LINK_TYPE_P2`
if [[ -n `echo "$p2" 2> /dev/null | grep "Unknown Parameter"` ]]; then
	echo "Single port NIC"
	if [[ -f $config_file ]]; then
		if [[ -n `grep "single_port" $config_file` ]]; then
			sed -ri 's/(^.*single_port.*:[ 	]*)([0-9]+)(.*$)/\11\3/' \
			    $config_file
		else
			sed -i '0,/{/s//{\n\	"single_port": 1,/' $config_file
		fi
	else
		echo -e '{\n	"single_port": 1\n}' >  $config_file
	fi
fi

if [[ -z `modinfo mlxdevm 2>&1 | grep -E "ERROR.*mlxdevm not found"` ]]; then
	echo "mlxdevm as SF provider"
	if [[ -f $config_file ]]; then
		if [[ -n `grep "sf_provider" $config_file` ]]; then
			sed -ri 's/(^.*sf_provider.*:[ 	]*)(".*")(.*$)/\1"mlxdevm"\3/' \
			    $config_file
		fi
	fi
else
	echo "devlink as SF provider"
	if [[ -f $config_file ]]; then
		if [[ -n `grep "sf_provider" $config_file` ]]; then
			sed -ri 's/(^.*sf_provider.*:[ 	]*)(".*")(.*$)/\1"devlink"\3/' \
			    $config_file
		else
			sed -i '0,/{/s//{\n\	"sf_provider": "devlink",/' $config_file
		fi
	else
		echo -e '{\n	"sf_provider": "devlink"\n}' >  $config_file
	fi
fi

bf3=`echo $pci | grep 'a2dc\|1021'`

if [[ -n $bf3 ]]; then
	if [[ ! -e /opt/mellanox/mlnx_virtnet/providers/dpa.provider ]]; then
		echo "Generating default dpa.provider for BlueField-3/ConnectX-7"
		echo -e "Provider=libprovider-dpa\nScore=200" > \
		      /opt/mellanox/mlnx_virtnet/providers/dpa.provider
	fi
fi

recovery_dir="/opt/mellanox/mlnx_virtnet/recovery"

is_lag_cur=0
if [[ -f $config_file ]]; then
	is_lag_cur=`cat "$config_file" | grep -E "is_lag" | tr -s ' ' | \
		    cut -d ':' -f 2 | cut -d ',' -f 1 | awk '{$1=$1};1'`
fi

mkdir -p ${recovery_dir}
if [[ -f "${recovery_dir}/.virtnet_conf_save" ]]; then
	is_lag_save=`cat "${recovery_dir}/.virtnet_conf_save" | grep -E "is_lag" | \
		     tr -s ' '| cut -d ':' -f 2 | cut -d ',' -f 1 | awk '{$1=$1};1'`
	if [[ "$is_lag_save" != "$is_lag_cur" ]]; then
		cd $recovery_dir
		find . -type f -not \( -name ".virtnet_conf_save" -or -name ".mlxconfig_save" \) -delete
	fi
fi

if [[ -f $config_file ]]; then
	cp "$config_file" "${recovery_dir}/.virtnet_conf_save"
else
	echo -e '{\n	"is_lag": 0\n}' > "${recovery_dir}/.virtnet_conf_save"
fi

curr_map_count=`cat /proc/sys/vm/max_map_count`

#Define map threshold value to 131060 (65530 * 2) to support upto 2K devices
max_map_threshold=131060

if [[ "$curr_map_count" -lt "$max_map_threshold" ]]; then
    echo $max_map_threshold > /proc/sys/vm/max_map_count
fi

fields=(PF_BAR2_ENABLE \
	HIDE_PORT2_PF \
	PER_PF_NUM_SF \
	PCI_SWITCH_EMULATION_ENABLE \
	PCI_SWITCH_EMULATION_NUM_PORT \
	VIRTIO_NET_EMULATION_NUM_VF \
	VIRTIO_NET_EMULATION_NUM_PF \
	VIRTIO_NET_EMULATION_NUM_MSIX \
	SRIOV_EN \
	PF_SF_BAR_SIZE \
	PF_TOTAL_SF)

fields_str=""
for f in ${fields[@]};
do
	if [[ $fields_str != "" ]]; then
		fields_str="${fields_str}|${f}"
	else
		fields_str="${f}"
	fi
done

mlxconfig_cur=`echo "$configs" | grep -E $fields_str | tr -s ' '`

if [[ ! -f "${recovery_dir}/.mlxconfig_save" ]]; then
	mkdir -p ${recovery_dir}
	echo "$mlxconfig_cur" > ${recovery_dir}/.mlxconfig_save
	exit 0
fi

mlxconfig_save=`cat ${recovery_dir}/.mlxconfig_save | grep -E $fields_str | tr -s ' '`

for f in ${fields[@]};
do
	val_save=`echo "$mlxconfig_save" | grep -o "$f.*" | awk '{print $3}'`
	val_cur=`echo "$mlxconfig_cur" | grep -o "$f.*" | awk '{print $3}'`
	if [[ "$val_save" != "$val_cur" ]]; then
		echo "$mlxconfig_cur" > ${recovery_dir}/.mlxconfig_save
		cd $recovery_dir
		find . -type f -not \( -name ".virtnet_conf_save" -or -name ".mlxconfig_save" \) -delete
		exit 0
	fi
done

exit 0
