Adding pseudo wire tests

Change-Id: If72e67e7bf1fa81b370c96696196fc575a453557
diff --git a/accton/accton_util.py b/accton/accton_util.py
index fd9d1fe..dd01dd1 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -879,7 +879,10 @@
 
         actions=[]
         if vlan_id > 1:
+    #        actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+vlan_id)))
+    #        actions.append(ofp.action.set_field(ofp.action.push_vlan(0x8100)))
             actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+vlan_id)))
+
         actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_TYPE, value=ofp.oxm.VPWS)))
         actions.append(ofp.action.set_field(ofp.oxm.tunnel_id(tunnel_index + ofp.oxm.TUNNEL_ID_BASE)))
         # 0x0000nnnn is for UNI interfaces
@@ -961,6 +964,7 @@
     return request
 
 def add_one_vlan_1_table_flow_pw(ctrl, of_port, tunnel_index, new_outer_vlan_id=-1, outer_vlan_id=1, inner_vlan_id=1, flag=VLAN_TABLE_FLAG_ONLY_TAG, send_barrier=False):
+
     # table 11: vlan 1 table
     # goto to table 13
     match = ofp.match()
@@ -971,9 +975,9 @@
     actions=[]
     actions.append(ofp.action.push_vlan(0x8100))
     if new_outer_vlan_id != -1:
-        actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+new_outer_vlan_id)))
+	actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+new_outer_vlan_id)))
     else:
-        actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+outer_vlan_id)))
+	actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+outer_vlan_id)))
 
     actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_TYPE, value=ofp.oxm.VPWS)))
     actions.append(ofp.action.set_field(ofp.oxm.tunnel_id(tunnel_index + ofp.oxm.TUNNEL_ID_BASE)))
@@ -981,19 +985,18 @@
     actions.append(ofp.action.set_field(ofp.oxm.exp4ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_L2_PORT, value=0x00000000 + of_port)))
 
     request = ofp.message.flow_add(
-        table_id=11,
-        cookie=42,
-        match=match,
-        instructions=[
-            ofp.instruction.apply_actions(
-                 actions=actions
-            ),
-            ofp.instruction.goto_table(MPLS_L2_PORT_FLOW_TABLE)
-        ],
-        priority=0)
+	table_id=11,
+	cookie=42,
+	match=match,
+	instructions=[
+	    ofp.instruction.apply_actions(
+		 actions=actions
+	    ),
+	    ofp.instruction.goto_table(MPLS_L2_PORT_FLOW_TABLE)
+	],
+	priority=0)
     logging.info("Add vlan 1 double tagged %d-%d packets on port %d and go to table %d" %( outer_vlan_id, inner_vlan_id, of_port, MPLS_L2_PORT_FLOW_TABLE))
     ctrl.message_send(request)
-
     if send_barrier:
         do_barrier(ctrl)
 
diff --git a/ofdpa/pw_flows.py b/ofdpa/pw_flows.py
index 42f8476..5713a94 100644
--- a/ofdpa/pw_flows.py
+++ b/ofdpa/pw_flows.py
@@ -199,6 +199,7 @@
                 verify_packet( self, pkt, out_port )
                 verify_no_packet( self, pkt, in_port )
                 verify_no_other_packets( self )
+
                 # Flush all the rules for the next couple
                 delete_all_flows( self.controller )
                 delete_groups( self.controller, Groups )
@@ -474,6 +475,7 @@
                 verify_packet( self, pkt, out_port )
                 verify_no_packet( self, pkt, in_port )
                 verify_no_other_packets( self )
+
                 delete_all_flows( self.controller )
                 delete_groups( self.controller, Groups )
                 delete_groups( self.controller, Groups2 )
@@ -567,6 +569,7 @@
                 verify_packet( self, pkt, out_port )
                 verify_no_packet( self, pkt, in_port )
                 verify_no_other_packets( self )
+
                 delete_all_flows( self.controller )
                 delete_groups( self.controller, Groups )
                 delete_groups( self.controller, Groups2 )
@@ -1156,6 +1159,7 @@
             delete_groups( self.controller, Groups2 )
             delete_all_groups( self.controller )
 
