Skip to content
Draft
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
55 changes: 38 additions & 17 deletions ansible/roles/test/files/ptftests/py3/dhcp_relay_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@
self.portchannels_ip_list = self.test_params.get('portchannels_ip_list', None)
self.agent_relay_mode = self.test_params.get('agent_relay_mode', None)
self.max_hop_count = self.test_params.get('max_hop_count', None)
self.client_giaddr = self.test_params.get('client_giaddr', self.switch_loopback_ip)
self.expected_forward = self.test_params.get('expected_forward', None)
self.client_vrf = self.test_params.get('client_vrf', None)
self.dhcpv4_disable_flag = self.test_params.get('dhcpv4_disable_flag', None)
if self.relay_agent == "sonic-relay-agent":
Expand Down Expand Up @@ -211,6 +213,8 @@
self.option82 += struct.pack('BB', self.REMOTE_ID_SUBOPTION, len(remote_id_string))
self.option82 += remote_id_string.encode('utf-8')

self.client_option82 = b'\x01\x07Vlan100\x02\x06\x11\x22\x33\x44\x55\x66'

link_selection_added = False # set below; dual-tor block skips SubOption 5 if set

if self.relay_agent == "sonic-relay-agent":
Expand Down Expand Up @@ -286,24 +290,14 @@
discover_packet[scapy.IP].dst = self.switch_loopback_ip
discover_packet[scapy.IP].src = self.client_ip
else:
# Sub-option 1: Circuit ID (VLAN 100)
# Circuit ID sub-option type 1, length 7, data 'Vlan100'
circuit_id = b'\x01' + bytes([7]) + b'Vlan100'

# Sub-option 2: Remote ID (MAC address)
# Remote ID sub-option type 2, length 6, MAC address
remote_id = b'\x02' + bytes([6]) + bytes.fromhex("112233445566")
# Combine the new sub-options for relay
relay_option82 = circuit_id + remote_id

discover_packet[scapy.Ether].dst = self.uplink_mac
discover_packet[scapy.IP].src = self.client_ip
discover_packet[scapy.IP].dst = self.switch_loopback_ip
discover_packet[scapy.BOOTP].hops = self.max_hop_count if self.max_hop_count == self.MAX_HOP_COUNT else 1
discover_packet[scapy.BOOTP].giaddr = self.switch_loopback_ip
discover_packet[scapy.BOOTP].giaddr = self.client_giaddr
discover_packet[scapy.DHCP].options.insert(
discover_packet[scapy.DHCP].options.index("end"),
(82, relay_option82)
(82, self.client_option82)
)

return discover_packet
Expand Down Expand Up @@ -337,8 +331,10 @@
else:
source_ip = self.portchannels_ip_list[0]

if ((self.link_selection and self.source_interface) or
self.server_vrf or self.dual_tor or self.agent_relay_mode):
if self.agent_relay_mode:
giaddr = self.client_giaddr
elif ((self.link_selection and self.source_interface) or
self.server_vrf or self.dual_tor):
giaddr = self.switch_loopback_ip
elif self.server_id_override or not self.dual_tor:
giaddr = self.relay_iface_ip
Expand All @@ -355,6 +351,9 @@
elif self.agent_relay_mode == "replace":
dhcp_options = [('message-type', 'discover'), (82, self.option82), ('end')]

elif self.agent_relay_mode == "forward":
dhcp_options = [('message-type', 'discover'), (82, self.client_option82), ('end')]

