#!/bin/bash
#
# Load the PF_RING kernel module and drivers
#

DISTRO="unknown"
if [ -f /lib/lsb/init-functions ]; then
	DISTRO="debian"
	. /lib/lsb/init-functions
fi
if [ -f /etc/init.d/functions ]; then
	DISTRO="centos"
	. /etc/init.d/functions
fi

PF_RING="pf_ring"
PF_RING_CONFIG_DIR="/etc/pf_ring"
DRIVERS_FLAVOR=("zc")
DKMS_DRIVERS=('e1000e' 'igb' 'ixgbe' 'ixgbevf' 'i40e' 'iavf' 'ice')
ERROR=0
DRIVER_INSTALLED=0
OLD_HUGEPAGES_CONFIG="${PF_RING_CONFIG_DIR}/hugepages"
HUGEPAGES_CONFIG="${PF_RING_CONFIG_DIR}/hugepages.conf"
HUGEPAGES_SIZE=`grep Hugepagesize /proc/meminfo | cut -d ':' -f 2|sed 's/kB//g'|sed 's/ //g'` # KB
HUGEPAGES_MOUNTPOINT="/dev/hugepages"
MTU_CONFIG="${PF_RING_CONFIG_DIR}/mtu.conf"
FORCESTART=0
FORCESTART_FILE="${PF_RING_CONFIG_DIR}/pf_ring.start"
DRIVER_FORCESTART_FILE="${PF_RING_CONFIG_DIR}/forcestart" # touch to load zc even if it matches the management
DO_NOT_LOAD_HUGEPAGES=0 # set to 1 to disable hugepages preallocation
LOAD_HUGEPAGES=0
INTERFACES_CONFIG="${PF_RING_CONFIG_DIR}/interfaces.conf"
MEM_AVAIL=1048576 # 1GB Hugepages (this avoids consuming all memory at boot time, causing kernel panic)

# Including interfaces conf containing MANAGEMENT_INTERFACES, CAPTURE_INTERFACES
[ -f ${INTERFACES_CONFIG} ] && . ${INTERFACES_CONFIG}

if [ "${MANAGEMENT_INTERFACES}" != "" ]; then
	MGMT_INTERFACES=($MANAGEMENT_INTERFACES)
else
	MGMT_INTERFACES=("$(/sbin/route | grep default | head -n 1 | tr -s ' ' | cut -d ' ' -f 8)")
fi

function is_management_interface {
	local e
	for e in "${MGMT_INTERFACES[@]}" ; do
		[[ "$e" == "$1" ]] && return 0
	done
	return 1
}

function is_management_interface_driver {
	local e
	for e in "${MGMT_INTERFACES[@]}" ; do
		DRIVER="$(/sbin/ethtool -i "${e}" | grep driver | cut -d ' ' -f 2)"
		[[ "$DRIVER" == "$1" ]] && return 0
	done
	return 1
}

function dkms_installed {
	if [ ${DISTRO} == "debian" ]; then
		if [ `dpkg -l | grep $1-zc-dkms | wc -l` -gt 0 ]; then
			return 0
		fi
	elif [ ${DISTRO} == "centos" ]; then
		if [ `rpm -qa | grep $1-zc | wc -l` -gt 0 ]; then
			return 0
		fi
	fi
	return 1
}

