Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions felix/bpf/libbpf/libbpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ const (

AttachTypeTcxIngress uint32 = C.BPF_TCX_INGRESS
AttachTypeTcxEgress uint32 = C.BPF_TCX_EGRESS
AttachTypeXDP uint32 = C.BPF_XDP
)

func (t *TcGlobalData) Set(m *Map) error {
Expand Down
1 change: 1 addition & 0 deletions felix/bpf/libbpf/libbpf_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ const (
GlobalsEgressPacketRateConfigured uint32 = 12345
AttachTypeTcxIngress uint32 = 12345
AttachTypeTcxEgress uint32 = 12345
AttachTypeXDP uint32 = 12345
)

func (m *Map) SetSize(size int) error {
Expand Down
72 changes: 45 additions & 27 deletions felix/bpf/ut/attach_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1266,21 +1266,23 @@ func TestAttachTcx(t *testing.T) {
Expect(err).NotTo(HaveOccurred())

loglevel := "off"
bpfEpMgr, err := newBPFTestEpMgr(
&linux.Config{
Hostname: "uthost",
BPFLogLevel: loglevel,
BPFDataIfacePattern: regexp.MustCompile("^hostep[12]"),
VXLANMTU: 1000,
VXLANPort: 1234,
BPFNodePortDSREnabled: false,
RulesConfig: rules.Config{
EndpointToHostAction: "RETURN",
},
BPFExtToServiceConnmark: 0,
BPFPolicyDebugEnabled: true,
BPFAttachType: v3.BPFAttachOptionTCX,
bpfConfig := &linux.Config{
Hostname: "uthost",
BPFLogLevel: loglevel,
BPFDataIfacePattern: regexp.MustCompile("^hostep[12]"),
VXLANMTU: 1000,
VXLANPort: 1234,
BPFNodePortDSREnabled: false,
RulesConfig: rules.Config{
EndpointToHostAction: "RETURN",
},
BPFExtToServiceConnmark: 0,
BPFPolicyDebugEnabled: true,
BPFAttachType: v3.BPFAttachOptionTCX,
}

bpfEpMgr, err := newBPFTestEpMgr(
bpfConfig,
bpfmaps,
regexp.MustCompile("^workloadep[0123]"),
)
Expand Down Expand Up @@ -1321,20 +1323,26 @@ func TestAttachTcx(t *testing.T) {
tcxProgs, err := tc.ListAttachedTcxPrograms("workloadep0", "ingress")
Expect(err).NotTo(HaveOccurred())
Expect(len(tcxProgs)).To(Equal(1))
// Now attach Tc program.
ap := &tc.AttachPoint{
AttachPoint: bpf.AttachPoint{
Iface: "workloadep0",
Hook: hook.Ingress,
},
HostIPv4: net.IPv4(1, 2, 3, 4),
IntfIPv4: net.IPv4(1, 6, 6, 6),
AttachType: v3.BPFAttachOptionTC,
}

_, err = tc.EnsureQdisc("workloadep0")
bpfConfig.BPFAttachType = v3.BPFAttachOptionTC
bpfEpMgr, err = newBPFTestEpMgr(
bpfConfig,
bpfmaps,
regexp.MustCompile("^workloadep[0123]"),
)
Expect(err).NotTo(HaveOccurred())
err = ap.AttachProgram()
bpfEpMgr.OnUpdate(&proto.HostMetadataUpdate{Hostname: "uthost", Ipv4Addr: "1.2.3.4"})
bpfEpMgr.OnUpdate(linux.NewIfaceStateUpdate("workloadep0", ifacemonitor.StateUp, workload0.Attrs().Index))
bpfEpMgr.OnUpdate(linux.NewIfaceAddrsUpdate("workloadep0", "1.6.6.6"))
bpfEpMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
Id: &proto.WorkloadEndpointID{
OrchestratorId: "k8s",
WorkloadId: "workloadep0",
EndpointId: "workloadep0",
},
Endpoint: &proto.WorkloadEndpoint{Name: "workloadep0"},
})
err = bpfEpMgr.CompleteDeferredWork()
Expect(err).NotTo(HaveOccurred())
progs, err = tc.ListAttachedPrograms("workloadep0", hook.Ingress.String(), true)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -1344,7 +1352,17 @@ func TestAttachTcx(t *testing.T) {
tcxProgs, err = tc.ListAttachedTcxPrograms("workloadep0", "ingress")
Expect(err).NotTo(HaveOccurred())
Expect(len(tcxProgs)).To(Equal(0))
// Now attach TCx again

bpfConfig.BPFAttachType = v3.BPFAttachOptionTCX
bpfEpMgr, err = newBPFTestEpMgr(
bpfConfig,
bpfmaps,
regexp.MustCompile("^workloadep[0123]"),
)
Expect(err).NotTo(HaveOccurred())
bpfEpMgr.OnUpdate(&proto.HostMetadataUpdate{Hostname: "uthost", Ipv4Addr: "1.2.3.4"})
bpfEpMgr.OnUpdate(linux.NewIfaceStateUpdate("workloadep0", ifacemonitor.StateUp, workload0.Attrs().Index))
bpfEpMgr.OnUpdate(linux.NewIfaceAddrsUpdate("workloadep0", "1.6.6.6"))
bpfEpMgr.OnUpdate(&proto.WorkloadEndpointUpdate{
Id: &proto.WorkloadEndpointID{
OrchestratorId: "k8s",
Expand Down
6 changes: 4 additions & 2 deletions felix/bpf/ut/bpf_prog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,14 +474,16 @@ func setupAndRun(logger testLogger, loglevel, section string, rules *polprog.Rul
}
Expect(errs).To(BeEmpty())
}()
var progType uint32
progType := uint32(0)
attachType := uint32(0)
if topts.xdp {
progType = unix.BPF_PROG_TYPE_XDP
attachType = libbpf.AttachTypeXDP
} else {
progType = unix.BPF_PROG_TYPE_SCHED_CLS
}
for i, p := range insns {
polProgFD, err := bpf.LoadBPFProgramFromInsns(p, "calico_policy", "Apache-2.0", progType)
polProgFD, err := bpf.LoadBPFProgramFromInsnsWithAttachType(p, "calico_policy", "Apache-2.0", progType, attachType)
Expect(err).NotTo(HaveOccurred(), "failed to load program into the kernel")
Expect(polProgFD).NotTo(BeZero())
polProgFDs = append(polProgFDs, polProgFD)
Expand Down
1 change: 1 addition & 0 deletions felix/dataplane/linux/bpf_ep_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -4145,6 +4145,7 @@ func (m *bpfEndpointManager) doUpdatePolicyProgram(
if hk == hook.XDP {
polProgsMap = m.commonMaps.XDPJumpMap
stride = jump.XDPMaxEntryPoints
attachType = libbpf.AttachTypeXDP
}
opts = append(opts, polprog.WithPolicyMapIndexAndStride(polJumpMapIdx, stride))

Expand Down
129 changes: 116 additions & 13 deletions felix/fv/bpf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import (
libapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
client "github.com/projectcalico/calico/libcalico-go/lib/clientv3"
options2 "github.com/projectcalico/calico/libcalico-go/lib/options"
"github.com/projectcalico/calico/libcalico-go/lib/set"
)

// We run with and without connection-time load balancing for a couple of reasons:
Expand Down Expand Up @@ -1190,6 +1191,83 @@ func describeBPFTests(opts ...bpfTestOpt) bool {
By("Waiting for dp to get setup up")

ensureBPFProgramsAttached(tc.Felixes[0], "bpfout.cali")
progIDs := set.New[int]()
mapIDs := set.New[int]()

// Get the program IDs of the preamble programs that we attach
// as part of this test. There can be other preamble programs
// from previous tests and we want to ignore those when checking that programs are cleaned up after disabling BPF.
getPreambleProgramIDs := func() set.Set[int] {
var bpfnetTCX []struct {
TC []struct {
Name string `json:"name"`
ID int `json:"prog_id"`
} `json:"tc"`
}

var bpfnet []struct {
TC []struct {
Name string `json:"name"`
ID int `json:"id"`
} `json:"tc"`
}
out, err := tc.Felixes[0].ExecOutput("bpftool", "net", "show", "-j")
Expect(err).NotTo(HaveOccurred())
preambleIDs := set.New[int]()
if BPFAttachType() == "tc" {
err = json.Unmarshal([]byte(out), &bpfnet)
Expect(err).NotTo(HaveOccurred())
for _, entry := range bpfnet {
for _, prog := range entry.TC {
if strings.Contains(prog.Name, "cali_tc_pream") {
preambleIDs.Add(prog.ID)
}
}
}
} else {
err = json.Unmarshal([]byte(out), &bpfnetTCX)
Expect(err).NotTo(HaveOccurred())
for _, entry := range bpfnetTCX {
for _, prog := range entry.TC {
if strings.Contains(prog.Name, "cali_tc_pream") {
preambleIDs.Add(prog.ID)
}
}
}
}
return preambleIDs
}

var preambleIDsBefore set.Set[int]
Eventually(func() int {
preambleIDsBefore = getPreambleProgramIDs()
return preambleIDsBefore.Len()
}, "15s", "1s").Should(Equal(10)) // 10 = 2 (ingress+egress) * 5 interfaces (bpfout, lo, eth0, caliXXX x2)

type bpfProgs []struct {
ID int `json:"id"`
Name string `json:"name"`
MapIDs []int `json:"map_ids"`
}
programs := bpfProgs{}
out, err := tc.Felixes[0].ExecOutput("bpftool", "prog", "show", "-j")
Expect(err).NotTo(HaveOccurred())
err = json.Unmarshal([]byte(out), &programs)
Expect(err).NotTo(HaveOccurred())

// Get the program and map IDs of all program that are currently attached.
for _, prog := range programs {
if strings.Contains(prog.Name, "cali_tc_pream") && !preambleIDsBefore.Contains(prog.ID) {
continue
}
progIDs.Add(prog.ID)
mapIDs.AddAll(prog.MapIDs)
}

// check for cgroups
out, err = tc.Felixes[0].ExecOutput("bpftool", "cgroup", "show", "/run/calico/cgroup")
Expect(err).NotTo(HaveOccurred())
Expect(out).To(ContainSubstring("calico_connect"))

By("Changing env and restarting felix")

Expand All @@ -1198,21 +1276,46 @@ func describeBPFTests(opts ...bpfTestOpt) bool {

By("Checking that all programs got cleaned up")

Eventually(func() string {
out, _ := tc.Felixes[0].ExecOutput("bpftool", "-jp", "prog", "show")
return out
}, "15s", "1s").ShouldNot(
Or(ContainSubstring("cali_"), ContainSubstring("calico_"), ContainSubstring("xdp_cali_")))
// Check that the preamble programs we attached got cleaned up.
Eventually(func() int {
return getPreambleProgramIDs().Len()
}, "15s", "1s").Should(Equal(0))

// N.B. calico_failsafe map is created in iptables mode by
// bpf.NewFailsafeMap() It has calico_ prefix. All other bpf
// maps have only cali_ prefix.
Eventually(func() string {
out, _ := tc.Felixes[0].ExecOutput("bpftool", "-jp", "map", "show")
return out
}, "15s", "1s").ShouldNot(Or(ContainSubstring("cali_"), ContainSubstring("xdp_cali_")))
programs = bpfProgs{}
out, err = tc.Felixes[0].ExecOutput("bpftool", "prog", "show", "-j")
Expect(err).NotTo(HaveOccurred())
err = json.Unmarshal([]byte(out), &programs)
Expect(err).NotTo(HaveOccurred())
mapIDsAfter := set.New[int]()
progIDsAfter := set.New[int]()
for _, prog := range programs {
progIDsAfter.Add(prog.ID)
}

for _, prog := range progIDs.Slice() {
Expect(progIDsAfter).NotTo(ContainElement(prog))
}

var bpfMaps []struct {
ID int `json:"id"`
}
out, err = tc.Felixes[0].ExecOutput("bpftool", "map", "show", "-j")
Expect(err).NotTo(HaveOccurred())
err = json.Unmarshal([]byte(out), &bpfMaps)
Expect(err).NotTo(HaveOccurred())

for _, m := range bpfMaps {
mapIDsAfter.Add(m.ID)
}
for _, id := range mapIDs.Slice() {
Expect(mapIDsAfter).NotTo(ContainElement(id))
}

out, err = tc.Felixes[0].ExecOutput("bpftool", "cgroup", "show", "/run/calico/cgroup")
Expect(err).NotTo(HaveOccurred())
Expect(out).NotTo(ContainSubstring("calico_connect"))

out, _ := tc.Felixes[0].ExecCombinedOutput("ip", "link", "show", "dev", "bpfin.cali")
out, _ = tc.Felixes[0].ExecCombinedOutput("ip", "link", "show", "dev", "bpfin.cali")
Expect(out).To(Equal("Device \"bpfin.cali\" does not exist.\n"))
out, _ = tc.Felixes[0].ExecCombinedOutput("ip", "link", "show", "dev", "bpfout.cali")
Expect(out).To(Equal("Device \"bpfout.cali\" does not exist.\n"))
Expand Down