Add PW initiation pipeline

Changes:

- Adds a reusable utility function to test all scenarios;
- Updates the missing code related to the extensions;
- Adds the missing utility functions to fill the single tables;
- Fix function to pack experimenter fields

Change-Id: Ic36fd4279fad18e22756fa307b154c9ce7ed483f
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 3d80de7..2a8eba3 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -25,7 +25,11 @@
 PORT_FLOW_TABLE=0
 VLAN_FLOW_TABLE=10
 VLAN_1_FLOW_TABLE=11
+MPLS_L2_PORT_FLOW_TABLE=13
+MPLS_L2_PORT_DSCP_TRUST_FLOW_TABLE=15
+MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE=16
 TERMINATION_FLOW_TABLE=20
+MPLS_TYPE_FLOW_TABLE=29
 UCAST_ROUTING_FLOW_TABLE=30
 MCAST_ROUTING_FLOW_TABLE=40
 BRIDGE_FLOW_TABLE=50
@@ -791,6 +795,70 @@
 
     return request
 
+def add_one_vlan_table_flow_pw(ctrl, of_port, tunnel_index, new_vlan_id=1, vlan_id=1, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_TAG, send_barrier=False):
+    # table 10: vlan
+    # goto to table 13
+    if flag == VLAN_TABLE_FLAG_ONLY_TAG:
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(of_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000+vlan_id, 0x1fff))
+
+        actions=[]
+        if vlan_id == -1:
+            actions.append(ofp.action.pop_vlan())
+        if new_vlan_id > 1:
+            actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+new_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
+        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=10,
+            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 %d tagged packets on port %d and go to table %d" % (vlan_id, of_port, MPLS_L2_PORT_FLOW_TABLE))
+        ctrl.message_send(request)
+
+    if flag == VLAN_TABLE_FLAG_ONLY_UNTAG:
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(of_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(0))
+
+        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.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
+        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=10,
+            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 %d untagged packets on port %d and go to table %d" % (vlan_id, of_port, MPLS_L2_PORT_FLOW_TABLE))
+        ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
+    return request
+
 def add_one_vlan_1_table_flow(ctrl, of_port, 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 20
@@ -847,6 +915,45 @@
 
     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()
+    match.oxm_list.append(ofp.oxm.in_port(of_port))
+    match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000+inner_vlan_id,0x1fff))
+    match.oxm_list.append(ofp.oxm.exp2ByteValue(ofp.oxm.OFDPA_EXP_TYPE_OVID, 0x1000+outer_vlan_id))
+
+    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)))
+    else:
+        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)))
+    # 0x0000nnnn is for UNI interfaces
+    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)
+    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)
+
+    return request
+
 def add_bridge_flow(ctrl, dst_mac, vlanid, group_id, send_barrier=False):
     match = ofp.match()
     priority=500
@@ -1399,6 +1506,9 @@
 OFDPA_MPLS_GROUP_SUBTYPE_ECMP=8
 OFDPA_MPLS_GROUP_SUBTYPE_L2_TAG=10
 
+
+
+
 def encode_mpls_interface_group_id(subtype, index):
     index=index&0x00ffffff
     assert(subtype==0)
@@ -1424,7 +1534,8 @@
     action=[]
     action.append(ofp.action.set_field(ofp.oxm.eth_src(src_mac)))
     action.append(ofp.action.set_field(ofp.oxm.eth_dst(dst_mac)))
-    action.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+vid)))
+    if vid != 1:
+        action.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+vid)))
     action.append(ofp.action.group(ref_gid))
 
     buckets = [ofp.bucket(actions=action)]
@@ -1437,6 +1548,29 @@
     ctrl.message_send(request)
     return mpls_group_id, request
 
+def add_mpls_tunnel_label_group(
+    ctrl,
+    ref_gid,
+    subtype,
+    index,
+    label,
+    ):
+
+    action=[]
+    action.append(ofp.action.push_mpls(0x8847))
+    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,
@@ -1506,6 +1640,40 @@
 
     return mpls_group_id, request
 
