HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux WebLive 5.15.0-79-generic #86-Ubuntu SMP Mon Jul 10 16:07:21 UTC 2023 x86_64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //proc/thread-self/root/proc/self/root/usr/local/qcloud/xps/set_xps.sh
#!/bin/bash
cd $(dirname $0)
g_n_dir='/sys/class/net'
g_dir='/usr/local/qcloud'
g_log='/tmp/tlinux_xps.log'
g_mod='/sys/module/virtio_net/parameters/tl2_priv_feature'


g_size=0
function log() {
    local _size=0
    # only call du one time, just assuming this script do
    # not output so many log by one-time running 
    if (( g_size == 0 ))
    then
        _size=$(du -sk "$g_log" 2>/dev/null|cut -f  1)
        g_size=$_size
        #max log size 10MB
        if (( _size > 10240)) 
        then
            mv -f $g_log ${g_log}.1
        fi
    fi
    echo "$(date '+%F_%T') $*"
    echo "$(date '+%F_%T') $*" >> $g_log
}

function check() {
    # if we fix in kernel in the feature, we will
    # add a file to tell we fixed, this script will
    # bypassed. by the wy g_mod is not exit for now #^_^
    local _fixed=$(cat "$g_mod" 2>/dev/null)
    if [[ -n "${_fixed}" ]]
    then
        local _xps_fixed_bit='0x1'
        fixed=$(( _fixed | _xps_fixed_bit ))
        if [[ "$fixed" != '0' ]]
        then
            return 1
        fi
    fi

    #only fix tlinux
    if [[ ! -e '/etc/tlinux-release' ]]
    then
        log "info: /etc/tlinux-release not exist"
        return 1
    fi

    #only fix tkernel3/4
    local os_ver=$(cat '/proc/sys/kernel/osrelease') 
    log "os_ver: $os_ver"

    local k_big_ver=$(echo $os_ver | cut -d '.' -f 1) 
    if (( k_big_ver != 3 && k_big_ver != 4 ))
    then
        return 1
    fi

    local n_need='info: no need set xps'
    # only fix tkernel 3.10.107  
    if (( k_big_ver == 3 ))
    then
        local small_ver=$(echo "$os_ver"|\
              awk -F '-' '/3.10.107.*tlinux2_kvm_guest/{print $NF}'|\
              sed -nr 's/^0*//gp')
        if [[ -z "$small_ver" ]]
        then
            return 1
        fi
        if echo "$small_ver" | grep -qsE '[[:alpha:]]' 
        then
            return 1
        fi
        if (( small_ver < 51 ))
        then
            return 1
        fi
        return 0
    fi
    # and all tkernel 4.19 babababa 4.XXXX 
    return 0
}

