testutils: add simple_{tcp,udp,icmp}v6_packet()

These are simplified and IPv6-ified versions of the existing functions.

Also added IPv6 packets to the OF 1.3 ethertype tests.
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index 7e1b2c8..33a4cc1 100644
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -122,6 +122,53 @@
 
     return pkt
 
+def simple_tcpv6_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,
+                        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):
+    """
+    Return a simple IPv6/TCP packet
+
+    Supports a few parameters:
+    @param len Length of packet in bytes w/o CRC
+    @param eth_dst Destination MAC
+    @param eth_src Source MAC
+    @param dl_vlan_enable True if the packet is with vlan, False otherwise
+    @param vlan_vid VLAN ID
+    @param vlan_pcp VLAN priority
+    @param ipv6_src IPv6 source
+    @param ipv6_dst IPv6 destination
+    @param ipv6_tc IPv6 traffic class
+    @param ipv6_ttl IPv6 hop limit
+    @param ipv6_fl IPv6 flow label
+    @param tcp_dport TCP destination port
+    @param tcp_sport TCP source port
+
+    Generates a simple TCP request. Users shouldn't assume anything about this
+    packet other than that it is a valid ethernet/IPv6/TCP frame.
+    """
+
+    if MINSIZE > pktlen:
+        pktlen = MINSIZE
+
+    pkt = scapy.Ether(dst=eth_dst, src=eth_src)
+    if dl_vlan_enable or vlan_vid or vlan_pcp:
+        pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
+    pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
+    pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
+    pkt /= ("D" * (pktlen - len(pkt)))
+
+    return pkt
+
 def simple_udp_packet(pktlen=100,
                       eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
@@ -182,6 +229,53 @@
 
     return pkt
 
+def simple_udpv6_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,
+                        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,
+                        udp_sport=1234,
+                        udp_dport=80):
+    """
+    Return a simple IPv6/UDP packet
+
+    Supports a few parameters:
+    @param len Length of packet in bytes w/o CRC
+    @param eth_dst Destination MAC
+    @param eth_src Source MAC
+    @param dl_vlan_enable True if the packet is with vlan, False otherwise
+    @param vlan_vid VLAN ID
+    @param vlan_pcp VLAN priority
+    @param ipv6_src IPv6 source
+    @param ipv6_dst IPv6 destination
+    @param ipv6_tc IPv6 traffic class
+    @param ipv6_ttl IPv6 hop limit
+    @param ipv6_fl IPv6 flow label
+    @param udp_dport UDP destination port
+    @param udp_sport UDP source port
+
+    Generates a simple UDP request. Users shouldn't assume anything about this
+    packet other than that it is a valid ethernet/IPv6/UDP frame.
+    """
+
+    if MINSIZE > pktlen:
+        pktlen = MINSIZE
+
+    pkt = scapy.Ether(dst=eth_dst, src=eth_src)
+    if dl_vlan_enable or vlan_vid or vlan_pcp:
+        pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
+    pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
+    pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
+    pkt /= ("D" * (pktlen - len(pkt)))
+
+    return pkt
+
 def simple_icmp_packet(pktlen=60, 
                       eth_dst='00:01:02:03:04:05',
                       eth_src='00:06:07:08:09:0a',
@@ -234,6 +328,53 @@
 
     return pkt
 
+def simple_icmpv6_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,
+                         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,
+                         icmp_type=8,
+                         icmp_code=0):
+    """
+    Return a simple ICMPv6 packet
+
+    Supports a few parameters:
+    @param len Length of packet in bytes w/o CRC
+    @param eth_dst Destination MAC
+    @param eth_src Source MAC
+    @param dl_vlan_enable True if the packet is with vlan, False otherwise
+    @param vlan_vid VLAN ID
+    @param vlan_pcp VLAN priority
+    @param ipv6_src IPv6 source
+    @param ipv6_dst IPv6 destination
+    @param ipv6_tc IPv6 traffic class
+    @param ipv6_ttl IPv6 hop limit
+    @param ipv6_fl IPv6 flow label
+    @param icmp_type ICMP type
+    @param icmp_code ICMP code
+
+    Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
+    about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
+    """
+
+    if MINSIZE > pktlen:
+        pktlen = MINSIZE
+
+    pkt = scapy.Ether(dst=eth_dst, src=eth_src)
+    if dl_vlan_enable or vlan_vid or vlan_pcp:
+        pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
+    pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
+    pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
+    pkt /= ("D" * (pktlen - len(pkt)))
+
+    return pkt
+
 def simple_arp_packet(pktlen=60, 
                       eth_dst='ff:ff:ff:ff:ff:ff',
                       eth_src='00:06:07:08:09:0a',
diff --git a/tests-1.3/match.py b/tests-1.3/match.py
index 8a46118..c81fc38 100644
--- a/tests-1.3/match.py
+++ b/tests-1.3/match.py
@@ -301,7 +301,30 @@
         nonmatching = {
             "arp": simple_arp_packet(),
             "llc": llc_pkt,
-            # TODO ipv6
+            "ipv6/tcp": simple_tcpv6_packet(),
+        }
+
+        self.verify_match(match, matching, nonmatching)
+
+class EthTypeIPv6(MatchTest):
+    """
+    Match on ethertype (IPv6)
+    """
+    def runTest(self):
+        match = ofp.match([
+            ofp.oxm.eth_type(0x86dd)
+        ])
+
+        matching = {
+            "ipv6/tcp": simple_tcpv6_packet(),
+            "ipv6/udp": simple_udpv6_packet(),
+            "ipv6/icmp": simple_icmpv6_packet(),
+            "vlan tagged": simple_tcpv6_packet(vlan_vid=2, vlan_pcp=3),
+        }
+
+        nonmatching = {
+            "ipv4/tcp": simple_tcp_packet(),
+            "arp": simple_arp_packet(),
         }
 
         self.verify_match(match, matching, nonmatching)
@@ -322,6 +345,7 @@
 
         nonmatching = {
             "ipv4/tcp": simple_tcp_packet(),
+            "ipv6/tcp": simple_tcpv6_packet(),
         }
 
         self.verify_match(match, matching, nonmatching)
@@ -352,6 +376,7 @@
 
         nonmatching = {
             "ipv4/tcp": simple_tcp_packet(),
+            "ipv6/tcp": simple_tcpv6_packet(),
             "llc/snap": snap_pkt,
         }