Added test for mpls swap functionality

Change-Id: I9e4e1a9c5935740ddaffd569a40c740a01178c17
diff --git a/accton/accton_util.py b/accton/accton_util.py
index dd01dd1..ac729a4 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -1089,7 +1089,6 @@
 
     logging.info("Inserting termination flow inport %d, eth_type %lx, vlan %d, mac %s", in_port, eth_type, vlanid, dst_mac)
     ctrl.message_send(request)
-
     if send_barrier:
         do_barrier(ctrl)
 
@@ -1163,7 +1162,7 @@
 
     return request
 
-def add_mpls_flow(ctrl, action_group_id=0x0, label=100 ,ethertype=0x0800, bos=1, vrf=1, goto_table=27, send_barrier=False):
+def add_mpls_flow(ctrl, action_group_id=0x0, label=100 ,ethertype=0x0800, bos=1, vrf=1, goto_table=27, dec_ttl=False, send_barrier=False):
     match = ofp.match()
     match.oxm_list.append(ofp.oxm.eth_type(0x8847))
     match.oxm_list.append(ofp.oxm.mpls_label(label))
@@ -1225,6 +1224,38 @@
 
     return request
 
+def add_mpls_flow_swap(ctrl, action_group_id, label, ethertype, bos, goto_table=MPLS_TYPE_FLOW_TABLE, of_port=0, send_barrier=False):
+    match = ofp.match()
+    match.oxm_list.append(ofp.oxm.eth_type(0x8847))
+    match.oxm_list.append(ofp.oxm.mpls_label(label))
+    match.oxm_list.append(ofp.oxm.mpls_bos(1))
+
+    apply_actions = []
+    write_actions = []
+    apply_actions.append(ofp.action.dec_mpls_ttl())
+    write_actions.append(ofp.action.group(action_group_id))
+
+    request = ofp.message.flow_add(
+            table_id=24,
+            cookie=43,
+            match=match,
+            instructions=[
+                    ofp.instruction.apply_actions(actions=apply_actions),
+                    ofp.instruction.write_actions(actions=write_actions),
+                    ofp.instruction.goto_table(goto_table)
+                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1)
+
+    logging.info("Inserting MPLS flow , label %ld", label)
+    ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
+    return request
+
+
 def add_mpls_flow_pw(ctrl, action_group_id, label, ethertype, bos, tunnel_index, goto_table=MPLS_TYPE_FLOW_TABLE, popMPLS=True, popL2=False, of_port=0, send_barrier=False):
     match = ofp.match()
     match.oxm_list.append(ofp.oxm.eth_type(0x8847))
@@ -1723,11 +1754,12 @@
                                     group_id=mpls_group_id,
                                     buckets=buckets
                                    )
+
+    logging.debug("Adding MPLS interface group %02x, src_mac %s , dst_mac %s , vid %d", mpls_group_id, src_mac, dst_mac, vid)
     ctrl.message_send(request)
 
     if send_barrier:
         do_barrier(ctrl)
-
     return mpls_group_id, request
 
 def add_mpls_tunnel_label_group(
@@ -1771,6 +1803,7 @@
                                     group_id=mpls_group_id,
                                     buckets=buckets
                                    )
+    logging.debug("Adding MPLS Swap group %02x, label %d", mpls_group_id, label)
     ctrl.message_send(request)
 
     return mpls_group_id, request
diff --git a/ofdpa/flows.py b/ofdpa/flows.py
index d13a4c3..6ca721b 100755
--- a/ofdpa/flows.py
+++ b/ofdpa/flows.py
@@ -2410,3 +2410,102 @@
             delete_all_flows( self.controller )
             delete_groups( self.controller, groups )
             delete_all_groups( self.controller )
+
+class MPLSSwapTest( base_tests.SimpleDataPlane ):
+    """
+    MPLS switching with the same label used.
+    Used for interconnecting spines between different fabrics where
+    the label should not be popped, but swapepd with the same label.
+    """
+
+    def runTest( self ):
+        try:
+            delete_all_flows( self.controller )
+            delete_all_groups( self.controller )
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 3, can't run this case" )
+                assert (False)
+                return
+
+            input_src_mac = [ 0x00, 0x00, 0x5e, 0x01, 0x01, 0x01 ]
+            input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+            input_dst_mac = [ 0x00, 0x00, 0x5e, 0x01, 0x01, 0x02 ]
+            input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+            output_dst_mac = [ 0x00, 0x00, 0x5e, 0x01, 0x01, 0x03 ]
+            output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+            mpls_label = 1000
+
+            src_ip = 0xc0a80101
+            src_ip_str = "192.168.1.1"
+            dst_ip = 0xe0010101
+            dst_ip_str = "224.1.1.1"
+
+            src_port = config[ "port_map" ].keys( )[ 0 ]
+            dst_port = config[ "port_map" ].keys( )[ 1 ]
+
+            out_vlan = 4094
+
+            add_one_l2_interface_group( self.controller, dst_port, vlan_id=out_vlan, is_tagged=False,
+                       		 	send_barrier=True )
+
+            # add vlan flow table
+            add_one_vlan_table_flow( self.controller, src_port, out_vlan_id=out_vlan, vlan_id=out_vlan, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+            add_one_vlan_table_flow( self.controller, src_port, out_vlan_id=out_vlan, vlan_id=out_vlan, flag=VLAN_TABLE_FLAG_ONLY_UNTAG )
+
+            # add termination flow
+
+            if config["switch_type"] == "qmx":
+                logging.debug("MPLSSwitching : Adding flow for qmx, without input port")
+                add_termination_flow( self.controller, 0, eth_type=0x08847, dst_mac=input_dst_mac, vlanid=out_vlan, goto_table=23)
+            else:
+                add_termination_flow( self.controller, in_port=src_port,
+				  eth_type=0x8847, dst_mac=input_dst_mac, vlanid=out_vlan, goto_table=23)
+
+	    # add groups that will be used now
+            l2_gid = encode_l2_interface_group_id( out_vlan, dst_port)
+            mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid,
+						      output_dst_mac, input_dst_mac,
+                    	  			      out_vlan, dst_port, send_barrier=True)
+            index = 60
+            mpls_swap_gid, mpls_swap_msg = add_mpls_swap_label_group( self.controller, mpls_gid,
+	 	            					      5, index, mpls_label)
+
+            # add flow to mpls table
+            add_mpls_flow_swap( self.controller, mpls_swap_gid, mpls_label, 0x8847, 1, send_barrier=True)
+
+            # we generate the packet which carries a single label
+            label = (mpls_label, 0, 1, 63)
+            parsed_pkt = mpls_packet(
+                pktlen=104,
+                label=[label],
+                eth_src=input_src_mac_str,
+                eth_dst=input_dst_mac_str,
+                )
+            pkt = str( parsed_pkt )
+            self.dataplane.send( src_port, pkt )
+
+            label = (mpls_label, 0, 1, 62)
+            parsed_pkt = mpls_packet(
+                pktlen=104,
+                label=[label],
+                eth_src=input_dst_mac_str,
+                eth_dst=output_dst_mac_str,
+                )
+            pkt = str( parsed_pkt )
+
+            verify_packet( self, pkt, dst_port )
+            verify_no_packet( self, pkt, src_port )
+            verify_no_other_packets( self )
+
+            delete_all_flows( self.controller )
+            delete_all_groups( self.controller )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_all_groups( self.controller )
+
+