root/samples/bpf/test_lwt_bpf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. SEC
  2. SEC
  3. SEC
  4. SEC
  5. rewrite
  6. SEC
  7. __do_push_ll_and_redirect
  8. SEC
  9. SEC
  10. __fill_garbage
  11. SEC
  12. SEC
  13. SEC

   1 /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
   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  * This program is distributed in the hope that it will be useful, but
   8  * WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10  * General Public License for more details.
  11  */
  12 
  13 #include <stdint.h>
  14 #include <stddef.h>
  15 #include <linux/bpf.h>
  16 #include <linux/ip.h>
  17 #include <linux/in.h>
  18 #include <linux/in6.h>
  19 #include <linux/tcp.h>
  20 #include <linux/udp.h>
  21 #include <linux/icmpv6.h>
  22 #include <linux/if_ether.h>
  23 #include "bpf_helpers.h"
  24 #include <string.h>
  25 
  26 # define printk(fmt, ...)                                               \
  27                 ({                                                      \
  28                         char ____fmt[] = fmt;                           \
  29                         bpf_trace_printk(____fmt, sizeof(____fmt),      \
  30                                      ##__VA_ARGS__);                    \
  31                 })
  32 
  33 #define CB_MAGIC 1234
  34 
  35 /* Test: Pass all packets through */
  36 SEC("nop")
  37 int do_nop(struct __sk_buff *skb)
  38 {
  39         return BPF_OK;
  40 }
  41 
  42 /* Test: Verify context information can be accessed */
  43 SEC("test_ctx")
  44 int do_test_ctx(struct __sk_buff *skb)
  45 {
  46         skb->cb[0] = CB_MAGIC;
  47         printk("len %d hash %d protocol %d\n", skb->len, skb->hash,
  48                skb->protocol);
  49         printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0],
  50                skb->ingress_ifindex, skb->ifindex);
  51 
  52         return BPF_OK;
  53 }
  54 
  55 /* Test: Ensure skb->cb[] buffer is cleared */
  56 SEC("test_cb")
  57 int do_test_cb(struct __sk_buff *skb)
  58 {
  59         printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1],
  60                skb->cb[2]);
  61         printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]);
  62 
  63         return BPF_OK;
  64 }
  65 
  66 /* Test: Verify skb data can be read */
  67 SEC("test_data")
  68 int do_test_data(struct __sk_buff *skb)
  69 {
  70         void *data = (void *)(long)skb->data;
  71         void *data_end = (void *)(long)skb->data_end;
  72         struct iphdr *iph = data;
  73 
  74         if (data + sizeof(*iph) > data_end) {
  75                 printk("packet truncated\n");
  76                 return BPF_DROP;
  77         }
  78 
  79         printk("src: %x dst: %x\n", iph->saddr, iph->daddr);
  80 
  81         return BPF_OK;
  82 }
  83 
  84 #define IP_CSUM_OFF offsetof(struct iphdr, check)
  85 #define IP_DST_OFF offsetof(struct iphdr, daddr)
  86 #define IP_SRC_OFF offsetof(struct iphdr, saddr)
  87 #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
  88 #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
  89 #define UDP_CSUM_OFF offsetof(struct udphdr, check)
  90 #define IS_PSEUDO 0x10
  91 
  92 static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
  93                           uint32_t new_ip, int rw_daddr)
  94 {
  95         int ret, off = 0, flags = IS_PSEUDO;
  96         uint8_t proto;
  97 
  98         ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
  99         if (ret < 0) {
 100                 printk("bpf_l4_csum_replace failed: %d\n", ret);
 101                 return BPF_DROP;
 102         }
 103 
 104         switch (proto) {
 105         case IPPROTO_TCP:
 106                 off = TCP_CSUM_OFF;
 107                 break;
 108 
 109         case IPPROTO_UDP:
 110                 off = UDP_CSUM_OFF;
 111                 flags |= BPF_F_MARK_MANGLED_0;
 112                 break;
 113 
 114         case IPPROTO_ICMPV6:
 115                 off = offsetof(struct icmp6hdr, icmp6_cksum);
 116                 break;
 117         }
 118 
 119         if (off) {
 120                 ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
 121                                           flags | sizeof(new_ip));
 122                 if (ret < 0) {
 123                         printk("bpf_l4_csum_replace failed: %d\n");
 124                         return BPF_DROP;
 125                 }
 126         }
 127 
 128         ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
 129         if (ret < 0) {
 130                 printk("bpf_l3_csum_replace failed: %d\n", ret);
 131                 return BPF_DROP;
 132         }
 133 
 134         if (rw_daddr)
 135                 ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
 136         else
 137                 ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
 138 
 139         if (ret < 0) {
 140                 printk("bpf_skb_store_bytes() failed: %d\n", ret);
 141                 return BPF_DROP;
 142         }
 143 
 144         return BPF_OK;
 145 }
 146 
 147 /* Test: Verify skb data can be modified */
 148 SEC("test_rewrite")
 149 int do_test_rewrite(struct __sk_buff *skb)
 150 {
 151         uint32_t old_ip, new_ip = 0x3fea8c0;
 152         int ret;
 153 
 154         ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
 155         if (ret < 0) {
 156                 printk("bpf_skb_load_bytes failed: %d\n", ret);
 157                 return BPF_DROP;
 158         }
 159 
 160         if (old_ip == 0x2fea8c0) {
 161                 printk("out: rewriting from %x to %x\n", old_ip, new_ip);
 162                 return rewrite(skb, old_ip, new_ip, 1);
 163         }
 164 
 165         return BPF_OK;
 166 }
 167 
 168 static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
 169 {
 170         uint64_t smac = SRC_MAC, dmac = DST_MAC;
 171         int ret, ifindex = DST_IFINDEX;
 172         struct ethhdr ehdr;
 173 
 174         ret = bpf_skb_change_head(skb, 14, 0);
 175         if (ret < 0) {
 176                 printk("skb_change_head() failed: %d\n", ret);
 177         }
 178 
 179         ehdr.h_proto = __constant_htons(ETH_P_IP);
 180         memcpy(&ehdr.h_source, &smac, 6);
 181         memcpy(&ehdr.h_dest, &dmac, 6);
 182 
 183         ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
 184         if (ret < 0) {
 185                 printk("skb_store_bytes() failed: %d\n", ret);
 186                 return BPF_DROP;
 187         }
 188 
 189         return bpf_redirect(ifindex, 0);
 190 }
 191 
 192 SEC("push_ll_and_redirect_silent")
 193 int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
 194 {
 195         return __do_push_ll_and_redirect(skb);
 196 }
 197 
 198 SEC("push_ll_and_redirect")
 199 int do_push_ll_and_redirect(struct __sk_buff *skb)
 200 {
 201         int ret, ifindex = DST_IFINDEX;
 202 
 203         ret = __do_push_ll_and_redirect(skb);
 204         if (ret >= 0)
 205                 printk("redirected to %d\n", ifindex);
 206 
 207         return ret;
 208 }
 209 
 210 static inline void __fill_garbage(struct __sk_buff *skb)
 211 {
 212         uint64_t f = 0xFFFFFFFFFFFFFFFF;
 213 
 214         bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
 215         bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
 216         bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
 217         bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
 218         bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
 219         bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
 220         bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
 221         bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
 222         bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
 223         bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
 224         bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
 225         bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
 226 }
 227 
 228 SEC("fill_garbage")
 229 int do_fill_garbage(struct __sk_buff *skb)
 230 {
 231         __fill_garbage(skb);
 232         printk("Set initial 96 bytes of header to FF\n");
 233         return BPF_OK;
 234 }
 235 
 236 SEC("fill_garbage_and_redirect")
 237 int do_fill_garbage_and_redirect(struct __sk_buff *skb)
 238 {
 239         int ifindex = DST_IFINDEX;
 240         __fill_garbage(skb);
 241         printk("redirected to %d\n", ifindex);
 242         return bpf_redirect(ifindex, 0);
 243 }
 244 
 245 /* Drop all packets */
 246 SEC("drop_all")
 247 int do_drop_all(struct __sk_buff *skb)
 248 {
 249         printk("dropping with: %d\n", BPF_DROP);
 250         return BPF_DROP;
 251 }
 252 
 253 char _license[] SEC("license") = "GPL";

/* [<][>][^][v][top][bottom][index][help] */