Implements [CORD-574] and [CORD-573]

Changes:
- Adds 10 new procedures to test IPv6 support;
- Adds missing IPv6 flows;
- Adds IPv6 over MPLS packets in Scapy;
- Update README;

Change-Id: I0277c04919f602caf4031645184f001676d77b5e
diff --git a/README.md b/README.md
index fdc088f..f59d638 100755
--- a/README.md
+++ b/README.md
@@ -170,3 +170,21 @@
 
 For major details on the test look the comments in the code.
 
+# IPv6 Test Result Summary
+
+The following tests are implemented in ipv6_flows.py and these are their results.
+
+Test Results                | 3.0 EA0
+----------------------      | -------
+PacketInICMPv6              | ok
+PacketInIPv6Table           | ok
+_128UcastUnTagged           | ok
+_128ECMPVpn                 | ok
+_128ECMPL3                  | ok
+_64UcastUnTagged            | ok
+_64ECMPVpn                  | ok
+_64ECMPL3                   | ok
+_0UcastV6                   | ok
+_MPLSTerminationV6          | ok
+
+For major details on the test look the comments in the code.
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 176ef28..a729f79 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -5,6 +5,7 @@
 import ofp
 import time
 from oftest.testutils import *
+from oftest.parse import parse_ipv6
 
 from ncclient import manager
 import ncclient
@@ -319,7 +320,7 @@
     ctrl.message_send(request)
     return request
 
-def add_l3_unicast_group(ctrl, port, vlanid, id, src_mac, dst_mac):
+def add_l3_unicast_group(ctrl, port, vlanid, id, src_mac, dst_mac, send_barrier=False):
     group_id = encode_l2_interface_group_id(vlanid, port)
 
     action=[]
@@ -341,6 +342,10 @@
                                     buckets=buckets
                                    )
     ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
     return request
 
 def add_l3_interface_group(ctrl, port, vlanid, id, src_mac):
@@ -361,7 +366,7 @@
     ctrl.message_send(request)
     return request
 
-def add_l3_ecmp_group(ctrl, id, l3_ucast_groups):
+def add_l3_ecmp_group(ctrl, id, l3_ucast_groups, send_barrier=False):
     buckets=[]
     for group in l3_ucast_groups:
         buckets.append(ofp.bucket(actions=[ofp.action.group(group)]))
@@ -372,6 +377,10 @@
                                     buckets=buckets
                                    )
     ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
     return request
 
 def mod_l3_ecmp_group(ctrl, id, l3_ucast_groups):
@@ -1101,6 +1110,40 @@
 
     return request
 
+def add_unicast_v6_routing_flow(ctrl, eth_type, dst_ip, mask, action_group_id, vrf=0, send_ctrl=False, send_barrier=False):
+    match = ofp.match()
+    match.oxm_list.append(ofp.oxm.eth_type(eth_type))
+    if vrf != 0:
+        match.oxm_list.append(ofp.oxm.exp2ByteValue(ofp.oxm.OFDPA_EXP_TYPE_VRF, vrf))
+
+    match.oxm_list.append(ofp.oxm.ipv6_dst_masked(parse_ipv6(dst_ip), parse_ipv6(mask)))
+
+    instructions = []
+    instructions.append(ofp.instruction.goto_table(60))
+    if send_ctrl:
+        instructions.append(ofp.instruction.apply_actions(
+                            actions=[ofp.action.output( port=ofp.OFPP_CONTROLLER,
+                            max_len=ofp.OFPCML_NO_BUFFER)]))
+    else:
+        instructions.append(ofp.instruction.write_actions(
+                        actions=[ofp.action.group(action_group_id)]))
+
+    request = ofp.message.flow_add(
+            table_id=30,
+            cookie=42,
+            match=match,
+            instructions=instructions,
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1)
+
+    logging.info("Inserting unicast routing flow eth_type %lx, dip %s",eth_type, dst_ip)
+    ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
+    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):
     match = ofp.match()
     match.oxm_list.append(ofp.oxm.eth_type(0x8847))
