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