+def add_mpls_l2_port_flow(ctrl, of_port, mpls_l2_port, tunnel_index, ref_gid, qos_index=0):
+    """
+    Only action is Group, which must indicate one of:
+    MPLS L2 VPN Label or Fast Failover Protection Group.
+    ref_gid contains this information
+    """
+    tunnel_id = tunnel_index + ofp.oxm.TUNNEL_ID_BASE
+
+    match = ofp.match()
+    match.oxm_list.append(ofp.oxm.exp4ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_L2_PORT, value=0x00000000 + of_port))
+    match.oxm_list.append(ofp.oxm.tunnel_id(tunnel_index + ofp.oxm.TUNNEL_ID_BASE))
+
+    action = []
+    action.append(ofp.action.group(ref_gid))
+    assert(qos_index>=0)
+    action.append(ofp.action.set_field(ofp.oxm.exp1ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_QOS_INDEX, value=qos_index)))
+
+    request = ofp.message.flow_add(
+            table_id=MPLS_L2_PORT_FLOW_TABLE,
+            cookie=42,
+            match=match,
+            instructions=[
+                    ofp.instruction.write_actions(
+                        actions=action
+                        ),
+                    ofp.instruction.goto_table(MPLS_L2_PORT_PCP_TRUST_FLOW_TABLE)                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1)
+    logging.info("Inserting flow %d mpls_l2_port, %d tunnel_id, action %x group and go to table %d", mpls_l2_port, tunnel_id, ref_gid, MPLS_L2_PORT_DSCP_TRUST_FLOW_TABLE)
+    ctrl.message_send(request)
+    return request
+
+    return
+
 def add_mpls_forwarding_group(ctrl, subtype, index, ref_gids,
                               watch_port=None,
 							  watch_group=ofp.OFPP_ANY,
@@ -1553,7 +1721,7 @@
 
 
 """
-dislay
+display
 """
 def print_current_table_flow_stat(ctrl, table_id=0xff):
     stat_req=ofp.message.flow_stats_request()
diff --git a/ofdpa/flows.py b/ofdpa/flows.py
index 675b284..fa4decd 100755
--- a/ofdpa/flows.py
+++ b/ofdpa/flows.py
@@ -1924,4 +1924,3 @@
             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 7fd78a0..0a41645 100644
--- a/ofdpa/utils.py
+++ b/ofdpa/utils.py
@@ -1,8 +1,79 @@
 import Queue
+import itertools
 
 from oftest.testutils import *
 from accton_util import *
 
+"""
+MISC
+"""
+
+def print_port_stats(test, port):
+    entries = get_port_stats(test, port)
+    for item in entries:
+        packet_rcv          = item.rx_packets
+        packet_rcv_dropped  = item.rx_dropped
+        packet_rcv_errors   = item.rx_errors
+
+        packet_sent         = item.tx_packets
+        packet_sent_dropped = item.tx_dropped
+        packet_sent_errors  = item.tx_errors
+
+    print "Port %d stats count: tx %d rx %d - tx_dropped %d rx_dropped %d - tx_errors %d rx_errors %d" % (
+        port, packet_sent, packet_rcv, packet_sent_dropped, packet_rcv_dropped, packet_sent_errors, packet_rcv_errors
+        )
+
+def filter_dhcp(controller):
+    match = ofp.match( )
+    match.oxm_list.append( ofp.oxm.eth_type( 0x0800 ) )
+    match.oxm_list.append( ofp.oxm.ip_proto( 17 ) )
+    match.oxm_list.append( ofp.oxm.udp_src( 68 ) )
+    match.oxm_list.append( ofp.oxm.udp_dst( 67 ))
+    request = ofp.message.flow_add(
+        table_id=60,
+        cookie=42,
+        match=match,
+        instructions=[ofp.instruction.clear_actions( )],
+        buffer_id=ofp.OFP_NO_BUFFER,
+        priority=1
+        )
+    controller.message_send( request )
+    do_barrier( controller )
+
+def filter_ipv6(controller):
+    match = ofp.match( )
+    match.oxm_list.append( ofp.oxm.eth_type( 0x86dd ) )
+    request = ofp.message.flow_add(
+        table_id=60,
+        cookie=42,
+        match=match,
+        instructions=[ofp.instruction.clear_actions( )],
+        buffer_id=ofp.OFP_NO_BUFFER,
+        priority=1
+        )
+    controller.message_send( request )
+    do_barrier( controller )
+
+def filter_igmp(controller):
+    match = ofp.match( )
+    match.oxm_list.append( ofp.oxm.eth_type( 0x0800 ) )
+    match.oxm_list.append( ofp.oxm.ip_proto( 2 ) )
+    request = ofp.message.flow_add(
+        table_id=60,
+        cookie=42,
+        match=match,
+        instructions=[ofp.instruction.clear_actions( )],
+        buffer_id=ofp.OFP_NO_BUFFER,
+        priority=1
+        )
+    controller.message_send( request )
+    do_barrier( controller )
+
+
+"""
+MULTICAST Pipelines
+"""
+
 def fill_mcast_pipeline_L3toL2(
     controller,
     logging,
@@ -219,4 +290,221 @@
         port_to_src_ip_str,
         port_to_intf_src_mac_str,
         Groups
-        )
\ No newline at end of file
+        )
+
+"""
+VPWS Pipeline
+"""
+
+OF_DPA_MPLS_L2_VPN_Label     = 1
+OF_DPA_MPLS_Tunnel_Label_1   = 3
+OF_DPA_MPLS_Tunnel_Label_2   = 4
+
+EGRESS_UNTAGGED     = 1
+EGRESS_TAGGED       = 2
+EGRESS_TAGGED_TRANS = 3
+
+
+def fill_pw_initiation_pipeline(
+    controller,
+    logging,
+    in_port,
+    out_port,
+    ingress_tags,
+    egress_tag,
+    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_in_vlan_1       = {}
+    port_to_in_vlan_2       = {}
+    port_to_in_vlan_3       = {}
+    port_to_src_mac         = {}
+    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   = {}
+    ports                   = [in_port, out_port]
+
+    for port in ports:
+        in_vlan_id_1                = port + 1
+        in_vlan_id_2                = port + 100
+        in_vlan_id_3                = port + 300
+        mpls_label_1                = port + 100
+        mpls_label_2                = port + 200
+        mpls_label_pw               = port + 300
+        port_to_in_vlan_1[port]     = in_vlan_id_1
+        port_to_in_vlan_2[port]     = in_vlan_id_2
+        port_to_in_vlan_3[port]     = in_vlan_id_3
+        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 ] )
+        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
+
+    # 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 )
+    mpls_gid = mpls_intf_gid
+    # add MPLS tunnel label groups, the number depends on the labels
+    if mpls_labels == 2:
+        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_gid = mpls_tunnel_gid
+    elif mpls_labels == 1:
+        mpls_tunnel_gid, mpls_tunnel_msg = add_mpls_tunnel_label_group(
+            ctrl=controller,
+            ref_gid=mpls_intf_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_gid = mpls_tunnel_gid
+
+    # add MPLS L2 VPN group
+    mpls_l2_vpn_gid, mpls_l2_vpn_msg = add_mpls_label_group(
+        ctrl=controller,
+        subtype=OF_DPA_MPLS_L2_VPN_Label,
+        index=in_port,
+        ref_gid=mpls_gid,
+        push_l2_header=True,
+        push_vlan=True,
+        push_mpls_header=True,
+        push_cw=True,
+        set_mpls_label=port_to_mpls_label_pw[in_port],
+        set_bos=1,
+        cpy_ttl_outward=True
+    )
+
+    Groups._put( mpls_l2_vpn_gid )
+    # add MPLS L2 port flow
+    add_mpls_l2_port_flow(
+        ctrl=controller,
+        of_port=in_port,
+        mpls_l2_port=in_port,
+        tunnel_index=1,
+        ref_gid=mpls_l2_vpn_gid
+        )
+    # add VLAN flows table
+    if ingress_tags == 2:
+        if egress_tag == EGRESS_TAGGED:
+            add_one_vlan_1_table_flow_pw(
+                ctrl=controller,
+                of_port=in_port,
+                tunnel_index=1,
+                new_outer_vlan_id=-1,
+                outer_vlan_id=port_to_in_vlan_2[in_port],
+                inner_vlan_id=port_to_in_vlan_1[in_port],
+                )
+        elif egress_tag == EGRESS_TAGGED_TRANS:
+            add_one_vlan_1_table_flow_pw(
+                ctrl=controller,
+                of_port=in_port,
+                tunnel_index=1,
+                new_outer_vlan_id=port_to_in_vlan_3[in_port],
+                outer_vlan_id=port_to_in_vlan_2[in_port],
+                inner_vlan_id=port_to_in_vlan_1[in_port],
+                )
+        add_one_vlan_table_flow(
+            ctrl=controller,
+            of_port=in_port,
+            vlan_id=port_to_in_vlan_2[in_port],
+            flag=VLAN_TABLE_FLAG_ONLY_STACKED,
+            )
+    elif ingress_tags == 1:
+        if egress_tag == EGRESS_TAGGED:
+            add_one_vlan_table_flow_pw(
+                ctrl=controller,
+                of_port=in_port,
+                tunnel_index=1,
+                vlan_id=port_to_in_vlan_1[in_port],
+                flag=VLAN_TABLE_FLAG_ONLY_TAG,
+                )
+        elif egress_tag == EGRESS_TAGGED_TRANS:
+            add_one_vlan_table_flow_pw(
+                ctrl=controller,
+                of_port=in_port,
+                tunnel_index=1,
+                vlan_id=port_to_in_vlan_1[in_port],
+                new_vlan_id=port_to_in_vlan_3[in_port],
+                flag=VLAN_TABLE_FLAG_ONLY_TAG,
+                )
+    elif ingress_tags == 0:
+        filter_dhcp(controller)
+        filter_ipv6(controller)
+        filter_igmp(controller)
+        if egress_tag == EGRESS_UNTAGGED:
+            add_one_vlan_table_flow_pw(
+                ctrl=controller,
+                of_port=in_port,
+                tunnel_index=1,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG,
+                )
+        elif egress_tag == EGRESS_TAGGED:
+            add_one_vlan_table_flow_pw(
+                ctrl=controller,
+                of_port=in_port,
+                tunnel_index=1,
+                vlan_id=port_to_in_vlan_1[in_port],
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG,
+                )
+
+    return (
+        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
+        )
diff --git a/src/python/loxi/of13/oxm.py b/src/python/loxi/of13/oxm.py
index 49c32bc..193ff6f 100755
--- a/src/python/loxi/of13/oxm.py
+++ b/src/python/loxi/of13/oxm.py
@@ -6146,9 +6146,13 @@
 OFDPA_EXP_TYPE_COLOR_ACTION_INDEX=16
 OFDPA_EXP_TYPE_TXFCL        =17
 OFDPA_EXP_TYPE_RXFCL        =18
+OFDPA_EXP_TYPE_MPLS_TYPE    = 23
 OFDPA_EXP_TYPE_RX_TIMESAMP  =19
 OFDPA_EXP_TYPE_ACTSET_OUTPUT=42
 
+VPWS                        = 1
+TUNNEL_ID_BASE              = 0x10000
+
 class exp1ByteValue(oxm):
     type_len = 0xffff0005
 
@@ -6165,7 +6169,7 @@
         packed.append(struct.pack("!L", self.type_len | (self.exp_type <<9)))
         packed.append(struct.pack("!L", OFDPA_EXPERIMETER))
         #packed.append(struct.pack("!H", self.exp_type))
-        packed.append(struct.pack("!b", self.value))        
+        packed.append(struct.pack("!b", self.value))
         return ''.join(packed)
 
     @staticmethod
@@ -6182,7 +6186,7 @@
     def __eq__(self, other):
         if type(self) != type(other): return False
         if self.value != other.value: return False
-        if self.exp_type != other.exp_type: return False        
+        if self.exp_type != other.exp_type: return False
         return True
 
     def pretty_print(self, q):
@@ -6213,7 +6217,7 @@
         packed.append(struct.pack("!L", self.type_len | (self.exp_type <<9)))
         packed.append(struct.pack("!L", OFDPA_EXPERIMETER))
         #packed.append(struct.pack("!H", self.exp_type))
-        packed.append(struct.pack("!H", self.value))        
+        packed.append(struct.pack("!H", self.value))
         return ''.join(packed)
 
     @staticmethod
@@ -6230,7 +6234,7 @@
     def __eq__(self, other):
         if type(self) != type(other): return False
         if self.value != other.value: return False
-        if self.exp_type != other.exp_type: return False        
+        if self.exp_type != other.exp_type: return False
         return True
 
     def pretty_print(self, q):
@@ -6245,9 +6249,8 @@
 
 oxm.subtypes[0xffff0008] = exp2ByteValue
 
-
 class exp4ByteValue(oxm):
-    type_len = 0xffff000a
+    type_len = 0xffff0008
 
     def __init__(self, exp_type=0, value=None):
         if value != None:
@@ -6259,10 +6262,9 @@
 
     def pack(self):
         packed = []
-        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.type_len | (self.exp_type <<9)))
         packed.append(struct.pack("!L", OFDPA_EXPERIMETER))
-        packed.append(struct.pack("!H", self.exp_type))
-        packed.append(struct.pack("!L", self.value))        
+        packed.append(struct.pack("!L", self.value))
         return ''.join(packed)
 
     @staticmethod
@@ -6279,7 +6281,7 @@
     def __eq__(self, other):
         if type(self) != type(other): return False
         if self.value != other.value: return False
-        if self.exp_type != other.exp_type: return False        
+        if self.exp_type != other.exp_type: return False
         return True
 
     def pretty_print(self, q):