99 "strings"
1010 "sync"
1111 "sync/atomic"
12+ "syscall"
1213 "time"
1314
1415 "github.com/cilium/ebpf/ringbuf"
@@ -28,6 +29,7 @@ const (
2829 qdiscType = "clsact"
2930 // constants defined in flows.c as "volatile const"
3031 constSampling = "sampling"
32+ constTraceMessages = "trace_messages"
3133 aggregatedFlowsMap = "aggregated_flows"
3234)
3335
@@ -50,10 +52,17 @@ type FlowTracer struct {
5052 cacheMaxSize int
5153 enableIngress bool
5254 enableEgress bool
55+ // ringBuf supports atomic logging of ringBuffer metrics
56+ ringBuf struct {
57+ isForwarding int32
58+ forwardedFlows int32
59+ mapFullErrs int32
60+ }
5361}
5462
5563// TODO: decouple flowtracer logic from eBPF maps access so we can inject mocks for testing
5664func NewFlowTracer (
65+ traceMessages bool ,
5766 sampling , cacheMaxSize , buffersLength int ,
5867 evictionTimeout time.Duration ,
5968 ingress , egress bool ,
@@ -73,8 +82,13 @@ func NewFlowTracer(
7382 // Resize aggregated flows map according to user-provided configuration
7483 spec .Maps [aggregatedFlowsMap ].MaxEntries = uint32 (cacheMaxSize )
7584
85+ traceMsgs := 0
86+ if traceMessages {
87+ traceMsgs = 1
88+ }
7689 if err := spec .RewriteConstants (map [string ]interface {}{
77- constSampling : uint32 (sampling ),
90+ constSampling : uint32 (sampling ),
91+ constTraceMessages : uint8 (traceMsgs ),
7892 }); err != nil {
7993 return nil , fmt .Errorf ("rewriting BPF constants definition: %w" , err )
8094 }
@@ -376,8 +390,7 @@ func (m *FlowTracer) Trace(ctx context.Context, forwardFlows chan<- []*flow.Reco
376390func (m * FlowTracer ) listenAndForwardRingBuffer (ctx context.Context , forwardFlows chan <- []* flow.Record ) {
377391 flowAccount := make (chan * flow.RawRecord , m .buffersLength )
378392 go m .accounter .Account (flowAccount , forwardFlows )
379- isForwarding := int32 (0 )
380- forwardedFlows := int32 (0 )
393+ debugging := logrus .IsLevelEnabled (logrus .DebugLevel )
381394 for {
382395 select {
383396 case <- ctx .Done ():
@@ -399,11 +412,15 @@ func (m *FlowTracer) listenAndForwardRingBuffer(ctx context.Context, forwardFlow
399412 log .WithError (err ).Warn ("reading ringbuf event" )
400413 continue
401414 }
402- if logrus .IsLevelEnabled (logrus .DebugLevel ) {
403- m .logRingBufferFlows (& forwardedFlows , & isForwarding )
415+ mapFullError := readFlow .Errno == uint8 (syscall .E2BIG )
416+ if debugging {
417+ m .logRingBufferFlows (mapFullError )
404418 }
419+ // if the flow was received due to lack of space in the eBPF map
405420 // forces a flow's eviction to leave room for new flows in the ebpf cache
406- m .flowsEvictor .Broadcast ()
421+ if mapFullError {
422+ m .flowsEvictor .Broadcast ()
423+ }
407424
408425 // Will need to send it to accounter anyway to account regardless of complete/ongoing flow
409426 flowAccount <- readFlow
@@ -413,17 +430,28 @@ func (m *FlowTracer) listenAndForwardRingBuffer(ctx context.Context, forwardFlow
413430
414431// logRingBufferFlows avoids flooding logs on long series of evicted flows by grouping how
415432// many flows are forwarded
416- func (m * FlowTracer ) logRingBufferFlows (forwardedFlows , isForwarding * int32 ) {
417- atomic .AddInt32 (forwardedFlows , 1 )
418- if atomic .CompareAndSwapInt32 (isForwarding , 0 , 1 ) {
433+ func (m * FlowTracer ) logRingBufferFlows (mapFullErr bool ) {
434+ atomic .AddInt32 (& m .ringBuf .forwardedFlows , 1 )
435+ if mapFullErr {
436+ atomic .AddInt32 (& m .ringBuf .mapFullErrs , 1 )
437+ }
438+ if atomic .CompareAndSwapInt32 (& m .ringBuf .isForwarding , 0 , 1 ) {
419439 go func () {
420440 time .Sleep (m .evictionTimeout )
421- log .WithFields (logrus.Fields {
422- "flows" : atomic .LoadInt32 (forwardedFlows ),
441+ mfe := atomic .LoadInt32 (& m .ringBuf .mapFullErrs )
442+ l := log .WithFields (logrus.Fields {
443+ "flows" : atomic .LoadInt32 (& m .ringBuf .forwardedFlows ),
444+ "mapFullErrs" : mfe ,
423445 "cacheMaxFlows" : m .cacheMaxSize ,
424- }).Debug ("received flows via ringbuffer. You might want to increase the CACHE_MAX_FLOWS value" )
425- atomic .StoreInt32 (forwardedFlows , 0 )
426- atomic .StoreInt32 (isForwarding , 0 )
446+ })
447+ if mfe == 0 {
448+ l .Debug ("received flows via ringbuffer" )
449+ } else {
450+ l .Debug ("received flows via ringbuffer. You might want to increase the CACHE_MAX_FLOWS value" )
451+ }
452+ atomic .StoreInt32 (& m .ringBuf .forwardedFlows , 0 )
453+ atomic .StoreInt32 (& m .ringBuf .isForwarding , 0 )
454+ atomic .StoreInt32 (& m .ringBuf .mapFullErrs , 0 )
427455 }()
428456 }
429457}
0 commit comments