samples/bpf: add comprehensive ipip, ipip6, ip6ip6 test
[cascardo/linux.git] / samples / bpf / tcbpf2_kern.c
index c1917d9..3303bb8 100644 (file)
@@ -9,12 +9,15 @@
 #include <uapi/linux/if_ether.h>
 #include <uapi/linux/if_packet.h>
 #include <uapi/linux/ip.h>
+#include <uapi/linux/ipv6.h>
 #include <uapi/linux/in.h>
 #include <uapi/linux/tcp.h>
 #include <uapi/linux/filter.h>
 #include <uapi/linux/pkt_cls.h>
+#include <net/ipv6.h>
 #include "bpf_helpers.h"
 
+#define _htonl __builtin_bswap32
 #define ERROR(ret) do {\
                char fmt[] = "ERROR line:%d ret:%d\n";\
                bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \
@@ -246,4 +249,133 @@ int _ipip_get_tunnel(struct __sk_buff *skb)
        return TC_ACT_OK;
 }
 
+SEC("ipip6_set_tunnel")
+int _ipip6_set_tunnel(struct __sk_buff *skb)
+{
+       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) {
+               ERROR(1);
+               return TC_ACT_SHOT;
+       }
+
+       key.remote_ipv6[0] = _htonl(0x2401db00);
+       key.tunnel_ttl = 64;
+
+       if (iph->protocol == IPPROTO_ICMP) {
+               key.remote_ipv6[3] = _htonl(1);
+       } else {
+               if (iph->protocol != IPPROTO_TCP || iph->ihl != 5) {
+                       ERROR(iph->protocol);
+                       return TC_ACT_SHOT;
+               }
+
+               if (tcp->dest == htons(5200)) {
+                       key.remote_ipv6[3] = _htonl(1);
+               } else if (tcp->dest == htons(5201)) {
+                       key.remote_ipv6[3] = _htonl(2);
+               } else {
+                       ERROR(tcp->dest);
+                       return TC_ACT_SHOT;
+               }
+       }
+
+       ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
+       if (ret < 0) {
+               ERROR(ret);
+               return TC_ACT_SHOT;
+       }
+
+       return TC_ACT_OK;
+}
+
+SEC("ipip6_get_tunnel")
+int _ipip6_get_tunnel(struct __sk_buff *skb)
+{
+       int ret;
+       struct bpf_tunnel_key key;
+       char fmt[] = "remote ip6 %x::%x\n";
+
+       ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
+       if (ret < 0) {
+               ERROR(ret);
+               return TC_ACT_SHOT;
+       }
+
+       bpf_trace_printk(fmt, sizeof(fmt), _htonl(key.remote_ipv6[0]),
+                        _htonl(key.remote_ipv6[3]));
+       return TC_ACT_OK;
+}
+
+SEC("ip6ip6_set_tunnel")
+int _ip6ip6_set_tunnel(struct __sk_buff *skb)
+{
+       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) {
+               ERROR(1);
+               return TC_ACT_SHOT;
+       }
+
+       key.remote_ipv6[0] = _htonl(0x2401db00);
+       key.tunnel_ttl = 64;
+
+       if (iph->nexthdr == NEXTHDR_ICMP) {
+               key.remote_ipv6[3] = _htonl(1);
+       } else {
+               if (iph->nexthdr != NEXTHDR_TCP) {
+                       ERROR(iph->nexthdr);
+                       return TC_ACT_SHOT;
+               }
+
+               if (tcp->dest == htons(5200)) {
+                       key.remote_ipv6[3] = _htonl(1);
+               } else if (tcp->dest == htons(5201)) {
+                       key.remote_ipv6[3] = _htonl(2);
+               } else {
+                       ERROR(tcp->dest);
+                       return TC_ACT_SHOT;
+               }
+       }
+
+       ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
+       if (ret < 0) {
+               ERROR(ret);
+               return TC_ACT_SHOT;
+       }
+
+       return TC_ACT_OK;
+}
+
+SEC("ip6ip6_get_tunnel")
+int _ip6ip6_get_tunnel(struct __sk_buff *skb)
+{
+       int ret;
+       struct bpf_tunnel_key key;
+       char fmt[] = "remote ip6 %x::%x\n";
+
+       ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
+       if (ret < 0) {
+               ERROR(ret);
+               return TC_ACT_SHOT;
+       }
+
+       bpf_trace_printk(fmt, sizeof(fmt), _htonl(key.remote_ipv6[0]),
+                        _htonl(key.remote_ipv6[3]));
+       return TC_ACT_OK;
+}
+
+
 char _license[] SEC("license") = "GPL";