Skip to content

Commit

Permalink
Adding IPSec ebpf tracker
Browse files Browse the repository at this point in the history
Signed-off-by: Mohamed Mahmoud <mmahmoud@redhat.com>
  • Loading branch information
msherif1234 committed Jan 31, 2025
1 parent b4122b0 commit 07aa040
Show file tree
Hide file tree
Showing 14 changed files with 328 additions and 6 deletions.
10 changes: 8 additions & 2 deletions .mk/bc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ define PROGRAMS
"tcp_rcv_kprobe":"kprobe",
"kfree_skb":"tracepoint",
"rh_network_events_monitoring":"kprobe",
"nf_nat_manip_pkt":"kprobe"
"nf_nat_manip_pkt":"kprobe",
"xfrm_input": "kprobe",
"xfrm_input": "kretprobe",
"xfrm_output": "kprobe",
"xfrm_output": "kretprobe"
}
endef

Expand All @@ -32,7 +36,9 @@ define MAPS
"dns_flows":"hash",
"global_counters":"per_cpu_array",
"filter_map":"lpm_trie",
"peer_filter_map":"lpm_trie"
"peer_filter_map":"lpm_trie",
"sk_buffs_ingress_map":"hash",
"sk_buffs_egress_map":"hash"
}
endef

Expand Down
1 change: 1 addition & 0 deletions bpf/configs.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ volatile const u16 dns_port = 0;
volatile const u8 enable_network_events_monitoring = 0;
volatile const u8 network_events_monitoring_groupid = 0;
volatile const u8 enable_pkt_translation_tracking = 0;
volatile const u8 enable_ipsec = 0;
#endif //__CONFIGS_H__
5 changes: 5 additions & 0 deletions bpf/flows.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
*/
#include "pkt_translation.h"

/*
* Defines ipsec tracker
*/
#include "ipsec.h"

// return 0 on success, 1 if capacity reached
static __always_inline int add_observed_intf(flow_metrics *value, pkt_info *pkt, u32 if_index,
u8 direction) {
Expand Down
205 changes: 205 additions & 0 deletions bpf/ipsec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* IPsec monitoring kretprobe eBPF hook.
*/

#ifndef __IPSEC_H__
#define __IPSEC_H__

#include "utils.h"

static inline int ipsec_lookup_and_update_flow(flow_id *id, bool flow_encrypted) {
additional_metrics *extra_metrics = bpf_map_lookup_elem(&additional_flow_metrics, id);
if (extra_metrics != NULL) {
extra_metrics->end_mono_time_ts = bpf_ktime_get_ns();
extra_metrics->flow_encrypted = flow_encrypted;
return 0;
}
return -1;
}

static inline int update_flow_with_ipsec_return(bool flow_encrypted, direction dir) {
u64 pid_tgid = bpf_get_current_pid_tgid();
u16 family = 0, flags = 0, eth_protocol = 0;
struct sk_buff *skb = NULL;
u8 dscp = 0, protocol = 0;
u32 tid = pid_tgid;
int ret = 0;
flow_id id;

if (dir == INGRESS) {
skb = bpf_map_lookup_elem(&sk_buffs_ingress_map, &tid);
} else {
skb = bpf_map_lookup_elem(&sk_buffs_egress_map, &tid);
}

if (!skb)
return 0;

__builtin_memset(&id, 0, sizeof(id));

// read L2 info
core_fill_in_l2(skb, &eth_protocol, &family);

// read L3 info
core_fill_in_l3(skb, &id, family, &protocol, &dscp);

// read L4 info
switch (protocol) {
case IPPROTO_TCP:
core_fill_in_tcp(skb, &id, &flags);
break;
case IPPROTO_UDP:
core_fill_in_udp(skb, &id);
break;
case IPPROTO_SCTP:
core_fill_in_sctp(skb, &id);
break;
case IPPROTO_ICMP:
core_fill_in_icmpv4(skb, &id);
break;
case IPPROTO_ICMPV6:
core_fill_in_icmpv6(skb, &id);
break;
default:
fill_in_others_protocol(&id, protocol);
}

// check if this packet need to be filtered if filtering feature is enabled
bool skip = check_and_do_flow_filtering(&id, flags, 0, eth_protocol, NULL, 0);
if (skip) {
return 0;
}

// update flow with ipsec info
ret = ipsec_lookup_and_update_flow(&id, flow_encrypted);
if (ret == 0) {
goto end;
}

u64 current_time = bpf_ktime_get_ns();
additional_metrics new_flow;
__builtin_memset(&new_flow, 0, sizeof(new_flow));
new_flow.start_mono_time_ts = current_time;
new_flow.end_mono_time_ts = current_time;
new_flow.eth_protocol = eth_protocol;
new_flow.flow_encrypted = flow_encrypted;
ret = bpf_map_update_elem(&additional_flow_metrics, &id, &new_flow, BPF_NOEXIST);
if (ret != 0) {
if (trace_messages && ret != -EEXIST) {
bpf_printk("error ipsec track creating flow %d\n", ret);
}
if (ret == -EEXIST) {
ret = ipsec_lookup_and_update_flow(&id, flow_encrypted);
if (trace_messages && ret != 0) {
bpf_printk("error ipsec track updating an existing flow %d\n", ret);
}
}
}
end:
if (dir == INGRESS) {
bpf_map_delete_elem(&sk_buffs_ingress_map, &tid);
} else {
bpf_map_delete_elem(&sk_buffs_egress_map, &tid);
}
return 0;
}

static inline int enter_xfrm_func(struct sk_buff *skb, direction dir) {
u64 pid_tgid = bpf_get_current_pid_tgid();
u16 family = 0, flags = 0, eth_protocol = 0;
u8 dscp = 0, protocol = 0;
u32 tid = pid_tgid;
flow_id id;
int ret = 0;

__builtin_memset(&id, 0, sizeof(id));

// read L2 info
core_fill_in_l2(skb, &eth_protocol, &family);

// read L3 info
core_fill_in_l3(skb, &id, family, &protocol, &dscp);

// read L4 info
switch (protocol) {
case IPPROTO_TCP:
core_fill_in_tcp(skb, &id, &flags);
break;
case IPPROTO_UDP:
core_fill_in_udp(skb, &id);
break;
case IPPROTO_SCTP:
core_fill_in_sctp(skb, &id);
break;
case IPPROTO_ICMP:
core_fill_in_icmpv4(skb, &id);
break;
case IPPROTO_ICMPV6:
core_fill_in_icmpv6(skb, &id);
break;
default:
fill_in_others_protocol(&id, protocol);
}

// check if this packet need to be filtered if filtering feature is enabled
bool skip = check_and_do_flow_filtering(&id, flags, 0, eth_protocol, NULL, 0);
if (skip) {
return 0;
}

if (dir == INGRESS) {
ret = bpf_map_update_elem(&sk_buffs_ingress_map, &tid, &skb, 0);
} else {
ret = bpf_map_update_elem(&sk_buffs_egress_map, &tid, &skb, 0);
}
if (ret != 0) {
if (trace_messages) {
bpf_printk("error updating dir: %d sk_buff map err: %d\n", dir, ret);
}
}
return 0;
}

SEC("kprobe/xfrm_input")
int BPF_KPROBE(xfrm_input_kprobe) {
if (do_sampling == 0 || enable_ipsec == 0) {
return 0;
}
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
if (!skb)
return 0;
return enter_xfrm_func(skb, INGRESS);
}

SEC("kretprobe/xfrm_input")
int BPF_KRETPROBE(xfrm_input_kretprobe) {
if (do_sampling == 0 || enable_ipsec == 0) {
return 0;
}
int xfrm_ret = PT_REGS_RC(ctx);
bool flow_encrypted = xfrm_ret == 0 ? 1 : 0;
return update_flow_with_ipsec_return(flow_encrypted, INGRESS);
}

SEC("kprobe/xfrm_output")
int BPF_KPROBE(xfrm_output_kprobe) {
if (do_sampling == 0 || enable_ipsec == 0) {
return 0;
}
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM2(ctx);
if (!skb)
return 0;
return enter_xfrm_func(skb, EGRESS);
}

SEC("kretprobe/xfrm_output")
int BPF_KRETPROBE(xfrm_output_kretprobe) {
if (do_sampling == 0 || enable_ipsec == 0) {
return 0;
}
int xfrm_ret = PT_REGS_RC(ctx);
bool flow_encrypted = xfrm_ret == 0 ? 1 : 0;
return update_flow_with_ipsec_return(flow_encrypted, EGRESS);
}

#endif /* __IPSEC_H__ */
20 changes: 20 additions & 0 deletions bpf/maps_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,24 @@ struct {
__uint(pinning, LIBBPF_PIN_BY_NAME);
} peer_filter_map SEC(".maps");

// HashMap to store ingress sk_buffs to be able to retrieve them from kretprobe hook
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1 << 20); // Will take around 64MB of space.
__type(key, u32);
__type(value, struct sk_buff *);
__uint(map_flags, BPF_F_NO_PREALLOC);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} sk_buffs_ingress_map SEC(".maps");

// HashMap to store egress sk_buffs to be able to retrieve them from kretprobe hook
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1 << 20); // Will take around 64MB of space.
__type(key, u32);
__type(value, struct sk_buff *);
__uint(map_flags, BPF_F_NO_PREALLOC);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} sk_buffs_egress_map SEC(".maps");

#endif //__MAPS_DEFINITION_H__
1 change: 1 addition & 0 deletions bpf/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ typedef struct additional_metrics_t {
} translated_flow;
u16 eth_protocol;
u8 network_events_idx;
bool flow_encrypted;
} additional_metrics;

// Force emitting enums/structs into the ELF
Expand Down
23 changes: 22 additions & 1 deletion pkg/ebpf/bpf_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified pkg/ebpf/bpf_arm64_bpfel.o
Binary file not shown.
Loading

0 comments on commit 07aa040

Please sign in to comment.