From 2d63d907d45815485e0064eabbac8e432f65bc17 Mon Sep 17 00:00:00 2001
From: "Mohamed S. Mahmoud" <mmahmoud@redhat.com>
Date: Fri, 23 Jun 2023 12:28:29 -0400
Subject: [PATCH] NETOBSERV-1103: optimize ebpf agent map memory and cpu usage
 (#140)

* Optimize ebpf agent map memory usage
- switch to use pointer to metric instead of metric
- manuall trigger GC after flow eviction complete

Signed-off-by: msherif1234 <mmahmoud@redhat.com>

* Fix memory and cpu scale issue work around in #133

following up on https://github.com/cilium/ebpf/issues/1063
it seems we have a way to fix resources issues

Signed-off-by: msherif1234 <mmahmoud@redhat.com>
(cherry picked from commit b9c9a035b25bd5b349071977aff0d7aebca40e75)

---------

Signed-off-by: msherif1234 <mmahmoud@redhat.com>
---
 bpf/flows.c                   |   1 -
 bpf/headers/bpf_core_read.h   | 484 ++++++++++++++++++++++++++++++++++
 pkg/agent/agent.go            |   6 +-
 pkg/agent/agent_test.go       |   4 +-
 pkg/agent/config.go           |   2 +
 pkg/ebpf/bpf_bpfeb.o          | Bin 22344 -> 27208 bytes
 pkg/ebpf/bpf_bpfel.o          | Bin 21568 -> 27280 bytes
 pkg/ebpf/tracer.go            |  31 +--
 pkg/exporter/ipfix.go         |   2 +-
 pkg/flow/tracer_map.go        |  19 +-
 pkg/flow/tracer_ringbuf.go    |  11 +-
 pkg/test/tracer_fake.go       |  10 +-
 scripts/update-bpf-headers.sh |   1 +
 13 files changed, 533 insertions(+), 38 deletions(-)
 create mode 100644 bpf/headers/bpf_core_read.h

diff --git a/bpf/flows.c b/bpf/flows.c
index a7c233f7..ba934557 100644
--- a/bpf/flows.c
+++ b/bpf/flows.c
@@ -13,7 +13,6 @@
             until an entry is available.
         4) When hash collision is detected, we send the new entry to userpace via ringbuffer.
 */
-#define BPF_NO_PRESERVE_ACCESS_INDEX
 #include <vmlinux.h>
 #include <bpf_helpers.h>
 
