diff --git a/ansible/roles/test/files/helpers/arp_responder.py b/ansible/roles/test/files/helpers/arp_responder.py index 9f1420f748e..adbfaa47483 100644 --- a/ansible/roles/test/files/helpers/arp_responder.py +++ b/ansible/roles/test/files/helpers/arp_responder.py @@ -76,6 +76,7 @@ def poll(self): class ARPResponder(object): ARP_PKT_LEN = 60 + ARP_OP_REQUEST = 1 def __init__(self, ip_sets): self.arp_chunk = binascii.unhexlify('08060001080006040002') # defines a part of the packet for ARP Reply self.arp_pad = binascii.unhexlify('00' * 18) @@ -89,7 +90,11 @@ def action(self, interface): if len(data) > self.ARP_PKT_LEN: return - remote_mac, remote_ip, request_ip = self.extract_arp_info(data) + remote_mac, remote_ip, request_ip, op_type = self.extract_arp_info(data) + + # Don't send ARP response if the ARP op code is not request + if op_type != self.ARP_OP_REQUEST: + return request_ip_str = socket.inet_ntoa(request_ip) if request_ip_str not in self.ip_sets[interface.name()]: @@ -106,7 +111,8 @@ def action(self, interface): return def extract_arp_info(self, data): - return data[6:12], data[28:32], data[38:42] # remote_mac, remote_ip, request_ip + # remote_mac, remote_ip, request_ip, op_type + return data[6:12], data[28:32], data[38:42], (ord(data[20]) * 256 + ord(data[21])) def generate_arp_reply(self, local_mac, remote_mac, local_ip, remote_ip, vlan_id): eth_hdr = remote_mac + local_mac diff --git a/ansible/roles/test/files/ptftests/advanced-reboot.py b/ansible/roles/test/files/ptftests/advanced-reboot.py index 4714c03f54a..62e531a532a 100644 --- a/ansible/roles/test/files/ptftests/advanced-reboot.py +++ b/ansible/roles/test/files/ptftests/advanced-reboot.py @@ -451,6 +451,7 @@ def __init__(self): # Default settings self.ping_dut_pkts = 10 + self.arp_ping_pkts = 1 self.nr_pc_pkts = 100 self.nr_tests = 3 self.reboot_delay = 10 @@ -577,6 +578,7 @@ def setUp(self): self.generate_from_t1() self.generate_from_vlan() self.generate_ping_dut_lo() + self.generate_arp_ping_packet() self.log("Test params:") self.log("DUT ssh: %s" % self.dut_ssh) @@ -737,6 +739,31 @@ def generate_ping_dut_lo(self): self.ping_dut_packet = str(packet) + def generate_arp_ping_packet(self): + vlan_ip_range = self.test_params['vlan_ip_range'] + + vlan_port_canadiates = range(len(self.vlan_ports)) + vlan_port_canadiates.remove(0) # subnet prefix + vlan_port_canadiates.remove(1) # subnet IP on dut + src_idx = random.choice(vlan_port_canadiates) + vlan_port_canadiates.remove(src_idx) + dst_idx = random.choice(vlan_port_canadiates) + src_port = self.vlan_ports[src_idx] + dst_port = self.vlan_ports[dst_idx] + src_mac = self.get_mac('eth%d' % src_port) + src_addr = self.host_ip(vlan_ip_range, src_idx) + dst_addr = self.host_ip(vlan_ip_range, dst_idx) + packet = simple_arp_packet(eth_src=src_mac, arp_op=1, ip_snd=src_addr, ip_tgt=dst_addr, hw_snd=src_mac) + expect = simple_arp_packet(eth_dst=src_mac, arp_op=2, ip_snd=dst_addr, ip_tgt=src_addr, hw_tgt=src_mac) + self.log("ARP ping: src idx %d port %d mac %s addr %s" % (src_idx, src_port, src_mac, src_addr)) + self.log("ARP ping: dst idx %d port %d addr %s" % (dst_idx, dst_port, dst_addr)) + self.arp_ping = str(packet) + self.arp_resp = Mask(expect) + self.arp_resp.set_do_not_care_scapy(scapy.Ether, 'src') + self.arp_resp.set_do_not_care_scapy(scapy.ARP, 'hwtype') + self.arp_resp.set_do_not_care_scapy(scapy.ARP, 'hwsrc') + self.arp_src_port = src_port + def generate_bidirectional(self, packets_to_send = None): """ This method is used to pre-generate packets to be sent in background thread. @@ -1453,6 +1480,7 @@ def reachability_watcher(self): partial = total_rcv_pkt_cnt > 0 and total_rcv_pkt_cnt < self.ping_dut_pkts self.cpu_flooding = reachable and total_rcv_pkt_cnt > self.ping_dut_pkts self.log_cpu_state_change(reachable, partial) + total_rcv_pkt_cnt = self.arpPing() self.watcher_is_running.set() # Watcher is running. self.watcher_is_stopped.set() # Watcher has stopped. self.watcher_is_running.clear() # Watcher has stopped. @@ -1487,3 +1515,10 @@ def pingDut(self): self.log("Send %5d Received %5d ping DUT" % (self.ping_dut_pkts, total_rcv_pkt_cnt), True) return total_rcv_pkt_cnt + + def arpPing(self): + for i in xrange(self.arp_ping_pkts): + testutils.send_packet(self, self.arp_src_port, self.arp_ping) + total_rcv_pkt_cnt = testutils.count_matched_packets_all_ports(self, self.arp_resp, [self.arp_src_port], timeout=self.TIMEOUT) + self.log("Send %5d Received %5d arp ping" % (self.arp_ping_pkts, total_rcv_pkt_cnt), True) + return total_rcv_pkt_cnt