@@ -1205,6 +1248,34 @@
 
     return request
 
+def add_acl_rule(ctrl, eth_type=None, ip_proto=None, send_barrier=False):
+    match = ofp.match()
+    if eth_type != None:
+            match.oxm_list.append(ofp.oxm.eth_type(eth_type))
+    if ip_proto != None:
+        match.oxm_list.append(ofp.oxm.ip_proto(ip_proto))
+
+    request = ofp.message.flow_add(
+        table_id=60,
+        cookie=42,
+        match=match,
+        instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[ofp.action.output(port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER)]
+                    ),
+                ],
+        buffer_id=ofp.OFP_NO_BUFFER,
+        priority=1
+        )
+
+    logging.info("Inserting ACL flow eth_type %lx, ip_proto %ld", eth_type, ip_proto)
+    ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
+    return request
+
 #dpctl tcp:192.168.1.1:6633 flow-mod table=28,cmd=add,prio=281 eth_type=0x800,ip_dst=100.0.0.1,ip_proto=6,tcp_dst=5000 write:set_field=ip_dst:10.0.0.1,set_field=tcp_dst:2000,group=0x71000001 goto:60
 def add_dnat_flow(ctrl, eth_type, ip_dst, ip_proto, tcp_dst, set_ip_dst, set_tcp_dst, action_group_id):
     match = ofp.match()
@@ -1590,7 +1661,7 @@
     return index + (10 << OFDPA_GROUP_TYPE_SHIFT)+(subtype<<OFDPA_MPLS_SUBTYPE_SHIFT)
 
 
-def add_mpls_intf_group(ctrl, ref_gid, dst_mac, src_mac, vid, index, subtype=0):
+def add_mpls_intf_group(ctrl, ref_gid, dst_mac, src_mac, vid, index, subtype=0, send_barrier=False):
     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)))
