Termination support

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

Change-Id: I1f4fa377681fc2a4b4aa106746de6bd8e1717860
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 75a1df5..15e6e99 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -164,6 +164,26 @@
 
     return group_id_list, msgs
 
+def add_one_l2_unfiltered_group(ctrl, of_port, send_barrier=False):
+    # group table
+    # set up untag groups for each port
+    group_id = encode_l2_unfiltered_group_id(of_port)
+    actions = [ofp.action.output(of_port)]
+    actions.append(ofp.action.set_field(ofp.oxm.exp1ByteValue(exp_type=24, value=1)))
+
+    buckets = [ofp.bucket(actions=actions)]
+    request = ofp.message.group_add(
+        group_type=ofp.OFPGT_INDIRECT,
+        group_id=group_id,
+        buckets=buckets
+    )
+    ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
+    return group_id, request
+
 def add_l2_interface_group(ctrl, ports, vlan_id=1, is_tagged=False, send_barrier=False):
     # group table
     # set up untag groups for each port
@@ -1117,7 +1137,7 @@
 
     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):
+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))
     match.oxm_list.append(ofp.oxm.mpls_label(label))
@@ -1125,9 +1145,16 @@
 
     actions = []
     actions.append(ofp.action.dec_mpls_ttl())
-    if pop == True:
+    if popMPLS == True:
         actions.append(ofp.action.copy_ttl_in())
         actions.append(ofp.action.pop_mpls(ethertype))
+    if bos==1 and popL2 == True:
+        actions.append(ofp.action.ofdpa_pop_l2_header())
+        actions.append(ofp.action.ofdpa_pop_cw())
+        actions.append(ofp.action.set_field(ofp.oxm.tunnel_id(tunnel_index + ofp.oxm.TUNNEL_ID_BASE)))
+        # 0x0002nnnn is for UNI interfaces
+        actions.append(ofp.action.set_field(ofp.oxm.exp4ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_L2_PORT, value=0x00020000 + of_port)))
+        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.group(action_group_id))
 
     request = ofp.message.flow_add(
diff --git a/ofdpa/flows.py b/ofdpa/flows.py
index fa4decd..dd04fa9 100755
--- a/ofdpa/flows.py
+++ b/ofdpa/flows.py
@@ -1924,3 +1924,6 @@
             delete_all_flows( self.controller )
             delete_groups( self.controller, groups )
             delete_all_groups( self.controller )
+
+
+
diff --git a/ofdpa/utils.py b/ofdpa/utils.py
index be7e869..cf797e8 100644
--- a/ofdpa/utils.py
+++ b/ofdpa/utils.py
@@ -659,3 +659,107 @@
         port_to_dst_mac_str,
         Groups
         )
+
+def fill_pw_termination_pipeline(
+    controller,
+    logging,
+    in_port,
+    out_port,
+    egress_tags,
+    ):
+    """
+    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_mpls_label_pw   = {}
+    port_to_vlan_2          = {}
+    port_to_vlan_1          = {}
+    port_to_switch_mac      = {}
+    port_to_switch_mac_str  = {}
+    ports                   = [in_port, out_port]
+
+    for port in ports:
+        mpls_label_pw                   = port + 300
+        in_vlan_id_1                    = port + 1
+        in_vlan_id_2                    = port + 100
+        switch_mac                      = [ 0x00, 0x00, 0x00, 0x00, 0x11, port ]
+        switch_mac_str                  = ':'.join( [ '%02X' % x for x in switch_mac ] )
+        port_to_mpls_label_pw[port]     = mpls_label_pw
+        port_to_vlan_2[port]            = in_vlan_id_2
+        port_to_vlan_1[port]            = in_vlan_id_1
+        port_to_switch_mac[port]        = switch_mac
+        port_to_switch_mac_str[port]    = switch_mac_str
+
+    # add l2 interface group;
+    if egress_tags == 2:
+        l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+            ctrl=controller,
+            port=out_port,
+            vlan_id=port_to_vlan_2[out_port],
+            is_tagged=True,
+            send_barrier=False
+            )
+    elif egress_tags == 1:
+        l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+            ctrl=controller,
+            port=out_port,
+            vlan_id=port_to_vlan_1[out_port],
+            is_tagged=True,
+            send_barrier=False
+            )
+    elif egress_tags == 0:
+        l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+            ctrl=controller,
+            port=out_port,
+            vlan_id=port_to_vlan_1[out_port],
+            is_tagged=False,
+            send_barrier=False
+            )
+    Groups._put( l2_intf_gid )
+    add_mpls_flow_pw(
+        ctrl=controller,
+        action_group_id=l2_intf_gid,
+        label=port_to_mpls_label_pw[out_port],
+        ethertype=0x6558,
+        bos=1,
+        tunnel_index=1,
+        popMPLS=True,
+        popL2=True,
+        of_port=in_port
+        )
+    # 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_pw,
+        port_to_vlan_2,
+        port_to_in_vlan_1,
+        port_to_switch_mac_str,
+        Groups
+        )