Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <stddef.h>
0003 #include <string.h>
0004 #include <netinet/in.h>
0005 #include <linux/bpf.h>
0006 #include <linux/if_ether.h>
0007 #include <linux/if_packet.h>
0008 #include <linux/ip.h>
0009 #include <linux/ipv6.h>
0010 #include <linux/types.h>
0011 #include <linux/socket.h>
0012 #include <linux/tcp.h>
0013 #include <bpf/bpf_helpers.h>
0014 #include <bpf/bpf_endian.h>
0015 #include "bpf_tcp_helpers.h"
0016 #include "test_tcpbpf.h"
0017 
0018 struct tcpbpf_globals global = {};
0019 
0020 /**
0021  * SOL_TCP is defined in <netinet/tcp.h> while
0022  * TCP_SAVED_SYN is defined in already included <linux/tcp.h>
0023  */
0024 #ifndef SOL_TCP
0025 #define SOL_TCP 6
0026 #endif
0027 
0028 static __always_inline int get_tp_window_clamp(struct bpf_sock_ops *skops)
0029 {
0030     struct bpf_sock *sk;
0031     struct tcp_sock *tp;
0032 
0033     sk = skops->sk;
0034     if (!sk)
0035         return -1;
0036     tp = bpf_skc_to_tcp_sock(sk);
0037     if (!tp)
0038         return -1;
0039     return tp->window_clamp;
0040 }
0041 
0042 SEC("sockops")
0043 int bpf_testcb(struct bpf_sock_ops *skops)
0044 {
0045     char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)];
0046     struct bpf_sock_ops *reuse = skops;
0047     struct tcphdr *thdr;
0048     int window_clamp = 9216;
0049     int good_call_rv = 0;
0050     int bad_call_rv = 0;
0051     int save_syn = 1;
0052     int rv = -1;
0053     int v = 0;
0054     int op;
0055 
0056     /* Test reading fields in bpf_sock_ops using single register */
0057     asm volatile (
0058         "%[reuse] = *(u32 *)(%[reuse] +96)"
0059         : [reuse] "+r"(reuse)
0060         :);
0061 
0062     asm volatile (
0063         "%[op] = *(u32 *)(%[skops] +96)"
0064         : [op] "+r"(op)
0065         : [skops] "r"(skops)
0066         :);
0067 
0068     asm volatile (
0069         "r9 = %[skops];\n"
0070         "r8 = *(u32 *)(r9 +164);\n"
0071         "*(u32 *)(r9 +164) = r8;\n"
0072         :: [skops] "r"(skops)
0073         : "r9", "r8");
0074 
0075     asm volatile (
0076         "r1 = %[skops];\n"
0077         "r1 = *(u64 *)(r1 +184);\n"
0078         "if r1 == 0 goto +1;\n"
0079         "r1 = *(u32 *)(r1 +4);\n"
0080         :: [skops] "r"(skops):"r1");
0081 
0082     asm volatile (
0083         "r9 = %[skops];\n"
0084         "r9 = *(u64 *)(r9 +184);\n"
0085         "if r9 == 0 goto +1;\n"
0086         "r9 = *(u32 *)(r9 +4);\n"
0087         :: [skops] "r"(skops):"r9");
0088 
0089     asm volatile (
0090         "r1 = %[skops];\n"
0091         "r2 = *(u64 *)(r1 +184);\n"
0092         "if r2 == 0 goto +1;\n"
0093         "r2 = *(u32 *)(r2 +4);\n"
0094         :: [skops] "r"(skops):"r1", "r2");
0095 
0096     op = (int) skops->op;
0097 
0098     global.event_map |= (1 << op);
0099 
0100     switch (op) {
0101     case BPF_SOCK_OPS_TCP_CONNECT_CB:
0102         rv = bpf_setsockopt(skops, SOL_TCP, TCP_WINDOW_CLAMP,
0103                     &window_clamp, sizeof(window_clamp));
0104         global.window_clamp_client = get_tp_window_clamp(skops);
0105         break;
0106     case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
0107         /* Test failure to set largest cb flag (assumes not defined) */
0108         global.bad_cb_test_rv = bpf_sock_ops_cb_flags_set(skops, 0x80);
0109         /* Set callback */
0110         global.good_cb_test_rv = bpf_sock_ops_cb_flags_set(skops,
0111                          BPF_SOCK_OPS_STATE_CB_FLAG);
0112         break;
0113     case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
0114         skops->sk_txhash = 0x12345f;
0115         v = 0xff;
0116         rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v,
0117                     sizeof(v));
0118         if (skops->family == AF_INET6) {
0119             v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN,
0120                        header, (sizeof(struct ipv6hdr) +
0121                             sizeof(struct tcphdr)));
0122             if (!v) {
0123                 int offset = sizeof(struct ipv6hdr);
0124 
0125                 thdr = (struct tcphdr *)(header + offset);
0126                 v = thdr->syn;
0127 
0128                 global.tcp_saved_syn = v;
0129             }
0130         }
0131         rv = bpf_setsockopt(skops, SOL_TCP, TCP_WINDOW_CLAMP,
0132                     &window_clamp, sizeof(window_clamp));
0133 
0134         global.window_clamp_server = get_tp_window_clamp(skops);
0135         break;
0136     case BPF_SOCK_OPS_RTO_CB:
0137         break;
0138     case BPF_SOCK_OPS_RETRANS_CB:
0139         break;
0140     case BPF_SOCK_OPS_STATE_CB:
0141         if (skops->args[1] == BPF_TCP_CLOSE) {
0142             if (skops->args[0] == BPF_TCP_LISTEN) {
0143                 global.num_listen++;
0144             } else {
0145                 global.total_retrans = skops->total_retrans;
0146                 global.data_segs_in = skops->data_segs_in;
0147                 global.data_segs_out = skops->data_segs_out;
0148                 global.bytes_received = skops->bytes_received;
0149                 global.bytes_acked = skops->bytes_acked;
0150             }
0151             global.num_close_events++;
0152         }
0153         break;
0154     case BPF_SOCK_OPS_TCP_LISTEN_CB:
0155         bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
0156         v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN,
0157                    &save_syn, sizeof(save_syn));
0158         /* Update global map w/ result of setsock opt */
0159         global.tcp_save_syn = v;
0160         break;
0161     default:
0162         rv = -1;
0163     }
0164     skops->reply = rv;
0165     return 1;
0166 }
0167 char _license[] SEC("license") = "GPL";