From 45b4757d2be2b41b2258ca8b0c9b4dd1b72b28aa Mon Sep 17 00:00:00 2001
From: shach33 <45016480+shach33@users.noreply.github.com>
Date: Wed, 18 Jan 2023 13:07:35 +0530
Subject: [PATCH] Added TCP Flags to Flow Record metrics (#68)

* Test commit

* Adding TCP flags

* Adding TCP flags to record metrics.TODO: Remove log stmts

* Updated tcp flags u32-> u16

* Updated indentation in C file

* Update flow.h

* Indent fixed. Tab -> 4 space

fixing indents

Indent fixes for flows.c

Indent fixes for flows.c-II

Still fixing indents

* Removed extra file

* Added clang-format config to bpf/. To use clang-format -i <file.c>

* Fixed message record member sequences

* Added TCP Flags combinations Read from flw

Updated changes according to comments on PR

* Removed log statements.

Rebase merges

* Fixing merge conflits

* Revert the renaming of grpc_test file

* Simplify setting flags for v4,v6

* Add flags to ipfix exporter

* Update protobuf

* Remove type conversions due to conflicts

* Remove .gitignore change

* Fix indentation

* Remove commented line

* Fixed typecast errors since move to go 1.18

* Reverting commit d1e9c44. Added changes as separate PR

* set flags for v6

Co-authored-by: Pravein Govindan Kannan <pravein.govindan.kannan@ibm.com>
---
 bpf/.clang-format                             |   9 ++
 bpf/flow.h                                    |   2 +
 bpf/flows.c                                   |  72 +++++++---
 .../server/flowlogs-dump-collector.go         |   8 +-
 go.mod                                        |   2 +-
 pkg/ebpf/bpf_bpfeb.o                          | Bin 17424 -> 20504 bytes
 pkg/ebpf/bpf_bpfel.o                          | Bin 17520 -> 21032 bytes
 pkg/exporter/ipfix.go                         | 126 +++++++++---------
 pkg/exporter/kafka_proto_test.go              |   4 +-
 pkg/exporter/proto.go                         |   4 +-
 pkg/flow/account_test.go                      |  24 ++--
 pkg/flow/deduper_test.go                      |   8 +-
 pkg/flow/record.go                            |   5 +-
 pkg/flow/record_test.go                       |   3 +
 pkg/flow/tracer_map_test.go                   |  20 +--
 pkg/grpc/grpc_test.go                         |   9 +-
 pkg/pbflow/flow.pb.go                         | 105 ++++++++-------
 pkg/pbflow/flow_grpc.pb.go                    |   2 +-
 proto/flow.proto                              |   1 +
 19 files changed, 238 insertions(+), 166 deletions(-)
 create mode 100644 bpf/.clang-format

diff --git a/bpf/.clang-format b/bpf/.clang-format
new file mode 100644
index 00000000..92af251e
--- /dev/null
+++ b/bpf/.clang-format
@@ -0,0 +1,9 @@
+{
+  BasedOnStyle: LLVM,
+  AllowShortFunctionsOnASingleLine: InlineOnly,
+  ColumnLimit: 100,
+  IndentWidth: 4,
+  SortIncludes: false,
+  ReflowComments: false,
+  TabWidth: 4,
+}
diff --git a/bpf/flow.h b/bpf/flow.h
index 1248838b..af668b5e 100644
--- a/bpf/flow.h
+++ b/bpf/flow.h
@@ -17,6 +17,8 @@ typedef struct flow_metrics_t {
     // as output from bpf_ktime_get_ns()
     u64 start_mono_time_ts;
     u64 end_mono_time_ts;
+    // TCP Flags from https://www.ietf.org/rfc/rfc793.txt
+    u16 flags;
     // The positive errno of a failed map insertion that caused a flow
     // to be sent via ringbuffer.
     // 0 otherwise
diff --git a/bpf/flows.c b/bpf/flows.c
index 790f24b8..72fa02ae 100644
--- a/bpf/flows.c
+++ b/bpf/flows.c
@@ -26,7 +26,6 @@
 #include <linux/udp.h>
 #include <linux/tcp.h>
 #include <string.h>
-
 #include <stdbool.h>
 #include <linux/if_ether.h>
 
@@ -42,6 +41,20 @@
 #define INGRESS 0
 #define EGRESS 1
 
+// Flags according to RFC 9293 & https://www.iana.org/assignments/ipfix/ipfix.xhtml
+#define FIN_FLAG 0x01
+#define SYN_FLAG 0x02
+#define RST_FLAG 0x04
+#define PSH_FLAG 0x08
+#define ACK_FLAG 0x10
+#define URG_FLAG 0x20
+#define ECE_FLAG 0x40
+#define CWR_FLAG 0x80
+// Custom flags exported
+#define SYN_ACK_FLAG 0x100
+#define FIN_ACK_FLAG 0x200
+#define RST_ACK_FLAG 0x400
+
 // Common Ringbuffer as a conduit for ingress/egress flows to userspace
 struct {
     __uint(type, BPF_MAP_TYPE_RINGBUF);
@@ -62,8 +75,35 @@ volatile const u8 trace_messages = 0;
 
 const u8 ip4in6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
 
+// sets the TCP header flags for connection information
+static inline void set_flags(struct tcphdr *th, u16 *flags) {
+    //If both ACK and SYN are set, then it is server -> client communication during 3-way handshake. 
+    if (th->ack && th->syn) {
+        *flags |= SYN_ACK_FLAG;
+    } else if (th->ack && th->fin ) {
+        // If both ACK and FIN are set, then it is graceful termination from server.
+        *flags |= FIN_ACK_FLAG;
+    } else if (th->ack && th->rst ) {
+        // If both ACK and RST are set, then it is abrupt connection termination. 
+        *flags |= RST_ACK_FLAG;
+    } else if (th->fin) {
+        *flags |= FIN_FLAG;
+    } else if (th->syn) {
+        *flags |= SYN_FLAG;
+    } else if (th->rst) {
+        *flags |= RST_FLAG;
+    } else if (th->psh) {
+        *flags |= PSH_FLAG;
+    } else if (th->urg) {
+        *flags |= URG_FLAG;
+    } else if (th->ece) {
+        *flags |= ECE_FLAG;
+    } else if (th->cwr) {
+        *flags |= CWR_FLAG;
+    }
+}
 // sets flow fields from IPv4 header information
-static inline int fill_iphdr(struct iphdr *ip, void *data_end, flow_id *id) {
+static inline int fill_iphdr(struct iphdr *ip, void *data_end, flow_id *id, u16 *flags) {
     if ((void *)ip + sizeof(*ip) > data_end) {
         return DISCARD;
     }
@@ -81,6 +121,7 @@ static inline int fill_iphdr(struct iphdr *ip, void *data_end, flow_id *id) {
         if ((void *)tcp + sizeof(*tcp) <= data_end) {
             id->src_port = __bpf_ntohs(tcp->source);
             id->dst_port = __bpf_ntohs(tcp->dest);
+            set_flags(tcp, flags);
         }
     } break;
     case IPPROTO_UDP: {
@@ -97,7 +138,7 @@ static inline int fill_iphdr(struct iphdr *ip, void *data_end, flow_id *id) {
 }
 
 // sets flow fields from IPv6 header information
-static inline int fill_ip6hdr(struct ipv6hdr *ip, void *data_end, flow_id *id) {
+static inline int fill_ip6hdr(struct ipv6hdr *ip, void *data_end, flow_id *id, u16 *flags) {
     if ((void *)ip + sizeof(*ip) > data_end) {
         return DISCARD;
     }
@@ -113,6 +154,7 @@ static inline int fill_ip6hdr(struct ipv6hdr *ip, void *data_end, flow_id *id) {
         if ((void *)tcp + sizeof(*tcp) <= data_end) {
             id->src_port = __bpf_ntohs(tcp->source);
             id->dst_port = __bpf_ntohs(tcp->dest);
+            set_flags(tcp, flags);
         }
     } break;
     case IPPROTO_UDP: {
@@ -128,7 +170,7 @@ static inline int fill_ip6hdr(struct ipv6hdr *ip, void *data_end, flow_id *id) {
     return SUBMIT;
 }
 // sets flow fields from Ethernet header information
-static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, flow_id *id) {
+static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, flow_id *id, u16 *flags) {
     if ((void *)eth + sizeof(*eth) > data_end) {
         return DISCARD;
     }
@@ -138,15 +180,15 @@ static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, flow_id *id) {
 
     if (id->eth_protocol == ETH_P_IP) {
         struct iphdr *ip = (void *)eth + sizeof(*eth);
-        return fill_iphdr(ip, data_end, id);
+        return fill_iphdr(ip, data_end, id, flags);
     } else if (id->eth_protocol == ETH_P_IPV6) {
         struct ipv6hdr *ip6 = (void *)eth + sizeof(*eth);
-        return fill_ip6hdr(ip6, data_end, id);
+        return fill_ip6hdr(ip6, data_end, id, flags);
     } else {
         // TODO : Need to implement other specific ethertypes if needed
         // For now other parts of flow id remain zero
-        memset (&(id->src_ip),0, sizeof(struct in6_addr));
-        memset (&(id->dst_ip),0, sizeof(struct in6_addr));
+        memset(&(id->src_ip), 0, sizeof(struct in6_addr));
+        memset(&(id->dst_ip), 0, sizeof(struct in6_addr));
         id->transport_protocol = 0;
         id->src_port = 0;
         id->dst_port = 0;
@@ -154,7 +196,6 @@ static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, flow_id *id) {
     return SUBMIT;
 }
 
-
 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 != 0 && (bpf_get_prandom_u32() % sampling) != 0) {
@@ -166,7 +207,8 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
     flow_id id;
     u64 current_time = bpf_ktime_get_ns();
     struct ethhdr *eth = data;
-    if (fill_ethhdr(eth, data_end, &id) == DISCARD) {
+    u16 flags = 0;
+    if (fill_ethhdr(eth, data_end, &id, &flags) == DISCARD) {
         return TC_ACT_OK;
     }
     id.if_index = skb->ifindex;
@@ -184,7 +226,7 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
         if (aggregate_flow->start_mono_time_ts == 0) {
             aggregate_flow->start_mono_time_ts = current_time;
         }
-
+        aggregate_flow->flags |= flags;
         long ret = bpf_map_update_elem(&aggregated_flows, &id, aggregate_flow, BPF_ANY);
         if (trace_messages && ret != 0) {
             // usually error -16 (-EBUSY) is printed here.
@@ -198,9 +240,10 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
         // Key does not exist in the map, and will need to create a new entry.
         flow_metrics new_flow = {
             .packets = 1,
-            .bytes=skb->len,
+            .bytes = skb->len,
             .start_mono_time_ts = current_time,
             .end_mono_time_ts = current_time,
+            .flags = flags, 
         };
 
         // even if we know that the entry is new, another CPU might be concurrently inserting a flow
@@ -230,15 +273,14 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
         }
     }
     return TC_ACT_OK;
-
 }
 SEC("tc_ingress")
-int ingress_flow_parse (struct __sk_buff *skb) {
+int ingress_flow_parse(struct __sk_buff *skb) {
     return flow_monitor(skb, INGRESS);
 }
 
 SEC("tc_egress")
-int egress_flow_parse (struct __sk_buff *skb) {
+int egress_flow_parse(struct __sk_buff *skb) {
     return flow_monitor(skb, EGRESS);
 }
 char _license[] SEC("license") = "GPL";
diff --git a/examples/flowlogs-dump/server/flowlogs-dump-collector.go b/examples/flowlogs-dump/server/flowlogs-dump-collector.go
index 26aff7fc..3d2c8ab9 100644
--- a/examples/flowlogs-dump/server/flowlogs-dump-collector.go
+++ b/examples/flowlogs-dump/server/flowlogs-dump-collector.go
@@ -61,7 +61,7 @@ func main() {
 	log.SetFlags(0)
 	flag.Parse()
 
-	receivedRecords := make(chan *pbflow.Records, 100)
+	receivedRecords := make(chan *pbflow.Records, 1000)
 	log.Println("starting flowlogs-dump-collector on port", *port)
 	go func() {
 		_, err := grpc.StartCollector(*port, receivedRecords)
@@ -72,7 +72,7 @@ func main() {
 	for records := range receivedRecords {
 		for _, record := range records.Entries {
 			if record.EthProtocol == ipv6 {
-				log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d ends: %v\n",
+				log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d flags:%d ends: %v\n",
 					ipProto[record.EthProtocol],
 					record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"),
 					record.Interface,
@@ -84,10 +84,11 @@ func main() {
 					record.Direction,
 					record.Bytes,
 					record.Packets,
+					record.Flags,
 					record.TimeFlowEnd.AsTime().Local().Format("15:04:05.000000"),
 				)
 			} else {
-				log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d ends: %v\n",
+				log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d flags:%d ends: %v\n",
 					ipProto[record.EthProtocol],
 					record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"),
 					record.Interface,
@@ -99,6 +100,7 @@ func main() {
 					record.Direction,
 					record.Bytes,
 					record.Packets,
+					record.Flags,
 					record.TimeFlowEnd.AsTime().Local().Format("15:04:05.000000"),
 				)
 			}
diff --git a/go.mod b/go.mod
index 4df6d82a..b06f7bfd 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
 	github.com/caarlos0/env/v6 v6.9.1
 	github.com/cilium/ebpf v0.8.1
 	github.com/gavv/monotime v0.0.0-20190418164738-30dba4353424
+	github.com/golang/protobuf v1.5.2
 	github.com/mariomac/guara v0.0.0-20220523124851-5fc279816f1f
 	github.com/netobserv/gopipes v0.3.0
 	github.com/paulbellamy/ratecounter v0.2.0
@@ -35,7 +36,6 @@ require (
 	github.com/go-openapi/jsonreference v0.19.5 // indirect
 	github.com/go-openapi/swag v0.19.14 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
-	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/gnostic v0.5.7-v3refs // indirect
 	github.com/google/go-cmp v0.5.7 // indirect
 	github.com/google/gofuzz v1.1.0 // indirect
diff --git a/pkg/ebpf/bpf_bpfeb.o b/pkg/ebpf/bpf_bpfeb.o
index ee6465770f750f986efe7ab54426cac2f1b26477..8f980bfe43902ca98206d83f9e1c41e70ad28c29 100644
GIT binary patch
literal 20504
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
Zs-eX@NC^mox~U)<-adxz@`I;e2>{ZQq1ONa

delta 6587
zcmbQSfN??x;{-hs`wI*p-~b{R92f){1ok&gbSkK4S^^TOUh#hch)!&02msU58GJx=
zD~MoVVBMbpVeFTL(Ch+Wnon1PX%2{0D9OMIqKg;)zXqZUB^g*ibn(LfS3z{4Bm*;u
zE?)Tm3WzS0WMBf(#q|sSUj{J>B^ek&bn(Lfmq2tO)S}{r|1U!M93Z-Q;s3KBx=@mV
z6GRs;{C^Ha7fLd)f#~9e|4)PHLP-X85M8|R{}~WnD9OMDqKg;)KM$e{B^kIubV%{S
z|KN}*)MVfV2^2~)@PO!ahz~jZg+M$8hU|s^Pk>mW0t|Kx3~hHq1sHl67&sWvLPSYd
zf~jgU3zKd=L_b6E!v7CI`id9+zYnGFLFv0t`VN%74W(~E>6=jc29&-IrQbp6w@~^G
zlzt7RUxDcQ;)VZTf*8dM|G$9J&!O}ODE%HpCu%ZCf$054Ad-Qh+yG2-6fge&6vRRk
z7bsr*{|QLEc+vl7Ai7)uL^4PeFZ%x&#7fj;kYiwAsAoXa2r}?1NCBES$iOck@#01Q
zzkz5Z13!cKg_;cFAi8+r|6fr0CzSpHrN4veMgM<;Xi)`*8j$^hp$ZKB3=9lxXi;RQ
zE5XnMQpn1{Pz9nf<(X_j;)Rk7svx>}A;hPJk_;+PJ~(6wB^i{Vd~k>qN-`)x`Hvau
z85kG}B^eZ<0*^p+p(F!1u!<M{e+cEvgJ@V9DU<{U9VpF!(@LQvgDg}YoMs9o8DyY*
zaM~%9WRQmP!D*;a5)zfg3;*8+*$;96I3E=+{0~l4g^~;sPz~V3RVWD$T5uvOlw=Tt
z%7YVIp(KM2ln+j9g^~=qP(C;j7D_T`LHXdsS18G#4dvH^Q)Qtfg9cOpoEQrw88o4M
za4Id7WKe_h!HKg_l0hBH2PfJ>Nd^-rADngyB^gYid~jMRlw<%W+v0`)A!$XD!5AW6
z{~w&F3MCo9>A85}|BoPvLP-Wg5M8|R|0fV#D9NA)qKg;)2j_-DNd|o=ADl}HB^g9O
z{O#a~V_+y=1WkmC{zDSsqW_RYxadD55iW!#!g>L)O9ev(80@hmLN8qj1{;vUtPBtr
zZ%33D_*3~pNG>T}_#Yf1#S0-Gg@pjjW1##G_HpsT|6rfMd|15jKRE7+7ybvwY4O7U
z;HWBI_#YgH#S8y~qXtj;0nYcu3nAr0@j_^Mun>~}ix>U}CH8tyDh8)=Sn8%?2?);T
ztPGH-LCd~cx)Kb644~Q|Q<6bxvJZ!>CN$r&g34<K2J|A^PFI2fT(@LOPWIxEXOx_r
z#UUq@C=N-vm0FORv3SwsDsD^036r;Q9}(E!4vIPkhW%v_dU6HNM9BaKa8;2Gu0R<$
z3KbZHL9+fqla+Yg>pehh1_pj`YGPp6?+)RYLn>sB>LpNXSRh##O<tgS$^RK39mOmR
z;2e!6FHybZ{{*N!IETYrSl$2<Wl*Ru=741N{nNn$4CP?u3>w9pkSxDH9V!l~=?#k6
z7(_uL#q5wW2F*f?Viri~r$aJ^fIqmXWMJ4I2-3yCP!0`-Vped)TaPXwQOpVnbu<kE
z#jKE;9Zg)Lm=zSK7#1iLvqEZmH1!t6tk5P1BdDgI{Ebh#J^)&^L!IUibt*K*1pI>`
zPKWXp{DUC;&;XDL3=EZ0&^Tg*#B`+;G)@>n2@Wg|4%A{s25@FB=3w9lnNZBhzz3p5
zirFA-jAC|3(kNzO;F<h}Kb#X>ZHO{3Do*wh&}WpMTq7XklDzEy0g$fbW&d}8=yFKJ
zC?qfYzX!xmUiN<rm|pmQ1BiwdAju2=uL1Fk7ydso`Hg@-BkN=v!Eo6lATbHByFe@m
zhL&oflQ#$&Gk%!-L{Oda^=2NS>nxmL<;9E)A)DWbr7%q{kW`p#A@!c~3IhZC6$S>r
zh|LDlo0(WaZ9dt_FJ#RX1sNC^9xyO4Hh^;y1E^wTY=N>>7#JA4Ci}>#OD<$!00*T5
z0|Vny1_lOD?bpD-z_@yHkDPS<9u@|01$uyif$<mv10>xsFfg8ivK1H@7(tCiP@M-d
z0aRsy*a-{_jG!V3#0HrLD#$_X1q=*~f1r8~FfcHITniF^z`(!+3J7TiaGR3}l%b><
z80r}n7#Ns9)e}g<fq{VuR8xT12@DKORtyZFs*ACKfdSk)kY-?D0;zX`Sil5Q?+ayv
z)PvFvNDWARG*o;60|QeslnruF7L*NgP$`2o*vFt|G83rs)?#2_23gR>zyPXbnL(PT
zKs2y`#6j(KX$A%skj1MfKadxf+{yqBcNUP*pd=#A0B)2s9i1$oAg%~%CWAyk4gyu~
zLJSP7ATvRYHf06|)&r9b6zmz_OfFDRX8bmJih?pHsDe{xU|{+?`GA7BA(Y1u#=rnd
z?#yA}W-<e$I^~51B?AK!R2^^SWDZ3oCf?nXbrjW@c#ljDQ8W_by$sF>4B)Ddk%58t
z*5nx=+53|ZC>k;GzL@+4#QQs0MoCSGPXwyg4U$&*v?qrsDKYUGPOeZ2QscAahgb=c
zgp{ESp#09~2yXU+L>c(}H-AuSVpK~lD$2`eC^a)-h>r)6Ir(|%3Sgo%uQ)S3FEvFW
zGp}UxEERJ`k&@z)#N2}TlFEWqhKzCuZ}SD!B`lNIX}1d~XsBsqrs&$G6qm$j7HH~B
zcGXdwJi*XxbDGW;#>q~4FBok%>*~idP1Z8HU;lbOxJLsi9~r>y7!w8tHX8;8wgRyG
zz||2mC?$dwGBALeD$Jk+0^=JoFz|LWAUq0c3kfhVfc1d;PYevq(hLmD`V7olK+yq`
zgYoNG85qEZ#X&3sE6ikIssM3e3fD6*HGuk28c>5kd{ATC0ErLEG8RaDPy@>Wi4T$w
zK;naPO#uT#J=j8!fglSSpb9=SF!g}4SO<j9qRPND0aSBLfb#trnC5^gumw<l6$6t1
zs2<vY#0QzT1Ik~`z$C-Uz`!U0<v(R$QULKQ80x`6!>Y)@q$0t<z&Hb<0L&L-U|@t=
zz#7cJq{GR;zzDT~wVHvEM}&ca@c>jkh!2v#0OhY@U<6zE0Lp*EzzDYR2b2$$XY#0r
z3P2SwK^?%R$H1t<%D}+%0wT}W!N8~iiYjOjvpr&9)KOw!V1@=UJ1+yHi4X$=Gc<_V
zl^GZfK>P%#evo<@1_tH~2%p`OfzbkFUVQ~rAe4d8MUsJm85-p5AU-bx12fb?ARkW=
zVPIfh0Z|X;b22b6LqmkUn}KnO7y|<fjK7?LafKKI11pSwn1OMP5~u)y=m$A?ix2}t
zJu5WGKrY?@Ds7-a#tzaT!@$4_4FUGI42(Ni85mfhK?ri-5lIFHHV&wPp$v>ico`Vj
z6d-&K4hE(WP6h^cXozq)GcYDdGBB`1Lj=s{WvFLhhXx5K!Gkb6)W;wN4?r5AJ_hr7
z85r21J_4x)VfGsk3qfoUX8!=;b5t@gZIEDKV23)GV<rO=$j2N|2ZQAW>lqk0ps5n1
z8H71tKG@E{bVP-Lfdd-noa_utCpZ}xIG}OPsmZ`}Mv;Mm1DY#1{TY}p$TKi-qRDfj
z%R>`2XB7j}gL+v8aLWsn4Z#MeGca&LT?ppOGca&L%K^@f3`|$F7#O&qJ_Z{A(hrRy
zn0juQg&+%L85p>sQ4Chk%fP@5)BlQrss4!p0|O7#hg_NrOdmuT7<iyj!qvpU^o5s!
zfd^VHfcY{E3_MT^xYjT*^MK?}K!Tj>DFd^NA_D^t)Ix4{24)pW1_mCeg)n(uXb5qu
zFw`?Uh%hklLM`O3U|@FPWnkbffEdU<fq^+jkb!|0nk(RZr~|k+F)$~9<e>!(_ge<$
z961ICUTC=h=F2cJ@IoEPBf!91pv=I)3r!<DdG!p;B_IQ!iG-(<fw@AIfq@Si<ZwPT
zjqt2zV6FklLw&%@&cNIw#lRp8RnM!!z&t^ofk6}+V!S>K%u{$77(}6onzx*Rc?GCS
z1=Sazx&btD0E&CwsSL~~kSYf-pLOy_DFqg01_s8-g;FAuWo*RjYnc%B3@EWOFffRM
zT2P?wF|0lU*BuZ^Mo>Q-Dh_f3M3jMn(G^i&fr=QoIH+ERs%Hb0@GuEb=admNUc&&%
z(lBubP=6Y#0hIG#;*1~<!o)LRq6`d-piw87IJmC_kz)k4!C~UymNHa42jNim8{qL8
zs03(40;+)r+ysY;g9e3Q;^09Ah&Y1;Be>}S=7HM5AO^^X{}C4Of}8Ll2?hqn5+wDY
zx)3BRX2HO~n1ay22W!)SgnW@SfCdvl8bHAh8dGHkN1%y~IO{?o1_q|d3ijfX;GtKL
zA}9v&tw4R^$pJ{RAW@J4ke779vJLj)lA!h{NEC)ajc##41_qYN8|=jyStt34gGV+&
z{sU=bU|;~1YT!;Ol+OclI;c$z<AWjzG{gwwgE~o|VJ0XalxLCkgR&^N6AY6_Q?CZf
zbKuSaOaW*F2FU_GkmJNAw>W6mhd>(4pq3%XL!c@GY!%e+?4Se<QVsPrdkX^t*lHLb
zWHmS=fpjx4u!9D>K~9IsuV7#Rcb{Q=P>&2ro{b$e_$)Ws#8ID7baRR$H=8o3=?7}i
zKwZEF>Ys!8a?0|Gs!9ri!lIKud483&WbkovGK@Eb(nc0gzQtrgZ&3|HGYHqn6iP!V
zV<QM{1f>lpmwC%^85=@G4Gkx+HIiV5m}@Zkp|{l}Y2L}vKFUm@3nn-CNHh9Rj`5M=
z5(SS}GcYhHfCb~gf*?<U!vHKe`L?e#lbFKfAHH@>VpAqt_}MXu&6r%_XU8Q5%`jpv
zlO24dS;2X4a-ozMmoCi16DA+<H`6kP=1@>G2;5r+wK_o-K>Li~aY|79a)NYgnSp`{
zBn`^Ip!Od~3dDyg2eqQT85kHK%FSWf6C?~$4k{4Ql}90zgHkL=8m1f?osa<v1_rPL
zLF1E9(;?#r3=E*u0Wuv_w1KoEI|ekn09Gz!4h>H>kT#HVj>#SVdR%reH*$eOYO=JC
SG?yKylL^Z3lP5d)NB{t?xbN!#

diff --git a/pkg/ebpf/bpf_bpfel.o b/pkg/ebpf/bpf_bpfel.o
index b28228617135f0ee03e3b7426a289ba71b98b12f..300e3452ad3b4b963cdf91ba9e7550ec1b03328e 100644
GIT binary patch
literal 21032
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
NA3=L<VD`htRRHZWu_yol

delta 6569
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

diff --git a/pkg/exporter/ipfix.go b/pkg/exporter/ipfix.go
index c6c33e6d..ad059a73 100644
--- a/pkg/exporter/ipfix.go
+++ b/pkg/exporter/ipfix.go
@@ -39,6 +39,42 @@ func addElementToTemplate(log *logrus.Entry, elementName string, value []byte, e
 	return nil
 }
 
+func AddRecordValuesToTemplate(log *logrus.Entry, elements *[]entities.InfoElementWithValue) error {
+	err := addElementToTemplate(log, "octetDeltaCount", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "tcpControlBits", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "flowStartSeconds", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "flowStartMilliseconds", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "flowEndSeconds", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "flowEndMilliseconds", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "packetDeltaCount", nil, elements)
+	if err != nil {
+		return err
+	}
+	err = addElementToTemplate(log, "interfaceName", nil, elements)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 func SendTemplateRecordv4(log *logrus.Entry, exporter *ipfixExporter.ExportingProcess) (uint16, []entities.InfoElementWithValue, error) {
 	templateID := exporter.NewTemplateID()
 	templateSet := entities.NewSet(false)
@@ -84,35 +120,10 @@ func SendTemplateRecordv4(log *logrus.Entry, exporter *ipfixExporter.ExportingPr
 	if err != nil {
 		return 0, nil, err
 	}
-	err = addElementToTemplate(log, "octetDeltaCount", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowStartSeconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowStartMilliseconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowEndSeconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowEndMilliseconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "packetDeltaCount", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "interfaceName", nil, &elements)
+	err = AddRecordValuesToTemplate(log, &elements)
 	if err != nil {
 		return 0, nil, err
 	}
-
 	err = templateSet.AddRecord(elements, templateID)
 	if err != nil {
 		return 0, nil, err
@@ -170,31 +181,7 @@ func SendTemplateRecordv6(log *logrus.Entry, exporter *ipfixExporter.ExportingPr
 	if err != nil {
 		return 0, nil, err
 	}
-	err = addElementToTemplate(log, "octetDeltaCount", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowStartSeconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowStartMilliseconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowEndSeconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "flowEndMilliseconds", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "packetDeltaCount", nil, &elements)
-	if err != nil {
-		return 0, nil, err
-	}
-	err = addElementToTemplate(log, "interfaceName", nil, &elements)
+	err = AddRecordValuesToTemplate(log, &elements)
 	if err != nil {
 		return 0, nil, err
 	}
@@ -262,6 +249,27 @@ func setIPv4Address(ieValPtr *entities.InfoElementWithValue, ipAddress net.IP) {
 		ieVal.SetIPAddressValue(ipAddress)
 	}
 }
+func setIERecordValue(record *flow.Record, ieValPtr *entities.InfoElementWithValue) {
+	ieVal := *ieValPtr
+	switch ieVal.GetName() {
+	case "octetDeltaCount":
+		ieVal.SetUnsigned64Value(record.Bytes)
+	case "tcpControlBits":
+		ieVal.SetUnsigned16Value(record.Flags)
+	case "flowStartSeconds":
+		ieVal.SetUnsigned32Value(uint32(record.TimeFlowStart.Unix()))
+	case "flowStartMilliseconds":
+		ieVal.SetUnsigned64Value(uint64(record.TimeFlowStart.UnixMilli()))
+	case "flowEndSeconds":
+		ieVal.SetUnsigned32Value(uint32(record.TimeFlowEnd.Unix()))
+	case "flowEndMilliseconds":
+		ieVal.SetUnsigned64Value(uint64(record.TimeFlowEnd.UnixMilli()))
+	case "packetDeltaCount":
+		ieVal.SetUnsigned64Value(uint64(record.Packets))
+	case "interfaceName":
+		ieVal.SetStringValue(record.Interface)
+	}
+}
 func setIEValue(record *flow.Record, ieValPtr *entities.InfoElementWithValue) {
 	ieVal := *ieValPtr
 	switch ieVal.GetName() {
@@ -289,26 +297,12 @@ func setIEValue(record *flow.Record, ieValPtr *entities.InfoElementWithValue) {
 		ieVal.SetUnsigned16Value(record.Transport.SrcPort)
 	case "destinationTransportPort":
 		ieVal.SetUnsigned16Value(record.Transport.DstPort)
-	case "octetDeltaCount":
-		ieVal.SetUnsigned64Value(record.Bytes)
-	case "flowStartSeconds":
-		ieVal.SetUnsigned32Value(uint32(record.TimeFlowStart.Unix()))
-	case "flowStartMilliseconds":
-		ieVal.SetUnsigned64Value(uint64(record.TimeFlowStart.UnixMilli()))
-	case "flowEndSeconds":
-		ieVal.SetUnsigned32Value(uint32(record.TimeFlowEnd.Unix()))
-	case "flowEndMilliseconds":
-		ieVal.SetUnsigned64Value(uint64(record.TimeFlowEnd.UnixMilli()))
-	case "packetDeltaCount":
-		ieVal.SetUnsigned64Value(uint64(record.Packets))
-	case "interfaceName":
-		ieVal.SetStringValue(record.Interface)
 	}
-
 }
 func setEntities(record *flow.Record, elements *[]entities.InfoElementWithValue) {
 	for _, ieVal := range *elements {
 		setIEValue(record, &ieVal)
+		setIERecordValue(record, &ieVal)
 	}
 }
 func (ipf *IPFIX) sendDataRecord(log *logrus.Entry, record *flow.Record, v6 bool) error {
diff --git a/pkg/exporter/kafka_proto_test.go b/pkg/exporter/kafka_proto_test.go
index 0093df1b..485b4c24 100644
--- a/pkg/exporter/kafka_proto_test.go
+++ b/pkg/exporter/kafka_proto_test.go
@@ -24,7 +24,7 @@ func IPAddrFromNetIP(netIP net.IP) flow.IPAddr {
 func TestProtoConversion(t *testing.T) {
 	wc := writerCapturer{}
 	kj := KafkaProto{Writer: &wc}
-	input := make(chan []*flow.Record, 10)
+	input := make(chan []*flow.Record, 11)
 	record := flow.Record{}
 	record.EthProtocol = 3
 	record.Direction = 1
@@ -39,6 +39,7 @@ func TestProtoConversion(t *testing.T) {
 	record.TimeFlowEnd = time.Now()
 	record.Bytes = 789
 	record.Packets = 987
+	record.Flags = uint16(1)
 	record.Interface = "veth0"
 
 	input <- []*flow.Record{&record}
@@ -61,6 +62,7 @@ func TestProtoConversion(t *testing.T) {
 	assert.Equal(t, record.TimeFlowEnd.UnixMilli(), r.TimeFlowEnd.AsTime().UnixMilli())
 	assert.EqualValues(t, 789, r.Bytes)
 	assert.EqualValues(t, 987, r.Packets)
+	assert.EqualValues(t, uint16(1), r.Flags)
 	assert.Equal(t, "veth0", r.Interface)
 }
 
diff --git a/pkg/exporter/proto.go b/pkg/exporter/proto.go
index a47048b9..f6374341 100644
--- a/pkg/exporter/proto.go
+++ b/pkg/exporter/proto.go
@@ -64,9 +64,10 @@ func v4FlowToPB(fr *flow.Record) *pbflow.Record {
 			Nanos:   int32(fr.TimeFlowEnd.Nanosecond()),
 		},
 		Packets:   uint64(fr.Packets),
-		Interface: fr.Interface,
 		Duplicate: fr.Duplicate,
 		AgentIp:   agentIP(fr.AgentIP),
+		Flags:     uint32(fr.Flags),
+		Interface: string(fr.Interface),
 	}
 }
 
@@ -97,6 +98,7 @@ func v6FlowToPB(fr *flow.Record) *pbflow.Record {
 			Nanos:   int32(fr.TimeFlowEnd.Nanosecond()),
 		},
 		Packets:   uint64(fr.Packets),
+		Flags:     uint32(fr.Flags),
 		Interface: fr.Interface,
 		Duplicate: fr.Duplicate,
 		AgentIp:   agentIP(fr.AgentIP),
diff --git a/pkg/flow/account_test.go b/pkg/flow/account_test.go
index 2bf2bf04..2e30ca79 100644
--- a/pkg/flow/account_test.go
+++ b/pkg/flow/account_test.go
@@ -55,19 +55,19 @@ func TestEvict_MaxEntries(t *testing.T) {
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 123, Packets: 1, StartMonoTimeNs: 123, EndMonoTimeNs: 123,
+			Bytes: 123, Packets: 1, StartMonoTimeNs: 123, EndMonoTimeNs: 123, Flags: 1,
 		},
 	}
 	inputs <- &RawRecord{
 		RecordKey: k2,
 		RecordMetrics: RecordMetrics{
-			Bytes: 456, Packets: 1, StartMonoTimeNs: 456, EndMonoTimeNs: 456,
+			Bytes: 456, Packets: 1, StartMonoTimeNs: 456, EndMonoTimeNs: 456, Flags: 1,
 		},
 	}
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 321, Packets: 1, StartMonoTimeNs: 789, EndMonoTimeNs: 789,
+			Bytes: 321, Packets: 1, StartMonoTimeNs: 789, EndMonoTimeNs: 789, Flags: 1,
 		},
 	}
 	requireNoEviction(t, evictor)
@@ -76,7 +76,7 @@ func TestEvict_MaxEntries(t *testing.T) {
 	inputs <- &RawRecord{
 		RecordKey: k3,
 		RecordMetrics: RecordMetrics{
-			Bytes: 111, Packets: 1, StartMonoTimeNs: 888, EndMonoTimeNs: 888,
+			Bytes: 111, Packets: 1, StartMonoTimeNs: 888, EndMonoTimeNs: 888, Flags: 1,
 		},
 	}
 
@@ -96,7 +96,7 @@ func TestEvict_MaxEntries(t *testing.T) {
 			RawRecord: RawRecord{
 				RecordKey: k1,
 				RecordMetrics: RecordMetrics{
-					Bytes: 444, Packets: 2, StartMonoTimeNs: 123, EndMonoTimeNs: 789,
+					Bytes: 444, Packets: 2, StartMonoTimeNs: 123, EndMonoTimeNs: 789, Flags: 1,
 				},
 			},
 			TimeFlowStart: now.Add(-(1000 - 123) * time.Nanosecond),
@@ -106,7 +106,7 @@ func TestEvict_MaxEntries(t *testing.T) {
 			RawRecord: RawRecord{
 				RecordKey: k2,
 				RecordMetrics: RecordMetrics{
-					Bytes: 456, Packets: 1, StartMonoTimeNs: 456, EndMonoTimeNs: 456,
+					Bytes: 456, Packets: 1, StartMonoTimeNs: 456, EndMonoTimeNs: 456, Flags: 1,
 				},
 			},
 			TimeFlowStart: now.Add(-(1000 - 456) * time.Nanosecond),
@@ -132,19 +132,19 @@ func TestEvict_Period(t *testing.T) {
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 10, Packets: 1, StartMonoTimeNs: 123, EndMonoTimeNs: 123,
+			Bytes: 10, Packets: 1, StartMonoTimeNs: 123, EndMonoTimeNs: 123, Flags: 1,
 		},
 	}
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 10, Packets: 1, StartMonoTimeNs: 456, EndMonoTimeNs: 456,
+			Bytes: 10, Packets: 1, StartMonoTimeNs: 456, EndMonoTimeNs: 456, Flags: 1,
 		},
 	}
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 10, Packets: 1, StartMonoTimeNs: 789, EndMonoTimeNs: 789,
+			Bytes: 10, Packets: 1, StartMonoTimeNs: 789, EndMonoTimeNs: 789, Flags: 1,
 		},
 	}
 	// Forcing at least one eviction here
@@ -152,13 +152,13 @@ func TestEvict_Period(t *testing.T) {
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 10, Packets: 1, StartMonoTimeNs: 1123, EndMonoTimeNs: 1123,
+			Bytes: 10, Packets: 1, StartMonoTimeNs: 1123, EndMonoTimeNs: 1123, Flags: 1,
 		},
 	}
 	inputs <- &RawRecord{
 		RecordKey: k1,
 		RecordMetrics: RecordMetrics{
-			Bytes: 10, Packets: 1, StartMonoTimeNs: 1456, EndMonoTimeNs: 1456,
+			Bytes: 10, Packets: 1, StartMonoTimeNs: 1456, EndMonoTimeNs: 1456, Flags: 1,
 		},
 	}
 
@@ -174,6 +174,7 @@ func TestEvict_Period(t *testing.T) {
 				Packets:         3,
 				StartMonoTimeNs: 123,
 				EndMonoTimeNs:   789,
+				Flags:           1,
 			},
 		},
 		TimeFlowStart: now.Add(-1000 + 123),
@@ -189,6 +190,7 @@ func TestEvict_Period(t *testing.T) {
 				Packets:         2,
 				StartMonoTimeNs: 1123,
 				EndMonoTimeNs:   1456,
+				Flags:           1,
 			},
 		},
 		TimeFlowStart: now.Add(-1000 + 1123),
diff --git a/pkg/flow/deduper_test.go b/pkg/flow/deduper_test.go
index 7f3176ff..ec359e7b 100644
--- a/pkg/flow/deduper_test.go
+++ b/pkg/flow/deduper_test.go
@@ -13,26 +13,26 @@ var (
 		EthProtocol: 1, Direction: 1, Transport: Transport{SrcPort: 123, DstPort: 456},
 		DataLink: DataLink{DstMac: MacAddr{0x1}, SrcMac: MacAddr{0x1}}, IFIndex: 1,
 	}, RecordMetrics: RecordMetrics{
-		Packets: 2, Bytes: 456,
+		Packets: 2, Bytes: 456, Flags: 1,
 	}}, Interface: "eth0"}
 	oneIf2 = &Record{RawRecord: RawRecord{RecordKey: RecordKey{
 		EthProtocol: 1, Direction: 1, Transport: Transport{SrcPort: 123, DstPort: 456},
 		DataLink: DataLink{DstMac: MacAddr{0x2}, SrcMac: MacAddr{0x2}}, IFIndex: 2,
 	}, RecordMetrics: RecordMetrics{
-		Packets: 2, Bytes: 456,
+		Packets: 2, Bytes: 456, Flags: 1,
 	}}, Interface: "123456789"}
 	// another fow from 2 different interfaces and directions
 	twoIf1 = &Record{RawRecord: RawRecord{RecordKey: RecordKey{
 		EthProtocol: 1, Direction: 1, Transport: Transport{SrcPort: 333, DstPort: 456},
 		DataLink: DataLink{DstMac: MacAddr{0x1}, SrcMac: MacAddr{0x1}}, IFIndex: 1,
 	}, RecordMetrics: RecordMetrics{
-		Packets: 2, Bytes: 456,
+		Packets: 2, Bytes: 456, Flags: 1,
 	}}, Interface: "eth0"}
 	twoIf2 = &Record{RawRecord: RawRecord{RecordKey: RecordKey{
 		EthProtocol: 1, Direction: 0, Transport: Transport{SrcPort: 333, DstPort: 456},
 		DataLink: DataLink{DstMac: MacAddr{0x2}, SrcMac: MacAddr{0x2}}, IFIndex: 2,
 	}, RecordMetrics: RecordMetrics{
-		Packets: 2, Bytes: 456,
+		Packets: 2, Bytes: 456, Flags: 1,
 	}}, Interface: "123456789"}
 )
 
diff --git a/pkg/flow/record.go b/pkg/flow/record.go
index 665f4ed2..4751c04c 100644
--- a/pkg/flow/record.go
+++ b/pkg/flow/record.go
@@ -65,8 +65,8 @@ type RecordMetrics struct {
 	// and monotime.Now() (user space)
 	StartMonoTimeNs uint64
 	EndMonoTimeNs   uint64
-
-	Errno uint8
+	Flags           uint16
+	Errno           uint8
 }
 
 // record structure as parsed from eBPF
@@ -124,6 +124,7 @@ func (r *RecordMetrics) Accumulate(src *RecordMetrics) {
 	}
 	r.Bytes += src.Bytes
 	r.Packets += src.Packets
+	r.Flags |= src.Flags
 }
 
 // IP returns the net.IP equivalent object
diff --git a/pkg/flow/record_test.go b/pkg/flow/record_test.go
index e26618aa..de782e71 100644
--- a/pkg/flow/record_test.go
+++ b/pkg/flow/record_test.go
@@ -26,7 +26,9 @@ func TestRecordBinaryEncoding(t *testing.T) {
 		0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, // u64 bytes
 		0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, // u64 flow_start_time
 		0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, // u64 flow_end_time
+		0x13, 0x14, //flags
 		0x33, // u8 errno
+
 	}))
 	require.NoError(t, err)
 
@@ -54,6 +56,7 @@ func TestRecordBinaryEncoding(t *testing.T) {
 			Bytes:           0x1a19181716151413,
 			StartMonoTimeNs: 0x1a19181716151413,
 			EndMonoTimeNs:   0x1a19181716151413,
+			Flags:           0x1413,
 			Errno:           0x33,
 		},
 	}, *fr)
diff --git a/pkg/flow/tracer_map_test.go b/pkg/flow/tracer_map_test.go
index 74c8c3d2..0518159e 100644
--- a/pkg/flow/tracer_map_test.go
+++ b/pkg/flow/tracer_map_test.go
@@ -14,23 +14,23 @@ func TestPacketAggregation(t *testing.T) {
 	}
 	tcs := []testCase{{
 		input: []RecordMetrics{
-			{Packets: 0, Bytes: 0, StartMonoTimeNs: 0, EndMonoTimeNs: 0},
-			{Packets: 0x7, Bytes: 0x22d, StartMonoTimeNs: 0x176a790b240b, EndMonoTimeNs: 0x176a792a755b},
-			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0},
-			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0},
+			{Packets: 0, Bytes: 0, StartMonoTimeNs: 0, EndMonoTimeNs: 0, Flags: 1},
+			{Packets: 0x7, Bytes: 0x22d, StartMonoTimeNs: 0x176a790b240b, EndMonoTimeNs: 0x176a792a755b, Flags: 1},
+			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0, Flags: 1},
+			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0, Flags: 1},
 		},
 		expected: RecordMetrics{
-			Packets: 0x7, Bytes: 0x22d, StartMonoTimeNs: 0x176a790b240b, EndMonoTimeNs: 0x176a792a755b,
+			Packets: 0x7, Bytes: 0x22d, StartMonoTimeNs: 0x176a790b240b, EndMonoTimeNs: 0x176a792a755b, Flags: 1,
 		},
 	}, {
 		input: []RecordMetrics{
-			{Packets: 0x3, Bytes: 0x5c4, StartMonoTimeNs: 0x17f3e9613a7f, EndMonoTimeNs: 0x17f3e979816e},
-			{Packets: 0x2, Bytes: 0x8c, StartMonoTimeNs: 0x17f3e9633a7f, EndMonoTimeNs: 0x17f3e96f164e},
-			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0},
-			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0},
+			{Packets: 0x3, Bytes: 0x5c4, StartMonoTimeNs: 0x17f3e9613a7f, EndMonoTimeNs: 0x17f3e979816e, Flags: 1},
+			{Packets: 0x2, Bytes: 0x8c, StartMonoTimeNs: 0x17f3e9633a7f, EndMonoTimeNs: 0x17f3e96f164e, Flags: 1},
+			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0, Flags: 1},
+			{Packets: 0x0, Bytes: 0x0, StartMonoTimeNs: 0x0, EndMonoTimeNs: 0x0, Flags: 1},
 		},
 		expected: RecordMetrics{
-			Packets: 0x5, Bytes: 0x5c4 + 0x8c, StartMonoTimeNs: 0x17f3e9613a7f, EndMonoTimeNs: 0x17f3e979816e,
+			Packets: 0x5, Bytes: 0x5c4 + 0x8c, StartMonoTimeNs: 0x17f3e9613a7f, EndMonoTimeNs: 0x17f3e979816e, Flags: 1,
 		},
 	}}
 	ft := MapTracer{}
