Skip to content
Snippets Groups Projects
Unverified Commit 2d9657e2 authored by Mohamed S. Mahmoud's avatar Mohamed S. Mahmoud Committed by GitHub
Browse files

Fix older kernel handling for Fentry (#374)


* Fix older kernel handling for Fentry

Signed-off-by: default avatarMohamed Mahmoud <mmahmoud@redhat.com>

* update grpc components

Signed-off-by: default avatarMohamed Mahmoud <mmahmoud@redhat.com>

---------

Signed-off-by: default avatarMohamed Mahmoud <mmahmoud@redhat.com>
parent 7b7dc40a
No related branches found
No related tags found
No related merge requests found
......@@ -3,7 +3,7 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/netobserv/netobserv-ebpf-agent)](https://goreportcard.com/report/github.com/netobserv/netobserv-ebpf-agent)
The Network Observability eBPF Agent allows collecting and aggregating all the ingress and
egress flows on a Linux host (required a Kernel 4.18+ with eBPF enabled).
egress flows on a Linux host (required a Kernel 5.8+ with eBPF enabled).
* [How to build](#how-to-build)
* [How to configure](#how-to-configure)
......
......@@ -45,6 +45,7 @@ const (
pcaRecordsMap = "packet_record"
tcEgressFilterName = "tc/tc_egress_flow_parse"
tcIngressFilterName = "tc/tc_ingress_flow_parse"
tcpFentryHook = "tcp_rcv_fentry"
)
var log = logrus.WithField("component", "ebpf.FlowFetcher")
......@@ -85,6 +86,7 @@ type FlowFetcherConfig struct {
FilterConfig *FilterConfig
}
// nolint:cyclop
func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) {
if err := rlimit.RemoveMemlock(); err != nil {
log.WithError(err).
......@@ -168,19 +170,26 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) {
var rttFentryLink, rttKprobeLink link.Link
if cfg.EnableRTT {
rttFentryLink, err = link.AttachTracing(link.TracingOptions{
Program: objects.BpfPrograms.TcpRcvFentry,
})
if err != nil {
log.Warningf("failed to attach the BPF program to tcpReceiveFentry: %v fallback to use kprobe", err)
// try to use kprobe for older kernels
rttKprobeLink, err = link.Kprobe("tcp_rcv_established", objects.TcpRcvKprobe, nil)
if !oldKernel {
rttFentryLink, err = link.AttachTracing(link.TracingOptions{
Program: objects.BpfPrograms.TcpRcvFentry,
})
if err == nil {
goto next
}
if err != nil {
return nil, fmt.Errorf("failed to attach the BPF program to tcpReceiveKprobe: %w", err)
log.Warningf("failed to attach the BPF program to tcpReceiveFentry: %v fallback to use kprobe", err)
// Fall through to use kprobe
}
}
// try to use kprobe for older kernels
rttKprobeLink, err = link.Kprobe("tcp_rcv_established", objects.TcpRcvKprobe, nil)
if err != nil {
log.Warningf("failed to attach the BPF program to kprobe: %v", err)
return nil, fmt.Errorf("failed to attach the BPF program to tcpReceiveKprobe: %w", err)
}
}
next:
// read events from igress+egress ringbuffer
flows, err := ringbuf.NewReader(objects.DirectFlows)
if err != nil {
......@@ -717,7 +726,6 @@ func kernelSpecificLoadAndAssign(oldKernel bool, spec *ebpf.CollectionSpec) (Bpf
TcIngressPcaParse *ebpf.Program `ebpf:"tc_ingress_pca_parse"`
TcxEgressPcaParse *ebpf.Program `ebpf:"tcx_egress_pca_parse"`
TcxIngressPcaParse *ebpf.Program `ebpf:"tcx_ingress_pca_parse"`
TCPRcvFentry *ebpf.Program `ebpf:"tcp_rcv_fentry"`
TCPRcvKprobe *ebpf.Program `ebpf:"tcp_rcv_kprobe"`
}
type NewBpfObjects struct {
......@@ -727,6 +735,8 @@ func kernelSpecificLoadAndAssign(oldKernel bool, spec *ebpf.CollectionSpec) (Bpf
var newObjects NewBpfObjects
// remove pktdrop hook from the spec
delete(spec.Programs, pktDropHook)
// remove fentry hook from the spec
delete(spec.Programs, tcpFentryHook)
newObjects.NewBpfPrograms = NewBpfPrograms{}
if err := spec.LoadAndAssign(&newObjects, nil); err != nil {
var ve *ebpf.VerifierError
......@@ -752,8 +762,8 @@ func kernelSpecificLoadAndAssign(oldKernel bool, spec *ebpf.CollectionSpec) (Bpf
objects.TcIngressPcaParse = newObjects.TcIngressPcaParse
objects.TcxEgressPcaParse = newObjects.TcxEgressPcaParse
objects.TcxIngressPcaParse = newObjects.TcxIngressPcaParse
objects.TcpRcvFentry = newObjects.TCPRcvFentry
objects.TcpRcvKprobe = newObjects.TCPRcvKprobe
objects.TcpRcvFentry = nil
objects.KfreeSkb = nil
} else {
if err := spec.LoadAndAssign(&objects, nil); err != nil {
......
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.4.0
// - protoc-gen-go-grpc v1.5.1
// - protoc v3.19.4
// source: proto/flow.proto
......@@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.62.0 or later.
const _ = grpc.SupportPackageIsVersion8
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Collector_Send_FullMethodName = "/pbflow.Collector/Send"
......@@ -49,20 +49,24 @@ func (c *collectorClient) Send(ctx context.Context, in *Records, opts ...grpc.Ca
// CollectorServer is the server API for Collector service.
// All implementations must embed UnimplementedCollectorServer
// for forward compatibility
// for forward compatibility.
type CollectorServer interface {
Send(context.Context, *Records) (*CollectorReply, error)
mustEmbedUnimplementedCollectorServer()
}
// UnimplementedCollectorServer must be embedded to have forward compatible implementations.
type UnimplementedCollectorServer struct {
}
// UnimplementedCollectorServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedCollectorServer struct{}
func (UnimplementedCollectorServer) Send(context.Context, *Records) (*CollectorReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Send not implemented")
}
func (UnimplementedCollectorServer) mustEmbedUnimplementedCollectorServer() {}
func (UnimplementedCollectorServer) testEmbeddedByValue() {}
// UnsafeCollectorServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to CollectorServer will
......@@ -72,6 +76,13 @@ type UnsafeCollectorServer interface {
}
func RegisterCollectorServer(s grpc.ServiceRegistrar, srv CollectorServer) {
// If the following call pancis, it indicates UnimplementedCollectorServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Collector_ServiceDesc, srv)
}
......
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.4.0
// - protoc-gen-go-grpc v1.5.1
// - protoc v3.19.4
// source: proto/packet.proto
......@@ -15,8 +15,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.62.0 or later.
const _ = grpc.SupportPackageIsVersion8
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Collector_Send_FullMethodName = "/pbpacket.Collector/Send"
......@@ -49,20 +49,24 @@ func (c *collectorClient) Send(ctx context.Context, in *Packet, opts ...grpc.Cal
// CollectorServer is the server API for Collector service.
// All implementations must embed UnimplementedCollectorServer
// for forward compatibility
// for forward compatibility.
type CollectorServer interface {
Send(context.Context, *Packet) (*CollectorReply, error)
mustEmbedUnimplementedCollectorServer()
}
// UnimplementedCollectorServer must be embedded to have forward compatible implementations.
type UnimplementedCollectorServer struct {
}
// UnimplementedCollectorServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedCollectorServer struct{}
func (UnimplementedCollectorServer) Send(context.Context, *Packet) (*CollectorReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Send not implemented")
}
func (UnimplementedCollectorServer) mustEmbedUnimplementedCollectorServer() {}
func (UnimplementedCollectorServer) testEmbeddedByValue() {}
// UnsafeCollectorServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to CollectorServer will
......@@ -72,6 +76,13 @@ type UnsafeCollectorServer interface {
}
func RegisterCollectorServer(s grpc.ServiceRegistrar, srv CollectorServer) {
// If the following call pancis, it indicates UnimplementedCollectorServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Collector_ServiceDesc, srv)
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment