diff --git a/pping/pping_helpers.h b/pping/pping_helpers.h index 9d775b3..26e7019 100644 --- a/pping/pping_helpers.h +++ b/pping/pping_helpers.h @@ -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 { diff --git a/pping/pping_kern_tc.c b/pping/pping_kern_tc.c index 2df3032..92ee487 100644 --- a/pping/pping_kern_tc.c +++ b/pping/pping_kern_tc.c @@ -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 diff --git a/pping/pping_kern_xdp.c b/pping/pping_kern_xdp.c index 00fe8ad..8ea4374 100644 --- a/pping/pping_kern_xdp.c +++ b/pping/pping_kern_xdp.c @@ -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;