+
 class IntraCO_2_Labels( base_tests.SimpleDataPlane ):
     """
     This is meant to test the PW intermediate transport.
@@ -1463,13 +1467,16 @@
                 return
             ports = config[ "port_map" ].keys( )
             for pair in itertools.product(ports, ports):
+
                 # we generate all possible products
                 in_port     = pair[0]
                 out_port    = pair[1]
                 if out_port == in_port:
                     continue
+
                 # we fill the pipeline for the pw initiation
                 # on the reverse path
+
                 (
                     port_to_mpls_label_2,
                     port_to_mpls_label_1,
@@ -1488,7 +1495,7 @@
                     egress_tag=EGRESS_TAGGED,
                     mpls_labels=1
                     )
-                # we fill the pipeline for the pw termination
+		# we fill the pipeline for the pw termination
                 (
                     port_to_mpls_label_pw,
                     port_to_in_vlan_2,
@@ -1523,12 +1530,13 @@
                 verify_packet( self, pkt, out_port )
                 verify_no_packet( self, pkt, in_port )
                 verify_no_other_packets( self )
-                delete_all_flows( self.controller )
+
+		delete_all_flows( self.controller )
                 delete_groups( self.controller, Groups )
                 delete_groups( self.controller, Groups2 )
                 delete_all_groups( self.controller )
         finally:
-            delete_all_flows( self.controller )
+	    delete_all_flows( self.controller )
             delete_groups( self.controller, Groups )
             delete_groups( self.controller, Groups2 )
             delete_all_groups( self.controller )
@@ -1613,6 +1621,7 @@
                 verify_packet( self, pkt, out_port )
                 verify_no_packet( self, pkt, in_port )
                 verify_no_other_packets( self )
+
                 delete_all_flows( self.controller )
                 delete_groups( self.controller, Groups )
                 delete_groups( self.controller, Groups2 )
@@ -1717,6 +1726,323 @@
             delete_groups( self.controller, Groups2 )
             delete_all_groups( self.controller )
 
+class IntermediateTransport( base_tests.SimpleDataPlane ):
+    """
+    This test is meant to verify that the alternative approach for handling
+    pseudowires in spine switches. Specifically, in the mpls table we install
+    2 rules , the match(SR1, BoS=1) and match(SR2, BoS=0). The match(SR2, BoS=0)
+    should match and the packet should be forwarded through the port and the label
+    for SR2 should be removed.
+    """
+    def runTest( self ):
+        Groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 1:
+                logging.info( "Port count less than 1, can't run this case" )
+                assert (False)
+                return
+            ports           = config[ "port_map" ].keys( )
+            in_port         = ports[0]
+            out_port        = ports[1]
+            out_vlan        = 4094
+            src_mac         = [ 0x00, 0x00, 0x00, 0x00, 0x11, 0x01 ]
+            src_mac_str     = ':'.join( [ '%02X' % x for x in src_mac ] )
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x11, 0x11, 0x01 ]
+            dst_mac_str     = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            mpls_label      = 100
+            mpls_label_SR1 = 100 + 5
+            mpls_label_SR2 = 100 + 10
+            mpls_label_PW = 100 + 15
+
+            # Add l2 interface group, we have to pop the VLAN;
+            l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=out_vlan,
+                is_tagged=False,
+                send_barrier=False
+                )
+            Groups._put( l2_intf_gid )
+
+            # add MPLS interface group
+            mpls_intf_gid, mpls_intf_msg = add_mpls_intf_group(
+                ctrl=self.controller,
+                ref_gid=l2_intf_gid,
+                dst_mac=dst_mac,
+                src_mac=src_mac,
+                vid=out_vlan,
+                index=in_port
+                )
+            Groups._put( mpls_intf_gid )
+
+            # Add L3 Unicast  group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=out_vlan,
+                id=in_port,
+                src_mac=src_mac,
+                dst_mac=dst_mac
+                )
+            Groups._put( l3_msg.group_id )
+
+            # Add L3 ecmp group
+            ecmp_msg = add_l3_ecmp_group(
+                ctrl=self.controller,
+                id=in_port,
+                l3_ucast_groups=[ l3_msg.group_id ]
+                )
+            Groups._put( ecmp_msg.group_id )
+
+            # Add MPLS flow with BoS=1
+            add_mpls_flow(
+                ctrl=self.controller,
+                action_group_id=ecmp_msg.group_id,
+                label=mpls_label_SR1
+                )
+
+            # add MPLS flow with BoS=0
+            add_mpls_flow_pw(
+                ctrl=self.controller,
+                action_group_id=mpls_intf_gid,
+                label=mpls_label_SR2,
+                ethertype=0x8847,
+                tunnel_index=1,
+                bos=0
+                )
+
+            # add Termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x8847,
+                dst_mac=src_mac,
+                vlanid=out_vlan,
+                goto_table=23
+                )
+            # add VLAN flows
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=out_vlan,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG,
+                )
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=out_vlan,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+            # Packet generation with sleep
+            time.sleep(2)
+            label_SR1 = (mpls_label_SR1, 0, 1, 32)
+            label_SR2 = (mpls_label_SR2, 0, 0, 32)
+            label_2 = (mpls_label_PW, 0, 1, 32)
+
+	    # set to false to test if routing traffic
+	    # comes through
+
+	    pw = True
+            if pw:
+		    parsed_pkt = mpls_packet(
+			pktlen=104,
+			ip_ttl=63,
+			eth_dst=src_mac_str,
+			label=[label_SR2, label_2],
+			encapsulated_ethernet = True
+		    )
+		    pkt = str( parsed_pkt )
+		    self.dataplane.send( in_port, pkt )
+
+
+		    expected_label = (mpls_label_PW, 0, 1, 31)
+		    # we geneate the expected pw packet
+		    parsed_pkt =  mpls_packet(
+			pktlen=100,
+			ip_ttl=63,
+			eth_dst=dst_mac_str,
+			eth_src=src_mac_str,
+			label=[ expected_label ],
+			encapsulated_ethernet = True
+		    )
+
+		    pkt = str( parsed_pkt )
+		    verify_packet( self, pkt, out_port )
+		    verify_no_packet( self, pkt, in_port )
+	    else:
+		    # packet for routing traffic
+		    parsed_pkt_2 = mpls_packet(
+			pktlen=104,
+			ip_ttl=63,
+			eth_dst=src_mac_str,
+			label=[ label_SR1 ]
+		    )
+		    pkt_2 = str(parsed_pkt_2)
+		    self.dataplane.send( in_port, pkt_2 )
+
+		    # we geneate the expected routed packet
+		    parsed_pkt_2 = simple_tcp_packet(
+			pktlen=100,
+			ip_ttl=31,
+			eth_dst=dst_mac_str,
+			eth_src=src_mac_str,
+		    )
+		    pkt_2 = str(parsed_pkt_2)
+
+		    verify_packet( self, pkt_2, out_port)
+		    verify_no_packet( self, pkt_2, in_port )
+
+            verify_no_other_packets( self )
+        finally:
+
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class PseudowireSpineTerminationBug( base_tests.SimpleDataPlane ):
+    """
+    This is meant to demonstrate a bug observed in the termination of
+    Leaf-Spine pseudowires, where the termination point at the spine
+    is a port connecting to another leaf switch.
+    In this case, there exist two L2 interface groups in the device for the
+    same port :
+
+    L2 interface for routing : POP_VLAN, output to port
+    L2 interface for pseudowire : outpute to port
+
+    The choice of the l2 interface group is associated with the vlan id of the packet.
+    In both cases, packets arrive with untagged vlan and are associated with vlan-id 4094.
+    However, in pw case the outer l2 is popped, and the vlan-id changes (that of the original
+    traffic) which matches the L2 interface group for the pw.
+
+    The bug is that still the group that is chossen is that for routing, which pops the vlan,
+    and thus the pseudowire results with untagged traffic.
+    """
+    def runTest( self ):
+
+        Groups  = Queue.LifoQueue( )
+        Groups2 = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 1:
+                logging.info( "Port count less than 1, can't run this case" )
+                assert (False)
+                return
+            ports = config[ "port_map" ].keys( )
+            for pair in itertools.product(ports, ports):
+                # we generate all possible products
+                in_port     = pair[0]
+                out_port    = pair[1]
+                if out_port == in_port:
+                    continue
+                # we fill the pipeline for the pw initiation
+                # on the reverse path
+                (
+                    port_to_mpls_label_2,
+                    port_to_mpls_label_1,
+                    port_to_mpls_label_pw,
+                    port_to_in_vlan_3,
+                    port_to_in_vlan_2,
+                    port_to_in_vlan_1,
+                    port_to_src_mac_str,
+                    port_to_dst_mac_str,
+                    Groups ) = fill_pw_initiation_pipeline(
+                    controller=self.controller,
+                    logging=logging,
+                    in_port=out_port,
+                    out_port=in_port,
+                    ingress_tags=1,
+                    egress_tag=EGRESS_TAGGED,
+                    mpls_labels=1
+                    )
+                # we fill the pipeline for the pw termination
+                (
+                    port_to_mpls_label_pw,
+                    port_to_in_vlan_2,
+                    port_to_in_vlan_1,
+                    port_to_dst_mac_str,
+                    Groups2 ) = fill_pw_termination_pipeline(
+                    controller=self.controller,
+                    logging=logging,
+                    in_port=in_port,
+                    out_port=out_port,
+                    egress_tags=1
+                    )
+
+		print('''\nBefore adding the l2 interface group that pops the vlan we expect to see tagged packets at the output. ''')
+
+                # we generate the pw packet
+                label_pw = (port_to_mpls_label_pw[out_port], 0, 1, 63)
+                cw = (0, 0, 0, 0)
+                parsed_pkt = pw_packet(
+                    pktlen=104,
+                    out_eth_dst=port_to_dst_mac_str[in_port],
+                    label=[label_pw],
+                    cw=cw,
+                    out_dl_vlan_enable=True,
+                    out_vlan_vid=port_to_in_vlan_1[out_port],
+                    )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+                # we generate the expected tcp packet
+                # with a vlan tag
+                parsed_pkt = simple_tcp_packet(
+                    pktlen=82,
+                    dl_vlan_enable=True,
+                    vlan_vid=port_to_in_vlan_1[out_port]
+                    )
+                pkt = str( parsed_pkt )
+
+                # Assertions
+                verify_packet( self, pkt, out_port )
+                verify_no_packet( self, pkt, in_port )
+                verify_no_other_packets( self )
+
+		print('''After adding the l2 interface group that pops the vlan, packets will come out UNTAGGED and test will fail. Check logs for details.''')
+	        # we create an l2 interface group for routing that
+		# pops the vlan tags
+            	l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+                	ctrl=self.controller,
+                	port=out_port,
+                	vlan_id=4094,
+                	is_tagged=False,
+                	send_barrier=False
+                	)
+		Groups._put( l2_intf_gid )
+
+                parsed_pkt = pw_packet(
+                    pktlen=104,
+                    out_eth_dst=port_to_dst_mac_str[in_port],
+                    label=[label_pw],
+                    cw=cw,
+                    out_dl_vlan_enable=True,
+                    out_vlan_vid=port_to_in_vlan_1[out_port],
+                    )
+                pkt = str( parsed_pkt )
+		self.dataplane.send( in_port, pkt )
+
+                parsed_pkt = simple_tcp_packet(
+                    pktlen=82,
+                    dl_vlan_enable=True,
+                    vlan_vid=port_to_in_vlan_1[out_port]
+                    )
+                pkt = str( parsed_pkt )
+
+		# send the packet, test should fail now
+                verify_packet( self, pkt, out_port )
+                verify_no_packet( self, pkt, in_port )
+                verify_no_other_packets( self )
+
+                delete_all_flows( self.controller )
+                delete_groups( self.controller, Groups )
+                delete_groups( self.controller, Groups2 )
+                delete_all_groups( self.controller )
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_groups( self.controller, Groups2 )
+            delete_all_groups( self.controller )
+
+
 class BoSBug( base_tests.SimpleDataPlane ):
     """
     This test is meant to verify the forwarding of the default traffic
