diff --git a/pkg/ebpf/bpf_bpfeb.o b/pkg/ebpf/bpf_bpfeb.o
index 92303ee5b710b77162cc4a4ebdea73096ff99b66..b606e40943a81445fb93153d1c64678ddf091639 100644
Binary files a/pkg/ebpf/bpf_bpfeb.o and b/pkg/ebpf/bpf_bpfeb.o differ
diff --git a/pkg/ebpf/bpf_bpfel.o b/pkg/ebpf/bpf_bpfel.o
index 4e3eb08e6013c0cb8dee3457fb206dfb289988a3..3e563be5bf9bf32c326400fadfa82b30382904ef 100644
Binary files a/pkg/ebpf/bpf_bpfel.o and b/pkg/ebpf/bpf_bpfel.o differ
diff --git a/pkg/ebpf/tracer.go b/pkg/ebpf/tracer.go
index c59cab71155515ac9e5f7fc0bd10040fce7febb8..f9ff359557a3b4e271fd6ed1d2257ee4a49f7bf4 100644
--- a/pkg/ebpf/tracer.go
+++ b/pkg/ebpf/tracer.go
@@ -6,12 +6,14 @@ import (
 	"io/fs"
 	"strings"
 
+	"github.com/netobserv/netobserv-ebpf-agent/pkg/ifaces"
+	"github.com/netobserv/netobserv-ebpf-agent/pkg/utils"
+
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/btf"
 	"github.com/cilium/ebpf/link"
 	"github.com/cilium/ebpf/ringbuf"
 	"github.com/cilium/ebpf/rlimit"
-	"github.com/netobserv/netobserv-ebpf-agent/pkg/ifaces"
 	"github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 	"golang.org/x/sys/unix"
@@ -29,6 +31,8 @@ const (
 	constSampling      = "sampling"
 	constTraceMessages = "trace_messages"
 	constEnableRtt     = "enable_rtt"
+	tcpDropHook        = "kfree_skb"
+	dnsTraceHook       = "net_dev_queue"
 )
 
 var log = logrus.WithField("component", "ebpf.FlowFetcher")
@@ -105,14 +109,53 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) {
 		return nil, fmt.Errorf("rewriting BPF constants definition: %w", err)
 	}
 