@@ -1606,6 +1677,10 @@
                                     buckets=buckets
                                    )
     ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
     return mpls_group_id, request
 
 def add_mpls_tunnel_label_group(
@@ -1668,7 +1743,8 @@
                          set_ttl=None,
                          cpy_ttl_outward=False,
                          oam_lm_tx_count=False,
-                         set_pri_from_table=False
+                         set_pri_from_table=False,
+                         send_barrier=False
                          ):
     """
     @ref_gid: only can be mpls intf group or mpls tunnel label 1/2 group
@@ -1720,6 +1796,9 @@
                                    )
     ctrl.message_send(request)
 
+    if send_barrier:
+        do_barrier(ctrl)
+
     return mpls_group_id, request
 
 def add_mpls_l2_port_flow(ctrl, of_port, mpls_l2_port, tunnel_index, ref_gid, qos_index=0):
diff --git a/ofdpa/ipv6_flows.py b/ofdpa/ipv6_flows.py
new file mode 100644
index 0000000..a7161a5
--- /dev/null
+++ b/ofdpa/ipv6_flows.py
@@ -0,0 +1,1097 @@
+"""
+Check README file
+"""
+import Queue
+
+import itertools
+from oftest import config
+import inspect
+import logging
+import oftest.base_tests as base_tests
+import ofp
+from oftest.testutils import *
+from accton_util import *
+from utils import *
+import time
+
+class PacketInICMPv6( base_tests.SimpleDataPlane ):
+    """
+    Verify ACL rule for ICMPv6 packet. The expected behavior is
+    Packet-In message in the control plane.
+    """
+
+    def runTest( self ):
+        try:
+            # We insert an ACL rule for ICMPv6
+            add_acl_rule(
+                self.controller,
+                eth_type=0x86dd,
+                ip_proto=0x3A,
+                send_barrier=False
+                )
+
+            ports = config[ "port_map" ].keys( )
+            for in_port in ports:
+                # Neighbor solicitation
+                parsed_icmpv6_pkt = simple_icmpv6_packet(icmp_type=135)
+                icmpv6_pkt = str( parsed_icmpv6_pkt )
+                self.dataplane.send(in_port, icmpv6_pkt)
+                verify_packet_in(self, icmpv6_pkt, in_port, ofp.OFPR_ACTION)
+                verify_no_other_packets( self )
+                # Neighbor advertisement
+                parsed_icmpv6_pkt = simple_icmpv6_packet(icmp_type=136)
+                icmpv6_pkt = str( parsed_icmpv6_pkt )
+                self.dataplane.send(in_port, icmpv6_pkt)
+                verify_packet_in(self, icmpv6_pkt, in_port, ofp.OFPR_ACTION)
+                verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_all_groups( self.controller )
+
+class PacketInIPv6Table( base_tests.SimpleDataPlane ):
+    """
+    Verify Packet-in message from IP table when controller action is used
+    Send a packet to each dataplane port and verify that a packet
+    in message is received from the controller for each
+    #todo verify you stop receiving after adding rule
+    """
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            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]
+                vlan_id         = in_port
+                dst_mac[ 5 ]    = vlan_id
+                dst_ip          = dip % in_port
+                # We fill the unicast_table
+                add_unicast_v6_routing_flow(
+                    ctrl=self.controller,
+                    eth_type=0x86dd,
+                    dst_ip=dst_ip,
+                    mask="ffff:ffff:ffff:ffff::",
+                    action_group_id=None,
+                    vrf=0,
+                    send_ctrl=True,
+                    send_barrier=False
+                    )
+                # add termination flow
+                add_termination_flow(
+                    ctrl=self.controller,
+                    in_port=in_port,
+                    eth_type=0x86dd,
+                    dst_mac=dst_mac,
+                    vlanid=vlan_id
+                    )
+                # add vlan table flow
+                add_one_vlan_table_flow(
+                    ctrl=self.controller,
+                    of_port=in_port,
+                    vlan_id=vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_TAG
+                    )
+
+            for port in ports:
+                vlan_id             = port
+                dst_mac[ 5 ]        = vlan_id
+                dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+                dip_str             = dip % port
+                parsed_tcpv6_pkt    = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    dl_vlan_enable=True,
+                    vlan_vid=vlan_id,
+                    ipv6_dst=dip_str,
+                    ipv6_src=sip
+                    )
+                tcpv6_pkt = str( parsed_tcpv6_pkt )
+                self.dataplane.send(port, tcpv6_pkt)
+                verify_packet_in(self, tcpv6_pkt, port, ofp.OFPR_ACTION)
+                verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_all_groups( self.controller )
+
+class _128UcastUnTagged( base_tests.SimpleDataPlane ):
+    """ Verify /128 IP forwarding to L3 Interface"""
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups._put(l2gid)
+            # We create the L3 group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=vlan_id,
+                id=vlan_id,
+                src_mac=intf_src_mac,
+                dst_mac=dst_mac,
+                send_barrier=True
+                )
+            Groups._put( l3_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip=dst_ip,
+                mask="ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+                action_group_id=l3_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id,
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63
+                    )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            verify_packet(self, tcpv6_pkt, out_port )
+            verify_no_packet(self, tcpv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class _128ECMPVpn( base_tests.SimpleDataPlane ):
+    """  Verify MPLS IP VPN Initiation from /128 rule using ECMP  """
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+            mpls_label      = 255
+            label = (mpls_label, 0, 1, 63)
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups.put(l2gid)
+            mpls_gid, mpls_msg = add_mpls_intf_group(
+                ctrl=self.controller,
+                ref_gid=l2gid,
+                dst_mac=dst_mac,
+                src_mac=intf_src_mac,
+                vid=vlan_id,
+                index=out_port,
+                send_barrier=True
+                )
+            Groups.put( mpls_gid )
+            # add MPLS L3 VPN group
+            mpls_label_gid, mpls_label_msg = add_mpls_label_group(
+                ctrl=self.controller,
+                subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL,
+                index=out_port,
+                ref_gid=mpls_gid,
+                push_mpls_header=True,
+                set_mpls_label=mpls_label,
+                set_bos=1,
+                cpy_ttl_outward=True,
+                send_barrier=True
+                )
+            Groups.put( mpls_label_gid )
+            # Add ECMP group
+            ecmp_msg = add_l3_ecmp_group(
+                ctrl=self.controller,
+                id=vlan_id,
+                l3_ucast_groups=[ mpls_label_gid ],
+                send_barrier=True
+            )
+            Groups.put( ecmp_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip=dst_ip,
+                mask="ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+                action_group_id=ecmp_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_mplsv6_pkt = mplsv6_packet(
+                    pktlen=104,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63,
+                    label=[ label ]
+                    )
+            mplsv6_pkt = str( parsed_mplsv6_pkt )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            verify_packet(self, mplsv6_pkt, out_port )
+            verify_no_packet(self, mplsv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class _128ECMPL3( base_tests.SimpleDataPlane ):
+    """ Verifies /128 IP routing and ECMP """
+
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups.put(l2gid)
+            # We create the L3 group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=vlan_id,
+                id=vlan_id,
+                src_mac=intf_src_mac,
+                dst_mac=dst_mac,
+                send_barrier=True
+                )
+            Groups.put( l3_msg.group_id )
+            # Add ECMP group
+            ecmp_msg = add_l3_ecmp_group(
+                ctrl=self.controller,
+                id=vlan_id,
+                l3_ucast_groups=[ l3_msg.group_id ],
+                send_barrier=True
+            )
+            Groups.put( ecmp_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip=dst_ip,
+                mask="ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+                action_group_id=ecmp_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            verify_packet(self, tcpv6_pkt, out_port )
+            verify_no_packet(self, tcpv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+        finally:
+            print "END"
+            #delete_all_flows( self.controller )
+            #delete_groups( self.controller, Groups )
+            #delete_all_groups( self.controller )
+
+class _64UcastUntagged( base_tests.SimpleDataPlane ):
+    """ Verify /64 IP forwarding to L3 Interface"""
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups._put(l2gid)
+            # We create the L3 group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=vlan_id,
+                id=vlan_id,
+                src_mac=intf_src_mac,
+                dst_mac=dst_mac,
+                send_barrier=True
+                )
+            Groups._put( l3_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip=dst_ip,
+                mask="ffff:ffff:ffff:ffff::",
+                action_group_id=l3_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id,
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63
+                    )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            verify_packet(self, tcpv6_pkt, out_port )
+            verify_no_packet(self, tcpv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class _64ECMPVpn( base_tests.SimpleDataPlane ):
+    """  Verify MPLS IP VPN Initiation from /64 rule using ECMP  """
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+            mpls_label      = 255
+            label = (mpls_label, 0, 1, 63)
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups.put(l2gid)
+            mpls_gid, mpls_msg = add_mpls_intf_group(
+                ctrl=self.controller,
+                ref_gid=l2gid,
+                dst_mac=dst_mac,
+                src_mac=intf_src_mac,
+                vid=vlan_id,
+                index=out_port,
+                send_barrier=True
+                )
+            Groups.put( mpls_gid )
+            # add MPLS L3 VPN group
+            mpls_label_gid, mpls_label_msg = add_mpls_label_group(
+                ctrl=self.controller,
+                subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL,
+                index=out_port,
+                ref_gid=mpls_gid,
+                push_mpls_header=True,
+                set_mpls_label=mpls_label,
+                set_bos=1,
+                cpy_ttl_outward=True,
+                send_barrier=True
+                )
+            Groups.put( mpls_label_gid )
+            # Add ECMP group
+            ecmp_msg = add_l3_ecmp_group(
+                ctrl=self.controller,
+                id=vlan_id,
+                l3_ucast_groups=[ mpls_label_gid ],
+                send_barrier=True
+            )
+            Groups.put( ecmp_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip=dst_ip,
+                mask="ffff:ffff:ffff:ffff::",
+                action_group_id=ecmp_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_mplsv6_pkt = mplsv6_packet(
+                    pktlen=104,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63,
+                    label=[ label ]
+                    )
+            mplsv6_pkt = str( parsed_mplsv6_pkt )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            verify_packet(self, mplsv6_pkt, out_port )
+            verify_no_packet(self, mplsv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class _64ECMPL3( base_tests.SimpleDataPlane ):
+    """ Verifies /64 IP routing and ECMP """
+
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups.put(l2gid)
+            # We create the L3 group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=vlan_id,
+                id=vlan_id,
+                src_mac=intf_src_mac,
+                dst_mac=dst_mac,
+                send_barrier=True
+                )
+            Groups.put( l3_msg.group_id )
+            # Add ECMP group
+            ecmp_msg = add_l3_ecmp_group(
+                ctrl=self.controller,
+                id=vlan_id,
+                l3_ucast_groups=[ l3_msg.group_id ],
+                send_barrier=True
+            )
+            Groups.put( ecmp_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip=dst_ip,
+                mask="ffff:ffff:ffff:ffff::",
+                action_group_id=ecmp_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            verify_packet(self, tcpv6_pkt, out_port )
+            verify_no_packet(self, tcpv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class _0UcastV6( base_tests.SimpleDataPlane ):
+    """  Verify default gateway IP forwarding to L3 Interface ( /0 rule ) """
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups._put(l2gid)
+            # We create the L3 group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=vlan_id,
+                id=vlan_id,
+                src_mac=intf_src_mac,
+                dst_mac=dst_mac,
+                send_barrier=True
+                )
+            Groups._put( l3_msg.group_id )
+            # We fill the unicast_table
+            add_unicast_v6_routing_flow(
+                ctrl=self.controller,
+                eth_type=0x86dd,
+                dst_ip="::",
+                mask="::",
+                action_group_id=l3_msg.group_id,
+                vrf=0,
+                send_ctrl=False,
+                send_barrier=True
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x86dd,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id,
+                )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            self.dataplane.send(in_port, tcpv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63
+                    )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            verify_packet(self, tcpv6_pkt, out_port )
+            verify_no_packet(self, tcpv6_pkt, in_port )
+            verify_no_other_packets(self)
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, Groups )
+            delete_all_groups( self.controller )
+
+class _MPLSTerminationV6( base_tests.SimpleDataPlane ):
+    """ Verify MPLS termination with IPv6 traffic """
+
+    def runTest( self ):
+        try:
+
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            Groups = Queue.LifoQueue( )
+            r_dst_mac       = [ 0x00, 0x00, 0x00, 0xa2, 0x22, 0x00 ]
+            dst_mac         = [ 0x00, 0x00, 0x00, 0x22, 0xa2, 0x00 ]
+            intf_src_mac    = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00 ]
+            # We are assuming that the port number are xx"
+            dip             = "2000::%s"
+            sip             = "2000::1"
+            ports           = config[ "port_map" ].keys( )
+            vlan_id         = 4094
+            mpls_label      = 255
+            label           = (mpls_label, 0, 1, 64)
+
+            in_port             = ports[0]
+            out_port            = ports[1]
+            r_dst_mac[5]        = in_port
+            intf_src_mac[5]     = out_port
+            dst_mac[5]          = out_port
+            dst_ip              = dip % in_port
+            dst_mac_str         = ':'.join( [ '%02X' % x for x in dst_mac ] )
+            r_dst_mac_str       = ':'.join( [ '%02X' % x for x in r_dst_mac ] )
+            intf_src_mac_str    = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+            # We create the L2 group
+            l2gid, msg = add_one_l2_interface_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlan_id=vlan_id,
+                is_tagged=False,
+                send_barrier=True
+                )
+            Groups.put(l2gid)
+            # We create the L3 group
+            l3_msg = add_l3_unicast_group(
+                ctrl=self.controller,
+                port=out_port,
+                vlanid=vlan_id,
+                id=vlan_id,
+                src_mac=intf_src_mac,
+                dst_mac=dst_mac,
+                send_barrier=True
+                )
+            Groups.put( l3_msg.group_id )
+            # Add ECMP group
+            ecmp_msg = add_l3_ecmp_group(
+                ctrl=self.controller,
+                id=vlan_id,
+                l3_ucast_groups=[ l3_msg.group_id ],
+                send_barrier=True
+            )
+            Groups.put( ecmp_msg.group_id )
+            # add filtering flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_TAG
+                )
+            # add assignment flow
+            add_one_vlan_table_flow(
+                ctrl=self.controller,
+                of_port=in_port,
+                vlan_id=vlan_id,
+                flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                )
+            # add termination flow
+            add_termination_flow(
+                ctrl=self.controller,
+                in_port=in_port,
+                eth_type=0x8847,
+                dst_mac=r_dst_mac,
+                vlanid=vlan_id,
+                goto_table=24
+                )
+            # We fill the mpls flow table 1
+            add_mpls_flow(
+                ctrl=self.controller,
+                action_group_id=ecmp_msg.group_id,
+                label=mpls_label,
+                send_barrier=True
+                )
+
+            parsed_mplsv6_pkt = mplsv6_packet(
+                    pktlen=104,
+                    eth_dst=r_dst_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    label=[ label ]
+                    )
+            mplsv6_pkt = str( parsed_mplsv6_pkt )
+            self.dataplane.send(in_port, mplsv6_pkt)
+            print_port_stats(self, in_port)
+            parsed_tcpv6_pkt = simple_tcpv6_packet(
+                    pktlen=100,
+                    eth_dst=dst_mac_str,
+                    eth_src=intf_src_mac_str,
+                    ipv6_dst=dst_ip,
+                    ipv6_src=sip,
+                    ipv6_hlim=63
+                    )
+            tcpv6_pkt = str( parsed_tcpv6_pkt )
+            time.sleep(2)
+            print_port_stats(self, in_port)
+            verify_packet(self, tcpv6_pkt, out_port )
+            verify_no_packet(self, tcpv6_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
diff --git a/ofdpa/utils.py b/ofdpa/utils.py
index 167763b..f4236a2 100644
--- a/ofdpa/utils.py
+++ b/ofdpa/utils.py
@@ -19,7 +19,7 @@
         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" % (
+    print "\nPort %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
         )
 
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index 1d48c60..cd501ac 100755
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -69,9 +69,7 @@
     """
     logging.info("Deleting groups")
     while (not group_queue.empty()):