@@ -1819,13 +2145,13 @@
                 )
             # Packet generation with sleep
             time.sleep(2)
-            label = (mpls_label, 0, 1, 32)
+            label = (mpls_label, 0, 0, 32)
             parsed_pkt = mpls_packet(
                 pktlen=104,
                 vlan_vid=out_vlan,
                 ip_ttl=63,
                 eth_dst=src_mac_str,
-                label=[ label]
+                label=[ label ]
             )
             pkt = str( parsed_pkt )
             self.dataplane.send( in_port, pkt )
@@ -1843,6 +2169,17 @@
             verify_no_packet( self, pkt, in_port )
             verify_no_other_packets( self )
         finally:
-            delete_all_flows( self.controller )
-            delete_groups( self.controller, Groups )
-            delete_all_groups( self.controller )
\ No newline at end of file
+	    print("SHOULD CLEAR STATE HERE")
+            # delete_all_flows( self.controller )
+            # delete_groups( self.controller, Groups )
+            # delete_all_groups( self.controller )
+
+class ClearAll( base_tests.SimpleDataPlane ):
+
+    def runTest( self ):
+    	delete_all_flows( self.controller )
+    	delete_all_groups( self.controller )
+
+
+
+
diff --git a/ofdpa/utils.py b/ofdpa/utils.py
index 693aa01..c5cf95f 100644
--- a/ofdpa/utils.py
+++ b/ofdpa/utils.py
@@ -732,6 +732,7 @@
             is_tagged=False,
             send_barrier=False
             )