-	if err := spec.LoadAndAssign(&objects, nil); err != nil {
-		var ve *ebpf.VerifierError
-		if errors.As(err, &ve) {
-			// Using %+v will print the whole verifier error, not just the last
-			// few lines.
-			log.Infof("Verifier error: %+v", ve)
+	oldKernel := utils.IskernelOlderthan514()
+
+	// For older kernel (< 5.14) kfree_sbk drop hook doesn't exists
+	if oldKernel {
+		// Here we define another structure similar to the bpf2go created one but w/o the hooks that does not exist in older kernel
+		// Note: if new hooks are added in the future we need to update the following structures manually
+		type NewBpfPrograms struct {
+			EgressFlowParse  *ebpf.Program `ebpf:"egress_flow_parse"`
+			IngressFlowParse *ebpf.Program `ebpf:"ingress_flow_parse"`
+			TraceNetPackets  *ebpf.Program `ebpf:"trace_net_packets"`
+		}
+		type NewBpfObjects struct {
+			NewBpfPrograms
+			BpfMaps
+		}
+		var newObjects NewBpfObjects
+		// remove tcpdrop hook from the spec
+		delete(spec.Programs, tcpDropHook)
+		newObjects.NewBpfPrograms = NewBpfPrograms{}
+		if err := spec.LoadAndAssign(&newObjects, nil); err != nil {
+			var ve *ebpf.VerifierError
+			if errors.As(err, &ve) {
+				// Using %+v will print the whole verifier error, not just the last
+				// few lines.
+				log.Infof("Verifier error: %+v", ve)
+			}
+			return nil, fmt.Errorf("loading and assigning BPF objects: %w", err)
+		}
+		// Manually assign maps and programs to the original objects variable
+		// Note for any future maps or programs make sure to copy them manually here
+		objects.DirectFlows = newObjects.DirectFlows
+		objects.AggregatedFlows = newObjects.AggregatedFlows
+		objects.FlowSequences = newObjects.FlowSequences
+		objects.EgressFlowParse = newObjects.EgressFlowParse
+		objects.IngressFlowParse = newObjects.IngressFlowParse
+		objects.TraceNetPackets = newObjects.TraceNetPackets
+		objects.KfreeSkb = nil
+	} else {
+		if err := spec.LoadAndAssign(&objects, nil); err != nil {
+			var ve *ebpf.VerifierError
+			if errors.As(err, &ve) {
+				// Using %+v will print the whole verifier error, not just the last
+				// few lines.
+				log.Infof("Verifier error: %+v", ve)
+			}
+			return nil, fmt.Errorf("loading and assigning BPF objects: %w", err)
 		}
-		return nil, fmt.Errorf("loading and assigning BPF objects: %w", err)
 	}
 
 	/*
@@ -123,8 +166,8 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) {
 	btf.FlushKernelSpec()
 
 	var tcpDropsLink link.Link
-	if cfg.TCPDrops {
-		tcpDropsLink, err = link.Tracepoint("skb", "kfree_skb", objects.KfreeSkb, nil)
+	if cfg.TCPDrops && !oldKernel {
+		tcpDropsLink, err = link.Tracepoint("skb", tcpDropHook, objects.KfreeSkb, nil)
 		if err != nil {
 			return nil, fmt.Errorf("failed to attach the BPF program to kfree_skb tracepoint: %w", err)
 		}
@@ -132,7 +175,7 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) {
 
 	var dnsTrackerLink link.Link
 	if cfg.DNSTracker {
-		dnsTrackerLink, err = link.Tracepoint("net", "net_dev_queue", objects.TraceNetPackets, nil)
+		dnsTrackerLink, err = link.Tracepoint("net", dnsTraceHook, objects.TraceNetPackets, nil)
 		if err != nil {
 			return nil, fmt.Errorf("failed to attach the BPF program to trace_net_packets: %w", err)
 		}
diff --git a/pkg/pbflow/flow.pb.go b/pkg/pbflow/flow.pb.go
index c14ac8d33ad8755c1ee730146baebc13138468d5..846d7467b8e50b3924cc8164a32bc56ed99e7e91 100644
--- a/pkg/pbflow/flow.pb.go
+++ b/pkg/pbflow/flow.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.30.0
-// 	protoc        v3.19.4
+// 	protoc-gen-go v1.25.0-devel
+// 	protoc        v3.14.0
 // source: proto/flow.proto
 
 package pbflow
diff --git a/pkg/pbflow/flow_grpc.pb.go b/pkg/pbflow/flow_grpc.pb.go
index fccb880954ed93e893e8284125931954f4962fb1..6b2e9616cc2f543ee6833cfee36292cdfb3a7d2c 100644
--- a/pkg/pbflow/flow_grpc.pb.go
+++ b/pkg/pbflow/flow_grpc.pb.go
@@ -1,8 +1,4 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-// versions:
-// - protoc-gen-go-grpc v1.3.0
-// - protoc             v3.19.4
-// source: proto/flow.proto
 
 package pbflow
 
@@ -18,10 +14,6 @@ import (
 // Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
-const (
-	Collector_Send_FullMethodName = "/pbflow.Collector/Send"
-)
-
 // CollectorClient is the client API for Collector service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -39,7 +31,7 @@ func NewCollectorClient(cc grpc.ClientConnInterface) CollectorClient {
 
 func (c *collectorClient) Send(ctx context.Context, in *Records, opts ...grpc.CallOption) (*CollectorReply, error) {
 	out := new(CollectorReply)
-	err := c.cc.Invoke(ctx, Collector_Send_FullMethodName, in, out, opts...)
+	err := c.cc.Invoke(ctx, "/pbflow.Collector/Send", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -84,7 +76,7 @@ func _Collector_Send_Handler(srv interface{}, ctx context.Context, dec func(inte
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: Collector_Send_FullMethodName,
+		FullMethod: "/pbflow.Collector/Send",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(CollectorServer).Send(ctx, req.(*Records))
diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go
index f0cb22cf3b643153e8da12c9b5f0f7f210f855a1..1c67d70e762c88704457b4ff172973acd2deed36 100644
--- a/pkg/utils/utils.go
+++ b/pkg/utils/utils.go
@@ -3,6 +3,17 @@ package utils
 import (
 	"fmt"
 	"net"
+	"regexp"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/sirupsen/logrus"
+)
+
+var (
+	getCurrentKernelVersion = currentKernelVersion
+	log                     = logrus.WithField("component", "utils")
 )
 
 // GetSocket returns socket string in the correct format based on address family
@@ -14,3 +25,69 @@ func GetSocket(hostIP string, hostPort int) string {
 	}
 	return socket
 }
+
+func IskernelOlderthan514() bool {
+	kernelVersion514, err := kernelVersionFromReleaseString("5.14.0")
+	if err != nil {
+		log.Warnf("failed to get kernel version from release string: %v", err)
+		return false
+	}
+	currentVersion, err := getCurrentKernelVersion()
+	if err != nil {
+		log.Warnf("failed to get current kernel version: %v", err)
+		return false
+	}
+	if currentVersion < kernelVersion514 {
+		log.Infof("older kernel version not all hooks will be supported")
+		return true
+	}
+	return false
+}
+
+var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+).(\d+).*$`)
+
+// kernelVersionFromReleaseString converts a release string with format
+// 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format.
+// That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c)
+func kernelVersionFromReleaseString(releaseString string) (uint32, error) {
+	versionParts := versionRegex.FindStringSubmatch(releaseString)
+	if len(versionParts) != 4 {
+		return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString)
+	}
+	major, err := strconv.Atoi(versionParts[1])
+	if err != nil {
+		return 0, err
+	}
+
+	minor, err := strconv.Atoi(versionParts[2])
+	if err != nil {
+		return 0, err
+	}
+
+	patch, err := strconv.Atoi(versionParts[3])
+	if err != nil {
+		return 0, err
+	}
+	out := major*256*256 + minor*256 + patch
+	return uint32(out), nil
+}
+
+func currentKernelVersion() (uint32, error) {
+	var buf syscall.Utsname
+	if err := syscall.Uname(&buf); err != nil {
+		return 0, err
+	}
+	releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00")
+	return kernelVersionFromReleaseString(releaseString)
+}
+
+func utsnameStr(in []int8) string {
+	out := make([]byte, len(in))
+	for i := 0; i < len(in); i++ {
+		if in[i] == 0 {
+			break
+		}
+		out = append(out, byte(in[i]))
+	}
+	return string(out)
+}
diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8f212a8d4033eb58a3dfffc0cb80414780f2aba4
--- /dev/null
+++ b/pkg/utils/utils_test.go
@@ -0,0 +1,55 @@
+package utils
+
+import (
+	"errors"
+	"testing"
+)
+
+func TestIskernelOlderthan514(t *testing.T) {
+	tests := []struct {
+		name              string
+		mockKernelVersion func() (uint32, error)
+		want              bool
+	}{
+		{
+			name: "Kernel version < 5.14.0",
+			mockKernelVersion: func() (uint32, error) {
+				ver, _ := kernelVersionFromReleaseString("5.13.0")
+				return ver, nil
+			},
+			want: true,
+		},
+		{
+			name: "Kernel version = 5.14.0",
+			mockKernelVersion: func() (uint32, error) {
+				ver, _ := kernelVersionFromReleaseString("5.14.0")
+				return ver, nil
+			},
+			want: false,
+		},
+		{
+			name: "Kernel version > 5.14.0",
+			mockKernelVersion: func() (uint32, error) {
+				ver, _ := kernelVersionFromReleaseString("5.15.0")
+				return ver, nil
+			},
+			want: false,
+		},
+		{
+			name: "Error getting kernel version",
+			mockKernelVersion: func() (uint32, error) {
+				return 0, errors.New("error")
+			},
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			getCurrentKernelVersion = tt.mockKernelVersion
+			got := IskernelOlderthan514()
+			if got != tt.want {
+				t.Errorf("%s: IskernelOlderthan514() = %v, want %v", tt.name, got, tt.want)
+			}
+		})
+	}
+}