|
3 | 3 | import time |
4 | 4 | import logging |
5 | 5 | import ipaddress |
| 6 | +import contextlib |
| 7 | +import time |
| 8 | +import scapy.all as scapyall |
| 9 | + |
| 10 | +from ptf import testutils, mask |
6 | 11 | from tests.common.dualtor.dual_tor_mock import * |
7 | | -from tests.common.dualtor.dual_tor_utils import dualtor_info, check_tunnel_balance, flush_neighbor |
| 12 | +from tests.common.dualtor.dual_tor_utils import dualtor_info, check_tunnel_balance, flush_neighbor, get_t1_ptf_ports |
8 | 13 | from tests.common.fixtures.ptfhost_utils import copy_ptftests_directory, change_mac_addresses, run_garp_service, run_icmp_responder # lgtm[py/unused-import] |
9 | 14 | from tests.common.helpers.assertions import pytest_require as pt_require |
| 15 | +from tests.common.dualtor.tunnel_traffic_utils import tunnel_traffic_monitor |
| 16 | +from tests.common.dualtor.server_traffic_utils import ServerTrafficMonitor |
10 | 17 |
|
11 | 18 | pytestmark = [ |
12 | 19 | pytest.mark.topology('t0'), |
|
19 | 26 |
|
20 | 27 | logger = logging.getLogger(__file__) |
21 | 28 |
|
| 29 | + |
22 | 30 | def shutdown_random_one_t1_link(dut): |
23 | 31 | """ |
24 | 32 | Shutdown a random t1 link |
@@ -185,3 +193,91 @@ def test_standby_tor_downstream_loopback_route_readded(ptfhost, rand_selected_du |
185 | 193 | # Readd loopback routes and verify traffic is equally distributed |
186 | 194 | add_loopback_routes(rand_selected_dut, active_tor_loopback0) |
187 | 195 | check_tunnel_balance(**params) |
| 196 | + |
| 197 | + |
| 198 | +def test_standby_tor_remove_neighbor_downstream_standby( |
| 199 | + conn_graph_facts, ptfadapter, ptfhost, |
| 200 | + rand_selected_dut, rand_unselected_dut, tbinfo, |
| 201 | + set_crm_polling_interval, |
| 202 | + tunnel_traffic_monitor, vmhost |
| 203 | +): |
| 204 | + """ |
| 205 | + @summary: Verify that after removing neighbor entry for a server over standby |
| 206 | + ToR, the packets sent to the server will be dropped(neither passed to the server |
| 207 | + or redirected to the active ToR). |
| 208 | + """ |
| 209 | + def build_packet_to_server(tor, ptfadapter, target_server_ip, tunnel_traffic_monitor): |
| 210 | + """Build packet destinated to server.""" |
| 211 | + pkt_dscp = random.choice(range(0, 33)) |
| 212 | + pkt_ttl = random.choice(range(3, 65)) |
| 213 | + pkt = testutils.simple_ip_packet( |
| 214 | + eth_dst=tor.facts["router_mac"], |
| 215 | + eth_src=ptfadapter.dataplane.get_mac(0, 0), |
| 216 | + ip_src="1.1.1.1", |
| 217 | + ip_dst=target_server_ip, |
| 218 | + ip_dscp=pkt_dscp, |
| 219 | + ip_ttl=pkt_ttl |
| 220 | + ) |
| 221 | + logging.info( |
| 222 | + "the packet destinated to server %s:\n%s", target_server_ip, |
| 223 | + tunnel_traffic_monitor._dump_show_str(pkt) |
| 224 | + ) |
| 225 | + return pkt |
| 226 | + |
| 227 | + def build_expected_packet_to_server(packet): |
| 228 | + """Build expected mask packet downstream to server.""" |
| 229 | + exp_pkt = mask.Mask(packet) |
| 230 | + exp_pkt.set_do_not_care_scapy(scapyall.Ether, "dst") |
| 231 | + exp_pkt.set_do_not_care_scapy(scapyall.Ether, "src") |
| 232 | + exp_pkt.set_do_not_care_scapy(scapyall.IP, "tos") |
| 233 | + exp_pkt.set_do_not_care_scapy(scapyall.IP, "ttl") |
| 234 | + exp_pkt.set_do_not_care_scapy(scapyall.IP, "chksum") |
| 235 | + return exp_pkt |
| 236 | + |
| 237 | + @contextlib.contextmanager |
| 238 | + def crm_neighbor_checker(duthost): |
| 239 | + crm_facts_before = duthost.get_crm_facts() |
| 240 | + ipv4_neighbor_before = crm_facts_before["resources"]["ipv4_neighbor"]["used"] |
| 241 | + logging.info("ipv4 neighbor before test: %s", ipv4_neighbor_before) |
| 242 | + yield |
| 243 | + time.sleep(crm_facts_before["polling_interval"]) |
| 244 | + crm_facts_after = duthost.get_crm_facts() |
| 245 | + ipv4_neighbor_after = crm_facts_after["resources"]["ipv4_neighbor"]["used"] |
| 246 | + logging.info("ipv4 neighbor after test: %s", ipv4_neighbor_after) |
| 247 | + if ipv4_neighbor_after != ipv4_neighbor_before: |
| 248 | + raise ValueError("ipv4 neighbor differs, before %s, after %s", ipv4_neighbor_before, ipv4_neighbor_after) |
| 249 | + |
| 250 | + @contextlib.contextmanager |
| 251 | + def stop_garp(ptfhost): |
| 252 | + """Temporarily stop garp service.""" |
| 253 | + ptfhost.shell("supervisorctl stop garp_service") |
| 254 | + yield |
| 255 | + ptfhost.shell("supervisorctl start garp_service") |
| 256 | + |
| 257 | + tor = rand_selected_dut |
| 258 | + test_params = dualtor_info(ptfhost, rand_selected_dut, rand_unselected_dut, tbinfo) |
| 259 | + server_ipv4 = test_params["target_server_ip"] |
| 260 | + |
| 261 | + pkt = build_packet_to_server(tor, ptfadapter, server_ipv4, tunnel_traffic_monitor) |
| 262 | + exp_pkt = build_expected_packet_to_server(pkt) |
| 263 | + ptf_t1_intf = random.choice(get_t1_ptf_ports(tor, tbinfo)) |
| 264 | + logging.info("send traffic to server %s from ptf t1 interface %s", server_ipv4, ptf_t1_intf) |
| 265 | + tunnel_monitor = tunnel_traffic_monitor(tor, existing=True) |
| 266 | + with tunnel_monitor: |
| 267 | + testutils.send(ptfadapter, int(ptf_t1_intf.strip("eth")), pkt, count=10) |
| 268 | + |
| 269 | + logging.info("send traffic to server %s after removing neighbor entry", server_ipv4) |
| 270 | + tunnel_monitor.existing = False |
| 271 | + server_traffic_monitor = ServerTrafficMonitor( |
| 272 | + tor, vmhost, test_params["selected_port"], |
| 273 | + conn_graph_facts, exp_pkt, existing=False |
| 274 | + ) |
| 275 | + # for real dualtor testbed, leave the neighbor restoration to garp service |
| 276 | + flush_neighbor_ct = flush_neighbor(tor, server_ipv4, restore=is_t0_mocked_dualtor) |
| 277 | + with crm_neighbor_checker(tor), stop_garp(ptfhost), flush_neighbor_ct, tunnel_monitor, server_traffic_monitor: |
| 278 | + testutils.send(ptfadapter, int(ptf_t1_intf.strip("eth")), pkt, count=10) |
| 279 | + |
| 280 | + logging.info("send traffic to server %s after neighbor entry is restored", server_ipv4) |
| 281 | + tunnel_monitor.existing = True |
| 282 | + with crm_neighbor_checker(tor), tunnel_monitor: |
| 283 | + testutils.send(ptfadapter, int(ptf_t1_intf.strip("eth")), pkt, count=10) |
0 commit comments