github.com/cilium/cilium@v1.16.2/pkg/hubble/observer/local_observer.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package observer
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"strings"
    12  	"sync/atomic"
    13  
    14  	"github.com/sirupsen/logrus"
    15  	"google.golang.org/grpc/codes"
    16  	"google.golang.org/grpc/status"
    17  	"google.golang.org/protobuf/types/known/timestamppb"
    18  
    19  	flowpb "github.com/cilium/cilium/api/v1/flow"
    20  	observerpb "github.com/cilium/cilium/api/v1/observer"
    21  	v1 "github.com/cilium/cilium/pkg/hubble/api/v1"
    22  	"github.com/cilium/cilium/pkg/hubble/build"
    23  	"github.com/cilium/cilium/pkg/hubble/container"
    24  	"github.com/cilium/cilium/pkg/hubble/filters"
    25  	"github.com/cilium/cilium/pkg/hubble/observer/observeroption"
    26  	observerTypes "github.com/cilium/cilium/pkg/hubble/observer/types"
    27  	"github.com/cilium/cilium/pkg/hubble/parser"
    28  	parserErrors "github.com/cilium/cilium/pkg/hubble/parser/errors"
    29  	"github.com/cilium/cilium/pkg/hubble/parser/fieldmask"
    30  	nodeTypes "github.com/cilium/cilium/pkg/node/types"
    31  	"github.com/cilium/cilium/pkg/time"
    32  )
    33  
    34  // DefaultOptions to include in the server. Other packages may extend this
    35  // in their init() function.
    36  var DefaultOptions []observeroption.Option
    37  
    38  // LocalObserverServer is an implementation of the server.Observer interface
    39  // that's meant to be run embedded inside the Cilium process. It ignores all
    40  // the state change events since the state is available locally.
    41  type LocalObserverServer struct {
    42  	// ring buffer that contains the references of all flows
    43  	ring *container.Ring
    44  
    45  	// events is the channel used by the writer(s) to send the flow data
    46  	// into the observer server.
    47  	events chan *observerTypes.MonitorEvent
    48  
    49  	// stopped is mostly used in unit tests to signalize when the events
    50  	// channel is empty, once it's closed.
    51  	stopped chan struct{}
    52  
    53  	log logrus.FieldLogger
    54  
    55  	// payloadParser decodes flowpb.Payload into flowpb.Flow
    56  	payloadParser parser.Decoder
    57  
    58  	opts observeroption.Options
    59  
    60  	// startTime is the time when this instance was started
    61  	startTime time.Time
    62  
    63  	// numObservedFlows counts how many flows have been observed
    64  	numObservedFlows atomic.Uint64
    65  
    66  	namespaceManager NamespaceManager
    67  }
    68  
    69  // NewLocalServer returns a new local observer server.
    70  func NewLocalServer(
    71  	payloadParser parser.Decoder,
    72  	namespaceManager NamespaceManager,
    73  	logger logrus.FieldLogger,
    74  	options ...observeroption.Option,
    75  ) (*LocalObserverServer, error) {
    76  	opts := observeroption.Default // start with defaults
    77  	options = append(options, DefaultOptions...)
    78  	for _, opt := range options {
    79  		if err := opt(&opts); err != nil {
    80  			return nil, fmt.Errorf("failed to apply option: %w", err)
    81  		}
    82  	}
    83  
    84  	logger.WithFields(logrus.Fields{
    85  		"maxFlows":       opts.MaxFlows,
    86  		"eventQueueSize": opts.MonitorBuffer,
    87  	}).Info("Configuring Hubble server")
    88  
    89  	s := &LocalObserverServer{
    90  		log:              logger,
    91  		ring:             container.NewRing(opts.MaxFlows),
    92  		events:           make(chan *observerTypes.MonitorEvent, opts.MonitorBuffer),
    93  		stopped:          make(chan struct{}),
    94  		payloadParser:    payloadParser,
    95  		startTime:        time.Now(),
    96  		namespaceManager: namespaceManager,
    97  		opts:             opts,
    98  	}
    99  
   100  	for _, f := range s.opts.OnServerInit {
   101  		err := f.OnServerInit(s)
   102  		if err != nil {
   103  			s.log.WithError(err).Error("failed in OnServerInit")
   104  			return nil, err
   105  		}
   106  	}
   107  
   108  	return s, nil
   109  }
   110  
   111  // Start implements GRPCServer.Start.
   112  func (s *LocalObserverServer) Start() {
   113  	// We use a cancellation context here so that any goroutines spawned in the
   114  	// OnMonitorEvent/OnDecodedFlow/OnDecodedEvent hooks have a signal for cancellation.
   115  	// When Start() returns, the deferred cancel() will run and we expect hooks
   116  	// to stop any goroutines that may have spawned by listening to the
   117  	// ctx.Done() channel for the stop signal.
   118  	ctx, cancel := context.WithCancel(context.Background())
   119  	defer cancel()
   120  
   121  nextEvent:
   122  	for monitorEvent := range s.GetEventsChannel() {
   123  		for _, f := range s.opts.OnMonitorEvent {
   124  			stop, err := f.OnMonitorEvent(ctx, monitorEvent)
   125  			if err != nil {
   126  				s.log.WithError(err).WithField("event", monitorEvent).Info("failed in OnMonitorEvent")
   127  			}
   128  			if stop {
   129  				continue nextEvent
   130  			}
   131  		}
   132  
   133  		ev, err := s.payloadParser.Decode(monitorEvent)
   134  		if err != nil {
   135  			switch {
   136  			case
   137  				// silently ignore unknown or skipped events
   138  				errors.Is(err, parserErrors.ErrUnknownEventType),
   139  				errors.Is(err, parserErrors.ErrEventSkipped),
   140  				// silently ignore perf ring buffer events with unknown types,
   141  				// since they are not intended for us (e.g. MessageTypeRecCapture)
   142  				parserErrors.IsErrInvalidType(err):
   143  			default:
   144  				s.log.WithError(err).WithField("event", monitorEvent).Debug("failed to decode payload")
   145  			}
   146  			continue
   147  		}
   148  
   149  		if flow, ok := ev.Event.(*flowpb.Flow); ok {
   150  			// track namespaces seen.
   151  			s.trackNamespaces(flow)
   152  			for _, f := range s.opts.OnDecodedFlow {
   153  				stop, err := f.OnDecodedFlow(ctx, flow)
   154  				if err != nil {
   155  					s.log.WithError(err).WithField("event", monitorEvent).Info("failed in OnDecodedFlow")
   156  				}
   157  				if stop {
   158  					continue nextEvent
   159  				}
   160  			}
   161  
   162  			s.numObservedFlows.Add(1)
   163  		}
   164  
   165  		for _, f := range s.opts.OnDecodedEvent {
   166  			stop, err := f.OnDecodedEvent(ctx, ev)
   167  			if err != nil {
   168  				s.log.WithError(err).WithField("event", ev).Info("failed in OnDecodedEvent")
   169  			}
   170  			if stop {
   171  				continue nextEvent
   172  			}
   173  		}
   174  		s.GetRingBuffer().Write(ev)
   175  	}
   176  	close(s.GetStopped())
   177  }
   178  
   179  // GetEventsChannel returns the event channel to receive flowpb.Payload events.
   180  func (s *LocalObserverServer) GetEventsChannel() chan *observerTypes.MonitorEvent {
   181  	return s.events
   182  }
   183  
   184  // GetRingBuffer implements GRPCServer.GetRingBuffer.
   185  func (s *LocalObserverServer) GetRingBuffer() *container.Ring {
   186  	return s.ring
   187  }
   188  
   189  // GetLogger implements GRPCServer.GetLogger.
   190  func (s *LocalObserverServer) GetLogger() logrus.FieldLogger {
   191  	return s.log
   192  }
   193  
   194  // GetStopped implements GRPCServer.GetStopped.
   195  func (s *LocalObserverServer) GetStopped() chan struct{} {
   196  	return s.stopped
   197  }
   198  
   199  // GetPayloadParser implements GRPCServer.GetPayloadParser.
   200  func (s *LocalObserverServer) GetPayloadParser() parser.Decoder {
   201  	return s.payloadParser
   202  }
   203  
   204  // GetOptions implements serveroptions.Server.GetOptions.
   205  func (s *LocalObserverServer) GetOptions() observeroption.Options {
   206  	return s.opts
   207  }
   208  
   209  // ServerStatus should have a comment, apparently. It returns the server status.
   210  func (s *LocalObserverServer) ServerStatus(
   211  	ctx context.Context, req *observerpb.ServerStatusRequest,
   212  ) (*observerpb.ServerStatusResponse, error) {
   213  
   214  	rate, err := getFlowRate(s.GetRingBuffer(), time.Now())
   215  	if err != nil {
   216  		s.log.WithError(err).Warn("Failed to get flow rate")
   217  	}
   218  
   219  	return &observerpb.ServerStatusResponse{
   220  		Version:   build.ServerVersion.String(),
   221  		MaxFlows:  s.GetRingBuffer().Cap(),
   222  		NumFlows:  s.GetRingBuffer().Len(),
   223  		SeenFlows: s.numObservedFlows.Load(),
   224  		UptimeNs:  uint64(time.Since(s.startTime).Nanoseconds()),
   225  		FlowsRate: rate,
   226  	}, nil
   227  }
   228  
   229  // GetNodes implements observerpb.ObserverClient.GetNodes.
   230  func (s *LocalObserverServer) GetNodes(ctx context.Context, req *observerpb.GetNodesRequest) (*observerpb.GetNodesResponse, error) {
   231  	return nil, status.Errorf(codes.Unimplemented, "GetNodes not implemented")
   232  }
   233  
   234  // GetNamespaces implements observerpb.ObserverClient.GetNamespaces.
   235  func (s *LocalObserverServer) GetNamespaces(ctx context.Context, req *observerpb.GetNamespacesRequest) (*observerpb.GetNamespacesResponse, error) {
   236  	return &observerpb.GetNamespacesResponse{Namespaces: s.namespaceManager.GetNamespaces()}, nil
   237  }
   238  
   239  // GetFlows implements the proto method for client requests.
   240  func (s *LocalObserverServer) GetFlows(
   241  	req *observerpb.GetFlowsRequest,
   242  	server observerpb.Observer_GetFlowsServer,
   243  ) (err error) {
   244  	if err := validateRequest(req); err != nil {
   245  		return err
   246  	}
   247  	// This context is used for goroutines spawned specifically to serve this
   248  	// request, meaning it must be cancelled once the request is done and this
   249  	// function returns.
   250  	ctx, cancel := context.WithCancel(server.Context())
   251  	defer cancel()
   252  
   253  	for _, f := range s.opts.OnGetFlows {
   254  		ctx, err = f.OnGetFlows(ctx, req)
   255  		if err != nil {
   256  			return err
   257  		}
   258  	}
   259  
   260  	log := s.GetLogger()
   261  	filterList := append(filters.DefaultFilters(log), s.opts.OnBuildFilter...)
   262  	whitelist, err := filters.BuildFilterList(ctx, req.Whitelist, filterList)
   263  	if err != nil {
   264  		return err
   265  	}
   266  	blacklist, err := filters.BuildFilterList(ctx, req.Blacklist, filterList)
   267  	if err != nil {
   268  		return err
   269  	}
   270  
   271  	start := time.Now()
   272  	ring := s.GetRingBuffer()
   273  
   274  	i := uint64(0)
   275  	defer func() {
   276  		log.WithFields(logrus.Fields{
   277  			"number_of_flows": i,
   278  			"buffer_size":     ring.Cap(),
   279  			"whitelist":       logFilters(req.Whitelist),
   280  			"blacklist":       logFilters(req.Blacklist),
   281  			"took":            time.Since(start),
   282  		}).Debug("GetFlows finished")
   283  	}()
   284  
   285  	ringReader, err := newRingReader(ring, req, whitelist, blacklist)
   286  	if err != nil {
   287  		if errors.Is(err, io.EOF) {
   288  			return nil
   289  		}
   290  		return err
   291  	}
   292  
   293  	eventsReader, err := newEventsReader(ringReader, req, log, whitelist, blacklist)
   294  	if err != nil {
   295  		return err
   296  	}
   297  
   298  	fm := req.GetFieldMask()
   299  	if len(fm.GetPaths()) == 0 {
   300  		// TODO: Remove req.Experimental.GetFieldMask after v1.17
   301  		fm = req.Experimental.GetFieldMask()
   302  	}
   303  	mask, err := fieldmask.New(fm)
   304  	if err != nil {
   305  		return err
   306  	}
   307  
   308  	var flow *flowpb.Flow
   309  	if mask.Active() {
   310  		flow = new(flowpb.Flow)
   311  		mask.Alloc(flow.ProtoReflect())
   312  	}
   313  
   314  nextEvent:
   315  	for ; ; i++ {
   316  		e, err := eventsReader.Next(ctx)
   317  		if err != nil {
   318  			if errors.Is(err, io.EOF) {
   319  				return nil
   320  			}
   321  			return err
   322  		}
   323  
   324  		var resp *observerpb.GetFlowsResponse
   325  
   326  		switch ev := e.Event.(type) {
   327  		case *flowpb.Flow:
   328  			eventsReader.eventCount++
   329  			for _, f := range s.opts.OnFlowDelivery {
   330  				stop, err := f.OnFlowDelivery(ctx, ev)
   331  				switch {
   332  				case err != nil:
   333  					return err
   334  				case stop:
   335  					continue nextEvent
   336  				}
   337  			}
   338  			if mask.Active() {
   339  				// Copy only fields in the mask
   340  				mask.Copy(flow.ProtoReflect(), ev.ProtoReflect())
   341  				ev = flow
   342  			}
   343  			resp = &observerpb.GetFlowsResponse{
   344  				Time:     ev.GetTime(),
   345  				NodeName: ev.GetNodeName(),
   346  				ResponseTypes: &observerpb.GetFlowsResponse_Flow{
   347  					Flow: ev,
   348  				},
   349  			}
   350  		case *flowpb.LostEvent:
   351  			// Don't increment eventsReader.eventCount as a LostEvent is an
   352  			// event type that is never explicitly requested by the user (e.g.
   353  			// when a query asks for 20 events, then lost events should not be
   354  			// accounted for as they are not events per se but an indication
   355  			// that some event was lost).
   356  			resp = &observerpb.GetFlowsResponse{
   357  				Time:     e.Timestamp,
   358  				NodeName: nodeTypes.GetAbsoluteNodeName(),
   359  				ResponseTypes: &observerpb.GetFlowsResponse_LostEvents{
   360  					LostEvents: ev,
   361  				},
   362  			}
   363  		}
   364  
   365  		if resp == nil {
   366  			continue
   367  		}
   368  
   369  		err = server.Send(resp)
   370  		if err != nil {
   371  			return err
   372  		}
   373  	}
   374  }
   375  
   376  // GetAgentEvents implements observerpb.ObserverClient.GetAgentEvents.
   377  func (s *LocalObserverServer) GetAgentEvents(
   378  	req *observerpb.GetAgentEventsRequest,
   379  	server observerpb.Observer_GetAgentEventsServer,
   380  ) (err error) {
   381  	if err := validateRequest(req); err != nil {
   382  		return err
   383  	}
   384  
   385  	ctx, cancel := context.WithCancel(server.Context())
   386  	defer cancel()
   387  
   388  	var whitelist, blacklist filters.FilterFuncs
   389  
   390  	start := time.Now()
   391  	log := s.GetLogger()
   392  	ring := s.GetRingBuffer()
   393  
   394  	i := uint64(0)
   395  	defer func() {
   396  		log.WithFields(logrus.Fields{
   397  			"number_of_agent_events": i,
   398  			"buffer_size":            ring.Cap(),
   399  			"took":                   time.Since(start),
   400  		}).Debug("GetAgentEvents finished")
   401  	}()
   402  
   403  	ringReader, err := newRingReader(ring, req, whitelist, blacklist)
   404  	if err != nil {
   405  		if errors.Is(err, io.EOF) {
   406  			return nil
   407  		}
   408  		return err
   409  	}
   410  
   411  	eventsReader, err := newEventsReader(ringReader, req, log, whitelist, blacklist)
   412  	if err != nil {
   413  		return err
   414  	}
   415  
   416  	for ; ; i++ {
   417  		e, err := eventsReader.Next(ctx)
   418  		if err != nil {
   419  			if errors.Is(err, io.EOF) {
   420  				return nil
   421  			}
   422  			return err
   423  		}
   424  
   425  		switch ev := e.Event.(type) {
   426  		case *flowpb.AgentEvent:
   427  			eventsReader.eventCount++
   428  			resp := &observerpb.GetAgentEventsResponse{
   429  				Time:       e.Timestamp,
   430  				NodeName:   nodeTypes.GetAbsoluteNodeName(),
   431  				AgentEvent: ev,
   432  			}
   433  			err = server.Send(resp)
   434  			if err != nil {
   435  				return err
   436  			}
   437  		}
   438  	}
   439  }
   440  
   441  // GetDebugEvents implements observerpb.ObserverClient.GetDebugEvents.
   442  func (s *LocalObserverServer) GetDebugEvents(
   443  	req *observerpb.GetDebugEventsRequest,
   444  	server observerpb.Observer_GetDebugEventsServer,
   445  ) (err error) {
   446  	if err := validateRequest(req); err != nil {
   447  		return err
   448  	}
   449  
   450  	ctx, cancel := context.WithCancel(server.Context())
   451  	defer cancel()
   452  
   453  	var whitelist, blacklist filters.FilterFuncs
   454  
   455  	start := time.Now()
   456  	log := s.GetLogger()
   457  	ring := s.GetRingBuffer()
   458  
   459  	i := uint64(0)
   460  	defer func() {
   461  		log.WithFields(logrus.Fields{
   462  			"number_of_debug_events": i,
   463  			"buffer_size":            ring.Cap(),
   464  			"took":                   time.Since(start),
   465  		}).Debug("GetDebugEvents finished")
   466  	}()
   467  
   468  	ringReader, err := newRingReader(ring, req, whitelist, blacklist)
   469  	if err != nil {
   470  		if errors.Is(err, io.EOF) {
   471  			return nil
   472  		}
   473  		return err
   474  	}
   475  
   476  	eventsReader, err := newEventsReader(ringReader, req, log, whitelist, blacklist)
   477  	if err != nil {
   478  		return err
   479  	}
   480  
   481  	for ; ; i++ {
   482  		e, err := eventsReader.Next(ctx)
   483  		if err != nil {
   484  			if errors.Is(err, io.EOF) {
   485  				return nil
   486  			}
   487  			return err
   488  		}
   489  
   490  		switch ev := e.Event.(type) {
   491  		case *flowpb.DebugEvent:
   492  			eventsReader.eventCount++
   493  			resp := &observerpb.GetDebugEventsResponse{
   494  				Time:       e.Timestamp,
   495  				NodeName:   nodeTypes.GetAbsoluteNodeName(),
   496  				DebugEvent: ev,
   497  			}
   498  			err = server.Send(resp)
   499  			if err != nil {
   500  				return err
   501  			}
   502  		}
   503  	}
   504  }
   505  
   506  func logFilters(filters []*flowpb.FlowFilter) string {
   507  	s := make([]string, 0, len(filters))
   508  	for _, f := range filters {
   509  		s = append(s, f.String())
   510  	}
   511  	return "{" + strings.Join(s, ",") + "}"
   512  }
   513  
   514  // genericRequest allows to abstract away generic request information for
   515  // GetFlowsRequest, GetAgentEventsRequest and GetDebugEventsRequest.
   516  type genericRequest interface {
   517  	GetNumber() uint64
   518  	GetFollow() bool
   519  	GetSince() *timestamppb.Timestamp
   520  	GetUntil() *timestamppb.Timestamp
   521  	GetFirst() bool
   522  }
   523  
   524  var (
   525  	_ genericRequest = (*observerpb.GetFlowsRequest)(nil)
   526  	_ genericRequest = (*observerpb.GetAgentEventsRequest)(nil)
   527  	_ genericRequest = (*observerpb.GetDebugEventsRequest)(nil)
   528  )
   529  
   530  // eventsReader reads flows using a RingReader. It applies the GetFlows request
   531  // criteria (blacklist, whitelist, follow, ...) before returning events.
   532  type eventsReader struct {
   533  	ringReader           *container.RingReader
   534  	whitelist, blacklist filters.FilterFuncs
   535  	maxEvents            uint64
   536  	follow, timeRange    bool
   537  	eventCount           uint64
   538  	since, until         *time.Time
   539  }
   540  
   541  // newEventsReader creates a new eventsReader that uses the given RingReader to
   542  // read through the ring buffer. Only events that match the request criteria
   543  // are returned.
   544  func newEventsReader(r *container.RingReader, req genericRequest, log logrus.FieldLogger, whitelist, blacklist filters.FilterFuncs) (*eventsReader, error) {
   545  	log.WithFields(logrus.Fields{
   546  		"req":       req,
   547  		"whitelist": whitelist,
   548  		"blacklist": blacklist,
   549  	}).Debug("creating a new eventsReader")
   550  
   551  	since, until := req.GetSince(), req.GetUntil()
   552  	reader := &eventsReader{
   553  		ringReader: r,
   554  		whitelist:  whitelist,
   555  		blacklist:  blacklist,
   556  		maxEvents:  req.GetNumber(),
   557  		follow:     req.GetFollow(),
   558  		timeRange:  since != nil || until != nil,
   559  	}
   560  
   561  	if since != nil {
   562  		if err := since.CheckValid(); err != nil {
   563  			return nil, err
   564  		}
   565  		sinceTime := since.AsTime()
   566  		reader.since = &sinceTime
   567  	}
   568  
   569  	if until != nil {
   570  		if err := until.CheckValid(); err != nil {
   571  			return nil, err
   572  		}
   573  		untilTime := until.AsTime()
   574  		reader.until = &untilTime
   575  	}
   576  
   577  	return reader, nil
   578  }
   579  
   580  // Next returns the next event that matches the request criteria.
   581  func (r *eventsReader) Next(ctx context.Context) (*v1.Event, error) {
   582  	for {
   583  		select {
   584  		case <-ctx.Done():
   585  			return nil, ctx.Err()
   586  		default:
   587  		}
   588  		var e *v1.Event
   589  		var err error
   590  		if r.follow {
   591  			e = r.ringReader.NextFollow(ctx)
   592  		} else {
   593  			if r.maxEvents > 0 && (r.eventCount >= r.maxEvents) {
   594  				return nil, io.EOF
   595  			}
   596  			e, err = r.ringReader.Next()
   597  			if err != nil {
   598  				return nil, err
   599  			}
   600  		}
   601  		if e == nil {
   602  			return nil, io.EOF
   603  		}
   604  
   605  		// Treat LostEvent as a special case as callers will never explicitly
   606  		// request them. This means that no regular filter nor time range
   607  		// filter should be applied.
   608  		// Note: lost events don't respect the assumption that "ring buffer
   609  		// timestamps are supposed to be monotonic" as their timestamp
   610  		// corresponds to when a LostEvent was detected.
   611  		_, isLostEvent := e.Event.(*flowpb.LostEvent)
   612  		if !isLostEvent {
   613  			if r.timeRange {
   614  				if err := e.Timestamp.CheckValid(); err != nil {
   615  					return nil, err
   616  				}
   617  				ts := e.Timestamp.AsTime()
   618  
   619  				if r.until != nil && ts.After(*r.until) {
   620  					return nil, io.EOF
   621  				}
   622  
   623  				if r.since != nil && ts.Before(*r.since) {
   624  					continue
   625  				}
   626  			}
   627  
   628  			if !filters.Apply(r.whitelist, r.blacklist, e) {
   629  				continue
   630  			}
   631  		}
   632  
   633  		return e, nil
   634  	}
   635  }
   636  
   637  func (s *LocalObserverServer) trackNamespaces(flow *flowpb.Flow) {
   638  	// track namespaces seen.
   639  	if srcNs := flow.GetSource().GetNamespace(); srcNs != "" {
   640  		s.namespaceManager.AddNamespace(&observerpb.Namespace{
   641  			Namespace: srcNs,
   642  			Cluster:   nodeTypes.GetClusterName(),
   643  		})
   644  	}
   645  	if dstNs := flow.GetDestination().GetNamespace(); dstNs != "" {
   646  		s.namespaceManager.AddNamespace(&observerpb.Namespace{
   647  			Namespace: dstNs,
   648  			Cluster:   nodeTypes.GetClusterName(),
   649  		})
   650  	}
   651  }
   652  
   653  func validateRequest(req genericRequest) error {
   654  	if req.GetFirst() && req.GetFollow() {
   655  		return status.Errorf(codes.InvalidArgument, "first cannot be specified with follow")
   656  	}
   657  	return nil
   658  }
   659  
   660  // newRingReader creates a new RingReader that starts at the correct ring
   661  // offset to match the flow request.
   662  func newRingReader(ring *container.Ring, req genericRequest, whitelist, blacklist filters.FilterFuncs) (*container.RingReader, error) {
   663  	since := req.GetSince()
   664  
   665  	// since takes precedence over Number (--first and --last)
   666  	if req.GetFirst() && since == nil {
   667  		// Start from the beginning of the ring.
   668  		return container.NewRingReader(ring, ring.OldestWrite()), nil
   669  	}
   670  
   671  	if req.GetFollow() && req.GetNumber() == 0 && since == nil {
   672  		// no need to rewind
   673  		return container.NewRingReader(ring, ring.LastWriteParallel()), nil
   674  	}
   675  
   676  	var sinceTime time.Time
   677  	if since != nil {
   678  		if err := since.CheckValid(); err != nil {
   679  			return nil, err
   680  		}
   681  		sinceTime = since.AsTime()
   682  	}
   683  
   684  	idx := ring.LastWriteParallel()
   685  	reader := container.NewRingReader(ring, idx)
   686  
   687  	var eventCount uint64
   688  	// We need to find out what the right index is; that is the index with the
   689  	// oldest entry that is within time range boundaries (if any is defined)
   690  	// or until we find enough events.
   691  	// In order to avoid buffering events, we have to rewind first to find the
   692  	// correct index, then create a new reader that starts from there
   693  	for i := ring.Len(); i > 0; i, idx = i-1, idx-1 {
   694  		e, err := reader.Previous()
   695  		lost := e.GetLostEvent()
   696  		if lost != nil && lost.Source == flowpb.LostEventSource_HUBBLE_RING_BUFFER {
   697  			idx++ // we went backward 1 too far
   698  			break
   699  		} else if err != nil {
   700  			return nil, err
   701  		}
   702  		// Note: LostEvent type is ignored here and this is expected as lost
   703  		// events will never be explicitly requested by the caller
   704  		_, isLostEvent := e.Event.(*flowpb.LostEvent)
   705  		if isLostEvent || !filters.Apply(whitelist, blacklist, e) {
   706  			continue
   707  		}
   708  		eventCount++
   709  		if since != nil {
   710  			if err := e.Timestamp.CheckValid(); err != nil {
   711  				return nil, err
   712  			}
   713  			ts := e.Timestamp.AsTime()
   714  			if ts.Before(sinceTime) {
   715  				idx++ // we went backward 1 too far
   716  				break
   717  			}
   718  		} else if eventCount == req.GetNumber() {
   719  			break // we went backward far enough
   720  		}
   721  	}
   722  	return container.NewRingReader(ring, idx), nil
   723  }
   724  
   725  func getFlowRate(ring *container.Ring, at time.Time) (float64, error) {
   726  	reader := container.NewRingReader(ring, ring.LastWriteParallel())
   727  	count := 0
   728  	since := at.Add(-1 * time.Minute)
   729  	var lastSeenEvent *v1.Event
   730  	for {
   731  		e, err := reader.Previous()
   732  		lost := e.GetLostEvent()
   733  		if lost != nil && lost.Source == flowpb.LostEventSource_HUBBLE_RING_BUFFER {
   734  			// a lost event means we read the complete ring buffer
   735  			// if we read at least one flow, update `since` to calculate the rate over the available time range
   736  			if lastSeenEvent != nil {
   737  				since = lastSeenEvent.Timestamp.AsTime()
   738  			}
   739  			break
   740  		} else if errors.Is(err, io.EOF) {
   741  			// an EOF error means the ring buffer is empty, ignore error and continue
   742  			break
   743  		} else if err != nil {
   744  			// unexpected error
   745  			return 0, err
   746  		}
   747  		if _, isFlowEvent := e.Event.(*flowpb.Flow); !isFlowEvent {
   748  			// ignore non flow events
   749  			continue
   750  		}
   751  		if err := e.Timestamp.CheckValid(); err != nil {
   752  			return 0, err
   753  		}
   754  		ts := e.Timestamp.AsTime()
   755  		if ts.Before(since) {
   756  			// scanned the last minute, exit loop
   757  			break
   758  		}
   759  		lastSeenEvent = e
   760  		count++
   761  	}
   762  	return float64(count) / at.Sub(since).Seconds(), nil
   763  }