+
     Groups._put( l2_intf_gid )
     add_mpls_flow_pw(
         ctrl=controller,
diff --git a/src/python/oftest/dataplane.py b/src/python/oftest/dataplane.py
index 97b47a3..232aadf 100644
--- a/src/python/oftest/dataplane.py
+++ b/src/python/oftest/dataplane.py
@@ -64,10 +64,10 @@
     #some nic card have capature problem, will have more bytes capatured.
     if pkt.find(exp_pkt) >=0:
         return True
-    else:      
+    else:
         if self.config["dump_packet"]:
-            self.logger.debug("rx pkt    ->"+(":".join("{:02x}".format(ord(c)) for c in pkt)))
-            self.logger.debug("expect pkt->"+(":".join("{:02x}".format(ord(c)) for c in exp_pkt)))
+            self.logger.debug("rx pkt    ->"+(" ".join("{:02x}".format(ord(c)) for c in pkt)))
+            self.logger.debug("expect pkt->"+(" ".join("{:02x}".format(ord(c)) for c in exp_pkt)))
 
         return False
 
@@ -194,17 +194,17 @@
         if config is None:
             self.config = {}
         else:
-            self.config = config; 
+            self.config = config;
 
         ############################################################
         #
         # The platform/config can provide a custom DataPlanePort class
         # here if you have a custom implementation with different
-        # behavior. 
+        # behavior.
         #
         # Set config.dataplane.portclass = MyDataPlanePortClass
         # where MyDataPlanePortClass has the same interface as the class
-        # DataPlanePort defined here. 
+        # DataPlanePort defined here.
         #
         if "dataplane" in self.config and "portclass" in self.config["dataplane"]:
             self.dppclass = self.config["dataplane"]["portclass"]
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index 5024d4a..7953bfe 100755
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -112,7 +112,7 @@
                 '08 00 45 00 00 2e 04 d2 00 00 7f 00 b2 47 c0 a8 '
                 '01 64 c0 a8 02 02 00 00 00 00 00 00 00 00 00 00 '
                 '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'):
