Skip to content

Commit

Permalink
Support stable rt header in katran
Browse files Browse the repository at this point in the history
Summary:
For UDP stable routing use case for Remote presence.
We introduce a new vip flag F_UDP_STABLE_ROUTING_VIP.
If we receive packets for this vip, we will parse the stable routing header to get server-id and then route to it.
Currently stable routing is 8bytes header, format same as QUIC conn id v2. (may change 1st byte later based on more experiments).

Stats collection will be added in next diffs

Reviewed By: avasylev

Differential Revision: D64728833

fbshipit-source-id: c2d85d69157f9a48688cbfd3c41b09f6a2a5b1dc
  • Loading branch information
Nikhil Dixit Limaye authored and facebook-github-bot committed Oct 24, 2024
1 parent e98d032 commit d2c4e38
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 0 deletions.
9 changes: 9 additions & 0 deletions katran/lib/BalancerStructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,13 @@ struct lb_tpr_packets_stats {
uint64_t tcp_syn;
};

// struct for udp stable routing statistics counters
struct lb_stable_rt_packets_stats {
uint64_t ch_routed;
uint64_t cid_routed;
uint64_t cid_invalid_server_id;
uint64_t cid_unknown_real_dropped;
uint64_t invalid_packet_type;
};

} // namespace katran
56 changes: 56 additions & 0 deletions katran/lib/bpf/balancer.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,56 @@ __attribute__((__always_inline__)) static inline int process_encaped_gue_pckt(
}
#endif // of INLINE_DECAP_GUE

#ifdef UDP_STABLE_ROUTING
__attribute__((__always_inline__)) static inline bool
process_udp_stable_routing(
void* data,
void* data_end,
struct real_definition** dst,
struct packet_description* pckt,
bool is_ipv6) {
__u32 stable_rt_stats_key = 0;
struct lb_stable_rt_packets_stats* stable_rt_packets_stats =
bpf_map_lookup_elem(&stable_rt_stats, &stable_rt_stats_key);
if (!stable_rt_packets_stats) {
return XDP_DROP;
}
struct udp_stable_rt_result usr =
parse_udp_stable_rt_hdr(data, data_end, is_ipv6, pckt);
if (usr.server_id > 0) {
// server_id is expected to always be positive
__u32 key = usr.server_id;
__u32* real_pos = bpf_map_lookup_elem(&server_id_map, &key);
if (real_pos) {
// get a real position for the server id
key = *real_pos;
if (key != 0) {
pckt->real_index = key;
*dst = bpf_map_lookup_elem(&reals, &key);
if (!*dst) {
// fail to find a real server with the real pos, drop the packet
stable_rt_packets_stats->cid_unknown_real_dropped += 1;
return XDP_DROP;
}
// increment cid routed stats
stable_rt_packets_stats->cid_routed += 1;
}
} else {
// increment invalid server id stats
stable_rt_packets_stats->cid_invalid_server_id += 1;
stable_rt_packets_stats->ch_routed += 1;
}
} else {
// cannot get a server id , fallback to lru or ch
if (!usr.is_stable_rt_pkt) {
// invalid packet type
stable_rt_packets_stats->invalid_packet_type += 1;
}
stable_rt_packets_stats->ch_routed += 1;
}
}
#endif // of UDP_STABLE_ROUTING

__attribute__((__always_inline__)) static inline void
increment_quic_cid_version_stats(
struct lb_quic_packets_stats* quic_packets_stats,
Expand Down Expand Up @@ -889,6 +939,12 @@ process_packet(struct xdp_md* xdp, __u64 off, bool is_ipv6) {
}
}
}
#ifdef UDP_STABLE_ROUTING
if (pckt.flow.proto == IPPROTO_UDP &&
vip_info->flags & F_UDP_STABLE_ROUTING_VIP) {
process_udp_stable_routing(data, data_end, &dst, &pckt, is_ipv6);
}
#endif // UDP_STABLE_ROUTING

// save the original sport before making real selection, possibly changing its
// value.
Expand Down
11 changes: 11 additions & 0 deletions katran/lib/bpf/balancer_consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
// process a packet to figure out what to do with it
#define FURTHER_PROCESSING -1

// indicates no server id was found in the packet
#define STABLE_RT_NO_SERVER_ID 0

// 3FFF mask covers more fragments flag and fragment offset field.
// 65343 = 3FFF in BigEndian
#define PCKT_FRAGMENTED 65343
Expand Down Expand Up @@ -96,6 +99,8 @@

#define TPR_STATS_MAP_SIZE 1

#define STABLE_RT_STATS_MAP_SIZE 1

