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/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