Intermediate transport support

Changes:
- Adds a procedure to fill the pipeline in different use cases;
- Adds a new utility function to fill the MPLS flow tables;
- Adds an utility function to print the ports stats

Change-Id: I8928b177ac93e4c05ced4573be87c1c9361d35b5
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 2a8eba3..75a1df5 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -674,6 +674,8 @@
         actions=[]
         if vrf!=0:
             actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=1, value=vrf)))
+        if mpls_type!=None:
+            actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_TYPE, value=mpls_type)))
 
         #actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(value=vlan_id)))
 
@@ -1086,6 +1088,7 @@
     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(bos))
+    actions = []
     actions = [ofp.action.dec_mpls_ttl(),
                ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=1, value=vrf))]
     if (goto_table == 29):
@@ -1114,6 +1117,38 @@
 
     return request
 
+def add_mpls_flow_pw(ctrl, action_group_id, label, ethertype, bos, goto_table=MPLS_TYPE_FLOW_TABLE, pop=True, 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(bos))
+
+    actions = []
+    actions.append(ofp.action.dec_mpls_ttl())
+    if pop == True:
+        actions.append(ofp.action.copy_ttl_in())
+        actions.append(ofp.action.pop_mpls(ethertype))
+    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=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_mcast4_routing_flow(ctrl, vlan_id, src_ip, src_ip_mask, dst_ip, action_group_id, send_barrier=False):
     match = ofp.match()
     match.oxm_list.append(ofp.oxm.eth_type(0x0800))
@@ -1571,6 +1606,28 @@
 
     return mpls_group_id, request
 
+def add_mpls_swap_label_group(
+    ctrl,
+    ref_gid,
+    subtype,
+    index,
+    label,
+    ):
+
+    action=[]
+    action.append(ofp.action.set_field(ofp.oxm.mpls_label(label)))
+    action.append(ofp.action.group(ref_gid))
+    buckets = [ofp.bucket(actions=action)]
+
+    mpls_group_id = encode_mpls_label_group_id(subtype, index)
+    request = ofp.message.group_add(group_type=ofp.OFPGT_INDIRECT,
+                                    group_id=mpls_group_id,
+                                    buckets=buckets
+                                   )
+    ctrl.message_send(request)
+
+    return mpls_group_id, request
+
 def add_mpls_label_group(ctrl, subtype, index, ref_gid,
                          lmep_id=-1,
                          qos_index=-1,
diff --git a/ofdpa/utils.py b/ofdpa/utils.py
index 0a41645..be7e869 100644
--- a/ofdpa/utils.py
+++ b/ofdpa/utils.py
@@ -331,7 +331,7 @@
     port_to_src_mac_str     = {}
     port_to_dst_mac         = {}
     port_to_dst_mac_str     = {}
-    mpls_labels_to_port     = []
+
     port_to_mpls_label_1    = {}
     port_to_mpls_label_2    = {}
     port_to_mpls_label_pw   = {}
@@ -508,3 +508,154 @@
         port_to_dst_mac_str,
         Groups
         )