diff --git a/bpf/headers/bpf_core_read.h b/bpf/headers/bpf_core_read.h
new file mode 100644
index 00000000..496e6a8e
--- /dev/null
+++ b/bpf/headers/bpf_core_read.h
@@ -0,0 +1,484 @@
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+#ifndef __BPF_CORE_READ_H__
+#define __BPF_CORE_READ_H__
+
+/*
+ * enum bpf_field_info_kind is passed as a second argument into
+ * __builtin_preserve_field_info() built-in to get a specific aspect of
+ * a field, captured as a first argument. __builtin_preserve_field_info(field,
+ * info_kind) returns __u32 integer and produces BTF field relocation, which
+ * is understood and processed by libbpf during BPF object loading. See
+ * selftests/bpf for examples.
+ */
+enum bpf_field_info_kind {
+	BPF_FIELD_BYTE_OFFSET = 0,	/* field byte offset */
+	BPF_FIELD_BYTE_SIZE = 1,
+	BPF_FIELD_EXISTS = 2,		/* field existence in target kernel */
+	BPF_FIELD_SIGNED = 3,
+	BPF_FIELD_LSHIFT_U64 = 4,
+	BPF_FIELD_RSHIFT_U64 = 5,
+};
+
+/* second argument to __builtin_btf_type_id() built-in */
+enum bpf_type_id_kind {
+	BPF_TYPE_ID_LOCAL = 0,		/* BTF type ID in local program */
+	BPF_TYPE_ID_TARGET = 1,		/* BTF type ID in target kernel */
+};
+
+/* second argument to __builtin_preserve_type_info() built-in */
+enum bpf_type_info_kind {
+	BPF_TYPE_EXISTS = 0,		/* type existence in target kernel */
+	BPF_TYPE_SIZE = 1,		/* type size in target kernel */
+	BPF_TYPE_MATCHES = 2,		/* type match in target kernel */
+};
+
+/* second argument to __builtin_preserve_enum_value() built-in */
+enum bpf_enum_value_kind {
+	BPF_ENUMVAL_EXISTS = 0,		/* enum value existence in kernel */
+	BPF_ENUMVAL_VALUE = 1,		/* enum value value relocation */
+};
+
+#define __CORE_RELO(src, field, info)					      \
+	__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define __CORE_BITFIELD_PROBE_READ(dst, src, fld)			      \
+	bpf_probe_read_kernel(						      \
+			(void *)dst,				      \
+			__CORE_RELO(src, fld, BYTE_SIZE),		      \
+			(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
+#else
+/* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so
+ * for big-endian we need to adjust destination pointer accordingly, based on
+ * field byte size
+ */
+#define __CORE_BITFIELD_PROBE_READ(dst, src, fld)			      \
+	bpf_probe_read_kernel(						      \
+			(void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \
+			__CORE_RELO(src, fld, BYTE_SIZE),		      \
+			(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
+#endif
+
+/*
+ * Extract bitfield, identified by s->field, and return its value as u64.
+ * All this is done in relocatable manner, so bitfield changes such as
+ * signedness, bit size, offset changes, this will be handled automatically.
+ * This version of macro is using bpf_probe_read_kernel() to read underlying
+ * integer storage. Macro functions as an expression and its return type is
+ * bpf_probe_read_kernel()'s return value: 0, on success, <0 on error.
+ */
+#define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({			      \
+	unsigned long long val = 0;					      \
+									      \
+	__CORE_BITFIELD_PROBE_READ(&val, s, field);			      \
+	val <<= __CORE_RELO(s, field, LSHIFT_U64);			      \
+	if (__CORE_RELO(s, field, SIGNED))				      \
+		val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64);  \
+	else								      \
+		val = val >> __CORE_RELO(s, field, RSHIFT_U64);		      \
+	val;								      \
+})
+
+/*
+ * Extract bitfield, identified by s->field, and return its value as u64.
+ * This version of macro is using direct memory reads and should be used from
+ * BPF program types that support such functionality (e.g., typed raw
+ * tracepoints).
+ */
+#define BPF_CORE_READ_BITFIELD(s, field) ({				      \
+	const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
+	unsigned long long val;						      \
+									      \
+	/* This is a so-called barrier_var() operation that makes specified   \
+	 * variable "a black box" for optimizing compiler.		      \
+	 * It forces compiler to perform BYTE_OFFSET relocation on p and use  \
+	 * its calculated value in the switch below, instead of applying      \
+	 * the same relocation 4 times for each individual memory load.       \
+	 */								      \
+	asm volatile("" : "=r"(p) : "0"(p));				      \
+									      \
+	switch (__CORE_RELO(s, field, BYTE_SIZE)) {			      \
+	case 1: val = *(const unsigned char *)p; break;			      \
+	case 2: val = *(const unsigned short *)p; break;		      \
+	case 4: val = *(const unsigned int *)p; break;			      \
+	case 8: val = *(const unsigned long long *)p; break;		      \
+	}								      \
+	val <<= __CORE_RELO(s, field, LSHIFT_U64);			      \
+	if (__CORE_RELO(s, field, SIGNED))				      \
+		val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64);  \
+	else								      \
+		val = val >> __CORE_RELO(s, field, RSHIFT_U64);		      \
+	val;								      \
+})
+
+#define ___bpf_field_ref1(field)	(field)
+#define ___bpf_field_ref2(type, field)	(((typeof(type) *)0)->field)
+#define ___bpf_field_ref(args...)					    \
+	___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args)
+
+/*
+ * Convenience macro to check that field actually exists in target kernel's.
+ * Returns:
+ *    1, if matching field is present in target kernel;
+ *    0, if no matching field found.
+ *
+ * Supports two forms:
+ *   - field reference through variable access:
+ *     bpf_core_field_exists(p->my_field);
+ *   - field reference through type and field names:
+ *     bpf_core_field_exists(struct my_type, my_field).
+ */
+#define bpf_core_field_exists(field...)					    \
+	__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_EXISTS)
+
+/*
+ * Convenience macro to get the byte size of a field. Works for integers,
+ * struct/unions, pointers, arrays, and enums.
+ *
+ * Supports two forms:
+ *   - field reference through variable access:
+ *     bpf_core_field_size(p->my_field);
+ *   - field reference through type and field names:
+ *     bpf_core_field_size(struct my_type, my_field).
+ */
+#define bpf_core_field_size(field...)					    \
+	__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_SIZE)
+
+/*
+ * Convenience macro to get field's byte offset.
+ *
+ * Supports two forms:
+ *   - field reference through variable access:
+ *     bpf_core_field_offset(p->my_field);
+ *   - field reference through type and field names:
+ *     bpf_core_field_offset(struct my_type, my_field).
+ */
+#define bpf_core_field_offset(field...)					    \
+	__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_OFFSET)
+
+/*
+ * Convenience macro to get BTF type ID of a specified type, using a local BTF
+ * information. Return 32-bit unsigned integer with type ID from program's own
+ * BTF. Always succeeds.
+ */
+#define bpf_core_type_id_local(type)					    \
+	__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)
+
+/*
+ * Convenience macro to get BTF type ID of a target kernel's type that matches
+ * specified local type.
+ * Returns:
+ *    - valid 32-bit unsigned type ID in kernel BTF;
+ *    - 0, if no matching type was found in a target kernel BTF.
+ */
+#define bpf_core_type_id_kernel(type)					    \
+	__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)
+
+/*
+ * Convenience macro to check that provided named type
+ * (struct/union/enum/typedef) exists in a target kernel.
+ * Returns:
+ *    1, if such type is present in target kernel's BTF;
+ *    0, if no matching type is found.
+ */
+#define bpf_core_type_exists(type)					    \
+	__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
+
+/*
+ * Convenience macro to check that provided named type
+ * (struct/union/enum/typedef) "matches" that in a target kernel.
+ * Returns:
+ *    1, if the type matches in the target kernel's BTF;
+ *    0, if the type does not match any in the target kernel
+ */
+#define bpf_core_type_matches(type)					    \
+	__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES)
+
+/*
+ * Convenience macro to get the byte size of a provided named type
+ * (struct/union/enum/typedef) in a target kernel.
+ * Returns:
+ *    >= 0 size (in bytes), if type is present in target kernel's BTF;
+ *    0, if no matching type is found.
+ */
+#define bpf_core_type_size(type)					    \
+	__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)
+
+/*
+ * Convenience macro to check that provided enumerator value is defined in
+ * a target kernel.
+ * Returns:
+ *    1, if specified enum type and its enumerator value are present in target
+ *    kernel's BTF;
+ *    0, if no matching enum and/or enum value within that enum is found.
+ */
+#define bpf_core_enum_value_exists(enum_type, enum_value)		    \
+	__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)
+
+/*
+ * Convenience macro to get the integer value of an enumerator value in
+ * a target kernel.
+ * Returns:
+ *    64-bit value, if specified enum type and its enumerator value are
+ *    present in target kernel's BTF;
+ *    0, if no matching enum and/or enum value within that enum is found.
+ */
+#define bpf_core_enum_value(enum_type, enum_value)			    \
+	__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)
+
+/*
+ * bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures
+ * offset relocation for source address using __builtin_preserve_access_index()
+ * built-in, provided by Clang.
+ *
+ * __builtin_preserve_access_index() takes as an argument an expression of
+ * taking an address of a field within struct/union. It makes compiler emit
+ * a relocation, which records BTF type ID describing root struct/union and an
+ * accessor string which describes exact embedded field that was used to take
+ * an address. See detailed description of this relocation format and
+ * semantics in comments to struct bpf_field_reloc in libbpf_internal.h.
+ *
+ * This relocation allows libbpf to adjust BPF instruction to use correct
+ * actual field offset, based on target kernel BTF type that matches original
+ * (local) BTF, used to record relocation.
+ */
+#define bpf_core_read(dst, sz, src)					    \
+	bpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src))
+
+/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */
+#define bpf_core_read_user(dst, sz, src)				    \
+	bpf_probe_read_user(dst, sz, (const void *)__builtin_preserve_access_index(src))
+/*
+ * bpf_core_read_str() is a thin wrapper around bpf_probe_read_str()
+ * additionally emitting BPF CO-RE field relocation for specified source
+ * argument.
+ */
+#define bpf_core_read_str(dst, sz, src)					    \
+	bpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
+
+/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */
+#define bpf_core_read_user_str(dst, sz, src)				    \
+	bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
+
+#define ___concat(a, b) a ## b
+#define ___apply(fn, n) ___concat(fn, n)
+#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N
+
+/*
+ * return number of provided arguments; used for switch-based variadic macro
+ * definitions (see ___last, ___arrow, etc below)
+ */
+#define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+/*
+ * return 0 if no arguments are passed, N - otherwise; used for
+ * recursively-defined macros to specify termination (0) case, and generic
+ * (N) case (e.g., ___read_ptrs, ___core_read)
+ */
+#define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)
+
+#define ___last1(x) x
+#define ___last2(a, x) x
+#define ___last3(a, b, x) x
+#define ___last4(a, b, c, x) x
+#define ___last5(a, b, c, d, x) x
+#define ___last6(a, b, c, d, e, x) x
+#define ___last7(a, b, c, d, e, f, x) x
+#define ___last8(a, b, c, d, e, f, g, x) x
+#define ___last9(a, b, c, d, e, f, g, h, x) x
+#define ___last10(a, b, c, d, e, f, g, h, i, x) x
+#define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__)
+
+#define ___nolast2(a, _) a
+#define ___nolast3(a, b, _) a, b
+#define ___nolast4(a, b, c, _) a, b, c
+#define ___nolast5(a, b, c, d, _) a, b, c, d
+#define ___nolast6(a, b, c, d, e, _) a, b, c, d, e
+#define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f
+#define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g
+#define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h
+#define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i
+#define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__)
+
+#define ___arrow1(a) a
+#define ___arrow2(a, b) a->b
+#define ___arrow3(a, b, c) a->b->c
+#define ___arrow4(a, b, c, d) a->b->c->d
+#define ___arrow5(a, b, c, d, e) a->b->c->d->e
+#define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f
+#define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g
+#define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h
+#define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i
+#define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j
+#define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__)
+
+#define ___type(...) typeof(___arrow(__VA_ARGS__))
+
+#define ___read(read_fn, dst, src_type, src, accessor)			    \
+	read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)
+
+/* "recursively" read a sequence of inner pointers using local __t var */
+#define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a);
+#define ___rd_last(fn, ...)						    \
+	___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));
+#define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__)
+#define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
+#define ___read_ptrs(fn, src, ...)					    \
+	___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__)
+
+#define ___core_read0(fn, fn_ptr, dst, src, a)				    \
+	___read(fn, dst, ___type(src), src, a);
+#define ___core_readN(fn, fn_ptr, dst, src, ...)			    \
+	___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__))		    \
+	___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t,	    \
+		___last(__VA_ARGS__));
+#define ___core_read(fn, fn_ptr, dst, src, a, ...)			    \
+	___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst,	    \
+						      src, a, ##__VA_ARGS__)
+
+/*
+ * BPF_CORE_READ_INTO() is a more performance-conscious variant of
+ * BPF_CORE_READ(), in which final field is read into user-provided storage.
+ * See BPF_CORE_READ() below for more details on general usage.
+ */
+#define BPF_CORE_READ_INTO(dst, src, a, ...) ({				    \
+	___core_read(bpf_core_read, bpf_core_read,			    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/*
+ * Variant of BPF_CORE_READ_INTO() for reading from user-space memory.
+ *
+ * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.
+ */
+#define BPF_CORE_READ_USER_INTO(dst, src, a, ...) ({			    \
+	___core_read(bpf_core_read_user, bpf_core_read_user,		    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/* Non-CO-RE variant of BPF_CORE_READ_INTO() */
+#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({			    \
+	___core_read(bpf_probe_read, bpf_probe_read,			    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/* Non-CO-RE variant of BPF_CORE_READ_USER_INTO().
+ *
+ * As no CO-RE relocations are emitted, source types can be arbitrary and are
+ * not restricted to kernel types only.
+ */
+#define BPF_PROBE_READ_USER_INTO(dst, src, a, ...) ({			    \
+	___core_read(bpf_probe_read_user, bpf_probe_read_user,		    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/*
+ * BPF_CORE_READ_STR_INTO() does same "pointer chasing" as
+ * BPF_CORE_READ() for intermediate pointers, but then executes (and returns
+ * corresponding error code) bpf_core_read_str() for final string read.
+ */
+#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({			    \
+	___core_read(bpf_core_read_str, bpf_core_read,			    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/*
+ * Variant of BPF_CORE_READ_STR_INTO() for reading from user-space memory.
+ *
+ * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.
+ */
+#define BPF_CORE_READ_USER_STR_INTO(dst, src, a, ...) ({		    \
+	___core_read(bpf_core_read_user_str, bpf_core_read_user,	    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */
+#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({			    \
+	___core_read(bpf_probe_read_str, bpf_probe_read,		    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/*
+ * Non-CO-RE variant of BPF_CORE_READ_USER_STR_INTO().
+ *
+ * As no CO-RE relocations are emitted, source types can be arbitrary and are
+ * not restricted to kernel types only.
+ */
+#define BPF_PROBE_READ_USER_STR_INTO(dst, src, a, ...) ({		    \
+	___core_read(bpf_probe_read_user_str, bpf_probe_read_user,	    \
+		     dst, (src), a, ##__VA_ARGS__)			    \
+})
+
+/*
+ * BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially
+ * when there are few pointer chasing steps.
+ * E.g., what in non-BPF world (or in BPF w/ BCC) would be something like:
+ *	int x = s->a.b.c->d.e->f->g;
+ * can be succinctly achieved using BPF_CORE_READ as:
+ *	int x = BPF_CORE_READ(s, a.b.c, d.e, f, g);
+ *
+ * BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF
+ * CO-RE relocatable bpf_probe_read_kernel() wrapper) calls, logically
+ * equivalent to:
+ * 1. const void *__t = s->a.b.c;
+ * 2. __t = __t->d.e;
+ * 3. __t = __t->f;
+ * 4. return __t->g;
+ *
+ * Equivalence is logical, because there is a heavy type casting/preservation
+ * involved, as well as all the reads are happening through
+ * bpf_probe_read_kernel() calls using __builtin_preserve_access_index() to
+ * emit CO-RE relocations.
+ *
+ * N.B. Only up to 9 "field accessors" are supported, which should be more
+ * than enough for any practical purpose.
+ */
+#define BPF_CORE_READ(src, a, ...) ({					    \
+	___type((src), a, ##__VA_ARGS__) __r;				    \
+	BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__);		    \
+	__r;								    \
+})
+
+/*
+ * Variant of BPF_CORE_READ() for reading from user-space memory.
+ *
+ * NOTE: all the source types involved are still *kernel types* and need to
+ * exist in kernel (or kernel module) BTF, otherwise CO-RE relocation will
+ * fail. Custom user types are not relocatable with CO-RE.
+ * The typical situation in which BPF_CORE_READ_USER() might be used is to
+ * read kernel UAPI types from the user-space memory passed in as a syscall
+ * input argument.
+ */
+#define BPF_CORE_READ_USER(src, a, ...) ({				    \
+	___type((src), a, ##__VA_ARGS__) __r;				    \
+	BPF_CORE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__);		    \
+	__r;								    \
+})
+
+/* Non-CO-RE variant of BPF_CORE_READ() */
+#define BPF_PROBE_READ(src, a, ...) ({					    \
+	___type((src), a, ##__VA_ARGS__) __r;				    \
+	BPF_PROBE_READ_INTO(&__r, (src), a, ##__VA_ARGS__);		    \
+	__r;								    \
+})
+
+/*
+ * Non-CO-RE variant of BPF_CORE_READ_USER().
+ *
+ * As no CO-RE relocations are emitted, source types can be arbitrary and are
+ * not restricted to kernel types only.
+ */
+#define BPF_PROBE_READ_USER(src, a, ...) ({				    \
+	___type((src), a, ##__VA_ARGS__) __r;				    \
+	BPF_PROBE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__);	    \
+	__r;								    \
+})
+
+#endif
+
diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go
index e2b77155..efd44c82 100644
--- a/pkg/agent/agent.go
+++ b/pkg/agent/agent.go
@@ -78,7 +78,7 @@ type ebpfFlowFetcher interface {
 	io.Closer
 	Register(iface ifaces.Interface) error
 
-	LookupAndDeleteMap() map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics
+	LookupAndDeleteMap() map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics
 	ReadRingBuf() (ringbuf.Record, error)
 }
 