// for LRU's map in map we will support up to this number of cpus
#ifndef MAX_SUPPORTED_CPUS
#define MAX_SUPPORTED_CPUS 128
Expand Down Expand Up @@ -145,6 +150,8 @@
// use both src and dst port for the hash calculation for vips which normally
// wouldn't
#define F_HASH_SRC_DST_PORT (1 << 7)
// parse udp stable routing header to get server-id
#define F_UDP_STABLE_ROUTING_VIP (1 << 8)
// packet_description flags:
// the description has been created from icmp msg
#define F_ICMP (1 << 0)
Expand All @@ -164,6 +171,7 @@
// draft-ietf-quic-invariants-06
#define QUIC_LONG_HEADER 0x80
#define QUIC_SHORT_HEADER 0x00
#define STABLE_ROUTING_HEADER 0x80
// Long header packet types (with alignment of 8-bits for packet-type)
#define QUIC_CLIENT_INITIAL 0x00
#define QUIC_0RTT 0x10
Expand All @@ -176,6 +184,9 @@
#ifndef QUIC_MIN_CONNID_LEN
#define QUIC_MIN_CONNID_LEN 8
#endif

#define STABLE_RT_LEN 8

// explicitly version the connection id
#ifndef QUIC_CONNID_VERSION_V1
#define QUIC_CONNID_VERSION_V1 0x1
Expand Down
9 changes: 9 additions & 0 deletions katran/lib/bpf/balancer_maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ struct {
__uint(map_flags, NO_FLAGS);
} quic_stats_map SEC(".maps");

// map for udp stable routing stats
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, __u32);
__type(value, struct lb_stable_rt_packets_stats);
__uint(max_entries, STABLE_RT_STATS_MAP_SIZE);
__uint(map_flags, NO_FLAGS);
} stable_rt_stats SEC(".maps");

// map w/ per vip decap statistics
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
Expand Down
9 changes: 9 additions & 0 deletions katran/lib/bpf/balancer_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,13 @@ struct lb_tpr_packets_stats {
__u64 tcp_syn;
};

// struct for udp stable routing statistics counters
struct lb_stable_rt_packets_stats {
__u64 ch_routed;
__u64 cid_routed;
__u64 cid_invalid_server_id;
__u64 cid_unknown_real_dropped;
__u64 invalid_packet_type;
};

#endif // of _BALANCER_STRUCTS
46 changes: 46 additions & 0 deletions katran/lib/bpf/pckt_parsing.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ struct quic_parse_result {
bool is_initial;
};

struct stable_routing_header {
__u8 connection_id[STABLE_RT_LEN];
} __attribute__((__packed__));

struct udp_stable_rt_result {
__be32 server_id;
bool is_stable_rt_pkt;
};

__attribute__((__always_inline__)) static inline __u64 calc_offset(
bool is_ipv6,
bool is_icmp) {
Expand Down Expand Up @@ -418,4 +427,41 @@ parse_quic(
return result;
}

__attribute__((__always_inline__)) static inline struct udp_stable_rt_result
parse_udp_stable_rt_hdr(
void* data,
void* data_end,
bool is_ipv6,
struct packet_description* pckt) {
struct udp_stable_rt_result result = {
.server_id = STABLE_RT_NO_SERVER_ID, .is_stable_rt_pkt = false};

bool is_icmp = (pckt->flags & F_ICMP);
__u64 off = calc_offset(is_ipv6, is_icmp);
// offset points to the beginning of transport header (udp)
/* |PKT TYPE| */
if ((data + off + sizeof(struct udphdr) + sizeof(__u8)) > data_end) {
return result;
}

__u8* udp_data = data + off + sizeof(struct udphdr);
__u8* pkt_type = udp_data;
__u8* connId = NULL;
if ((*pkt_type & STABLE_ROUTING_HEADER) == STABLE_ROUTING_HEADER) {
// packet with stable routing header
if (udp_data + sizeof(struct stable_routing_header) > data_end) {
return result;
}
connId = ((struct stable_routing_header*)udp_data)->connection_id;
result.is_stable_rt_pkt = true;
}
if (!connId) {
return result;
}

// same as QUIC connId v2 schema
result.server_id = (connId[1] << 16) | (connId[2] << 8) | (connId[3]);
return result;
}

#endif // of __PCKT_PARSING_H
2 changes: 2 additions & 0 deletions katran/lib/testing/BpfTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ bool BpfTester::runBpfTesterFromFixtures(
if (config_.testData[i].routedThroughGlobalLru) {
packetsRoutedGlobalLruBefore = getGlobalLruRoutedPackets();
}
VLOG(2) << "Running test for pckt #" << pckt_num
<< " with description: " << config_.testData[i].description;
auto res = adapter_.testXdpProg(
progFd,
kTestRepeatCount,
Expand Down

0 comments on commit d2c4e38

Please sign in to comment.