diff --git a/felix/bpf/bpf.go b/felix/bpf/bpf.go index 360e95f33bc..883375a4c68 100644 --- a/felix/bpf/bpf.go +++ b/felix/bpf/bpf.go @@ -38,7 +38,8 @@ import ( "golang.org/x/sys/unix" "github.com/projectcalico/calico/felix/bpf/bpfdefs" - "github.com/projectcalico/calico/felix/bpf/hook" + "github.com/projectcalico/calico/felix/bpf/libbpf" + "github.com/projectcalico/calico/felix/bpf/maps" "github.com/projectcalico/calico/felix/bpf/utils" "github.com/projectcalico/calico/felix/environment" "github.com/projectcalico/calico/felix/labelindex" @@ -2247,7 +2248,7 @@ func PolicyDebugJSONFileName(iface, polDir string, ipFamily proto.IPVersion) str return path.Join(RuntimePolDir, fmt.Sprintf("%s_%s_v%d.json", iface, polDir, ipFamily)) } -func MapPinDir(typ int, name, iface string, h hook.Hook) string { +func MapPinDir() string { PinBaseDir := path.Join(bpfdefs.DefaultBPFfsPath, "tc") subDir := "globals" return path.Join(PinBaseDir, subDir) @@ -2349,3 +2350,67 @@ func IterPerCpuMapCmdOutput(output []byte, f func(k, v []byte)) error { } return nil } + +func LoadObject(file string, data libbpf.GlobalData, mapsToBePinned ...string) (*libbpf.Obj, error) { + obj, err := libbpf.OpenObject(file) + if err != nil { + return nil, err + } + + success := false + defer func() { + if !success { + err := obj.Close() + if err != nil { + log.WithError(err).Error("Error closing BPF object.") + } + } + }() + + for m, err := obj.FirstMap(); m != nil && err == nil; m, err = m.NextMap() { + // In case of global variables, libbpf creates an internal map .rodata + // The values are read only for the BPF programs, but can be set to a value from + // userspace before the program is loaded. + mapName := m.Name() + if m.IsMapInternal() { + if strings.HasPrefix(mapName, ".rodata") { + continue + } + + if err := data.Set(m); err != nil { + return nil, fmt.Errorf("failed to configure %s: %w", file, err) + } + continue + } + + if size := maps.Size(mapName); size != 0 { + if err := m.SetSize(size); err != nil { + return nil, fmt.Errorf("error resizing map %s: %w", mapName, err) + } + } + + log.Debugf("Pinning map %s k %d v %d", mapName, m.KeySize(), m.ValueSize()) + pinDir := MapPinDir() + // If mapsToBePinned is not specified, pin all the maps. + if len(mapsToBePinned) == 0 { + if err := m.SetPinPath(path.Join(pinDir, mapName)); err != nil { + return nil, fmt.Errorf("error pinning map %s k %d v %d: %w", mapName, m.KeySize(), m.ValueSize(), err) + } + } else { + for _, name := range mapsToBePinned { + if mapName == name { + if err := m.SetPinPath(path.Join(pinDir, mapName)); err != nil { + return nil, fmt.Errorf("error pinning map %s k %d v %d: %w", mapName, m.KeySize(), m.ValueSize(), err) + } + } + } + } + } + + if err := obj.Load(); err != nil { + return nil, fmt.Errorf("error loading program: %w", err) + } + + success = true + return obj, nil +} diff --git a/felix/bpf/conntrack/bpf_scanner.go b/felix/bpf/conntrack/bpf_scanner.go index f7c09f9521b..5d832c4fb0b 100644 --- a/felix/bpf/conntrack/bpf_scanner.go +++ b/felix/bpf/conntrack/bpf_scanner.go @@ -27,7 +27,6 @@ import ( "github.com/projectcalico/calico/felix/bpf" "github.com/projectcalico/calico/felix/bpf/bpfdefs" "github.com/projectcalico/calico/felix/bpf/libbpf" - "github.com/projectcalico/calico/felix/bpf/maps" ) type BPFLogLevel string @@ -112,91 +111,25 @@ func (s *BPFProgLivenessScanner) ensureBPFExpiryProgram() (*libbpf.Obj, error) { // needs a newer than co-re. binaryToLoad := path.Join(bpfdefs.ObjectDir, fmt.Sprintf("conntrack_cleanup_%s_co-re_v%d.o", s.logLevel, s.ipVersion)) - obj, err := libbpf.OpenObject(binaryToLoad) - if err != nil { - return nil, fmt.Errorf("failed to load conntrack cleanup BPF program: %w", err) - } - - success := false - defer func() { - if !success { - err := obj.Close() - if err != nil { - log.WithError(err).Error("Error closing BPF object.") - } - } - }() - ctMapParams := MapParams if s.ipVersion == 6 { ctMapParams = MapParamsV6 } - configuredGlobals := false - pinnedCTMap := false - var internalMaps []string - for m, err := obj.FirstMap(); m != nil && err == nil; m, err = m.NextMap() { - // In case of global variables, libbpf creates an internal map .rodata - // The values are read only for the BPF programs, but can be set to a value from - // userspace before the program is loaded. - mapName := m.Name() - if m.IsMapInternal() { - internalMaps = append(internalMaps, mapName) - if mapName != "conntrac.rodata" { - continue - } - - err := libbpf.CTCleanupSetGlobals( - m, - s.timeouts.CreationGracePeriod, - s.timeouts.TCPPreEstablished, - s.timeouts.TCPEstablished, - s.timeouts.TCPFinsSeen, - s.timeouts.TCPResetSeen, - s.timeouts.UDPLastSeen, - s.timeouts.GenericIPLastSeen, - s.timeouts.ICMPLastSeen, - ) - if err != nil { - return nil, fmt.Errorf("error setting global variables for map %s: %w", mapName, err) - } - configuredGlobals = true - continue - } - - if size := maps.Size(mapName); size != 0 { - log.WithField("mapName", mapName).Info("Resizing map") - if err := m.SetSize(size); err != nil { - return nil, fmt.Errorf("error resizing map %s: %w", mapName, err) - } - } - - if mapName == ctMapParams.VersionedName() { - log.Debugf("Pinning map %s k %d v %d", mapName, m.KeySize(), m.ValueSize()) - pinDir := bpf.MapPinDir(m.Type(), mapName, "", 0) - if err := m.SetPinPath(path.Join(pinDir, mapName)); err != nil { - return nil, fmt.Errorf("error pinning map %s k %d v %d: %w", mapName, m.KeySize(), m.ValueSize(), err) - } - pinnedCTMap = true - } - } - if !configuredGlobals { - // Panic here because it indicates a coding error that we want to - // catch in testing. - log.WithField("maps", internalMaps).Panic("Bug: failed to find/set global variable map.") - } - - if !pinnedCTMap { - // Panic here because it indicates a coding error that we want to - // catch in testing. - log.Panic("Bug: failed to find/pin conntrack map.") - } + ctCleanupData := &libbpf.CTCleanupGlobalData{ + CreationGracePeriod: s.timeouts.CreationGracePeriod, + TCPPreEstablished: s.timeouts.TCPPreEstablished, + TCPEstablished: s.timeouts.TCPEstablished, + TCPFinsSeen: s.timeouts.TCPFinsSeen, + TCPResetSeen: s.timeouts.TCPResetSeen, + UDPLastSeen: s.timeouts.UDPLastSeen, + GenericIPLastSeen: s.timeouts.GenericIPLastSeen, + ICMPLastSeen: s.timeouts.ICMPLastSeen} - if err := obj.Load(); err != nil { - return nil, fmt.Errorf("error loading conntrack expiry program: %w", err) + obj, err := bpf.LoadObject(binaryToLoad, ctCleanupData, ctMapParams.VersionedName()) + if err != nil { + return nil, fmt.Errorf("error loading %s: %w", binaryToLoad, err) } - - success = true s.bpfExpiryProgram = obj return s.bpfExpiryProgram, nil } diff --git a/felix/bpf/libbpf/libbpf.go b/felix/bpf/libbpf/libbpf.go index e8fa0999f0d..5ee38247feb 100644 --- a/felix/bpf/libbpf/libbpf.go +++ b/felix/bpf/libbpf/libbpf.go @@ -384,73 +384,42 @@ const ( GlobalsRedirectPeer uint32 = C.CALI_GLOBALS_REDIRECT_PEER ) -func CTCleanupSetGlobals( - m *Map, - CreationGracePeriod time.Duration, - TCPPreEstablished time.Duration, - TCPEstablished time.Duration, - TCPFinsSeen time.Duration, - TCPResetSeen time.Duration, - UDPLastSeen time.Duration, - GenericIPLastSeen time.Duration, - ICMPLastSeen time.Duration, -) error { - _, err := C.bpf_ct_cleanup_set_globals( - m.bpfMap, - C.uint64_t(CreationGracePeriod.Nanoseconds()), - - C.uint64_t(TCPPreEstablished.Nanoseconds()), - C.uint64_t(TCPEstablished.Nanoseconds()), - C.uint64_t(TCPFinsSeen.Nanoseconds()), - C.uint64_t(TCPResetSeen.Nanoseconds()), - - C.uint64_t(UDPLastSeen.Nanoseconds()), - C.uint64_t(GenericIPLastSeen.Nanoseconds()), - C.uint64_t(ICMPLastSeen.Nanoseconds()), - ) - return err -} - -func TcSetGlobals( - m *Map, - globalData *TcGlobalData, -) error { - - cName := C.CString(globalData.IfaceName) +func (t *TcGlobalData) Set(m *Map) error { + cName := C.CString(t.IfaceName) defer C.free(unsafe.Pointer(cName)) - cJumps := make([]C.uint, len(globalData.Jumps)) + cJumps := make([]C.uint, len(t.Jumps)) - for i, v := range globalData.Jumps { + for i, v := range t.Jumps { cJumps[i] = C.uint(v) } - cJumpsV6 := make([]C.uint, len(globalData.JumpsV6)) + cJumpsV6 := make([]C.uint, len(t.JumpsV6)) - for i, v := range globalData.JumpsV6 { + for i, v := range t.JumpsV6 { cJumpsV6[i] = C.uint(v) } _, err := C.bpf_tc_set_globals(m.bpfMap, cName, - (*C.char)(unsafe.Pointer(&globalData.HostIPv4[0])), - (*C.char)(unsafe.Pointer(&globalData.IntfIPv4[0])), - (*C.char)(unsafe.Pointer(&globalData.HostIPv6[0])), - (*C.char)(unsafe.Pointer(&globalData.IntfIPv6[0])), - C.uint(globalData.ExtToSvcMark), - C.ushort(globalData.Tmtu), - C.ushort(globalData.VxlanPort), - C.ushort(globalData.PSNatStart), - C.ushort(globalData.PSNatLen), - (*C.char)(unsafe.Pointer(&globalData.HostTunnelIPv4[0])), - (*C.char)(unsafe.Pointer(&globalData.HostTunnelIPv6[0])), - C.uint(globalData.Flags), - C.ushort(globalData.WgPort), - C.ushort(globalData.Wg6Port), - C.ushort(globalData.Profiling), - C.uint(globalData.NatIn), - C.uint(globalData.NatOut), - C.uint(globalData.LogFilterJmp), + (*C.char)(unsafe.Pointer(&t.HostIPv4[0])), + (*C.char)(unsafe.Pointer(&t.IntfIPv4[0])), + (*C.char)(unsafe.Pointer(&t.HostIPv6[0])), + (*C.char)(unsafe.Pointer(&t.IntfIPv6[0])), + C.uint(t.ExtToSvcMark), + C.ushort(t.Tmtu), + C.ushort(t.VxlanPort), + C.ushort(t.PSNatStart), + C.ushort(t.PSNatLen), + (*C.char)(unsafe.Pointer(&t.HostTunnelIPv4[0])), + (*C.char)(unsafe.Pointer(&t.HostTunnelIPv6[0])), + C.uint(t.Flags), + C.ushort(t.WgPort), + C.ushort(t.Wg6Port), + C.ushort(t.Profiling), + C.uint(t.NatIn), + C.uint(t.NatOut), + C.uint(t.LogFilterJmp), &cJumps[0], // it is safe because we hold the reference here until we return. &cJumpsV6[0], ) @@ -458,29 +427,42 @@ func TcSetGlobals( return err } -func CTLBSetGlobals(m *Map, udpNotSeen time.Duration, excludeUDP bool) error { - udpNotSeen /= time.Second // Convert to seconds - _, err := C.bpf_ctlb_set_globals(m.bpfMap, C.uint(udpNotSeen), C.bool(excludeUDP)) +func (c *CTCleanupGlobalData) Set(m *Map) error { + _, err := C.bpf_ct_cleanup_set_globals( + m.bpfMap, + C.uint64_t(c.CreationGracePeriod.Nanoseconds()), + + C.uint64_t(c.TCPPreEstablished.Nanoseconds()), + C.uint64_t(c.TCPEstablished.Nanoseconds()), + C.uint64_t(c.TCPFinsSeen.Nanoseconds()), + C.uint64_t(c.TCPResetSeen.Nanoseconds()), + C.uint64_t(c.UDPLastSeen.Nanoseconds()), + C.uint64_t(c.GenericIPLastSeen.Nanoseconds()), + C.uint64_t(c.ICMPLastSeen.Nanoseconds()), + ) return err } -func XDPSetGlobals( - m *Map, - globalData *XDPGlobalData, -) error { +func (c *CTLBGlobalData) Set(m *Map) error { + udpNotSeen := c.UDPNotSeen / time.Second // Convert to seconds + _, err := C.bpf_ctlb_set_globals(m.bpfMap, C.uint(udpNotSeen), C.bool(c.ExcludeUDP)) + + return err +} - cName := C.CString(globalData.IfaceName) +func (x *XDPGlobalData) Set(m *Map) error { + cName := C.CString(x.IfaceName) defer C.free(unsafe.Pointer(cName)) - cJumps := make([]C.uint, len(globalData.Jumps)) - cJumpsV6 := make([]C.uint, len(globalData.Jumps)) + cJumps := make([]C.uint, len(x.Jumps)) + cJumpsV6 := make([]C.uint, len(x.Jumps)) - for i, v := range globalData.Jumps { + for i, v := range x.Jumps { cJumps[i] = C.uint(v) } - for i, v := range globalData.JumpsV6 { + for i, v := range x.JumpsV6 { cJumpsV6[i] = C.uint(v) } _, err := C.bpf_xdp_set_globals(m.bpfMap, diff --git a/felix/bpf/libbpf/libbpf_common.go b/felix/bpf/libbpf/libbpf_common.go index 1a4d9753aa5..ae7a14045be 100644 --- a/felix/bpf/libbpf/libbpf_common.go +++ b/felix/bpf/libbpf/libbpf_common.go @@ -14,6 +14,14 @@ package libbpf +import ( + "time" +) + +type GlobalData interface { + Set(m *Map) error +} + type TcGlobalData struct { IfaceName string HostIPv4 [16]byte @@ -44,3 +52,19 @@ type XDPGlobalData struct { Jumps [16]uint32 JumpsV6 [16]uint32 } + +type CTCleanupGlobalData struct { + CreationGracePeriod time.Duration + TCPPreEstablished time.Duration + TCPEstablished time.Duration + TCPFinsSeen time.Duration + TCPResetSeen time.Duration + UDPLastSeen time.Duration + GenericIPLastSeen time.Duration + ICMPLastSeen time.Duration +} + +type CTLBGlobalData struct { + UDPNotSeen time.Duration + ExcludeUDP bool +} diff --git a/felix/bpf/libbpf/libbpf_stub.go b/felix/bpf/libbpf/libbpf_stub.go index 547a083b58d..16a549192e8 100644 --- a/felix/bpf/libbpf/libbpf_stub.go +++ b/felix/bpf/libbpf/libbpf_stub.go @@ -18,7 +18,6 @@ package libbpf import ( "runtime" - "time" ) type Obj struct { @@ -139,44 +138,34 @@ const ( GlobalsRedirectPeer uint32 = 12345 ) -func TcSetGlobals(_ *Map, globalData *TcGlobalData) error { +func (m *Map) SetSize(size int) error { panic("LIBBPF syscall stub") } -func CTLBSetGlobals(_ *Map, _ time.Duration, _ bool) error { - panic("LIBBPF syscall stub") +func NumPossibleCPUs() (int, error) { + return runtime.NumCPU(), nil } -func CTCleanupSetGlobals( - m *Map, - CreationGracePeriod time.Duration, - TCPPreEstablished time.Duration, - TCPEstablished time.Duration, - TCPFinsSeen time.Duration, - TCPResetSeen time.Duration, - UDPLastSeen time.Duration, - GenericIPLastSeen time.Duration, - ICMPLastSeen time.Duration, -) error { +func ObjPin(_ int, _ string) error { panic("LIBBPF syscall stub") } -func XDPSetGlobals(_ *Map, _ *XDPGlobalData) error { +func ObjGet(_ string) (int, error) { panic("LIBBPF syscall stub") } -func (m *Map) SetSize(size int) error { +func (t *TcGlobalData) Set(m *Map) error { panic("LIBBPF syscall stub") } -func NumPossibleCPUs() (int, error) { - return runtime.NumCPU(), nil +func (t *XDPGlobalData) Set(m *Map) error { + panic("LIBBPF syscall stub") } -func ObjPin(_ int, _ string) error { +func (t *CTCleanupGlobalData) Set(m *Map) error { panic("LIBBPF syscall stub") } -func ObjGet(_ string) (int, error) { +func (t *CTLBGlobalData) Set(m *Map) error { panic("LIBBPF syscall stub") } diff --git a/felix/bpf/nat/connecttime.go b/felix/bpf/nat/connecttime.go index f59a6f399b1..08a658158ea 100644 --- a/felix/bpf/nat/connecttime.go +++ b/felix/bpf/nat/connecttime.go @@ -119,42 +119,9 @@ func RemoveConnectTimeLoadBalancer(cgroupv2 string) error { func loadProgram(logLevel, ipver string, udpNotSeen time.Duration, excludeUDP bool) (*libbpf.Obj, error) { filename := path.Join(bpfdefs.ObjectDir, ProgFileName(logLevel, ipver)) - - log.WithField("filename", filename).Debug("Loading object file") - obj, err := libbpf.OpenObject(filename) + obj, err := bpf.LoadObject(filename, &libbpf.CTLBGlobalData{UDPNotSeen: udpNotSeen, ExcludeUDP: excludeUDP}) if err != nil { - return nil, fmt.Errorf("failed to load %s: %w", filename, err) - } - - for m, err := obj.FirstMap(); m != nil && err == nil; m, err = m.NextMap() { - // In case of global variables, libbpf creates an internal map .rodata - // The values are read only for the BPF programs, but can be set to a value from - // userspace before the program is loaded. - mapName := m.Name() - if m.IsMapInternal() { - if strings.HasPrefix(mapName, ".rodata") { - continue - } - if err := libbpf.CTLBSetGlobals(m, udpNotSeen, excludeUDP); err != nil { - return nil, fmt.Errorf("error setting globals: %w", err) - } - continue - } - - if size := maps.Size(mapName); size != 0 { - err := m.SetSize(size) - if err != nil { - return nil, fmt.Errorf("error set map size %s: %w", m.Name(), err) - } - } - if err := m.SetPinPath(path.Join(bpfdefs.GlobalPinDir, mapName)); err != nil { - return nil, fmt.Errorf("error pinning map %s: %w", mapName, err) - } - log.WithFields(log.Fields{"obj": filename, "map": mapName}).Debug("Pinned map") - } - - if err := obj.Load(); err != nil { - return nil, fmt.Errorf("error loading object %s: %w", filename, err) + return nil, fmt.Errorf("error loading %s:%w", filename, err) } return obj, nil } diff --git a/felix/bpf/tc/attach.go b/felix/bpf/tc/attach.go index a7a213d1a6c..4ba6aa3f50b 100644 --- a/felix/bpf/tc/attach.go +++ b/felix/bpf/tc/attach.go @@ -30,7 +30,6 @@ import ( "github.com/projectcalico/calico/felix/bpf/bpfdefs" "github.com/projectcalico/calico/felix/bpf/hook" "github.com/projectcalico/calico/felix/bpf/libbpf" - "github.com/projectcalico/calico/felix/bpf/maps" tcdefs "github.com/projectcalico/calico/felix/bpf/tc/defs" ) @@ -80,44 +79,10 @@ func (ap *AttachPoint) Log() *log.Entry { } func (ap *AttachPoint) loadObject(file string) (*libbpf.Obj, error) { - obj, err := libbpf.OpenObject(file) + obj, err := bpf.LoadObject(file, ap.Configure()) if err != nil { - return nil, err - } - - for m, err := obj.FirstMap(); m != nil && err == nil; m, err = m.NextMap() { - // In case of global variables, libbpf creates an internal map .rodata - // The values are read only for the BPF programs, but can be set to a value from - // userspace before the program is loaded. - mapName := m.Name() - if m.IsMapInternal() { - if strings.HasPrefix(mapName, ".rodata") { - continue - } - - if err := ap.ConfigureProgram(m); err != nil { - return nil, fmt.Errorf("failed to configure %s: %w", file, err) - } - continue - } - - if size := maps.Size(mapName); size != 0 { - if err := m.SetSize(size); err != nil { - return nil, fmt.Errorf("error resizing map %s: %w", mapName, err) - } - } - - log.Debugf("Pinning map %s k %d v %d", mapName, m.KeySize(), m.ValueSize()) - pinDir := bpf.MapPinDir(m.Type(), mapName, ap.Iface, ap.Hook) - if err := m.SetPinPath(path.Join(pinDir, mapName)); err != nil { - return nil, fmt.Errorf("error pinning map %s k %d v %d: %w", mapName, m.KeySize(), m.ValueSize(), err) - } + return nil, fmt.Errorf("error loading %s: %w", file, err) } - - if err := obj.Load(); err != nil { - return nil, fmt.Errorf("error loading program: %w", err) - } - return obj, nil } @@ -406,8 +371,8 @@ func (ap *AttachPoint) Config() string { return fmt.Sprintf("%+v", ap) } -func (ap *AttachPoint) ConfigureProgram(m *libbpf.Map) error { - globalData := libbpf.TcGlobalData{ +func (ap *AttachPoint) Configure() *libbpf.TcGlobalData { + globalData := &libbpf.TcGlobalData{ ExtToSvcMark: ap.ExtToServiceConnmark, VxlanPort: ap.VXLANPort, Tmtu: ap.TunnelMTU, @@ -466,7 +431,7 @@ func (ap *AttachPoint) ConfigureProgram(m *libbpf.Map) error { } if ap.HookLayoutV4 != nil { - log.WithField("HookLayout", ap.HookLayoutV4).Debugf("ConfigureProgram") + log.WithField("HookLayout", ap.HookLayoutV4).Debugf("Configure") for p, i := range ap.HookLayoutV4 { globalData.Jumps[p] = uint32(i) } @@ -474,20 +439,16 @@ func (ap *AttachPoint) ConfigureProgram(m *libbpf.Map) error { } if ap.HookLayoutV6 != nil { - log.WithField("HookLayout", ap.HookLayoutV6).Debugf("ConfigureProgram") + log.WithField("HookLayout", ap.HookLayoutV6).Debugf("Configure") for p, i := range ap.HookLayoutV6 { globalData.JumpsV6[p] = uint32(i) } globalData.JumpsV6[tcdefs.ProgIndexPolicy] = uint32(ap.PolicyIdxV6) } - return ConfigureProgram(m, ap.Iface, &globalData) -} - -func ConfigureProgram(m *libbpf.Map, iface string, globalData *libbpf.TcGlobalData) error { in := []byte("---------------") - copy(in, iface) + copy(in, ap.Iface) globalData.IfaceName = string(in) - return libbpf.TcSetGlobals(m, globalData) + return globalData } diff --git a/felix/bpf/ut/bpf_prog_test.go b/felix/bpf/ut/bpf_prog_test.go index 87ab78cef9e..843bd2a0bac 100644 --- a/felix/bpf/ut/bpf_prog_test.go +++ b/felix/bpf/ut/bpf_prog_test.go @@ -54,9 +54,7 @@ import ( "github.com/projectcalico/calico/felix/bpf/profiling" "github.com/projectcalico/calico/felix/bpf/routes" "github.com/projectcalico/calico/felix/bpf/state" - "github.com/projectcalico/calico/felix/bpf/tc" tcdefs "github.com/projectcalico/calico/felix/bpf/tc/defs" - "github.com/projectcalico/calico/felix/bpf/xdp" "github.com/projectcalico/calico/felix/environment" "github.com/projectcalico/calico/felix/idalloc" "github.com/projectcalico/calico/felix/ip" @@ -751,34 +749,10 @@ func objLoad(fname, bpfFsDir, ipFamily string, topts testOpts, polProg, hasHostC } } - if err := xdp.ConfigureProgram(m, bpfIfaceName, &globals); err != nil { - return nil, err + globals.IfaceName = setLogPrefix(bpfIfaceName) + if err := globals.Set(m); err != nil { + return nil, fmt.Errorf("failed to configure xdp program: %w", err) } - } else if topts.ipv6 { - ifaceLog := topts.progLog + "-" + bpfIfaceName - globals := libbpf.TcGlobalData{ - Tmtu: natTunnelMTU, - VxlanPort: testVxlanPort, - PSNatStart: uint16(topts.psnaStart), - PSNatLen: uint16(topts.psnatEnd-topts.psnaStart) + 1, - Flags: libbpf.GlobalsNoDSRCidrs | libbpf.GlobalsRPFOptionStrict, - LogFilterJmp: 0xffffffff, - } - - copy(globals.HostTunnelIPv6[:], node1tunIPV6.To16()) - copy(globals.HostIPv6[:], hostIP.To16()) - copy(globals.IntfIPv6[:], intfIPV6.To16()) - - for i := 0; i < tcdefs.ProgIndexEnd; i++ { - globals.JumpsV6[i] = uint32(i) - } - - log.WithField("globals", globals).Debugf("configure program v6") - - if err := tc.ConfigureProgram(m, ifaceLog, &globals); err != nil { - return nil, fmt.Errorf("failed to configure tc program: %w", err) - } - log.WithField("program", fname).Debugf("Configured BPF program iface \"%s\"", ifaceLog) } else { ifaceLog := topts.progLog + "-" + bpfIfaceName globals := libbpf.TcGlobalData{ @@ -788,19 +762,29 @@ func objLoad(fname, bpfFsDir, ipFamily string, topts testOpts, polProg, hasHostC PSNatLen: uint16(topts.psnatEnd-topts.psnaStart) + 1, Flags: libbpf.GlobalsNoDSRCidrs, LogFilterJmp: 0xffffffff, + IfaceName: setLogPrefix(ifaceLog), } + if topts.ipv6 { + copy(globals.HostTunnelIPv6[:], node1tunIPV6.To16()) + copy(globals.HostIPv6[:], hostIP.To16()) + copy(globals.IntfIPv6[:], intfIPV6.To16()) - copy(globals.HostIPv4[0:4], hostIP) - copy(globals.IntfIPv4[0:4], intfIP) - copy(globals.HostTunnelIPv4[0:4], node1tunIP.To4()) - - for i := 0; i < tcdefs.ProgIndexEnd; i++ { - globals.Jumps[i] = uint32(i) + for i := 0; i < tcdefs.ProgIndexEnd; i++ { + globals.JumpsV6[i] = uint32(i) + } + globals.Flags |= libbpf.GlobalsRPFOptionStrict + log.WithField("globals", globals).Debugf("configure program v6") + } else { + copy(globals.HostIPv4[0:4], hostIP) + copy(globals.IntfIPv4[0:4], intfIP) + copy(globals.HostTunnelIPv4[0:4], node1tunIP.To4()) + + for i := 0; i < tcdefs.ProgIndexEnd; i++ { + globals.Jumps[i] = uint32(i) + } + log.WithField("globals", globals).Debugf("configure program") } - - log.WithField("globals", globals).Debugf("configure program") - - if err := tc.ConfigureProgram(m, ifaceLog, &globals); err != nil { + if err := globals.Set(m); err != nil { return nil, fmt.Errorf("failed to configure tc program: %w", err) } log.WithField("program", fname).Debugf("Configured BPF program iface \"%s\"", ifaceLog) @@ -892,38 +876,25 @@ func objUTLoad(fname, bpfFsDir, ipFamily string, topts testOpts, polProg, hasHos for m, err := obj.FirstMap(); m != nil && err == nil; m, err = m.NextMap() { if m.IsMapInternal() { - ifaceLog := topts.progLog + "-" + bpfIfaceName + globals := libbpf.TcGlobalData{ + Tmtu: natTunnelMTU, + VxlanPort: testVxlanPort, + PSNatStart: uint16(topts.psnaStart), + PSNatLen: uint16(topts.psnatEnd-topts.psnaStart) + 1, + Flags: libbpf.GlobalsNoDSRCidrs, + IfaceName: setLogPrefix(topts.progLog + "-" + bpfIfaceName), + } if topts.ipv6 { - globals := libbpf.TcGlobalData{ - Tmtu: natTunnelMTU, - VxlanPort: testVxlanPort, - PSNatStart: uint16(topts.psnaStart), - PSNatLen: uint16(topts.psnatEnd-topts.psnaStart) + 1, - Flags: libbpf.GlobalsNoDSRCidrs, - } - copy(globals.HostTunnelIPv6[:], node1tunIPV6.To16()) copy(globals.HostIPv6[:], hostIP.To16()) copy(globals.IntfIPv6[:], intfIPV6.To16()) - - if err := tc.ConfigureProgram(m, ifaceLog, &globals); err != nil { - return nil, fmt.Errorf("failed to configure v6 tc program: %w", err) - } } else { - globals := libbpf.TcGlobalData{ - Tmtu: natTunnelMTU, - VxlanPort: testVxlanPort, - PSNatStart: uint16(topts.psnaStart), - PSNatLen: uint16(topts.psnatEnd-topts.psnaStart) + 1, - Flags: libbpf.GlobalsNoDSRCidrs, - } copy(globals.HostTunnelIPv4[0:4], node1tunIP.To4()) copy(globals.HostIPv4[0:4], hostIP.To4()) copy(globals.IntfIPv4[0:4], intfIP.To4()) - - if err := tc.ConfigureProgram(m, ifaceLog, &globals); err != nil { - return nil, fmt.Errorf("failed to configure tc program: %w", err) - } + } + if err := globals.Set(m); err != nil { + return nil, fmt.Errorf("failed to configure tc program: %w", err) } break } @@ -957,6 +928,12 @@ func xdpUpdateJumpMap(obj *libbpf.Obj, progs map[int]string) error { return nil } +func setLogPrefix(ifaceLog string) string { + in := []byte("---------------") + copy(in, ifaceLog) + return string(in) +} + type bpfRunResult struct { Retval int Duration int diff --git a/felix/bpf/xdp/attach.go b/felix/bpf/xdp/attach.go index a4cde68aefe..beed148ddb4 100644 --- a/felix/bpf/xdp/attach.go +++ b/felix/bpf/xdp/attach.go @@ -26,7 +26,6 @@ import ( "github.com/projectcalico/calico/felix/bpf/bpfdefs" "github.com/projectcalico/calico/felix/bpf/hook" "github.com/projectcalico/calico/felix/bpf/libbpf" - "github.com/projectcalico/calico/felix/bpf/maps" tcdefs "github.com/projectcalico/calico/felix/bpf/tc/defs" ) @@ -110,76 +109,39 @@ func (ap *AttachPoint) AlreadyAttached(object string) (int, bool) { return -1, false } -func ConfigureProgram(m *libbpf.Map, iface string, globalData *libbpf.XDPGlobalData) error { - in := []byte("---------------") - copy(in, iface) - globalData.IfaceName = string(in) - - if err := libbpf.XDPSetGlobals(m, globalData); err != nil { - return fmt.Errorf("failed to configure xdp: %w", err) - } - - return nil -} - type AttachResult int func (ar AttachResult) ProgID() int { return int(ar) } +func (ap *AttachPoint) Configuration() *libbpf.XDPGlobalData { + globalData := &libbpf.XDPGlobalData{} + if ap.HookLayoutV4 != nil { + for p, i := range ap.HookLayoutV4 { + globalData.Jumps[p] = uint32(i) + } + globalData.Jumps[tcdefs.ProgIndexPolicy] = uint32(ap.PolicyIdxV4) + } + if ap.HookLayoutV6 != nil { + for p, i := range ap.HookLayoutV6 { + globalData.JumpsV6[p] = uint32(i) + } + globalData.JumpsV6[tcdefs.ProgIndexPolicy] = uint32(ap.PolicyIdxV6) + } + in := []byte("---------------") + copy(in, ap.Iface) + globalData.IfaceName = string(in) + + return globalData +} + func (ap *AttachPoint) AttachProgram() (bpf.AttachResult, error) { // By now the attach type specific generic set of programs is loaded and we // only need to load and configure the preamble that will pass the // configuration further to the selected set of programs. binaryToLoad := path.Join(bpfdefs.ObjectDir, "xdp_preamble.o") - - obj, err := libbpf.OpenObject(binaryToLoad) - if err != nil { - return nil, err - } - defer obj.Close() - - for m, err := obj.FirstMap(); m != nil && err == nil; m, err = m.NextMap() { - mapName := m.Name() - if m.IsMapInternal() { - if strings.HasPrefix(mapName, ".rodata") { - continue - } - var globals libbpf.XDPGlobalData - - if ap.HookLayoutV4 != nil { - for p, i := range ap.HookLayoutV4 { - globals.Jumps[p] = uint32(i) - } - globals.Jumps[tcdefs.ProgIndexPolicy] = uint32(ap.PolicyIdxV4) - } - if ap.HookLayoutV6 != nil { - for p, i := range ap.HookLayoutV6 { - globals.JumpsV6[p] = uint32(i) - } - globals.JumpsV6[tcdefs.ProgIndexPolicy] = uint32(ap.PolicyIdxV6) - } - - if err := ConfigureProgram(m, ap.Iface, &globals); err != nil { - return nil, err - } - continue - } - - if size := maps.Size(mapName); size != 0 { - if err := m.SetSize(size); err != nil { - return nil, fmt.Errorf("error resizing map %s: %w", mapName, err) - } - } - - pinDir := bpf.MapPinDir(m.Type(), mapName, ap.Iface, hook.XDP) - if err := m.SetPinPath(path.Join(pinDir, mapName)); err != nil { - return nil, fmt.Errorf("error pinning map %s: %w", mapName, err) - } - } - // Check if the bpf object is already attached, and we should skip re-attaching it progID, isAttached := ap.AlreadyAttached(binaryToLoad) if isAttached { @@ -187,10 +149,9 @@ func (ap *AttachPoint) AttachProgram() (bpf.AttachResult, error) { return AttachResult(progID), nil } ap.Log().Infof("Continue with attaching BPF program %s", binaryToLoad) - - if err := obj.Load(); err != nil { - ap.Log().Warn("Failed to load program") - return nil, fmt.Errorf("error loading program: %w", err) + obj, err := bpf.LoadObject(binaryToLoad, ap.Configuration()) + if err != nil { + return nil, fmt.Errorf("error loading %s:%w", binaryToLoad, err) } oldID, err := ap.ProgramID()