-             
+
     pkt = ''.join(content.split(" ")).decode('hex')
     pkt = scapy.Ether(pkt)
     if len(pkt) < 64:
@@ -120,7 +120,7 @@
     #scapy.hexdump(pkt)
     return pkt
 
-def simple_tcp_packet(pktlen=100, 
+def simple_tcp_packet(pktlen=100,
                       eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
                       dl_vlan_enable=False,
@@ -153,7 +153,7 @@
     @param ip_ttl IP TTL
     @param tcp_dport TCP destination port
     @param tcp_sport TCP source port
-    @param tcp_flags TCP Control flags  	
+    @param tcp_flags TCP Control flags
 
     Generates a simple TCP request.  Users
     shouldn't assume anything about this packet other than that
@@ -214,7 +214,7 @@
     @param ipv6_fl IPv6 flow label
     @param tcp_dport TCP destination port
     @param tcp_sport TCP source port
-    @param tcp_flags TCP Control flags	
+    @param tcp_flags TCP Control flags
 
     Generates a simple TCP request. Users shouldn't assume anything about this
     packet other than that it is a valid ethernet/IPv6/TCP frame.
@@ -293,16 +293,16 @@
     return pkt
 
 
-def simple_tcp_packet_two_vlan(pktlen=100, 
+def simple_tcp_packet_two_vlan(pktlen=100,
                       eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
                       out_dl_vlan_enable=False,
                       in_dl_vlan_enable=False,
                       out_vlan_vid=0,
                       out_vlan_pcp=0,
-                      out_dl_vlan_cfi=0,                      
+                      out_dl_vlan_cfi=0,
                       in_vlan_vid=0,
-                      in_vlan_pcp=0,  
+                      in_vlan_pcp=0,
                       in_dl_vlan_cfi=0,
                       ip_src='192.168.0.1',
                       ip_dst='192.168.0.2',
@@ -330,7 +330,7 @@
     @param ip_ttl IP TTL
     @param tcp_dport TCP destination port
     @param tcp_sport TCP source port
-    @param tcp_flags TCP Control flags  	
+    @param tcp_flags TCP Control flags
 
     Generates a simple TCP request.  Users
     shouldn't assume anything about this packet other than that
@@ -433,7 +433,7 @@
 
     return pkt
 
-def mpls_packet(pktlen=100, 
+def mpls_packet(pktlen=100,
                       eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
                       dl_vlan_enable=False,
@@ -450,7 +450,10 @@
                       ip_ihl=None,
                       ip_options=False,
                       label=None,
-                      inner_payload=True
+                      inner_payload=True,
+		      encapsulated_ethernet=False,
+		      encapsulated_eth_src='01:02:03:04:05:11',
+		      encapsulated_eth_dst='01:02:03:04:05:22'
                       ):
     if MINSIZE > pktlen:
         pktlen = MINSIZE
@@ -464,15 +467,21 @@
 
     #add MPLS header
     for i in range(len(label)):
-        l,c,s,t=label[i]    
+        l,c,s,t=label[i]
         pkt = pkt/scapy.MPLS(label=l, cos=c, s=s, ttl=t)
 
     #add innder payload
     if inner_payload!=None:
-        pkt=pkt / \
-            scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
-            scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
-    
+        if not encapsulated_ethernet:
+        	pkt=pkt / \
+           	   scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
+            	   scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
+        else:
+	       	pkt=pkt / \
+		   scapy.Ether(dst=encapsulated_eth_dst, src=encapsulated_eth_src)/ \
+           	   scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
+            	   scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
+
     pkt = pkt/("D" * (pktlen - len(pkt)))
 
     return pkt
@@ -634,7 +643,7 @@
 
     #add MPLS header
     for i in range(len(label)):
-        l,c,s,t=label[i]    
+        l,c,s,t=label[i]
         pkt = pkt/scapy.MPLS(label=l, cos=c, s=s, ttl=t)
 
     #add innder payload
@@ -642,7 +651,7 @@
         pkt=pkt/inner_payload
 
     return pkt
-    
+
 def simple_udpv6_packet(pktlen=100,
                         eth_dst='00:01:02:03:04:05',
                         eth_src='00:06:07:08:09:0a',
@@ -690,7 +699,7 @@
 
     return pkt
 
-def simple_icmp_packet(pktlen=60, 
+def simple_icmp_packet(pktlen=60,
                       eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
                       dl_vlan_enable=False,
@@ -700,7 +709,7 @@
                       ip_dst='192.168.0.2',
                       ip_tos=0,
                       ip_ttl=64,
-                      ip_id=1,  
+                      ip_id=1,
                       icmp_type=8,
                       icmp_code=0,
                       icmp_data=''):
@@ -792,7 +801,7 @@
 
     return pkt
 
-def simple_arp_packet(pktlen=60, 
+def simple_arp_packet(pktlen=60,
                       eth_dst='ff:ff:ff:ff:ff:ff',
                       eth_src='00:06:07:08:09:0a',
                       vlan_vid=0,
@@ -847,7 +856,7 @@
 
     return pkt
 
-def qinq_tcp_packet(pktlen=100, 
+def qinq_tcp_packet(pktlen=100,
                     eth_dst='00:01:02:03:04:05',
                     eth_src='00:06:07:08:09:0a',
                     dl_vlan_outer=20,
@@ -947,7 +956,7 @@
     for port in ports:
         if port.port_no == port_no:
             return (port.hw_addr, port.config, port.advertised)
-    
+
     logging.warn("Did not find port number for port config")
     return None, None, None
 
@@ -992,7 +1001,7 @@
         logging.debug("Checking for pkt on port " + str(ofport))
         (rcv_port, rcv_pkt, pkt_time) = dp.poll(
             port_number=ofport, exp_pkt=exp_pkt_arg)
-        assert_if.assertTrue(rcv_pkt is not None, 
+        assert_if.assertTrue(rcv_pkt is not None,
                              "Did not receive pkt on " + str(ofport))
         if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
             logging.debug("Expected %s" % format_packet(pkt))
@@ -1006,7 +1015,7 @@
         logging.debug("Negative check for pkt on port " + str(ofport))
         (rcv_port, rcv_pkt, pkt_time) = dp.poll(
             port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
-        assert_if.assertTrue(rcv_pkt is None, 
+        assert_if.assertTrue(rcv_pkt is None,
                              "Unexpected pkt on port " + str(ofport))
 
 
@@ -1037,12 +1046,12 @@
             port_number=check_port, exp_pkt=exp_pkt_arg)
 
         if rcv_pkt is None:
-            logging.error("ERROR: No packet received from " + 
+            logging.error("ERROR: No packet received from " +
                                 str(check_port))
 
         parent.assertTrue(rcv_pkt is not None,
                           "Did not receive packet port " + str(check_port))
-        logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + 
+        logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
                             str(rcv_port))
 
         if str(exp_pkt) != str(rcv_pkt):
@@ -1080,8 +1089,8 @@
                        'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
                        " != " + str(res_match.vlan_vid))
     parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
-                       'Match failed: vlan_pcp: ' + 
-                       str(req_match.vlan_pcp) + " != " + 
+                       'Match failed: vlan_pcp: ' +
+                       str(req_match.vlan_pcp) + " != " +
                        str(res_match.vlan_pcp))
     parent.assertEqual(req_match.eth_type, res_match.eth_type,
                        'Match failed: eth_type: ' + str(req_match.eth_type) +
@@ -1106,11 +1115,11 @@
             and ((req_match.ip_proto == TCP_PROTOCOL)
                  or (req_match.ip_proto == UDP_PROTOCOL))):
             parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
-                               'Match failed: tcp_src: ' + 
+                               'Match failed: tcp_src: ' +
                                str(req_match.tcp_src) +
                                " != " + str(res_match.tcp_src))
             parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
-                               'Match failed: tcp_dst: ' + 
+                               'Match failed: tcp_dst: ' +
                                str(req_match.tcp_dst) +
                                " != " + str(res_match.tcp_dst))
 
@@ -1128,7 +1137,7 @@
     """
     Create a flow message
 
-    Match on packet with given wildcards.  
+    Match on packet with given wildcards.
     See flow_match_test for other parameter descriptoins
     @param egr_queue if not None, make the output an enqueue action
     @param in_band if True, do not wildcard ingress port
@@ -1195,7 +1204,7 @@
     if(clear_table_override != None):
         clear_table = clear_table_override
 
-    if clear_table: 
+    if clear_table:
         logging.debug("Clear flow table")
         delete_all_flows(parent.controller)
 
@@ -1217,7 +1226,7 @@
 
     if wildcards is None:
         wildcards = required_wildcards(parent)
-    logging.info("Pkt match test: " + str(ing_port) + " to " + 
+    logging.info("Pkt match test: " + str(ing_port) + " to " +
                        str(egr_ports))
     logging.debug("  WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
     if pkt is None:
@@ -1225,13 +1234,13 @@
     if exp_pkt is None:
         exp_pkt = pkt
 
-    request = flow_msg_create(parent, pkt, ing_port=ing_port, 
+    request = flow_msg_create(parent, pkt, ing_port=ing_port,
                               wildcards=wildcards, egr_ports=egr_ports,
                               action_list=action_list)
 
     flow_msg_install(parent, request)
 
-    logging.debug("Send packet: " + str(ing_port) + " to " + 
+    logging.debug("Send packet: " + str(ing_port) + " to " +
                         str(egr_ports))
     parent.dataplane.send(ing_port, str(pkt))
 
@@ -1291,7 +1300,7 @@
 
     count = 0
     egr_ports = []
-    for egr_idx in range(len(of_ports)): 
+    for egr_idx in range(len(of_ports)):
         if of_ports[egr_idx] not in exclude_list:
             egr_ports.append(of_ports[egr_idx])
             count += 1
@@ -1299,8 +1308,8 @@
                 return egr_ports
     logging.debug("Could not generate enough egress ports for test")
     return []
-    
-def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None, 
+
+def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
                     exp_pkt=None, action_list=None,
                     max_test=0, egr_count=1, ing_port=False):
     """
@@ -1325,18 +1334,18 @@
 
     if egr_count == -1:
         egr_count = test_param_get('egr_count', default=2)
-    
+
     for ing_idx in range(len(of_ports)):
         ingress_port = of_ports[ing_idx]
-        egr_ports = get_egr_list(parent, of_ports, egr_count, 
+        egr_ports = get_egr_list(parent, of_ports, egr_count,
                                  exclude_list=[ingress_port])
         if ing_port:
             egr_ports.append(ofp.OFPP_IN_PORT)
         if len(egr_ports) == 0:
             parent.assertTrue(0, "Failed to generate egress port list")
 
-        flow_match_test_port_pair(parent, ingress_port, egr_ports, 
-                                  wildcards=wildcards, vlan_vid=vlan_vid, 
+        flow_match_test_port_pair(parent, ingress_port, egr_ports,
+                                  wildcards=wildcards, vlan_vid=vlan_vid,
                                   pkt=pkt, exp_pkt=exp_pkt,
                                   action_list=action_list)
         test_count += 1
@@ -1368,7 +1377,7 @@
     on the command line, return val (as interpreted by exec).  Otherwise
     return default value.
 
-    WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS; 
+    WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
     eg egr_count, not egr-count.
     """
     try:
@@ -1438,7 +1447,7 @@
 
     return act
 
-def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={}, 
+def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
                      mod_fields=[], tp="tcp", check_test_params=False):
     """
     Set up the ingress and expected packet and action list for a test
@@ -1578,7 +1587,7 @@
     """
     Get the aggregate stats for all flows in the table
     @param parent Test instance with controller connection and assert
-    @returns dict with keys flows, packets, bytes, active (flows), 
+    @returns dict with keys flows, packets, bytes, active (flows),
     lookups, matched
     """
     stat_req = ofp.message.aggregate_stats_request()
@@ -1593,14 +1602,14 @@
     parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
 
     for obj in reply.entries:
-        (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count, 
+        (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
                                                   obj.packet_count, obj.byte_count)
         break
 
     request = ofp.message.table_stats_request()
     (reply , pkt) = parent.controller.transact(request)
 
-    
+
     (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
     for obj in reply.entries:
         rv["active"] += obj.active_count
@@ -1610,7 +1619,7 @@
     return rv
 
 _import_blacklist.add('FILTER')
-FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' 
+FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
                 for x in range(256)])
 
 def hex_dump_buffer(src, length=16):
@@ -1630,7 +1639,7 @@
     return ''.join(result)
 
 def format_packet(pkt):
-    return "Packet length %d \n%s" % (len(str(pkt)), 
+    return "Packet length %d \n%s" % (len(str(pkt)),
                                       hex_dump_buffer(str(pkt)))
 
 def inspect_packet(pkt):
@@ -2045,7 +2054,7 @@
     (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
     test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
     return (rcv_port, rcv_pkt, pkt_time)
-    
+
 def verify_no_packet(test, pkt, ofport):
     """
     Check that a particular packet is not received
@@ -2107,7 +2116,7 @@
     test.assertIn(capability, ofp.const.ofp_capabilities_map,
                   "Capability code %d does not exist." % capability)
     capability_str = ofp.const.ofp_capabilities_map[capability]
-    
+
     logging.info(("Sending features_request to test if capability "
                   "%s is supported."), capability_str)
     req = ofp.message.features_request()
@@ -2117,7 +2126,7 @@
                      ("Unexpected packet type %d received in response to "
                       "OFPT_FEATURES_REQUEST") % res.type)
     logging.info("Received features_reply.")
-    
+
     if (res.capabilities & capability) > 0:
         logging.info("Switch capabilities bitmask claims to support %s",
                      capability_str)
@@ -2140,7 +2149,7 @@
                   "flag  %s does not exist." % flag)
     flag_str = ofp.const.ofp_config_flags_map[flag]
 
-    logging.info("Sending OFPT_GET_CONFIG_REQUEST.")    
+    logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
     req = ofp.message.get_config_request()
     rv = test.controller.message_send(req)
     test.assertNotEqual(rv, -1, "Not able to send get_config_request.")