From 668f371b70f1150c1464b21476a5475fcce64be2 Mon Sep 17 00:00:00 2001 From: Santhosh Fernandes Date: Wed, 22 May 2024 03:15:28 +0530 Subject: [PATCH] Enable support for ebpf program type Probes Signed-off-by: Santhosh Fernandes --- docs/docs.go | 14 +++++ docs/swagger.json | 14 +++++ docs/swagger.yaml | 10 ++++ kf/bpf.go | 114 +++++++++++++++----------------------- kf/kfmetrics.go | 29 ++++++++-- kf/kfmetrics_test.go | 3 +- kf/nfconfig.go | 118 +++++++++++++++++++++++++++++++++++++++- kf/probes.go | 55 +++++++++++++++++++ kf/processCheck.go | 63 ++++++++++++++++++++- kf/processCheck_test.go | 3 +- models/l3afd.go | 2 + 11 files changed, 344 insertions(+), 81 deletions(-) create mode 100644 kf/probes.go diff --git a/docs/docs.go b/docs/docs.go index f9c70c3e..55b8aa25 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -312,6 +312,13 @@ const docTemplate = `{ "models.BPFProgramNames": { "type": "object", "properties": { + "probes": { + "description": "names of the probe eBPF programs", + "type": "array", + "items": { + "type": "string" + } + }, "tc_egress": { "description": "names of the TC egress eBPF programs", "type": "array", @@ -338,6 +345,13 @@ const docTemplate = `{ "models.BPFPrograms": { "type": "object", "properties": { + "probes": { + "description": "list of probe bpf programs", + "type": "array", + "items": { + "$ref": "#/definitions/models.BPFProgram" + } + }, "tc_egress": { "description": "list of tc egress bpf programs", "type": "array", diff --git a/docs/swagger.json b/docs/swagger.json index f77a7b48..1d5c8576 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -305,6 +305,13 @@ "models.BPFProgramNames": { "type": "object", "properties": { + "probes": { + "description": "names of the probe eBPF programs", + "type": "array", + "items": { + "type": "string" + } + }, "tc_egress": { "description": "names of the TC egress eBPF programs", "type": "array", @@ -331,6 +338,13 @@ "models.BPFPrograms": { "type": "object", "properties": { + "probes": { + "description": "list of probe bpf programs", + "type": "array", + "items": { + "$ref": "#/definitions/models.BPFProgram" + } + }, "tc_egress": { "description": "list of tc egress bpf programs", "type": "array", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index efeb2e86..52d0bcbb 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -106,6 +106,11 @@ definitions: type: object models.BPFProgramNames: properties: + probes: + description: names of the probe eBPF programs + items: + type: string + type: array tc_egress: description: names of the TC egress eBPF programs items: @@ -124,6 +129,11 @@ definitions: type: object models.BPFPrograms: properties: + probes: + description: list of probe bpf programs + items: + $ref: '#/definitions/models.BPFProgram' + type: array tc_egress: description: list of tc egress bpf programs items: diff --git a/kf/bpf.go b/kf/bpf.go index 74f5424c..216b2162 100644 --- a/kf/bpf.go +++ b/kf/bpf.go @@ -81,9 +81,6 @@ func NewBpfProgram(ctx context.Context, program models.BPFProgram, conf *config. progMapFilePath = filepath.Join(conf.BpfMapDefaultPath, ifaceName, program.MapName) } else if program.ProgType == models.TCType { progMapFilePath = filepath.Join(conf.BpfMapDefaultPath, models.TCMapPinPath, ifaceName, program.MapName) - } else { - log.Error().Msgf("unsupported program type - %s", program.ProgType) - return nil } if strings.Contains(progMapFilePath, "..") { log.Error().Msgf("program map file contains relative path %s", progMapFilePath) @@ -292,9 +289,12 @@ func (b *BPF) Stop(ifaceName, direction string, chain bool) error { } args := make([]string, 0, len(b.Program.StopArgs)<<1) - args = append(args, "--iface="+ifaceName) // detaching from iface - args = append(args, "--direction="+direction) // xdpingress or ingress or egress - + if len(ifaceName) > 0 { + args = append(args, "--iface="+ifaceName) // detaching from iface + } + if len(direction) > 0 { + args = append(args, "--direction="+direction) // xdpingress or ingress or egress + } for k, val := range b.Program.StopArgs { if v, ok := val.(string); !ok { err := fmt.Errorf("stop args is not a string for the bpf program %s", b.Program.Name) @@ -1063,12 +1063,6 @@ func (b *BPF) LoadXDPAttachProgram(ifaceName string) error { // UnloadProgram - Unload or detach the program from the interface and close all the program resources func (b *BPF) UnloadProgram(ifaceName, direction string) error { - _, err := net.InterfaceByName(ifaceName) - if err != nil { - log.Error().Err(err).Msgf("UnloadProgram - look up network iface %q", ifaceName) - return err - } - // Verifying program attached to the interface. // SeqID will be 0 for root program or any other program without chaining if b.Program.SeqID == 0 || !b.hostConfig.BpfChainingEnabled { @@ -1198,7 +1192,7 @@ func (b *BPF) LoadBPFProgram(ifaceName string) error { var mapPinPath string if b.Program.ProgType == models.TCType { mapPinPath = filepath.Join(b.hostConfig.BpfMapDefaultPath, models.TCMapPinPath, ifaceName) - } else { + } else if b.Program.ProgType == models.XDPType { mapPinPath = filepath.Join(b.hostConfig.BpfMapDefaultPath, ifaceName) } collOptions := ebpf.CollectionOptions{ @@ -1220,31 +1214,33 @@ func (b *BPF) LoadBPFProgram(ifaceName string) error { return fmt.Errorf("LoadBPFProgramProbeTypes failed with error %v ", err) } - bpfProg := prg.Programs[b.Program.EntryFunctionName] - if bpfProg == nil { - return fmt.Errorf("%s entry function is not found in the loaded object file of the program %s", b.Program.EntryFunctionName, b.Program.Name) - } + //var bpfProg *ebpf.Program + if len(b.Program.EntryFunctionName) > 0 { + bpfProg := prg.Programs[b.Program.EntryFunctionName] + if bpfProg == nil { + return fmt.Errorf("%s entry function is not found in the loaded object file of the program %s", b.Program.EntryFunctionName, b.Program.Name) + } - progInfo, err := bpfProg.Info() - if err != nil { - return fmt.Errorf("%s: information of bpf program failed : %w", b.Program.Name, err) - } + progInfo, err := bpfProg.Info() + if err != nil { + return fmt.Errorf("%s: information of bpf program failed : %w", b.Program.Name, err) + } - ok := false - b.ProgID, ok = progInfo.ID() - if !ok { - log.Warn().Msgf("Program ID fetch failed: %s", b.Program.Name) - } + ok := false + b.ProgID, ok = progInfo.ID() + if !ok { + log.Warn().Msgf("Program ID fetch failed: %s", b.Program.Name) + } - // Initialise metric maps - if err := b.InitialiseMetricMaps(); err != nil { - return fmt.Errorf("initialising metric maps failed %w", err) - } + // Initialise metric maps + if err := b.InitialiseMetricMaps(); err != nil { + return fmt.Errorf("initialising metric maps failed %w", err) + } - if err := b.PinBpfMaps(ifaceName); err != nil { - return err + if err := b.PinBpfMaps(ifaceName); err != nil { + return err + } } - return nil } @@ -1366,8 +1362,12 @@ func (b *BPF) StartUserProgram(ifaceName, direction string, chain bool) error { } args := make([]string, 0, len(b.Program.StartArgs)<<1) - args = append(args, "--iface="+ifaceName) // attaching to interface - args = append(args, "--direction="+direction) // direction xdpingress or ingress or egress + if len(ifaceName) > 0 { + args = append(args, "--iface="+ifaceName) // attaching to interface + } + if len(direction) > 0 { + args = append(args, "--direction="+direction) // direction xdpingress or ingress or egress + } if chain && b.ProgMapCollection == nil { // chaining from user program @@ -1429,12 +1429,15 @@ func (b *BPF) CreateMapPinDirectory(ifaceName string) error { } else if b.Program.ProgType == models.TCType { mapPathDir = filepath.Join(b.hostConfig.BpfMapDefaultPath, models.TCMapPinPath, ifaceName) } - // codeQL Check - if strings.Contains(mapPathDir, "..") { - return fmt.Errorf("%s contains relative path is not supported - %s", mapPathDir, b.Program.Name) - } - if err := os.MkdirAll(mapPathDir, 0750); err != nil { - return fmt.Errorf("%s failed to create map dir path of %s program %s with err : %w", mapPathDir, b.Program.ProgType, b.Program.Name, err) + // Create map dir for XDP and TC programs only + if len(mapPathDir) > 0 { + // codeQL Check + if strings.Contains(mapPathDir, "..") { + return fmt.Errorf("%s contains relative path is not supported - %s", mapPathDir, b.Program.Name) + } + if err := os.MkdirAll(mapPathDir, 0750); err != nil { + return fmt.Errorf("%s failed to create map dir path of %s program %s with err : %w", mapPathDir, b.Program.ProgType, b.Program.Name, err) + } } return nil } @@ -1534,35 +1537,6 @@ func (b *BPF) LoadBPFProgramChain(ifaceName, direction string) error { return nil } -// LoadBPFProgramProbeTypes - Load the BPF programs of probe types - TracePoint -func (b *BPF) LoadBPFProgramProbeTypes(objSpec *ebpf.CollectionSpec) error { - for i, prog := range b.ProgMapCollection.Programs { - if i == b.Program.EntryFunctionName { - // skipping XDP/TC programs - continue - } - if err := b.LoadBPFProgramProbeType(prog, objSpec.Programs[i].SectionName); err != nil { - return err - } - } - return nil -} - -func (b *BPF) LoadBPFProgramProbeType(prog *ebpf.Program, sectionName string) error { - switch prog.Type() { - case ebpf.TracePoint: - group, probeName := GetProgramSectionDetails(sectionName) - tp, err := link.Tracepoint(group, probeName, prog, nil) - if err != nil { - return fmt.Errorf("failed to link tracepoint sec name %s error %v", sectionName, err) - } - b.ProbeLinks = append(b.ProbeLinks, &tp) - default: - return fmt.Errorf("un-supported probe type %s ", prog.Type()) - } - return nil -} - // GetProgramSectionDetails returns group and name details // Section name format /prob type/group/name // e.g.: tracepoint/sock/inet_sock_set_state diff --git a/kf/kfmetrics.go b/kf/kfmetrics.go index e8c33035..6c930c62 100644 --- a/kf/kfmetrics.go +++ b/kf/kfmetrics.go @@ -26,13 +26,14 @@ func NewpKFMetrics(chain bool, interval int) *kfMetrics { return m } -func (c *kfMetrics) kfMetricsStart(xdpProgs, ingressTCProgs, egressTCProgs map[string]*list.List) { - go c.kfMetricsWorker(xdpProgs, models.XDPIngressType) - go c.kfMetricsWorker(ingressTCProgs, models.IngressType) - go c.kfMetricsWorker(egressTCProgs, models.EgressType) +func (c *kfMetrics) kfMetricsStart(xdpProgs, ingressTCProgs, egressTCProgs map[string]*list.List, probes *list.List) { + go c.kfMetricsWorker(xdpProgs) + go c.kfMetricsWorker(ingressTCProgs) + go c.kfMetricsWorker(egressTCProgs) + go c.kfMetricsProbeWorker(probes) } -func (c *kfMetrics) kfMetricsWorker(bpfProgs map[string]*list.List, direction string) { +func (c *kfMetrics) kfMetricsWorker(bpfProgs map[string]*list.List) { for range time.NewTicker(1 * time.Second).C { for ifaceName, bpfList := range bpfProgs { if bpfList == nil { // no bpf programs are running @@ -53,3 +54,21 @@ func (c *kfMetrics) kfMetricsWorker(bpfProgs map[string]*list.List, direction st } } } + +func (c *kfMetrics) kfMetricsProbeWorker(bpfProgs *list.List) { + for range time.NewTicker(1 * time.Second).C { + if bpfProgs == nil { + time.Sleep(time.Second) + continue + } + for e := bpfProgs.Front(); e != nil; e = e.Next() { + bpf := e.Value.(*BPF) + if bpf.Program.AdminStatus == models.Disabled { + continue + } + if err := bpf.MonitorMaps("", c.Intervals); err != nil { + log.Error().Err(err).Msgf("pMonitor probe monitor maps failed - %s", bpf.Program.Name) + } + } + } +} diff --git a/kf/kfmetrics_test.go b/kf/kfmetrics_test.go index 512fee1d..94abd138 100644 --- a/kf/kfmetrics_test.go +++ b/kf/kfmetrics_test.go @@ -52,6 +52,7 @@ func Test_KFMetrics_Start(t *testing.T) { IngressXDPbpfProgs map[string]*list.List IngressTCbpfProgs map[string]*list.List EgressTCbpfProgs map[string]*list.List + Probebpfs list.List } tests := []struct { name string @@ -75,7 +76,7 @@ func Test_KFMetrics_Start(t *testing.T) { Chain: tt.fields.Chain, Intervals: tt.fields.Interval, } - c.kfMetricsStart(tt.args.IngressXDPbpfProgs, tt.args.IngressTCbpfProgs, tt.args.EgressTCbpfProgs) + c.kfMetricsStart(tt.args.IngressXDPbpfProgs, tt.args.IngressTCbpfProgs, tt.args.EgressTCbpfProgs, &tt.args.Probebpfs) }) } } diff --git a/kf/nfconfig.go b/kf/nfconfig.go index 1db6980c..9aafc973 100644 --- a/kf/nfconfig.go +++ b/kf/nfconfig.go @@ -34,6 +34,7 @@ type NFConfigs struct { IngressXDPBpfs map[string]*list.List IngressTCBpfs map[string]*list.List EgressTCBpfs map[string]*list.List + ProbesBpfs list.List HostConfig *config.Config processMon *pCheck @@ -64,9 +65,9 @@ func NewNFConfigs(ctx context.Context, host string, hostConf *config.Config, pMo } nfConfigs.processMon = pMon - nfConfigs.processMon.pCheckStart(nfConfigs.IngressXDPBpfs, nfConfigs.IngressTCBpfs, nfConfigs.EgressTCBpfs) + nfConfigs.processMon.pCheckStart(nfConfigs.IngressXDPBpfs, nfConfigs.IngressTCBpfs, nfConfigs.EgressTCBpfs, &nfConfigs.ProbesBpfs) nfConfigs.kfMetricsMon = metricsMon - nfConfigs.kfMetricsMon.kfMetricsStart(nfConfigs.IngressXDPBpfs, nfConfigs.IngressTCBpfs, nfConfigs.EgressTCBpfs) + nfConfigs.kfMetricsMon.kfMetricsStart(nfConfigs.IngressXDPBpfs, nfConfigs.IngressTCBpfs, nfConfigs.EgressTCBpfs, &nfConfigs.ProbesBpfs) return nfConfigs, nil } @@ -116,6 +117,15 @@ func (c *NFConfigs) Close(ctx context.Context) error { } }() + wg.Add(1) + go func() { + defer wg.Done() + if err := c.StopNRemoveAllBPFProbePrograms(); err != nil { + log.Warn().Err(err).Msg("failed to Close Probe BPF Programs") + } + + }() + select { case <-ctx.Done(): return ctx.Err() @@ -281,6 +291,22 @@ func (c *NFConfigs) StopNRemoveAllBPFPrograms(ifaceName, direction string) error return nil } +// StopNRemoveAllBPFProbePrograms Stopping all probe programs in order +func (c *NFConfigs) StopNRemoveAllBPFProbePrograms() error { + + for e := c.ProbesBpfs.Front(); e != nil; { + data := e.Value.(*BPF) + if err := data.Stop("", "", false); err != nil { + return fmt.Errorf("failed to stop probe program %s with err :%w", data.Program.Name, err) + } + nextBPF := e.Next() + c.ProbesBpfs.Remove(e) + e = nextBPF + } + + return nil +} + // VerifyNUpdateBPFProgram - This method checks the following conditions // 1. BPF Program already running with no change // 2. BPF Program running but needs to stop (admin_status == disabled) @@ -635,6 +661,11 @@ func (c *NFConfigs) KFDetails(iface string) []*BPF { arrBPFDetails = append(arrBPFDetails, e.Value.(*BPF)) } } + + for e := c.ProbesBpfs.Front(); e != nil; e = e.Next() { + arrBPFDetails = append(arrBPFDetails, e.Value.(*BPF)) + } + return arrBPFDetails } @@ -721,6 +752,12 @@ func (c *NFConfigs) Deploy(ifaceName, HostName string, bpfProgs *models.BPFProgr } } + for _, bpfProg := range bpfProgs.Probes { + if err := c.PushBackAndStartProbe(bpfProg); err != nil { + return fmt.Errorf("failed to update Probe BPF Program: %w", err) + } + } + return nil } @@ -809,6 +846,11 @@ func (c *NFConfigs) EBPFPrograms(iface string) models.L3afBPFPrograms { } } + e := c.ProbesBpfs.Front() + for ; e != nil; e = e.Next() { + BPFProgram.BpfPrograms.Probes = append(BPFProgram.BpfPrograms.Probes, &e.Value.(*BPF).Program) + } + return BPFProgram } @@ -1081,10 +1123,11 @@ func (c *NFConfigs) AddProgramWithoutChaining(ifaceName string, bpfProgs *models } } } + return nil } -// AddProgramsOnInterface: AddProgramsOnInterface will add given ebpf programs on given interface +// AddProgramsOnInterface will add given ebpf programs on given interface func (c *NFConfigs) AddProgramsOnInterface(ifaceName, HostName string, bpfProgs *models.BPFPrograms) error { if HostName != c.HostName { @@ -1182,6 +1225,12 @@ func (c *NFConfigs) AddeBPFPrograms(bpfProgs []models.L3afBPFPrograms) error { } return fmt.Errorf("failed to Add BPF program on iface %s with error: %w", bpfProg.Iface, err) } + if err := c.AddProbePrograms(bpfProg.HostName, bpfProg.BpfPrograms.Probes); err != nil { + if err := c.SaveConfigsToConfigStore(); err != nil { + return fmt.Errorf("add eBPF Programs of type probes failed to save configs %w", err) + } + return fmt.Errorf("failed to Add eBPF program of type probe with error: %w", err) + } c.ifaces = map[string]string{bpfProg.Iface: bpfProg.Iface} } if err := c.SaveConfigsToConfigStore(); err != nil { @@ -1268,6 +1317,19 @@ func (c *NFConfigs) DeleteProgramsOnInterface(ifaceName, HostName string, bpfPro c.EgressTCBpfs[ifaceName] = nil } } + + sort.Strings(bpfProgs.Probes) + for e := c.ProbesBpfs.Front(); e != nil; { + next := e.Next() + data := e.Value.(*BPF) + if BinarySearch(bpfProgs.Probes, data.Program.Name) { + err := c.DeleteProgramsOnInterfaceHelper(e, ifaceName, "", &c.ProbesBpfs) + if err != nil { + return fmt.Errorf("DeleteProgramsOnInterfaceHelper function failed : %w", err) + } + } + e = next + } return nil } @@ -1339,3 +1401,53 @@ func BinarySearch(names []string, target string) bool { } return false } + +func (c *NFConfigs) AddProbePrograms(HostName string, bpfProgs []*models.BPFProgram) error { + if HostName != c.HostName { + errOut := fmt.Errorf("provided bpf programs do not belong to this host") + log.Error().Err(errOut) + return errOut + } + + if len(bpfProgs) == 0 { + return nil + } + + for _, bpfProg := range bpfProgs { + if err := c.PushBackAndStartProbe(bpfProg); err != nil { + return fmt.Errorf("failed to PushBackAndStartBPF BPF Program: %w", err) + } + } + + return nil +} + +// PushBackAndStartProbe method inserts the element at the end of the list +func (c *NFConfigs) PushBackAndStartProbe(bpfProg *models.BPFProgram) error { + log.Info().Msgf("PushBackAndStartProbe: %s", bpfProg.Name) + bpf := NewBpfProgram(c.ctx, *bpfProg, c.HostConfig, "") + + if err := c.DownloadAndStartProbes(c.ProbesBpfs.PushBack(bpf)); err != nil { + return fmt.Errorf("failed to download and start the BPF %s with err: %w", bpfProg.Name, err) + } + + return nil +} + +func (c *NFConfigs) DownloadAndStartProbes(element *list.Element) error { + if element == nil { + return fmt.Errorf("element is nil pointer") + } + + bpf := element.Value.(*BPF) + + if err := bpf.VerifyAndGetArtifacts(c.HostConfig); err != nil { + return fmt.Errorf("failed to get artifacts %s with error: %w", bpf.Program.Artifact, err) + } + + if err := bpf.LoadBPFProgram(""); err != nil { + return fmt.Errorf("failed to load bpf program %s with error: %w", bpf.Program.Name, err) + } + + return nil +} diff --git a/kf/probes.go b/kf/probes.go new file mode 100644 index 00000000..1697294b --- /dev/null +++ b/kf/probes.go @@ -0,0 +1,55 @@ +// Copyright Contributors to the L3AF Project. +// SPDX-License-Identifier: Apache-2.0 + +package kf + +import ( + "fmt" + "time" + + "github.com/l3af-project/l3afd/v2/stats" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/link" + "github.com/rs/zerolog/log" +) + +func (b *BPF) LoadBPFProgramProbeType(prog *ebpf.Program, sectionName string) error { + var probeName, group string + switch prog.Type() { + case ebpf.TracePoint: + group, probeName = GetProgramSectionDetails(sectionName) + tp, err := link.Tracepoint(group, probeName, prog, nil) + if err != nil { + return fmt.Errorf("failed to link tracepoint sec name %s error %v", sectionName, err) + } + b.ProbeLinks = append(b.ProbeLinks, &tp) + default: + return fmt.Errorf("un-supported probe type %s ", prog.Type()) + } + ebpfProgName := b.Program.Name + "_" + probeName + stats.Incr(stats.BPFStartCount, ebpfProgName, "", "") + stats.Set(float64(time.Now().Unix()), stats.BPFStartTime, ebpfProgName, "", "") + return nil +} + +// LoadBPFProgramProbeTypes - Load the BPF programs of probe types - TracePoint +func (b *BPF) LoadBPFProgramProbeTypes(objSpec *ebpf.CollectionSpec) error { + for i, prog := range b.ProgMapCollection.Programs { + if prog.Type() == ebpf.XDP || prog.Type() == ebpf.SchedACT || prog.Type() == ebpf.SchedCLS { + // skipping XDP/TC programs + continue + } + if err := b.LoadBPFProgramProbeType(prog, objSpec.Programs[i].SectionName); err != nil { + return err + } + for _, tmpMap := range b.Program.MonitorMaps { + tmpMetricsMap := b.ProgMapCollection.Maps[tmpMap.Name] + if tmpMetricsMap == nil { + log.Error().Msgf("%s map is not loaded", tmpMap.Name) + continue + } + } + } + return nil +} diff --git a/kf/processCheck.go b/kf/processCheck.go index 0f4767a8..6f54c6ef 100644 --- a/kf/processCheck.go +++ b/kf/processCheck.go @@ -29,10 +29,11 @@ func NewpCheck(rc int, chain bool, interval time.Duration) *pCheck { return c } -func (c *pCheck) pCheckStart(xdpProgs, ingressTCProgs, egressTCProgs map[string]*list.List) { +func (c *pCheck) pCheckStart(xdpProgs, ingressTCProgs, egressTCProgs map[string]*list.List, probes *list.List) { go c.pMonitorWorker(xdpProgs, models.XDPIngressType) go c.pMonitorWorker(ingressTCProgs, models.IngressType) go c.pMonitorWorker(egressTCProgs, models.EgressType) + go c.pMonitorProbeWorker(probes) } func (c *pCheck) pMonitorWorker(bpfProgs map[string]*list.List, direction string) { @@ -86,3 +87,63 @@ func (c *pCheck) pMonitorWorker(bpfProgs map[string]*list.List, direction string } } } + +func (c *pCheck) pMonitorProbeWorker(bpfProgs *list.List) { + for range time.NewTicker(c.retryMonitorDelay).C { + if bpfProgs == nil { + time.Sleep(time.Second) + continue + } + for e := bpfProgs.Front(); e != nil; e = e.Next() { + bpf := e.Value.(*BPF) + if bpf.Program.AdminStatus == models.Disabled { + continue + } + userProgram, bpfProgram, _ := bpf.isRunning() + if userProgram && bpfProgram { + stats.SetWithVersion(1.0, stats.BPFRunning, bpf.Program.Name, bpf.Program.Version, "", "") + continue + } + // Not running trying to restart + if bpf.RestartCount < c.MaxRetryCount && bpf.Program.AdminStatus == models.Enabled { + bpf.RestartCount++ + log.Warn().Msgf("pMonitor BPF Program is not running. Restart attempt: %d, probe program name: %s", + bpf.RestartCount, bpf.Program.Name) + // User program is a daemon and not running, but the BPF program is loaded + if !userProgram && bpfProgram { + if err := bpf.StartUserProgram("", "", c.Chain); err != nil { + log.Error().Err(err).Msgf("pMonitorWorker: BPF Program start user program failed for program %s", bpf.Program.Name) + } + } + // Not running trying to restart + if bpf.RestartCount < c.MaxRetryCount && bpf.Program.AdminStatus == models.Enabled { + bpf.RestartCount++ + log.Warn().Msgf("pMonitor BPF Program is not running. Restart attempt: %d, program name: %s, iface: %s", + bpf.RestartCount, bpf.Program.Name, "") + // User program is a daemon and not running, but the BPF program is loaded + if !userProgram && bpfProgram { + if err := bpf.StartUserProgram("", "", c.Chain); err != nil { + log.Error().Err(err).Msgf("pMonitorWorker: BPF Program start user program failed for program %s", bpf.Program.Name) + } + } + // BPF program is not loaded. + // if user program is daemon then stop it and restart both the programs + if !bpfProgram { + log.Warn().Msgf("%s BPF program is not loaded, %s program reloading ...", bpf.Program.EntryFunctionName, bpf.Program.Name) + // User program is a daemon and running, stop before reloading the BPF program + if bpf.Program.UserProgramDaemon && userProgram { + if err := bpf.Stop("", "", c.Chain); err != nil { + log.Error().Err(err).Msgf("pMonitorWorker: BPF Program stop failed for program %s", bpf.Program.Name) + } + } + if err := bpf.Start("", "", c.Chain); err != nil { + log.Error().Err(err).Msgf("pMonitorWorker: BPF Program start failed for program %s", bpf.Program.Name) + } + } + } else { + stats.SetWithVersion(0.0, stats.BPFRunning, bpf.Program.Name, bpf.Program.Version, "", "") + } + } + } + } +} diff --git a/kf/processCheck_test.go b/kf/processCheck_test.go index 87e2057b..76f17f68 100644 --- a/kf/processCheck_test.go +++ b/kf/processCheck_test.go @@ -55,6 +55,7 @@ func Test_pCheck_pCheckStart(t *testing.T) { IngressXDPbpfProgs map[string]*list.List IngressTCbpfProgs map[string]*list.List EgressTCbpfProgs map[string]*list.List + Probebpfs list.List } tests := []struct { name string @@ -79,7 +80,7 @@ func Test_pCheck_pCheckStart(t *testing.T) { Chain: tt.fields.chain, retryMonitorDelay: tt.fields.retryMonitorDelay, } - c.pCheckStart(tt.args.IngressXDPbpfProgs, tt.args.IngressTCbpfProgs, tt.args.EgressTCbpfProgs) + c.pCheckStart(tt.args.IngressXDPbpfProgs, tt.args.IngressTCbpfProgs, tt.args.EgressTCbpfProgs, &tt.args.Probebpfs) }) } } diff --git a/models/l3afd.go b/models/l3afd.go index a4acc9e7..ae144c52 100644 --- a/models/l3afd.go +++ b/models/l3afd.go @@ -77,6 +77,7 @@ type BPFPrograms struct { XDPIngress []*BPFProgram `json:"xdp_ingress"` // list of xdp ingress bpf programs TCIngress []*BPFProgram `json:"tc_ingress"` // list of tc ingress bpf programs TCEgress []*BPFProgram `json:"tc_egress"` // list of tc egress bpf programs + Probes []*BPFProgram `json:"probes"` // list of probe bpf programs } // L3afBPFProgramNames defines names of Bpf programs on interface @@ -91,4 +92,5 @@ type BPFProgramNames struct { XDPIngress []string `json:"xdp_ingress"` // names of the XDP ingress eBPF programs TCIngress []string `json:"tc_ingress"` // names of the TC ingress eBPF programs TCEgress []string `json:"tc_egress"` // names of the TC egress eBPF programs + Probes []string `json:"probes"` // names of the probe eBPF programs }