This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-rover.git
The following commit(s) were added to refs/heads/main by this push:
new 2331dbe Support monitoring ztunnel to adapt istio ambient mode (#142)
2331dbe is described below
commit 2331dbe091343b9ebb2c74a8c6500af80274fb07
Author: mrproliu <[email protected]>
AuthorDate: Sat Sep 14 15:09:51 2024 +0800
Support monitoring ztunnel to adapt istio ambient mode (#142)
---
CHANGES.md | 1 +
bpf/accesslog/accesslog.c | 5 +-
bpf/accesslog/ambient/ztunnel.c | 52 ++++++
bpf/accesslog/ambient/ztunnel.h | 39 ++++
go.mod | 2 +-
go.sum | 4 +-
pkg/accesslog/collector/collector.go | 4 +
pkg/accesslog/collector/ztunnel.go | 200 +++++++++++++++++++++
pkg/accesslog/common/connection.go | 20 +++
.../{collector/collector.go => events/ztunnel.go} | 27 +--
pkg/tools/elf/elf.go | 23 ++-
scripts/build/bash/btfgen.sh | 2 +-
12 files changed, 350 insertions(+), 29 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 320d3f9..0e1c187 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ Release Notes.
* Add `pprof` module for observe self.
* Add detect process from `CRI-O` container in Kubernetes.
* Introduce `MonitorFilter` into access log module.
+* Support monitoring ztunnel to adapt istio ambient mode.
#### Bug Fixes
* Fixed the issue where `conntrack` could not find the Reply IP in the access
log module.
diff --git a/bpf/accesslog/accesslog.c b/bpf/accesslog/accesslog.c
index 87b62dd..a9e1088 100644
--- a/bpf/accesslog/accesslog.c
+++ b/bpf/accesslog/accesslog.c
@@ -56,4 +56,7 @@ char __license[] SEC("license") = "Dual MIT/GPL";
// tls monitoring
#include "tls/go_tls.c"
#include "tls/node_tls.c"
-#include "tls/openssl.c"
\ No newline at end of file
+#include "tls/openssl.c"
+
+// ambient istio
+#include "ambient/ztunnel.c"
\ No newline at end of file
diff --git a/bpf/accesslog/ambient/ztunnel.c b/bpf/accesslog/ambient/ztunnel.c
new file mode 100644
index 0000000..5d5ffae
--- /dev/null
+++ b/bpf/accesslog/ambient/ztunnel.c
@@ -0,0 +1,52 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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.
+
+#include "ztunnel.h"
+
+static __inline bool get_socket_addr_ip_in_ztunnel(bool success, void * arg,
__u32 *ip, __u16 *port) {
+ if (!success) {
+ return false;
+ }
+ __u8 sockaddr[8];
+ if (bpf_probe_read(&sockaddr, sizeof(sockaddr), (void *)arg) != 0) {
+ return false;
+ }
+ // ip is stored in sockaddr[2], sockaddr[3], sockaddr[4], sockaddr[5]
+ *ip = ((__u32)sockaddr[2] << 24) | ((__u32)sockaddr[3] << 16) |
((__u32)sockaddr[4] << 8) | (__u32)sockaddr[5];
+ if (port != NULL) {
+ // port is stored in sockaddr[6], sockaddr[7](should convert to
big-endian)
+ *port = ((__u16)sockaddr[7] << 8) | sockaddr[6];
+ }
+ return true;
+}
+
+SEC("uprobe/connection_manager_track_outbound")
+int connection_manager_track_outbound(struct pt_regs* ctx) {
+ struct ztunnel_socket_mapping_t *event =
create_ztunnel_socket_mapping_event();
+ if (event == NULL) {
+ return 0;
+ }
+ bool success = true;
+ success = get_socket_addr_ip_in_ztunnel(success, (void
*)PT_REGS_PARM3(ctx), &event->orginal_src_ip, &event->src_port);
+ success = get_socket_addr_ip_in_ztunnel(success, (void
*)PT_REGS_PARM4(ctx), &event->original_dst_ip, &event->dst_port);
+ success = get_socket_addr_ip_in_ztunnel(success, (void
*)PT_REGS_PARM5(ctx), &event->lb_dst_ip, NULL);
+ if (!success) {
+ return 0;
+ }
+ bpf_perf_event_output(ctx, &ztunnel_lb_socket_mapping_event_queue,
BPF_F_CURRENT_CPU, event, sizeof(*event));
+ return 0;
+}
diff --git a/bpf/accesslog/ambient/ztunnel.h b/bpf/accesslog/ambient/ztunnel.h
new file mode 100644
index 0000000..95fc1a0
--- /dev/null
+++ b/bpf/accesslog/ambient/ztunnel.h
@@ -0,0 +1,39 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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.
+
+struct ztunnel_socket_mapping_t {
+ __u32 orginal_src_ip; // origin local ip
+ __u32 original_dst_ip; // origin remote ip(should be service ip)
+ __u16 src_port; // origin local port
+ __u16 dst_port; // origin remote port
+ __u32 lb_dst_ip; // load balanced remote ip(should be real pod
ip)
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+} ztunnel_lb_socket_mapping_event_queue SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, __u32);
+ __type(value, struct ztunnel_socket_mapping_t);
+ __uint(max_entries, 1);
+} ztunnel_socket_mapping_event_per_cpu_map SEC(".maps");
+
+static __inline struct ztunnel_socket_mapping_t*
create_ztunnel_socket_mapping_event() {
+ __u32 kZero = 0;
+ return bpf_map_lookup_elem(&ztunnel_socket_mapping_event_per_cpu_map,
&kZero);
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 0b60a47..191be7b 100644
--- a/go.mod
+++ b/go.mod
@@ -26,7 +26,7 @@ require (
k8s.io/apimachinery v0.23.5
k8s.io/client-go v0.23.5
k8s.io/utils v0.0.0-20211116205334-6203023598ed
- skywalking.apache.org/repo/goapi v0.0.0-20240604102541-64f9001abe03
+ skywalking.apache.org/repo/goapi v0.0.0-20240914024804-703f701836e6
)
require (
diff --git a/go.sum b/go.sum
index 09ece52..5fcd734 100644
--- a/go.sum
+++ b/go.sum
@@ -1062,5 +1062,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.2.1
h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLz
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod
h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-skywalking.apache.org/repo/goapi v0.0.0-20240604102541-64f9001abe03
h1:y0f+3gNmeyC/V5Bt8VE9aL9mmWESj+WvyqJ2tOb7qrk=
-skywalking.apache.org/repo/goapi v0.0.0-20240604102541-64f9001abe03/go.mod
h1:+n8BMuS8eRdzdnGh15ElRGBXPi0eYZSs2TKySBDmRTE=
+skywalking.apache.org/repo/goapi v0.0.0-20240914024804-703f701836e6
h1:ZGcxRsuAF+Q/IHzNzunHTeYPSCbXcLIjonEFkDlAfPc=
+skywalking.apache.org/repo/goapi v0.0.0-20240914024804-703f701836e6/go.mod
h1:+n8BMuS8eRdzdnGh15ElRGBXPi0eYZSs2TKySBDmRTE=
diff --git a/pkg/accesslog/collector/collector.go
b/pkg/accesslog/collector/collector.go
index e7d6e9b..8e2f4ae 100644
--- a/pkg/accesslog/collector/collector.go
+++ b/pkg/accesslog/collector/collector.go
@@ -19,9 +19,12 @@ package collector
import (
"github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/logger"
"github.com/apache/skywalking-rover/pkg/module"
)
+var log = logger.GetLogger("accesslog", "collector")
+
type Collector interface {
Start(mgr *module.Manager, context *common.AccessLogContext) error
Stop()
@@ -35,5 +38,6 @@ func Collectors() []Collector {
connectCollectInstance,
tlsCollectInstance,
processCollectInstance,
+ zTunnelCollectInstance,
}
}
diff --git a/pkg/accesslog/collector/ztunnel.go
b/pkg/accesslog/collector/ztunnel.go
new file mode 100644
index 0000000..16c39a5
--- /dev/null
+++ b/pkg/accesslog/collector/ztunnel.go
@@ -0,0 +1,200 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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 collector
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "time"
+
+ "k8s.io/apimachinery/pkg/util/cache"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/module"
+ "github.com/apache/skywalking-rover/pkg/tools/elf"
+ "github.com/apache/skywalking-rover/pkg/tools/host"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+
+ "github.com/shirou/gopsutil/process"
+)
+
+var (
+ // ZTunnelProcessFinderInterval is the interval to find ztunnel process
+ ZTunnelProcessFinderInterval = time.Second * 30
+ // ZTunnelTrackBoundSymbolPrefix is the prefix of the symbol name to
track outbound connections in ztunnel process
+ // ztunnel::proxy::connection_manager::ConnectionManager::track_outbound
+ ZTunnelTrackBoundSymbolPrefix =
"_ZN7ztunnel5proxy18connection_manager17ConnectionManager14track_outbound"
+)
+
+var zTunnelCollectInstance = NewZTunnelCollector(time.Minute)
+
+// ZTunnelCollector is a collector for ztunnel process in the Ambient Istio
scenario
+type ZTunnelCollector struct {
+ ctx context.Context
+ cancel context.CancelFunc
+ alc *common.AccessLogContext
+
+ collectingProcess *process.Process
+ ipMappingCache *cache.Expiring
+ ipMappingExpireDuration time.Duration
+}
+
+func NewZTunnelCollector(expireTime time.Duration) *ZTunnelCollector {
+ return &ZTunnelCollector{
+ ipMappingCache: cache.NewExpiring(),
+ ipMappingExpireDuration: expireTime,
+ }
+}
+
+func (z *ZTunnelCollector) Start(mgr *module.Manager, ctx
*common.AccessLogContext) error {
+ z.ctx, z.cancel = context.WithCancel(ctx.RuntimeContext)
+ z.alc = ctx
+ ctx.ConnectionMgr.RegisterNewFlushListener(z)
+
+ err := z.findZTunnelProcessAndCollect()
+ if err != nil {
+ return err
+ }
+
+ ctx.BPF.ReadEventAsync(ctx.BPF.ZtunnelLbSocketMappingEventQueue,
func(data interface{}) {
+ event := data.(*events.ZTunnelSocketMappingEvent)
+ localIP := z.convertBPFIPToString(event.OriginalSrcIP)
+ localPort := event.OriginalSrcPort
+ remoteIP := z.convertBPFIPToString(event.OriginalDestIP)
+ remotePort := event.OriginalDestPort
+ lbIP := z.convertBPFIPToString(event.LoadBalancedDestIP)
+ log.Debugf("received ztunnel lb socket mapping event: %s:%d ->
%s:%d, lb: %s", localIP, localPort, remoteIP, remotePort, lbIP)
+
+ key := z.buildIPMappingCacheKey(localIP, int(localPort),
remoteIP, int(remotePort))
+ z.ipMappingCache.Set(key, lbIP, z.ipMappingExpireDuration)
+ }, func() interface{} {
+ return &events.ZTunnelSocketMappingEvent{}
+ })
+ go func() {
+ ticker := time.NewTicker(ZTunnelProcessFinderInterval)
+ for {
+ select {
+ case <-ticker.C:
+ err := z.findZTunnelProcessAndCollect()
+ if err != nil {
+ log.Error("failed to find and collect
ztunnel process: ", err)
+ }
+ case <-z.ctx.Done():
+ ticker.Stop()
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (z *ZTunnelCollector) ReadyToFlushConnection(connection
*common.ConnectionInfo, _ events.Event) {
+ if connection == nil || connection.Socket == nil ||
connection.RPCConnection == nil || connection.RPCConnection.Attachment != nil {
+ return
+ }
+ key := z.buildIPMappingCacheKey(connection.Socket.SrcIP,
int(connection.Socket.SrcPort),
+ connection.Socket.DestIP, int(connection.Socket.DestPort))
+ lbIPObj, found := z.ipMappingCache.Get(key)
+ if !found {
+ log.Debugf("there no ztunnel mapped IP address found for
connection ID: %d, random ID: %d",
+ connection.ConnectionID, connection.RandomID)
+ return
+ }
+ lbIP := lbIPObj.(string)
+ log.Debugf("found the ztunnel load balanced IP for the connection: %s,
connectionID: %d, randomID: %d", lbIP,
+ connection.ConnectionID, connection.RandomID)
+ connection.RPCConnection.Attachment = &v3.ConnectionAttachment{
+ Environment: &v3.ConnectionAttachment_ZTunnel{
+ ZTunnel: &v3.ZTunnelAttachmentEnvironment{
+ RealDestinationIp: lbIP,
+ By:
v3.ZTunnelAttachmentEnvironmentDetectBy_ZTUNNEL_OUTBOUND_FUNC,
+ },
+ },
+ }
+}
+
+func (z *ZTunnelCollector) convertBPFIPToString(ip uint32) string {
+ return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip>>16&0xff, ip>>8&0xff,
ip&0xff)
+}
+
+func (z *ZTunnelCollector) buildIPMappingCacheKey(localIP string, localPort
int, remoteIP string, remotePort int) string {
+ return fmt.Sprintf("%s:%d-%s:%d", localIP, localPort, remoteIP,
remotePort)
+}
+
+func (z *ZTunnelCollector) Stop() {
+ if z.cancel != nil {
+ z.cancel()
+ }
+}
+
+func (z *ZTunnelCollector) findZTunnelProcessAndCollect() error {
+ if z.collectingProcess != nil {
+ running, err := z.collectingProcess.IsRunning()
+ if err == nil && running {
+ // already collecting the process
+ return nil
+ }
+ log.Warnf("detected ztunnel process is not running, should
re-scan process to find and collect it")
+ }
+
+ processes, err := process.Processes()
+ if err != nil {
+ return err
+ }
+ var zTunnelProcess *process.Process
+ for _, p := range processes {
+ name, err := p.Exe()
+ if err != nil {
+ continue
+ }
+ if strings.HasSuffix(name, "/ztunnel") {
+ zTunnelProcess = p
+ break
+ }
+ }
+
+ if zTunnelProcess == nil {
+ log.Debugf("ztunnel process not found is current node")
+ return nil
+ }
+
+ log.Infof("ztunnel process founded in current node, pid: %d",
zTunnelProcess.Pid)
+ z.collectingProcess = zTunnelProcess
+ return z.collectZTunnelProcess(zTunnelProcess)
+}
+
+func (z *ZTunnelCollector) collectZTunnelProcess(p *process.Process) error {
+ pidExeFile := host.GetFileInHost(fmt.Sprintf("/proc/%d/exe", p.Pid))
+ elfFile, err := elf.NewFile(pidExeFile)
+ if err != nil {
+ return fmt.Errorf("read executable file error: %v", err)
+ }
+ trackBoundSymbol := elfFile.FilterSymbol(func(name string) bool {
+ return strings.HasPrefix(name, ZTunnelTrackBoundSymbolPrefix)
+ }, true)
+ if len(trackBoundSymbol) == 0 {
+ return fmt.Errorf("failed to find track outbound symbol in
ztunnel process")
+ }
+
+ uprobeFile := z.alc.BPF.OpenUProbeExeFile(pidExeFile)
+ uprobeFile.AddLink(trackBoundSymbol[0].Name,
z.alc.BPF.ConnectionManagerTrackOutbound, nil)
+ return nil
+}
diff --git a/pkg/accesslog/common/connection.go
b/pkg/accesslog/common/connection.go
index de98fb9..fe1065c 100644
--- a/pkg/accesslog/common/connection.go
+++ b/pkg/accesslog/common/connection.go
@@ -85,6 +85,11 @@ type ConnectionProcessor interface {
OnConnectionClose(event *events.SocketCloseEvent, callback
ConnectionProcessFinishCallback)
}
+type FlusherListener interface {
+ // ReadyToFlushConnection notify which connection ready to flush
+ ReadyToFlushConnection(connection *ConnectionInfo,
getConnectionFromEvent events.Event)
+}
+
type ProcessListener interface {
OnNewProcessMonitoring(pid int32)
OnProcessRemoved(pid int32)
@@ -115,6 +120,8 @@ type ConnectionManager struct {
// connection already close but the connection (protocols)log not build
finished
allUnfinishedConnections map[string]*bool
+
+ flushListeners []FlusherListener
}
func (c *ConnectionManager) RegisterProcessor(processor ConnectionProcessor) {
@@ -125,6 +132,10 @@ func (c *ConnectionManager) AddProcessListener(listener
ProcessListener) {
c.processListeners = append(c.processListeners, listener)
}
+func (c *ConnectionManager) RegisterNewFlushListener(listener FlusherListener)
{
+ c.flushListeners = append(c.flushListeners, listener)
+}
+
type addressInfo struct {
pid uint32
}
@@ -135,6 +146,7 @@ type ConnectionInfo struct {
RPCConnection *v3.AccessLogConnection
MarkDeletable bool
PID uint32
+ Socket *ip.SocketPair
}
func NewConnectionManager(config *Config, moduleMgr *module.Manager, bpfLoader
*bpf.Loader, filter MonitorFilter) *ConnectionManager {
@@ -150,6 +162,7 @@ func NewConnectionManager(config *Config, moduleMgr
*module.Manager, bpfLoader *
activeConnectionMap: bpfLoader.ActiveConnectionMap,
allUnfinishedConnections: make(map[string]*bool),
monitorFilter: filter,
+ flushListeners: make([]FlusherListener, 0),
}
return mgr
}
@@ -246,6 +259,7 @@ func (c *ConnectionManager) Find(event events.Event)
*ConnectionInfo {
e.GetConnectionID(), e.GetRandomID(),
socket.Role, socket.SrcIP, socket.SrcPort, socket.DestIP, socket.DestPort,
localAddress.String(), remoteAddress.String())
}
+ c.connectionPostHandle(connection, event)
return connection
}
return nil
@@ -312,6 +326,11 @@ func (c *ConnectionManager)
connectionPostHandle(connection *ConnectionInfo, eve
}
}
}
+
+ // notify all flush listeners the connection is ready to flush
+ for _, flush := range c.flushListeners {
+ flush.ReadyToFlushConnection(connection, event)
+ }
}
func (c *ConnectionManager) ProcessIsMonitor(pid uint32) bool {
@@ -341,6 +360,7 @@ func (c *ConnectionManager) buildConnection(event
*events.SocketConnectEvent, so
RandomID: event.RandomID,
RPCConnection: connection,
PID: event.PID,
+ Socket: socket,
}
}
diff --git a/pkg/accesslog/collector/collector.go
b/pkg/accesslog/events/ztunnel.go
similarity index 64%
copy from pkg/accesslog/collector/collector.go
copy to pkg/accesslog/events/ztunnel.go
index e7d6e9b..33c6d35 100644
--- a/pkg/accesslog/collector/collector.go
+++ b/pkg/accesslog/events/ztunnel.go
@@ -15,25 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-package collector
+package events
-import (
- "github.com/apache/skywalking-rover/pkg/accesslog/common"
- "github.com/apache/skywalking-rover/pkg/module"
-)
-
-type Collector interface {
- Start(mgr *module.Manager, context *common.AccessLogContext) error
- Stop()
-}
-
-func Collectors() []Collector {
- return []Collector{
- l24CollectorsInstance,
- transferCollectInstance,
- closeCollectorInstance,
- connectCollectInstance,
- tlsCollectInstance,
- processCollectInstance,
- }
+type ZTunnelSocketMappingEvent struct {
+ OriginalSrcIP uint32
+ OriginalDestIP uint32
+ OriginalSrcPort uint16
+ OriginalDestPort uint16
+ LoadBalancedDestIP uint32
}
diff --git a/pkg/tools/elf/elf.go b/pkg/tools/elf/elf.go
index 51237ff..9d01111 100644
--- a/pkg/tools/elf/elf.go
+++ b/pkg/tools/elf/elf.go
@@ -50,22 +50,37 @@ func (f *File) Close() error {
}
func (f *File) FindSymbol(name string) *Symbol {
+ symbol := f.FilterSymbol(func(n string) bool {
+ return n == name
+ }, true)
+ if len(symbol) > 0 {
+ return symbol[0]
+ }
+ return nil
+}
+
+func (f *File) FilterSymbol(filter func(name string) bool, onlyOneResult bool)
[]*Symbol {
symbols, _ := f.realFile.Symbols()
dynamicSymbols, _ := f.realFile.DynamicSymbols()
if len(symbols) == 0 && len(dynamicSymbols) == 0 {
return nil
}
symbols = append(symbols, dynamicSymbols...)
+
+ result := make([]*Symbol, 0)
for _, s := range symbols {
- if s.Name == name {
- return &Symbol{
- Name: name,
+ if filter(s.Name) {
+ result = append(result, &Symbol{
+ Name: s.Name,
Location: s.Value,
Size: s.Size,
+ })
+ if onlyOneResult {
+ break
}
}
}
- return nil
+ return result
}
func (f *File) ReadSymbolData(section string, offset, size uint64) ([]byte,
error) {
diff --git a/scripts/build/bash/btfgen.sh b/scripts/build/bash/btfgen.sh
index 80ecd68..8441e73 100644
--- a/scripts/build/bash/btfgen.sh
+++ b/scripts/build/bash/btfgen.sh
@@ -21,7 +21,7 @@ TMPDIR=$1
ARCH=$2
FROM=$3
OUTPUT=$4
-BPF_SO_PATTERN="^bpf\_[a-z0-9]+\.o"
+BPF_SO_PATTERN="^bpf\_[a-z0-9]+(_[a-z0-9]+)?\.o"
echo "btfhub-archive is a big archive project, maybe take some times..."
git clone --depth 1 https://github.com/aquasecurity/btfhub $TMPDIR/btfhub