elif self.agent_relay_mode == "append":
# Sub-option 1: Circuit ID (VLAN 100)
# Circuit ID sub-option type 1, length 7, data 'Vlan100'
Expand Down Expand Up @@ -1203,11 +1202,33 @@
logger.info("Expect receiving {} packets from port [{}]".format(packet_type, self.server_port_indices))
log_dhcp_packet_info(pkt)
num_expected_packets = self.num_dhcp_servers
if self.agent_relay_mode == "discard" or self.dhcpv4_disable_flag or self.max_hop_count == self.MAX_HOP_COUNT:
# Expected result: No packet sent
if self.expected_forward is None:
expected_forward = not (
self.agent_relay_mode == "discard"
or self.dhcpv4_disable_flag
or self.max_hop_count == self.MAX_HOP_COUNT
)
else:
expected_forward = self.expected_forward
if expected_forward:
packet_mask = mask
else:
num_expected_packets = 0
unexpected_packet = (
scapy.Ether(src=self.uplink_mac)
/ scapy.IP()
/ scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT)
)
packet_mask = Mask(unexpected_packet)
packet_mask.set_do_not_care_scapy(scapy.Ether, "dst")
for field in ("version", "ihl", "tos", "len", "id", "flags",
"frag", "ttl", "chksum", "src", "dst", "options"):
packet_mask.set_do_not_care_scapy(scapy.IP, field)
packet_mask.set_do_not_care_scapy(scapy.UDP, "chksum")
packet_mask.set_do_not_care_scapy(scapy.UDP, "len")
packet_mask.set_ignore_extra_bytes()
captured_count = testutils.count_matched_packets_all_ports(
self, mask, self.server_port_indices)
self, packet_mask, self.server_port_indices)
self.assertTrue(captured_count == num_expected_packets,
"Failed: %s packet counts are not equal %d != %d"
% (packet_type, captured_count, num_expected_packets))
Expand Down
62 changes: 62 additions & 0 deletions tests/dhcp_relay/test_dhcpv4_relay.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def _restore_interface_ip_entries(duthost, saved_entries):
CLIENT_VRF_NAME = "Vrf01" # Global macro for Client VRF
MAX_HOP_COUNT = 16
CONFIG_HOP_COUNT = 2
DOWNSTREAM_RELAY_IP = '192.0.2.1' # TEST-NET-1; synthetic downstream relay

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -422,6 +423,7 @@ def test_dhcp_relay_agent_mode(
"kvm_support": True,
"relay_agent": relay_agent,
"agent_relay_mode": test_mode,
"client_giaddr": DOWNSTREAM_RELAY_IP,
"downlink_vlan_iface_name": str(dhcp_relay['downlink_vlan_iface']['name']),
},
log_file="/tmp/test_dhcp_relay_agent_mode.log",
Expand All @@ -439,6 +441,66 @@ def test_dhcp_relay_agent_mode(
sonic_dhcp_relay_config(duthost, dut_dhcp_relay_data)


def test_dhcp_relay_local_giaddr_dropped(
ptfhost,
dut_dhcp_relay_data,
validate_dut_routes_exist,
testing_config,
setup_standby_ports_on_rand_unselected_tor,
rand_unselected_dut,
toggle_all_simulator_ports_to_rand_selected_tor_m, # noqa: F811
relay_agent # noqa: F811
):
"""Verify native relay rejects a chained request spoofing its local giaddr."""
testing_mode, duthost = testing_config

try:
for dhcp_relay in dut_dhcp_relay_data:
vlan = str(dhcp_relay['downlink_vlan_iface']['name'])
dhcp_servers = ",".join(dhcp_relay['downlink_vlan_iface']['dhcp_server_addrs'])
duthost.shell(f'config dhcpv4_relay del {vlan}')
duthost.shell(f'config dhcpv4_relay add --dhcpv4-servers {dhcp_servers}'
f' --agent-relay-mode forward {vlan}')

ptf_runner(
ptfhost,
"ptftests",
"dhcp_relay_test.DHCPTest",
platform_dir="ptftests",
params={
"hostname": duthost.hostname,
"client_port_index": dhcp_relay['client_iface']['port_idx'],
"other_client_port": repr(dhcp_relay['other_client_ports']),
"client_iface_alias": str(dhcp_relay['client_iface']['alias']),
"leaf_port_indices": repr(dhcp_relay['uplink_port_indices']),
"num_dhcp_servers": len(dhcp_relay['downlink_vlan_iface']['dhcp_server_addrs']),
"server_ip": dhcp_relay['downlink_vlan_iface']['dhcp_server_addrs'],
"relay_iface_ip": str(dhcp_relay['downlink_vlan_iface']['addr']),
"relay_iface_mac": str(dhcp_relay['downlink_vlan_iface']['mac']),
"relay_iface_netmask": str(dhcp_relay['downlink_vlan_iface']['mask']),
"dest_mac_address": BROADCAST_MAC,
"client_udp_src_port": DEFAULT_DHCP_CLIENT_PORT,
"switch_loopback_ip": dhcp_relay['switch_loopback_ip'],
"uplink_mac": str(dhcp_relay['uplink_mac']),
"testing_mode": testing_mode,
"kvm_support": True,
"relay_agent": relay_agent,
"agent_relay_mode": "forward",
"client_giaddr": dhcp_relay['switch_loopback_ip'],
"expected_forward": False,
"downlink_vlan_iface_name": str(dhcp_relay['downlink_vlan_iface']['name']),
},
log_file="/tmp/test_dhcp_relay_local_giaddr.log",
is_python3=True
)
except LogAnalyzerError as err:
logger.error("Unable to find expected log in syslog")
raise err
finally:
sonic_dhcp_relay_unconfig(duthost, dut_dhcp_relay_data)
sonic_dhcp_relay_config(duthost, dut_dhcp_relay_data)


@pytest.mark.parametrize("testcase", ["vrf_selection", "source_intf", "server_id_override"])
def test_dhcp_relay_with_non_default_vrf(
ptfhost,
Expand Down
Loading