diff --git a/pkg/grpc/grpc_test.go b/pkg/grpc/grpc_test.go
index eb2184ab..fb858433 100644
--- a/pkg/grpc/grpc_test.go
+++ b/pkg/grpc/grpc_test.go
@@ -29,7 +29,7 @@ func TestGRPCCommunication(t *testing.T) {
 	go func() {
 		_, err = client.Send(context.Background(),
 			&pbflow.Records{Entries: []*pbflow.Record{{
-				EthProtocol: 123, Bytes: 456, Network: &pbflow.Network{
+				EthProtocol: 123, Flags: 1, Bytes: 456, Network: &pbflow.Network{
 					SrcAddr: &pbflow.IP{
 						IpFamily: &pbflow.IP_Ipv4{Ipv4: 0x11223344},
 					},
@@ -43,7 +43,7 @@ func TestGRPCCommunication(t *testing.T) {
 		require.NoError(t, err)
 		_, err = client.Send(context.Background(),
 			&pbflow.Records{Entries: []*pbflow.Record{{
-				EthProtocol: 789, Bytes: 101, Network: &pbflow.Network{
+				EthProtocol: 789, Flags: 1, Bytes: 101, Network: &pbflow.Network{
 					SrcAddr: &pbflow.IP{
 						IpFamily: &pbflow.IP_Ipv4{Ipv4: 0x44332211},
 					},
@@ -66,6 +66,7 @@ func TestGRPCCommunication(t *testing.T) {
 	assert.Len(t, rs.Entries, 1)
 	r := rs.Entries[0]
 	assert.EqualValues(t, 123, r.EthProtocol)
+	assert.EqualValues(t, 1, r.Flags)
 	assert.EqualValues(t, 456, r.Bytes)
 	assert.EqualValues(t, 0x11223344, r.GetNetwork().GetSrcAddr().GetIpv4())
 	assert.EqualValues(t, 0x55667788, r.GetNetwork().GetDstAddr().GetIpv4())
@@ -78,6 +79,7 @@ func TestGRPCCommunication(t *testing.T) {
 	assert.Len(t, rs.Entries, 1)
 	r = rs.Entries[0]
 	assert.EqualValues(t, 789, r.EthProtocol)
+	assert.EqualValues(t, 1, r.Flags)
 	assert.EqualValues(t, 101, r.Bytes)
 	assert.EqualValues(t, 0x44332211, r.GetNetwork().GetSrcAddr().GetIpv4())
 	assert.EqualValues(t, uint64(0x88776655), r.GetNetwork().GetDstAddr().GetIpv4())
@@ -114,7 +116,7 @@ func TestConstructorOptions(t *testing.T) {
 
 	go func() {
 		_, err = client.Send(context.Background(),
-			&pbflow.Records{Entries: []*pbflow.Record{{EthProtocol: 123, Bytes: 456}}})
+			&pbflow.Records{Entries: []*pbflow.Record{{EthProtocol: 123, Bytes: 456, Flags: 1}}})
 		require.NoError(t, err)
 	}()
 
@@ -140,6 +142,7 @@ func BenchmarkGRPCCommunication(b *testing.B) {
 	f := &pbflow.Record{
 		EthProtocol:   2048,
 		Bytes:         456,
+		Flags:         1,
 		Direction:     pbflow.Direction_EGRESS,
 		TimeFlowStart: timestamppb.Now(),
 		TimeFlowEnd:   timestamppb.Now(),
diff --git a/pkg/pbflow/flow.pb.go b/pkg/pbflow/flow.pb.go
index 4458513e..6306ac87 100644
--- a/pkg/pbflow/flow.pb.go
+++ b/pkg/pbflow/flow.pb.go
@@ -1,15 +1,15 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.1
-// 	protoc        v3.19.4
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.12.4
 // source: proto/flow.proto
 
 package pbflow
 
 import (
+	timestamp "github.com/golang/protobuf/ptypes/timestamp"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
 	reflect "reflect"
 	sync "sync"
 )
@@ -162,10 +162,10 @@ type Record struct {
 
 	// protocol as defined by ETH_P_* in linux/if_ether.h
 	// https://github.com/torvalds/linux/blob/master/include/uapi/linux/if_ether.h
-	EthProtocol   uint32                 `protobuf:"varint,1,opt,name=eth_protocol,json=ethProtocol,proto3" json:"eth_protocol,omitempty"`
-	Direction     Direction              `protobuf:"varint,2,opt,name=direction,proto3,enum=pbflow.Direction" json:"direction,omitempty"`
-	TimeFlowStart *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time_flow_start,json=timeFlowStart,proto3" json:"time_flow_start,omitempty"`
-	TimeFlowEnd   *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time_flow_end,json=timeFlowEnd,proto3" json:"time_flow_end,omitempty"`
+	EthProtocol   uint32               `protobuf:"varint,1,opt,name=eth_protocol,json=ethProtocol,proto3" json:"eth_protocol,omitempty"`
+	Direction     Direction            `protobuf:"varint,2,opt,name=direction,proto3,enum=pbflow.Direction" json:"direction,omitempty"`
+	TimeFlowStart *timestamp.Timestamp `protobuf:"bytes,3,opt,name=time_flow_start,json=timeFlowStart,proto3" json:"time_flow_start,omitempty"`
+	TimeFlowEnd   *timestamp.Timestamp `protobuf:"bytes,4,opt,name=time_flow_end,json=timeFlowEnd,proto3" json:"time_flow_end,omitempty"`
 	// OSI-layer attributes
 	DataLink  *DataLink  `protobuf:"bytes,5,opt,name=data_link,json=dataLink,proto3" json:"data_link,omitempty"`
 	Network   *Network   `protobuf:"bytes,6,opt,name=network,proto3" json:"network,omitempty"`
@@ -177,7 +177,8 @@ type Record struct {
 	// From all the duplicate flows, one will set this value to false and the rest will be true.
 	Duplicate bool `protobuf:"varint,11,opt,name=duplicate,proto3" json:"duplicate,omitempty"`
 	// Agent IP address to help identifying the source of the flow
-	AgentIp *IP `protobuf:"bytes,12,opt,name=agent_ip,json=agentIp,proto3" json:"agent_ip,omitempty"`
+	AgentIp *IP    `protobuf:"bytes,12,opt,name=agent_ip,json=agentIp,proto3" json:"agent_ip,omitempty"`
+	Flags   uint32 `protobuf:"varint,13,opt,name=flags,proto3" json:"flags,omitempty"`
 }
 
 func (x *Record) Reset() {
@@ -226,14 +227,14 @@ func (x *Record) GetDirection() Direction {
 	return Direction_INGRESS
 }
 
-func (x *Record) GetTimeFlowStart() *timestamppb.Timestamp {
+func (x *Record) GetTimeFlowStart() *timestamp.Timestamp {
 	if x != nil {
 		return x.TimeFlowStart
 	}
 	return nil
 }
 
-func (x *Record) GetTimeFlowEnd() *timestamppb.Timestamp {
+func (x *Record) GetTimeFlowEnd() *timestamp.Timestamp {
 	if x != nil {
 		return x.TimeFlowEnd
 	}
@@ -296,6 +297,13 @@ func (x *Record) GetAgentIp() *IP {
 	return nil
 }
 
+func (x *Record) GetFlags() uint32 {
+	if x != nil {
+		return x.Flags
+	}
+	return 0
+}
+
 type DataLink struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -562,7 +570,7 @@ var file_proto_flow_proto_rawDesc = []byte{
 	0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72,
 	0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x66, 0x6c,
 	0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69,
-	0x65, 0x73, 0x22, 0xfe, 0x03, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a,
+	0x65, 0x73, 0x22, 0x94, 0x04, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a,
 	0x0c, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
 	0x12, 0x2f, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
@@ -594,34 +602,35 @@ var file_proto_flow_proto_rawDesc = []byte{
 	0x08, 0x52, 0x09, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x08,
 	0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a,
 	0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e,
-	0x74, 0x49, 0x70, 0x22, 0x3c, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x12,
-	0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f,
-	0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x64, 0x73, 0x74, 0x4d, 0x61,
-	0x63, 0x22, 0x57, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x25, 0x0a, 0x08,
-	0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a,
-	0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41,
-	0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49,
-	0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50,
-	0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00,
-	0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09,
-	0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61,
-	0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f,
-	0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72,
-	0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2a, 0x24, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53,
-	0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x32, 0x3e,
-	0x0a, 0x09, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x04, 0x53,
-	0x65, 0x6e, 0x64, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63,
-	0x6f, 0x72, 0x64, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f,
-	0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a,
-	0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x33,
+	0x74, 0x49, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0d, 0x20, 0x01,
+	0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x3c, 0x0a, 0x08, 0x44, 0x61, 0x74,
+	0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, 0x61, 0x63,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, 0x12, 0x17,
+	0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x06, 0x64, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x22, 0x57, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f,
+	0x72, 0x6b, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50,
+	0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74,
+	0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62,
+	0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72,
+	0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x14, 0x0a, 0x04,
+	0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70,
+	0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22,
+	0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08,
+	0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
+	0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70,
+	0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f,
+	0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2a, 0x24,
+	0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49,
+	0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45,
+	0x53, 0x53, 0x10, 0x01, 0x32, 0x3e, 0x0a, 0x09, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f,
+	0x72, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x66, 0x6c,
+	0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x66,
+	0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -639,15 +648,15 @@ func file_proto_flow_proto_rawDescGZIP() []byte {
 var file_proto_flow_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_proto_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
 var file_proto_flow_proto_goTypes = []interface{}{
-	(Direction)(0),                // 0: pbflow.Direction
-	(*CollectorReply)(nil),        // 1: pbflow.CollectorReply
-	(*Records)(nil),               // 2: pbflow.Records
-	(*Record)(nil),                // 3: pbflow.Record
-	(*DataLink)(nil),              // 4: pbflow.DataLink
-	(*Network)(nil),               // 5: pbflow.Network
-	(*IP)(nil),                    // 6: pbflow.IP
-	(*Transport)(nil),             // 7: pbflow.Transport
-	(*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
+	(Direction)(0),              // 0: pbflow.Direction
+	(*CollectorReply)(nil),      // 1: pbflow.CollectorReply
+	(*Records)(nil),             // 2: pbflow.Records
+	(*Record)(nil),              // 3: pbflow.Record
+	(*DataLink)(nil),            // 4: pbflow.DataLink
+	(*Network)(nil),             // 5: pbflow.Network
+	(*IP)(nil),                  // 6: pbflow.IP
+	(*Transport)(nil),           // 7: pbflow.Transport
+	(*timestamp.Timestamp)(nil), // 8: google.protobuf.Timestamp
 }
 var file_proto_flow_proto_depIdxs = []int32{
 	3,  // 0: pbflow.Records.entries:type_name -> pbflow.Record
diff --git a/pkg/pbflow/flow_grpc.pb.go b/pkg/pbflow/flow_grpc.pb.go
index 11aee366..9b91b5ef 100644
--- a/pkg/pbflow/flow_grpc.pb.go
+++ b/pkg/pbflow/flow_grpc.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
 // - protoc-gen-go-grpc v1.2.0
-// - protoc             v3.19.4
+// - protoc             v3.12.4
 // source: proto/flow.proto
 
 package pbflow
diff --git a/proto/flow.proto b/proto/flow.proto
index 8b5994ee..9e291f72 100644
--- a/proto/flow.proto
+++ b/proto/flow.proto
@@ -40,6 +40,7 @@ message Record {
 
   // Agent IP address to help identifying the source of the flow
   IP agent_ip = 12;
+  uint32 flags = 13;
 }
 
 message DataLink {
-- 
GitLab