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_helpers.h"
  16
  17struct bpf_map_def SEC("maps") rxcnt = {
  18        .type = BPF_MAP_TYPE_PERCPU_ARRAY,
  19        .key_size = sizeof(u32),
  20        .value_size = sizeof(long),
  21        .max_entries = 256,
  22};
  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        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
  77                struct vlan_hdr *vhdr;
  78
  79                vhdr = data + nh_off;
  80                nh_off += sizeof(struct vlan_hdr);
  81                if (data + nh_off > data_end)
  82                        return rc;
  83                h_proto = vhdr->h_vlan_encapsulated_proto;
  84        }
  85        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
  86                struct vlan_hdr *vhdr;
  87
  88                vhdr = data + nh_off;
  89                nh_off += sizeof(struct vlan_hdr);
  90                if (data + nh_off > data_end)
  91                        return rc;
  92                h_proto = vhdr->h_vlan_encapsulated_proto;
  93        }
  94
  95        if (h_proto == htons(ETH_P_IP))
  96                ipproto = parse_ipv4(data, nh_off, data_end);
  97        else if (h_proto == htons(ETH_P_IPV6))
  98                ipproto = parse_ipv6(data, nh_off, data_end);
  99        else
 100                ipproto = 0;
 101
 102        value = bpf_map_lookup_elem(&rxcnt, &ipproto);
 103        if (value)
 104                *value += 1;
 105
 106        if (ipproto == IPPROTO_UDP) {
 107                swap_src_dst_mac(data);
 108                rc = XDP_TX;
 109        }
 110
 111        return rc;
 112}
 113
 114char _license[] SEC("license") = "GPL";
 115