Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/dhcp_relay/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def dut_dhcp_relay_data(duthosts, rand_one_dut_hostname, ptfhost, tbinfo):
dhcp_relay_data['uplink_interfaces'] = uplink_interfaces
dhcp_relay_data['uplink_port_indices'] = uplink_port_indices
dhcp_relay_data['switch_loopback_ip'] = str(switch_loopback_ip)
dhcp_relay_data['portchannels'] = mg_facts['minigraph_portchannels']

# Obtain MAC address of an uplink interface because vlan mac may be different than that of physical interfaces
res = duthost.shell('cat /sys/class/net/{}/address'.format(uplink_interfaces[0]))
Expand Down
133 changes: 132 additions & 1 deletion tests/dhcp_relay/test_dhcp_relay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import time
import logging
import re
import json

from tests.common.fixtures.ptfhost_utils import copy_ptftests_directory # noqa F401
from tests.common.fixtures.ptfhost_utils import change_mac_addresses # noqa F401
Expand All @@ -25,6 +26,12 @@
pytest.mark.device_type('vs')
]

SUPPORTED_DHCPV4_TYPE = [
"Unknown", "Discover", "Offer", "Request", "Decline", "Ack", "Nak", "Release", "Inform", "Bootp"
]
SUPPORTED_DIR = ["TX", "RX"]


BROADCAST_MAC = 'ff:ff:ff:ff:ff:ff'
DEFAULT_DHCP_CLIENT_PORT = 68
SINGLE_TOR_MODE = 'single'
Expand Down Expand Up @@ -55,6 +62,111 @@ def check_interface_status(duthost):
return False


def query_dhcpcom_relay_counter_result(duthost, query_key):
'''
Query the DHCPv4 counters from the COUNTERS_DB by the given key.
The returned value is a dictionary and the counter values are converted to integers.

Example return value:
{"TX": {"Unknown": 0, "Discover": 48, "Offer": 0, "Request": 96, "Decline": 0, "Ack": 0, "Nak": 0, "Release": 0,
"Inform": 0, "Bootp": 48}, "RX": {"Unknown": 0, "Discover": 0, "Offer": 1, "Request": 0, "Decline": 0, "Ack": 1,
"Nak": 0, "Release": 0, "Inform": 0, "Bootp": 0}}
'''
counters_query_string = 'sonic-db-cli COUNTERS_DB hgetall "DHCPV4_COUNTER_TABLE:{key}"'
shell_result = json.loads(
duthost.shell(counters_query_string.format(key=query_key))['stdout'].replace("\"", "").replace("'", "\"")
)
return {
rx_or_tx: {
dhcp_type: int(counter_value) for dhcp_type, counter_value in counters.items()
} for rx_or_tx, counters in shell_result.items()}


def query_and_sum_dhcpcom_relay_counters(duthost, vlan_name, interface_name_list):
'''Query the DHCPv4 counters from the COUNTERS_DB and sum the counters for the given interface names.'''
if interface_name_list is None or len(interface_name_list) == 0:
# If no interface names are provided, return the counters for the VLAN interface only.
return query_dhcpcom_relay_counter_result(duthost, vlan_name)
total_counters = {}
# If interface names are provided, sum all of the provided interface names' counters
for interface_name in interface_name_list:
internal_shell_result = query_dhcpcom_relay_counter_result(duthost, vlan_name + ":" + interface_name)
for rx_or_tx, counters in internal_shell_result.items():
total_value = total_counters.setdefault(rx_or_tx, {})
for dhcp_type, counter_value in counters.items():
total_value[dhcp_type] = total_value.get(dhcp_type, 0) + counter_value
return total_counters


def compare_dhcpcom_relay_counter_values(dhcp_relay_counter, expected_counter):
"""Compare the DHCP relay counter value with the expected counter."""
for dir in SUPPORTED_DIR:
for dhcp_type in SUPPORTED_DHCPV4_TYPE:
expected_value = expected_counter.setdefault(dir, {}).get(dhcp_type, 0)
actual_value = dhcp_relay_counter.setdefault(dir, {}).get(dhcp_type, 0)
pytest_assert(actual_value == expected_value,
"DHCP relay counter {} {} is {}, but expected {}".format(dir, dhcp_type,
actual_value,
expected_value))


def validate_dhcpcom_relay_counters(dhcp_relay, duthost, expected_uplink_counter, expected_downlink_counter):
"""Validate the dhcpcom relay counters"""
downlink_vlan_iface = dhcp_relay['downlink_vlan_iface']['name']
# it can be portchannel or interface, it depends on the topology
uplink_portchannels_or_interfaces = dhcp_relay['uplink_interfaces']
client_iface = dhcp_relay['client_iface']['name']
portchannels = dhcp_relay['portchannels']

'''
If the uplink_portchannels_or_interfaces are portchannels,
uplink_interfaces will contains the members of the portchannels
If the uplink_portchannels_or_interfaces are not portchannels,
uplink_interfaces will equal to uplink_portchannels_or_interfaces
'''
uplink_interfaces = []
for portchannel_name in uplink_portchannels_or_interfaces:
if portchannel_name in portchannels.keys():
uplink_interfaces.extend(portchannels[portchannel_name]['members'])
portchannel_counters = query_and_sum_dhcpcom_relay_counters(duthost,
downlink_vlan_iface,
[portchannel_name])
members_counters = query_and_sum_dhcpcom_relay_counters(duthost,
downlink_vlan_iface,
portchannels[portchannel_name]['members'])
pytest_assert(portchannel_counters == members_counters,
"Portchannel {} counters {} are not equal to its members counters {}"
.format(portchannel_name, portchannel_counters, members_counters))
else:
uplink_interfaces.append(portchannel_name)