check_pf_ring() {
	# check the module status
	ERROR=0
	WARNING=0
	RETVAL=0
	if [ $1 == "start" ] && [ `lsmod | grep ^${PF_RING} | wc -l ` -gt 0 ]; then
		MSG="PF_RING already loaded."
		WARNING=1
		RETVAL=1
	elif [ $1 == "stop" ] && [ `lsmod | grep ^${PF_RING} | wc -l ` -le 0 ]; then
		MSG="PF_RING already unloaded."
		WARNING=1
		RETVAL=1
	fi

	if [ ${ERROR} -gt 0 ]; then
		if [ ${DISTRO} == "debian" ]; then
			log_failure_msg "${MSG}"
			log_end_msg $ERROR
			exit 99
		elif [ ${DISTRO} == "centos" ]; then
			echo -n ${MSG} 
			echo_failure; echo
			exit 99
		fi
	elif [ ${WARNING} -gt 0 ]; then
		[ ${DISTRO} == "debian" ] && log_daemon_msg "${MSG}"
		[ ${DISTRO} == "centos" ] && echo -n "${MSG}"
		[ ${DISTRO} == "debian" ] && log_end_msg $ERROR
		[ ${DISTRO} == "centos" ] && echo_success && echo
	fi

	return $RETVAL
}

#
# Rebuild DKMS driver
# Parameter is 'pfring' or '<driver>-zc'
#
rebuild_dkms() {
	# Get module version
	MOD_VERSION=""

	# The command below leads to conflicts if old source folders are installed
	#MOD_VERSION=`ls -1d /usr/src/${1}* | tail -1 | cut -d '/' -f 4 | sed -e "s/${1}-//"`

	if [ ${DISTRO} == "debian" ]; then
		SUFFIX="-dkms"
		MOD_VERSION=`dpkg -l | grep ${1}${SUFFIX} | awk '{print $3}'`
	elif [ ${DISTRO} == "centos" ]; then
		SUFFIX=""
		if [ ${1} == "pfring" ]; then
			SUFFIX="-dkms"
		fi
		MOD_VERSION=`rpm -q ${1}${SUFFIX} | cut -d'-' -f3`
	fi

	echo "Uninstalling old ${1} version"
	/usr/sbin/dkms uninstall -m ${1} -v ${MOD_VERSION} > /dev/null
	#/usr/sbin/dkms remove -m ${1} -v ${MOD_VERSION} -k `uname -r` > /dev/null
	/usr/sbin/dkms remove -m ${1} -v ${MOD_VERSION} --all > /dev/null

	echo "Compiling new ${1} driver"
	/usr/sbin/dkms build -m ${1} -v ${MOD_VERSION} > /dev/null

	echo "Installing new ${1} driver"
	/usr/sbin/dkms install -m ${1} -v ${MOD_VERSION} > /dev/null
}

check_hugepages() {
	HUGEPAGES_TOTAL=0
	if [ -f ${HUGEPAGES_CONFIG} ]; then
		while IFS=" " read HUGEPAGES_NODE HUGEPAGES_NUMBER HUGEPAGES_GID; do
			HUGEPAGES_TOTAL=$(( HUGEPAGES_TOTAL + ${HUGEPAGES_NUMBER/hugepagenumber=/} ))
		done < ${HUGEPAGES_CONFIG}
	else
		HUGEPAGES_TOTAL=$(( MEM_AVAIL / HUGEPAGES_SIZE ))
	fi

	#check if huge pages are already loaded and the number of pages are greater than defined or minimum value
	if [ `cat /sys/kernel/mm/hugepages/hugepages-${HUGEPAGES_SIZE}kB/nr_hugepages` -gt ${HUGEPAGES_TOTAL} ] && [ `grep ${HUGEPAGES_MOUNTPOINT} /proc/mounts | wc -l` -gt 0 ]; then
		LOAD_HUGEPAGES=0
		return
	fi
}

unload_hugepages() {
	umount ${HUGEPAGES_MOUNTPOINT}
	echo 0 > /sys/kernel/mm/hugepages/hugepages-${HUGEPAGES_SIZE}kB/nr_hugepages
}

load_hugepages() {
	check_hugepages
	HUGEPAGES_NUMBER=0
	if [ ${LOAD_HUGEPAGES} -eq 0 ]; then
		#hugepages already loaded
		return
	fi

	MOUNT_OPTION=""
	if [ -f ${HUGEPAGES_CONFIG} ]; then
		while read node ; do
			# entry should contain 'node=X hugepagenumber=Y gid=Z'
			HUGEPAGES_NODE=`echo ${node} | cut -d ' ' -f 1 | cut -d '=' -f 2`
			HUGEPAGES_NUMBER=`echo ${node} | cut -d ' ' -f 2 | cut -d '=' -f 2`
			HUGEPAGES_GID=`echo ${node} | cut -d ' ' -f 3 | cut -d '=' -f 2`
			if [[ ${HUGEPAGES_NUMBER} -gt 0 ]] && [ -f /sys/devices/system/node/node${HUGEPAGES_NODE}/hugepages/hugepages-${HUGEPAGES_SIZE}kB/nr_hugepages ]; then
				echo ${HUGEPAGES_NUMBER} > /sys/devices/system/node/node${HUGEPAGES_NODE}/hugepages/hugepages-${HUGEPAGES_SIZE}kB/nr_hugepages
			fi
			if [ -n "$HUGEPAGES_GID" ]; then
				MOUNT_OPTION="-o gid=${HUGEPAGES_GID}"
			fi
			HUGEPAGES_NODE=""
			HUGEPAGES_NUMBER=""
		done <<< "$(cat ${HUGEPAGES_CONFIG})"
	else # set it to default
		# Computing max available
		#MEM_AVAIL=`grep MemFree /proc/meminfo | cut -d ':' -f 2|sed 's/kB//g'|sed 's/ //g'`;
		#MEM_AVAIL=$(( MEM_AVAIL - 524288 ))
		HUGEPAGES_NUMBER=$(( MEM_AVAIL / HUGEPAGES_SIZE ))
		if [[ ${HUGEPAGES_NUMBER} -gt 0 ]]; then
			echo ${HUGEPAGES_NUMBER} > /sys/kernel/mm/hugepages/hugepages-${HUGEPAGES_SIZE}kB/nr_hugepages
		fi
	fi
	if [ `grep ${HUGEPAGES_MOUNTPOINT} /proc/mounts | wc -l` -eq 0 ]; then
		if [ ! -d ${HUGEPAGES_MOUNTPOINT} ]; then
			mkdir ${HUGEPAGES_MOUNTPOINT}
		fi
		mount -t hugetlbfs ${MOUNT_OPTION} none ${HUGEPAGES_MOUNTPOINT}
	fi
}

set_interface_mtu() {
	MTU=""
	if [ -f ${MTU_CONFIG} ]; then 
		HWADDR=`ip link show ${1} | grep -w link/ether | awk '{print $2}'`
		MTU=`grep -w "${HWADDR}" ${MTU_CONFIG} | cut -d ' ' -f 2`
		if [ $((MTU)) -ne 0 ]; then
			/sbin/ifconfig "${1}" mtu ${MTU} > /dev/null 2>&1
		fi
	fi
}

start_interfaces() {
	SETUP_FOR_PACKET_CAPTURE=$1

	if [ "${CAPTURE_INTERFACES}" != "" ]; then
		INTERFACES=($CAPTURE_INTERFACES)
	else
		INTERFACES=($(cat /proc/net/dev | grep ':' | cut -d ':' -f 1|grep -v 'lo' | tr '\n' ' '| sed 's/  / /g'))
	fi

	for D in ${INTERFACES[@]} ; do
		D_PHYSIF=$D

		# Check if this is a VLAN interface
		if [ -f /proc/net/vlan/config ]; then
			D_PHYSIF=`cat /proc/net/vlan/config | awk '/^${D} / {print $5}'`
			if [ -z $D_PHYSIF ]; then
				D_PHYSIF=$D
			fi
		fi

		if [ $SETUP_FOR_PACKET_CAPTURE -eq 1 ] && ! is_management_interface $D_PHYSIF ; then
			# Disabling offloads
			/sbin/ethtool -K "${D}" sg off tso off gso off gro off > /dev/null 2>&1

			# Disabling VLAN stripping
			/sbin/ethtool -K "${D}" rxvlan off > /dev/null 2>&1

			# Disabling Flow Control
			/sbin/ethtool -A "${D}" rx off > /dev/null 2>&1
			/sbin/ethtool -A "${D}" tx off > /dev/null 2>&1

			# Setting max number of RX/TX slots
			MAX_RX_SLOTS=$(/sbin/ethtool -g "${D}" 2>/dev/null | grep "RX" | head -n 1 | cut -d ':' -f 2 | tr -d '\t')
			MAX_TX_SLOTS=$(/sbin/ethtool -g "${D}" 2>/dev/null | grep "TX" | head -n 1 | cut -d ':' -f 2 | tr -d '\t')
			if [ ! -z $MAX_RX_SLOTS ]; then
				/sbin/ethtool -G "${D}" rx ${MAX_RX_SLOTS} 2>/dev/null
				/sbin/ethtool -G "${D}" tx ${MAX_TX_SLOTS} 2>/dev/null
			fi

			set_interface_mtu ${D}
		fi
		/sbin/ifconfig "${D}" up
	done
}

