linux/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <stddef.h>
   3#include <string.h>
   4#include <netinet/in.h>
   5#include <linux/bpf.h>
   6#include <linux/if_ether.h>
   7#include <linux/if_packet.h>
   8#include <linux/ip.h>
   9#include <linux/ipv6.h>
  10#include <linux/types.h>
  11#include <linux/socket.h>
  12#include <linux/tcp.h>
  13#include "bpf_helpers.h"
  14#include "bpf_endian.h"
  15#include "test_tcpbpf.h"
  16
  17struct {
  18        __uint(type, BPF_MAP_TYPE_ARRAY);
  19        __uint(max_entries, 4);
  20        __type(key, __u32);
  21        __type(value, struct tcpbpf_globals);
  22} global_map SEC(".maps");
  23
  24struct {
  25        __uint(type, BPF_MAP_TYPE_ARRAY);
  26        __uint(max_entries, 2);
  27        __type(key, __u32);
  28        __type(value, int);
  29} sockopt_results SEC(".maps");
  30
  31static inline void update_event_map(int event)
  32{
  33        __u32 key = 0;
  34        struct tcpbpf_globals g, *gp;
  35
  36        gp = bpf_map_lookup_elem(&global_map, &key);
  37        if (gp == NULL) {
  38                struct tcpbpf_globals g = {0};
  39
  40                g.event_map |= (1 << event);
  41                bpf_map_update_elem(&global_map, &key, &g,
  42                            BPF_ANY);
  43        } else {
  44                g = *gp;
  45                g.event_map |= (1 << event);
  46                bpf_map_update_elem(&global_map, &key, &g,
  47                            BPF_ANY);
  48        }
  49}
  50
  51int _version SEC("version") = 1;
  52
  53SEC("sockops")
  54int bpf_testcb(struct bpf_sock_ops *skops)
  55{
  56        char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)];
  57        struct tcphdr *thdr;
  58        int good_call_rv = 0;
  59        int bad_call_rv = 0;
  60        int save_syn = 1;
  61        int rv = -1;
  62        int v = 0;
  63        int op;
  64
  65        op = (int) skops->op;
  66
  67        update_event_map(op);
  68
  69        switch (op) {
  70        case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
  71                /* Test failure to set largest cb flag (assumes not defined) */
  72                bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80);
  73                /* Set callback */
  74                good_call_rv = bpf_sock_ops_cb_flags_set(skops,
  75                                                 BPF_SOCK_OPS_STATE_CB_FLAG);
  76                /* Update results */
  77                {
  78                        __u32 key = 0;
  79                        struct tcpbpf_globals g, *gp;
  80
  81                        gp = bpf_map_lookup_elem(&global_map, &key);
  82                        if (!gp)
  83                                break;
  84                        g = *gp;
  85                        g.bad_cb_test_rv = bad_call_rv;
  86                        g.good_cb_test_rv = good_call_rv;
  87                        bpf_map_update_elem(&global_map, &key, &g,
  88                                            BPF_ANY);
  89                }
  90                break;
  91        case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
  92                skops->sk_txhash = 0x12345f;
  93                v = 0xff;
  94                rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v,
  95                                    sizeof(v));
  96                if (skops->family == AF_INET6) {
  97                        v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN,
  98                                           header, (sizeof(struct ipv6hdr) +
  99                                                    sizeof(struct tcphdr)));
 100                        if (!v) {
 101                                int offset = sizeof(struct ipv6hdr);
 102
 103                                thdr = (struct tcphdr *)(header + offset);
 104                                v = thdr->syn;
 105                                __u32 key = 1;
 106
 107                                bpf_map_update_elem(&sockopt_results, &key, &v,
 108                                                    BPF_ANY);
 109                        }
 110                }
 111                break;
 112        case BPF_SOCK_OPS_RTO_CB:
 113                break;
 114        case BPF_SOCK_OPS_RETRANS_CB:
 115                break;
 116        case BPF_SOCK_OPS_STATE_CB:
 117                if (skops->args[1] == BPF_TCP_CLOSE) {
 118                        __u32 key = 0;
 119                        struct tcpbpf_globals g, *gp;
 120
 121                        gp = bpf_map_lookup_elem(&global_map, &key);
 122                        if (!gp)
 123                                break;
 124                        g = *gp;
 125                        if (skops->args[0] == BPF_TCP_LISTEN) {
 126                                g.num_listen++;
 127                        } else {
 128                                g.total_retrans = skops->total_retrans;
 129                                g.data_segs_in = skops->data_segs_in;
 130                                g.data_segs_out = skops->data_segs_out;
 131                                g.bytes_received = skops->bytes_received;
 132                                g.bytes_acked = skops->bytes_acked;
 133                        }
 134                        bpf_map_update_elem(&global_map, &key, &g,
 135                                            BPF_ANY);
 136                }
 137                break;
 138        case BPF_SOCK_OPS_TCP_LISTEN_CB:
 139                bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
 140                v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN,
 141                                   &save_syn, sizeof(save_syn));
 142                /* Update global map w/ result of setsock opt */
 143                __u32 key = 0;
 144
 145                bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY);
 146                break;
 147        default:
 148                rv = -1;
 149        }
 150        skops->reply = rv;
 151        return 1;
 152}
 153char _license[] SEC("license") = "GPL";
 154