Skip to content

Commit

Permalink
Add Devlink functional tests
Browse files Browse the repository at this point in the history
Signed-off-by: Andriy Lozovyy <andriy.lozovyy@plvision.eu>
  • Loading branch information
AndriyLozovyyPLV committed May 2, 2023
1 parent 71c33c2 commit f121a61
Show file tree
Hide file tree
Showing 8 changed files with 981 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
'suite_functional_port_isolation': 'Functional Port Isolation tests',
'suite_functional_igmp': 'IGMP snooping functional tests',
'suite_functional_storm_control': 'Functional Storm Control tests',
'suite_functional_devlink': 'Devlink functional tests',
}

PYTEST_SUITE_GROUPS = {
Expand Down Expand Up @@ -123,5 +124,6 @@
'suite_functional_port_isolation',
'suite_functional_igmp',
'suite_functional_storm_control',
'suite_functional_devlink',
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import pytest
import pytest_asyncio


from dent_os_testbed.utils.test_utils.tgen_utils import (
tgen_utils_get_dent_devices_with_tgen,
)


BASH_UTILS = '''
# Sniff pkt for specified/any interface and return amount of sniffed packets
tcpdump_cpu_traps_rate()
{
local IFACE="any"
if [ $# -ge 1 ]; then IFACE=$1; fi
timeout 1.06 tcpdump -i $IFACE &> xx; cat xx | grep -Eo "[0-9]+ packets received by filter" | cut -d " " -f 1; rm xx
}
# Get average CPU rate by tcpdump
tcpdump_cpu_traps_rate_avg()
{
local start_index=0
local end=25
local counter=0
for((num=start_index; num<=end; num++)); do
local temp=$(tcpdump_cpu_traps_rate $1)
sleep 1
counter=$((counter+temp))
done
echo $((counter/6))
}
# Get CPU rate by reading traps debug counters
get_cpu_traps_rate_code()
{
R1=`cat /sys/kernel/debug/prestera/$2_counters/traps/cpu_code_$1_stats | tr -d "\\0"`
sleep 1
R2=`cat /sys/kernel/debug/prestera/$2_counters/traps/cpu_code_$1_stats | tr -d "\\0"`
RXPPS=`expr $R2 - $R1`
echo $RXPPS
}
# Get average CPU rate by reading traps debug counters
get_cpu_traps_rate_code_avg()
{
local start_index=0
local end=9
local counter=0
for((num=start_index; num<=end; num++)); do
local temp=$(get_cpu_traps_rate_code $1 $2)
sleep 1
counter=$((counter+temp))
done
echo $((counter/10))
}
# Get CPU rate by reading devlink trap counters
get_devlink_cpu_traps_rate()
{
R1=`devlink -vs trap show pci/0000:01:00.0 trap $1 | grep -o "packets.*" | cut -d " " -f 2`
sleep 1
R2=`devlink -vs trap show pci/0000:01:00.0 trap $1 | grep -o "packets.*" | cut -d " " -f 2`
RXPPS=`expr $R2 - $R1`
echo $RXPPS
}
# Get average CPU rate by reading devlink trap counters
get_devlink_cpu_traps_rate_avg()
{
local start_index=0
local end=9
local counter=0
for((num=start_index; num<=end; num++)); do
local temp=$(get_devlink_cpu_traps_rate $1)
sleep 1
counter=$((counter+temp))
done
echo $((counter/10))
}
'''


@pytest_asyncio.fixture()
async def define_bash_utils(testbed):
tgen_dev, dent_devices = await tgen_utils_get_dent_devices_with_tgen(testbed, [], 4)
if not tgen_dev or not dent_devices:
pytest.skip('The testbed does not have enough dent with tgen connections')
dent_dev = dent_devices[0]
func_list = ['tcpdump_cpu_traps_rate', 'tcpdump_cpu_traps_rate_avg', 'get_cpu_traps_rate_code',
'get_cpu_traps_rate_code_avg', 'get_devlink_cpu_traps_rate', 'get_devlink_cpu_traps_rate_avg']
listed_funcs = ' '.join(func_list)
bashrc = '/root/.bashrc'
backup = '/root/.bashrc.bak'

res, _ = await dent_dev.run_cmd(f'type {listed_funcs} > /dev/null 2>&1')
if res:
dent_dev.applog.info(f'Bash func isnt defined: \n{listed_funcs} \nDefining func in .bashrc')
rc, out = await dent_dev.run_cmd(f'cp {bashrc} {backup}', sudo=True)
rc, out = await dent_dev.run_cmd(f"echo '{BASH_UTILS}' >> {bashrc}", sudo=True)
try:
assert not rc
except AssertionError:
_, _ = await dent_dev.run_cmd(f'mv {backup} {bashrc}', sudo=True)
pytest.skip('Skiping test due defining func failed with rc {}'.format(rc))

yield

_, _ = await dent_dev.run_cmd(f'mv {backup} {bashrc}', sudo=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from random import choice
from math import isclose

CPU_MAX_PPS = 4000
CPU_STAT_CODE_ACL_CODE_3 = '195'
DEVIATION = 0.1
RATE_UNITS = {
'bit': 1,
'kbit': 1_000,
'gbit': 1_000_000_000,
'bps': 1 * 8,
'kbps': 1_000 * 8,
'mbps': 1_000_000 * 8,
'gbps': 1_000_000_000 * 8,
'tbps': 1_000_000_000_000 * 8,
}


def randomize_rule_by_src_dst_field(tc_rule, rule_selectors):
"""
Randomize applying rule by choosing src/dst field
Args:
tc_rule (dict): Dict with tc_rule
rule_selectors (dict): Dict with rule selectors
"""
mac, ip, port = choice(['src_mac', 'dst_mac', 'both']), choice(['src_ip', 'dst_ip', 'both']), choice(['src_port', 'dst_port', 'both'])

if mac in ['src_mac', 'dst_mac']:
del tc_rule['filtertype'][mac]
if rule_selectors['want_ip']:
if ip in ['src_ip', 'dst_ip']:
del tc_rule['filtertype'][ip]
if rule_selectors['want_port']:
if port in ['src_port', 'dst_port']:
del tc_rule['filtertype'][port]


def overwrite_src_dst_stream_fields(streams, tc_rule_copy, rule_selectors):
"""
Overwrite streams src/dst fields for mac, ip and ports
Args:
streams (dict): Dict with streams configuration
tc_rule_copy (dict): Copied original tc_rule
rule_selectors (dict): Dict with rule selectors
"""
stream_names = list(streams.keys())
for name in stream_names:
streams[name]['srcMac'] = tc_rule_copy['filtertype']['src_mac']
streams[name]['dstMac'] = tc_rule_copy['filtertype']['dst_mac']
if rule_selectors['want_ip']:
streams[name]['srcIp'] = tc_rule_copy['filtertype']['src_ip']
streams[name]['dstIp'] = tc_rule_copy['filtertype']['dst_ip']
if rule_selectors['want_port']:
streams[name]['srcPort'] = tc_rule_copy['filtertype']['src_port']
streams[name]['dstPort'] = tc_rule_copy['filtertype']['dst_port']
if tc_rule_copy['protocol'] not in ['ipv6', 'ipv4', 'ip', '802.1q']:
streams[name]['protocol'] = tc_rule_copy['protocol']


async def verify_cpu_traps_rate_code_avg(dent_dev, cpu_stat_code, exp_rate, counter_type='sw', deviation=DEVIATION):
"""
Verify cpu trap average rate is equal to expected rate including deviation
Args:
dent_dev: Dent device
cpu_stat_code (str): Cpu code to read counters from
exp_rate (float): Expected rate value
counter_type (str): Type of counters to read (sw or hw)
deviation (float): Deviation percentage
"""
rc, out = await dent_dev.run_cmd(f'get_cpu_traps_rate_code_avg {cpu_stat_code} {counter_type}')
assert not rc, f'get_cpu_traps_rate_code_avg failed with rc {rc}'
actual_rate = int(out.strip())
res = isclose(exp_rate, actual_rate, rel_tol=deviation)
assert res, f'Current rate {actual_rate} exceeds expected rate {exp_rate} including deviation {deviation}'


async def verify_devlink_cpu_traps_rate_avg(dent_dev, trap_code, exp_rate, deviation=DEVIATION):
"""
Verify cpu trap average rate is equal to expected rate including deviation
Args:
dent_dev: Dent device
trap_code (str): Trap code for devlink trap show command
exp_rate (float): Expected rate value
deviation (float): Deviation percentage
"""
rc, out = await dent_dev.run_cmd(f'get_devlink_cpu_traps_rate_avg {trap_code}')
assert not rc, f'get_devlink_cpu_traps_rate_avg failed with rc {rc}'
actual_rate = int(out.strip())
res = isclose(exp_rate, actual_rate, rel_tol=deviation)
assert res, f'Current rate {actual_rate} exceeds expected rate {exp_rate} including deviation {deviation}'
Loading

0 comments on commit f121a61

Please sign in to comment.