# Configure RSS using ethtool
configure_rss() {
	# Default RSS queues
	DEF_RSS=1

	# Driver name (e.g. mlx5_core)
	D=$1
	# Family (e.g. zc)
	F=$2
	# Configuration name (e.g. mlx)
	C=$3

	# Setting configured number of RSS queues (or default)
	INTERFACES=$(cat /proc/net/dev|grep ':'|grep -v 'lo'|grep -v 'sit'|awk -F":" '{print $1}'|tr -d ' ')
	for IF in $INTERFACES ; do
		D_MATCH=$(ethtool -i $IF|grep "$D\$"|wc -l)

		if [ "$D_MATCH" -eq 1 ]; then
			RSS=$(cat ${PF_RING_CONFIG_DIR}/${F}/${C}/${C}.conf 2>/dev/null | grep RSS | cut -d'=' -f2 | cut -d',' -f1)
			if [ -z "${RSS}" ]; then
				RSS=$DEF_RSS
			fi
			ethtool -L ${IF} combined ${RSS}
		fi
	done
}

load_driver() {
	DRV_PARAM=""

	if [ `/sbin/modinfo ${1}-${2} | wc -l` -gt 1 ]; then
		# driver is available
		DRV_PARAM=`cat ${PF_RING_CONFIG_DIR}/${2}/${1}/${1}.conf | tr '\n' ' '`
		if [ ! -f ${DRIVER_FORCESTART_FILE} ] && is_management_interface_driver ${1} ; then
			echo "Skipping driver ${1}: driver matches the management interface"
			return
		fi

		# unload old module if needed
		if [ `lsmod |grep -w ^${1} | wc -l` -eq 1 ]; then

			# Unload dependencies, if any
			if [ ${1} == "i40e" ]; then
				/sbin/modprobe -r i40iw 2>/dev/null
			fi
			if [ ${1} == "ice" ]; then
				/sbin/modprobe -r irdma 2>/dev/null
			fi

			/sbin/modprobe -r ${1}
			if [ `echo $?` -gt 0 ]; then
				echo "Error unloading driver ${1}"
				return
			fi
		fi

		# check if already loaded
		if [ `lsmod |grep -w ^${1}_${2} | wc -l` -eq 1 ]; then
			echo "Driver ${1}-${2} already installed"
			DRIVER_INSTALLED=1
			return
		fi

		# Check if there is a pre script (e.g. used for VFs configuration)
		DRV_PRE_SCRIPT="${PF_RING_CONFIG_DIR}/${2}/${1}/${1}.pre"
		if [ -x ${DRV_PRE_SCRIPT} ]; then
			${DRV_PRE_SCRIPT}
		fi

		/sbin/modprobe ${1}_${2} ${DRV_PARAM}
		if [ `echo $?` -gt 0 ]; then
			echo "Error loading driver ${1}-${2}"
			# last resort: try rebuilding dkms driver
			rebuild_dkms ${1}-${2}
			# attempt to load the driver now that it has been rebuilt
			/sbin/modprobe ${1}_${2} ${DRV_PARAM}
			if [ `echo $?` -eq 0 ]; then
				DRIVER_INSTALLED=1
			fi
		else 
			DRIVER_INSTALLED=1
		fi

		if [ ${1} == "iavf" ] || [ ${1} == "ixgbevf" ]; then
			# Setting configured number of RSS queues (or default)
			configure_rss ${1} ${2} ${1}
		fi

		# Check if there is a post script
		DRV_POST_SCRIPT="${PF_RING_CONFIG_DIR}/${2}/${1}/${1}.post"
		if [ -x ${DRV_POST_SCRIPT} ]; then
			${DRV_POST_SCRIPT}
		fi

	else
		echo "Driver ${1}-${2} not available"
	fi
}

load_zc() {
	# load dependencies
	/sbin/modprobe uio > /dev/null 2>&1
	/sbin/modprobe ptp > /dev/null 2>&1
	/sbin/modprobe vxlan > /dev/null 2>&1
	/sbin/modprobe dca > /dev/null 2>&1
	/sbin/modprobe configfs > /dev/null 2>&1

	# load dkms drivers
	# search for file under /etc/pf_ring/zc/{e1000e,igb,ixgbe,ixgbevf,i40e,iavf,ice}/{e1000e,igb,ixgbe,ixgbevf,i40e,iavf,ice}.conf
	for F in ${DRIVERS_FLAVOR[@]} ; do
		for D in ${DKMS_DRIVERS[@]} ; do
			if [ -f ${PF_RING_CONFIG_DIR}/${F}/${D}/${D}.conf ] && [ -f ${PF_RING_CONFIG_DIR}/${F}/${D}/${D}.start ]; then
				load_driver ${D} ${F}
				if [ ${F} == "zc" ] && [ ${DO_NOT_LOAD_HUGEPAGES} -eq 0 ]; then
					LOAD_HUGEPAGES=1
				fi
			fi
		done
	done
	
	if hash systemctl 2>/dev/null; then
		if [ `find /etc/systemd/system/multi-user.target.wants/ -name "cluster@*.service" | wc -l ` -ge 1 ]; then
			LOAD_HUGEPAGES=1
		fi
	else
		if [ `grep '\-u\=' /etc/cluster/cluster-*conf 2>/dev/null | wc -l` -ge 1 ] && [ `ls /etc/cluster/cluster-*.start 2>/dev/null | wc -l` -ge 1 ]; then
			LOAD_HUGEPAGES=1
		fi
	fi

	if [ -f ${HUGEPAGES_CONFIG} ] ; then
		LOAD_HUGEPAGES=1
	fi

	if [ ${LOAD_HUGEPAGES} -eq 1 ] ; then
		load_hugepages
	fi
}

load_mlx() {
	# Driver name
	D=mlx5_core
	# Family
	F=zc
	# Configuration name
	C=mlx
	# Default RSS queues
	DEF_RSS=1

	if [ -f ${PF_RING_CONFIG_DIR}/${F}/${C}/${C}.conf ] && [ -f ${PF_RING_CONFIG_DIR}/${F}/${C}/${C}.start ] && [ $(lspci | grep Mellanox | wc -l) -gt 0 ]; then

		# Load required modules
		modprobe -a ib_uverbs mlx5_core mlx5_ib > /dev/null 2>&1

		# Setting configured number of RSS queues (or default)
		configure_rss ${D} ${F} ${C}
	fi
}

load_nt() {
	if [ $(lspci | grep Napatech | wc -l) -gt 0 ] && [ -d "/opt/napatech3" ]; then
		if [ $(ps aux | grep ntservice | grep napatech | wc -l) -eq 0 ]; then
			/opt/napatech3/bin/ntstart.sh
		fi
	fi
}

unload_driver() {
	/sbin/modprobe -r ${1}_${2}
	if [ `echo $?` -gt 0 ]; then
		echo "Error unloading driver ${1}"
		return
	fi

	# Restore vanilla driver
	/sbin/modprobe ${1}
}

unload_zc() {
	UNLOAD_HUGEPAGES=0
	for F in ${DRIVERS_FLAVOR[@]} ; do
		for D in ${DKMS_DRIVERS[@]} ; do
			if [ `/sbin/lsmod | grep -w ^${D}_${F} |wc -l ` -eq 1 ]; then
				unload_driver ${D} ${F}
				if [ ${F} == "zc" ] && [ ${DO_NOT_LOAD_HUGEPAGES} -eq 0 ]; then
					UNLOAD_HUGEPAGES=1
				fi
			fi
		done
	done
	if [ ${UNLOAD_HUGEPAGES} -eq 1 ]; then
		unload_hugepages
	fi
	start_interfaces 0
}

start_pf_ring() {

	init_config

	if [ ! -d /var/lib/dkms/pfring ]; then
		[ ${DISTRO} == "debian" ] && log_daemon_msg "PF_RING kernel module not installed, please install pfring-dkms"
		[ ${DISTRO} == "centos" ] && echo "PF_RING kernel module not installed, please install pfring-dkms"
		return
	fi

	if [ ! -f "${FORCESTART_FILE}" ] && [ ${FORCESTART} -eq 0 ]; then
		# remove pf_ring in any case
		/sbin/modprobe -r pf_ring
		
		echo "PF_RING not enabled: please touch /etc/pf_ring/pf_ring.start"
		[ ${DISTRO} == "debian" ] && log_end_msg $ERROR
		[ ${DISTRO} == "centos" ] && echo_success && echo
		return
	fi

	[ ${DISTRO} == "debian" ] && log_daemon_msg "Starting PF_RING module"
	[ ${DISTRO} == "centos" ] && echo -n "Starting PF_RING module: "

	# Set CPU freq to performance useful in particular
	# on CPUs with aggressive scaling such as Intel E5
	
	find /sys/devices/system/cpu/ -name scaling_governor -exec sh -c 'echo performance > {}' \;

	KERNEL_VERSION=$(uname -r)

	PARAM="$(cat "$PF_RING_CONFIG_DIR/pf_ring.conf")"

	PF_RING_MOD="/lib/modules/$KERNEL_VERSION/kernel/net/pf_ring/pf_ring.ko"
	#PF_RING_MOD_LOCAL="/usr/local/pfring/kernel/pf_ring.ko"

	check_pf_ring start

	if [ $? -ne 0 ]; then
		: # pf_ring.ko already loaded
	else
		# Try loading pfring
		/sbin/modprobe pf_ring $PARAM

		if [ `echo $?` -gt 0 ]; then
			# try building dkms
			rebuild_dkms pfring
			/sbin/modprobe pf_ring $PARAM
		
			# try with local copies in case of failure
			if [ `echo $?` -gt 0 ]; then
				if [ -f $PF_RING_MOD ]; then
					/sbin/insmod $PF_RING_MOD $PARAM
				#elif [ -f $PF_RING_MOD_LOCAL ]; then
				#	/sbin/insmod $PF_RING_MOD_LOCAL $PARAM
				fi
			fi
		fi
	
		if [ `lsmod | grep ^${PF_RING} | wc -l ` -le 0 ] ; then
			# PF_RING not loaded. Exiting
			MSG="Unable to load PF_RING. Exiting"
			ERROR=1
			if [ ${DISTRO} == "debian" ]; then
				log_failure_msg "${MSG}"
				log_end_msg $ERROR
				exit 99
			elif [ ${DISTRO} == "centos" ]; then
				echo -n ${MSG} 
				echo_failure; echo
				exit 99
			fi
		fi
	fi

	## Load NTOP drivers ##
	load_zc

	## Load Mellanox drivers ##
	load_mlx

	## Load Napatech drivers ##
	load_nt

	## Sleep a bit for changes to be applied
	sleep 1

	## Load NTOP drivers ##
	sleep 1

	## Load dummy interfaces associated to timelines or nic cards ##
	local N2IF_SCRIPT="/usr/bin/n2if"
	if [ -f "${N2IF_SCRIPT}" ]; then
		${N2IF_SCRIPT} up-all
		sleep 1
	fi
	
	start_interfaces 1

	[ ${DISTRO} == "debian" ] && log_end_msg $ERROR
	[ ${DISTRO} == "centos" ] && echo_success && echo
}


