linux/samples/bpf/parse_varlen.c
<<
>>
Prefs
   1/* Copyright (c) 2016 Facebook
   2 *
   3 * This program is free software; you can redistribute it and/or
   4 * modify it under the terms of version 2 of the GNU General Public
   5 * License as published by the Free Software Foundation.
   6 */
   7#define KBUILD_MODNAME "foo"
   8#include <linux/if_ether.h>
   9#include <linux/ip.h>
  10#include <linux/ipv6.h>
  11#include <linux/in.h>
  12#include <linux/tcp.h>
  13#include <linux/udp.h>
  14#include <uapi/linux/bpf.h>
  15#include <net/ip.h>
  16#include "bpf_helpers.h"
  17
  18#define DEFAULT_PKTGEN_UDP_PORT 9
  19#define DEBUG 0
  20
  21static int tcp(void *data, uint64_t tp_off, void *data_end)
  22{
  23        struct tcphdr *tcp = data + tp_off;
  24
  25        if (tcp + 1 > data_end)
  26                return 0;
  27        if (tcp->dest == htons(80) || tcp->source == htons(80))
  28                return TC_ACT_SHOT;
  29        return 0;
  30}
  31
  32static int udp(void *data, uint64_t tp_off, void *data_end)
  33{
  34        struct udphdr *udp = data + tp_off;
  35
  36        if (udp + 1 > data_end)
  37                return 0;
  38        if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT) ||
  39            udp->source == htons(DEFAULT_PKTGEN_UDP_PORT)) {
  40                if (DEBUG) {
  41                        char fmt[] = "udp port 9 indeed\n";
  42
  43                        bpf_trace_printk(fmt, sizeof(fmt));
  44                }
  45                return TC_ACT_SHOT;
  46        }
  47        return 0;
  48}
  49
  50static int parse_ipv4(void *data, uint64_t nh_off, void *data_end)
  51{
  52        struct iphdr *iph;
  53        uint64_t ihl_len;
  54
  55        iph = data + nh_off;
  56        if (iph + 1 > data_end)
  57                return 0;
  58
  59        if (ip_is_fragment(iph))
  60                return 0;
  61        ihl_len = iph->ihl * 4;
  62
  63        if (iph->protocol == IPPROTO_IPIP) {
  64                iph = data + nh_off + ihl_len;
  65                if (iph + 1 > data_end)
  66                        return 0;
  67                ihl_len += iph->ihl * 4;
  68        }
  69
  70        if (iph->protocol == IPPROTO_TCP)
  71                return tcp(data, nh_off + ihl_len, data_end);
  72        else if (iph->protocol == IPPROTO_UDP)
  73                return udp(data, nh_off + ihl_len, data_end);
  74        return 0;
  75}
  76
  77static int parse_ipv6(void *data, uint64_t nh_off, void *data_end)
  78{
  79        struct ipv6hdr *ip6h;
  80        struct iphdr *iph;
  81        uint64_t ihl_len = sizeof(struct ipv6hdr);
  82        uint64_t nexthdr;
  83
  84        ip6h = data + nh_off;
  85        if (ip6h + 1 > data_end)
  86                return 0;
  87
  88        nexthdr = ip6h->nexthdr;
  89
  90        if (nexthdr == IPPROTO_IPIP) {
  91                iph = data + nh_off + ihl_len;
  92                if (iph + 1 > data_end)
  93                        return 0;
  94                ihl_len += iph->ihl * 4;
  95                nexthdr = iph->protocol;
  96        } else if (nexthdr == IPPROTO_IPV6) {
  97                ip6h = data + nh_off + ihl_len;
  98                if (ip6h + 1 > data_end)
  99                        return 0;
 100                ihl_len += sizeof(struct ipv6hdr);
 101                nexthdr = ip6h->nexthdr;
 102        }
 103
 104        if (nexthdr == IPPROTO_TCP)
 105                return tcp(data, nh_off + ihl_len, data_end);
 106        else if (nexthdr == IPPROTO_UDP)
 107                return udp(data, nh_off + ihl_len, data_end);
 108        return 0;
 109}
 110
 111struct vlan_hdr {
 112        uint16_t h_vlan_TCI;
 113        uint16_t h_vlan_encapsulated_proto;
 114};
 115
 116SEC("varlen")
 117int handle_ingress(struct __sk_buff *skb)
 118{
 119        void *data = (void *)(long)skb->data;
 120        struct ethhdr *eth = data;
 121        void *data_end = (void *)(long)skb->data_end;
 122        uint64_t h_proto, nh_off;
 123
 124        nh_off = sizeof(*eth);
 125        if (data + nh_off > data_end)
 126                return 0;
 127
 128        h_proto = eth->h_proto;
 129
 130        if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
 131                struct vlan_hdr *vhdr;
 132
 133                vhdr = data + nh_off;
 134                nh_off += sizeof(struct vlan_hdr);
 135                if (data + nh_off > data_end)
 136                        return 0;
 137                h_proto = vhdr->h_vlan_encapsulated_proto;
 138        }
 139        if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
 140                struct vlan_hdr *vhdr;
 141
 142                vhdr = data + nh_off;
 143                nh_off += sizeof(struct vlan_hdr);
 144                if (data + nh_off > data_end)
 145                        return 0;
 146                h_proto = vhdr->h_vlan_encapsulated_proto;
 147        }
 148        if (h_proto == htons(ETH_P_IP))
 149                return parse_ipv4(data, nh_off, data_end);
 150        else if (h_proto == htons(ETH_P_IPV6))
 151                return parse_ipv6(data, nh_off, data_end);
 152        return 0;
 153}
 154char _license[] SEC("license") = "GPL";
 155