Commit 9b75803e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'samples-pktgen-allow-to-specify-destination-IP-range'



Daniel T. Lee says:

====================
samples: pktgen: allow to specify destination IP range

Currently, pktgen script supports specify destination port range.

To further extend the capabilities, this commit allows to specify destination
IP range with CIDR when running pktgen script.

Specifying destination IP range will be useful on various situation such as
testing RSS/RPS with randomizing n-tuple.

This patchset fixes the problem with checking the command result on proc_cmd,
and add feature to allow destination IP range.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents db7fe42d 40f843ee
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ across the sample scripts. Usage example is printed on errors::
 Usage: ./pktgen_sample01_simple.sh [-vx] -i ethX
  -i : ($DEV)       output interface/device (required)
  -s : ($PKT_SIZE)  packet size
  -d : ($DEST_IP)   destination IP
  -d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed
  -m : ($DST_MAC)   destination MAC-addr
  -p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed
  -t : ($THREADS)   threads to start
+145 −9
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@
# Author: Jesper Dangaaard Brouer
# License: GPL

set -o errexit

## -- General shell logging cmds --
function err() {
    local exitcode=$1
@@ -58,6 +60,7 @@ function pg_set() {
function proc_cmd() {
    local result
    local proc_file=$1
    local status=0
    # after shift, the remaining args are contained in $@
    shift
    local proc_ctrl=${PROC_DIR}/$proc_file
@@ -73,14 +76,14 @@ function proc_cmd() {
	echo "cmd: $@ > $proc_ctrl"
    fi
    # Quoting of "$@" is important for space expansion
    echo "$@" > "$proc_ctrl"
    local status=$?
    echo "$@" > "$proc_ctrl" || status=$?

    result=$(grep "Result: OK:" $proc_ctrl)
    # Due to pgctrl, cannot use exit code $? from grep
    if [[ "$proc_file" != "pgctrl" ]]; then
        result=$(grep "Result: OK:" $proc_ctrl) || true
        if [[ "$result" == "" ]]; then
            grep "Result:" $proc_ctrl >&2
        fi
    fi
    if (( $status != 0 )); then
	err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
    fi
@@ -105,6 +108,8 @@ function pgset() {
    fi
}

[[ $EUID -eq 0 ]] && trap 'pg_ctrl "reset"' EXIT

## -- General shell tricks --

function root_check_run_with_sudo() {
@@ -163,6 +168,137 @@ function get_node_cpus()
	echo $node_cpu_list
}

# Check $1 is in between $2, $3 ($2 <= $1 <= $3)
function in_between() { [[ ($1 -ge $2) && ($1 -le $3) ]] ; }

# Extend shrunken IPv6 address.
# fe80::42:bcff:fe84:e10a => fe80:0:0:0:42:bcff:fe84:e10a
function extend_addr6()
{
    local addr=$1
    local sep=: sep2=::
    local sep_cnt=$(tr -cd $sep <<< $1 | wc -c)
    local shrink

    # separator count should be (2 <= $sep_cnt <= 7)
    if ! (in_between $sep_cnt 2 7); then
        err 5 "Invalid IP6 address: $1"
    fi

    # if shrink '::' occurs multiple, it's malformed.
    shrink=( $(egrep -o "$sep{2,}" <<< $addr) )
    if [[ ${#shrink[@]} -ne 0 ]]; then
        if [[ ${#shrink[@]} -gt 1 || ( ${shrink[0]} != $sep2 ) ]]; then
            err 5 "Invalid IP6 address: $1"
        fi
    fi

    # add 0 at begin & end, and extend addr by adding :0
    [[ ${addr:0:1} == $sep ]] && addr=0${addr}
    [[ ${addr: -1} == $sep ]] && addr=${addr}0
    echo "${addr/$sep2/$(printf ':0%.s' $(seq $[8-sep_cnt])):}"
}

# Given a single IP(v4/v6) address, whether it is valid.
function validate_addr()
{
    # check function is called with (funcname)6
    [[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
    local bitlen=$[ IP6 ? 128 : 32 ]
    local len=$[ IP6 ? 8 : 4 ]
    local max=$[ 2**(len*2)-1 ]
    local net prefix
    local addr sep

    IFS='/' read net prefix <<< $1
    [[ $IP6 ]] && net=$(extend_addr6 $net)

    # if prefix exists, check (0 <= $prefix <= $bitlen)
    if [[ -n $prefix ]]; then
        if ! (in_between $prefix 0 $bitlen); then
            err 5 "Invalid prefix: /$prefix"
        fi
    fi

    # set separator for each IP(v4/v6)
    [[ $IP6 ]] && sep=: || sep=.
    IFS=$sep read -a addr <<< $net

    # array length
    if [[ ${#addr[@]} != $len ]]; then
        err 5 "Invalid IP$IP6 address: $1"
    fi

    # check each digit (0 <= $digit <= $max)
    for digit in "${addr[@]}"; do
        [[ $IP6 ]] && digit=$[ 16#$digit ]
        if ! (in_between $digit 0 $max); then
            err 5 "Invalid IP$IP6 address: $1"
        fi
    done

    return 0
}

function validate_addr6() { validate_addr $@ ; }

# Given a single IP(v4/v6) or CIDR, return minimum and maximum IP addr.
function parse_addr()
{
    # check function is called with (funcname)6
    [[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
    local net prefix
    local min_ip max_ip

    IFS='/' read net prefix <<< $1
    [[ $IP6 ]] && net=$(extend_addr6 $net)

    if [[ -z $prefix ]]; then
        min_ip=$net
        max_ip=$net
    else
        # defining array for converting Decimal 2 Binary
        # 00000000 00000001 00000010 00000011 00000100 ...
        local d2b='{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}'
        [[ $IP6 ]] && d2b+=$d2b
        eval local D2B=($d2b)

        local bitlen=$[ IP6 ? 128 : 32 ]
        local remain=$[ bitlen-prefix ]
        local octet=$[ IP6 ? 16 : 8 ]
        local min_mask max_mask
        local min max
        local ip_bit
        local ip sep

        # set separator for each IP(v4/v6)
        [[ $IP6 ]] && sep=: || sep=.
        IFS=$sep read -ra ip <<< $net

        min_mask="$(printf '1%.s' $(seq $prefix))$(printf '0%.s' $(seq $remain))"
        max_mask="$(printf '0%.s' $(seq $prefix))$(printf '1%.s' $(seq $remain))"

        # calculate min/max ip with &,| operator
        for i in "${!ip[@]}"; do
            digit=$[ IP6 ? 16#${ip[$i]} : ${ip[$i]} ]
            ip_bit=${D2B[$digit]}

            idx=$[ octet*i ]
            min[$i]=$[ 2#$ip_bit & 2#${min_mask:$idx:$octet} ]
            max[$i]=$[ 2#$ip_bit | 2#${max_mask:$idx:$octet} ]
            [[ $IP6 ]] && { min[$i]=$(printf '%X' ${min[$i]});
                            max[$i]=$(printf '%X' ${max[$i]}); }
        done

        min_ip=$(IFS=$sep; echo "${min[*]}")
        max_ip=$(IFS=$sep; echo "${max[*]}")
    fi

    echo $min_ip $max_ip
}

function parse_addr6() { parse_addr $@ ; }

# Given a single or range of port(s), return minimum and maximum port number.
function parse_ports()
{
@@ -185,9 +321,9 @@ function validate_ports()
    local min_port=$1
    local max_port=$2

    # 0 < port < 65536
    if [[ $min_port -gt 0 && $min_port -lt 65536 ]]; then
	if [[ $max_port -gt 0 && $max_port -lt 65536 ]]; then
    # 1 <= port <= 65535
    if (in_between $min_port 1 65535); then
	if (in_between $max_port 1 65535); then
	    if [[ $min_port -le $max_port ]]; then
		return 0
	    fi
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ function usage() {
    echo "Usage: $0 [-vx] -i ethX"
    echo "  -i : (\$DEV)       output interface/device (required)"
    echo "  -s : (\$PKT_SIZE)  packet size"
    echo "  -d : (\$DEST_IP)   destination IP"
    echo "  -d : (\$DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed"
    echo "  -m : (\$DST_MAC)   destination MAC-addr"
    echo "  -p : (\$DST_PORT)  destination PORT range (e.g. 433-444) is also allowed"
    echo "  -t : (\$THREADS)   threads to start"
+10 −5
Original line number Diff line number Diff line
@@ -41,9 +41,13 @@ fi
[ -z "$DST_MAC" ] && DST_MAC="90:e2:ba:ff:ff:ff"
[ -z "$BURST" ] && BURST=1024
[ -z "$COUNT" ] && COUNT="10000000" # Zero means indefinitely
if [ -n "$DEST_IP" ]; then
    validate_addr${IP6} $DEST_IP
    read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
fi
if [ -n "$DST_PORT" ]; then
    read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
    validate_ports $DST_MIN $DST_MAX
    read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
    validate_ports $UDP_DST_MIN $UDP_DST_MAX
fi

# Base Config
@@ -71,13 +75,14 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do

    # Destination
    pg_set $dev "dst_mac $DST_MAC"
    pg_set $dev "dst$IP6 $DEST_IP"
    pg_set $dev "dst${IP6}_min $DST_MIN"
    pg_set $dev "dst${IP6}_max $DST_MAX"

    if [ -n "$DST_PORT" ]; then
	# Single destination port or random port range
	pg_set $dev "flag UDPDST_RND"
	pg_set $dev "udp_dst_min $DST_MIN"
	pg_set $dev "udp_dst_max $DST_MAX"
	pg_set $dev "udp_dst_min $UDP_DST_MIN"
	pg_set $dev "udp_dst_max $UDP_DST_MAX"
    fi

    # Inject packet into RX path of stack
+10 −5
Original line number Diff line number Diff line
@@ -24,9 +24,13 @@ if [[ -n "$BURST" ]]; then
    err 1 "Bursting not supported for this mode"
fi
[ -z "$COUNT" ] && COUNT="10000000" # Zero means indefinitely
if [ -n "$DEST_IP" ]; then
    validate_addr${IP6} $DEST_IP
    read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
fi
if [ -n "$DST_PORT" ]; then
    read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
    validate_ports $DST_MIN $DST_MAX
    read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
    validate_ports $UDP_DST_MIN $UDP_DST_MAX
fi

# Base Config
@@ -54,13 +58,14 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do

    # Destination
    pg_set $dev "dst_mac $DST_MAC"
    pg_set $dev "dst$IP6 $DEST_IP"
    pg_set $dev "dst${IP6}_min $DST_MIN"
    pg_set $dev "dst${IP6}_max $DST_MAX"

    if [ -n "$DST_PORT" ]; then
	# Single destination port or random port range
	pg_set $dev "flag UDPDST_RND"
	pg_set $dev "udp_dst_min $DST_MIN"
	pg_set $dev "udp_dst_max $DST_MAX"
	pg_set $dev "udp_dst_min $UDP_DST_MIN"
	pg_set $dev "udp_dst_max $UDP_DST_MAX"
    fi

    # Inject packet into TX qdisc egress path of stack
Loading