stop_pf_ring() {

	[ ${DISTRO} == "debian" ] && log_daemon_msg "Stopping PF_RING module"
	[ ${DISTRO} == "centos" ] && echo -n "Stopping PF_RING module: "

	check_pf_ring stop

	if [ $? -ne 0 ]; then
		return
	fi

	if hash systemctl 2>/dev/null && [ -f /etc/systemd/system/nprobe@.service ]; then
		# Systemd will take care of stopping nprobe
		:
	elif [ -f /etc/init.d/nprobe ]; then
		/etc/init.d/nprobe stop
	fi

	if hash systemctl 2>/dev/null && [ -f /etc/systemd/system/n2disk@.service ]; then
		# Systemd will take care of stopping n2disk
		:
	elif [ -f /etc/init.d/n2disk ]; then
		/etc/init.d/n2disk stop
	fi

	if hash systemctl 2>/dev/null && [ -f /etc/systemd/system/ntopng.service ]; then
		# Systemd will take care of stopping ntopng
		:
	elif [ -f /etc/init.d/ntopng ]; then
		/etc/init.d/ntopng stop
	fi

	if hash systemctl 2>/dev/null && [ -f /etc/systemd/system/cento.service ]; then
		# Systemd will take care of stopping cento
		:
	elif [ -f /etc/init.d/cento ]; then
		/etc/init.d/cento stop
	fi

	if hash systemctl 2>/dev/null && [ -f /etc/systemd/system/cluster@.service ]; then
		# Systemd will take care of stopping clusters
		:
	elif [ -f /etc/init.d/cluster ]; then
		/etc/init.d/cluster stop
	fi

	if hash systemctl 2>/dev/null && [ -f /etc/systemd/system/nscrub.service ]; then
		# Systemd will take care of stopping clusters
		:
	elif [ -f /etc/init.d/nscrub ]; then
		/etc/init.d/nscrub stop
	fi

	sleep 1

	## Unload drivers ##
	unload_zc

	NUM="$(grep pf_ring /proc/modules|wc -l)"
	if [ $NUM -gt 0 ]; then
	/sbin/modprobe -r pf_ring
		NUM="$(grep pf_ring /proc/modules|wc -l)"
	if [ ${NUM} -gt 0 ]; then
		MSG="unable to unload PF_RING module"
			[ ${DISTRO} == "debian" ] && log_failure_msg "$MSG"
			[ ${DISTRO} == "centos" ] && echo_failure
			ERROR=1
	fi
	fi
	[ ${DISTRO} == "debian" ] && log_end_msg $ERROR
	[ ${DISTRO} == "centos" ] && echo_success && echo
}

