Skip to content

Commit

Permalink
[BPF] programs profiling
Browse files Browse the repository at this point in the history
When BPFPRofiling is set to Enabled, bpf programs execution will collect
duration of ebpf processing per device, per direction and per
new/established connection metrics. 'calico-bpf prifiling e2e' can dump
the stats. It zeroes the stats after dump.

----------------+-------------+-----+-------------+-------+-------------+-------+-------------+-------+
|     IFACE      | INGRESS NEW |  #  | INGRESS EST |   #   | EGRESS NEW  |   #   | EGRESS ETS  |   #   |
+----------------+-------------+-----+-------------+-------+-------------+-------+-------------+-------+
| lo             | ---         | --- | ---         | ---   | 142.263 ns  | 10272 | ---         | ---   |
| eth0           | 2492.344 ns |  32 | 1535.443 ns | 16114 | 6296.421 ns |   749 | 1503.339 ns | 10982 |
| eni76136be4c77 | 5031.436 ns | 149 | 1194.923 ns |  1421 | 4950.196 ns |   138 | 1437.015 ns |  1432 |
| eni80d5c04bc95 | 7773.459 ns |  74 | 1508.973 ns |   641 | 4907.333 ns |    69 | 1715.848 ns |   646 |
| eth1           | 136.250 ns  |  24 | ---         | ---   | 75.320 ns   |    25 | ---         | ---   |
| eni5f8ab1cfc29 | 107.250 ns  |  36 | 1068.596 ns |  1514 | 189.528 ns  |    36 | 1104.335 ns |  1658 |
| bpfout.cali    | 440.000 ns  |   1 | ---         | ---   | 206.000 ns  |     1 | ---         | ---   |
+----------------+-------------+-----+-------------+-------+-------------+-------+-------------+-------+
  • Loading branch information
tomastigera committed Dec 3, 2024
1 parent 8a901cc commit 966f3b1
Show file tree
Hide file tree
Showing 37 changed files with 1,530 additions and 28 deletions.
5 changes: 5 additions & 0 deletions api/pkg/apis/projectcalico/v3/felixconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,11 @@ type FelixConfigurationSpec struct {
//+kubebuilder:validation:Enum=Enabled;Disabled;L2Only
BPFRedirectToPeer string `json:"bpfRedirectToPeer,omitempty"`

// BPFProfiling controls profiling of BPF programs. At the monent, it can be
// Disabled or Enabled. [Default: Disabled]
//+kubebuilder:validation:Enum=Enabled;Disabled
BPFProfiling string `json:"bpfProfiling,omitempty"`

// RouteSource configures where Felix gets its routing information.
// - WorkloadIPs: use workload endpoints to construct routes.
// - CalicoIPAM: the default - use IPAM data to construct routes.
Expand Down
7 changes: 7 additions & 0 deletions api/pkg/openapi/generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion felix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ $(FELIX_CONTAINER_CREATED): register \
docker-image/felix.cfg \
docker-image/Dockerfile \
$(shell test "$(FELIX_IMAGE_ID)" || echo force-rebuild)
$(DOCKER_BUILD) -t $(FELIX_IMAGE_WITH_TAG) -f ./docker-image/Dockerfile docker-image
$(DOCKER_BUILD) --network=host -t $(FELIX_IMAGE_WITH_TAG) -f ./docker-image/Dockerfile docker-image
$(MAKE) retag-build-images-with-registries VALIDARCHES=$(ARCH) IMAGETAG=latest
touch $(FELIX_CONTAINER_CREATED)

Expand Down
1 change: 1 addition & 0 deletions felix/bpf-gpl/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ extern const volatile struct cali_tc_preamble_globals __globals;
#define HOST_TUNNEL_IP CALI_CONFIGURABLE_IP(host_tunnel_ip)
#define WG_PORT CALI_CONFIGURABLE(wg_port)
#define NATIN_IFACE CALI_CONFIGURABLE(natin_idx)
#define PROFILING CALI_CONFIGURABLE(profiling)

#ifdef UNITTEST
#define CALI_PATCH_DEFINE(name, pattern) \
Expand Down
33 changes: 22 additions & 11 deletions felix/bpf-gpl/fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "types.h"
#include "skb.h"
#include "ifstate.h"
#include "profiling.h"

#if CALI_FIB_ENABLED
#define fwd_fib(fwd) ((fwd)->fib)
Expand Down Expand Up @@ -382,22 +383,32 @@ static CALI_BPF_INLINE int forward_or_drop(struct cali_tc_ctx *ctx)
skb_set_mark(ctx->skb, ctx->fwd.mark); /* make sure that each pkt has SEEN mark */
}

if (CALI_LOG_LEVEL >= CALI_LOG_LEVEL_INFO) {
__u64 prog_end_time = bpf_ktime_get_ns();
CALI_INFO("Final result=ALLOW (%d). Program execution time: %lluns",
reason, prog_end_time-state->prog_start_time);
}