+
+MPLS_FLOW_TABLE_0           = 23
+OF_DPA_MPLS_SWAP_Label      = 5
+
+def fill_pw_intermediate_transport_pipeline(
+    controller,
+    logging,
+    ports,
+    mpls_labels
+    ):
+    """
+    This method, according to the scenario, fills properly
+    the pw pipeline. The method generates using ports data the
+    necessary information to fill the pw pipeline and
+    fills properly the pipeline which consists into:
+
+    """
+
+    Groups                  = Queue.LifoQueue( )
+    out_vlan                = 4094
+    port_to_src_mac         = {}
+    port_to_src_mac_str     = {}
+    port_to_dst_mac         = {}
+    port_to_dst_mac_str     = {}
+    port_to_mpls_label_2    = {}
+    port_to_mpls_label_1    = {}
+    port_to_mpls_label_pw   = {}
+    port_to_switch_mac      = {}
+    port_to_switch_mac_str  = {}
+
+    for port in ports:
+        mpls_label_1                    = port + 10
+        mpls_label_2                    = port + 100
+        mpls_label_pw                   = port + 300
+        src_mac                         = [ 0x00, 0x00, 0x00, 0x00, 0x11, port ]
+        src_mac_str                     = ':'.join( [ '%02X' % x for x in src_mac ] )
+        dst_mac                         = [ 0x00, 0x00, 0x00, 0x11, 0x11, port ]
+        dst_mac_str                     = ':'.join( [ '%02X' % x for x in dst_mac ] )
+        switch_mac                      = [ 0x00, 0x00, 0x00, 0x00, 0x00, port ]
+        switch_mac_str                  = ':'.join( [ '%02X' % x for x in switch_mac ] )
+        port_to_src_mac[port]           = src_mac
+        port_to_src_mac_str[port]       = src_mac_str
+        port_to_dst_mac[port]           = dst_mac
+        port_to_dst_mac_str[port]       = dst_mac_str
+        port_to_mpls_label_1[port]      = mpls_label_1
+        port_to_mpls_label_2[port]      = mpls_label_2
+        port_to_mpls_label_pw[port]     = mpls_label_pw
+        port_to_switch_mac[port]        = switch_mac
+        port_to_switch_mac_str[port]    = switch_mac_str
+
+    for pair in itertools.product(ports, ports):
+        in_port     = pair[0]
+        out_port    = pair[1]
+        if out_port == in_port:
+            continue
+        # add l2 interface group, we have to pop the VLAN;
+        l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+            ctrl=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=controller,
+            ref_gid=l2_intf_gid,
+            dst_mac=port_to_dst_mac[in_port],
+            src_mac=port_to_src_mac[out_port],
+            vid=out_vlan,
+            index=in_port
+            )
+        Groups._put( mpls_intf_gid )
+        # add MPLS flows
+        if mpls_labels >=2:
+            add_mpls_flow_pw(
+                ctrl=controller,
+                action_group_id=mpls_intf_gid,
+                label=port_to_mpls_label_2[in_port],
+                ethertype=0x8847,
+                tunnel_index=1,
+                bos=0
+                )
+        else:
+            mpls_tunnel_gid, mpls_tunnel_msg = add_mpls_tunnel_label_group(
+                ctrl=controller,
+                ref_gid=mpls_intf_gid,
+                subtype=OF_DPA_MPLS_Tunnel_Label_2,
+                index=in_port,
+                label=port_to_mpls_label_2[in_port]
+                )
+            Groups._put( mpls_tunnel_gid )
+            mpls_tunnel_gid, mpls_tunnel_msg = add_mpls_tunnel_label_group(
+                ctrl=controller,
+                ref_gid=mpls_tunnel_gid,
+                subtype=OF_DPA_MPLS_Tunnel_Label_1,
+                index=in_port,
+                label=port_to_mpls_label_1[in_port]
+                )
+            Groups._put( mpls_tunnel_gid )
+            mpls_swap_gid, mpls_tunnel_msg = add_mpls_swap_label_group(
+                ctrl=controller,
+                ref_gid=mpls_tunnel_gid,
+                subtype=OF_DPA_MPLS_SWAP_Label,
+                index=in_port,
+                label=port_to_mpls_label_pw[in_port]
+                )
+            Groups._put( mpls_swap_gid )
+            add_mpls_flow_pw(
+                ctrl=controller,
+                action_group_id=mpls_swap_gid,
+                label=port_to_mpls_label_pw[in_port],
+                ethertype=0x8847,
+                tunnel_index=1,
+                bos=1,
+                popMPLS=False,
+                popL2=False
+                )
+        # add Termination flow
+        add_termination_flow(
+            ctrl=controller,
+            in_port=in_port,
+            eth_type=0x8847,
+            dst_mac=port_to_switch_mac[in_port],
+            vlanid=out_vlan,
+            goto_table=MPLS_FLOW_TABLE_0)
+        # add VLAN flows
+        add_one_vlan_table_flow(
+            ctrl=controller,
+            of_port=in_port,
+            vlan_id=out_vlan,
+            flag=VLAN_TABLE_FLAG_ONLY_TAG,
+            mpls_type=None
+            )
+        add_one_vlan_table_flow(
+            ctrl=controller,
+            of_port=in_port,
+            vlan_id=out_vlan,
+            flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+            )
+
+    return (
+        port_to_mpls_label_2,
+        port_to_mpls_label_1,
+        port_to_mpls_label_pw,
+        port_to_switch_mac_str,
+        port_to_src_mac_str,
+        port_to_dst_mac_str,
+        Groups
+        )
diff --git a/src/python/loxi/of13/oxm.py b/src/python/loxi/of13/oxm.py
index 193ff6f..9b46aab 100755
--- a/src/python/loxi/of13/oxm.py
+++ b/src/python/loxi/of13/oxm.py
@@ -6152,6 +6152,7 @@
 
 VPWS                        = 1
 TUNNEL_ID_BASE              = 0x10000
+L3_PHP                      = 32
 
 class exp1ByteValue(oxm):
     type_len = 0xffff0005