linux/samples/bpf/xdp2_kern.c
<<
>>
Prefs
   1/* Copyright (c) 2016 PLUMgrid
   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 <uapi/linux/bpf.h>
   9#include <linux/in.h>
  10#include <linux/if_ether.h>
  11#include <linux/if_packet.h>
  12#include <linux/if_vlan.h>
  13#include <linux/ip.h>
  14#include <linux/ipv6.h>
  15#include <bpf/bpf_helpers.h>
  16
  17struct {
  18        __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  19        __type(key, u32);
  20        __type(value, long);
  21        __uint(max_entries, 256);
  22} rxcnt SEC(".maps");
  23
  24static void swap_src_dst_mac(void *data)
  25{
  26        unsigned short *p = data;
  27        unsigned short dst[3];
  28
  29        dst[0] = p[0];
  30        dst[1] = p[1];
  31        dst[2] = p[2];
  32        p[0] = p[3];
  33        p[1] = p[4];
  34        p[2] = p[5];
  35        p[3] = dst[0];
  36        p[4] = dst[1];
  37        p[5] = dst[2];
  38}
  39
  40static int parse_ipv4(void *data, u64 nh_off, void *data_end)
  41{
  42        struct iphdr *iph = data + nh_off;
  43
  44        if (iph + 1 > data_end)
  45                return 0;
  46        return iph->protocol;
  47}
  48
  49static int parse_ipv6(void *data, u64 nh_off, void *data_end)
  50{
  51        struct ipv6hdr *ip6h = data + nh_off;
  52
  53        if (ip6h + 1 > data_end)
  54                return 0;
  55        return ip6h->nexthdr;
  56}
  57
  58SEC("xdp1")
  59int xdp_prog1(struct xdp_md *ctx)
  60{
  61        void *data_end = (void *)(long)ctx->data_end;
  62        void *data = (void *)(long)ctx->data;
  63        struct ethhdr *eth = data;
  64        int rc = XDP_DROP;
  65        long *value;
  66        u16 h_proto;
  67        u64 nh_off;
  68        u32 ipproto;
  69
  70        nh_off = sizeof(*eth);
  71        if (data + nh_off > data_end)
  72                return rc;
  73
  74        h_proto = eth->h_proto;
  75
  76        /* Handle VLAN tagged packet */
  77        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
  78                struct vlan_hdr *vhdr;
  79
  80                vhdr = data + nh_off;
  81                nh_off += sizeof(struct vlan_hdr);
  82                if (data + nh_off > data_end)
  83                        return rc;
  84                h_proto = vhdr->h_vlan_encapsulated_proto;
  85        }
  86        /* Handle double VLAN tagged packet */
  87        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
  88                struct vlan_hdr *vhdr;
  89
  90                vhdr = data + nh_off;
  91                nh_off += sizeof(struct vlan_hdr);
  92                if (data + nh_off > data_end)
  93                        return rc;
  94                h_proto = vhdr->h_vlan_encapsulated_proto;
  95        }
  96
  97        if (h_proto == htons(ETH_P_IP))
  98                ipproto = parse_ipv4(data, nh_off, data_end);
  99        else if (h_proto == htons(ETH_P_IPV6))
 100                ipproto = parse_ipv6(data, nh_off, data_end);
 101        else
 102                ipproto = 0;
 103
 104        value = bpf_map_lookup_elem(&rxcnt, &ipproto);
 105        if (value)
 106                *value += 1;
 107
 108        if (ipproto == IPPROTO_UDP) {
 109                swap_src_dst_mac(data);
 110                rc = XDP_TX;
 111        }
 112
 113        return rc;
 114}
 115
 116char _license[] SEC("license") = "GPL";
 117