-        group_id = group_queue.get()
-        print "0x%x" % group_id
-        msg = ofp.message.group_delete(group_id=group_id)
+        msg = ofp.message.group_delete(group_id=group_queue.get())
         ctrl.message_send(msg)
         do_barrier(ctrl)
 
@@ -533,6 +531,49 @@
 
     return pkt
 
+def mplsv6_packet(pktlen=100,
+                      eth_dst='00:01:02:03:04:05',
+                      eth_src='00:06:07:08:09:0a',
+                      dl_vlan_enable=False,
+                      vlan_vid=0,
+                      vlan_pcp=0,
+                      dl_vlan_cfi=0,
+                      ipv6_src='2001:db8:85a3::8a2e:370:7334',
+                      ipv6_dst='2001:db8:85a3::8a2e:370:7335',
+                      ipv6_tc=0,
+                      ipv6_hlim=64,
+                      ipv6_fl=0,
+                      tcp_sport=1234,
+                      tcp_dport=80,
+                      tcp_flags="S",
+                      label=None,
+                      inner_payload=True
+                      ):
+    if MINSIZE > pktlen:
+        pktlen = MINSIZE
+
+    # Note Dot1Q.id is really CFI
+    if (dl_vlan_enable):
+        pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
+            scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)
+    else:
+        pkt = scapy.Ether(dst=eth_dst, src=eth_src)
+
+    #add MPLS header
+    for i in range(len(label)):
+        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.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)/ \
+            scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
+
+    pkt = pkt/("D" * (pktlen - len(pkt)))
+
+    return pkt
+
 def simple_mpls_packet(eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
                       dl_vlan_enable=False,