@@ -352,8 +352,8 @@ func (f *Flows) buildAndStartPipeline(ctx context.Context) (*node.Terminal[[]*fl
 	}
 
 	alog.Debug("connecting flows' processing graph")
-	mapTracer := node.AsStart(f.mapTracer.TraceLoop(ctx))
-	rbTracer := node.AsStart(f.rbTracer.TraceLoop(ctx))
+	mapTracer := node.AsStart(f.mapTracer.TraceLoop(ctx, f.cfg.EnableGC))
+	rbTracer := node.AsStart(f.rbTracer.TraceLoop(ctx, f.cfg.EnableGC))
 
 	accounter := node.AsMiddle(f.accounter.Account,
 		node.ChannelBufferLen(f.cfg.BuffersLength))
diff --git a/pkg/agent/agent_test.go b/pkg/agent/agent_test.go
index a8818ab9..1cf3a1ff 100644
--- a/pkg/agent/agent_test.go
+++ b/pkg/agent/agent_test.go
@@ -185,8 +185,8 @@ func testAgent(t *testing.T, cfg *Config) *test.ExporterFake {
 	now := uint64(monotime.Now())
 	key1Metrics := ebpf.BpfFlowMetrics{Packets: 3, Bytes: 44, StartMonoTimeTs: now + 1000, EndMonoTimeTs: now + 1_000_000_000}
 
-	ebpfTracer.AppendLookupResults(map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics{
-		key1: key1Metrics,
+	ebpfTracer.AppendLookupResults(map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics{
+		key1: &key1Metrics,
 	})
 	return export
 }
diff --git a/pkg/agent/config.go b/pkg/agent/config.go
index c9e9d913..6dfb49b2 100644
--- a/pkg/agent/config.go
+++ b/pkg/agent/config.go
@@ -136,4 +136,6 @@ type Config struct {
 	KafkaSASLClientSecretPath string `env:"KAFKA_SASL_CLIENT_SECRET_PATH"`
 	// ProfilePort sets the listening port for Go's Pprof tool. If it is not set, profile is disabled
 	ProfilePort int `env:"PROFILE_PORT"`
+	// EnableGC enables golang garbage collection run at the end of every map eviction, default is true
+	EnableGC bool `env:"ENABLE_GARBAGE_COLLECTION" envDefault:"true"`
 }
diff --git a/pkg/ebpf/bpf_bpfeb.o b/pkg/ebpf/bpf_bpfeb.o
index d844353d9a0b367e85237787e1313b1b601b1c01..f3dd6b1ea09dea6751857a74838cac9ded0401a6 100644
GIT binary patch
literal 27208
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

literal 22344
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
GO8@|}%0I9G

diff --git a/pkg/ebpf/bpf_bpfel.o b/pkg/ebpf/bpf_bpfel.o
index 75c4ad1b1b0fbd9c97adbcf8009bb3811e575f2c..b6095610414e142b585363b87c85ed31fa4fe8f5 100644
GIT binary patch
literal 27280
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

delta 6581
zcmbPmmGQs|#t9ls2mB{$buccSxVgQ43KIhZ14CgWD~Mt!mOA$z#3*cJ0Z|OaQfHxj
zW+?v*ln>U%P%L#C%4dYipMvtiT!vz)lTbbfSfE(yD3s3$;nzzYg9@-g1f&i_`Rq{s
z5h$Mv%0CX}b3^$j!2HZc9x#8u5SU`P!^FTKz`($et#tq_FUsh{&~}%BA(U|y1IQ`c
z*%%l=PL|#dv4>%QBSa%RBLjmH0|SHZM3>3cO!t_Yq$Wo*`!O}iO<v9HXVNSVR#j~E
z8EoqQC15TCI|~EDg8%>j@1F$W?}r-ND!{;CGuf7<v|a}sUaSnQU<KQmAhu((+zf1a
z1Y8}6QLVKAY+qrMDu~NataT5{SAp{HLix&2{v9YE<P`>n;(D#yPyt1#f?H6&0+fFf
z%9n@oZ$SBSQ2uo&Ulz*02Ib2@`B$NQX(;~+lrIJ5*B5JDh6+f61&XyULHQC;{zWJs
z8p2u^pnNf?{COx}2g-j6<?BNE&!BuQDE~2(uMOhYGZbq*feL7V1Q?379zyw=Q2rw*
zUk%E?59O;v`46Cc6Da>Jly3^<zk~9Pp#0ZRzA*y>Lly%=vDO=?fB{s&ODNwE%6|pr
z>p}U?p?rNP{{@8KECS)<NQ0XL*e@~)g3>qx14HGq8DLF`iIa^u<Lj9~NuGfrorwXQ
z2?`-x27hR#DP)A?@^nV1JTo}eGWbJW$N&-tWh#G2B4Q|HhLjrV%uw}AkW#}Rk_s6L
znIQQ9W}kB*3nZ8OJAu8x0LpA2H|&RaiJ_bYl52|{AQmHwgVIT{1M}o=VOcJafnbLi
zO}@qHCIxpFk~=}^+Fx<<EiN^w#AJwV{7`BCA_#wf%VsHVaVE}0D7SgD6|VxPp%1v=
z5M>Sq7Z9S%j0_-0vofTCmF*V>Qw;3P3=AMw>nbNt?iMp;17&Fj#>svXQuQz;;h@kI
zVqg$uHf3NCVqgF(VParFkrxEX8!|8mGBCi(u5gg&LFzzWWME(j2iYjVz_6VeT57OD
z=uof&85p)hVu4{h16aJCAru<VAOVox{g6Dw5DxN)2-G1g3=E=dj9^cI90rO8I3MJ2
z1_lNceT)nY<!q36_J;;&C^JYG#5|Cj{lWU`85ocyK%Vdq1~~&&9F$Z*Ap|lalvxn0
z03~EtK<fFx;vfftQZ$M@2S^@LD}dxd5e}BO0|gn#B?=$~ATL8)=m7E&H1<FiGdO_c
zLGFggH!v_Tq%tZ_&X$n3gp_ik%-o=OVGv~&VX$HVMHC}L3j+fKD+8nu16#+y08R^_
z>PJ^uY;v}wJSQYOu`=*(R+gN|$n}JSfdPaigf{P!;$meCoqSSWnK5kgTY2xvALK>U
z()hsf#sewIz#fLU3e03+0wvoOe3PA&gX%Z&F))CN0}CbyeTEU7av1jWF))CNmE(}`
z;(?SwVEtT>@(Il51SJGlNLcfM$}v#jgJl>PxGbOy1_lOBkP<%-!N9<04oOxZ*~ypH
zMe9K!0g613k7J=~tf6XBAbduUxg20$fwVDzVuQh!fq?;}4}>!z>i9r$1yT!E#lXPi
z2xTxZFmQotk|L-&P~1V))q|8UxqwIr=Hg{wV5ovBbcQ+vBE`Vu4rPE0^k86MXcA;#
zU}9ikiDY14m>|f&0P+M#$z(wW22fRXfsuh>Hq<OPRI|819$;Vq+Yj-P7t}|fqG>Ty
zlQ+mT1P1#YrVbSPJD}=(5o$mz6m_5&I}cUo50YhIV0b3T0J4;y0aRT<i%)PN?g~`^
z${(Ic?AL;m`!tp6KMFE{$}fJ945(=VqCqiW31UD!Xai+~0>g&^lA=I<@?&5CTL*G?
z00RSqJp%&+$ZbCb!BGn~6C?)G4l<JwlJLQWK0k!LSzqfO^JF1Cqsg9n8zy@iNKUrV
zSDf5zAUU~8UwQLF{QyQVC*9C;a<hT_<l~0MoBtWcF-}g@m!15;Sb1`@f%0S{6WPiC
z3>7DrnDlLCH_c(4e92aH@&l{6laE>pPtLODo;=^01H@)7D9)IC&{~|iv?v`+rzWR@
z=*jIij+4V}ttRW)nN7ZFXFIvf!J8>FW%2=sHo5t)85uw&2gnPcU;yDe91IK+;P&a{
zG)Fbj6`~9bpgOz)l1)J>8T2MEbd;%o!2+%-K((eQGXn$b3l;`XW(I~1uo4CakT|$V
z+`$Z2H<g)zf%5<}1E>)Kk_Yj{4={r>FN`mJfSCc58DV_m1I(bZ3Tz%oJxCrD9rZ8;
zh6k7#3P5qm%)kIr0I~p7nt|kRGBYq}o?&K~0F~!vVPH_bz|61!$~R?UU|_w&%<urp
zk7r?Eka)n%@B+&30@V{C%nUz}_?#i&ny4P^qTL_^5||kh7$H9X3gV|QGaP{O4Otl&
zBr=#8ZXof+GME`2K>3NR3=EtF%;0PZa&RXr1B3h$CI$ge8=0AbVH-$(1rvh;lz)?z
zfq``g6N3R$J;Xv`HU<XPJxmN9XbL)@d|#0K7AA%XP(I9n1yDXr{|6|)5v2YA6N3ZD
zlgtbZmqGj^ObipCd{uS^2Bi~B3^VGH1Y}MyF|2^{VHRwF@&niz7+B9RF<gN1C$cjz
z$lhRLxPinMzQM%s0LtG1lE1^m@B)c1e20nQ1C)QCoq<8-0uw|14<rGh3rq|GERYak
z;b35pxx&OCfy5WO!o*+z<!f><Fo->1Vz7YnT{##SINvZcL_qoADBxgb$bj;}QNY8@
zPyywGLsWvfo}mFM(9FTWz$(Mc&;V+gFf%Y52Jsb`85%&nEM^7<W=;kMB^73d4kW&e
z3NynDC?9Gd!vZK@my>~kRfCz~1e6aBF%xEn3rKunlX_-`8&CmokXbM@JV4?LTQD=c
zfbzjXro+te0f{f9!_2_Jjuc`B%nSlZd?5p71`Q}59AY-i3<gj>IK=ATFf({S1#&qV
z7&vDzGc<r|J!S@mO`Hr25<i$3I-vYZoD2*?f0!9&K=~kf!5_>FJD_}Mk-=~P%KyO0
zz@Wmz!f*r1ci>`R;1pnCcmU-maWOE|D~hl%7;r*-(80yPATPnfPypqF6oBLpK>09v
z11^aA%^>v(EDQlqK1g0&f`uUhi4QU_0m_G|FM#rIb1~F2XvwfJC~%`1XaVJe3<MeQ
z0?LQ^@B@@D!p*=SqQb%;!2{8s%gw;RtHHuxfW(*4U}128@~4C39atDDp!^Hm^$ZM(
z0W1s+P=Qa}3=Gl{EDRH%{0rO=c@AEP1%f;b3?daQ3<gksDh~q#Zw(8B1(aXQ!@wXo
zg@qvijUNH!&j-oRU}0#0@^97iFfhn1VPWWi3Ggs5$Sh%Dm;mMf<zZk@Ucth!1Imx)
zWnd6o!@_U?$}i((U=ZEF!f*qP{{YIL1Crmu!oUHlc$gU&zVI?INF8Be_#p)GP`w}@
z1B3ht7KRQ{h=3&@0|W0F7KQ~-ehNtA9To;q4F)P&FY_@lFuh=8I02P^!N<TL`Gt|;
z1`?n53nRk=C|{1BfkE*HBf|$IzWfhHh93}qJwq5s!5>Bj4l#%WKz#W>j0_S`eh)tb
z1Fr=mg8>p>(1MX60Lov*&%hwzz{oHI$_J_Ev|wa70Oel*$@?%ebcjRD|HjY2AW*@`
zFayl5XJCK{tN;rzFbD`RFbFg-GVDO(pMdhUK=K`o3^&mDFQ9xEko*Kjh7V9aEYS)`
zKpX%IK?4vURQ|^aFfd3PFfllQ1eh5ZKzv>UCWZhge+Ee2hlwEpiO=i9#83d`UlL$o
zkQ8BJXh7ogiZC&BK>08S9DwpU1Q{4)Gng1INH8!2gW?n<z?Z?qa099Urr`&a4^9Ie
zObnpb3#?ZG($~btz`*kd(SQN*S^uz1E|gN7%oAY42}&~{v*t_=3=pqx0XM#xz$ptP
z3d536aSu@Q4<^XK!0-tw?f`BJA|y1R;-H!bA<Dqe&j70bnZPL(Bpv~74>K@qhNw4U
zC;&BYK{8M*3HA#UxIl&qfvHf428M#kl7Z@;f>0hP%Yvn$#4k|WgMotq)RqPbff~3V
zdNou%D93^LFuZ$mXP|z4DO47e7+^9WIu$AoigOSjhTWjzpzH<{1JMdlaZnV2_%ICa
zH8C)O6CX?rM8ATlk78H>b0<iYfq|h1A_2}WP$4iC3l)EXrrsPX{sT>%b8=#kc;X|d
ztOH~O4r~&LsDX+{pot4YqX3kYLF!=G7pfkVWMN_;dhuk#AaSKzP+3p{2Z_S4K2-dM
z#N<ao+ZgR9&kWX=yaevvLi+e1g|I|0W%9#damL)qKZBL)LBn;RS`#D>G6OVR2dZO`
z`Jg%m#s{^$L3Ij@4;n!QRS_^gNI$4bfbl`<K~(^Z4^j^*;h}sba3TT~=}-Z1(;ifW
z!}uzb_l79fn?T(T$|#_Yz5@~;G~nlh#0T~8Q;_(eWD3gwApIaGf*KYe8$cNa6a-VC
z>Op*vlNTWIwHX-f7}g*OfcyYzdB6++@sFU%gL*+Ad60!Vo9Bi;=1_-piXgpsQ1?y)
z+(|<4bqsa&jSciRv!`$})*D$e_&7Nk#~XraLpW^#5jF<XhVkZ5E|fMjXUHrt$;>l@
z2tz4jFl`ub2&RqW4NW1^#wHA<d8NgvDaKGfgfcQ_@R^*KsyTUnY8s1iys^P##x%dl
z0cjGPv!LB>#mR+f_KXaZH>R00F*r|tm1f82Fj+I*o@s;g<g9c%#)Qc$)9slKI8T0+
zZpYX#Su?|)>5Js#tPDG*ACi+-L8w<5c3cLaF#`q$1`+AWMww<z7n~<&W!iDMfI7(x
z3=9^WlQ(6WaZP{?R&Y-KlxfB^!FRG&mYqfeXzYW50o;ZLg)=Daf=2hD(ZB%efP=&V
Dq^&2c

diff --git a/pkg/ebpf/tracer.go b/pkg/ebpf/tracer.go
index 4efa75bb..2253c1f4 100644
--- a/pkg/ebpf/tracer.go
+++ b/pkg/ebpf/tracer.go
@@ -7,6 +7,7 @@ import (
 	"strings"
 
 	"github.com/cilium/ebpf"
+	"github.com/cilium/ebpf/btf"
 	"github.com/cilium/ebpf/ringbuf"
 	"github.com/cilium/ebpf/rlimit"
 	"github.com/netobserv/netobserv-ebpf-agent/pkg/ifaces"
@@ -81,7 +82,12 @@ func NewFlowFetcher(
 		}
 		return nil, fmt.Errorf("loading and assigning BPF objects: %w", err)
 	}
-
+	/*
+	 * since we load the program only when the we start we need to release
+	 * memory used by cached kernel BTF see https://github.com/cilium/ebpf/issues/1063
+	 * for more details.
+	 */
+	btf.FlushKernelSpec()
 	// read events from igress+egress ringbuffer
 	flows, err := ringbuf.NewReader(objects.DirectFlows)
 	if err != nil {
@@ -124,7 +130,7 @@ func (m *FlowFetcher) Register(iface ifaces.Interface) error {
 		if errors.Is(err, fs.ErrExist) {
 			ilog.WithError(err).Warn("qdisc clsact already exists. Ignoring")
 		} else {
-			return fmt.Errorf("failed to create clsact qdisc on %d (%s): %T %w", iface.Index, iface.Name, err, err)
+			return fmt.Errorf("failed to create clsact qdisc on %d (%s): %w", iface.Index, iface.Name, err)
 		}
 	}
 	m.qdiscs[iface] = qdisc
@@ -133,11 +139,7 @@ func (m *FlowFetcher) Register(iface ifaces.Interface) error {
 		return err
 	}
 
-	if err := m.registerIngress(iface, ipvlan); err != nil {
-		return err
-	}
-
-	return nil
+	return m.registerIngress(iface, ipvlan)
 }
 
 func (m *FlowFetcher) registerEgress(iface ifaces.Interface, ipvlan netlink.Link) error {
@@ -308,14 +310,14 @@ func (m *FlowFetcher) ReadRingBuf() (ringbuf.Record, error) {
 // TODO: detect whether BatchLookupAndDelete is supported (Kernel>=5.6) and use it selectively
 // Supported Lookup/Delete operations by kernel: https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md
 // Race conditions here causes that some flows are lost in high-load scenarios
-func (m *FlowFetcher) LookupAndDeleteMap() map[BpfFlowId]BpfFlowMetrics {
+func (m *FlowFetcher) LookupAndDeleteMap() map[BpfFlowId]*BpfFlowMetrics {
 	flowMap := m.objects.AggregatedFlows
 
 	iterator := flowMap.Iterate()
-	var flow = make(map[BpfFlowId]BpfFlowMetrics, m.cacheMaxSize)
-
-	id := BpfFlowId{}
+	var flow = make(map[BpfFlowId]*BpfFlowMetrics, m.cacheMaxSize)
+	var id BpfFlowId
 	var metric BpfFlowMetrics
+
 	// Changing Iterate+Delete by LookupAndDelete would prevent some possible race conditions
 	// TODO: detect whether LookupAndDelete is supported (Kernel>=4.20) and use it selectively
 	for iterator.Next(&id, &metric) {
@@ -323,10 +325,9 @@ func (m *FlowFetcher) LookupAndDeleteMap() map[BpfFlowId]BpfFlowMetrics {
 			log.WithError(err).WithField("flowId", id).
 				Warnf("couldn't delete flow entry")
 		}
-		// We observed that eBFP PerCPU map might insert multiple times the same key in the map
-		// (probably due to race conditions) so we need to re-join metrics again at userspace
-		// TODO: instrument how many times the keys are is repeated in the same eviction
-		flow[id] = metric
+		metricPtr := new(BpfFlowMetrics)
+		*metricPtr = metric
+		flow[id] = metricPtr
 	}
 	return flow
 }
diff --git a/pkg/exporter/ipfix.go b/pkg/exporter/ipfix.go
index 67f18adc..e3066a75 100644
--- a/pkg/exporter/ipfix.go
+++ b/pkg/exporter/ipfix.go
@@ -327,7 +327,7 @@ func setEntities(record *flow.Record, elements *[]entities.InfoElementWithValue)
 		setIERecordValue(record, &ieVal)
 	}
 }
-func (ipf *IPFIX) sendDataRecord(log *logrus.Entry, record *flow.Record, v6 bool) error {
+func (ipf *IPFIX) sendDataRecord(_ *logrus.Entry, record *flow.Record, v6 bool) error {
 	dataSet := entities.NewSet(false)
 	var templateID uint16
 	if v6 {
diff --git a/pkg/flow/tracer_map.go b/pkg/flow/tracer_map.go
index 563c2850..e067e34e 100644
--- a/pkg/flow/tracer_map.go
+++ b/pkg/flow/tracer_map.go
@@ -2,6 +2,7 @@ package flow
 
 import (
 	"context"
+	"runtime"
 	"sync"
 	"time"
 
@@ -25,7 +26,7 @@ type MapTracer struct {
 }
 
 type mapFetcher interface {
-	LookupAndDeleteMap() map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics
+	LookupAndDeleteMap() map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics
 }
 
 func NewMapTracer(fetcher mapFetcher, evictionTimeout time.Duration) *MapTracer {
@@ -43,10 +44,10 @@ func (m *MapTracer) Flush() {
 	m.evictionCond.Broadcast()
 }
 
-func (m *MapTracer) TraceLoop(ctx context.Context) node.StartFunc[[]*Record] {
+func (m *MapTracer) TraceLoop(ctx context.Context, enableGC bool) node.StartFunc[[]*Record] {
 	return func(out chan<- []*Record) {
 		evictionTicker := time.NewTicker(m.evictionTimeout)
-		go m.evictionSynchronization(ctx, out)
+		go m.evictionSynchronization(ctx, enableGC, out)
 		for {
 			select {
 			case <-ctx.Done():
@@ -64,7 +65,7 @@ func (m *MapTracer) TraceLoop(ctx context.Context) node.StartFunc[[]*Record] {
 // evictionSynchronization loop just waits for the evictionCond to happen
 // and triggers the actual eviction. It makes sure that only one eviction
 // is being triggered at the same time
-func (m *MapTracer) evictionSynchronization(ctx context.Context, out chan<- []*Record) {
+func (m *MapTracer) evictionSynchronization(ctx context.Context, enableGC bool, out chan<- []*Record) {
 	// flow eviction loop. It just keeps waiting for eviction until someone triggers the
 	// evictionCond.Broadcast signal
 	for {
@@ -77,14 +78,14 @@ func (m *MapTracer) evictionSynchronization(ctx context.Context, out chan<- []*R
 			return
 		default:
 			mtlog.Debug("evictionSynchronization signal received")
-			m.evictFlows(ctx, out)
+			m.evictFlows(ctx, enableGC, out)
 		}
 		m.evictionCond.L.Unlock()
 
 	}
 }
 
-func (m *MapTracer) evictFlows(ctx context.Context, forwardFlows chan<- []*Record) {
+func (m *MapTracer) evictFlows(ctx context.Context, enableGC bool, forwardFlows chan<- []*Record) {
 	// it's important that this monotonic timer reports same or approximate values as kernel-side bpf_ktime_get_ns()
 	monotonicTimeNow := monotime.Now()
 	currentTime := time.Now()
@@ -103,7 +104,7 @@ func (m *MapTracer) evictFlows(ctx context.Context, forwardFlows chan<- []*Recor
 		}
 		forwardingFlows = append(forwardingFlows, NewRecord(
 			flowKey,
-			aggregatedMetrics,
+			*aggregatedMetrics,
 			currentTime,
 			uint64(monotonicTimeNow),
 		))
@@ -115,5 +116,9 @@ func (m *MapTracer) evictFlows(ctx context.Context, forwardFlows chan<- []*Recor
 	default:
 		forwardFlows <- forwardingFlows
 	}
+
+	if enableGC {
+		runtime.GC()
+	}
 	mtlog.Debugf("%d flows evicted", len(forwardingFlows))
 }
diff --git a/pkg/flow/tracer_ringbuf.go b/pkg/flow/tracer_ringbuf.go
index bd6e3791..eadfcea8 100644
--- a/pkg/flow/tracer_ringbuf.go
+++ b/pkg/flow/tracer_ringbuf.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"runtime"
 	"sync/atomic"
 	"syscall"
 	"time"
@@ -51,7 +52,7 @@ func NewRingBufTracer(
 	}
 }
 
-func (m *RingBufTracer) TraceLoop(ctx context.Context) node.StartFunc[*RawRecord] {
+func (m *RingBufTracer) TraceLoop(ctx context.Context, enableGC bool) node.StartFunc[*RawRecord] {
 	return func(out chan<- *RawRecord) {
 		debugging := logrus.IsLevelEnabled(logrus.DebugLevel)
 		for {
@@ -60,7 +61,7 @@ func (m *RingBufTracer) TraceLoop(ctx context.Context) node.StartFunc[*RawRecord
 				rtlog.Debug("exiting trace loop due to context cancellation")
 				return
 			default:
-				if err := m.listenAndForwardRingBuffer(debugging, out); err != nil {
+				if err := m.listenAndForwardRingBuffer(debugging, enableGC, out); err != nil {
 					if errors.Is(err, ringbuf.ErrClosed) {
 						rtlog.Debug("Received signal, exiting..")
 						return
@@ -73,7 +74,7 @@ func (m *RingBufTracer) TraceLoop(ctx context.Context) node.StartFunc[*RawRecord
 	}
 }
 
-func (m *RingBufTracer) listenAndForwardRingBuffer(debugging bool, forwardCh chan<- *RawRecord) error {
+func (m *RingBufTracer) listenAndForwardRingBuffer(debugging, enableGC bool, forwardCh chan<- *RawRecord) error {
 	event, err := m.ringBuffer.ReadRingBuf()
 	if err != nil {
 		return fmt.Errorf("reading from ring buffer: %w", err)
@@ -95,7 +96,9 @@ func (m *RingBufTracer) listenAndForwardRingBuffer(debugging bool, forwardCh cha
 
 	// Will need to send it to accounter anyway to account regardless of complete/ongoing flow
 	forwardCh <- readFlow
-
+	if enableGC {
+		runtime.GC()
+	}
 	return nil
 }
 
diff --git a/pkg/test/tracer_fake.go b/pkg/test/tracer_fake.go
index 495acfca..960de0c6 100644
--- a/pkg/test/tracer_fake.go
+++ b/pkg/test/tracer_fake.go
@@ -13,14 +13,14 @@ import (
 // TracerFake fakes the kernel-side eBPF map structures for testing
 type TracerFake struct {
 	interfaces map[ifaces.Interface]struct{}
-	mapLookups chan map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics
+	mapLookups chan map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics
 	ringBuf    chan ringbuf.Record
 }
 
 func NewTracerFake() *TracerFake {
 	return &TracerFake{
 		interfaces: map[ifaces.Interface]struct{}{},
-		mapLookups: make(chan map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics, 100),
+		mapLookups: make(chan map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics, 100),
 		ringBuf:    make(chan ringbuf.Record, 100),
 	}
 }
@@ -33,12 +33,12 @@ func (m *TracerFake) Register(iface ifaces.Interface) error {
 	return nil
 }
 
-func (m *TracerFake) LookupAndDeleteMap() map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics {
+func (m *TracerFake) LookupAndDeleteMap() map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics {
 	select {
 	case r := <-m.mapLookups:
 		return r
 	default:
-		return map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics{}
+		return map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics{}
 	}
 }
 
@@ -46,7 +46,7 @@ func (m *TracerFake) ReadRingBuf() (ringbuf.Record, error) {
 	return <-m.ringBuf, nil
 }
 
-func (m *TracerFake) AppendLookupResults(results map[ebpf.BpfFlowId]ebpf.BpfFlowMetrics) {
+func (m *TracerFake) AppendLookupResults(results map[ebpf.BpfFlowId]*ebpf.BpfFlowMetrics) {
 	m.mapLookups <- results
 }
 
diff --git a/scripts/update-bpf-headers.sh b/scripts/update-bpf-headers.sh
index 38f97d87..ce0301b2 100755
--- a/scripts/update-bpf-headers.sh
+++ b/scripts/update-bpf-headers.sh
@@ -11,6 +11,7 @@ headers=(
     "$prefix"/src/bpf_helper_defs.h
     "$prefix"/src/bpf_helpers.h
     "$prefix"/src/bpf_tracing.h
+    "$prefix"/src/bpf_core_read.h
 )
 
 # Fetch libbpf release and extract the desired headers
-- 
GitLab