Merge "[SDFAB-548] Create TestON test for INT drop report"
diff --git a/TestON/drivers/common/api/deepinsightapidriver.py b/TestON/drivers/common/api/deepinsightapidriver.py
index af02256..7cdcc45 100644
--- a/TestON/drivers/common/api/deepinsightapidriver.py
+++ b/TestON/drivers/common/api/deepinsightapidriver.py
@@ -91,3 +91,25 @@
             endTime,
             granularity,
         )
+
+    def getAnomalyRecords(
+        self,
+        startTime = None,
+        endTime = None,
+        srcIp = None,
+        dstIp = None,
+        srcPort = None,
+        dstPort = None,
+        ipProto = None,
+        anomalyType = None,
+    ):
+        return self.client.get_anomaly_records(
+            startTime,
+            endTime,
+            srcIp,
+            dstIp,
+            srcPort,
+            dstPort,
+            ipProto,
+            anomalyType
+        )
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params
index 85f3fd6..7d19924 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params
@@ -1,5 +1,5 @@
 <PARAMS>
-    <testcases>1,2,101,102,103,104,301,302</testcases>
+    <testcases>1,2,101,102,103,104,301,302,303,304</testcases>
 
     <GRAPH>
         <nodeCluster>pairedleaves</nodeCluster>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py
index 5911832..668a7a6 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py
@@ -730,3 +730,194 @@
         )
 
         main.funcs.cleanup( main )
