#!/bin/bash
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (c) 2020 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.

PATH=/opt/mellanox/iproute2/sbin:/opt/mellanox/ethtool/sbin:/bin:/sbin:/usr/bin:/usr/sbin
CT_MAX_OFFLOADED_CONNS=${CT_MAX_OFFLOADED_CONNS:-1000000}
MLXCONFIG_TIMEOUT=${MLXCONFIG_TIMEOUT:-60}
RDMA_SET_NETNS_TIMEOUT=${RDMA_SET_NETNS_TIMEOUT:-30}
SET_MODE_RETRY_NUM=${SET_MODE_RETRY_NUM:-60}
RUN_CMD_RETRY_NUM=${RUN_CMD_RETRY_NUM:-10}
SUPPORTED_DEVICES="a2d[26cf]|1025"
BLUEFIELD_DEVICES="a2d[26cf]"
BF4_DEVICES="1023|1025"
SD_MERGED_ESWITCH=0

ipsec_services="strongswan.service ipsec.service"
ipsec_was_active=""

RC=0

info()
{
	logger -t $prog -i "INFO: $*"
}

error()
{
	logger -t $prog -i "ERR: $*"
}

debug()
{
	if [ "X${LOG_LEVEL}" == "Xdebug" ]; then
		logger -t $prog -i "DBG: $*"
	fi
}

is_bf=`lspci -s 00:00.0 2> /dev/null | grep -wq "PCI bridge: Mellanox Technologies" && echo 1 || echo 0`
if [ $is_bf -ne 1 ]; then
	# Check if the device is a Mellanox BlueField 4 or newer
	if [ -e /etc/mlnx-release ]; then
		if [ $(lspci -nD -d 15b3: | grep -E "$BLUEFIELD_DEVICES" | wc -l) -gt 0 ]; then
			info "Device is a Mellanox BlueField 4 or newer"
		else
			exit 0
		fi
	else
		info "Device is not a Mellanox BlueField. Exiting..."
		exit 0
	fi
fi

prog=`basename $0`

PID=$(pgrep -oxf "/bin/bash /sbin/$prog" \
        || pgrep -oxf "/bin/bash /usr/sbin/$prog" \
        || pgrep -oxf "/usr/bin/bash /sbin/$prog" \
        || pgrep -oxf "/usr/bin/bash /usr/sbin/$prog")
if [[ -n $PID && $$ -ne $PID ]]; then
	# $prog is running already with PID: $PID
	exit 0
fi

run_command_with_retry()
{
	cmd=$1
	shift

	i=0
	while ! (eval "$cmd"); do
		if [ $i -gt $RUN_CMD_RETRY_NUM ]; then
			error "Failed to run $cmd after $i retries"
			return 1
		fi
		let i++
		sleep 1
	done
	if [ $i -gt 0 ]; then
		info "$cmd passed after $i retries"
	fi

	return 0
}

get_steering_mode()
{
	pci_dev=$1
	shift

	compat=`/bin/ls -1 /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/steering_mode 2> /dev/null`
	if [ -n "$compat" ]; then
		cat ${compat} 2> /dev/null
	else
		run_devlink dev param show pci/${pci_dev} name flow_steering_mode | tail -1 | awk '{print $NF}'
	fi
}

set_steering_mode()
{
	pci_dev=$1
	mode=$2
	shift 2

	rc=1
	i=0
	compat=`/bin/ls -1 /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/steering_mode 2> /dev/null`
	while [ $rc -ne 0 ]
	do
		if [ -n "$compat" ]; then
			run_command_with_retry "echo ${mode} > /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/steering_mode"
		else
			run_command_with_retry "run_devlink dev param set pci/${pci_dev} name flow_steering_mode value ${mode} cmode runtime"
		fi
		rc=$?
		let i++
		if [ $i -gt $SET_MODE_RETRY_NUM ]; then
			break
		fi
		sleep 1
	done
	if [ $rc -ne 0 ]; then
		error "Failed to configure steering mode ${mode} for ${pci_dev} after $i retries"
	else
		info "Configured mode steering ${mode} for ${pci_dev} on try: $i"
	fi

	return $rc
}

get_eswitch_mode()
{
	pci_dev=$1
	shift

	compat=`/bin/ls -1 /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/mode 2> /dev/null`
	if [ -n "$compat" ]; then
		cat ${compat}
	else
		run_devlink dev eswitch show pci/${pci_dev} 2> /dev/null | cut -d ' ' -f 3
	fi
}

set_eswitch_mode()
{
	pci_dev=$1
	mode=$2
	shift 2

	rc=1
	i=0
	compat=`/bin/ls -1 /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/mode 2> /dev/null`
	while [ $rc -ne 0 ]
	do
		if [ -n "$compat" ]; then
			echo ${mode} > ${compat}
		else
			run_devlink dev eswitch set pci/${pci_dev} mode ${mode}
		fi
		rc=$?
		let i++
		if [ $i -gt $SET_MODE_RETRY_NUM ]; then
			break
		fi
		sleep 1
	done
	if [ $rc -ne 0 ]; then
		error "Failed to configure ${mode} mode for ${pci_dev} after $i retries"
	else
		info "Configured ${mode} mode for ${pci_dev} on try: $i"
	fi

	return $rc
}

get_dev_param()
{
	pci_dev=$1
	name=$2
	shift 2
	compat=`/bin/ls -1 /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/${name} 2> /dev/null`
	if [ -n "$compat" ]; then
		cat ${compat} 2> /dev/null
	else
		run_devlink dev param show pci/${pci_dev} name ${name} 2> /dev/null | tail -1 | awk '{print $NF}'
	fi
}

set_dev_param()
{
	pci_dev=$1
	name=$2
	value=$3
	msg=$4
	shift 4

	compat=`/bin/ls -1 /sys/bus/pci/devices/${pci_dev}/net/*/compat/*/${name} 2> /dev/null`
	if [ -n "$compat" ]; then
		run_command_with_retry "echo ${value} > ${compat}"
	else
		run_command_with_retry "run_devlink dev param set pci/${pci_dev} name ${name} value ${value} cmode runtime"
	fi
	rc=$?
	if [ $rc -ne 0 ]; then
		error "${msg} Failed to set parameter ${name} to ${value} value for ${pci_dev}"
	else
		info "${msg} Set ${name} parameter to ${value} value for ${pci_dev}"
	fi

	return $rc
}

