linux/samples/sockmap/sockmap_kern.c
<<
>>
Prefs
   1/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
   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#include <uapi/linux/bpf.h>
  13#include <uapi/linux/if_ether.h>
  14#include <uapi/linux/if_packet.h>
  15#include <uapi/linux/ip.h>
  16#include "../../tools/testing/selftests/bpf/bpf_helpers.h"
  17#include "../../tools/testing/selftests/bpf/bpf_endian.h"
  18
  19/* Sockmap sample program connects a client and a backend together
  20 * using cgroups.
  21 *
  22 *    client:X <---> frontend:80 client:X <---> backend:80
  23 *
  24 * For simplicity we hard code values here and bind 1:1. The hard
  25 * coded values are part of the setup in sockmap.sh script that
  26 * is associated with this BPF program.
  27 *
  28 * The bpf_printk is verbose and prints information as connections
  29 * are established and verdicts are decided.
  30 */
  31
  32#define bpf_printk(fmt, ...)                                    \
  33({                                                              \
  34               char ____fmt[] = fmt;                            \
  35               bpf_trace_printk(____fmt, sizeof(____fmt),       \
  36                                ##__VA_ARGS__);                 \
  37})
  38
  39struct bpf_map_def SEC("maps") sock_map = {
  40        .type = BPF_MAP_TYPE_SOCKMAP,
  41        .key_size = sizeof(int),
  42        .value_size = sizeof(int),
  43        .max_entries = 20,
  44};
  45
  46struct bpf_map_def SEC("maps") sock_map_txmsg = {
  47        .type = BPF_MAP_TYPE_SOCKMAP,
  48        .key_size = sizeof(int),
  49        .value_size = sizeof(int),
  50        .max_entries = 20,
  51};
  52
  53struct bpf_map_def SEC("maps") sock_map_redir = {
  54        .type = BPF_MAP_TYPE_SOCKMAP,
  55        .key_size = sizeof(int),
  56        .value_size = sizeof(int),
  57        .max_entries = 20,
  58};
  59
  60struct bpf_map_def SEC("maps") sock_apply_bytes = {
  61        .type = BPF_MAP_TYPE_ARRAY,
  62        .key_size = sizeof(int),
  63        .value_size = sizeof(int),
  64        .max_entries = 1
  65};
  66
  67struct bpf_map_def SEC("maps") sock_cork_bytes = {
  68        .type = BPF_MAP_TYPE_ARRAY,
  69        .key_size = sizeof(int),
  70        .value_size = sizeof(int),
  71        .max_entries = 1
  72};
  73
  74struct bpf_map_def SEC("maps") sock_pull_bytes = {
  75        .type = BPF_MAP_TYPE_ARRAY,
  76        .key_size = sizeof(int),
  77        .value_size = sizeof(int),
  78        .max_entries = 2
  79};
  80
  81struct bpf_map_def SEC("maps") sock_redir_flags = {
  82        .type = BPF_MAP_TYPE_ARRAY,
  83        .key_size = sizeof(int),
  84        .value_size = sizeof(int),
  85        .max_entries = 1
  86};
  87
  88struct bpf_map_def SEC("maps") sock_skb_opts = {
  89        .type = BPF_MAP_TYPE_ARRAY,
  90        .key_size = sizeof(int),
  91        .value_size = sizeof(int),
  92        .max_entries = 1
  93};
  94
  95SEC("sk_skb1")
  96int bpf_prog1(struct __sk_buff *skb)
  97{
  98        return skb->len;
  99}
 100
 101SEC("sk_skb2")
 102int bpf_prog2(struct __sk_buff *skb)
 103{
 104        __u32 lport = skb->local_port;
 105        __u32 rport = skb->remote_port;
 106        int len, *f, ret, zero = 0;
 107        __u64 flags = 0;
 108
 109        if (lport == 10000)
 110                ret = 10;
 111        else
 112                ret = 1;
 113
 114        len = (__u32)skb->data_end - (__u32)skb->data;
 115        f = bpf_map_lookup_elem(&sock_skb_opts, &zero);
 116        if (f && *f) {
 117                ret = 3;
 118                flags = *f;
 119        }
 120
 121        bpf_printk("sk_skb2: redirect(%iB) flags=%i\n",
 122                   len, flags);
 123        return bpf_sk_redirect_map(skb, &sock_map, ret, flags);
 124}
 125
 126SEC("sockops")
 127int bpf_sockmap(struct bpf_sock_ops *skops)
 128{
 129        __u32 lport, rport;
 130        int op, err = 0, index, key, ret;
 131
 132
 133        op = (int) skops->op;
 134
 135        switch (op) {
 136        case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
 137                lport = skops->local_port;
 138                rport = skops->remote_port;
 139
 140                if (lport == 10000) {
 141                        ret = 1;
 142                        err = bpf_sock_map_update(skops, &sock_map, &ret,
 143                                                  BPF_NOEXIST);
 144                        bpf_printk("passive(%i -> %i) map ctx update err: %d\n",
 145                                   lport, bpf_ntohl(rport), err);
 146                }
 147                break;
 148        case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
 149                lport = skops->local_port;
 150                rport = skops->remote_port;
 151
 152                if (bpf_ntohl(rport) == 10001) {
 153                        ret = 10;
 154                        err = bpf_sock_map_update(skops, &sock_map, &ret,
 155                                                  BPF_NOEXIST);
 156                        bpf_printk("active(%i -> %i) map ctx update err: %d\n",
 157                                   lport, bpf_ntohl(rport), err);
 158                }
 159                break;
 160        default:
 161                break;
 162        }
 163
 164        return 0;
 165}
 166
 167SEC("sk_msg1")
 168int bpf_prog4(struct sk_msg_md *msg)
 169{
 170        int *bytes, zero = 0, one = 1;
 171        int *start, *end;
 172
 173        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
 174        if (bytes)
 175                bpf_msg_apply_bytes(msg, *bytes);
 176        bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
 177        if (bytes)
 178                bpf_msg_cork_bytes(msg, *bytes);
 179        start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
 180        end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
 181        if (start && end)
 182                bpf_msg_pull_data(msg, *start, *end, 0);
 183        return SK_PASS;
 184}
 185
 186SEC("sk_msg2")
 187int bpf_prog5(struct sk_msg_md *msg)
 188{
 189        int err1 = -1, err2 = -1, zero = 0, one = 1;
 190        int *bytes, *start, *end, len1, len2;
 191
 192        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
 193        if (bytes)
 194                err1 = bpf_msg_apply_bytes(msg, *bytes);
 195        bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
 196        if (bytes)
 197                err2 = bpf_msg_cork_bytes(msg, *bytes);
 198        len1 = (__u64)msg->data_end - (__u64)msg->data;
 199        start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
 200        end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
 201        if (start && end) {
 202                int err;
 203
 204                bpf_printk("sk_msg2: pull(%i:%i)\n",
 205                           start ? *start : 0, end ? *end : 0);
 206                err = bpf_msg_pull_data(msg, *start, *end, 0);
 207                if (err)
 208                        bpf_printk("sk_msg2: pull_data err %i\n",
 209                                   err);
 210                len2 = (__u64)msg->data_end - (__u64)msg->data;
 211                bpf_printk("sk_msg2: length update %i->%i\n",
 212                           len1, len2);
 213        }
 214        bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n",
 215                   len1, err1, err2);
 216        return SK_PASS;
 217}
 218
 219SEC("sk_msg3")
 220int bpf_prog6(struct sk_msg_md *msg)
 221{
 222        int *bytes, zero = 0, one = 1, key = 0;
 223        int *start, *end, *f;
 224        __u64 flags = 0;
 225
 226        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
 227        if (bytes)
 228                bpf_msg_apply_bytes(msg, *bytes);
 229        bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
 230        if (bytes)
 231                bpf_msg_cork_bytes(msg, *bytes);
 232        start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
 233        end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
 234        if (start && end)
 235                bpf_msg_pull_data(msg, *start, *end, 0);
 236        f = bpf_map_lookup_elem(&sock_redir_flags, &zero);
 237        if (f && *f) {
 238                key = 2;
 239                flags = *f;
 240        }
 241        return bpf_msg_redirect_map(msg, &sock_map_redir, key, flags);
 242}
 243
 244SEC("sk_msg4")
 245int bpf_prog7(struct sk_msg_md *msg)
 246{
 247        int err1 = 0, err2 = 0, zero = 0, one = 1, key = 0;
 248        int *f, *bytes, *start, *end, len1, len2;
 249        __u64 flags = 0;
 250
 251                int err;
 252        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
 253        if (bytes)
 254                err1 = bpf_msg_apply_bytes(msg, *bytes);
 255        bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
 256        if (bytes)
 257                err2 = bpf_msg_cork_bytes(msg, *bytes);
 258        len1 = (__u64)msg->data_end - (__u64)msg->data;
 259        start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
 260        end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
 261        if (start && end) {
 262
 263                bpf_printk("sk_msg2: pull(%i:%i)\n",
 264                           start ? *start : 0, end ? *end : 0);
 265                err = bpf_msg_pull_data(msg, *start, *end, 0);
 266                if (err)
 267                        bpf_printk("sk_msg2: pull_data err %i\n",
 268                                   err);
 269                len2 = (__u64)msg->data_end - (__u64)msg->data;
 270                bpf_printk("sk_msg2: length update %i->%i\n",
 271                           len1, len2);
 272        }
 273        f = bpf_map_lookup_elem(&sock_redir_flags, &zero);
 274        if (f && *f) {
 275                key = 2;
 276                flags = *f;
 277        }
 278        bpf_printk("sk_msg3: redirect(%iB) flags=%i err=%i\n",
 279                   len1, flags, err1 ? err1 : err2);
 280        err = bpf_msg_redirect_map(msg, &sock_map_redir, key, flags);
 281        bpf_printk("sk_msg3: err %i\n", err);
 282        return err;
 283}
 284
 285SEC("sk_msg5")
 286int bpf_prog8(struct sk_msg_md *msg)
 287{
 288        void *data_end = (void *)(long) msg->data_end;
 289        void *data = (void *)(long) msg->data;
 290        int ret = 0, *bytes, zero = 0;
 291
 292        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
 293        if (bytes) {
 294                ret = bpf_msg_apply_bytes(msg, *bytes);
 295                if (ret)
 296                        return SK_DROP;
 297        } else {
 298                return SK_DROP;
 299        }
 300        return SK_PASS;
 301}
 302SEC("sk_msg6")
 303int bpf_prog9(struct sk_msg_md *msg)
 304{
 305        void *data_end = (void *)(long) msg->data_end;
 306        void *data = (void *)(long) msg->data;
 307        int ret = 0, *bytes, zero = 0;
 308
 309        bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
 310        if (bytes) {
 311                if (((__u64)data_end - (__u64)data) >= *bytes)
 312                        return SK_PASS;
 313                ret = bpf_msg_cork_bytes(msg, *bytes);
 314                if (ret)
 315                        return SK_DROP;
 316        }
 317        return SK_PASS;
 318}
 319
 320SEC("sk_msg7")
 321int bpf_prog10(struct sk_msg_md *msg)
 322{
 323        int *bytes, zero = 0, one = 1;
 324        int *start, *end;
 325
 326        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
 327        if (bytes)
 328                bpf_msg_apply_bytes(msg, *bytes);
 329        bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
 330        if (bytes)
 331                bpf_msg_cork_bytes(msg, *bytes);
 332        start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
 333        end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
 334        if (start && end)
 335                bpf_msg_pull_data(msg, *start, *end, 0);
 336
 337        return SK_DROP;
 338}
 339
 340
 341char _license[] SEC("license") = "GPL";
 342