^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) # Common functions used by pktgen scripts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) # - Depending on bash 3 (or higher) syntax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) # Author: Jesper Dangaaard Brouer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) # License: GPL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) set -o errexit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) ## -- General shell logging cmds --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) function err() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) local exitcode=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) echo "ERROR: $@" >&2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) exit $exitcode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) function warn() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) echo "WARN : $@" >&2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) function info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) if [[ -n "$VERBOSE" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) echo "INFO : $@" >&2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) ## -- Pktgen proc config commands -- ##
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) export PROC_DIR=/proc/net/pktgen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) # Three different shell functions for configuring the different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) # components of pktgen:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) # pg_ctrl(), pg_thread() and pg_set().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) # These functions correspond to pktgens different components.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) # * pg_ctrl() control "pgctrl" (/proc/net/pktgen/pgctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) # * pg_thread() control the kernel threads and binding to devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) # * pg_set() control setup of individual devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) function pg_ctrl() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) local proc_file="pgctrl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) proc_cmd ${proc_file} "$@"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) function pg_thread() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) local thread=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) local proc_file="kpktgend_${thread}"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) proc_cmd ${proc_file} "$@"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) function pg_set() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) local dev=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) local proc_file="$dev"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) proc_cmd ${proc_file} "$@"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) # More generic replacement for pgset(), that does not depend on global
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) # variable for proc file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) function proc_cmd() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) local result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) local proc_file=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) local status=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) # after shift, the remaining args are contained in $@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) local proc_ctrl=${PROC_DIR}/$proc_file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if [[ ! -e "$proc_ctrl" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) err 3 "proc file:$proc_ctrl does not exists (dev added to thread?)"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if [[ ! -w "$proc_ctrl" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) err 4 "proc file:$proc_ctrl not writable, not root?!"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if [[ "$DEBUG" == "yes" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) echo "cmd: $@ > $proc_ctrl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) # Quoting of "$@" is important for space expansion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) echo "$@" > "$proc_ctrl" || status=$?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if [[ "$proc_file" != "pgctrl" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) result=$(grep "Result: OK:" $proc_ctrl) || true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if [[ "$result" == "" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) grep "Result:" $proc_ctrl >&2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (( $status != 0 )); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) # Old obsolete "pgset" function, with slightly improved err handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) function pgset() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) local result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if [[ "$DEBUG" == "yes" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) echo "cmd: $1 > $PGDEV"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) echo $1 > $PGDEV
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) local status=$?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) result=`cat $PGDEV | fgrep "Result: OK:"`
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if [[ "$result" == "" ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) cat $PGDEV | fgrep Result:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (( $status != 0 )); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) err 5 "Write error($status) occurred cmd: \"$1 > $PGDEV\""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) [[ $EUID -eq 0 ]] && trap 'pg_ctrl "reset"' EXIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ## -- General shell tricks --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) function root_check_run_with_sudo() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) # Trick so, program can be run as normal user, will just use "sudo"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) # call as root_check_run_as_sudo "$@"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if [ "$EUID" -ne 0 ]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if [ -x $0 ]; then # Directly executable use sudo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) info "Not root, running with sudo"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) sudo "$0" "$@"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) exit $?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) err 4 "cannot perform sudo run of $0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) # Exact input device's NUMA node info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) function get_iface_node()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) local node=$(</sys/class/net/$1/device/numa_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if [[ $node == -1 ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) echo 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) echo $node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) # Given an Dev/iface, get its queues' irq numbers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) function get_iface_irqs()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) local IFACE=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) local queues="${IFACE}-.*TxRx"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) irqs=$(grep "$queues" /proc/interrupts | cut -f1 -d:)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) [ -z "$irqs" ] && irqs=$(grep $IFACE /proc/interrupts | cut -f1 -d:)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) [ -z "$irqs" ] && irqs=$(for i in `ls -Ux /sys/class/net/$IFACE/device/msi_irqs` ;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) do grep "$i:.*TxRx" /proc/interrupts | grep -v fdir | cut -f 1 -d : ;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) done)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) [ -z "$irqs" ] && err 3 "Could not find interrupts for $IFACE"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) echo $irqs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) # Given a NUMA node, return cpu ids belonging to it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) function get_node_cpus()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) local node=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) local node_cpu_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) local node_cpu_range_list=`cut -f1- -d, --output-delimiter=" " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /sys/devices/system/node/node$node/cpulist`
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) for cpu_range in $node_cpu_range_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) node_cpu_list="$node_cpu_list "`seq -s " " ${cpu_range//-/ }`
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) echo $node_cpu_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) # Check $1 is in between $2, $3 ($2 <= $1 <= $3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) function in_between() { [[ ($1 -ge $2) && ($1 -le $3) ]] ; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) # Extend shrunken IPv6 address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) # fe80::42:bcff:fe84:e10a => fe80:0:0:0:42:bcff:fe84:e10a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) function extend_addr6()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) local addr=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) local sep=: sep2=::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) local sep_cnt=$(tr -cd $sep <<< $1 | wc -c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) local shrink
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) # separator count should be (2 <= $sep_cnt <= 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if ! (in_between $sep_cnt 2 7); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) err 5 "Invalid IP6 address: $1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) # if shrink '::' occurs multiple, it's malformed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) shrink=( $(egrep -o "$sep{2,}" <<< $addr) )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if [[ ${#shrink[@]} -ne 0 ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if [[ ${#shrink[@]} -gt 1 || ( ${shrink[0]} != $sep2 ) ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) err 5 "Invalid IP6 address: $1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) # add 0 at begin & end, and extend addr by adding :0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) [[ ${addr:0:1} == $sep ]] && addr=0${addr}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) [[ ${addr: -1} == $sep ]] && addr=${addr}0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) echo "${addr/$sep2/$(printf ':0%.s' $(seq $[8-sep_cnt])):}"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) # Given a single IP(v4/v6) address, whether it is valid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) function validate_addr()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) # check function is called with (funcname)6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) [[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) local bitlen=$[ IP6 ? 128 : 32 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) local len=$[ IP6 ? 8 : 4 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) local max=$[ 2**(len*2)-1 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) local net prefix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) local addr sep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) IFS='/' read net prefix <<< $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) [[ $IP6 ]] && net=$(extend_addr6 $net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) # if prefix exists, check (0 <= $prefix <= $bitlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if [[ -n $prefix ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if ! (in_between $prefix 0 $bitlen); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) err 5 "Invalid prefix: /$prefix"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) # set separator for each IP(v4/v6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) [[ $IP6 ]] && sep=: || sep=.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) IFS=$sep read -a addr <<< $net
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) # array length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if [[ ${#addr[@]} != $len ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) err 5 "Invalid IP$IP6 address: $1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) # check each digit (0 <= $digit <= $max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) for digit in "${addr[@]}"; do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) [[ $IP6 ]] && digit=$[ 16#$digit ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if ! (in_between $digit 0 $max); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) err 5 "Invalid IP$IP6 address: $1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) function validate_addr6() { validate_addr $@ ; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) # Given a single IP(v4/v6) or CIDR, return minimum and maximum IP addr.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) function parse_addr()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) # check function is called with (funcname)6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) [[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) local net prefix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) local min_ip max_ip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) IFS='/' read net prefix <<< $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) [[ $IP6 ]] && net=$(extend_addr6 $net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if [[ -z $prefix ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) min_ip=$net
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) max_ip=$net
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) # defining array for converting Decimal 2 Binary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) # 00000000 00000001 00000010 00000011 00000100 ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) local d2b='{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) [[ $IP6 ]] && d2b+=$d2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) eval local D2B=($d2b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) local bitlen=$[ IP6 ? 128 : 32 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) local remain=$[ bitlen-prefix ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) local octet=$[ IP6 ? 16 : 8 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) local min_mask max_mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) local min max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) local ip_bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) local ip sep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) # set separator for each IP(v4/v6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) [[ $IP6 ]] && sep=: || sep=.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) IFS=$sep read -ra ip <<< $net
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) min_mask="$(printf '1%.s' $(seq $prefix))$(printf '0%.s' $(seq $remain))"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) max_mask="$(printf '0%.s' $(seq $prefix))$(printf '1%.s' $(seq $remain))"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) # calculate min/max ip with &,| operator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) for i in "${!ip[@]}"; do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) digit=$[ IP6 ? 16#${ip[$i]} : ${ip[$i]} ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) ip_bit=${D2B[$digit]}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) idx=$[ octet*i ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) min[$i]=$[ 2#$ip_bit & 2#${min_mask:$idx:$octet} ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) max[$i]=$[ 2#$ip_bit | 2#${max_mask:$idx:$octet} ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) [[ $IP6 ]] && { min[$i]=$(printf '%X' ${min[$i]});
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) max[$i]=$(printf '%X' ${max[$i]}); }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) min_ip=$(IFS=$sep; echo "${min[*]}")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) max_ip=$(IFS=$sep; echo "${max[*]}")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) echo $min_ip $max_ip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) function parse_addr6() { parse_addr $@ ; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) # Given a single or range of port(s), return minimum and maximum port number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) function parse_ports()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) local port_str=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) local port_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) local min_port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) local max_port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) IFS="-" read -ra port_list <<< $port_str
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) min_port=${port_list[0]}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) max_port=${port_list[1]:-$min_port}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) echo $min_port $max_port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) # Given a minimum and maximum port, verify port number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) function validate_ports()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) local min_port=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) local max_port=$2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) # 1 <= port <= 65535
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (in_between $min_port 1 65535); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (in_between $max_port 1 65535); then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if [[ $min_port -le $max_port ]]; then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) err 5 "Invalid port(s): $min_port-$max_port"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }