Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
152 changes: 151 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 Expand Up @@ -299,6 +430,7 @@ def test_dhcp_relay_with_source_port_ip_in_relay_enabled(ptfhost, dut_dhcp_relay
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 @@ -308,6 +440,7 @@ def test_dhcp_relay_with_source_port_ip_in_relay_enabled(ptfhost, dut_dhcp_relay
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 @@ -354,8 +487,25 @@ def test_dhcp_relay_with_source_port_ip_in_relay_enabled(ptfhost, dut_dhcp_relay
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