Skip to content

Commit

Permalink
Merge pull request #1097 from tempesta-tech/ao-1073
Browse files Browse the repository at this point in the history
Fix #1073: Add support MSI/MSI-X interrupts during NIC queues configuration
  • Loading branch information
aleksostapenko authored Nov 21, 2018
2 parents c662213 + 7ea10c5 commit 774869c
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 30 deletions.
8 changes: 7 additions & 1 deletion scripts/tempesta.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ tdb_mod=tempesta_db
tfw_mod=tempesta_fw
declare -r LONG_OPTS="help,load,unload,start,stop,restart,reload"

declare devs=$(ip addr show up | awk '/^[0-9]+/ { sub(/:/, "", $2); print $2}')
# Exclude loopback interface since it needn't any tuning here: it hasn't RSS
# while RPS just add unnecessary overhead for it (traffic redistribution, IPIs
# introduction etc.).
declare devs=$(ip addr show up | grep -P '^[0-9]+' | grep -Pv '\bLOOPBACK\b' \
| awk '{ sub(/:/, "", $2); print $2}')

usage()
{
Expand Down Expand Up @@ -204,6 +208,8 @@ stop()
echo "...unload Tempesta modules"
unload_modules

tfw_irqbalance_revert

echo "done"
}

Expand Down
141 changes: 112 additions & 29 deletions scripts/tfw_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,100 @@ declare -r TFW_NAME=`basename $0` # program name (comm name in ps)
declare -r TFW_NETDEV_PATH="/sys/class/net/"
declare -r TFW_SCRIPTS="$TFW_ROOT/scripts"
declare -r CPUS_N=$(grep -c processor /proc/cpuinfo)
declare -r IRQB_CONF_PATH="/etc/default/irqbalance"
declare -r SYSD_IRQB_PATH="/lib/systemd/system/irqbalance.service"
declare -r BAN_CONF_VAR="TFW_BAN_IRQS"
declare -a IRQS_GLOB_LIST

calc()
{
echo "$1" | bc -iq | tail -1
}

# Assigned IRQs can be reassigned by irqbalance. To avoid this, assigned
# vectors should be added to irqbalance config with '--banirq' option.
irqbalance_ban_irqs()
{
args_str=""
sysd_conf_var="ExecStart"

echo "...ban IRQs for irqbalance..."
for irq in ${IRQS_GLOB_LIST[@]}; do
args_str=$args_str"--banirq=$irq "
done

conf_var_str="$BAN_CONF_VAR=$args_str"
perl -i.orig -ple '
if (/^'"$BAN_CONF_VAR"'=.*$/) {
$_ = "'"$conf_var_str"'";
$found = 1;
}
END {
unless ($found) {
open(CONFIG, ">>", $ARGV);
select(CONFIG);
print("\n# Do not edit this variable. It is"
. " automatically generated by start\n#"
. " script of Tempesta FW and is intended"
. " to avoid reassigning of specified"
. " IRQs.");
printf("%s\n", "'"$conf_var_str"'");
select(STDOUT);
}
}
' $IRQB_CONF_PATH

perl -i.orig -ple '
if (/^('"$sysd_conf_var"'=.*)$/) {
unless (/.*\$'"$BAN_CONF_VAR"'\b.*/) {
$_ = $1 . " \$'"$BAN_CONF_VAR"'";
}
}
' $SYSD_IRQB_PATH

systemctl daemon-reload >/dev/null
systemctl restart irqbalance.service >/dev/null
}

