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 17 struct bpf_map_def SEC("maps") global_map = { 18 .type = BPF_MAP_TYPE_ARRAY, 19 .key_size = sizeof(__u32), 20 .value_size = sizeof(struct tcpbpf_globals), 21 .max_entries = 4, 22 }; 23 24 struct bpf_map_def SEC("maps") sockopt_results = { 25 .type = BPF_MAP_TYPE_ARRAY, 26 .key_size = sizeof(__u32), 27 .value_size = sizeof(int), 28 .max_entries = 2, 29 }; 30 31 static 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 51 int _version SEC("version") = 1; 52 53 SEC("sockops") 54 int 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 } 153 char _license[] SEC("license") = "GPL"; 154