+
+    def CASE303 ( self, main ):
+        """
+        Send a packet with invalid VLAN from one host to another host and check
+        if DeepInsight receives drop reports.
+        """
+
+        try:
+            from tests.USECASE.SegmentRouting.SRStaging.dependencies.SRStagingTest import SRStagingTest
+            from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as run
+            from core import utilities
+            import time
+            import socket
+        except ImportError as e:
+            main.log.exception( "SRStagingTest not found. Exiting the test" )
+            main.cleanAndExit()
+        try:
+            main.funcs
+        except ( NameError, AttributeError ):
+            main.funcs = SRStagingTest()
+
+        pod = main.params['GRAPH'].get( 'nodeCluster', "hardware" )
+        main.cfgName = 'CASE303'
+        main.funcs.setupTest( main,
+                              topology='0x2',
+                              onosNodes=3,
+                              description="INT drop report tests on %s POD with invalid VLAN" % ( pod ) )
+        # FIXME: Remove this ping test
+        #        Use this ping function to initialize 'main.h1' and 'main.h2'.
+        #        Same question, maybe there is a better way to initialize them?
+        run.verifyPing( main, ['h1', 'h2'], ['h2'] )
+        main.h1.sudoRequired = True
+        main.h2.sudoRequired = True
+        main.h1.startScapy()
+        main.h2.startScapy()
+        srcIfaceName = main.h1.interfaces[0]['name']
+        dstIfaceName = main.h2.interfaces[0]['name']
+        srcMac = main.h1.getMac(srcIfaceName)
+        dstMac = main.h2.getMac(dstIfaceName)
+        srcIp = main.h1.getIp(srcIfaceName)
+        dstIp = main.h2.getIp(dstIfaceName)
+        srcPort = 2000
+        dstPort = 8888
+
+        main.step( "Sending a packet with invalid VLAN ID from h1" )
+        startTimeMs = ( time.time() - 5 ) * 1000
+        pkt = '''(
+            Ether(src='{}', dst='{}') /
+            Dot1Q(vlan=123) /
+            IP(src='{}', dst='{}') /
+            UDP(sport={}, dport={}) /
+            ('A'*30)
+        )'''.format(srcMac, dstMac, srcIp, dstIp, srcPort, dstPort)
+        main.h1.sendPacket( iface=srcIfaceName, packet=pkt )
+        endTimeMs = ( time.time() + 5 ) * 1000
+
+        main.step( "Checking drop report from DeepInsight" )
+        def getDropAnomalies(*args, **kwargs):
+            return main.DeepInsight.getAnomalyRecords(
+                startTime=startTimeMs,
+                endTime=endTimeMs,
+                srcIp=srcIp,
+                dstIp=dstIp,
+                srcPort=srcPort,
+                dstPort=dstPort,
+                ipProto=socket.IPPROTO_UDP,
+                anomalyType="packet_drop",
+            )
+
+        # Need to wait few seconds until DeepInsight database updated.
+        dropAnomalies = utilities.retry(
+            f=getDropAnomalies,
+            retValue=[[]],
+            attempts=60,
+        )
+
+        utilities.assert_equals(
+            expect=1, actual=len(dropAnomalies),
+            onpass="Got 1 drop anomaly from DeepInsight as expected.",
+            onfail="Got %d drop anomaly from DeepInsight (expect 1)" % ( len(dropAnomalies) )
+        )
+
+        dropAnomaly = dropAnomalies[0]
+        dropReason = dropAnomaly["DropReason"]
+
+        # DROP_REASON_PORT_VLAN_MAPPING_MISS = 55
+        utilities.assert_equals(
+            expect=55, actual=dropReason,
+            onpass="Got drop reason '55' as expected.",
+            onfail="Got drop reason '%d', expect '55'." % ( dropReason )
+        )
+
+        main.h1.stopScapy()
+        main.h2.stopScapy()
+        main.funcs.cleanup( main )
+
+    def CASE304 ( self, main ):
+        """
+        Send a packet with IP TTL value 1 from one host to another host and check
+        if DeepInsight receives drop reports.
+        """
+
+        try:
+            from tests.USECASE.SegmentRouting.SRStaging.dependencies.SRStagingTest import SRStagingTest
+            from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as run
+            from core import utilities
+            import time
+            import socket
+            import json
+        except ImportError as e:
+            main.log.exception( "SRStagingTest not found. Exiting the test" )
+            main.cleanAndExit()
+        try:
+            main.funcs
+        except ( NameError, AttributeError ):
+            main.funcs = SRStagingTest()
+
+        pod = main.params['GRAPH'].get( 'nodeCluster', "hardware" )
+        main.cfgName = 'CASE304'
+        main.funcs.setupTest( main,
+                              topology='0x2',
+                              onosNodes=3,
+                              description="INT drop report tests with IP TTL 1 on %s POD" % ( pod ) )
+        # FIXME: Remove this ping test
+        #        Use this ping function to initialize 'main.h1' and 'main.h3'.
+        #        Is there a better way to initialize them?
+        run.verifyPing( main, ['h1'], ['h3'] )
+        main.h1.sudoRequired = True
+        main.h3.sudoRequired = True
+        main.h1.startScapy()
+        main.h3.startScapy()
+        srcIfaceName = main.h1.interfaces[0]['name']
+        dstIfaceName = main.h3.interfaces[0]['name']
+        srcMac = main.h1.getMac(srcIfaceName)
+        netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='devices') )
+        dstMac = netcfgJson["device:leaf2"]["segmentrouting"]["routerMac"]
+        srcIp = main.h1.getIp(srcIfaceName)
+        dstIp = main.h3.getIp(dstIfaceName)
+        srcPort = 3000
+        dstPort = 8888
+
+        main.step( "Sending a packet with IP TTL value 1 from h1" )
+        startTimeMs = ( time.time() - 5 ) * 1000
+        pkt = '''(
+            Ether(src='{}', dst='{}') /
+            IP(src='{}', dst='{}', ttl=1) /
+            UDP(sport={}, dport={}) /
+            ('A'*30)
+        )'''.format(srcMac, dstMac, srcIp, dstIp, srcPort, dstPort)
+        main.h1.sendPacket( iface=srcIfaceName, packet=pkt )
+        endTimeMs = ( time.time() + 5 ) * 1000
+
+        main.step( "Checking drop report from DeepInsight" )
+        def getDropAnomalies(*args, **kwargs):
+            return main.DeepInsight.getAnomalyRecords(
+                startTime=startTimeMs,
+                endTime=endTimeMs,
+                srcIp=srcIp,
+                dstIp=dstIp,
+                srcPort=srcPort,
+                dstPort=dstPort,
+                ipProto=socket.IPPROTO_UDP,
+                anomalyType="packet_drop",
+            )
+
+        # Need to wait few seconds until DeepInsight database updated.
+        dropAnomalies = utilities.retry(
+            f=getDropAnomalies,
+            retValue=[[]],
+            attempts=60,
+        )
+
+        utilities.assert_equals(
+            expect=1, actual=len(dropAnomalies),
+            onpass="Got 1 drop anomaly from DeepInsight as expected.",
+            onfail="Got %d drop anomaly from DeepInsight (expect 1)" % ( len(dropAnomalies) )
+        )
+
+        dropAnomaly = dropAnomalies[0]
+        dropReason = dropAnomaly["DropReason"]
+
+        # DROP_REASON_IP_TTL_ZERO = 26
+        utilities.assert_equals(
+            expect=26, actual=dropReason,
+            onpass="Got drop reason '26' as expected.",
+            onfail="Got drop reason '%d', expect 26" % ( dropReason )
+        )
+
+        main.h1.stopScapy()
+        main.h3.stopScapy()
+        main.funcs.cleanup( main )