check_driver_status() {
	local NUM_CONFIGED_DRIVERS=0
	local NUM_LOADED_DRIVERS=0
	local UNLOADED_DRIVERS=()
	for F in ${DRIVERS_FLAVOR[@]} ; do
		for D in ${DKMS_DRIVERS[@]} ; do
			if [ -f ${PF_RING_CONFIG_DIR}/${F}/${D}/${D}.conf ] && [ -f ${PF_RING_CONFIG_DIR}/${F}/${D}/${D}.start ]; then
				NUM_CONFIGED_DRIVERS=$((NUM_CONFIGED_DRIVERS+1))
				if [ `lsmod |grep -w ^${D}_${F} | wc -l` -eq 1 ]; then
					NUM_LOADED_DRIVERS=$((NUM_LOADED_DRIVERS+1))
				else
					UNLOADED_DRIVERS+=(${D}_${F})
				fi
			fi
		done
	done
	if [ $NUM_CONFIGED_DRIVERS -eq $NUM_LOADED_DRIVERS ]; then
		echo "UP"
	else
		local MSG="The following drivers has not been loaded: "
		for driver in ${UNLOADED_DRIVERS[@]}; do
			 MSG+="$driver "
		done
		echo "$MSG"
	fi
}

check_pf_ring_status() {
	# check the module status
	if [ -f ${PF_RING_CONFIG_DIR}/${PF_RING}.conf ] && [ -f ${PF_RING_CONFIG_DIR}/${PF_RING}.start ]; then
		if [ `lsmod | grep ^${PF_RING} | wc -l` -gt 0 ]; then
			echo "UP"
		elif [ `lsmod | grep ^${PF_RING} | wc -l` -le 0 ]; then
			local MSG="pf_ring module not running"
			echo "$MSG"
		fi
	fi

}

get_status() {
	EXIT_CODE=0
	driver_result=$(check_driver_status);
	pf_ring_result=$(check_pf_ring_status);

	if [[ $driver_result == UP* ]]; then
		echo "Drivers Loaded"
	else
		echo "$driver_result"
		EXIT_CODE=3
	fi

	if [[ $pf_ring_result == UP* ]]; then
		echo "pf_ring Loaded"
	else
		echo "$pf_ring_result"
		EXIT_CODE=3
	fi

	exit "$EXIT_CODE"
}

init_config() {
	if [ -f "${PF_RING_CONFIG_DIR}/pf_ring.conf" ]; then
		return # PF_RING already configured, do not change the current conf
	fi

	# Create an initial configuration structure 

	if [ ! -d "${PF_RING_CONFIG_DIR}" ]; then
		mkdir ${PF_RING_CONFIG_DIR}
	fi
	if [ ! -f "${PF_RING_CONFIG_DIR}/pf_ring.conf" ]; then
		touch "${PF_RING_CONFIG_DIR}/pf_ring.conf"
	fi
	if [ ! -f "${PF_RING_CONFIG_DIR}/pf_ring.start" ]; then
		touch "${PF_RING_CONFIG_DIR}/pf_ring.start"
	fi
	if [ ! -f ${INTERFACES_CONFIG} ]; then
		touch "${INTERFACES_CONFIG}"
		echo "#MANAGEMENT_INTERFACES=\"eth0\"" >> ${INTERFACES_CONFIG}
		echo "#CAPTURE_INTERFACES=\"eth1 eth2\"" >> ${INTERFACES_CONFIG}
	fi 
	for F in ${DRIVERS_FLAVOR[@]} ; do
		for D in ${DKMS_DRIVERS[@]} ; do
			if [ ! -d ${PF_RING_CONFIG_DIR}/${F}/${D} ]; then
				mkdir -p ${PF_RING_CONFIG_DIR}/${F}/${D}
			fi
		done
	done
}
########

echo "$(/bin/date) pf_ringctl $1" >> /var/log/ntop-systemd.log

case "$1" in
  start)
	FORCESTART=1
	start_pf_ring;
	;;

  start-if-enabled)
	start_pf_ring;
	;;

  stop)
	stop_pf_ring;
	;;

  restart)
	FORCESTART=1
	stop_pf_ring;
	start_pf_ring;
	;;

  restart-if-enabled)
	stop_pf_ring;
	start_pf_ring;
	;;

  status)
	get_status;
	;;

  *)
	echo "Usage: ${0} {start|stop|restart|status}"
	exit 1
esac

echo "$(/bin/date) pf_ringctl done" >> /var/log/ntop-systemd.log

exit 0
