1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018 Facebook */
7 #include <linux/ipv6.h>
10 #include <linux/bpf.h>
11 #include <linux/types.h>
12 #include <linux/if_ether.h>
14 #include <bpf/bpf_endian.h>
15 #include <bpf/bpf_helpers.h>
16 #include "test_select_reuseport_common.h"
18 int _version
SEC("version") = 1;
21 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
25 __uint(type
, BPF_MAP_TYPE_ARRAY_OF_MAPS
);
26 __uint(max_entries
, 1);
27 __uint(key_size
, sizeof(__u32
));
28 __uint(value_size
, sizeof(__u32
));
29 } outer_map
SEC(".maps");
32 __uint(type
, BPF_MAP_TYPE_ARRAY
);
33 __uint(max_entries
, NR_RESULTS
);
36 } result_map
SEC(".maps");
39 __uint(type
, BPF_MAP_TYPE_ARRAY
);
40 __uint(max_entries
, 1);
43 } tmp_index_ovr_map
SEC(".maps");
46 __uint(type
, BPF_MAP_TYPE_ARRAY
);
47 __uint(max_entries
, 1);
50 } linum_map
SEC(".maps");
53 __uint(type
, BPF_MAP_TYPE_ARRAY
);
54 __uint(max_entries
, 1);
56 __type(value
, struct data_check
);
57 } data_check_map
SEC(".maps");
59 #define GOTO_DONE(_result) ({ \
66 int _select_by_skb_data(struct sk_reuseport_md
*reuse_md
)
68 __u32 linum
, index
= 0, flags
= 0, index_zero
= 0;
69 __u32
*result_cnt
, *linum_value
;
70 struct data_check data_check
= {};
71 struct cmd
*cmd
, cmd_copy
;
72 void *data
, *data_end
;
73 void *reuseport_array
;
78 data
= reuse_md
->data
;
79 data_end
= reuse_md
->data_end
;
80 data_check
.len
= reuse_md
->len
;
81 data_check
.eth_protocol
= reuse_md
->eth_protocol
;
82 data_check
.ip_protocol
= reuse_md
->ip_protocol
;
83 data_check
.hash
= reuse_md
->hash
;
84 data_check
.bind_inany
= reuse_md
->bind_inany
;
85 if (data_check
.eth_protocol
== bpf_htons(ETH_P_IP
)) {
86 if (bpf_skb_load_bytes_relative(reuse_md
,
87 offsetof(struct iphdr
, saddr
),
88 data_check
.skb_addrs
, 8,
92 if (bpf_skb_load_bytes_relative(reuse_md
,
93 offsetof(struct ipv6hdr
, saddr
),
94 data_check
.skb_addrs
, 32,
100 * The ip_protocol could be a compile time decision
101 * if the bpf_prog.o is dedicated to either TCP or
104 * Otherwise, reuse_md->ip_protocol or
105 * the protocol field in the iphdr can be used.
107 if (data_check
.ip_protocol
== IPPROTO_TCP
) {
108 struct tcphdr
*th
= data
;
110 if (th
+ 1 > data_end
)
111 GOTO_DONE(DROP_MISC
);
113 data_check
.skb_ports
[0] = th
->source
;
114 data_check
.skb_ports
[1] = th
->dest
;
117 /* The connection is being torn down at the end of a
118 * test. It can't contain a cmd, so return early.
122 if ((th
->doff
<< 2) + sizeof(*cmd
) > data_check
.len
)
123 GOTO_DONE(DROP_ERR_SKB_DATA
);
124 if (bpf_skb_load_bytes(reuse_md
, th
->doff
<< 2, &cmd_copy
,
126 GOTO_DONE(DROP_MISC
);
128 } else if (data_check
.ip_protocol
== IPPROTO_UDP
) {
129 struct udphdr
*uh
= data
;
131 if (uh
+ 1 > data_end
)
132 GOTO_DONE(DROP_MISC
);
134 data_check
.skb_ports
[0] = uh
->source
;
135 data_check
.skb_ports
[1] = uh
->dest
;
137 if (sizeof(struct udphdr
) + sizeof(*cmd
) > data_check
.len
)
138 GOTO_DONE(DROP_ERR_SKB_DATA
);
139 if (data
+ sizeof(struct udphdr
) + sizeof(*cmd
) > data_end
) {
140 if (bpf_skb_load_bytes(reuse_md
, sizeof(struct udphdr
),
141 &cmd_copy
, sizeof(cmd_copy
)))
142 GOTO_DONE(DROP_MISC
);
145 cmd
= data
+ sizeof(struct udphdr
);
148 GOTO_DONE(DROP_MISC
);
151 reuseport_array
= bpf_map_lookup_elem(&outer_map
, &index_zero
);
152 if (!reuseport_array
)
153 GOTO_DONE(DROP_ERR_INNER_MAP
);
155 index
= cmd
->reuseport_index
;
156 index_ovr
= bpf_map_lookup_elem(&tmp_index_ovr_map
, &index_zero
);
158 GOTO_DONE(DROP_MISC
);
160 if (*index_ovr
!= -1) {
164 err
= bpf_sk_select_reuseport(reuse_md
, reuseport_array
, &index
,
169 if (cmd
->pass_on_failure
)
170 GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT
);
172 GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT
);
175 result_cnt
= bpf_map_lookup_elem(&result_map
, &result
);
179 bpf_map_update_elem(&linum_map
, &index_zero
, &linum
, BPF_ANY
);
180 bpf_map_update_elem(&data_check_map
, &index_zero
, &data_check
, BPF_ANY
);
183 return result
< PASS
? SK_DROP
: SK_PASS
;
186 char _license
[] SEC("license") = "GPL";