#include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/types.h>
-#include <linux/tcp.h>
 #include <linux/socket.h>
 #include <linux/pkt_cls.h>
 #include <linux/erspan.h>
        struct bpf_tunnel_key key = {};
        void *data = (void *)(long)skb->data;
        struct iphdr *iph = data;
-       struct tcphdr *tcp = data + sizeof(*iph);
        void *data_end = (void *)(long)skb->data_end;
        int ret;
 
        /* single length check */
-       if (data + sizeof(*iph) + sizeof(*tcp) > data_end) {
+       if (data + sizeof(*iph) > data_end) {
                ERROR(1);
                return TC_ACT_SHOT;
        }
        key.tunnel_ttl = 64;
        if (iph->protocol == IPPROTO_ICMP) {
                key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
-       } else {
-               if (iph->protocol != IPPROTO_TCP || iph->ihl != 5)
-                       return TC_ACT_SHOT;
-
-               if (tcp->dest == bpf_htons(5200))
-                       key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
-               else if (tcp->dest == bpf_htons(5201))
-                       key.remote_ipv4 = 0xac100165; /* 172.16.1.101 */
-               else
-                       return TC_ACT_SHOT;
        }
 
        ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);
        struct bpf_tunnel_key key = {};
        void *data = (void *)(long)skb->data;
        struct iphdr *iph = data;
-       struct tcphdr *tcp = data + sizeof(*iph);
        void *data_end = (void *)(long)skb->data_end;
        int ret;
 
        /* single length check */
-       if (data + sizeof(*iph) + sizeof(*tcp) > data_end) {
+       if (data + sizeof(*iph) > data_end) {
                ERROR(1);
                return TC_ACT_SHOT;
        }
 
        __builtin_memset(&key, 0x0, sizeof(key));
-       key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
        key.tunnel_ttl = 64;
+       if (iph->protocol == IPPROTO_ICMP) {
+               key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
+       }
 
        ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
                                     BPF_F_TUNINFO_IPV6);
        struct bpf_tunnel_key key = {};
        void *data = (void *)(long)skb->data;
        struct ipv6hdr *iph = data;
-       struct tcphdr *tcp = data + sizeof(*iph);
        void *data_end = (void *)(long)skb->data_end;
        int ret;
 
        /* single length check */
-       if (data + sizeof(*iph) + sizeof(*tcp) > data_end) {
+       if (data + sizeof(*iph) > data_end) {
                ERROR(1);
                return TC_ACT_SHOT;
        }
 
-       key.remote_ipv6[0] = bpf_htonl(0x2401db00);
        key.tunnel_ttl = 64;
-
        if (iph->nexthdr == 58 /* NEXTHDR_ICMP */) {
-               key.remote_ipv6[3] = bpf_htonl(1);
-       } else {
-               if (iph->nexthdr != 6 /* NEXTHDR_TCP */) {
-                       ERROR(iph->nexthdr);
-                       return TC_ACT_SHOT;
-               }
-
-               if (tcp->dest == bpf_htons(5200)) {
-                       key.remote_ipv6[3] = bpf_htonl(1);
-               } else if (tcp->dest == bpf_htons(5201)) {
-                       key.remote_ipv6[3] = bpf_htonl(2);
-               } else {
-                       ERROR(tcp->dest);
-                       return TC_ACT_SHOT;
-               }
+               key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
        }
 
        ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
 
 # Root namespace with metadata-mode tunnel + BPF
 # Device names and addresses:
 #      veth1 IP: 172.16.1.200, IPv6: 00::22 (underlay)
-#      tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200 (overlay)
+#      tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay)
 #
 # Namespace at_ns0 with native tunnel
 # Device names and addresses:
 #      veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay)
-#      tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100 (overlay)
+#      tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay)
 #
 #
 # End-to-end ping packet flow
        ip addr add dev $DEV 10.1.1.200/24
 }
 
-add_ipip6tnl_tunnel()
+add_ip6tnl_tunnel()
 {
        ip netns exec at_ns0 ip addr add ::11/96 dev veth0
        ip netns exec at_ns0 ip link set dev veth0 up
                ip link add dev $DEV_NS type $TYPE \
                local ::11 remote ::22
        ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
+       ip netns exec at_ns0 ip addr add dev $DEV_NS 1::11/96
        ip netns exec at_ns0 ip link set dev $DEV_NS up
 
        # root namespace
        ip link add dev $DEV type $TYPE external
        ip addr add dev $DEV 10.1.1.200/24
+       ip addr add dev $DEV 1::22/96
        ip link set dev $DEV up
 }
 
 
        check $TYPE
        config_device
-       add_ipip6tnl_tunnel
+       add_ip6tnl_tunnel
        ip link set dev veth1 mtu 1500
        attach_bpf $DEV ipip6_set_tunnel ipip6_get_tunnel
        # underlay
         echo -e ${GREEN}"PASS: $TYPE"${NC}
 }
 
+test_ip6ip6()
+{
+       TYPE=ip6tnl
+       DEV_NS=ip6ip6tnl00
+       DEV=ip6ip6tnl11
+       ret=0
+
+       check $TYPE
+       config_device
+       add_ip6tnl_tunnel
+       ip link set dev veth1 mtu 1500
+       attach_bpf $DEV ip6ip6_set_tunnel ip6ip6_get_tunnel
+       # underlay
+       ping6 $PING_ARG ::11
+       # ip6 over ip6
+       ping6 $PING_ARG 1::11
+       check_err $?
+       ip netns exec at_ns0 ping6 $PING_ARG 1::22
+       check_err $?
+       cleanup
+
+       if [ $ret -ne 0 ]; then
+                echo -e ${RED}"FAIL: ip6$TYPE"${NC}
+                return 1
+        fi
+        echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
+}
+
 setup_xfrm_tunnel()
 {
        auth=0x$(printf '1%.0s' {1..40})
        ip link del veth1 2> /dev/null
        ip link del ipip11 2> /dev/null
        ip link del ipip6tnl11 2> /dev/null
+       ip link del ip6ip6tnl11 2> /dev/null
        ip link del gretap11 2> /dev/null
        ip link del ip6gre11 2> /dev/null
        ip link del ip6gretap11 2> /dev/null
        test_ipip6
        errors=$(( $errors + $? ))
 
+       echo "Testing IP6IP6 tunnel..."
+       test_ip6ip6
+       errors=$(( $errors + $? ))
+
        echo "Testing IPSec tunnel..."
        test_xfrm_tunnel
        errors=$(( $errors + $? ))