1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2017 Facebook
6 #include <linux/pkt_cls.h>
9 #include <linux/if_ether.h>
11 #include <linux/ipv6.h>
12 #include <linux/icmp.h>
13 #include <linux/icmpv6.h>
14 #include <linux/tcp.h>
15 #include <linux/udp.h>
16 #include <bpf/bpf_helpers.h>
17 #include "test_iptunnel_common.h"
18 #include <bpf/bpf_endian.h>
20 static __always_inline __u32
rol32(__u32 word
, unsigned int shift
)
22 return (word
<< shift
) | (word
>> ((-shift
) & 31));
25 /* copy paste of jhash from kernel sources to make sure llvm
26 * can compile it into valid sequence of bpf instructions
28 #define __jhash_mix(a, b, c) \
30 a -= c; a ^= rol32(c, 4); c += b; \
31 b -= a; b ^= rol32(a, 6); a += c; \
32 c -= b; c ^= rol32(b, 8); b += a; \
33 a -= c; a ^= rol32(c, 16); c += b; \
34 b -= a; b ^= rol32(a, 19); a += c; \
35 c -= b; c ^= rol32(b, 4); b += a; \
38 #define __jhash_final(a, b, c) \
40 c ^= b; c -= rol32(b, 14); \
41 a ^= c; a -= rol32(c, 11); \
42 b ^= a; b -= rol32(a, 25); \
43 c ^= b; c -= rol32(b, 16); \
44 a ^= c; a -= rol32(c, 4); \
45 b ^= a; b -= rol32(a, 14); \
46 c ^= b; c -= rol32(b, 24); \
49 #define JHASH_INITVAL 0xdeadbeef
51 typedef unsigned int u32
;
53 static __noinline u32
jhash(const void *key
, u32 length
, u32 initval
)
56 const unsigned char *k
= key
;
58 a
= b
= c
= JHASH_INITVAL
+ length
+ initval
;
69 case 12: c
+= (u32
)k
[11]<<24;
70 case 11: c
+= (u32
)k
[10]<<16;
71 case 10: c
+= (u32
)k
[9]<<8;
73 case 8: b
+= (u32
)k
[7]<<24;
74 case 7: b
+= (u32
)k
[6]<<16;
75 case 6: b
+= (u32
)k
[5]<<8;
77 case 4: a
+= (u32
)k
[3]<<24;
78 case 3: a
+= (u32
)k
[2]<<16;
79 case 2: a
+= (u32
)k
[1]<<8;
81 __jhash_final(a
, b
, c
);
82 case 0: /* Nothing left to add */
89 static __noinline u32
__jhash_nwords(u32 a
, u32 b
, u32 c
, u32 initval
)
94 __jhash_final(a
, b
, c
);
98 static __noinline u32
jhash_2words(u32 a
, u32 b
, u32 initval
)
100 return __jhash_nwords(a
, b
, 0, initval
+ JHASH_INITVAL
+ (2 << 2));
103 #define PCKT_FRAGMENTED 65343
104 #define IPV4_HDR_LEN_NO_OPT 20
105 #define IPV4_PLUS_ICMP_HDR 28
106 #define IPV6_PLUS_ICMP_HDR 48
110 #define CTL_MAP_SIZE 16
111 #define CH_RINGS_SIZE (MAX_VIPS * RING_SIZE)
112 #define F_IPV6 (1 << 0)
113 #define F_HASH_NO_SRC_PORT (1 << 0)
114 #define F_ICMP (1 << 0)
115 #define F_SYN_SET (1 << 1)
117 struct packet_description
{
147 struct real_definition
{
161 unsigned char eth_dest
[ETH_ALEN
];
162 unsigned char eth_source
[ETH_ALEN
];
163 unsigned short eth_proto
;
167 __uint(type
, BPF_MAP_TYPE_HASH
);
168 __uint(max_entries
, MAX_VIPS
);
169 __type(key
, struct vip
);
170 __type(value
, struct vip_meta
);
171 } vip_map
SEC(".maps");
174 __uint(type
, BPF_MAP_TYPE_ARRAY
);
175 __uint(max_entries
, CH_RINGS_SIZE
);
177 __type(value
, __u32
);
178 } ch_rings
SEC(".maps");
181 __uint(type
, BPF_MAP_TYPE_ARRAY
);
182 __uint(max_entries
, MAX_REALS
);
184 __type(value
, struct real_definition
);
185 } reals
SEC(".maps");
188 __uint(type
, BPF_MAP_TYPE_PERCPU_ARRAY
);
189 __uint(max_entries
, MAX_VIPS
);
191 __type(value
, struct vip_stats
);
192 } stats
SEC(".maps");
195 __uint(type
, BPF_MAP_TYPE_ARRAY
);
196 __uint(max_entries
, CTL_MAP_SIZE
);
198 __type(value
, struct ctl_value
);
199 } ctl_array
SEC(".maps");
201 static __noinline __u32
get_packet_hash(struct packet_description
*pckt
, bool ipv6
)
204 return jhash_2words(jhash(pckt
->srcv6
, 16, MAX_VIPS
),
205 pckt
->ports
, CH_RINGS_SIZE
);
207 return jhash_2words(pckt
->src
, pckt
->ports
, CH_RINGS_SIZE
);
210 static __noinline
bool get_packet_dst(struct real_definition
**real
,
211 struct packet_description
*pckt
,
212 struct vip_meta
*vip_info
,
215 __u32 hash
= get_packet_hash(pckt
, is_ipv6
);
216 __u32 key
= RING_SIZE
* vip_info
->vip_num
+ hash
% RING_SIZE
;
219 if (hash
!= 0x358459b7 /* jhash of ipv4 packet */ &&
220 hash
!= 0x2f4bc6bb /* jhash of ipv6 packet */)
223 real_pos
= bpf_map_lookup_elem(&ch_rings
, &key
);
227 *real
= bpf_map_lookup_elem(&reals
, &key
);
233 static __noinline
int parse_icmpv6(void *data
, void *data_end
, __u64 off
,
234 struct packet_description
*pckt
)
236 struct icmp6hdr
*icmp_hdr
;
237 struct ipv6hdr
*ip6h
;
239 icmp_hdr
= data
+ off
;
240 if (icmp_hdr
+ 1 > data_end
)
242 if (icmp_hdr
->icmp6_type
!= ICMPV6_PKT_TOOBIG
)
244 off
+= sizeof(struct icmp6hdr
);
246 if (ip6h
+ 1 > data_end
)
248 pckt
->proto
= ip6h
->nexthdr
;
249 pckt
->flags
|= F_ICMP
;
250 memcpy(pckt
->srcv6
, ip6h
->daddr
.s6_addr32
, 16);
251 memcpy(pckt
->dstv6
, ip6h
->saddr
.s6_addr32
, 16);
252 return TC_ACT_UNSPEC
;
255 static __noinline
int parse_icmp(void *data
, void *data_end
, __u64 off
,
256 struct packet_description
*pckt
)
258 struct icmphdr
*icmp_hdr
;
261 icmp_hdr
= data
+ off
;
262 if (icmp_hdr
+ 1 > data_end
)
264 if (icmp_hdr
->type
!= ICMP_DEST_UNREACH
||
265 icmp_hdr
->code
!= ICMP_FRAG_NEEDED
)
267 off
+= sizeof(struct icmphdr
);
269 if (iph
+ 1 > data_end
)
273 pckt
->proto
= iph
->protocol
;
274 pckt
->flags
|= F_ICMP
;
275 pckt
->src
= iph
->daddr
;
276 pckt
->dst
= iph
->saddr
;
277 return TC_ACT_UNSPEC
;
280 static __noinline
bool parse_udp(void *data
, __u64 off
, void *data_end
,
281 struct packet_description
*pckt
)
286 if (udp
+ 1 > data_end
)
289 if (!(pckt
->flags
& F_ICMP
)) {
290 pckt
->port16
[0] = udp
->source
;
291 pckt
->port16
[1] = udp
->dest
;
293 pckt
->port16
[0] = udp
->dest
;
294 pckt
->port16
[1] = udp
->source
;
299 static __noinline
bool parse_tcp(void *data
, __u64 off
, void *data_end
,
300 struct packet_description
*pckt
)
305 if (tcp
+ 1 > data_end
)
309 pckt
->flags
|= F_SYN_SET
;
311 if (!(pckt
->flags
& F_ICMP
)) {
312 pckt
->port16
[0] = tcp
->source
;
313 pckt
->port16
[1] = tcp
->dest
;
315 pckt
->port16
[0] = tcp
->dest
;
316 pckt
->port16
[1] = tcp
->source
;
321 static __noinline
int process_packet(void *data
, __u64 off
, void *data_end
,
322 bool is_ipv6
, struct __sk_buff
*skb
)
324 void *pkt_start
= (void *)(long)skb
->data
;
325 struct packet_description pckt
= {};
326 struct eth_hdr
*eth
= pkt_start
;
327 struct bpf_tunnel_key tkey
= {};
328 struct vip_stats
*data_stats
;
329 struct real_definition
*dst
;
330 struct vip_meta
*vip_info
;
331 struct ctl_value
*cval
;
332 __u32 v4_intf_pos
= 1;
333 __u32 v6_intf_pos
= 2;
334 struct ipv6hdr
*ip6h
;
345 tkey
.tunnel_ttl
= 64;
348 if (ip6h
+ 1 > data_end
)
351 iph_len
= sizeof(struct ipv6hdr
);
352 protocol
= ip6h
->nexthdr
;
353 pckt
.proto
= protocol
;
354 pkt_bytes
= bpf_ntohs(ip6h
->payload_len
);
356 if (protocol
== IPPROTO_FRAGMENT
) {
358 } else if (protocol
== IPPROTO_ICMPV6
) {
359 action
= parse_icmpv6(data
, data_end
, off
, &pckt
);
362 off
+= IPV6_PLUS_ICMP_HDR
;
364 memcpy(pckt
.srcv6
, ip6h
->saddr
.s6_addr32
, 16);
365 memcpy(pckt
.dstv6
, ip6h
->daddr
.s6_addr32
, 16);
369 if (iph
+ 1 > data_end
)
374 protocol
= iph
->protocol
;
375 pckt
.proto
= protocol
;
376 pkt_bytes
= bpf_ntohs(iph
->tot_len
);
377 off
+= IPV4_HDR_LEN_NO_OPT
;
379 if (iph
->frag_off
& PCKT_FRAGMENTED
)
381 if (protocol
== IPPROTO_ICMP
) {
382 action
= parse_icmp(data
, data_end
, off
, &pckt
);
385 off
+= IPV4_PLUS_ICMP_HDR
;
387 pckt
.src
= iph
->saddr
;
388 pckt
.dst
= iph
->daddr
;
391 protocol
= pckt
.proto
;
393 if (protocol
== IPPROTO_TCP
) {
394 if (!parse_tcp(data
, off
, data_end
, &pckt
))
396 } else if (protocol
== IPPROTO_UDP
) {
397 if (!parse_udp(data
, off
, data_end
, &pckt
))
404 memcpy(vip
.daddr
.v6
, pckt
.dstv6
, 16);
406 vip
.daddr
.v4
= pckt
.dst
;
408 vip
.dport
= pckt
.port16
[1];
409 vip
.protocol
= pckt
.proto
;
410 vip_info
= bpf_map_lookup_elem(&vip_map
, &vip
);
413 vip_info
= bpf_map_lookup_elem(&vip_map
, &vip
);
419 if (vip_info
->flags
& F_HASH_NO_SRC_PORT
)
422 if (!get_packet_dst(&dst
, &pckt
, vip_info
, is_ipv6
))
425 if (dst
->flags
& F_IPV6
) {
426 cval
= bpf_map_lookup_elem(&ctl_array
, &v6_intf_pos
);
429 ifindex
= cval
->ifindex
;
430 memcpy(tkey
.remote_ipv6
, dst
->dstv6
, 16);
431 tun_flag
= BPF_F_TUNINFO_IPV6
;
433 cval
= bpf_map_lookup_elem(&ctl_array
, &v4_intf_pos
);
436 ifindex
= cval
->ifindex
;
437 tkey
.remote_ipv4
= dst
->dst
;
439 vip_num
= vip_info
->vip_num
;
440 data_stats
= bpf_map_lookup_elem(&stats
, &vip_num
);
444 data_stats
->bytes
+= pkt_bytes
;
445 bpf_skb_set_tunnel_key(skb
, &tkey
, sizeof(tkey
), tun_flag
);
446 *(u32
*)eth
->eth_dest
= tkey
.remote_ipv4
;
447 return bpf_redirect(ifindex
, 0);
451 int balancer_ingress(struct __sk_buff
*ctx
)
453 void *data_end
= (void *)(long)ctx
->data_end
;
454 void *data
= (void *)(long)ctx
->data
;
455 struct eth_hdr
*eth
= data
;
459 nh_off
= sizeof(struct eth_hdr
);
460 if (data
+ nh_off
> data_end
)
462 eth_proto
= eth
->eth_proto
;
463 if (eth_proto
== bpf_htons(ETH_P_IP
))
464 return process_packet(data
, nh_off
, data_end
, false, ctx
);
465 else if (eth_proto
== bpf_htons(ETH_P_IPV6
))
466 return process_packet(data
, nh_off
, data_end
, true, ctx
);
470 char _license
[] SEC("license") = "GPL";