vlan_interface_counter = query_and_sum_dhcpcom_relay_counters(duthost, downlink_vlan_iface, [])
client_interface_counter = query_and_sum_dhcpcom_relay_counters(duthost, downlink_vlan_iface, [client_iface])
uplink_portchannels_interfaces_counter = query_and_sum_dhcpcom_relay_counters(
duthost, downlink_vlan_iface, uplink_portchannels_or_interfaces
)
uplink_interface_counter = query_and_sum_dhcpcom_relay_counters(duthost, downlink_vlan_iface, uplink_interfaces)

pytest_assert(vlan_interface_counter == client_interface_counter,
"VLAN interface {} counters {} are not equal to client interface {} counters {}"
.format(downlink_vlan_iface, vlan_interface_counter, client_iface, client_interface_counter))
pytest_assert(uplink_interface_counter == uplink_portchannels_interfaces_counter,
"Uplink interfaces {} counters {} are not equal to uplink portchannels or interfaces {} counters {}"
.format(uplink_interfaces, uplink_interface_counter,
uplink_portchannels_or_interfaces, uplink_portchannels_interfaces_counter))
compare_dhcpcom_relay_counter_values(vlan_interface_counter,
expected_downlink_counter)

compare_dhcpcom_relay_counter_values(uplink_interface_counter,
expected_uplink_counter)


def init_dhcpcom_relay_counters(duthost):
command_output = duthost.shell("sudo sonic-clear dhcp_relay ipv4 counters")
pytest_assert("Clear DHCPv4 relay counter done" == command_output["stdout"],
"dhcp_relay counters are not cleared successfully, output: {}".format(command_output["stdout"]))


@pytest.fixture(scope="function")
def enable_source_port_ip_in_relay(duthosts, rand_one_dut_hostname, tbinfo):
duthost = duthosts[rand_one_dut_hostname]
Expand Down Expand Up @@ -133,7 +245,7 @@ def start_dhcp_monitor_debug_counter(duthost):
program_pid_list.append(program_pid)

for program_pid in program_pid_list:
kill_cmd_result = duthost.shell("sudo kill {} || true".format(program_pid), module_ignore_errors=True)
kill_cmd_result = duthost.shell("sudo kill -9 {} || true".format(program_pid), module_ignore_errors=True)
# Get the exit code of 'kill' command
exit_code = kill_cmd_result["rc"]
if exit_code != 0:
Expand Down Expand Up @@ -208,6 +320,7 @@ def test_dhcp_relay_default(ptfhost, dut_dhcp_relay_data, validate_dut_routes_ex
if testing_mode == DUAL_TOR_MODE:
standby_duthost = rand_unselected_dut
start_dhcp_monitor_debug_counter(standby_duthost)
init_dhcpcom_relay_counters(standby_duthost)
expected_standby_agg_counter_message = (
r".*dhcp_relay#dhcpmon\[[0-9]+\]: "
r"\[\s*Agg-%s\s*-[\sA-Za-z0-9]+\s*rx/tx\] "
Expand All @@ -217,6 +330,7 @@ def test_dhcp_relay_default(ptfhost, dut_dhcp_relay_data, validate_dut_routes_ex
marker_standby = loganalyzer_standby.init()
loganalyzer_standby.expect_regex = [expected_standby_agg_counter_message]
start_dhcp_monitor_debug_counter(duthost)
init_dhcpcom_relay_counters(duthost)
if testing_mode == DUAL_TOR_MODE:
expected_agg_counter_message = (
r".*dhcp_relay#dhcpmon\[[0-9]+\]: "
Expand Down Expand Up @@ -262,8 +376,25 @@ def test_dhcp_relay_default(ptfhost, dut_dhcp_relay_data, validate_dut_routes_ex
if not skip_dhcpmon:
time.sleep(36) # dhcpmon debug counter prints every 18 seconds
loganalyzer.analyze(marker)
dhcp_server_sum = len(dhcp_relay['downlink_vlan_iface']['dhcp_server_addrs'])
dhcy_relay_request_times = 2
if testing_mode == DUAL_TOR_MODE:
loganalyzer_standby.analyze(marker_standby)
dhcy_relay_request_times = 1
# If the testing mode is DUAL_TOR_MODE, standby tor's dhcpcom relay counters should all be 0
validate_dhcpcom_relay_counters(dhcp_relay, standby_duthost, {}, {})
expected_downlink_counter = {
"RX": {"Discover": 1, "Request": dhcy_relay_request_times, "Bootp": 1},
"TX": {"Ack": 1, "Offer": 1}
}
expected_uplink_counter = {
"RX": {"Ack": 1, "Offer": 1},
"TX": {"Bootp": dhcp_server_sum, "Discover": dhcp_server_sum,
"Request": dhcp_server_sum * dhcy_relay_request_times}
}
validate_dhcpcom_relay_counters(dhcp_relay, duthost,
expected_uplink_counter,
expected_downlink_counter)
except LogAnalyzerError as err:
logger.error("Unable to find expected log in syslog")
raise err
Expand Down
Loading