run_mlxconfig()
{
	cmd="$*"
	mft_output=""

	start_time=$(awk '{print $1}' /proc/uptime)
	mft_output="$($cmd 2>&1)"
	while (echo "$mft_output" | grep -q "Failed to open"); do
		echo "$mft_output" >> ${MLXCONFIG_DEBUG_LOG}
		elapsed=$(awk "BEGIN {printf \"%.0f\", $(awk '{print $1}' /proc/uptime) - $start_time}")
		if [ $elapsed -gt $MLXCONFIG_TIMEOUT ]; then
			error "Failed to run $cmd"
			exit 1
		fi
		sleep 1
		export MLXCONFIG_DEBUG=1
		mft_output=$($cmd 2>&1)
		export MLXCONFIG_DEBUG=0
	done
	echo "$mft_output"
}

run_devlink()
{
	cmd="$*"
	output=$(devlink $cmd 2>&1)
	if [ $? -ne 0 ]; then
		if command -v mlxdevm > /dev/null 2>&1; then
			info "Running devlink $cmd failed: $output. Trying mlxdevm..."
			output=$(mlxdevm $cmd 2>&1)
			if [ $? -ne 0 ]; then
				error "Failed to run mlxdevm $cmd: $output"
				return 1
			else
				debug "Ran mlxdevm successfully: $cmd: $output"
				echo "$output"
				return 0
			fi
		else
			error "Failed to run devlink $cmd: $output"
			return 1
		fi
	else
		debug "Ran devlink successfully: $cmd: $output"
		echo "$output"
		return 0
	fi
}

# Numeric value (0-15) of the PCIe function nibble (last character of BDF dddd:bb:dd.f).
pci_function_digit_value()
{
	local c=${1: -1}
	case "$c" in
		[0-9]) printf '%d' "$((10#$c))";;
		[aA]) printf '%d' 10;;
		[bB]) printf '%d' 11;;
		[cC]) printf '%d' 12;;
		[dD]) printf '%d' 13;;
		[eE]) printf '%d' 14;;
		[fF]) printf '%d' 15;;
		*) return 1;;
	esac
}

is_dev_eth()
{
	dev=$1
	shift

	for link_layer in /sys/bus/pci/devices/${dev}/infiniband/*/ports/1/link_layer
	do
		if [ ! -e "$link_layer" ]; then
			continue
		fi
		if grep -Fxq "Ethernet" "$link_layer" 2> /dev/null; then
			return 0
		fi
	done
	return 1
}

# Check if the device is in Socket Direct mode
is_sd_mode()
{
	dev=$1
	shift 1

	mft_output=$(run_mlxconfig "$mftconfig -d ${dev} -e q PF_SD_GROUP")

	if (echo "$mft_output" | grep -o PF_SD_GROUP.* | awk '{print$3}'  | grep -q "^1$"); then
		return 0
	fi
	return 1
}

# Check if the device is in Multi-Host mode
is_mh_mode()
{
	dev=$1
	shift 1

	mft_output=$(run_mlxconfig "$mftconfig -d ${dev} -e q MULTI_HOST")

	if (echo "$mft_output" | grep -o 'MULTI_HOST.*' | awk '{print $3}' | grep -q "^1$"); then
		return 0
	fi
	return 1
}

is_supported_device()
{
	dev=$1
	shift 1

	if (lspci -nD -s ${dev} | grep -E "$SUPPORTED_DEVICES"); then
		return 0
	fi
	return 1
}

is_smartnic_mode()
{
	dev=$1
	shift 1

	mft_output=$(run_mlxconfig "$mftconfig -d ${dev} -e q INTERNAL_CPU_MODEL")

	if (echo $mft_output | grep -o INTERNAL_CPU_MODEL.* | awk '{print$3}' | grep -q "EMBEDDED_CPU(1)"); then
		info "Device ${dev} is in SmartNIC mode"
		return 0
	elif (echo $mft_output | grep -o INTERNAL_CPU_MODEL.* | awk '{print$3}' | grep -q "SEPARATED_HOST(0)"); then
		info "Device ${dev} is in SEPERATED_HOST mode"
		return 1
	fi
	# Assume SmartNIC mode if no match is found
	info "Device ${dev} is in SmartNIC mode"
	return 0
}

get_mlnx_netdevs_by_slot()
{
	dev_num=$1
	shift 1

	pci_id=$(lspci -nD -d 15b3: | grep -E "$SUPPORTED_DEVICES" | cut -d ' ' -f 1 | head -${dev_num} | tail -1)
	netdevs=$(grep PCI_SLOT_NAME=${pci_id} /sys/class/net/*/device/uevent | cut -d '/' -f 5)
	if [ -n "$netdevs" ]; then
		echo "$netdevs"
	fi

	return 0
}