distribute_queues()
{
dev=$1
RXQ_MAX=$(ethtool -l $dev 2>/dev/null \
| grep -m 1 RX | sed -e 's/RX\:\s*//')

echo "...distribute $dev queues"

if [ -n "$RXQ_MAX" -a ${RXQ_MAX:-0} -gt 0 ]; then
echo "...set rx channels to $RXQ_MAX, please wait..."
# Set maximum number of available channels for better
# packets hashing.
ethtool -L $dev rx $RXQ_MAX >/dev/null 2>&1
# Wait for the interface reconfiguration.
opstate="$TFW_NETDEV_PATH/$dev/operstate"
while [ "$(cat $opstate)" = "down" ]; do
sleep 1
done
else
echo "...0 channels for $dev - skip"
RXQ_MAX=$2

echo "...set rx channels to $RXQ_MAX, please wait..."
# Set maximum number of available channels for better
# packets hashing.
res=$(ethtool -L $dev rx $RXQ_MAX 2>&1)
if [ $? -ne 0 -a -z "$(echo $res | grep -P '^rx unmodified, ignoring')" ]
then
printf "Error: cannot set new queues count for %s:\n %s\n" \
$dev "$res"
return
fi

# Wait for the interface reconfiguration.
opstate="$TFW_NETDEV_PATH/$dev/operstate"
while [ "$(cat $opstate)" = "down" ]; do
sleep 1
done

# Interrupts may not have interface-like description in
# '/proc/interrupts' - so, to find the vectors we also need
# to check the MSI directory for device.
dev_irqs_path="/sys/class/net/$dev/device/msi_irqs"
irqs=($(grep $dev /proc/interrupts | sed -e 's/\s*\|:.*//g'))
if [ -z "$irqs" -a -d $dev_irqs_path ]; then
irqs=($(ls $dev_irqs_path))
fi

if [ -z "$irqs" ]; then
echo "Error: cannot find interrupts for $dev"
return
fi

# Skip the first IRQ since this is general async interrupt
# for device (not assigned to any of the queues).
irqs=(${irqs[@]:1})
irq0=${irqs[0]}
for i in ${irqs[@]}; do
# Wrap around CPU mask if number of queues is
Expand All @@ -74,33 +138,52 @@ distribute_queues()
}
' > /proc/irq/$i/smp_affinity
done

IRQS_GLOB_LIST+=(${irqs[@]})
}

# Enable RPS for specified, or all by default, networking interfaces.
# This is required for loopback interface for proper local delivery,
# but physical interfaces can have RSS.
# Enable RSS for networking interfaces. Enable RPS for those devices which
# doesn't have enough hardware queues.
tfw_set_net_queues()
{
devs=$1
min_queues=$(calc "$CPUS_N / 2")
cpu_mask=$(perl -le 'printf("%x", (1 << '$CPUS_N') - 1)')

for dev in $devs; do
queues=$(ls -d /sys/class/net/$dev/queues/rx-* | wc -l)
if [ $queues -le $min_queues ]; then
echo "...enable RPS on $dev"
for rx in $TFW_NETDEV_PATH/$dev/queues/rx-*; do
echo $cpu_mask > $rx/rps_cpus
done
else

queues=$(ethtool -l $dev 2>/dev/null \
| grep -m 1 RX | sed -e 's/RX\:\s*//')
if [ -n "$queues" -a ${queues:-0} -gt $min_queues ]; then
# Switch off RPS for multi-queued interfaces.
for rx in $TFW_NETDEV_PATH/$dev/queues/rx-*; do
echo 0 > $rx/rps_cpus
done

distribute_queues $dev
echo "...distribute $dev queues"
distribute_queues $dev $queues
else
echo "...enable RPS on $dev"
for rx in $TFW_NETDEV_PATH/$dev/queues/rx-*; do
echo $cpu_mask > $rx/rps_cpus
done
fi
done

if [ ${#IRQS_GLOB_LIST[@]} -ne 0 -a -f $SYSD_IRQB_PATH \
-a -f $IRQB_CONF_PATH ]; then
systemctl status irqbalance.service >/dev/null
[ $? -ne 0 ] || irqbalance_ban_irqs
fi
}

tfw_irqbalance_revert()
{
systemctl status irqbalance.service >/dev/null
if [ $? -eq 0 -a -f $IRQB_CONF_PATH ]; then
echo "...revert irqbalance config"
perl -i.orig -ple '
s/^('"$BAN_CONF_VAR"'=).*$/$1/;
' $IRQB_CONF_PATH
systemctl restart irqbalance.service >/dev/null
fi
}

0 comments on commit 774869c

Please sign in to comment.