mirror of
https://github.com/xdp-project/bpf-examples.git
synced 2024-05-06 15:54:53 +00:00
pping: Add instant cleanup of flow state
Add parsing of TCP FIN/RST to determine if connection is being closed, and if so delete state directly from BPF programs. Only enabled on tc-program, as verifier is unhappy about in on XDP side for some reason. Signed-off-by: Simon Sundberg <simon.sundberg@kau.se>
This commit is contained in:
@ -30,6 +30,7 @@ struct parsing_context {
|
||||
void *data_end; //End of safe acessible area
|
||||
struct hdr_cursor nh; //Position to parse next
|
||||
__u32 pkt_len; //Full packet length (headers+data)
|
||||
bool is_egress; //Is packet on egress or ingress?
|
||||
};
|
||||
|
||||
// Timestamp map
|
||||
@ -41,6 +42,15 @@ struct {
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} ts_start SEC(".maps");
|
||||
|
||||
// Flow state map
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__type(key, struct network_tuple);
|
||||
__type(value, struct flow_state);
|
||||
__uint(max_entries, 16384);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} flow_state SEC(".maps");
|
||||
|
||||
/*
|
||||
* Maps an IPv4 address into an IPv6 address according to RFC 4291 sec 2.5.5.2
|
||||
*/
|
||||
@ -101,15 +111,18 @@ static int parse_tcp_ts(struct tcphdr *tcph, void *data_end, __u32 *tsval,
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to fetch an identifier for TCP packets, based on the TCP timestamp
|
||||
* option. If sucessful, identifier will be set to TSval if is_ingress, TSecr
|
||||
* otherwise, the port-members of saddr and daddr will be set the the TCP source
|
||||
* and dest, respectively, and 0 will be returned. On failure, -1 will be
|
||||
* returned.
|
||||
* returned. Additionally, if the connection is closing (FIN or RST flag), sets
|
||||
* flow_closing to true.
|
||||
*/
|
||||
static int parse_tcp_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
__be16 *sport, __be16 *dport, __u32 *identifier)
|
||||
static int parse_tcp_identifier(struct parsing_context *ctx, __be16 *sport,
|
||||
__be16 *dport, bool *flow_closing,
|
||||
__u32 *identifier)
|
||||
{
|
||||
__u32 tsval, tsecr;
|
||||
struct tcphdr *tcph;
|
||||
@ -117,8 +130,16 @@ static int parse_tcp_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
if (parse_tcphdr(&ctx->nh, ctx->data_end, &tcph) < 0)
|
||||
return -1;
|
||||
|
||||
// Check if connection is closing
|
||||
if (tcph->fin || tcph->rst) {
|
||||
*flow_closing = true;
|
||||
/* bpf_printk("Detected connection closing on %d\n", */
|
||||
/* ctx->is_egress); //Upsets verifier? */
|
||||
}
|
||||
|
||||
// Do not timestamp pure ACKs
|
||||
if (is_egress && ctx->nh.pos - ctx->data >= ctx->pkt_len && !tcph->syn)
|
||||
if (ctx->is_egress && ctx->nh.pos - ctx->data >= ctx->pkt_len &&
|
||||
!tcph->syn)
|
||||
return -1;
|
||||
|
||||
if (parse_tcp_ts(tcph, ctx->data_end, &tsval, &tsecr) < 0)
|
||||
@ -126,7 +147,7 @@ static int parse_tcp_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
|
||||
*sport = tcph->source;
|
||||
*dport = tcph->dest;
|
||||
*identifier = is_egress ? tsval : tsecr;
|
||||
*identifier = ctx->is_egress ? tsval : tsecr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -141,8 +162,8 @@ static int parse_tcp_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
* destination and source of packet, respectively), and identifier will be
|
||||
* set to the identifier of a response.
|
||||
*/
|
||||
static int parse_packet_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
struct packet_id *p_id)
|
||||
static int parse_packet_identifier(struct parsing_context *ctx,
|
||||
struct packet_id *p_id, bool *flow_closing)
|
||||
{
|
||||
int proto, err;
|
||||
struct ethhdr *eth;
|
||||
@ -151,7 +172,7 @@ static int parse_packet_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
struct flow_address *saddr, *daddr;
|
||||
|
||||
// Switch saddr <--> daddr on ingress to match egress
|
||||
if (is_egress) {
|
||||
if (ctx->is_egress) {
|
||||
saddr = &p_id->flow.saddr;
|
||||
daddr = &p_id->flow.daddr;
|
||||
} else {
|
||||
@ -174,8 +195,8 @@ static int parse_packet_identifier(struct parsing_context *ctx, bool is_egress,
|
||||
|
||||
// Add new protocols here
|
||||
if (proto == IPPROTO_TCP) {
|
||||
err = parse_tcp_identifier(ctx, is_egress, &saddr->port,
|
||||
&daddr->port, &p_id->identifier);
|
||||
err = parse_tcp_identifier(ctx, &saddr->port, &daddr->port,
|
||||
flow_closing, &p_id->identifier);
|
||||
if (err)
|
||||
return -1;
|
||||
} else {
|
||||
|
@ -11,16 +11,9 @@
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__type(key, struct network_tuple);
|
||||
__type(value, struct flow_state);
|
||||
__uint(max_entries, 16384);
|
||||
} flow_state SEC(".maps");
|
||||
|
||||
// TC-BFP for parsing packet identifier from egress traffic and add to map
|
||||
SEC(TCBPF_PROG_SEC)
|
||||
int tc_bpf_prog_egress(struct __sk_buff *skb)
|
||||
int pping_egress(struct __sk_buff *skb)
|
||||
{
|
||||
struct packet_id p_id = { 0 };
|
||||
__u64 p_ts;
|
||||
@ -29,13 +22,21 @@ int tc_bpf_prog_egress(struct __sk_buff *skb)
|
||||
.data_end = (void *)(long)skb->data_end,
|
||||
.pkt_len = skb->len,
|
||||
.nh = { .pos = pctx.data },
|
||||
.is_egress = true,
|
||||
};
|
||||
bool flow_closing = false;
|
||||
struct flow_state *f_state;
|
||||
struct flow_state new_state = { 0 };
|
||||
|
||||
if (parse_packet_identifier(&pctx, true, &p_id) < 0)
|
||||
if (parse_packet_identifier(&pctx, &p_id, &flow_closing) < 0)
|
||||
goto out;
|
||||
|
||||
// Delete flow and create no timestamp entry if flow is closing
|
||||
if (flow_closing) {
|
||||
bpf_map_delete_elem(&flow_state, &p_id.flow);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Check flow state
|
||||
f_state = bpf_map_lookup_elem(&flow_state, &p_id.flow);
|
||||
if (!f_state) { // No previous state - attempt to create it
|
||||
|
@ -15,7 +15,7 @@ struct {
|
||||
|
||||
// XDP program for parsing identifier in ingress traffic and check for match in map
|
||||
SEC(XDP_PROG_SEC)
|
||||
int xdp_prog_ingress(struct xdp_md *ctx)
|
||||
int pping_ingress(struct xdp_md *ctx)
|
||||
{
|
||||
struct packet_id p_id = { 0 };
|
||||
__u64 *p_ts;
|
||||
@ -25,11 +25,18 @@ int xdp_prog_ingress(struct xdp_md *ctx)
|
||||
.data_end = (void *)(long)ctx->data_end,
|
||||
.pkt_len = pctx.data_end - pctx.data,
|
||||
.nh = { .pos = pctx.data },
|
||||
.is_egress = false,
|
||||
};
|
||||
bool flow_closing = false;
|
||||
|
||||
if (parse_packet_identifier(&pctx, false, &p_id) < 0)
|
||||
if (parse_packet_identifier(&pctx, &p_id, &flow_closing) < 0)
|
||||
goto out;
|
||||
|
||||
/* // Delete flow, but allow final attempt at RTT calculation */
|
||||
/* if (flow_closing) // For some reason verifier is very unhappy about this */
|
||||
/* bpf_map_delete_elem(&flow_state, &p_id.flow); */
|
||||
|
||||
|
||||
p_ts = bpf_map_lookup_elem(&ts_start, &p_id);
|
||||
if (!p_ts)
|
||||
goto out;
|
||||
|
Reference in New Issue
Block a user