Skip to content

Commit

Permalink
allow to mangle source ip (#218)
Browse files Browse the repository at this point in the history
Summary:
Right now for ipip healtchecks we are using balancer's source ip. While for data packets (the one which would be actually load balanced) we are using specially crafted (mangled) source IPs to play nice with NIC's RSS. However there could be unfortunate scenarios when backend has some kind of FW rules installed which allow packets from internal IPs (e.g. from 10/8) but do not allow packets from say mangled space (which by default is 172.16/16). In such unfortunate events we could end up w/ load balancer thinks that backend is healthy (because healthchecks are passing just fine; as 10/8 is permitted from firewall point of view) but actually data packets are being dropped / blackholled by FW (because 172.16/16 is not allowed)

This diff creates a common functions which could be reused both in HC and Balancer itself to enable healtchecks source mangling. As well as introduces new compile time flag which enables this feature (so it is no-op for default setup) for ipip healthchecks

Tested by:
default katran_tester's UTs are passing as is (both for balancer and healthchecker)

w/ MANGLE_HC_SOURCE define set HC sources became from the "mangled" space
```
10:19:24.279152 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 43)
    192.168.1.1.31337 > 10.200.1.1.80: [udp sum ok] UDP, length 15

# Mangled v4 src
10:19:24.279155 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto IPIP (4), length 63)
    172.16.119.76 > 10.0.0.1: IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 43)
    192.168.1.1.31337 > 10.200.1.1.80: [udp sum ok] UDP, length 15

10:19:24.279160 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto TCP (6), length 55)
    192.168.1.1.31337 > 10.200.1.1.80: Flags [.], cksum 0x27e4 (correct), seq 0:15, ack 1, win 8192, length 15: HTTP

10:19:24.279162 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto IPIP (4), length 75)
    172.16.119.76 > 10.0.0.2: IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto TCP (6), length 55)
    192.168.1.1.31337 > 10.200.1.1.80: Flags [.], cksum 0x27e4 (correct), seq 0:15, ack 1, win 8192, length 15: HTTP

10:19:24.279169 IP6 (hlim 64, next-header TCP (6) payload length: 35) fc00:2::1.31337 > fc00:1::1.80: Flags [.], cksum 0xfd4f (correct), seq 0:15, ack 1, win 8192, length 15: HTTP

#Mangled v6 src
10:19:24.279173 IP6 (hlim 64, next-header IPv6 (41) payload length: 75) 100::697a:1337 > fc00::1: IP6 (hlim 64, next-header TCP (6) payload length: 35) fc00:2::1.31337 > fc00:1::1.80: Flags [.], cksum 0xfd4f (correct), seq 0:15, ack 1, win 8192, length 15: HTTP

```

Pull Request resolved: #218

Reviewed By: frankfeir

Differential Revision: D53024979

Pulled By: avasylev

fbshipit-source-id: c8272d4e22f7559a121acef186796e0038ef8086
  • Loading branch information
tehnerd authored and facebook-github-bot committed Jan 24, 2024
1 parent 66ac216 commit 43889f1
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 22 deletions.
17 changes: 17 additions & 0 deletions katran/lib/bpf/encap_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@
#include "katran/lib/bpf/balancer_consts.h"
#include "katran/lib/bpf/csum_helpers.h"

__attribute__((__always_inline__)) static inline void
create_encap_ipv6_src(__u16 port, __be32 src, __u32* saddr) {
saddr[0] = IPIP_V6_PREFIX1;
saddr[1] = IPIP_V6_PREFIX2;
saddr[2] = IPIP_V6_PREFIX3;
saddr[3] = src ^ port;
}

__attribute__((__always_inline__)) static inline __u32 create_encap_ipv4_src(
__u16 port,
__be32 src) {
__u32 ip_suffix = bpf_htons(port);
ip_suffix <<= 16;
ip_suffix ^= src;
return ((0xFFFF0000 & ip_suffix) | IPIP_V4_PREFIX);
}

__attribute__((__always_inline__)) static inline void create_v4_hdr(
struct iphdr* iph,
__u8 tos,
Expand Down
6 changes: 6 additions & 0 deletions katran/lib/bpf/healthchecking_consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@

#define NO_FLAGS 0

// for ip-in-ip encap
// source address of the healthcheck would be crafted the same way as data
// packet
//#define MANGLE_HC_SRC 1
#define MANGLED_HC_SRC_PORT 31337

#define V6DADDR (1 << 0)

#define HC_SRC_MAC_POS 0
Expand Down
18 changes: 14 additions & 4 deletions katran/lib/bpf/healthchecking_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,13 @@ __attribute__((__always_inline__)) static inline bool hc_encap_ipip(
if (!is_ipv6) {
proto = IPPROTO_IPIP;
}
create_v6_hdr(
ip6h, DEFAULT_TOS, src->v6daddr, real->v6daddr, pkt_len, proto);
__u32 saddr[4];
#ifdef MANGLE_HC_SRC
create_encap_ipv6_src(MANGLED_HC_SRC_PORT, src->v6daddr[3], saddr);
#else
memcpy(saddr, src->v6daddr, 16);
#endif
create_v6_hdr(ip6h, DEFAULT_TOS, saddr, real->v6daddr, pkt_len, proto);
} else {
key = V4_SRC_INDEX;
src = bpf_map_lookup_elem(&hc_pckt_srcs_map, &key);
Expand All @@ -132,8 +137,13 @@ __attribute__((__always_inline__)) static inline bool hc_encap_ipip(
return false;
}
struct iphdr* iph = (void*)(long)skb->data + sizeof(struct ethhdr);
create_v4_hdr(
iph, DEFAULT_TOS, src->daddr, real->daddr, pkt_len, IPPROTO_IPIP);
#ifdef MANGLE_HC_SRC
__u32 ip_src = create_encap_ipv4_src(MANGLED_HC_SRC_PORT, src->daddr);
#else
__u32 ip_src = src->daddr;
#endif

create_v4_hdr(iph, DEFAULT_TOS, ip_src, real->daddr, pkt_len, IPPROTO_IPIP);
}
return true;
}
Expand Down
22 changes: 4 additions & 18 deletions katran/lib/bpf/pckt_encap.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ __attribute__((__always_inline__)) static inline bool encap_v6(
struct ethhdr* new_eth;
struct ethhdr* old_eth;
__u16 payload_len;
__u32 ip_suffix;
__u32 saddr[4];
__u8 proto;
// ip(6)ip6 encap
Expand All @@ -73,19 +72,14 @@ __attribute__((__always_inline__)) static inline bool encap_v6(

if (is_ipv6) {
proto = IPPROTO_IPV6;
ip_suffix = pckt->flow.srcv6[3] ^ pckt->flow.port16[0];
create_encap_ipv6_src(pckt->flow.port16[0], pckt->flow.srcv6[3], saddr);
payload_len = pkt_bytes + sizeof(struct ipv6hdr);
} else {
proto = IPPROTO_IPIP;
ip_suffix = pckt->flow.src ^ pckt->flow.port16[0];
create_encap_ipv6_src(pckt->flow.port16[0], pckt->flow.src, saddr);
payload_len = pkt_bytes;
}

saddr[0] = IPIP_V6_PREFIX1;
saddr[1] = IPIP_V6_PREFIX2;
saddr[2] = IPIP_V6_PREFIX3;
saddr[3] = ip_suffix;

create_v6_hdr(ip6h, pckt->tos, saddr, dst->dstv6, payload_len, proto);

return true;
Expand All @@ -102,9 +96,7 @@ __attribute__((__always_inline__)) static inline bool encap_v4(
struct iphdr* iph;
struct ethhdr* new_eth;
struct ethhdr* old_eth;
__u32 ip_suffix = bpf_htons(pckt->flow.port16[0]);
ip_suffix <<= 16;
ip_suffix ^= pckt->flow.src;
__u32 ip_src = create_encap_ipv4_src(pckt->flow.port16[0], pckt->flow.src);
__u64 csum = 0;
// ipip encap
if (XDP_ADJUST_HEAD_FUNC(xdp, 0 - (int)sizeof(struct iphdr))) {
Expand All @@ -122,13 +114,7 @@ __attribute__((__always_inline__)) static inline bool encap_v4(
memcpy(new_eth->h_source, old_eth->h_dest, 6);
new_eth->h_proto = BE_ETH_P_IP;

create_v4_hdr(
iph,
pckt->tos,
((0xFFFF0000 & ip_suffix) | IPIP_V4_PREFIX),
dst->dst,
pkt_bytes,
IPPROTO_IPIP);
create_v4_hdr(iph, pckt->tos, ip_src, dst->dst, pkt_bytes, IPPROTO_IPIP);

return true;
}
Expand Down

0 comments on commit 43889f1

Please sign in to comment.