1818from tests .common .helpers .assertions import pytest_assert
1919from tests .common .utilities import find_duthost_on_role
2020from tests .common .helpers .constants import UPSTREAM_NEIGHBOR_MAP , DOWNSTREAM_NEIGHBOR_MAP
21+ from tests .common .helpers .sonic_db import AsicDbCli
2122import json
2223
2324# TODO: Add suport for CONFIGLET mode
@@ -378,6 +379,28 @@ def setup_info(duthosts, rand_one_dut_hostname, tbinfo, request, topo_scenario):
378379 time .sleep (60 )
379380
380381
382+ def validate_asic_route (duthost , prefix ):
383+ """
384+ Check if a route exists in the routing table of the asic.
385+ """
386+ asicdb = AsicDbCli (duthost )
387+ route_table = asicdb .dump ("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY" )
388+ if prefix in str (route_table ):
389+ return True
390+ return False
391+
392+
393+ def validate_mirror_session_up (duthost , session_name ):
394+ """
395+ Check if a mirror session is up.
396+ """
397+ cmd = f'sonic-db-cli STATE_DB HGET \" MIRROR_SESSION_TABLE|{ session_name } \" status'
398+ mirror_status = duthost .command (cmd )['stdout' ]
399+ if 'active' in mirror_status :
400+ return True
401+ return False
402+
403+
381404# TODO: This should be refactored to some common area of sonic-mgmt.
382405def add_route (duthost , prefix , nexthop , namespace ):
383406 """
@@ -452,7 +475,7 @@ def setup_arp_responder(duthost, ptfhost, setup_info):
452475
453476
454477# TODO: This should be refactored to some common area of sonic-mgmt.
455- def get_neighbor_info (duthost , dest_port , tbinfo , resolved = True ):
478+ def get_neighbor_info (duthost , dest_port , tbinfo , resolved = True , ip_version = 4 ):
456479 """
457480 Get the IP and MAC of the neighbor on the specified destination port.
458481
@@ -462,13 +485,13 @@ def get_neighbor_info(duthost, dest_port, tbinfo, resolved=True):
462485 resolved: Whether to return a resolved route or not
463486 """
464487 if not resolved :
465- return "20.20.20.100"
488+ return "20.20.20.100" if ip_version == 4 else "2020::20:20:20:100"
466489
467490 mg_facts = duthost .get_extended_minigraph_facts (tbinfo )
468491
469492 for bgp_peer in mg_facts ["minigraph_bgp" ]:
470493 if bgp_peer ["name" ] == mg_facts ["minigraph_neighbors" ][dest_port ]["name" ] \
471- and ipaddr .IPAddress (bgp_peer ["addr" ]).version == 4 :
494+ and ipaddr .IPAddress (bgp_peer ["addr" ]).version == ip_version :
472495 peer_ip = bgp_peer ["addr" ]
473496 break
474497
@@ -745,6 +768,47 @@ def acl_stage(self):
745768 """
746769 pass
747770
771+ def remove_outer_ip (self , packet_data ):
772+ """
773+ The mirror packet from IP in IP tunnel would take an external IP header.
774+ Remove the outer IP header from the IPinIP packet and keeps the original Ethernet header.
775+
776+ Args:
777+ packet_data: Original IPinIP packet
778+
779+ Returns:
780+ scapy.Ether: Original Ethernet header + Inner IP header + payload
781+ """
782+ if isinstance (packet_data , bytes ):
783+ outer_pkt = Ether (packet_data ) # noqa: F821
784+ else :
785+ outer_pkt = packet_data
786+
787+ if not outer_pkt .haslayer (IP ): # noqa: F821
788+ return None
789+
790+ outer_ip = outer_pkt [IP ] # noqa: F821
791+
792+ if outer_ip .proto != 4 :
793+ return None
794+
795+ # Extract the original Ethernet header
796+ original_eth = outer_pkt [Ether ] # noqa: F821
797+ eth_dst = original_eth .dst
798+ eth_src = original_eth .src
799+ eth_type = 0x0800
800+
801+ inner_payload = outer_ip .payload
802+
803+ # If the payload is Raw type, we need to re-parse it as IP
804+ if isinstance (inner_payload , Raw ): # noqa: F821
805+ inner_ip_packet = IP (bytes (inner_payload )) # noqa: F821
806+ else :
807+ inner_ip_packet = inner_payload
808+ new_packet = Ether (dst = eth_dst , src = eth_src , type = eth_type ) / inner_ip_packet # noqa: F821
809+
810+ return new_packet
811+
748812 def send_and_check_mirror_packets (self ,
749813 setup ,
750814 mirror_session ,
@@ -755,8 +819,8 @@ def send_and_check_mirror_packets(self,
755819 src_port = None ,
756820 dest_ports = None ,
757821 expect_recv = True ,
758- valid_across_namespace = True ):
759-
822+ valid_across_namespace = True ,
823+ multi_binding_acl = False ):
760824 # In Below logic idea is to send traffic in such a way so that mirror traffic
761825 # will need to go across namespaces and within namespace. If source and mirror destination
762826 # namespace are different then traffic mirror will go across namespace via (backend asic)
@@ -797,7 +861,8 @@ def send_and_check_mirror_packets(self,
797861 duthost ,
798862 direction ,
799863 mirror_packet ,
800- src_port_metadata_map [src_port ][1 ])
864+ src_port_metadata_map [src_port ][1 ],
865+ multi_binding_acl = multi_binding_acl )
801866 # Avoid changing the original packet
802867 mirror_packet_sent = mirror_packet .copy ()
803868 if src_port_metadata_map [src_port ][0 ]:
@@ -819,7 +884,9 @@ def send_and_check_mirror_packets(self,
819884 _ , received_packet = result
820885 logging .info ("Received packet: %s" , packet .Ether (received_packet ).summary ())
821886
822- inner_packet = self ._extract_mirror_payload (received_packet , len (mirror_packet_sent ))
887+ inner_packet = self ._extract_mirror_payload (received_packet , len (mirror_packet_sent ),
888+ multi_binding_acl = multi_binding_acl )
889+
823890 logging .info ("Received inner packet: %s" , inner_packet .summary ())
824891
825892 inner_packet = Mask (inner_packet )
@@ -847,22 +914,37 @@ def send_and_check_mirror_packets(self,
847914 inner_packet .set_do_not_care_scapy (packet .Ether , "dst" )
848915 inner_packet .set_do_not_care_scapy (packet .IP , "chksum" )
849916
917+ if multi_binding_acl :
918+ inner_packet .set_do_not_care_scapy (packet .Ether , "dst" )
919+ inner_packet .set_do_not_care_scapy (packet .Ether , "src" )
920+ inner_packet .set_do_not_care_scapy (packet .IP , "chksum" )
921+ inner_packet .set_do_not_care_scapy (packet .IP , "ttl" )
922+
850923 logging .info ("Expected inner packet: %s" , mirror_packet_sent .summary ())
851924 pytest_assert (inner_packet .pkt_match (mirror_packet_sent ),
852925 "Mirror payload does not match received packet" )
853926 else :
854927 testutils .verify_no_packet_any (ptfadapter , expected_mirror_packet , dest_ports )
855928
856929 @staticmethod
857- def get_expected_mirror_packet (mirror_session , setup , duthost , direction , mirror_packet , ttl_dec ):
930+ def get_expected_mirror_packet (mirror_session , setup , duthost , direction , mirror_packet , ttl_dec ,
931+ multi_binding_acl = False ):
858932 payload = mirror_packet .copy ()
859933
860934 # Add vendor specific padding to the packet
861935 if duthost .facts ["asic_type" ] in ["mellanox" ]:
862936 if six .PY2 :
863- payload = binascii .unhexlify ("0" * 44 ) + str (payload )
937+ if multi_binding_acl :
938+ payload = binascii .unhexlify ("0" * 44 ) + str (payload )[:24 ] + binascii .unhexlify ("0" * 40 ) + \
939+ str (payload )[24 :]
940+ else :
941+ payload = binascii .unhexlify ("0" * 44 ) + str (payload )
864942 else :
865- payload = binascii .unhexlify ("0" * 44 ) + bytes (payload )
943+ if multi_binding_acl :
944+ payload = binascii .unhexlify ("0" * 44 ) + bytes (payload )[:24 ] + binascii .unhexlify ("0" * 40 ) + \
945+ bytes (payload )[24 :]
946+ else :
947+ payload = binascii .unhexlify ("0" * 44 ) + bytes (payload )
866948 if (
867949 duthost .facts ["asic_type" ] in ["barefoot" , "cisco-8000" , "marvell-teralynx" ]
868950 or duthost .facts .get ("platform_asic" ) in ["broadcom-dnx" ]
@@ -908,11 +990,18 @@ def get_expected_mirror_packet(mirror_session, setup, duthost, direction, mirror
908990
909991 return expected_packet
910992
911- def _extract_mirror_payload (self , encapsulated_packet , payload_size ):
912- pytest_assert (len (encapsulated_packet ) >= OUTER_HEADER_SIZE ,
913- "Incomplete packet, expected at least {} header bytes" .format (OUTER_HEADER_SIZE ))
993+ def _extract_mirror_payload (self , encapsulated_packet , payload_size , multi_binding_acl = False ):
994+ outer_header_size = OUTER_HEADER_SIZE
995+ if multi_binding_acl :
996+ outer_header_size += 20
997+ pytest_assert (len (encapsulated_packet ) >= outer_header_size ,
998+ "Incomplete packet, expected at least {} header bytes" .format (outer_header_size ))
914999
9151000 inner_frame = encapsulated_packet [- payload_size :]
1001+ if multi_binding_acl :
1002+ inner_frame = encapsulated_packet [- (payload_size + 20 ):]
1003+ inner_frame = self .remove_outer_ip (inner_frame )
1004+ return inner_frame
9161005 return packet .Ether (inner_frame )
9171006
9181007 @staticmethod
0 commit comments