get_mlnx_netdevs_by_pci_id()
{
	pci_id=$1
	shift 1

	netdevs=$(grep PCI_SLOT_NAME=${pci_id} /sys/class/net/*/device/uevent | cut -d '/' -f 5)
	if [ -n "$netdevs" ]; then
		echo "$netdevs"
	fi

	return 0
}

# Helper: check if a value is in an array
in_array() {
    local needle=$1; shift
    local elem
    for elem in "$@"; do
        [[ "$elem" == "$needle" ]] && return 0
    done
    return 1
}

stop_ipsec_services()
{
	# Stop IPsec-related services temporarily if active to remove offloaded IPsec bypass policies
	# This is done so we can change the eswitch mode
	for svc in $ipsec_services; do
		if systemctl is-active --quiet $svc; then
			[ -z "$ipsec_was_active" ] && ipsec_was_active=$svc || ipsec_was_active="$ipsec_was_active $svc"
		fi
	done
	for svc in $ipsec_was_active; do
		systemctl stop $svc
	done
	for svc in $ipsec_was_active; do
		if systemctl is-active --quiet $svc; then
			error "Failed to stop $svc"
		else
			info "Stopped $svc successfully"
		fi
	done
}

start_ipsec_services()
{
	# Start IPsec-related services again if they were active
	for svc in $ipsec_was_active; do
		systemctl start $svc
		if systemctl is-active --quiet $svc; then
			info "Started $svc successfully"
		else
			error "Failed to start $svc"
		fi
	done
}

pci_id=$(lspci -nD -d 15b3: | grep -E "$BLUEFIELD_DEVICES" | cut -d ' ' -f 1 | head -1)
host_en=$(mlxreg -d ${pci_id} --get --reg_name MMHI | grep host_en | awk '{print $NF}')

decimal=$(( host_en ))
is_power_of_two=$(( (decimal & (decimal - 1)) == 0 ))

if [[ $decimal != 0 && $is_power_of_two == 1 ]]; then
	info "Detected Controller device. Exiting..."
	exit 0
fi

is_SecureBoot=0
if (mokutil --sb-state 2>&1 | grep -q "SecureBoot enabled"); then
	is_SecureBoot=1
fi

if [ $is_SecureBoot -eq 1 ]; then
	mst_dev=`/bin/ls -1 /dev/mst/mt*_pciconf0 2> /dev/null`
	if [ ! -n "${mst_dev}" ]; then
		mst start > /dev/null 2>&1
	fi
fi

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

if [ -f /etc/mellanox/mlnx-bf.conf ]; then
	. /etc/mellanox/mlnx-bf.conf
fi
IPSEC_FULL_OFFLOAD=${IPSEC_FULL_OFFLOAD:-"no"}
LAG_HASH_MODE=${LAG_HASH_MODE:-"yes"}
ENABLE_ESWITCH_MULTIPORT=${ENABLE_ESWITCH_MULTIPORT:-"no"}
ENABLE_SD_MERGED_ESWITCH=${ENABLE_SD_MERGED_ESWITCH:-"auto"}
SNAP_DMA_SF=${SNAP_DMA_SF:-"auto"}
SNAP_DMA_SF_NUM=${SNAP_DMA_SF_NUM:-8000}
SNAP_DMA_SF_MAC=${SNAP_DMA_SF_MAC:-""}
SNAP_EMULATION_MANAGERS_FILE=${SNAP_EMULATION_MANAGERS_FILE:-"/run/mellanox/snap_emulation_managers"}
MLXCONFIG_DEBUG_LOG=${MLXCONFIG_DEBUG_LOG:-"/tmp/mlxconfig_debug.log"}
LOG_LEVEL=${LOG_LEVEL:-"info"}
SWITCHDEV_DEVICES_LIST=()
SD_DEVICES_LIST=()
MH_DEVICES_LIST=()
DEVICE_LIST_FOR_OVS_BRIDGES=()

RDMA_SET_NETNS_EXCLUSIVE=${RDMA_SET_NETNS_EXCLUSIVE:-"yes"}
if [ "X${RDMA_SET_NETNS_EXCLUSIVE}" == "Xyes" ]; then
	if ! (rdma system show netns 2>&1 | grep -q exclusive); then
		start_time=$(awk '{print $1}' /proc/uptime)
		while ! (rdma system set netns exclusive); do
			elapsed=$(awk "BEGIN {printf \"%.0f\", $(awk '{print $1}' /proc/uptime) - $start_time}")
			if [ $elapsed -gt $RDMA_SET_NETNS_TIMEOUT ]; then
				break
			fi
			sleep 1
		done
	fi

	if (rdma system show netns 2>&1 | grep -q exclusive); then
		info "The RDMA subsystem is set in network namespace exclusive mode."
	else
		error "Failed to set rdma exclusive mode"
	fi
fi

ctrl_dev=$(lspci -nD -d 15b3: | grep -E "$BLUEFIELD_DEVICES" | cut -d ' ' -f 1 | head -1)
num_of_supported_devs=$(lspci -nD -d 15b3: | grep -E "$SUPPORTED_DEVICES" | wc -l)

start_time=$(awk '{print $1}' /proc/uptime)
mft_output=$($mftconfig -d $ctrl_dev -e q INTERNAL_CPU_MODEL 2>&1)
if ! (echo "$mft_output" | grep -q 'E- The Device doesn.*t support INTERNAL_CPU_MODEL parameter'); then
	while (echo "$mft_output" | grep -q "Failed to open"); do
		echo "$mft_output" >> ${MLXCONFIG_DEBUG_LOG}
		elapsed=$(awk "BEGIN {printf \"%.0f\", $(awk '{print $1}' /proc/uptime) - $start_time}")
		if [ $elapsed -gt $MLXCONFIG_TIMEOUT ]; then
			error "Failed to run $mftconfig query on $ctrl_dev after $elapsed seconds"
			exit 1
		fi
		sleep 1
		mft_output=$($mftconfig -d $ctrl_dev -e q INTERNAL_CPU_MODEL 2>&1)
	done
else
	info "Device $ctrl_dev does not support INTERNAL_CPU_MODEL parameter"
fi
info "MFT output: $mft_output"

num_of_devs_switchdev=0
# Set eswitch mode to switchdev for all devices
if (is_smartnic_mode "$ctrl_dev"); then
	stop_ipsec_services
	for dev in $(devlink dev show | awk -F'/' '/^pci\//{gsub(/:$/,"",$2); print $2}')
	do
		if ! (is_dev_eth "$dev"); then
			info "Link type is IB for ${dev}. Skipping mode configuration."
			continue
		fi

		if [ "X${LAG_HASH_MODE}" == "Xno" ]; then
			set_dev_param ${dev} lag_port_select_mode queue_affinity
		elif [ "X${LAG_MULTIPORT_ESW_MODE}" == "Xyes" ]; then
			eswitch_mode=`get_eswitch_mode ${dev}`
			if [ "${eswitch_mode}" != "legacy" ]; then
				set_eswitch_mode ${dev} legacy
				RC=$((RC+$?))
			fi

			set_dev_param ${dev} lag_port_select_mode multiport_esw
		fi

		if [ "X${ENCAP_NONE_MODE}" == "Xyes" ]; then
			eswitch_mode=`get_eswitch_mode ${dev}`
			if [ "${eswitch_mode}" != "legacy" ]; then
				set_eswitch_mode ${dev} legacy
				RC=$((RC+$?))
			fi

			set_dev_param ${dev} encap none
		fi

		steering_mode=`get_steering_mode ${dev}`
		if [ "${steering_mode}" == "dmfs" ]; then
			eswitch_mode=`get_eswitch_mode ${dev}`
			if [ "${eswitch_mode}" != "legacy" ]; then
				set_eswitch_mode ${dev} legacy
				RC=$((RC+$?))
			fi

			set_steering_mode ${dev} smfs
		fi

		if [ "${IPSEC_FULL_OFFLOAD}" == "yes" ]; then
			lscpu | grep Flags | grep sha1 | grep sha2 | grep -q aes
			if [ $? -eq 0 ]; then
				eswitch_mode=`get_eswitch_mode ${dev}`
				if [ "${eswitch_mode}" != "legacy" ]; then
					set_eswitch_mode ${dev} legacy
					RC=$((RC+$?))
				fi
				steering_mode=`get_steering_mode ${dev}`
				if [ "${steering_mode}" == "smfs" ]; then
					set_steering_mode ${dev} dmfs
				fi
			else
				info "Crypto disabled on this devide. Skipping IPsec mode configuration."
			fi
		fi

		eswitch_mode=`get_eswitch_mode ${dev}`
		if [ "${eswitch_mode}" != "switchdev" ]; then
			if [ "X${LEGACY_METADATA_MATCH_MODE}" == "Xyes" ]; then
				set_dev_param ${dev} vport_match_mode legacy
			fi

			set_eswitch_mode ${dev} switchdev
			RC=$((RC+$?))

			set_dev_param ${dev} ct_max_offloaded_conns ${CT_MAX_OFFLOADED_CONNS}
		fi
		eswitch_mode=`get_eswitch_mode ${dev}`
		if [ "${eswitch_mode}" == "switchdev" ]; then
			if [ "X${ENABLE_ESWITCH_MULTIPORT}" == "Xyes" ]; then
				set_dev_param ${dev} esw_multiport  1 "ESW Multiport:"
			fi
			num_of_devs_switchdev=$((num_of_devs_switchdev+1))
			SWITCHDEV_DEVICES_LIST+=( "$dev" )
		fi
		if is_sd_mode ${dev}; then
			debug "Adding SD device $dev to SD_DEVICES_LIST"
			SD_DEVICES_LIST+=( "$dev" )
		fi
		if is_mh_mode ${dev}; then
			debug "Adding MH device $dev to MH_DEVICES_LIST"
			MH_DEVICES_LIST+=( "$dev" )
		fi
		if is_supported_device ${dev}; then
			debug "Adding supported device $dev to DEVICE_LIST_FOR_OVS_BRIDGES"
			DEVICE_LIST_FOR_OVS_BRIDGES+=( "$dev" )
		fi
	done
	start_ipsec_services
fi

is_bf4()
{
	if [ -e /etc/mlnx-release ]; then
		if [ $(lspci -nD -d 15b3: | grep -E "$BF4_DEVICES" | wc -l) -gt 0 ]; then
			return 0
		fi
	fi
	return 1
}

# For BF4 SD with merged eswitch, use a single bridge on LAG master only
if is_bf4 && [ ${#SD_DEVICES_LIST[@]} -gt 0 ]; then
	if [ "X${ENABLE_SD_MERGED_ESWITCH}" != "Xno" ]; then
		SD_MERGED_ESWITCH=1
		info "BF4 SD merged eswitch mode: single OVS bridge on LAG master only."
		# Configure silent mode on secondary ECPFs
		local_is_first=1
		for sd_dev in ${SD_DEVICES_LIST[@]}; do
			if [ $local_is_first -eq 1 ]; then
				local_is_first=0
				info "SD merged eswitch: $sd_dev is LAG master (no silent mode)"
				continue
			fi
			info "SD merged eswitch: Setting silent mode on secondary ECPF $sd_dev"
			set_dev_param ${sd_dev} silent_mode 1 "SD Silent Mode:"
		done
		# Keep only the first (LAG master) device for bridge creation
		DEVICE_LIST_FOR_OVS_BRIDGES=( "${DEVICE_LIST_FOR_OVS_BRIDGES[0]}" )
	fi
fi

# Create well-known DMA SF for SNAP doca service on the 2nd PCI link ECPF
# The DMA SF provides an additional ibdev needed for 800Gbps DMA across dual
# Grace PCI links in BF-4. It is created only when all preconditions are met:
#   - BF4 platform
#   - Multi-port eswitch enabled
#   - At least 2 switchdev ECPFs across two PCI links
#   - Emulation enabled (PCI_SWITCH_EMULATION_ENABLE + at least one emulation type)
#   - PER_PF_NUM_SF=1 and PF_TOTAL_SF >= SNAP_DMA_SF_NUM
# The SF is created on the ECPF of the 2nd PCI link that has no RDMA device.
SNAP_DMA_SF_TARGET_ECPF=""

create_snap_dma_sf()
{
	# Must be BF4
	if ! is_bf4; then
		debug "SNAP DMA SF: not BF4, skipping"
		return 1
	fi

	# Must have multiport eswitch enabled
	if [ "X${ENABLE_ESWITCH_MULTIPORT}" != "Xyes" ]; then
		debug "SNAP DMA SF: multiport eswitch not enabled, skipping"
		return 1
	fi

	# Must have at least 2 switchdev ECPFs
	if [ ${#SWITCHDEV_DEVICES_LIST[@]} -lt 2 ]; then
		debug "SNAP DMA SF: fewer than 2 switchdev ECPFs, skipping"
		return 1
	fi

	# Check emulation is enabled on the first ECPF
	local ctrl=${SWITCHDEV_DEVICES_LIST[0]}
	local emu_output
	emu_output=$(run_mlxconfig "$mftconfig -d ${ctrl} -e q \
		PCI_SWITCH_EMULATION_ENABLE \
		VIRTIO_NET_EMULATION_ENABLE NVME_EMULATION_ENABLE \
		VIRTIO_BLK_EMULATION_ENABLE VIRTIO_FS_EMULATION_ENABLE \
		TLP_EMULATION_ENABLE")

	if ! (echo "$emu_output" | grep -q 'PCI_SWITCH_EMULATION_ENABLE.*True(1)') && \
	   ! (echo "$emu_output" | grep 'PCI_SWITCH_EMULATION_ENABLE' | awk '{print $3}' | grep -q "^1$"); then
		debug "SNAP DMA SF: PCI_SWITCH_EMULATION_ENABLE not set, skipping"
		return 1
	fi

	local emu_found=0
	local emu_type
	for emu_type in VIRTIO_NET_EMULATION_ENABLE NVME_EMULATION_ENABLE \
	          VIRTIO_BLK_EMULATION_ENABLE VIRTIO_FS_EMULATION_ENABLE \
	          TLP_EMULATION_ENABLE; do
		if (echo "$emu_output" | grep -q "${emu_type}.*True(1)") || \
		   (echo "$emu_output" | grep "${emu_type}" | awk '{print $3}' | grep -q "^1$"); then
			emu_found=1
			break
		fi
	done
	if [ $emu_found -eq 0 ]; then
		debug "SNAP DMA SF: no emulation type enabled, skipping"
		return 1
	fi

	# Check PER_PF_NUM_SF and PF_TOTAL_SF
	local sf_output
	sf_output=$(run_mlxconfig "$mftconfig -d ${ctrl} -e q PER_PF_NUM_SF PF_TOTAL_SF")
	if ! (echo "$sf_output" | grep -q 'PER_PF_NUM_SF.*True(1)') && \
	   ! (echo "$sf_output" | grep 'PER_PF_NUM_SF' | awk '{print $3}' | grep -q "^1$"); then
		debug "SNAP DMA SF: PER_PF_NUM_SF not enabled, skipping"
		return 1
	fi
	local total_sf
	total_sf=$(echo "$sf_output" | grep -o 'PF_TOTAL_SF.*' | awk '{print $3}' | head -1)
	if [ -n "$total_sf" ] && [ "$total_sf" -lt 1 ] 2>/dev/null; then
		debug "SNAP DMA SF: PF_TOTAL_SF ($total_sf) is 0, no capacity to create SF, skipping"
		return 1
	fi

	# --- Identify the target ECPF on the 2nd PCI link ---
	# a. List all switchdev ECPFs (ASTRA/HW multiplane excluded upstream)
	# b. Find PCI link (domain:bus) of each ECPF
	# c. Find RDMA device for each ECPF
	# d. Eliminate ECPFs that have an RDMA device
	# e. Eliminate ECPFs sharing the same PCI link as RDMA-bearing ECPFs
	# f. Pick the first remaining ECPF
	local links_with_rdma=""
	local dev pci_link rdma_dev

	for dev in ${SWITCHDEV_DEVICES_LIST[@]}; do
		pci_link=$(echo $dev | cut -d: -f1-2)
		rdma_dev=$(/bin/ls /sys/bus/pci/devices/${dev}/infiniband/ 2>/dev/null | head -1)
		if [ -n "$rdma_dev" ]; then
			links_with_rdma="$links_with_rdma $pci_link"
			debug "SNAP DMA SF: ECPF $dev has RDMA device $rdma_dev on link $pci_link"
		fi
	done

	local target_ecpf=""
	local on_rdma_link rdma_link
	for dev in ${SWITCHDEV_DEVICES_LIST[@]}; do
		# Skip if this ECPF has an RDMA device
		rdma_dev=$(/bin/ls /sys/bus/pci/devices/${dev}/infiniband/ 2>/dev/null | head -1)
		if [ -n "$rdma_dev" ]; then
			continue
		fi
		# Skip if this ECPF is on the same PCI link as one with RDMA
		pci_link=$(echo $dev | cut -d: -f1-2)
		on_rdma_link=0
		for rdma_link in $links_with_rdma; do
			if [ "$pci_link" == "$rdma_link" ]; then
				on_rdma_link=1
				break
			fi
		done
		if [ $on_rdma_link -eq 0 ]; then
			target_ecpf=$dev
			break
		fi
	done

	if [ -z "$target_ecpf" ]; then
		debug "SNAP DMA SF: no eligible 2nd-link ECPF found, skipping"
		return 1
	fi

	SNAP_DMA_SF_TARGET_ECPF=$target_ecpf
	info "SNAP DMA SF: target ECPF is $target_ecpf (2nd PCI link)"

	# Determine MAC address:
	# 1. User-specified SNAP_DMA_SF_MAC takes priority
	# 2. Otherwise derive a deterministic MAC from PCI device + sfnum
	#    so the address is stable across reboots
	local snap_dma_sf_mac
	if [ -n "$SNAP_DMA_SF_MAC" ]; then
		snap_dma_sf_mac=$SNAP_DMA_SF_MAC
	else
		snap_dma_sf_mac=$(echo -n "${target_ecpf}:${SNAP_DMA_SF_NUM}" | md5sum | \
			sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
	fi

	info "Creating SNAP DMA SF (sfnum=$SNAP_DMA_SF_NUM, mac=$snap_dma_sf_mac) on $target_ecpf"

	if ! (which mlnx-sf > /dev/null 2>&1); then
		info "mlnx-sf not found, skipping SNAP DMA SF creation"
		return 1
	fi

	# Create SF with RoCE disabled, no netdev
	mlnx-sf --action create --device $target_ecpf \
		--sfnum $SNAP_DMA_SF_NUM \
		--hwaddr $snap_dma_sf_mac \
		--disable-roce 2>/dev/null
	local rc=$?
	if [ $rc -ne 0 ]; then
		debug "SNAP DMA SF on $target_ecpf sfnum=$SNAP_DMA_SF_NUM may already exist or failed (rc=$rc)"
		return 1
	fi

	# Disable netdev on the SF (devlink param netdev_disable=true + reload)
	# Find the auxiliary device for this SF
	local aux_dev=""
	local retries=0
	while [ -z "$aux_dev" ] && [ $retries -lt 20 ]; do
		aux_dev=$(/bin/ls -d /sys/bus/pci/devices/${target_ecpf}/mlx5_core.sf.* 2>/dev/null | \
			xargs -I{} sh -c 'cat {}/sfnum 2>/dev/null | grep -q "^${SNAP_DMA_SF_NUM}$" && basename {}' 2>/dev/null | head -1)
		if [ -z "$aux_dev" ]; then
			sleep 0.1
			retries=$((retries+1))
		fi
	done
	if [ -n "$aux_dev" ]; then
		devlink dev param set auxiliary/${aux_dev} name enable_eth value false cmode driverinit 2>/dev/null
		devlink dev reload auxiliary/${aux_dev} 2>/dev/null
		debug "SNAP DMA SF: disabled netdev on auxiliary/${aux_dev}"
	else
		debug "SNAP DMA SF: could not find auxiliary device to disable netdev"
	fi

	# Bring the SF representor UP (but it must NOT be added to any OVS bridge)
	local sf_rep
	sf_rep=$(mlnx-sf --action show --device $target_ecpf --json 2>/dev/null | \
		python3 -c "import sys,json; data=json.load(sys.stdin); \
		[print(sf.get('netdev','')) for sf in data if str(sf.get('sfnum',''))=='$SNAP_DMA_SF_NUM']" 2>/dev/null | head -1)
	if [ -n "$sf_rep" ]; then
		ip link set $sf_rep up 2>/dev/null
		info "SNAP DMA SF: representor $sf_rep set UP (not added to OVS bridge)"
	fi

	info "Created SNAP DMA SF on $target_ecpf sfnum=$SNAP_DMA_SF_NUM mac=$snap_dma_sf_mac"
	return 0
}

# Run SNAP DMA SF creation if enabled (auto or yes)
if [ "X${SNAP_DMA_SF}" == "Xauto" ] || [ "X${SNAP_DMA_SF}" == "Xyes" ]; then
	create_snap_dma_sf
fi

# Export discovered ECPF ibdevs for SNAP emulation manager auto-configuration
if [ ${#SWITCHDEV_DEVICES_LIST[@]} -gt 0 ]; then
	mkdir -p $(dirname $SNAP_EMULATION_MANAGERS_FILE)
	> $SNAP_EMULATION_MANAGERS_FILE
	for em_dev in ${SWITCHDEV_DEVICES_LIST[@]}; do
		ibdev=$(/bin/ls /sys/bus/pci/devices/${em_dev}/infiniband/ 2>/dev/null | head -1)
		if [ -n "$ibdev" ]; then
			echo "$ibdev $em_dev" >> $SNAP_EMULATION_MANAGERS_FILE
			debug "Exported emulation manager: $ibdev ($em_dev)"
		fi
	done
	info "Exported ${#SWITCHDEV_DEVICES_LIST[@]} emulation managers to $SNAP_EMULATION_MANAGERS_FILE"
fi

debug "num_of_devs_switchdev: $num_of_devs_switchdev"
debug "SWITCHDEV_DEVICES_LIST: ${SWITCHDEV_DEVICES_LIST[*]}"
debug "SD_DEVICES_LIST: ${SD_DEVICES_LIST[*]}"
debug "MH_DEVICES_LIST: ${MH_DEVICES_LIST[*]}"
debug "DEVICE_LIST_FOR_OVS_BRIDGES: ${DEVICE_LIST_FOR_OVS_BRIDGES[*]}"
debug "SD_MERGED_ESWITCH: $SD_MERGED_ESWITCH"

if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then
	info "Running in chroot environment. Exiting..."
	exit 0
fi

if [ $RC -ne 0 ]; then
	error "Exiting due to failures. RC=$RC"
	exit $RC
fi

if [ $num_of_devs_switchdev -eq 0 ]; then
	info "No devices configured to switchdev mod. Skipping SF/Bridges configuration."
	exit 0
fi

if [ -f /etc/mellanox/mlnx-sf.conf ]; then
	. /etc/mellanox/mlnx-sf.conf
fi

HUGEPAGES_TOOL=/usr/sbin/doca-hugepages
OVS_DEFAULT_HUGEPAGE_SIZE=2048
OVS_DEFAULT_HUGEPAGE_NUM=512
OVS_DEFAULT_HUGEPAGE_NUM_BF4=2048
# Marker file to track if OVS_DOCA was previously set to "yes".
# Used to distinguish between OVS_DOCA=no as a default vs. a user
# explicitly switching from yes to no, so we only run cleanup in the latter case.
OVS_DOCA_MARKER=/etc/mellanox/.ovs_doca_configured

add_default_hugepages_configurations()
{
	if [ "X${OVS_DOCA}" != "Xyes" ]; then
		return
	fi
	touch $OVS_DOCA_MARKER
	[ -z "$OVS_HUGEPAGE_SIZE" ] && OVS_HUGEPAGE_SIZE=$OVS_DEFAULT_HUGEPAGE_SIZE
	if [ -z "$OVS_HUGEPAGE_NUM" ]; then
		if is_bf4; then
			OVS_HUGEPAGE_NUM=$OVS_DEFAULT_HUGEPAGE_NUM_BF4
			info "BlueField 4 detected, using 4GB hugepages allocation"
		else
			OVS_HUGEPAGE_NUM=$OVS_DEFAULT_HUGEPAGE_NUM
		fi
	fi
	info "Adding ovs-doca default hugepages configuration"
	$HUGEPAGES_TOOL config --force --app "ovs-doca (default)" --size $OVS_HUGEPAGE_SIZE --num $OVS_HUGEPAGE_NUM
}

config_hugepages()
{
	add_default_hugepages_configurations
	info "Applying hugepages configuration"
	$HUGEPAGES_TOOL reload
}

cleanup_hugepages()
{
	if [ "X${OVS_DOCA}" != "Xyes" ] && [ -f $OVS_DOCA_MARKER ] && $HUGEPAGES_TOOL show | grep -q "ovs-doca"; then
		info "Removing ovs-doca default hugepages configuration"
		$HUGEPAGES_TOOL remove ovs-doca
		$HUGEPAGES_TOOL reload
		rm -f $OVS_DOCA_MARKER
	fi
}

if [ -f /etc/mellanox/mlnx-ovs.conf ]; then
	. /etc/mellanox/mlnx-ovs.conf
fi

# Configure hugepages
config_hugepages

# Configure the default OVS bridge
vsctl=`which ovs-vsctl 2> /dev/null`
if [ ! -n "$vsctl" ]; then
	info "OVS is not installed. Skipping OVS bridges creation."
	exit 0
fi

max_num_of_ovs_bridges=$num_of_devs_switchdev
max_num_of_sd_ovs_bridges=0
num_of_sd_devs=${#SD_DEVICES_LIST[@]}
if [ $num_of_sd_devs -gt 0 ] && [ $SD_MERGED_ESWITCH -eq 0 ]; then
	if [ $num_of_sd_devs -eq 1 ]; then
		max_num_of_sd_ovs_bridges=1
	else
		max_num_of_sd_ovs_bridges=2
	fi
fi

# In SD merged eswitch mode, override to create only 1 bridge
if [ $SD_MERGED_ESWITCH -eq 1 ]; then
	max_num_of_ovs_bridges=1
	max_num_of_sd_ovs_bridges=0
fi

debug "max_num_of_ovs_bridges: $max_num_of_ovs_bridges"
debug "max_num_of_sd_ovs_bridges: $max_num_of_sd_ovs_bridges"

num_of_sd_ovs_bridges=0
num_of_ovs_bridges=0
i=1
for dev in ${DEVICE_LIST_FOR_OVS_BRIDGES[@]}; do
	sd_dev=""
	if [ $num_of_sd_devs -gt 0 ] && [ $SD_MERGED_ESWITCH -eq 0 ]; then
		if in_array $dev ${SD_DEVICES_LIST[@]}; then
			if [ $num_of_sd_ovs_bridges -lt $max_num_of_sd_ovs_bridges ]; then
				num_of_sd_ovs_bridges=$((num_of_sd_ovs_bridges+1))
			else
				continue
			fi
			sd_dev=$dev
		fi
	fi
	bridge_var=OVS_BRIDGE${i}
	ports_var=OVS_BRIDGE${i}_PORTS
	idx=$((i-1))

	# Set default bridge name if not already set
	if [ -z "${!bridge_var}" ]; then
		eval "${bridge_var}=ovsbr${i}"
	fi

	# Set default ports if not already set
	if [ -z "${!ports_var}" ]; then
		eval "${ports_var}=\"$(get_mlnx_netdevs_by_pci_id $dev)\""
		# Workaround: Add extra netdev
		if [ "$dev" == "$sd_dev" ]; then
			num_of_ports=$(wc -w <<< "$ports_var")
			if [ $num_of_ports -lt 4 ]; then
				# Add extra netdev as a workaround for SD device
				# increase the PCIe function nibble by 2
				fn=$(pci_function_digit_value "$dev")
				if [ -n "$fn" ]; then
					new_dev_name=${dev:0:-1}$(printf '%x' "$((fn + 2))")
					extra_netdevs=$(get_mlnx_netdevs_by_pci_id "$new_dev_name")
				else
					extra_netdevs=
				fi
				num_of_extra_netdevs=$(wc -w <<< "$extra_netdevs")
				if [ $num_of_extra_netdevs -eq 1 ]; then
					extra_netdev=$extra_netdevs
				else
					# Choose netdedv that has "pf<num><string>" in its name
					extra_netdev=$(echo "$extra_netdevs" | grep -oE 'pf[0-9][[:alnum:]]+')
				fi
				if [ -n "$extra_netdev" ]; then
					debug "Adding extra netdev $extra_netdev to $ports_var"
					eval "${ports_var}=\"${!ports_var} $extra_netdev\""
				fi
			fi
		fi
	fi
	i=$((i+1))
	num_of_ovs_bridges=$((num_of_ovs_bridges+1))
done

OVS_HW_OFFLOAD=${OVS_HW_OFFLOAD:-"yes"}
OVS_TIMEOUT=${OVS_TIMEOUT:-30}
SKIP_OVS_CONFIG_VALIDATION=${SKIP_OVS_CONFIG_VALIDATION:-"yes"}

ovs_service=""
if [ -e /etc/init.d/openvswitch ]; then
	ovs_service="openvswitch.service"
elif [ -e /usr/lib/systemd/system/openvswitch.service ]; then
	ovs_service="openvswitch.service"
else
	ovs_service=`systemctl list-unit-files 2> /dev/null | grep -E "openvswitch.service|openvswitch.service" | awk '{print $1}'`
fi

if ! (systemctl is-enabled $ovs_service 2> /dev/null | grep -wq enabled); then
	# OVS service is not enabled
	info "$ovs_service is not enabled. Exiting..."
	exit 0
fi

ovs_restart="systemctl restart $ovs_service"

need_restart=false

ovs_restart()
{
	if [ "$need_restart" == "false" ]; then
		info "Restarting of $ovs_service is not required"
		return 0
	fi

	if [ -n "$ovs_service" ]; then
		info "Restarting $ovs_service"
		$ovs_restart
		need_restart=false
	fi

	# Re-apply udev settings removed by OVS
	if [ -x /lib/udev/mlnx_bf_udev ]; then
		for p in $(cd /sys/class/net; /bin/ls -d *)
		do
			case "$p" in
				p*|e*)
				/lib/udev/mlnx_bf_udev $p > /dev/null 2>&1
				;;
				*)
				;;
			esac
		done
	fi

	# Enable hw-tc-offload for all bridge ports dynamically
	for i in `seq $num_of_devs_switchdev`
	do
		br_ports=OVS_BRIDGE${i}_PORTS
		br_ports=${!br_ports}
		for p in $br_ports
		do
			ethtool -K $p hw-tc-offload on
		done
	done
}

{
start_time=$(awk '{print $1}' /proc/uptime)
while ! ($vsctl show > /dev/null 2>&1)
do
	elapsed=$(awk "BEGIN {printf \"%.0f\", $(awk '{print $1}' /proc/uptime) - $start_time}")
	if [ $elapsed -gt $OVS_TIMEOUT ]; then
		info "$ovs_service is not up. Exiting..."
		exit 1
	fi
	sleep 1
done

ovs_config_default_datapath()
{
	ovs_default_datapath=${1:-"system"}

	if !($vsctl get Open_vSwitch . Other_config 2> /dev/null | grep -q "default-datapath-type=$ovs_default_datapath"); then
		$vsctl --no-wait set Open_vSwitch . Other_config:default-datapath-type=$ovs_default_datapath 2> /dev/null
		if [ $? -eq 0 ]; then
			info "OVS default-datapath-type is set"
		fi
	fi

	if !($vsctl get Open_vSwitch . Other_config 2> /dev/null | grep -q "default-datapath-type=$ovs_default_datapath"); then
		error "Failed setting OVS default-datapath-type"
		return 1
	fi
}

ovs_cleanup_doca()
{
	if ($vsctl get Open_vSwitch . Other_config 2> /dev/null | grep -q 'default-datapath-type'); then
		info "OVS cleanup default-datapath-type"
		$vsctl --no-wait remove Open_vSwitch . other_config default-datapath-type
	fi

	if ($vsctl get Open_vSwitch . Other_config 2> /dev/null | grep -q 'doca-init'); then
		info "OVS cleanup doca-init"
		$vsctl --no-wait remove Open_vSwitch . other_config doca-init
		need_restart=true
	fi
}

ovs_config_doca()
{
	local doca_initialized=`$vsctl get Open_vSwitch . doca_initialized`

	if [ "X${OVS_DOCA}" != "Xyes" ]; then
		if [ -f $OVS_DOCA_MARKER ]; then
			ovs_cleanup_doca
			rm -f $OVS_DOCA_MARKER
		fi
		return 0
	fi

	if [ "$doca_initialized" == "true" ]; then
		return 0
	fi

	$vsctl --no-wait set Open_vSwitch . Other_config:doca-init="true" 2> /dev/null
	if ($vsctl get Open_vSwitch . Other_config 2> /dev/null | grep -q 'doca-init="true"'); then
		info "OVS doca-init is set to true"
		need_restart=true
	else
		info "OVS failed setting doca-init to true"
	fi

	ovs_config_default_datapath netdev
}

is_ovs_config_valid()
{
	if [ "X${SKIP_OVS_CONFIG_VALIDATION}" == "Xyes" ]; then
		debug "SKIP_OVS_CONFIG_VALIDATION is set to yes. Skipping OVS configuration validation."
		return 0
	fi

	# Check that all OVS bridges ports exist
	for br in `$vsctl list-br`; do
		for port in `$vsctl list-ports $br`; do
			if echo $port | grep -qE 'vf[0-9]'; then
				# Ignore VF representors
				continue
			elif echo $port | grep -qE 'geneve|vxlan|gre|l2tp|stt'; then
				# Ignore tunnel ports
				continue
			fi
			if ! [ -d /sys/class/net/$port ]; then
				info "Port $port for bridge $br does not exist. OVS configuration is invalid."
				return 1
			fi
		done
	done
	return 0
}

ovs_remove_bridges()
{
	for br in `$vsctl list-br`; do
		$vsctl del-br $br
		debug "Removed bridge $br"
	done
}

#Enable OVS-DOCA
ovs_config_doca

#Cleanup hugepage if neccessary
cleanup_hugepages

CREATE_OVS_BRIDGES=${CREATE_OVS_BRIDGES:-"yes"}
if [ "X${CREATE_OVS_BRIDGES}" != "Xyes" ]; then
    debug "CREATE_OVS_BRIDGES is not set to yes. Skipping OVS bridges creation."
    if [ "$need_restart" == true ]; then
		ovs_restart
    fi
	exit $RC
fi

ovsbr_number=`$vsctl list-br | wc -l`
if [ $ovsbr_number -gt 0 ]; then
	if is_ovs_config_valid; then
		debug "OVS bridges already exist. Skipping OVS bridges creation."
		if ($vsctl get Open_vSwitch . Other_config 2> /dev/null | grep -q 'hw-offload="true"') || [ "$need_restart" == true ]; then
			ovs_restart
		fi
		exit $RC
	else
		info "Removing OVS bridges and creating new ones."
		ovs_remove_bridges
		ovsbr_number=0
	fi
fi

OVS_BR_PORTS_TIMEOUT=${OVS_BR_PORTS_TIMEOUT:-30}
for i in `seq $num_of_ovs_bridges`
do
	br_name=OVS_BRIDGE${i}
	br_name=${!br_name}
	br_ports=OVS_BRIDGE${i}_PORTS
	br_ports=${!br_ports}

	if ($vsctl br-exists $br_name); then
		info "bridge $br_name exist already."
		if ! [[ $(uname -r) =~ "4.19" ]]; then
			ip link set $br_name up
		fi
		continue
	fi

	missing_port=0
	ovs_br_ports=""
	for port in $br_ports
	do
		start_time=$(awk '{print $1}' /proc/uptime)
		while ! [ -d /sys/class/net/$port ]
		do
			elapsed=$(awk "BEGIN {printf \"%.0f\", $(awk '{print $1}' /proc/uptime) - $start_time}")
			if [ $elapsed -gt $OVS_BR_PORTS_TIMEOUT ]; then
				break
			fi
			sleep 1
		done

		if [ -d /sys/class/net/$port ]; then
			ovs_br_ports="$ovs_br_ports $port"
		else
			info "port device $port for bridge $br_name is missing."
			case $port in
				pf*sf*)
					info "RDMA functionality is not expected to work without $port in $br_name"
				;;
				*)
					missing_port=$((missing_port+1))
				;;
			esac
		fi
	done

	if [ $missing_port -gt 0 ]; then
		info "Skipping $br_name configuration."
		continue
	fi

	$vsctl add-br $br_name
	info "Created bridge: $br_name"
	for port in $ovs_br_ports
	do
		$vsctl add-port $br_name $port
		info "bridge $br_name: added port $port"
	done
	if ! [[ $(uname -r) =~ "4.19" ]]; then
		ip link set $br_name up
	fi

done

if [ "X${OVS_HW_OFFLOAD}" == "Xyes" ]; then
	$vsctl --no-wait set Open_vSwitch . Other_config:hw-offload=true
	if [ $? -eq 0 ]; then
		info "OVS HW offload is set"
		info "Going to restart $ovs_service to activate hw-offload"
		need_restart=true
	fi
fi

if [ $need_restart == true ];then
	ovs_restart
fi

#Indication that the script has finished and other underlying services can start
if systemctl is-active --quiet mlnx_bf_configure_sync.service; then
	systemctl stop --no-block mlnx_bf_configure_sync
fi
} &

sync

exit $RC
