Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NETOBSERV-1965: WIP: eBPF packet translation tracker #438

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bpf/configs.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ volatile const u8 enable_flows_filtering = 0;
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_transformation_tracking = 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 @@ -51,6 +51,11 @@
*/
#include "network_events_monitoring.h"

/*
* Defines packets transformation tracker
*/
#include "pkt_transformation.h"

static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
// If sampling is defined, will only parse 1 out of "sampling" flows
if (sampling > 1 && (bpf_get_prandom_u32() % sampling) != 0) {
Expand Down
10 changes: 3 additions & 7 deletions bpf/flows_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@

#include "utils.h"

// remove the comment below to enable debug prints
//#define ENABLE_BPF_PRINTK
#ifdef ENABLE_BPF_PRINTK
#define BPF_PRINTK(fmt, args...) bpf_printk(fmt, ##args)
#else
#define BPF_PRINTK(fmt, args...)
#endif
#define BPF_PRINTK(fmt, args...) \
if (trace_messages) \
bpf_printk(fmt, ##args)

static __always_inline int is_zero_ip(u8 *ip, u8 len) {
for (int i = 0; i < len; i++) {
Expand Down
13 changes: 7 additions & 6 deletions bpf/headers/vmlinux_amd64.h
Original file line number Diff line number Diff line change
Expand Up @@ -22484,10 +22484,17 @@ union nf_conntrack_proto {

struct nf_ct_ext;

struct nf_conntrack_zone {
u16 id;
u8 flags;
u8 dir;
};

struct nf_conn {
struct nf_conntrack ct_general;
spinlock_t lock;
u32 timeout;
struct nf_conntrack_zone zone;
struct nf_conntrack_tuple_hash tuplehash[2];
long unsigned int status;
possible_net_t ct_net;
Expand All @@ -22499,12 +22506,6 @@ struct nf_conn {
union nf_conntrack_proto proto;
};

struct nf_conntrack_zone {
u16 id;
u8 flags;
u8 dir;
};

struct xt_action_param;

struct xt_mtchk_param;
Expand Down
13 changes: 7 additions & 6 deletions bpf/headers/vmlinux_arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -22582,10 +22582,17 @@ union nf_conntrack_proto {

struct nf_ct_ext;

struct nf_conntrack_zone {
u16 id;
u8 flags;
u8 dir;
};

struct nf_conn {
struct nf_conntrack ct_general;
spinlock_t lock;
u32 timeout;
struct nf_conntrack_zone zone;
struct nf_conntrack_tuple_hash tuplehash[2];
long unsigned int status;
possible_net_t ct_net;
Expand All @@ -22597,12 +22604,6 @@ struct nf_conn {
union nf_conntrack_proto proto;
};

struct nf_conntrack_zone {
u16 id;
u8 flags;
u8 dir;
};

struct icmphdr {
__u8 type;
__u8 code;
Expand Down
13 changes: 7 additions & 6 deletions bpf/headers/vmlinux_ppc64le.h
Original file line number Diff line number Diff line change
Expand Up @@ -67125,10 +67125,17 @@ union nf_conntrack_proto {

struct nf_ct_ext;

struct nf_conntrack_zone {
u16 id;
u8 flags;
u8 dir;
};

struct nf_conn {
struct nf_conntrack ct_general;
spinlock_t lock;
u32 timeout;
struct nf_conntrack_zone zone;
struct nf_conntrack_tuple_hash tuplehash[2];
long unsigned int status;
possible_net_t ct_net;
Expand Down Expand Up @@ -133097,12 +133104,6 @@ struct nf_hook_entries_rcu_head {
void *allocation;
};

struct nf_conntrack_zone {
u16 id;
u8 flags;
u8 dir;
};

struct nf_conntrack_tuple;

struct nf_ct_hook {
Expand Down
180 changes: 180 additions & 0 deletions bpf/pkt_transformation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Packets Transformations tracker eBPF hooks.
*/

#ifndef __PKT_TRANSFORMATION_H__
#define __PKT_TRANSFORMATION_H__

#include "utils.h"

#define s6_addr in6_u.u6_addr8

static inline void dump_xlated_flow(struct translated_flow_t *flow) {
BPF_PRINTK("zone_id %d sport %d dport %d icmpId %d\n", flow->zone_id, flow->sport, flow->dport,
flow->icmp_id);
int i;
for (i = 0; i < IP_MAX_LEN; i += 4) {
BPF_PRINTK("scrIP[%d]:%d.%d.%d.%d\n", i, flow->saddr[0 + i], flow->saddr[1 + i],
flow->saddr[2 + i], flow->saddr[3 + i]);
}
for (i = 0; i < IP_MAX_LEN; i += 4) {
BPF_PRINTK("dstIP[%d]:%d.%d.%d.%d\n", i, flow->daddr[0 + i], flow->daddr[1 + i],
flow->daddr[2 + i], flow->daddr[3 + i]);
}
}

static inline void parse_tuple(struct nf_conntrack_tuple *t, struct translated_flow_t *flow,
u16 zone_id, u16 family, bool invert) {
__builtin_memset(flow, 0, sizeof(*flow));
if (invert) {
flow->dport = bpf_ntohs(t->src.u.all);
flow->sport = bpf_ntohs(t->dst.u.all);

switch (family) {
case AF_INET:
__builtin_memcpy(flow->saddr, ip4in6, sizeof(ip4in6));
__builtin_memcpy(flow->daddr, ip4in6, sizeof(ip4in6));
bpf_probe_read(flow->daddr + sizeof(ip4in6), sizeof(u32), &t->src.u3.in.s_addr);
bpf_probe_read(flow->saddr + sizeof(ip4in6), sizeof(u32), &t->dst.u3.in.s_addr);
break;

case AF_INET6:
bpf_probe_read(flow->daddr, IP_MAX_LEN, &t->src.u3.in6.s6_addr);
bpf_probe_read(flow->saddr, IP_MAX_LEN, &t->dst.u3.in6.s6_addr);
break;
}
} else {
flow->dport = bpf_ntohs(t->dst.u.all);
flow->sport = bpf_ntohs(t->src.u.all);

switch (family) {
case AF_INET:
__builtin_memcpy(flow->saddr, ip4in6, sizeof(ip4in6));
__builtin_memcpy(flow->daddr, ip4in6, sizeof(ip4in6));
bpf_probe_read(flow->daddr + sizeof(ip4in6), sizeof(u32), &t->dst.u3.in.s_addr);
bpf_probe_read(flow->saddr + sizeof(ip4in6), sizeof(u32), &t->src.u3.in.s_addr);
break;

case AF_INET6:
bpf_probe_read(flow->daddr, IP_MAX_LEN, &t->dst.u3.in6.s6_addr);
bpf_probe_read(flow->saddr, IP_MAX_LEN, &t->src.u3.in6.s6_addr);
break;
}
}
flow->icmp_id = t->src.u.icmp.id;
flow->zone_id = zone_id;
dump_xlated_flow(flow);
}

static inline long translate_lookup_and_update_flow(flow_id *id, u16 flags,
struct nf_conntrack_tuple *orig_t,
struct nf_conntrack_tuple *reply_t, u64 len,
u16 zone_id, u16 family) {
long ret = 0;
u64 current_time = bpf_ktime_get_ns();
struct translated_flow_t orig;

parse_tuple(orig_t, &orig, zone_id, family, false);

// update id with original flow info
__builtin_memcpy(id->src_ip, orig.saddr, IP_MAX_LEN);
__builtin_memcpy(id->dst_ip, orig.daddr, IP_MAX_LEN);
id->src_port = orig.sport;
id->dst_port = orig.dport;

flow_metrics *aggregate_flow = bpf_map_lookup_elem(&aggregated_flows, id);
if (aggregate_flow != NULL) {
aggregate_flow->end_mono_time_ts = current_time;
parse_tuple(reply_t, &aggregate_flow->translated_flow, zone_id, family, true);
ret = bpf_map_update_elem(&aggregated_flows, id, aggregate_flow, BPF_EXIST);
if (trace_messages && ret != 0) {
bpf_printk("error packet translation updating flow %d\n", ret);
}
return ret;
}

// there is no matching flows so lets create new one and add the xlation
flow_metrics new_flow = {
.start_mono_time_ts = current_time,
.end_mono_time_ts = current_time,
.packets = 1,
.bytes = len,
.flags = flags,
};
parse_tuple(reply_t, &new_flow.translated_flow, zone_id, family, true);
ret = bpf_map_update_elem(&aggregated_flows, id, &new_flow, BPF_ANY);
if (trace_messages && ret != 0) {
bpf_printk("error packet translation creating new flow %d\n", ret);
}

return ret;
}

static inline int trace_nat_manip_pkt(struct nf_conn *ct, struct sk_buff *skb) {
struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
u16 family = 0, flags = 0, zone_id = 0;
u8 dscp = 0, protocol = 0;
long ret = 0;
u64 len = 0;
flow_id id;

if (!enable_pkt_transformation_tracking) {
return 0;
}
__builtin_memset(&id, 0, sizeof(id));

bpf_probe_read(&tuplehash, sizeof(tuplehash), &ct->tuplehash);

bpf_probe_read(&zone_id, sizeof(zone_id), &ct->zone.id);
bpf_probe_read(&zone_id, sizeof(zone_id), &ct->zone.id);

struct nf_conntrack_tuple *orig_tuple = &tuplehash[IP_CT_DIR_ORIGINAL].tuple;
struct nf_conntrack_tuple *reply_tuple = &tuplehash[IP_CT_DIR_REPLY].tuple;

len = BPF_CORE_READ(skb, len);
id.if_index = BPF_CORE_READ(skb, skb_iif);
// read L2 info
core_fill_in_l2(skb, &id, &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);
}

BPF_PRINTK("Xlat: protocol %d flags 0x%x family %d dscp %d\n", protocol, flags, family, dscp);

bpf_probe_read(&zone_id, sizeof(zone_id), &ct->zone.id);
ret =
translate_lookup_and_update_flow(&id, flags, orig_tuple, reply_tuple, len, zone_id, family);

return ret;
}

SEC("kprobe/nf_nat_manip_pkt")
int BPF_KPROBE(track_nat_manip_pkt) {
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
struct nf_conn *ct = (struct nf_conn *)PT_REGS_PARM2(ctx);

return trace_nat_manip_pkt(ct, skb);
}

#endif /* __PKT_TRANSFORMATION_H__ */
11 changes: 11 additions & 0 deletions bpf/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ typedef struct flow_metrics_t {
u64 flow_rtt;
u8 network_events_idx;
u8 network_events[MAX_NETWORK_EVENTS][MAX_EVENT_MD];
struct translated_flow_t {
u8 saddr[IP_MAX_LEN];
u8 daddr[IP_MAX_LEN];
u16 sport;
u16 dport;
u16 zone_id;
u8 icmp_id;
} __attribute__((packed)) translated_flow;
} __attribute__((packed)) flow_metrics;

// Force emitting struct pkt_drops into the ELF.
Expand Down Expand Up @@ -241,4 +249,7 @@ struct filter_value_t {
// Force emitting struct filter_value_t into the ELF.
const struct filter_value_t *unused9 __attribute__((unused));

// Force emitting struct translated_flow_t into the ELF.
const struct translated_flow_t *unused11 __attribute__((unused));

#endif /* __TYPES_H__ */
8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ require (
github.com/containernetworking/cni v1.1.2 // indirect
github.com/containernetworking/plugins v1.2.0 // indirect
github.com/coreos/go-iptables v0.6.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
Expand Down Expand Up @@ -109,11 +109,12 @@ require (
github.com/safchain/ethtool v0.3.1-0.20231027162144-83e5e0097c91 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/urfave/cli/v2 v2.2.0 // indirect
github.com/urfave/cli/v2 v2.27.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 // indirect
Expand Down Expand Up @@ -151,3 +152,6 @@ require (
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

// HACK
replace github.com/ovn-org/ovn-kubernetes/go-controller => github.com/npinaeva/ovn-kubernetes/go-controller v0.0.0-20241022150829-c03e72d94693
Loading
Loading