#get all virtio_net driver netif
function get_veth_list() {
    local _eths=''
    for _path in ${g_n_dir}/*/device/driver
    do
        local _d_path=$(realpath $_path 2>/dev/null)
        if [[ -z "$_d_path" ]]
        then
            continue
        fi

        local _d_name=$(basename $_d_path 2>/dev/null)
        if [[ "$_d_name" != 'virtio_net' ]]
        then
            continue
        fi

        _eth=$(echo "$_path" | awk -F '/' '{print $(NF-2)}')
        _eths="$_eth $_eths"
    done
    echo "$_eths"
}

#error: return null
#error: return cpumask u32list from list
function u32list() {
    local max_cpu=0
    local cpulist="${1}"
    local ii=0

    if [[ -z "${cpulist}" ]]
    then
        return
    fi

    #find max cpu in cpulist
    local _cpu
    for _cpu in ${cpulist}
    do
        if ((max_cpu < _cpu))
        then
            max_cpu=$_cpu
        fi
    done

    #echo max_cpu=$max_cpu
    #init a bitmap
    for ((ii=0; ii <= max_cpu; ii++))
    do
        map[$ii]=0
    done

    # set bit map according to cpulist
    for _cpu in $cpulist
    do
        map[$_cpu]=1
    done

    #format a u32list
    local seg=0
    local mask=''
    local ii=0
    for ((ii=0; ii <= max_cpu; ii++))
    do
        if (( ii % 4 == 0  && ii != 0))
        then
            seg=$(printf '%0x' $seg)
            mask=${seg}${mask} 
            seg=0
        fi

        if (( ii % 32 == 0 && ii != 0))
        then
            mask=",${mask}"
        fi

        cur=${map[$ii]}
        if ((cur == 1 ))
        then
            val=$((1<<(ii%4)))
            seg=$((seg+val))
        fi
    done

    if [[ "$seg" != '0' ]]
    then
        seg=$(printf '%0x' $seg)
        mask=${seg}${mask}
    fi
    echo "${mask}"
}

function set_eth_xps() {
    local tx_qs=$(ls "${g_n_dir}/${1}/queues" 2>/dev/null|\
                  grep -E '^tx-[[:digit:]]+$'|wc -l)
    if (( tx_qs <= 1 ))
    then
        log "info: eth: $1 qnum: $tx_qs"
        return 0
    fi

    local cpus=$(nproc --all 2>/dev/null)
    if (( cpus <= 1 ))
    then
        log "info: cpus: $cpus"
        return 0
    fi
    #tx_qs=5
    #cpus=100

    #here is what take from tkernel-5.4
    local stride=$((cpus / tx_qs))
    if (( stride == 0 ))
    then
        stride=1
    fi

    local stragglers=0
    if (( cpus > tx_qs ))
    then
        stragglers=$((cpus % tx_qs)) 
    fi

    local _i=0
    local _curcpu=0
    for (( _i=0; _i < tx_qs; _i++ ))
    do
        local _list=''
        local gsize=$stride
        if (( _i < stragglers ))
        then
            gsize=$((gsize + 1 ))
        fi
        local _j=0
        for ((_j=0; _j < gsize; _j++ ))
        do
            _list="$_curcpu $_list"
            ((_curcpu++))
        done

        local mask=$(u32list "$_list")
        log "$mask -> ${g_n_dir}/${1}/queues/tx-${_i}/xps_cpus"
        echo "$mask" > ${g_n_dir}/${1}/queues/tx-${_i}/xps_cpus
    done 
}

function set_eth_xps_numa_sensed()
{
    echo "set_eth_xps_numa_sensed..."
    local tx_qs=$(ls "${g_n_dir}/${1}/queues" 2>/dev/null|\
                  grep -E '^tx-[[:digit:]]+$'|wc -l)
    if (( tx_qs <= 1 ))
    then
        log "info: eth: $1 qnum: $tx_qs"
        return 0
    fi

    local cpus=$(nproc --all 2>/dev/null)
    if (( cpus <= 1 ))
    then
        log "info: cpus: $cpus"
        return 0
    fi

    local numa_cnt=`ls -d /sys/devices/system/node/node*|wc -l`
    local random_tag=`tr -dc 'a-zA-Z0-9' </dev/urandom | head -c 10`
    local cpu_numa_map=/tmp/set_xps_tmpfile.$random_tag
    > $cpu_numa_map
    for ((i = 0; i < numa_cnt; i++)); do
        local numa_cpus=`ls -d /sys/devices/system/node/node$i/cpu*|grep -Po "cpu\d+"|grep -Po "\d+"|sort -n`
        echo $numa_cpus >> $cpu_numa_map
    done

    local curr_idx=1
    local txq_aff_per_numa=$((cpus/numa_cnt/tx_qs))
    local left=$(((cpus/numa_cnt) % tx_qs))
    for ((i = 0; i < tx_qs; i++ )); do
        local aff_pnuma=$txq_aff_per_numa
        [ $((i + left)) -ge $tx_qs ] && aff_pnuma=$((aff_pnuma+1))
        cpulist=`awk -v idx="$curr_idx" -v aff_pnuma="$aff_pnuma" '{for(i=idx;i<idx+aff_pnuma;i++){printf "%d ",$i}}' $cpu_numa_map`
        local mask=$(u32list "$cpulist")
        log "$mask -> ${g_n_dir}/${1}/queues/tx-${i}/xps_cpus"
        echo "$mask" > ${g_n_dir}/${1}/queues/tx-${i}/xps_cpus
        curr_idx=$((curr_idx+aff_pnuma))
    done

    rm -f $cpu_numa_map
}

function set_eth_xps_alternative_queue()
{
    echo "set_eth_xps_alternative_queue..."
    local tx_qs=$(ls "${g_n_dir}/${1}/queues" 2>/dev/null|\
                  grep -E '^tx-[[:digit:]]+$'|wc -l)
    if (( tx_qs <= 1 ))
    then
        log "info: eth: $1 qnum: $tx_qs"
        return 0
    fi

    local cpus=$(nproc --all 2>/dev/null)
    if (( cpus <= 1 ))
    then
        log "info: cpus: $cpus"
        return 0
    fi
    #tx_qs=5
    #cpus=100

    #here is what take from tkernel-5.4
    local stride=$((cpus / tx_qs))
    if (( stride == 0 ))
    then
        stride=1
    fi

    local stragglers=0
    if (( cpus > tx_qs ))
    then
        stragglers=$((cpus % tx_qs))
    fi

    local _i=0
    local _curcpu=0
    for (( _i=0; _i < tx_qs; _i++ ))
    do
        local _list=''
        local gsize=$stride
        if (( _i < stragglers ))
        then
            gsize=$((gsize + 1 ))
        fi
        local _j=0
        _curcpu=$_i
        for ((_j=0; _j < gsize; _j++ ))
        do
            _list="$_curcpu $_list"
            _curcpu=$((_curcpu + tx_qs))
        done

        local mask=$(u32list "$_list")
        log "$mask -> ${g_n_dir}/${1}/queues/tx-${_i}/xps_cpus"
        echo "$mask" > ${g_n_dir}/${1}/queues/tx-${_i}/xps_cpus
    done

}

function set_xps_tlinux() {
    local _eths=$(get_veth_list)
    for _eth in $_eths
    do
        set_eth_xps $_eth
    done
}

function set_xps_generic()
{
    local _eths=$(get_veth_list)
    local _callback=$1
    for _eth in $_eths$
    do
        $_callback $_eth
    done

}

# return 0 is milan baremetal()
function is_milan_baremetal() {
    # Only AMD baremetal has svm feature.
    grep -q svm /proc/cpuinfo
    [ $? != 0 ] && return 1

    # check number check
    local cpunr=`lscpu|grep -i "^CPU(s)"|awk '{print $2}'`
    [ $cpunr != 256 ] && return 1

    lscpu | grep -q "AMD EPYC 7K83 64-Core Processor"
    [ $? != 0 ] && return 1

    return 0
}

# return 0 means OK. return 1 means not found.
function is_target_cpu_baremetal()
{
    grep -Pq "svm|vmx" /proc/cpuinfo
    [ $? != 0 ] && return 1

    local model_name=$(grep -i "model name" /proc/cpuinfo|uniq)
    local found=0
    for model in "$@";do
        echo $model_name|grep -q "$model"
        [ $? == 0 ] && found=1 && echo "found $model_name of $model" && break
    done

    [ $found == 0 ] && return 1 || return 0
}

function is_target_cpu_cvm_numad()
{
    grep -Pq "svm|vmx" /proc/cpuinfo
    [ $? == 0 ] && return 1
    grep -Pq "CVM|KVM" /sys/class/dmi/id/product_name
    [ $? != 0 ] && return 1

    local numa_count=$(ls /sys/bus/node/devices/| wc -l)
    [ $numa_count -le 1 ] && return 1

    local model_name=$(grep -i "model name" /proc/cpuinfo|uniq)
    local found=0
    for model in "$@";do
        echo $model_name|grep -q "$model"
        [ $? == 0 ] && found=1 && echo "found $model_name of $model" && break
    done

    [ $found == 0 ] && return 1 || return 0
}

##<==main
#udev may export a  env var:
#ACTION=='add' when add a nic
#ACTION=='remove' when remove a nic
#we need not to set xps when remove a nic
if [[ ${ACTION} == 'remove' ]]
then
    exit 0
fi

if ! check 
then # Non-tlinux
    # set xps for milan baremetal.
    is_target_cpu_baremetal "7K83"
    [ $? == 0 ] && set_xps_generic set_eth_xps_alternative_queue

    # set xps for icx baremetal.
    #is_target_cpu_baremetal "8372C" "8374B" "8374C"
    #[ $? == 0 ] && set_xps_generic set_eth_xps_numa_sensed
    is_target_cpu_cvm_numad "7K83" "8374B" "8374C" "8372C"
    [ $? == 0 ] && set_xps_generic set_eth_xps_numa_sensed

    exit 0
else
    set_xps_tlinux
    exit 0
fi