return rc;
goto allow;

deny:
if (CALI_LOG_LEVEL >= CALI_LOG_LEVEL_INFO) {
rc = TC_ACT_SHOT;

allow:
if (CALI_LOG_LEVEL_INFO >= CALI_LOG_LEVEL_INFO || PROFILING) {
__u64 prog_end_time = bpf_ktime_get_ns();
CALI_INFO("Final result=DENY (%x). Program execution time: %lluns",
reason, prog_end_time-state->prog_start_time);

if (PROFILING) {
prof_record_sample(ctx->skb->ifindex,
(CALI_F_FROM_HEP || CALI_F_TO_WEP ? 0 : 2) +
(ct_result_rc(ctx->state->ct_result.rc) == CALI_CT_NEW ? 0 : 1),
state->prog_start_time, prog_end_time);
}

if (rc == TC_ACT_SHOT) {
CALI_INFO("Final result=DENY (%d). Program execution time: %lluns",
reason, prog_end_time-state->prog_start_time);
} else {
CALI_INFO("Final result=ALLOW (%d). Program execution time: %lluns",
reason, prog_end_time-state->prog_start_time);
}
}

return TC_ACT_SHOT;
return rc;
}

#endif /* __CALI_FIB_H__ */
2 changes: 1 addition & 1 deletion felix/bpf-gpl/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct name { \
ip_t host_tunnel_ip; \
__be32 flags; \
__be16 wg_port; \
__be16 __pad; \
__be16 profiling; \
__u32 natin_idx; \
__u32 natout_idx; \
__u8 iface_name[16]; \
Expand Down
47 changes: 47 additions & 0 deletions felix/bpf-gpl/profiling.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Project Calico BPF dataplane programs.
// Copyright (c) 2024 Tigera, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later

#ifndef __CALI_BPF_PROFILING_H__
#define __CALI_BPF_PROFILING_H__

struct prof_key {
__u32 ifindex;
__u32 kind;
};

struct prof_val {
__u64 time;
__u64 samples;
};

CALI_MAP(cali_profiling, 2,
BPF_MAP_TYPE_PERCPU_HASH,
struct prof_key, struct prof_val,
20000, 0)

static CALI_BPF_INLINE void prof_record_sample(__u32 ifindex, __u32 kind, __u64 start, __u64 end)
{
struct prof_key key = {
.ifindex = ifindex,
.kind = kind,
};

__u64 diff = end - start;

struct prof_val *val = cali_profiling_lookup_elem(&key);

if (val) {
val->time += diff;
val->samples++;
} else {
struct prof_val val = {
.time = diff,
.samples = 1,
};

cali_profiling_update_elem(&key, &val, 0);
}
}

#endif /* __CALI_BPF_PROFILING_H__ */
2 changes: 1 addition & 1 deletion felix/bpf-gpl/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ int calico_tc_main(struct __sk_buff *skb)

counter_inc(ctx, COUNTER_TOTAL_PACKETS);

if (CALI_LOG_LEVEL >= CALI_LOG_LEVEL_INFO) {
if (CALI_LOG_LEVEL >= CALI_LOG_LEVEL_INFO || PROFILING) {
ctx->state->prog_start_time = bpf_ktime_get_ns();
}

Expand Down
1 change: 1 addition & 0 deletions felix/bpf/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type AttachPoint struct {
PolicyIdxV6 int
Iface string
LogLevel string
Profiling string
}

func (ap *AttachPoint) LogVal() string {
Expand Down
4 changes: 4 additions & 0 deletions felix/bpf/bpfmap/bpf_maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/projectcalico/calico/felix/bpf/jump"
"github.com/projectcalico/calico/felix/bpf/maps"
"github.com/projectcalico/calico/felix/bpf/nat"
"github.com/projectcalico/calico/felix/bpf/profiling"
"github.com/projectcalico/calico/felix/bpf/routes"
"github.com/projectcalico/calico/felix/bpf/state"
)
Expand All @@ -56,6 +57,7 @@ type CommonMaps struct {
JumpMap maps.MapWithDeleteIfExists
XDPProgramsMap maps.Map
XDPJumpMap maps.MapWithDeleteIfExists
ProfilingMap maps.Map
}

type Maps struct {
Expand Down Expand Up @@ -87,6 +89,7 @@ func getCommonMaps() *CommonMaps {
JumpMap: jump.Map().(maps.MapWithDeleteIfExists),
XDPProgramsMap: hook.NewXDPProgramsMap(),
XDPJumpMap: jump.XDPMap().(maps.MapWithDeleteIfExists),
ProfilingMap: profiling.Map(),
}
}

Expand Down Expand Up @@ -168,6 +171,7 @@ func (c *CommonMaps) slice() []maps.Map {
c.JumpMap,
c.XDPProgramsMap,
c.XDPJumpMap,
c.ProfilingMap,
}
}

Expand Down
1 change: 1 addition & 0 deletions felix/bpf/libbpf/libbpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ func TcSetGlobals(
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),
Expand Down
4 changes: 3 additions & 1 deletion felix/bpf/libbpf/libbpf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ void bpf_tc_set_globals(struct bpf_map *map,
uint flags,
ushort wg_port,
ushort wg6_port,
ushort profiling,
uint natin,
uint natout,
uint log_filter_jmp,
Expand All @@ -167,6 +168,7 @@ void bpf_tc_set_globals(struct bpf_map *map,
.psnat_len = psnat_len,
.flags = flags,
.wg_port = wg_port,
.profiling = profiling,
.natin_idx = natin,
.natout_idx = natout,
.log_filter_jmp = log_filter_jmp,
Expand Down Expand Up @@ -334,7 +336,7 @@ void bpf_xdp_set_globals(struct bpf_map *map, char *iface_name, uint *jumps, uin
strncpy(data.v4.iface_name, iface_name, sizeof(data.v4.iface_name));
data.v4.iface_name[sizeof(data.v4.iface_name)-1] = '\0';
data.v6 = data.v4;

int i;

for (i = 0; i < sizeof(data.v4.jumps)/sizeof(__u32); i++) {
Expand Down
1 change: 1 addition & 0 deletions felix/bpf/libbpf/libbpf_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type TcGlobalData struct {
Flags uint32
WgPort uint16
Wg6Port uint16
Profiling uint16
NatIn uint32
NatOut uint32
LogFilterJmp uint32
Expand Down
63 changes: 63 additions & 0 deletions felix/bpf/profiling/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2024 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package profiling

import (
"encoding/binary"

"github.com/projectcalico/calico/felix/bpf/maps"
)

const (
KeySize = 8 // 2 x uint32
ValueSize = 16 // 2 x uint64
)

var MapParameters = maps.MapParameters{
Type: "percpu_hash",
KeySize: KeySize,
ValueSize: ValueSize,
MaxEntries: 20000,
Name: "cali_profiling",
Version: 2,
}

func Map() maps.Map {
return maps.NewPinnedMap(MapParameters)
}

type Key struct {
Ifindex int
Kind int
}

func KeyFromBytes(b []byte) Key {
return Key{
Ifindex: int(binary.LittleEndian.Uint32(b[0:4])),
Kind: int(binary.LittleEndian.Uint32(b[4:8])),
}
}

type Value struct {
Time int
Samples int
}

func ValueFromBytes(b []byte) Value {
return Value{
Time: int(binary.LittleEndian.Uint64(b[0:8])),
Samples: int(binary.LittleEndian.Uint64(b[8:16])),
}
}
4 changes: 4 additions & 0 deletions felix/bpf/tc/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,10 @@ func (ap *AttachPoint) ConfigureProgram(m *libbpf.Map) error {
LogFilterJmp: uint32(ap.LogFilterIdx),
}

if ap.Profiling == "Enabled" {
globalData.Profiling = 1
}

copy(globalData.HostIPv4[0:4], ap.HostIPv4.To4())
copy(globalData.HostIPv6[:], ap.HostIPv6.To16())

Expand Down
5 changes: 4 additions & 1 deletion felix/bpf/ut/bpf_prog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import (
"github.com/projectcalico/calico/felix/bpf/maps"
"github.com/projectcalico/calico/felix/bpf/nat"
"github.com/projectcalico/calico/felix/bpf/polprog"
"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"
Expand Down Expand Up @@ -576,6 +577,7 @@ var (
natMap, natBEMap, ctMap, rtMap, ipsMap, testStateMap, affinityMap, arpMap, fsafeMap maps.Map
natMapV6, natBEMapV6, ctMapV6, rtMapV6, ipsMapV6, affinityMapV6, arpMapV6, fsafeMapV6 maps.Map
stateMap, countersMap, ifstateMap, progMap, progMapXDP, policyJumpMap, policyJumpMapXDP maps.Map
profilingMap maps.Map
allMaps []maps.Map
)

Expand Down Expand Up @@ -603,10 +605,11 @@ func initMapsOnce() {
ifstateMap = ifstate.Map()
policyJumpMap = jump.Map()
policyJumpMapXDP = jump.XDPMap()
profilingMap = profiling.Map()

allMaps = []maps.Map{natMap, natBEMap, natMapV6, natBEMapV6, ctMap, ctMapV6, rtMap, rtMapV6, ipsMap, ipsMapV6,
stateMap, testStateMap, affinityMap, affinityMapV6, arpMap, arpMapV6, fsafeMap, fsafeMapV6,
countersMap, ifstateMap,
countersMap, ifstateMap, profilingMap,
policyJumpMap, policyJumpMapXDP}
for _, m := range allMaps {
err := m.EnsureExists()
Expand Down
Loading

0 comments on commit 966f3b1

Please sign in to comment.